flow-props 0.1.2__tar.gz → 0.3.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.
Files changed (102) hide show
  1. flow_props-0.3.0/.github/workflows/package.yml +41 -0
  2. {flow_props-0.1.2 → flow_props-0.3.0}/.github/workflows/publish.yml +8 -8
  3. {flow_props-0.1.2 → flow_props-0.3.0}/.github/workflows/test.yml +1 -1
  4. {flow_props-0.1.2 → flow_props-0.3.0}/CITATION.cff +0 -1
  5. {flow_props-0.1.2 → flow_props-0.3.0}/PKG-INFO +32 -9
  6. {flow_props-0.1.2 → flow_props-0.3.0}/README.md +27 -5
  7. flow_props-0.3.0/docs/api/architecture.md +39 -0
  8. {flow_props-0.1.2 → flow_props-0.3.0}/docs/api/index.md +2 -1
  9. flow_props-0.3.0/docs/api/shock.md +46 -0
  10. {flow_props-0.1.2 → flow_props-0.3.0}/docs/index.md +3 -3
  11. flow_props-0.3.0/docs/theory/shock.md +143 -0
  12. {flow_props-0.1.2 → flow_props-0.3.0}/docs/user-guide/basic-usage.md +26 -1
  13. flow_props-0.3.0/docs/user-guide/cli.md +60 -0
  14. flow_props-0.3.0/docs/user-guide/config-files.md +93 -0
  15. flow_props-0.3.0/docs/user-guide/output.md +38 -0
  16. {flow_props-0.1.2 → flow_props-0.3.0}/mkdocs.yml +2 -0
  17. {flow_props-0.1.2 → flow_props-0.3.0}/pyproject.toml +6 -4
  18. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props/__init__.py +14 -2
  19. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props/bl.py +0 -26
  20. flow_props-0.3.0/src/flow_props/calculators/__init__.py +67 -0
  21. flow_props-0.3.0/src/flow_props/calculators/bl.py +274 -0
  22. flow_props-0.3.0/src/flow_props/calculators/common.py +508 -0
  23. flow_props-0.3.0/src/flow_props/calculators/entropy_layer.py +172 -0
  24. flow_props-0.3.0/src/flow_props/calculators/profiles.py +147 -0
  25. flow_props-0.3.0/src/flow_props/calculators/shock.py +427 -0
  26. flow_props-0.3.0/src/flow_props/cli/app.py +61 -0
  27. flow_props-0.3.0/src/flow_props/cli/callbacks.py +39 -0
  28. flow_props-0.3.0/src/flow_props/cli/cmd_calculator.py +107 -0
  29. flow_props-0.3.0/src/flow_props/cli/examples_command.py +186 -0
  30. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props/entropy_layer.py +0 -34
  31. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props/output.py +51 -1
  32. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props/profiles/__init__.py +0 -2
  33. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props/profiles/api.py +1 -24
  34. flow_props-0.3.0/src/flow_props/shock.py +768 -0
  35. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props/wall.py +0 -12
  36. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props.egg-info/PKG-INFO +32 -9
  37. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props.egg-info/SOURCES.txt +19 -15
  38. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props.egg-info/scm_file_list.json +19 -15
  39. flow_props-0.3.0/src/flow_props.egg-info/scm_version.json +8 -0
  40. flow_props-0.3.0/tests/synthetic.py +119 -0
  41. flow_props-0.3.0/tests/test_calculators.py +184 -0
  42. flow_props-0.3.0/tests/test_cli.py +408 -0
  43. {flow_props-0.1.2 → flow_props-0.3.0}/tests/test_output.py +19 -1
  44. flow_props-0.3.0/tests/test_shock.py +410 -0
  45. flow_props-0.1.2/docs/api/architecture.md +0 -26
  46. flow_props-0.1.2/docs/user-guide/cli.md +0 -100
  47. flow_props-0.1.2/docs/user-guide/config-files.md +0 -47
  48. flow_props-0.1.2/docs/user-guide/output.md +0 -48
  49. flow_props-0.1.2/src/flow_props/cli/app.py +0 -48
  50. flow_props-0.1.2/src/flow_props/cli/cmd_examples.py +0 -55
  51. flow_props-0.1.2/src/flow_props/cli/cmd_init.py +0 -110
  52. flow_props-0.1.2/src/flow_props/cli/cmd_run.py +0 -51
  53. flow_props-0.1.2/src/flow_props/cli/common.py +0 -427
  54. flow_props-0.1.2/src/flow_props/cli/config_init.py +0 -208
  55. flow_props-0.1.2/src/flow_props/config.py +0 -50
  56. flow_props-0.1.2/src/flow_props/examples/__init__.py +0 -1
  57. flow_props-0.1.2/src/flow_props/io/__init__.py +0 -13
  58. flow_props-0.1.2/src/flow_props/io/examples.py +0 -72
  59. flow_props-0.1.2/src/flow_props/pipeline.py +0 -315
  60. flow_props-0.1.2/src/flow_props/schema.py +0 -117
  61. flow_props-0.1.2/src/flow_props.egg-info/scm_version.json +0 -8
  62. flow_props-0.1.2/tests/test_cli.py +0 -108
  63. flow_props-0.1.2/tests/test_station_selection.py +0 -62
  64. {flow_props-0.1.2 → flow_props-0.3.0}/.github/workflows/docs.yml +0 -0
  65. {flow_props-0.1.2 → flow_props-0.3.0}/.gitignore +0 -0
  66. {flow_props-0.1.2 → flow_props-0.3.0}/.vscode/settings.json +0 -0
  67. {flow_props-0.1.2 → flow_props-0.3.0}/LICENSE +0 -0
  68. {flow_props-0.1.2 → flow_props-0.3.0}/docs/api/boundary-layer.md +0 -0
  69. {flow_props-0.1.2 → flow_props-0.3.0}/docs/api/entropy-layer.md +0 -0
  70. {flow_props-0.1.2 → flow_props-0.3.0}/docs/api/profiles.md +0 -0
  71. {flow_props-0.1.2 → flow_props-0.3.0}/docs/api/wall.md +0 -0
  72. {flow_props-0.1.2 → flow_props-0.3.0}/docs/cli-reference/index.md +0 -0
  73. {flow_props-0.1.2 → flow_props-0.3.0}/docs/examples.md +0 -0
  74. {flow_props-0.1.2 → flow_props-0.3.0}/docs/installation.md +0 -0
  75. {flow_props-0.1.2 → flow_props-0.3.0}/docs/javascripts/mathjax.js +0 -0
  76. {flow_props-0.1.2 → flow_props-0.3.0}/docs/nomenclature.md +0 -0
  77. {flow_props-0.1.2 → flow_props-0.3.0}/docs/theory/boundary-layer.md +0 -0
  78. {flow_props-0.1.2 → flow_props-0.3.0}/docs/theory/entropy-layer.md +0 -0
  79. {flow_props-0.1.2 → flow_props-0.3.0}/docs/theory/index.md +0 -0
  80. {flow_props-0.1.2 → flow_props-0.3.0}/docs/theory/wall-quantities.md +0 -0
  81. {flow_props-0.1.2 → flow_props-0.3.0}/docs/user-guide/configuration.md +0 -0
  82. {flow_props-0.1.2 → flow_props-0.3.0}/docs/user-guide/index.md +0 -0
  83. {flow_props-0.1.2 → flow_props-0.3.0}/docs/user-guide/workflow.md +0 -0
  84. {flow_props-0.1.2 → flow_props-0.3.0}/docs/vnv/index.md +0 -0
  85. {flow_props-0.1.2 → flow_props-0.3.0}/docs/vnv/validation/index.md +0 -0
  86. {flow_props-0.1.2 → flow_props-0.3.0}/docs/vnv/verification/index.md +0 -0
  87. {flow_props-0.1.2 → flow_props-0.3.0}/setup.cfg +0 -0
  88. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props/cli/__init__.py +0 -0
  89. /flow_props-0.1.2/src/flow_props/examples/cone_7deg_m14.toml → /flow_props-0.3.0/src/flow_props/examples/bl/cone_7deg_m14/bl.toml +0 -0
  90. /flow_props-0.1.2/src/flow_props/examples/ogive_m5pt3.toml → /flow_props-0.3.0/src/flow_props/examples/bl/ogive_m5pt3/bl.toml +0 -0
  91. /flow_props-0.1.2/src/flow_props/examples/sharp_flat_plate_m5.toml → /flow_props-0.3.0/src/flow_props/examples/bl/sharp_flat_plate_m5/bl.toml +0 -0
  92. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props/profiles/geometry.py +0 -0
  93. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props/profiles/grid_line.py +0 -0
  94. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props/profiles/wall_normal.py +0 -0
  95. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props.egg-info/dependency_links.txt +0 -0
  96. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props.egg-info/entry_points.txt +0 -0
  97. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props.egg-info/requires.txt +0 -0
  98. {flow_props-0.1.2 → flow_props-0.3.0}/src/flow_props.egg-info/top_level.txt +0 -0
  99. {flow_props-0.1.2 → flow_props-0.3.0}/tests/test_bl.py +0 -0
  100. {flow_props-0.1.2 → flow_props-0.3.0}/tests/test_entropy_layer.py +0 -0
  101. {flow_props-0.1.2 → flow_props-0.3.0}/tests/test_profiles.py +0 -0
  102. {flow_props-0.1.2 → flow_props-0.3.0}/tests/test_wall.py +0 -0
@@ -0,0 +1,41 @@
1
+ # GPL-3.0-or-later - see LICENSE
2
+ name: Package
3
+
4
+ on:
5
+ push:
6
+ branches: [main]
7
+ pull_request:
8
+ branches: [main]
9
+ workflow_dispatch:
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v6
16
+ with:
17
+ fetch-depth: 0
18
+
19
+ - uses: actions/setup-python@v6
20
+ with:
21
+ python-version: "3.11"
22
+
23
+ - name: Build distributions
24
+ run: |
25
+ python -m pip install build twine
26
+ python -m build
27
+ python -m twine check dist/*
28
+
29
+ - name: Smoke-test wheel
30
+ run: |
31
+ python -m venv "${RUNNER_TEMP}/wheel-test"
32
+ "${RUNNER_TEMP}/wheel-test/bin/python" -m pip install dist/*.whl
33
+ cd "${RUNNER_TEMP}"
34
+ "${RUNNER_TEMP}/wheel-test/bin/python" -c "import flow_props"
35
+ "${RUNNER_TEMP}/wheel-test/bin/flow-props" --help
36
+
37
+ - name: Upload distributions
38
+ uses: actions/upload-artifact@v7
39
+ with:
40
+ name: distributions
41
+ path: dist/
@@ -10,12 +10,12 @@ jobs:
10
10
  runs-on: ubuntu-latest
11
11
  strategy:
12
12
  matrix:
13
- python-version: ["3.11", "3.12", "3.13"]
13
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
14
14
  steps:
15
- - uses: actions/checkout@v4
15
+ - uses: actions/checkout@v6
16
16
 
17
17
  - name: Set up Python ${{ matrix.python-version }}
18
- uses: actions/setup-python@v5
18
+ uses: actions/setup-python@v6
19
19
  with:
20
20
  python-version: ${{ matrix.python-version }}
21
21
 
@@ -32,10 +32,10 @@ jobs:
32
32
  needs: test
33
33
  runs-on: ubuntu-latest
34
34
  steps:
35
- - uses: actions/checkout@v4
35
+ - uses: actions/checkout@v6
36
36
 
37
37
  - name: Set up Python
38
- uses: actions/setup-python@v5
38
+ uses: actions/setup-python@v6
39
39
  with:
40
40
  python-version: "3.11"
41
41
 
@@ -46,7 +46,7 @@ jobs:
46
46
  run: python -m build
47
47
 
48
48
  - name: Upload dist artifacts
49
- uses: actions/upload-artifact@v4
49
+ uses: actions/upload-artifact@v7
50
50
  with:
51
51
  name: dist
52
52
  path: dist/
@@ -60,7 +60,7 @@ jobs:
60
60
 
61
61
  steps:
62
62
  - name: Download dist artifacts
63
- uses: actions/download-artifact@v4
63
+ uses: actions/download-artifact@v8
64
64
  with:
65
65
  name: dist
66
66
  path: dist/
@@ -74,7 +74,7 @@ jobs:
74
74
  permissions:
75
75
  contents: write
76
76
  steps:
77
- - uses: actions/checkout@v4
77
+ - uses: actions/checkout@v6
78
78
  - name: Create GitHub Release (skip if it already exists)
79
79
  run: |
80
80
  if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then
@@ -11,7 +11,7 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  strategy:
13
13
  matrix:
14
- python-version: ["3.11", "3.12", "3.13"]
14
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
15
15
 
16
16
  steps:
17
17
  - uses: actions/checkout@v6
@@ -6,7 +6,6 @@ type: software
6
6
  authors:
7
7
  - family-names: "Hader"
8
8
  given-names: "Christoph"
9
- affiliation: "University of Arizona"
10
9
  orcid: "https://orcid.org/0000-0002-0956-000X"
11
10
  repository-code: "https://github.com/uahypersonics/flow-props"
12
11
  license: GPL-3.0-or-later
@@ -1,18 +1,19 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flow-props
3
- Version: 0.1.2
4
- Summary: Extract flow properties from CFD data: boundary layer thickness, entropy layer thickness
5
- Author-email: Christoph Hader <chader@arizona.edu>
3
+ Version: 0.3.0
4
+ Summary: Extract flow properties from CFD data: boundary layer, entropy layer, shock
5
+ Author-email: Christoph Hader <christoph.hader@gmail.com>
6
6
  License-Expression: GPL-3.0-or-later
7
7
  Project-URL: Homepage, https://github.com/uahypersonics/flow-props
8
8
  Project-URL: Repository, https://github.com/uahypersonics/flow-props
9
- Keywords: boundary-layer,entropy-layer,cfd,flow-properties,aerodynamics
9
+ Keywords: boundary-layer,entropy-layer,shock,cfd,flow-properties,aerodynamics
10
10
  Classifier: Development Status :: 1 - Planning
11
11
  Classifier: Intended Audience :: Science/Research
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
16
17
  Classifier: Topic :: Scientific/Engineering :: Physics
17
18
  Requires-Python: >=3.11
18
19
  Description-Content-Type: text/markdown
@@ -30,7 +31,7 @@ Dynamic: license-file
30
31
 
31
32
  # flow-props
32
33
 
33
- Python tool suite to extract flow properties from CFD data, such as boundary layer thickness and entropy layer thickness.
34
+ Python tool suite to extract flow properties from CFD data, such as boundary layer thickness, entropy layer thickness and the shock.
34
35
 
35
36
  [![Test](https://github.com/uahypersonics/flow-props/actions/workflows/test.yml/badge.svg)](https://github.com/uahypersonics/flow-props/actions/workflows/test.yml)
36
37
  [![PyPI](https://img.shields.io/pypi/v/flow-props)](https://pypi.org/project/flow-props/)
@@ -45,15 +46,37 @@ Python tool suite to extract flow properties from CFD data, such as boundary lay
45
46
  pip install flow-props
46
47
  ```
47
48
 
49
+ To upgrade an existing installation:
50
+
51
+ ```bash
52
+ pip install --upgrade flow-props
53
+ ```
54
+
48
55
  ## Quick Start
49
56
 
50
- ```python
51
- import flow_props
57
+ Every calculation is a command group (`bl`, `entropy-layer`, `profiles`, `shock`):
58
+
59
+ ```bash
60
+ flow-props bl init # writes bl.toml, every key documented
61
+ flow-props bl run # reads bl.toml
62
+ flow-props shock init # shock curve of a solution (for grid-generator's [shock] curve)
63
+ flow-props shock run
52
64
  ```
53
65
 
54
- ## Features
66
+ `flow-props -v <calculation> run` adds debug output.
67
+
68
+ ## Documentation
69
+
70
+ Full documentation: https://uahypersonics.github.io/flow-props
71
+
72
+ ## Testing
55
73
 
56
- - under construction
74
+ Run the ruff check and pytest check in the project root:
75
+
76
+ ```bash
77
+ ruff check
78
+ pytest --cov
79
+ ```
57
80
 
58
81
  ## Documentation
59
82
 
@@ -1,6 +1,6 @@
1
1
  # flow-props
2
2
 
3
- Python tool suite to extract flow properties from CFD data, such as boundary layer thickness and entropy layer thickness.
3
+ Python tool suite to extract flow properties from CFD data, such as boundary layer thickness, entropy layer thickness and the shock.
4
4
 
5
5
  [![Test](https://github.com/uahypersonics/flow-props/actions/workflows/test.yml/badge.svg)](https://github.com/uahypersonics/flow-props/actions/workflows/test.yml)
6
6
  [![PyPI](https://img.shields.io/pypi/v/flow-props)](https://pypi.org/project/flow-props/)
@@ -15,15 +15,37 @@ Python tool suite to extract flow properties from CFD data, such as boundary lay
15
15
  pip install flow-props
16
16
  ```
17
17
 
18
+ To upgrade an existing installation:
19
+
20
+ ```bash
21
+ pip install --upgrade flow-props
22
+ ```
23
+
18
24
  ## Quick Start
19
25
 
20
- ```python
21
- import flow_props
26
+ Every calculation is a command group (`bl`, `entropy-layer`, `profiles`, `shock`):
27
+
28
+ ```bash
29
+ flow-props bl init # writes bl.toml, every key documented
30
+ flow-props bl run # reads bl.toml
31
+ flow-props shock init # shock curve of a solution (for grid-generator's [shock] curve)
32
+ flow-props shock run
22
33
  ```
23
34
 
24
- ## Features
35
+ `flow-props -v <calculation> run` adds debug output.
36
+
37
+ ## Documentation
38
+
39
+ Full documentation: https://uahypersonics.github.io/flow-props
40
+
41
+ ## Testing
25
42
 
26
- - under construction
43
+ Run the ruff check and pytest check in the project root:
44
+
45
+ ```bash
46
+ ruff check
47
+ pytest --cov
48
+ ```
27
49
 
28
50
  ## Documentation
29
51
 
@@ -0,0 +1,39 @@
1
+ # Architecture
2
+
3
+ `flow_props` follows a narrow pipeline:
4
+
5
+ 1. `cfd-io` reads a CFD dataset
6
+ 2. `flow_props.profiles.extract_profiles` slices wall-normal profiles at chosen stations
7
+ 3. reduction modules compute derived quantities from those profiles
8
+
9
+ ## Module Layout
10
+
11
+ - `profiles/`: wall-normal profile extraction (along grid lines or interpolated normals)
12
+ - `bl.py`: boundary-layer edge detection and integral thicknesses
13
+ - `entropy_layer.py`: entropy-layer thickness
14
+ - `shock.py`: shock point per grid line and the shock curve
15
+ - `wall.py`: wall shear and thermal quantities
16
+ - `output.py`: Tecplot ASCII writers
17
+ - `calculators/`: one module per CLI calculation (`bl`, `entropy_layer`, `profiles`,
18
+ `shock`) with its pydantic config model, its `init` template and its `run_case`;
19
+ `common.py` holds the shared parts (input files, `[stations]`, `[gas]`), and
20
+ `__init__.py` the registry the CLI is built from
21
+ - `cli/`: Typer app (`app.py`), callbacks (`--version`, `--verbose`), the command-group
22
+ factory (`cmd_calculator.py`) and the `examples` command
23
+ - `examples/<calculation>/<name>/`: bundled cases; the folders are the registry
24
+
25
+ ## Adding a Calculation
26
+
27
+ Write `calculators/<name>.py` with a config model, a `TEMPLATE` and
28
+ `run_case(config, config_dir) -> list[str]`, and add one entry to `CALCULATORS` in
29
+ `calculators/__init__.py`. The CLI then has `flow-props <name> init` and `run`.
30
+
31
+ ## Design Intent
32
+
33
+ The package is deliberately lightweight.
34
+
35
+ - it does not own CFD file I/O
36
+ - it assumes `cfd-io` has already constructed a dataset
37
+ - it focuses on profile-based property extraction rather than general field operations
38
+
39
+ That separation keeps `flow_props` easy to reason about and consistent with the rest of the workspace.
@@ -7,6 +7,7 @@ The public API is intentionally small and organized around the main post-process
7
7
  - `flow_props.profiles` for wall-normal profile extraction
8
8
  - `flow_props.bl` for boundary-layer edge detection and integral thicknesses
9
9
  - `flow_props.entropy_layer` for entropy-layer thickness
10
+ - `flow_props.shock` for the shock point on each grid line and the shock curve
10
11
  - `flow_props.wall` for wall shear and heat-transfer quantities
11
12
  - `flow_props.cli` for command-line entry points
12
13
 
@@ -15,7 +16,7 @@ The public API is intentionally small and organized around the main post-process
15
16
  The package re-exports the most common functions through `flow_props` itself, so this style works:
16
17
 
17
18
  ```python
18
- from flow_props import extract_profiles, run_bl, run_entropy, run_wall
19
+ from flow_props import extract_profiles, extract_shock, run_bl, run_entropy, run_wall
19
20
  ```
20
21
 
21
22
  Use the pages in this section for a module-by-module view.
@@ -0,0 +1,46 @@
1
+ # Shock
2
+
3
+ Module: `flow_props.shock`
4
+
5
+ ## Purpose
6
+
7
+ This module finds the shock on each wall-normal grid line of a structured solution and
8
+ writes the shock curve (see [Shock Extraction](../theory/shock.md) for the method).
9
+
10
+ ## Main Functions
11
+
12
+ - `find_shock_on_line(values, level=0.5, min_rise=0.05, max_thickness=20.0, method="walk",
13
+ indicator_threshold=0.0025)`: the shock on one line, as a `ShockCrossing` (fractional
14
+ `j`, `j_tail`, the outer edge `j_foot`, `thickness_cells`, `detected_by`, and each
15
+ detector's own point `j_walk`, `j_indicator`, whatever the method), or `None`
16
+ - `extract_shock(ds, quantity="pressure", ..., method="walk", indicator_threshold=0.0025)`:
17
+ every line of a dataset, as a `ShockExtraction` (station, x, y, j, distance,
18
+ thickness_cells, detected_by, and the stations without a shock)
19
+ - `smoothness_indicator(values, reference)`: the WENO smoothness indicator along a line,
20
+ divided by 5040 reference^2
21
+ - `smooth_shock(ds, extraction, length)`: the same points moved, along their grid lines,
22
+ onto local quadratics fitted in the shock's frame over `length` wall-to-shock distances
23
+ (see
24
+ [Smoothing the Curve](../theory/shock.md#smoothing-the-curve))
25
+ - `write_shock_curve(path, extraction)`: the x, y CSV that grid-generator's `[shock] curve`
26
+ reads
27
+
28
+ ## Example
29
+
30
+ ```python
31
+ import cfd_io
32
+ from flow_props import extract_shock, smooth_shock, write_shock_curve
33
+
34
+ dataset = cfd_io.read_file("solution.h5")
35
+ extraction = extract_shock(dataset)
36
+ smoothed = smooth_shock(dataset, extraction, length=0.5)
37
+ write_shock_curve("shock_cfd.csv", smoothed)
38
+
39
+ print(extraction.thickness_cells.max(), extraction.stations_without_shock)
40
+ ```
41
+
42
+ ## Notes
43
+
44
+ - the dataset must use a `StructuredGrid` with $j = 0$ at the wall (cfd-io's canonical
45
+ orientation) and the outer boundary in the freestream
46
+ - the quantity's field is looked up as `pres`, `pressure`, `p` (or `dens`, `density`, `rho`)
@@ -1,6 +1,6 @@
1
1
  # flow_props
2
2
 
3
- `flow_props` extracts physically meaningful boundary-layer and wall quantities from structured CFD datasets.
3
+ `flow_props` extracts physically meaningful boundary-layer, entropy-layer and shock quantities from structured CFD datasets.
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -15,8 +15,8 @@ pip install flow-props
15
15
  === "CLI"
16
16
 
17
17
  ```bash
18
- flow-props init --bl
19
- flow-props run --bl
18
+ flow-props bl init
19
+ flow-props bl run
20
20
  ```
21
21
 
22
22
  === "API"
@@ -0,0 +1,143 @@
1
+ # Shock Extraction
2
+
3
+ `flow-props shock` finds the shock of a CFD solution on every wall-normal grid line. Each
4
+ line runs from the wall ($j = 0$) to the outer boundary, which must lie in the freestream.
5
+ A shock-capturing solver smears the shock over a few cells, so along the line the
6
+ quantity $q$ (pressure by default, or density) climbs from its freestream value to the
7
+ post-shock value over a short stretch.
8
+
9
+ ## Finding the Jump
10
+
11
+ Walking inward from the line's outer end, where $q_\infty$ is $q$ at the outer end, a
12
+ detector proposes where a jump starts (`method`):
13
+
14
+ - **walk** (default): the first point where $q > (1 + \text{min\_rise})\, q_\infty$;
15
+ - **indicator**: the first point whose smoothness indicator reaches
16
+ `indicator_threshold` (see [Smoothness Indicator](#smoothness-indicator));
17
+ - **hybrid**: both detectors, and the outermost jump either finds, since the shock is
18
+ the first jump from outside. The report says which detector found each line.
19
+
20
+ From the proposed start, the steepest cell within `max_thickness` cells inward is the
21
+ jump's core. Walking on inward, the rise per cell shrinks across the jump's rounded
22
+ shoulder; once past the jump's center (the rise below half the steepest), the jump ends
23
+ where the rise shrinks by less than 1 % of the steepest from one cell to the next: at the
24
+ knee into the post-shock plateau or the top of an overshoot. $q_t$ is the post-shock
25
+ value there. The profile is flat
26
+ there, so $q_t$ barely changes when the shock drifts by a cell from one grid line to the
27
+ next. (Ending the jump on the shoulder instead makes $q_t$, and with it the shock point,
28
+ jump at every such drift: a staircase along the shock.)
29
+
30
+ Because the walk starts outside, the first jump it meets is the shock: the boundary layer,
31
+ the entropy layer and any inner compression are never reached.
32
+
33
+ ## Placing the Shock Point
34
+
35
+ The shock point is where $q$ crosses
36
+
37
+ $$
38
+ q_\text{level} = q_\infty + \text{level}\,(q_t - q_\infty),
39
+ $$
40
+
41
+ interpolated linearly between the two grid points around the crossing. `level = 0.5`
42
+ puts it in the middle of the captured jump, which is where a grid line should sit; values
43
+ toward 0 move it to the freestream side, toward 1 to the post-shock side.
44
+
45
+ Only this crossing places the point; the foot and tail just bracket the jump. The point
46
+ therefore doesn't depend on `min_rise`, and is placed the same way for a shock of 40 times
47
+ freestream pressure at the nose and a weak one far downstream. On synthetic captured
48
+ shocks (jumps 0.3 to 40 times freestream) it lands within 0.1 cell of the jump's center
49
+ for shocks captured over up to about 5 cells; with a post-shock gradient, a shock smeared
50
+ over more cells comes out inward by up to about 2 % of its thickness. As a shock drifts
51
+ across the cells from one grid line to the next, its point moves smoothly; what remains
52
+ is a small error that repeats with the shock's position inside a cell (about 0.03 to
53
+ 0.07 cell for shocks captured over 1 to 2 cells), which the smoothing removes.
54
+
55
+ ## Thickness and Smooth Compressions
56
+
57
+ The captured thickness is the distance, in cells, between the crossings of 10 % and 90 %
58
+ of the jump. A rise spread over more than `max_thickness` cells (default 20) is a smooth
59
+ compression, not a shock: for example the pressure rise toward the stagnation point on a
60
+ line that ends inside the shock layer. Such lines are reported as having no shock.
61
+
62
+ ## Comparison with a Shock-Line Grid
63
+
64
+ On a shock-line grid the shock is meant to lie on grid line `shock_line_j`. The report
65
+ gives each line's offset $j_\text{shock} - j_s$ in cells, and the run summary the range of
66
+ offsets and the number of lines more than a quarter cell off.
67
+
68
+ ## Checks in the Report
69
+
70
+ Both detectors run on every line, whichever the method, so each result can be checked
71
+ against the other. The run summary warns when
72
+
73
+ - the shock's outer edge (where $q$ crosses 10 % of the jump) lies within 5 cells of the
74
+ outer boundary: too little freestream outside it to read $q_\infty$ from, or a
75
+ disturbance ahead of the shock was taken for it;
76
+ - the walk and the indicator differ by more than 3 cells on a line: one of them found
77
+ something else. A smooth compression ahead of the shock (e.g. freestream compressed
78
+ against a bent symmetry line) is met first by the walk, while the indicator, which
79
+ only flags sharp jumps, finds the shock.
80
+
81
+ It also counts how often the shock's outer edge changes grid row along the body and, on
82
+ a shock-line grid, how often it crosses the shock line `shock_line_j`. A captured shock
83
+ that moves between rows makes a solver's wall quantities wave; on a converged
84
+ shock-line grid the edge stays on one side of the shock line.
85
+
86
+ ## Solutions at Cell Centres
87
+
88
+ A finite-volume solution holds cell values. Read through cfd-io as fields at the cell
89
+ centres of the vertex grid (association `cell`: one point fewer than the grid in each
90
+ direction), they are put on a grid of the cell centres, each the mean of its cell's
91
+ corners, and the shock is found along the lines through them. Those lines lie half a
92
+ cell from the vertex grid's lines, so:
93
+
94
+ - the shock line `shock_line_j` counts vertices, and cell $j$ lies at $j + 0.5$ on the
95
+ vertex grid; the report's `j_shock` and the offsets use that, and the run summary
96
+ says the solution was at cell centres;
97
+ - the first line runs half a cell off the symmetry axis, so the curve starts there;
98
+ grid-generator continues a curve that starts slightly off the axis to it.
99
+
100
+ A solution whose grid is the cell centres themselves (stored as an ordinary grid)
101
+ can't be told from vertex data; write cell values on the vertex grid instead.
102
+
103
+ ## Smoothing the Curve
104
+
105
+ The extracted curve becomes a grid line of the next grid, so line-to-line jitter of the
106
+ points would become wiggles in the grid. With `smoothing_length = a` (default 0.5), each
107
+ point is moved onto a quadratic fitted, by least squares, through the shock points within
108
+ a stretch of the shock $a\,d$ long, with $d$ the local wall-to-shock distance, and the
109
+ curve that is written is the smoothed one.
110
+
111
+ The stretch scales with $d$ because the shock bends on scales of $d$: tightly around a
112
+ blunt nose, gently far downstream. A fixed number of grid lines fails one way or the
113
+ other: a precursor grid's lines are dense on the body compared with a shock-line grid's
114
+ cells, so a short window leaves wiggles a few millimetres long that the new grid resolves
115
+ (its shock line zig-zags), and a long one flattens the nose.
116
+
117
+ The fit is made in the shock's own local frame: the tangent along the chord of the window
118
+ and the normal to it. The point then moves along its own grid line onto the fitted
119
+ quadratic, so there is still one point per grid line. Fitting the distance along the grid
120
+ lines instead would be wrong where the body's curvature jumps: at a nose-body tangency
121
+ the wall normals stop turning, and the distance along them bends although the shock is
122
+ smooth. A straight shock over such lines stays exactly where it is.
123
+
124
+ The report keeps the raw and the smoothed points, and the run summary says how far the
125
+ smoothing moved them, in cells; `smoothing_length = 0` writes the points as found.
126
+
127
+ ## Smoothness Indicator
128
+
129
+ A WENO smoothness indicator measures how far a stencil is from smooth. flow-props uses the
130
+ central five-point measure of ninth-order WENO (Balsara and Shu, J. Comput. Phys. 160,
131
+ 2000) divided by $5040\, q_\infty^2$, which on a smooth ramp equals
132
+ $(\Delta q_\text{cell} / q_\infty)^2$, with $\Delta q_\text{cell}$ the rise per cell; a jump
133
+ captured over fewer cells scores higher. The default threshold 0.0025 is thus a rise of
134
+ 5 % of freestream per cell. Dividing by $q_\infty^2$ makes one threshold work for any
135
+ freestream pressure.
136
+
137
+ Its peak scales with $(\text{jump} / \text{thickness})^2$, so the threshold that finds
138
+ the shock depends on how strong and how smeared it is: on synthetic captured shocks a
139
+ jump of $0.3\, q_\infty$ peaks at about 0.06 when captured over 2 cells and at about
140
+ 0.0015 over 9 cells. Along a body, from the strong nose shock to a weak, smeared shock
141
+ downstream, a single threshold can miss part of the shock; lower it, or use the walk (its
142
+ `min_rise` is a total rise, whatever the width) or the hybrid. Where the walk and the
143
+ indicator find the same jump, the shock point is the same: the level crossing places it.
@@ -17,7 +17,7 @@ For split solution/grid formats, provide the separate grid file through `cfd-io`
17
17
  ```python
18
18
  from flow_props import extract_profiles
19
19
 
20
- profiles = extract_profiles(dataset, stations=[10, 50, 100], j_max=80)
20
+ profiles = extract_profiles(dataset, stations=[10, 50, 100])
21
21
  print(profiles[0].keys())
22
22
  ```
23
23
 
@@ -27,6 +27,19 @@ Each extracted profile includes:
27
27
  - `eta`
28
28
  - one array per flow field available in the input dataset
29
29
 
30
+ For config-driven extraction, `flow-props bl init` creates `bl.toml`. Set
31
+ `fname` to a structured HDF5 file, then run `flow-props bl run`. To look at the
32
+ profiles behind the table, `flow-props profiles init` / `run` writes them, for the
33
+ same stations, as multi-zone Tecplot ASCII.
34
+ `cfd-io` handles file reading; `flow-props` does not convert CFD formats.
35
+ Leave `[stations]` empty to process all i-indices from 0 through `Nx - 1` with
36
+ step 1, or choose one station-selection mode to limit the run.
37
+
38
+ Only the `htot_derivative` criterion requires gas constants. The tool reads
39
+ `gamma` and `r_gas` from HDF5 attributes, fills missing values from an adjacent
40
+ `flow_conditions.json`, and allows optional `[gas]` overrides. The default
41
+ `velocity_ratio` criterion does not require those values.
42
+
30
43
  ## Compute Boundary-Layer Properties
31
44
 
32
45
  ```python
@@ -58,6 +71,18 @@ entropy_results = run_entropy(
58
71
  )
59
72
  ```
60
73
 
74
+ ## Extract the Shock
75
+
76
+ ```python
77
+ from flow_props import extract_shock, write_shock_curve
78
+
79
+ extraction = extract_shock(dataset, quantity="pressure", level=0.5)
80
+ write_shock_curve("shock_cfd.csv", extraction)
81
+ ```
82
+
83
+ `extraction.j` holds the fractional grid index of the shock on each line, for comparing
84
+ with a shock-line grid's shock line.
85
+
61
86
  ## Compute Wall Quantities
62
87
 
63
88
  ```python
@@ -0,0 +1,60 @@
1
+ # CLI
2
+
3
+ The command-line interface is exposed through `flow-props`. Every calculation is a
4
+ command group with the same commands:
5
+
6
+ ```bash
7
+ flow-props <calculation> init # write <calculation>.toml, every key documented
8
+ flow-props <calculation> run # run <calculation>.toml
9
+ flow-props <calculation> examples # bundled cases (calculations that ship some)
10
+ ```
11
+
12
+ ## Calculations
13
+
14
+ | Command | What it computes | Default config |
15
+ |---|---|---|
16
+ | `bl` | boundary-layer edge $\delta$, $\delta^*$, $\theta$, $H$ and edge state per station | `bl.toml` |
17
+ | `entropy-layer` | entropy-layer thickness per station | `entropy-layer.toml` |
18
+ | `profiles` | wall-normal profiles of every flow variable per station | `profiles.toml` |
19
+ | `shock` | the shock curve, and its offset from a shock-line grid's shock line | `shock.toml` |
20
+
21
+ ## Global Options
22
+
23
+ Global options go before the calculation:
24
+
25
+ ```bash
26
+ flow-props --version # or -V
27
+ flow-props -v shock run # --verbose: debug output from flow-props (not from cfd-io)
28
+ ```
29
+
30
+ ## init
31
+
32
+ ```bash
33
+ flow-props bl init # writes bl.toml
34
+ flow-props bl init -o ogive_bl.toml # another name (then: flow-props bl run -c ogive_bl.toml)
35
+ flow-props bl init --force # overwrite an existing file
36
+ ```
37
+
38
+ ## run
39
+
40
+ `run` reads the calculation's default config, or the one named with `--config` / `-c`.
41
+ Paths in the config (solution file, outputs) are relative to the config file's folder.
42
+
43
+ ```bash
44
+ flow-props bl run
45
+ flow-props shock run -c precursor.toml
46
+ ```
47
+
48
+ Bad input (a misspelled key, a missing solution file, a missing field) is reported as one
49
+ `error: ...` line with exit code 1.
50
+
51
+ ## examples
52
+
53
+ ```bash
54
+ flow-props bl examples # list the bundled cases
55
+ flow-props bl examples sharp_flat_plate_m5 # copy its files here (as bl.toml)
56
+ flow-props bl run
57
+ ```
58
+
59
+ An example is copied into the current folder; it refuses to overwrite existing files
60
+ unless `--force` is given.