pystormflow 0.2.1__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.
@@ -0,0 +1,14 @@
1
+ # Cargo configuration for pystormflow
2
+ # These settings optimize the build for the user's specific CPU
3
+
4
+ [build]
5
+ # Use all available CPU cores for compilation
6
+ jobs = -1
7
+
8
+ [target.'cfg(target_arch = "x86_64")']
9
+ # Enable native CPU optimizations (AVX, AVX2, etc. if available)
10
+ rustflags = ["-C", "target-cpu=native"]
11
+
12
+ [target.'cfg(target_arch = "aarch64")']
13
+ # Enable native CPU optimizations for ARM64 (Apple Silicon, etc.)
14
+ rustflags = ["-C", "target-cpu=native"]
@@ -0,0 +1,24 @@
1
+ # Change log pystormflow
2
+
3
+ This file contains an overview of the changes made to pystormflow, the Python interface to the Stormflow CFD solver. See the [Stormflow change log](../../stormflow/CHANGELOG.md) for changes to the solver, and the [Stormbird change log](../../stormbird/CHANGELOG.md) for changes to the actuator line model.
4
+
5
+ ## 0.3.0 - 2026-10-31
6
+ ### Breaking changes
7
+ - Depends on the published versions of Stormflow 0.3.0 and Stormbird 0.12.0. There are no changes to the Python interface itself, but the setup files may need to be updated. See the [Stormflow change log](../../stormflow/CHANGELOG.md) for the changes to the solver, such as the new `boundary_condition_type` setting, and the [Stormbird change log](../../stormbird/CHANGELOG.md) for the changes to the actuator line model, such as the new dynamic stall model.
8
+
9
+ ### Other changes
10
+ - Invalid input raises a Python exception rather than a panic, in the same way as in pystormbird: creating a `Simulation` from a setup string that can not be read raises a `ValueError`, and reading simulation results from file with `SimulationResult.from_json_file` or `SimulationResult.result_history_from_file` raises an `OSError` if the file can not be read, and a `ValueError` if the content can not be parsed. Settings that are found to be invalid when the simulation is built in Stormflow still give a panic.
11
+ - New `section_models_internal_state` and `amount_of_stall` properties on the `SectionalForcesInput` class, as in pystormbird.
12
+ - The source distribution is compiled with native CPU optimizations, through a new `.cargo/config.toml`, as in pystormbird.
13
+ - The single rotor example is replaced by the new `rotor_sails/deybach_wind_tunnel` example, with one or two rotor sails in a wind tunnel, compared against the experiments by Deybach et al.
14
+
15
+ ## 0.2.1
16
+ - Depends on Stormflow 0.2.1 and Stormbird 0.11.1. The main changes are new experimental limits on the lifting line correction in the actuator line model. See the [Stormflow change log](../../stormflow/CHANGELOG.md) and the [Stormbird change log](../../stormbird/CHANGELOG.md).
17
+
18
+ ## 0.2.0 - 2026-10-23
19
+ ### Breaking changes
20
+ - Depends on Stormflow 0.2.0, Stormbird 0.11.0 and Stormath 0.4.0. The input format for the Stormbird models has changed in Stormbird 0.11.0, so setup files may need to be updated.
21
+ - The `gyroscopic` property of the `SectionalForces` class is renamed to `gyroscopic_moment`, as the gyroscopic effect is now a pure moment in Stormbird. The `gyroscopic` property of the `IntegratedValues` class is unchanged.
22
+
23
+ ## 0.1.0
24
+ The first version.
@@ -919,7 +919,7 @@ dependencies = [
919
919
 
920
920
  [[package]]
921
921
  name = "pystormflow"
922
- version = "0.2.1"
922
+ version = "0.3.0"
923
923
  dependencies = [
924
924
  "pyo3",
925
925
  "stormath",
@@ -1141,9 +1141,9 @@ dependencies = [
1141
1141
 
1142
1142
  [[package]]
1143
1143
  name = "stormbird"
1144
- version = "0.11.1"
1144
+ version = "0.12.0"
1145
1145
  source = "registry+https://github.com/rust-lang/crates.io-index"
1146
- checksum = "fdfe6efffc14873788f547e5294bd9c881f24b84e033a2e02c1c2112fe303469"
1146
+ checksum = "58dd3ef773ce702fd01e8928fd09c122b71dfe0d611850d1c066cc775e212929"
1147
1147
  dependencies = [
1148
1148
  "serde",
1149
1149
  "serde_json",
@@ -1152,9 +1152,9 @@ dependencies = [
1152
1152
 
1153
1153
  [[package]]
1154
1154
  name = "stormflow"
1155
- version = "0.2.1"
1155
+ version = "0.3.0"
1156
1156
  source = "registry+https://github.com/rust-lang/crates.io-index"
1157
- checksum = "e1631c825f7e6cd9329e27e45e4fb26e9481a2fe1e6c3bb737968190fa268e1e"
1157
+ checksum = "af8cf495075d36001dbac15413c67142fd30915a5ced8dc28a0eba76e8c8ba2c"
1158
1158
  dependencies = [
1159
1159
  "bytemuck",
1160
1160
  "clap",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "pystormflow"
3
- version = "0.2.1"
3
+ version = "0.3.0"
4
4
  authors = ["Jarle Kramer <jarle.kramer@gmail.com>"]
5
5
  description = "Python interface to the Stormflow CFD solver."
6
6
  homepage = "https://github.com/NTNU-IMT/stormbird"
@@ -16,8 +16,8 @@ crate-type = ["cdylib"]
16
16
  [dependencies]
17
17
  pyo3 = "0.29.0"
18
18
  stormath = {version = "0.4.0", features=["single_precision"]}
19
- stormbird = { version="0.11.1", features=["single_precision"]}
20
- stormflow = { version="0.2.1" }
19
+ stormbird = { version = "0.12.0", features = ["single_precision"] }
20
+ stormflow = "0.3.0"
21
21
 
22
22
  [profile.release]
23
23
  opt-level = 3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pystormflow
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Science/Research
6
6
  Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
@@ -35,7 +35,8 @@ module-name = "pystormflow._native"
35
35
  python-source = "."
36
36
  features = ["pyo3/extension-module"]
37
37
  profile = "release"
38
- # The examples are not needed in the source distribution
38
+ # The examples and the notes for the maintainer are not needed in the source distribution
39
39
  exclude = [
40
40
  { path = "examples/**/*", format = "sdist" },
41
+ { path = "maintainer_cheat_sheet.md", format = "sdist" },
41
42
  ]
@@ -9,6 +9,10 @@ class SectionalForcesInput:
9
9
  @property
10
10
  def angles_of_attack(self) -> list[float]: ...
11
11
  @property
12
+ def section_models_internal_state(self) -> list[float]: ...
13
+ @property
14
+ def amount_of_stall(self) -> list[float]: ...
15
+ @property
12
16
  def acceleration(self) -> list[list[float]]: ...
13
17
  @property
14
18
  def rotation_velocity(self) -> list[float]: ...
@@ -4,9 +4,12 @@
4
4
 
5
5
  use pyo3::prelude::*;
6
6
  use pyo3::types::PyType;
7
+ use pyo3::exceptions::{PyIOError, PyValueError};
7
8
 
8
9
  use stormath::type_aliases::Float;
9
10
 
11
+ use stormbird::error::Error;
12
+
10
13
  use stormbird::common_utils::results::simulation::SimulationResult as SimulationResultRust;
11
14
  use stormbird::common_utils::forces_and_moments::SectionalForces as SectionalForcesRust;
12
15
  use stormbird::common_utils::forces_and_moments::IntegratedValues as IntegratedValuesRust;
@@ -35,6 +38,20 @@ impl SectionalForcesInput {
35
38
  self.data.angles_of_attack.clone()
36
39
  }
37
40
 
41
+ #[getter]
42
+ /// The internal state given to the section model on each line element
43
+ pub fn section_models_internal_state(&self) -> Vec<Float> {
44
+ self.data.section_models_internal_state.clone()
45
+ }
46
+
47
+ #[getter]
48
+ /// The amount of stall used for the lift and drag on each line element. This is the dynamic
49
+ /// amount of stall for wings with a dynamic stall model, and zero for section models that are
50
+ /// not built on the foil model.
51
+ pub fn amount_of_stall(&self) -> Vec<Float> {
52
+ self.data.amount_of_stall.clone()
53
+ }
54
+
38
55
  #[getter]
39
56
  pub fn acceleration(&self) -> Vec<[Float; 3]> {
40
57
  self.data.acceleration.iter().map(|v| v.0).collect()
@@ -123,17 +140,21 @@ pub struct SimulationResult {
123
140
  #[pymethods]
124
141
  impl SimulationResult {
125
142
  #[classmethod]
126
- pub fn from_json_file(_cls: &Bound<'_, PyType>, file_path: String) -> SimulationResult {
127
- let data = SimulationResultRust::from_json(&file_path).unwrap();
128
-
129
- SimulationResult { data }
143
+ pub fn from_json_file(_cls: &Bound<'_, PyType>, file_path: String) -> PyResult<SimulationResult> {
144
+ let data = SimulationResultRust::from_json(&file_path).map_err(|e| {
145
+ Self::read_file_error(&file_path, e)
146
+ })?;
147
+
148
+ Ok(SimulationResult { data })
130
149
  }
131
150
 
132
151
  #[classmethod]
133
- pub fn result_history_from_file(_cls: &Bound<'_, PyType>, file_path: String) -> Vec<SimulationResult> {
134
- let rust_vector = SimulationResultRust::result_history_from_file(&file_path).unwrap();
152
+ pub fn result_history_from_file(_cls: &Bound<'_, PyType>, file_path: String) -> PyResult<Vec<SimulationResult>> {
153
+ let rust_vector = SimulationResultRust::result_history_from_file(&file_path).map_err(|e| {
154
+ Self::read_file_error(&file_path, e)
155
+ })?;
135
156
 
136
- rust_vector.iter().map(|v| SimulationResult { data: v.clone() }).collect()
157
+ Ok(rust_vector.iter().map(|v| SimulationResult { data: v.clone() }).collect())
137
158
  }
138
159
 
139
160
  #[getter]
@@ -209,3 +230,16 @@ impl SimulationResult {
209
230
  self.data.write_to_file(&file_path).expect("Error from write to file")
210
231
  }
211
232
  }
233
+
234
+ impl SimulationResult {
235
+ /// Converts an error from reading a result file to a Python error. Errors from reading the
236
+ /// file become an OSError, while errors from parsing the content become a ValueError.
237
+ fn read_file_error(file_path: &str, error: Error) -> PyErr {
238
+ let message = format!("Failed to read simulation result from file {}: {}", file_path, error);
239
+
240
+ match error {
241
+ Error::IoError(_) => PyIOError::new_err(message),
242
+ _ => PyValueError::new_err(message),
243
+ }
244
+ }
245
+ }
@@ -1,6 +1,7 @@
1
1
 
2
2
  use pyo3::prelude::*;
3
3
  use pyo3::types::PyBytes;
4
+ use pyo3::exceptions::PyValueError;
4
5
 
5
6
  use stormath::type_aliases::Float;
6
7
  use stormflow::simulation::Simulation as SimulationRust;
@@ -15,10 +16,12 @@ pub struct Simulation {
15
16
  #[pymethods]
16
17
  impl Simulation {
17
18
  #[new]
18
- pub fn new(setup_string: String) -> Self {
19
- Self {
20
- data: SimulationRust::new_from_string(&setup_string).unwrap()
21
- }
19
+ pub fn new(setup_string: String) -> PyResult<Self> {
20
+ let data = SimulationRust::new_from_string(&setup_string).map_err(|e| {
21
+ PyValueError::new_err(format!("Failed to create simulation from string: {}", e))
22
+ })?;
23
+
24
+ Ok(Self { data })
22
25
  }
23
26
 
24
27
  pub fn time_step_from_courant_number(&self, courant_number: Float) -> Float {
@@ -1,14 +0,0 @@
1
- # Change log pystormflow
2
-
3
- This file contains an overview of the changes made to pystormflow, the Python interface to the Stormflow CFD solver. See the [Stormflow change log](../../stormflow/CHANGELOG.md) for changes to the solver, and the [Stormbird change log](../../stormbird/CHANGELOG.md) for changes to the actuator line model.
4
-
5
- ## 0.2.1
6
- - Depends on Stormflow 0.2.1 and Stormbird 0.11.1. The main changes are new experimental limits on the lifting line correction in the actuator line model. See the [Stormflow change log](../../stormflow/CHANGELOG.md) and the [Stormbird change log](../../stormbird/CHANGELOG.md).
7
-
8
- ## 0.2.0 - 2026-10-23
9
- ### Breaking changes
10
- - Depends on Stormflow 0.2.0, Stormbird 0.11.0 and Stormath 0.4.0. The input format for the Stormbird models has changed in Stormbird 0.11.0, so setup files may need to be updated.
11
- - The `gyroscopic` property of the `SectionalForces` class is renamed to `gyroscopic_moment`, as the gyroscopic effect is now a pure moment in Stormbird. The `gyroscopic` property of the `IntegratedValues` class is unchanged.
12
-
13
- ## 0.1.0
14
- The first version.
File without changes
File without changes
File without changes
File without changes