wakemarch 0.1.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.
- wakemarch-0.1.0/CHANGELOG.md +19 -0
- wakemarch-0.1.0/CITATION.cff +24 -0
- wakemarch-0.1.0/CITATION.md +8 -0
- wakemarch-0.1.0/LICENSE +28 -0
- wakemarch-0.1.0/MANIFEST.in +11 -0
- wakemarch-0.1.0/PKG-INFO +197 -0
- wakemarch-0.1.0/PROVENANCE.md +40 -0
- wakemarch-0.1.0/README.md +159 -0
- wakemarch-0.1.0/docs/RELEASING.md +77 -0
- wakemarch-0.1.0/docs/SCIENCE.md +74 -0
- wakemarch-0.1.0/docs/TURBINES.md +161 -0
- wakemarch-0.1.0/docs/USER_GUIDE.md +192 -0
- wakemarch-0.1.0/docs/images/wake.png +0 -0
- wakemarch-0.1.0/docs/release-metadata.json +20 -0
- wakemarch-0.1.0/examples/first_wake.py +25 -0
- wakemarch-0.1.0/examples/plot_wake.py +53 -0
- wakemarch-0.1.0/examples/wakemarch_api_test.ipynb +287 -0
- wakemarch-0.1.0/examples/wakemarch_performance.ipynb +147 -0
- wakemarch-0.1.0/examples/wakemarch_piv_validation.ipynb +134 -0
- wakemarch-0.1.0/examples/wakemarch_turbines.ipynb +142 -0
- wakemarch-0.1.0/pyproject.toml +47 -0
- wakemarch-0.1.0/setup.cfg +4 -0
- wakemarch-0.1.0/src/wakemarch/__init__.py +9 -0
- wakemarch-0.1.0/src/wakemarch/_kernel.py +538 -0
- wakemarch-0.1.0/src/wakemarch/_progress.py +57 -0
- wakemarch-0.1.0/src/wakemarch/data/FLORIS_LICENSE.txt +26 -0
- wakemarch-0.1.0/src/wakemarch/data/iea_10MW.json +89 -0
- wakemarch-0.1.0/src/wakemarch/data/iea_15MW.json +179 -0
- wakemarch-0.1.0/src/wakemarch/data/nrel_5MW.json +179 -0
- wakemarch-0.1.0/src/wakemarch/model.py +219 -0
- wakemarch-0.1.0/src/wakemarch/turbine.py +260 -0
- wakemarch-0.1.0/src/wakemarch.egg-info/PKG-INFO +197 -0
- wakemarch-0.1.0/src/wakemarch.egg-info/SOURCES.txt +39 -0
- wakemarch-0.1.0/src/wakemarch.egg-info/dependency_links.txt +1 -0
- wakemarch-0.1.0/src/wakemarch.egg-info/requires.txt +16 -0
- wakemarch-0.1.0/src/wakemarch.egg-info/top_level.txt +1 -0
- wakemarch-0.1.0/tests/test_api.py +184 -0
- wakemarch-0.1.0/tests/test_turbine.py +154 -0
- wakemarch-0.1.0/tools/check_docs.py +48 -0
- wakemarch-0.1.0/tools/check_release.py +126 -0
- wakemarch-0.1.0/tools/run_notebooks.py +67 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 — 2026-11-02
|
|
4
|
+
|
|
5
|
+
First public release.
|
|
6
|
+
|
|
7
|
+
- Single-turbine steady wake model with curled wake shape: the recommended
|
|
8
|
+
configuration of the authors' research solver (thrust exponent 2, vortex
|
|
9
|
+
diffusivity factor 0.5, momentum fraction 0.95, near-wake display ramp).
|
|
10
|
+
- `WakeModel`, `Numerics` and `WakeResult`: immutable inputs, explicit deficit
|
|
11
|
+
and velocity sampling, read-only histories, live progress display.
|
|
12
|
+
- `Turbine`: power/CT and CP/CT tables, three reference presets pinned from
|
|
13
|
+
FLORIS 4.6.2 (NREL 5 MW, IEA 10 MW, IEA 15 MW), rotor-equivalent operating
|
|
14
|
+
point. The tabulated speed range is the operating range; table CT ≥ 1 is capped
|
|
15
|
+
at 0.97 for the wake with a warning. `Turbine.fixed` for constant coefficients.
|
|
16
|
+
- Input limits: H ≥ D/2 and |yaw| ≤ 50° (validated to 40°).
|
|
17
|
+
- Runtime dependencies NumPy ≥ 1.24 and SciPy ≥ 1.10; Python ≥ 3.11.
|
|
18
|
+
- Four example notebooks (API, resolution/cost, turbines, optional public PIV
|
|
19
|
+
comparison).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: >-
|
|
3
|
+
If you use WakeMarch, please cite it using these metadata. The paper
|
|
4
|
+
describing the model will be added here once it has a DOI.
|
|
5
|
+
title: WakeMarch
|
|
6
|
+
abstract: >-
|
|
7
|
+
Steady cross-plane marching wake model for a single yawed wind turbine with
|
|
8
|
+
curled wake shape.
|
|
9
|
+
type: software
|
|
10
|
+
authors:
|
|
11
|
+
- family-names: Bui
|
|
12
|
+
given-names: Hoang Hai
|
|
13
|
+
orcid: "https://orcid.org/0000-0003-4485-0325"
|
|
14
|
+
affiliation: University of Bergen
|
|
15
|
+
version: 0.1.0
|
|
16
|
+
date-released: "2026-11-02"
|
|
17
|
+
license: BSD-3-Clause
|
|
18
|
+
repository-code: "https://github.com/haibuihoang/wakemarch"
|
|
19
|
+
keywords:
|
|
20
|
+
- wind energy
|
|
21
|
+
- wake model
|
|
22
|
+
- yaw
|
|
23
|
+
- wake steering
|
|
24
|
+
- curled wake
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Citation
|
|
2
|
+
|
|
3
|
+
Citation metadata are in [CITATION.cff](CITATION.cff) (GitHub shows a "Cite this
|
|
4
|
+
repository" button for it). The paper describing the model and a software DOI
|
|
5
|
+
will be added there when available.
|
|
6
|
+
|
|
7
|
+
For reproducibility, also record `wakemarch.__version__`, the Python, NumPy and
|
|
8
|
+
SciPy versions, all physical and numerical inputs, and your sampling definitions.
|
wakemarch-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, University of Bergen
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
include README.md PROVENANCE.md pyproject.toml
|
|
2
|
+
include CITATION.md CITATION.cff CHANGELOG.md LICENSE
|
|
3
|
+
recursive-include docs *.md *.json *.png
|
|
4
|
+
recursive-include tools *.py
|
|
5
|
+
recursive-include examples *.py
|
|
6
|
+
recursive-include examples *.ipynb
|
|
7
|
+
recursive-include tests *.py
|
|
8
|
+
prune examples/.ipynb_checkpoints
|
|
9
|
+
global-exclude .DS_Store
|
|
10
|
+
|
|
11
|
+
recursive-include src/wakemarch/data *.json *.txt
|
wakemarch-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wakemarch
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Cross-plane marching wake model for yawed wind turbines with curled wakes
|
|
5
|
+
Author: Hoang Hai Bui
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://github.com/haibuihoang/wakemarch
|
|
8
|
+
Project-URL: Issues, https://github.com/haibuihoang/wakemarch/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/haibuihoang/wakemarch/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: wind energy,wake model,yaw,wake steering,curled wake
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
License-File: src/wakemarch/data/FLORIS_LICENSE.txt
|
|
24
|
+
Requires-Dist: numpy<3,>=1.24
|
|
25
|
+
Requires-Dist: scipy<2,>=1.10
|
|
26
|
+
Provides-Extra: plot
|
|
27
|
+
Requires-Dist: matplotlib>=3.8; extra == "plot"
|
|
28
|
+
Provides-Extra: notebooks
|
|
29
|
+
Requires-Dist: matplotlib>=3.8; extra == "notebooks"
|
|
30
|
+
Requires-Dist: jupyterlab>=4; extra == "notebooks"
|
|
31
|
+
Requires-Dist: ipykernel>=6; extra == "notebooks"
|
|
32
|
+
Requires-Dist: nbclient>=0.10; extra == "notebooks"
|
|
33
|
+
Requires-Dist: nbconvert>=7; extra == "notebooks"
|
|
34
|
+
Provides-Extra: validation
|
|
35
|
+
Requires-Dist: h5py>=3.10; extra == "validation"
|
|
36
|
+
Requires-Dist: netCDF4>=1.6; extra == "validation"
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
|
|
39
|
+
# WakeMarch
|
|
40
|
+
|
|
41
|
+
WakeMarch is a steady, cross-plane marching wake model for a single yawed wind
|
|
42
|
+
turbine. It resolves the curled (kidney-shaped) wake produced by the
|
|
43
|
+
counter-rotating streamwise vortex pair of a yawed rotor, in uniform or
|
|
44
|
+
power-law-sheared inflow, and returns the wake deficit, streamwise vorticity and
|
|
45
|
+
velocity anywhere downstream.
|
|
46
|
+
|
|
47
|
+
The core depends only on NumPy (≥ 1.24) and SciPy (≥ 1.10) and needs
|
|
48
|
+
Python 3.11 or later. The upper bounds `<3`/`<2` are compatibility boundaries,
|
|
49
|
+
not evidence of tests on every release.
|
|
50
|
+
|
|
51
|
+

|
|
52
|
+
|
|
53
|
+
Start with the [user guide](https://github.com/haibuihoang/wakemarch/blob/main/docs/USER_GUIDE.md), then the
|
|
54
|
+
[API notebook](https://github.com/haibuihoang/wakemarch/blob/main/examples/wakemarch_api_test.ipynb) and
|
|
55
|
+
[resolution/cost notebook](https://github.com/haibuihoang/wakemarch/blob/main/examples/wakemarch_performance.ipynb).
|
|
56
|
+
[Turbine curves and presets](https://github.com/haibuihoang/wakemarch/blob/main/docs/TURBINES.md) and an
|
|
57
|
+
[interactive turbine notebook](https://github.com/haibuihoang/wakemarch/blob/main/examples/wakemarch_turbines.ipynb) accept user CP/CT
|
|
58
|
+
or power/CT tables, including rotor-wide velocity samples.
|
|
59
|
+
An optional [PIV comparison](https://github.com/haibuihoang/wakemarch/blob/main/examples/wakemarch_piv_validation.ipynb) uses a
|
|
60
|
+
separately downloaded public dataset and discloses inherited calibration.
|
|
61
|
+
Read [scientific scope](https://github.com/haibuihoang/wakemarch/blob/main/docs/SCIENCE.md) and [citation](https://github.com/haibuihoang/wakemarch/blob/main/CITATION.md) before
|
|
62
|
+
using results in research. The figure is generated by `examples/plot_wake.py`.
|
|
63
|
+
|
|
64
|
+
## Install and run
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
python -m pip install wakemarch
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Or, from a source checkout (the directory containing `pyproject.toml`):
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
python -m pip install .
|
|
74
|
+
python -I examples/first_wake.py
|
|
75
|
+
python -I tests/test_api.py
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Jupyter notebooks
|
|
79
|
+
|
|
80
|
+
The interactive entry point is `examples/wakemarch_api_test.ipynb`. It contains
|
|
81
|
+
editable inputs, live progress, hub-height/cross-plane plots, yaw comparisons,
|
|
82
|
+
and executable API checks. Run every cell with a fresh kernel.
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
python -m pip install 'wakemarch[notebooks]' # or '.[notebooks]' from source
|
|
86
|
+
python -m jupyterlab examples/wakemarch_api_test.ipynb
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
No measurement data, FLORIS, plotting or Jupyter are needed for the core example
|
|
90
|
+
or tests. For verifying built artifacts, see [release checks](https://github.com/haibuihoang/wakemarch/blob/main/docs/RELEASING.md).
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from wakemarch import Numerics, WakeModel
|
|
94
|
+
|
|
95
|
+
model = WakeModel(
|
|
96
|
+
D=126, H=90, U=8, CT=0.8, yaw_deg=25, TI=0.06,
|
|
97
|
+
numerics=Numerics(h_D=1 / 20),
|
|
98
|
+
)
|
|
99
|
+
result = model.solve(max_dist_D=10)
|
|
100
|
+
deficit = result.sample_deficit(x=5 * 126, y=0, z=90)
|
|
101
|
+
velocity = result.sample_streamwise_velocity(x=5 * 126, y=0, z=90)
|
|
102
|
+
print(deficit, velocity) # m/s
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Progress is enabled by default. Jupyter uses a native HTML progress bar (no widget
|
|
106
|
+
extension needed); terminals use a text bar. `model.solve(progress=False)` is
|
|
107
|
+
silent. A callable such as `progress=lambda completed_D, total_D: ...` receives
|
|
108
|
+
an initial zero and updates after each marching step. Total distance includes
|
|
109
|
+
the reconstruction buffer. The display closes on success, errors and interrupts;
|
|
110
|
+
callback exceptions propagate. Progress observes the solve without changing its
|
|
111
|
+
numerical operations. It measures downstream advancement, not a guaranteed time
|
|
112
|
+
remaining estimate.
|
|
113
|
+
|
|
114
|
+
## Define turbine performance once
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from wakemarch import Turbine, Numerics
|
|
118
|
+
|
|
119
|
+
turbine = Turbine.preset("nrel_5MW")
|
|
120
|
+
point = turbine.operating_point([6.0, 10.0], yaw_deg=20)
|
|
121
|
+
print(point.power_W, point.CT)
|
|
122
|
+
model = turbine.wake_model([6.0, 10.0], yaw_deg=20, TI=0.1,
|
|
123
|
+
numerics=Numerics(h_D=0.1))
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Use `Turbine.from_cp_ct(...)` or `Turbine.from_power_ct(...)` for your own curves,
|
|
127
|
+
or `Turbine.fixed(...)` for constant coefficients. See
|
|
128
|
+
[units, efficiency, averaging and table limits](https://github.com/haibuihoang/wakemarch/blob/main/docs/TURBINES.md). The scalar-CT
|
|
129
|
+
`WakeModel` API does not require a power curve.
|
|
130
|
+
|
|
131
|
+
## Conventions and API
|
|
132
|
+
|
|
133
|
+
- Physical inputs: `D`, `H` in metres (H ≥ D/2); `U` in m/s; `CT` is the
|
|
134
|
+
**unyawed** thrust coefficient; `TI` is a fraction, e.g. 0.06, not 6; yaw is in
|
|
135
|
+
degrees, |yaw| ≤ 50 (validated to 40).
|
|
136
|
+
- Positive yaw deflects towards negative `y`. `x` is downstream from the turbine,
|
|
137
|
+
`y` is lateral from its centre, and sampled `z` is height above ground.
|
|
138
|
+
- `Numerics` groups grid and stepping choices. Defaults are grid D/30, lateral
|
|
139
|
+
width 8D, top 3.5D **above hub**, dx=0.1D, requested storage interval=0.25D.
|
|
140
|
+
There is no automatic coarsening. Ground and open boundaries are enabled.
|
|
141
|
+
- `WakeModel` uses the recommended thrust exponent 2, vortex diffusivity factor
|
|
142
|
+
0.5, momentum fraction 0.95, and near-wake display ramp (0.5, 1D). Historical
|
|
143
|
+
empirical additions are not exposed in the public API.
|
|
144
|
+
- `solve()` returns an independent `WakeResult`; solving again never changes a
|
|
145
|
+
previous result. Inputs/settings are immutable dataclasses.
|
|
146
|
+
- Sampling accepts scalars or broadcastable arrays. `sample_deficit` includes
|
|
147
|
+
reconstruction and the display ramp; `sample_streamwise_velocity` subtracts
|
|
148
|
+
this from the same power-law background used by the model.
|
|
149
|
+
- Upstream of the tilted rotor (`x + y*tan(yaw) < 0`), deficit is zero. Outside
|
|
150
|
+
downstream stored support the default is an error. `bounds="zero"` explicitly
|
|
151
|
+
requests a zero-deficit extension (background streamwise velocity).
|
|
152
|
+
Nonfinite coordinates and negative heights raise errors.
|
|
153
|
+
- `result.x` is the stored **marching** coordinate x_s, not global x on a yawed
|
|
154
|
+
cross-plane. `result.z` is absolute height; `z_relative` is relative to hub.
|
|
155
|
+
`marching_deficit`, `streamwise_vorticity`, and
|
|
156
|
+
`streamwise_velocity_derivative` have axes `(x_s, z_relative, y)` and units m/s,
|
|
157
|
+
1/s and 1/s. They are read-only views; the histories do not include the display
|
|
158
|
+
ramp. Use the sampling methods for physical-space visualizations.
|
|
159
|
+
|
|
160
|
+
The kernel marches an extra yaw-dependent distance for reconstruction. With
|
|
161
|
+
dx=0.1D, requested storage 0.25D stores at 0.3D spacing (storage happens on
|
|
162
|
+
marching steps). Sampling uses actual stored support, not the nominal requested
|
|
163
|
+
distance.
|
|
164
|
+
|
|
165
|
+
## Scientific scope
|
|
166
|
+
|
|
167
|
+
This is a steady engineering model of one turbine in uniform or power-law-sheared
|
|
168
|
+
inflow, not an active downstream-turbine or farm solver. Input bounds are numerical
|
|
169
|
+
guards, not claims of validation over their entire range. It does not resolve
|
|
170
|
+
ground-boundary-layer dynamics or wake pressure gradients. It has known near-wake,
|
|
171
|
+
high-TI and high-yaw/far-wake limitations.
|
|
172
|
+
|
|
173
|
+
The vorticity advection construction is approximately conservative; the full
|
|
174
|
+
variable-coefficient diffusion equation does not establish exact circulation
|
|
175
|
+
conservation. Force-based initialization does not imply exact agreement of the
|
|
176
|
+
discrete vortex integral with its target. Better empirical predictions are not
|
|
177
|
+
proof of exact force or conservation consistency. Validation evidence is in the
|
|
178
|
+
accompanying paper; installing the package does not add new observational
|
|
179
|
+
validation.
|
|
180
|
+
|
|
181
|
+
Optional dependency groups: `[plot]`, `[notebooks]`, `[validation]`. They are
|
|
182
|
+
conveniences for documentation and data workflows, not required by the core.
|
|
183
|
+
Measurement and simulation datasets are not distributed with the package; each
|
|
184
|
+
keeps its own licence and access terms.
|
|
185
|
+
|
|
186
|
+
## Development and provenance
|
|
187
|
+
|
|
188
|
+
See [provenance](https://github.com/haibuihoang/wakemarch/blob/main/PROVENANCE.md). `wakemarch._kernel` is private; its many
|
|
189
|
+
historical research switches are not a supported public interface. The package
|
|
190
|
+
reproduces eight frozen reference cases of the authors' research solver to
|
|
191
|
+
rtol=1e-7, atol=1e-8 (`tools/check_release.py` runs the portable checks).
|
|
192
|
+
|
|
193
|
+
## Licence
|
|
194
|
+
|
|
195
|
+
BSD 3-Clause; see [LICENSE](https://github.com/haibuihoang/wakemarch/blob/main/LICENSE). The bundled reference turbine tables come
|
|
196
|
+
from FLORIS 4.6.2 and keep their own BSD 3-Clause licence
|
|
197
|
+
(`src/wakemarch/data/FLORIS_LICENSE.txt`).
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Provenance
|
|
2
|
+
|
|
3
|
+
WakeMarch packages the recommended configuration
|
|
4
|
+
(`YawedWakeSolver.recommended(...)`) of the authors' research solver
|
|
5
|
+
`src/curl_pns.py`, SHA-256
|
|
6
|
+
`f3dce8e95c77942caf59c8a0745d9ff6d2f9ed4ab642062cec46e752856a33fc`
|
|
7
|
+
(research repository commit `3027932`). The solver is project research code,
|
|
8
|
+
not the official implementation of any comparison model.
|
|
9
|
+
|
|
10
|
+
## Kernel
|
|
11
|
+
|
|
12
|
+
`src/wakemarch/_kernel.py` is a copy of that solver with:
|
|
13
|
+
|
|
14
|
+
- explanatory comments and an optional progress observer;
|
|
15
|
+
- caching of fixed advection and multipole geometry;
|
|
16
|
+
- reuse of the exact variable-coefficient diffusion factorization as the next
|
|
17
|
+
preconditioner after a stalled refinement.
|
|
18
|
+
|
|
19
|
+
The discrete operators, residual threshold (1e-9), precision, grid, physics and
|
|
20
|
+
fitted constants are unchanged. Iteration paths can differ, so equality is
|
|
21
|
+
checked numerically, not textually: the installed package reproduces eight
|
|
22
|
+
frozen reference cases of the research solver (zero, positive, negative and
|
|
23
|
+
40° yaw; shear; low/high turbulence; coarse and fine grids) at rtol=1e-7,
|
|
24
|
+
atol=1e-8. This holds from NumPy 1.24.4/SciPy 1.10.1 to NumPy 2.4/SciPy 1.17.
|
|
25
|
+
The reference arrays are kept with the authors' development records and are not
|
|
26
|
+
shipped.
|
|
27
|
+
|
|
28
|
+
## Added code
|
|
29
|
+
|
|
30
|
+
- The public API (`WakeModel`, `Numerics`, `WakeResult`), input checks,
|
|
31
|
+
explicitly named sampling methods and tests. No change to model equations or
|
|
32
|
+
fitted constants.
|
|
33
|
+
- `Turbine` (power/CT and CP/CT tables, presets, rotor-equivalent operating
|
|
34
|
+
point) and `Turbine.fixed` (constant coefficients). Three reference tables are
|
|
35
|
+
pinned from FLORIS 4.6.2 with their source hashes and licence
|
|
36
|
+
(`src/wakemarch/data/`).
|
|
37
|
+
|
|
38
|
+
An independently developed set of additional wake corrections was evaluated and
|
|
39
|
+
not adopted; it is not part of the package. Packaging does not establish new
|
|
40
|
+
scientific claims; see [scientific scope](docs/SCIENCE.md).
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# WakeMarch
|
|
2
|
+
|
|
3
|
+
WakeMarch is a steady, cross-plane marching wake model for a single yawed wind
|
|
4
|
+
turbine. It resolves the curled (kidney-shaped) wake produced by the
|
|
5
|
+
counter-rotating streamwise vortex pair of a yawed rotor, in uniform or
|
|
6
|
+
power-law-sheared inflow, and returns the wake deficit, streamwise vorticity and
|
|
7
|
+
velocity anywhere downstream.
|
|
8
|
+
|
|
9
|
+
The core depends only on NumPy (≥ 1.24) and SciPy (≥ 1.10) and needs
|
|
10
|
+
Python 3.11 or later. The upper bounds `<3`/`<2` are compatibility boundaries,
|
|
11
|
+
not evidence of tests on every release.
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
Start with the [user guide](https://github.com/haibuihoang/wakemarch/blob/main/docs/USER_GUIDE.md), then the
|
|
16
|
+
[API notebook](https://github.com/haibuihoang/wakemarch/blob/main/examples/wakemarch_api_test.ipynb) and
|
|
17
|
+
[resolution/cost notebook](https://github.com/haibuihoang/wakemarch/blob/main/examples/wakemarch_performance.ipynb).
|
|
18
|
+
[Turbine curves and presets](https://github.com/haibuihoang/wakemarch/blob/main/docs/TURBINES.md) and an
|
|
19
|
+
[interactive turbine notebook](https://github.com/haibuihoang/wakemarch/blob/main/examples/wakemarch_turbines.ipynb) accept user CP/CT
|
|
20
|
+
or power/CT tables, including rotor-wide velocity samples.
|
|
21
|
+
An optional [PIV comparison](https://github.com/haibuihoang/wakemarch/blob/main/examples/wakemarch_piv_validation.ipynb) uses a
|
|
22
|
+
separately downloaded public dataset and discloses inherited calibration.
|
|
23
|
+
Read [scientific scope](https://github.com/haibuihoang/wakemarch/blob/main/docs/SCIENCE.md) and [citation](https://github.com/haibuihoang/wakemarch/blob/main/CITATION.md) before
|
|
24
|
+
using results in research. The figure is generated by `examples/plot_wake.py`.
|
|
25
|
+
|
|
26
|
+
## Install and run
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
python -m pip install wakemarch
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Or, from a source checkout (the directory containing `pyproject.toml`):
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
python -m pip install .
|
|
36
|
+
python -I examples/first_wake.py
|
|
37
|
+
python -I tests/test_api.py
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Jupyter notebooks
|
|
41
|
+
|
|
42
|
+
The interactive entry point is `examples/wakemarch_api_test.ipynb`. It contains
|
|
43
|
+
editable inputs, live progress, hub-height/cross-plane plots, yaw comparisons,
|
|
44
|
+
and executable API checks. Run every cell with a fresh kernel.
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
python -m pip install 'wakemarch[notebooks]' # or '.[notebooks]' from source
|
|
48
|
+
python -m jupyterlab examples/wakemarch_api_test.ipynb
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
No measurement data, FLORIS, plotting or Jupyter are needed for the core example
|
|
52
|
+
or tests. For verifying built artifacts, see [release checks](https://github.com/haibuihoang/wakemarch/blob/main/docs/RELEASING.md).
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from wakemarch import Numerics, WakeModel
|
|
56
|
+
|
|
57
|
+
model = WakeModel(
|
|
58
|
+
D=126, H=90, U=8, CT=0.8, yaw_deg=25, TI=0.06,
|
|
59
|
+
numerics=Numerics(h_D=1 / 20),
|
|
60
|
+
)
|
|
61
|
+
result = model.solve(max_dist_D=10)
|
|
62
|
+
deficit = result.sample_deficit(x=5 * 126, y=0, z=90)
|
|
63
|
+
velocity = result.sample_streamwise_velocity(x=5 * 126, y=0, z=90)
|
|
64
|
+
print(deficit, velocity) # m/s
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Progress is enabled by default. Jupyter uses a native HTML progress bar (no widget
|
|
68
|
+
extension needed); terminals use a text bar. `model.solve(progress=False)` is
|
|
69
|
+
silent. A callable such as `progress=lambda completed_D, total_D: ...` receives
|
|
70
|
+
an initial zero and updates after each marching step. Total distance includes
|
|
71
|
+
the reconstruction buffer. The display closes on success, errors and interrupts;
|
|
72
|
+
callback exceptions propagate. Progress observes the solve without changing its
|
|
73
|
+
numerical operations. It measures downstream advancement, not a guaranteed time
|
|
74
|
+
remaining estimate.
|
|
75
|
+
|
|
76
|
+
## Define turbine performance once
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from wakemarch import Turbine, Numerics
|
|
80
|
+
|
|
81
|
+
turbine = Turbine.preset("nrel_5MW")
|
|
82
|
+
point = turbine.operating_point([6.0, 10.0], yaw_deg=20)
|
|
83
|
+
print(point.power_W, point.CT)
|
|
84
|
+
model = turbine.wake_model([6.0, 10.0], yaw_deg=20, TI=0.1,
|
|
85
|
+
numerics=Numerics(h_D=0.1))
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Use `Turbine.from_cp_ct(...)` or `Turbine.from_power_ct(...)` for your own curves,
|
|
89
|
+
or `Turbine.fixed(...)` for constant coefficients. See
|
|
90
|
+
[units, efficiency, averaging and table limits](https://github.com/haibuihoang/wakemarch/blob/main/docs/TURBINES.md). The scalar-CT
|
|
91
|
+
`WakeModel` API does not require a power curve.
|
|
92
|
+
|
|
93
|
+
## Conventions and API
|
|
94
|
+
|
|
95
|
+
- Physical inputs: `D`, `H` in metres (H ≥ D/2); `U` in m/s; `CT` is the
|
|
96
|
+
**unyawed** thrust coefficient; `TI` is a fraction, e.g. 0.06, not 6; yaw is in
|
|
97
|
+
degrees, |yaw| ≤ 50 (validated to 40).
|
|
98
|
+
- Positive yaw deflects towards negative `y`. `x` is downstream from the turbine,
|
|
99
|
+
`y` is lateral from its centre, and sampled `z` is height above ground.
|
|
100
|
+
- `Numerics` groups grid and stepping choices. Defaults are grid D/30, lateral
|
|
101
|
+
width 8D, top 3.5D **above hub**, dx=0.1D, requested storage interval=0.25D.
|
|
102
|
+
There is no automatic coarsening. Ground and open boundaries are enabled.
|
|
103
|
+
- `WakeModel` uses the recommended thrust exponent 2, vortex diffusivity factor
|
|
104
|
+
0.5, momentum fraction 0.95, and near-wake display ramp (0.5, 1D). Historical
|
|
105
|
+
empirical additions are not exposed in the public API.
|
|
106
|
+
- `solve()` returns an independent `WakeResult`; solving again never changes a
|
|
107
|
+
previous result. Inputs/settings are immutable dataclasses.
|
|
108
|
+
- Sampling accepts scalars or broadcastable arrays. `sample_deficit` includes
|
|
109
|
+
reconstruction and the display ramp; `sample_streamwise_velocity` subtracts
|
|
110
|
+
this from the same power-law background used by the model.
|
|
111
|
+
- Upstream of the tilted rotor (`x + y*tan(yaw) < 0`), deficit is zero. Outside
|
|
112
|
+
downstream stored support the default is an error. `bounds="zero"` explicitly
|
|
113
|
+
requests a zero-deficit extension (background streamwise velocity).
|
|
114
|
+
Nonfinite coordinates and negative heights raise errors.
|
|
115
|
+
- `result.x` is the stored **marching** coordinate x_s, not global x on a yawed
|
|
116
|
+
cross-plane. `result.z` is absolute height; `z_relative` is relative to hub.
|
|
117
|
+
`marching_deficit`, `streamwise_vorticity`, and
|
|
118
|
+
`streamwise_velocity_derivative` have axes `(x_s, z_relative, y)` and units m/s,
|
|
119
|
+
1/s and 1/s. They are read-only views; the histories do not include the display
|
|
120
|
+
ramp. Use the sampling methods for physical-space visualizations.
|
|
121
|
+
|
|
122
|
+
The kernel marches an extra yaw-dependent distance for reconstruction. With
|
|
123
|
+
dx=0.1D, requested storage 0.25D stores at 0.3D spacing (storage happens on
|
|
124
|
+
marching steps). Sampling uses actual stored support, not the nominal requested
|
|
125
|
+
distance.
|
|
126
|
+
|
|
127
|
+
## Scientific scope
|
|
128
|
+
|
|
129
|
+
This is a steady engineering model of one turbine in uniform or power-law-sheared
|
|
130
|
+
inflow, not an active downstream-turbine or farm solver. Input bounds are numerical
|
|
131
|
+
guards, not claims of validation over their entire range. It does not resolve
|
|
132
|
+
ground-boundary-layer dynamics or wake pressure gradients. It has known near-wake,
|
|
133
|
+
high-TI and high-yaw/far-wake limitations.
|
|
134
|
+
|
|
135
|
+
The vorticity advection construction is approximately conservative; the full
|
|
136
|
+
variable-coefficient diffusion equation does not establish exact circulation
|
|
137
|
+
conservation. Force-based initialization does not imply exact agreement of the
|
|
138
|
+
discrete vortex integral with its target. Better empirical predictions are not
|
|
139
|
+
proof of exact force or conservation consistency. Validation evidence is in the
|
|
140
|
+
accompanying paper; installing the package does not add new observational
|
|
141
|
+
validation.
|
|
142
|
+
|
|
143
|
+
Optional dependency groups: `[plot]`, `[notebooks]`, `[validation]`. They are
|
|
144
|
+
conveniences for documentation and data workflows, not required by the core.
|
|
145
|
+
Measurement and simulation datasets are not distributed with the package; each
|
|
146
|
+
keeps its own licence and access terms.
|
|
147
|
+
|
|
148
|
+
## Development and provenance
|
|
149
|
+
|
|
150
|
+
See [provenance](https://github.com/haibuihoang/wakemarch/blob/main/PROVENANCE.md). `wakemarch._kernel` is private; its many
|
|
151
|
+
historical research switches are not a supported public interface. The package
|
|
152
|
+
reproduces eight frozen reference cases of the authors' research solver to
|
|
153
|
+
rtol=1e-7, atol=1e-8 (`tools/check_release.py` runs the portable checks).
|
|
154
|
+
|
|
155
|
+
## Licence
|
|
156
|
+
|
|
157
|
+
BSD 3-Clause; see [LICENSE](https://github.com/haibuihoang/wakemarch/blob/main/LICENSE). The bundled reference turbine tables come
|
|
158
|
+
from FLORIS 4.6.2 and keep their own BSD 3-Clause licence
|
|
159
|
+
(`src/wakemarch/data/FLORIS_LICENSE.txt`).
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Development and release verification
|
|
2
|
+
|
|
3
|
+
## Portable checks
|
|
4
|
+
|
|
5
|
+
From the package root, in an environment with Python 3.11+ and setuptools/wheel:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
python -m pip install 'setuptools>=77' wheel
|
|
9
|
+
python -I -B tools/check_release.py --output /tmp/wakemarch-check --notebooks
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Use any new writable output directory on Windows instead of `/tmp/...`. The
|
|
13
|
+
driver builds a wheel and sdist, creates fresh isolated environments, resolves
|
|
14
|
+
dependencies, checks import origins, runs `pip check`, tests, the example and
|
|
15
|
+
executable documentation. It checks the built source contains the guide and
|
|
16
|
+
notebooks. `--notebooks` adds figure generation and fresh-kernel execution from
|
|
17
|
+
the extracted source using the installed wheel. Outputs and logs stay outside
|
|
18
|
+
the source tree. `--minimum` pins the declared floors, NumPy 1.24.4 and
|
|
19
|
+
SciPy 1.10.1.
|
|
20
|
+
|
|
21
|
+
For an offline local check only:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
python -I -B tools/check_release.py --offline --notebooks --output /tmp/wakemarch-offline
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This mode inherits local numerical/notebook/build dependencies; it is **not**
|
|
28
|
+
fresh dependency resolution. Its result records `isolated_dependencies=false`.
|
|
29
|
+
The authors additionally compare every release with eight frozen reference
|
|
30
|
+
cases of the research solver at rtol=1e-7, atol=1e-8; those reference arrays are
|
|
31
|
+
not shipped.
|
|
32
|
+
|
|
33
|
+
## Continuous integration
|
|
34
|
+
|
|
35
|
+
`.github/workflows/package.yml` runs wheel/sdist checks on Linux, macOS and
|
|
36
|
+
Windows with Python 3.11–3.14, plus a Linux Python 3.11 minimum-dependency job.
|
|
37
|
+
The Linux Python 3.11 job also executes the data-free notebooks. Dependency
|
|
38
|
+
upper bounds are not evidence of compatibility with every future version.
|
|
39
|
+
The workflow has read-only repository access.
|
|
40
|
+
|
|
41
|
+
## Publishing
|
|
42
|
+
|
|
43
|
+
`.github/workflows/publish.yml` builds the distributions and uploads them with
|
|
44
|
+
PyPI trusted publishing (no API tokens): manually to TestPyPI
|
|
45
|
+
(`workflow_dispatch`, target `testpypi`) or to PyPI when a GitHub release is
|
|
46
|
+
published. The trusted publisher must be configured on (Test)PyPI for this
|
|
47
|
+
repository, workflow `publish.yml` and environments `testpypi`/`pypi`.
|
|
48
|
+
The workflow refuses to run while any release file still contains the marker
|
|
49
|
+
`PENDING-D2` (author/copyright metadata not yet supplied) or the classifier
|
|
50
|
+
`Private :: Do Not Upload`.
|
|
51
|
+
|
|
52
|
+
Release steps: update `version`, `CHANGELOG.md` and `CITATION.cff`; run the
|
|
53
|
+
portable checks (normal, `--minimum`, `--notebooks`); confirm CI is green;
|
|
54
|
+
rehearse on TestPyPI; then publish a GitHub release.
|
|
55
|
+
|
|
56
|
+
This follows the [GitHub Python CI guide](https://docs.github.com/en/actions/tutorials/build-and-test-code/python),
|
|
57
|
+
the [PyPA packaging guide](https://packaging.python.org/en/latest/tutorials/packaging-projects/)
|
|
58
|
+
and [PyPA trusted publishing](https://docs.pypi.org/trusted-publishers/).
|
|
59
|
+
|
|
60
|
+
## Paper reproducibility
|
|
61
|
+
|
|
62
|
+
The paper's figures were produced with the authors' research solver. Record the
|
|
63
|
+
package version used for any figure only after reproducing it with that version.
|
|
64
|
+
`docs/release-metadata.json` records licence, repository and DOI metadata.
|
|
65
|
+
|
|
66
|
+
## Notebooks
|
|
67
|
+
|
|
68
|
+
To run all four notebooks with a registered local kernel and an existing
|
|
69
|
+
download of the PIV data (no automatic data access):
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
python -I -B tools/run_notebooks.py --output /tmp/wakemarch-notebooks --piv-data /path/to/Bastankhah_jfm_2016.h5
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The CI notebook job executes only the three data-free examples. The PIV notebook
|
|
76
|
+
is checked locally against the checksum-pinned public file; this does not create
|
|
77
|
+
a redistributable data fixture or a blind-validation claim.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Scientific scope and evidence
|
|
2
|
+
|
|
3
|
+
WakeMarch implements the accepted recommended single-turbine model: thrust
|
|
4
|
+
exponent 2, vortex diffusivity factor 0.5, momentum fraction 0.95, and display
|
|
5
|
+
ramp (0.5, 1D). The package does not expose historical optional empirical
|
|
6
|
+
corrections as supported public settings. The combined independent-correction
|
|
7
|
+
experiment remains archived and is not the production model.
|
|
8
|
+
|
|
9
|
+
The intended first audience is researchers. The model has known near-wake,
|
|
10
|
+
high-turbulence and high-yaw/far-wake limitations. It does not resolve wake
|
|
11
|
+
pressure gradients or ground-boundary-layer dynamics. Input guards are not an
|
|
12
|
+
experimental validation envelope. Engineering and operational use requires
|
|
13
|
+
application-specific assessment; no farm solver or active downstream-turbine
|
|
14
|
+
model is provided.
|
|
15
|
+
|
|
16
|
+
Advection is approximately conservative; variable-coefficient diffusion does not
|
|
17
|
+
establish exact circulation conservation. Force-based initialization does not
|
|
18
|
+
guarantee exact equality of the discrete vortex integral and its target. Better
|
|
19
|
+
empirical predictions are not proof of exact conservation or force consistency.
|
|
20
|
+
|
|
21
|
+
## What the software checks establish
|
|
22
|
+
|
|
23
|
+
- API tests: input conventions, sampling, progress, independent results and
|
|
24
|
+
diffusion residual checks.
|
|
25
|
+
- Frozen-array comparisons: implementation agreement with eight accepted
|
|
26
|
+
research cases at rtol=1e-7, atol=1e-8. These are not observational error bars.
|
|
27
|
+
- Grid notebook: differences between numerical resolutions for a specified case.
|
|
28
|
+
Its finest grid is a reference, not a converged solution or observation.
|
|
29
|
+
- Historical numerical tests: manufactured operators, symmetry and approximate
|
|
30
|
+
invariants, subject to their stated tolerances.
|
|
31
|
+
- Historical measurement comparisons: scientific evidence with calibration and
|
|
32
|
+
preprocessing choices described in the research reports, not recreated by a
|
|
33
|
+
successful package installation.
|
|
34
|
+
|
|
35
|
+
## Data and validation boundary
|
|
36
|
+
|
|
37
|
+
The accompanying paper compares the model with PALM LES, hub-height PIV,
|
|
38
|
+
Oldenburg lidar and NTNU/ForWind LDA data. The LES data used in the paper are not
|
|
39
|
+
distributed with this package. Other datasets have their own access and license
|
|
40
|
+
terms; a code license cannot grant redistribution rights to them. No measurement
|
|
41
|
+
files are included in the wheel or source distribution.
|
|
42
|
+
|
|
43
|
+
The optional [PIV measurement notebook](../examples/wakemarch_piv_validation.ipynb)
|
|
44
|
+
uses [Bastankhah and Porté-Agel's Zenodo v1 dataset](https://zenodo.org/records/3607598),
|
|
45
|
+
DOI 10.5281/zenodo.3607598. Obtain the HDF5 file separately and inspect its terms;
|
|
46
|
+
the notebook checks the record's MD5 and records SHA-256. No data are bundled.
|
|
47
|
+
It inherits the historical unyawed CT=0.9 and k=0.024 calibration, converts k to
|
|
48
|
+
equivalent TI and performs no new fit. These cases were previously examined
|
|
49
|
+
during model development: this is not a new blind test. Its same-point RMS
|
|
50
|
+
comparison differs from historical scoreboard preprocessing and metrics.
|
|
51
|
+
Do not label the introductory or grid notebooks as measurement validation.
|
|
52
|
+
Record geometry, inflow/CT values, yaw sign and coordinate mapping, uncertainty
|
|
53
|
+
and calibration exposure. Evaluate model and data on the same measurement support.
|
|
54
|
+
For tower/floor-contaminated laboratory planes, document the rotor-band mask.
|
|
55
|
+
|
|
56
|
+
Do not silently substitute synthetic data when measurements are missing. Farm
|
|
57
|
+
validation additionally requires turbine interaction, local inflow and thrust
|
|
58
|
+
definitions; the single-wake downstream rotor u³ proxy is insufficient.
|
|
59
|
+
|
|
60
|
+
## Paper linkage
|
|
61
|
+
|
|
62
|
+
`release-metadata.json` records publication metadata. The paper's figures were
|
|
63
|
+
produced with the authors' research solver, which this package reproduces to
|
|
64
|
+
rtol=1e-7 on eight reference cases; the paper-specific software version is
|
|
65
|
+
recorded once figure reproduction with the package has been verified. Until the
|
|
66
|
+
paper reference is available, see [citation](../CITATION.md).
|
|
67
|
+
|
|
68
|
+
## Reference turbine performance inputs
|
|
69
|
+
|
|
70
|
+
The package now includes reference power/CT tables and a rotor-equivalent
|
|
71
|
+
operating model; see [TURBINES.md](TURBINES.md). This adds no farm validation or
|
|
72
|
+
new wake physics. CP converted from the power tables is electrical-equivalent.
|
|
73
|
+
User CP inputs require an explicit efficiency convention. Effective-speed yaw
|
|
74
|
+
power mapping is an approximation, not a controller simulation.
|