Skip to content

Commit d25b912

Browse files
Merge pull request #6 from aeronauty-flexcompute/chore/merge-bl-wake-into-main
merge: integrate latest BL wake visualization updates
2 parents dfa985b + bd48460 commit d25b912

11 files changed

Lines changed: 1233 additions & 266 deletions

File tree

crates/rustfoil-solver/src/inviscid/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub mod velocity;
3030
pub mod smoke;
3131

3232
pub use error::SolverError;
33-
pub use velocity::{build_streamlines, velocity_at, is_inside_airfoil, psi_at, compute_psi_grid, compute_psi_grid_with_interior, StreamlineOptions};
33+
pub use velocity::{build_streamlines, build_streamlines_viscous, velocity_at, velocity_at_with_sources, is_inside_airfoil, psi_at, psi_at_with_sources, compute_psi_grid, compute_psi_grid_with_interior, compute_psi_grid_with_sources, StreamlineOptions, WakePanels};
3434
pub use smoke::SmokeSystem;
3535

3636
use nalgebra::{DMatrix, DVector};

crates/rustfoil-solver/src/inviscid/smoke.rs

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
//! Spawns blobs of particles at regular intervals. Each particle is
44
//! individually advected through the flow field using RK2 integration.
55
6-
use super::velocity::{velocity_at, is_inside_airfoil, psi_at};
6+
use super::velocity::{
7+
is_inside_airfoil, is_inside_polygon, psi_at, psi_at_with_sources, velocity_at,
8+
velocity_at_with_sources, WakePanels,
9+
};
710
use rustfoil_core::Point;
811

912
/// A particle in the smoke system.
@@ -151,6 +154,77 @@ impl SmokeSystem {
151154
self.particles.retain(|p| p.age < self.max_age);
152155
}
153156

157+
/// Update particles using a source-inclusive viscous field.
158+
pub fn update_with_sources(
159+
&mut self,
160+
nodes: &[Point],
161+
gamma: &[f64],
162+
sigma: &[f64],
163+
alpha: f64,
164+
v_inf: f64,
165+
wake_panels: Option<&WakePanels>,
166+
effective_body: Option<&[Point]>,
167+
dt: f64,
168+
) {
169+
self.time_since_spawn += dt;
170+
171+
if self.time_since_spawn >= self.spawn_interval {
172+
self.spawn_blobs();
173+
self.time_since_spawn = 0.0;
174+
}
175+
176+
for particle in &mut self.particles {
177+
particle.age += dt;
178+
if particle.age >= self.max_age {
179+
continue;
180+
}
181+
182+
if is_inside_airfoil(particle.x, particle.y, nodes)
183+
|| effective_body.is_some_and(|poly| is_inside_polygon(particle.x, particle.y, poly))
184+
{
185+
particle.age = self.max_age;
186+
continue;
187+
}
188+
189+
let (u1, v1) = velocity_at_with_sources(
190+
particle.x,
191+
particle.y,
192+
nodes,
193+
gamma,
194+
sigma,
195+
alpha,
196+
v_inf,
197+
wake_panels,
198+
);
199+
200+
let mid_x = particle.x + 0.5 * dt * u1;
201+
let mid_y = particle.y + 0.5 * dt * v1;
202+
203+
let (u2, v2) = velocity_at_with_sources(
204+
mid_x,
205+
mid_y,
206+
nodes,
207+
gamma,
208+
sigma,
209+
alpha,
210+
v_inf,
211+
wake_panels,
212+
);
213+
214+
let new_x = particle.x + dt * u2;
215+
let new_y = particle.y + dt * v2;
216+
if effective_body.is_some_and(|poly| is_inside_polygon(new_x, new_y, poly)) {
217+
particle.age = self.max_age;
218+
continue;
219+
}
220+
221+
particle.x = new_x;
222+
particle.y = new_y;
223+
}
224+
225+
self.particles.retain(|p| p.age < self.max_age);
226+
}
227+
154228
/// Get all particle positions as a flat array [x0, y0, x1, y1, ...].
155229
pub fn get_positions(&self) -> Vec<f64> {
156230
let mut positions = Vec::with_capacity(self.particles.len() * 2);
@@ -196,6 +270,24 @@ impl SmokeSystem {
196270
.collect()
197271
}
198272

273+
/// Get stream function values using a source-inclusive viscous field.
274+
pub fn get_psi_values_with_sources(
275+
&self,
276+
nodes: &[Point],
277+
gamma: &[f64],
278+
sigma: &[f64],
279+
alpha: f64,
280+
v_inf: f64,
281+
wake_panels: Option<&WakePanels>,
282+
) -> Vec<f64> {
283+
self.particles
284+
.iter()
285+
.map(|p| {
286+
psi_at_with_sources(p.x, p.y, nodes, gamma, sigma, alpha, v_inf, wake_panels)
287+
})
288+
.collect()
289+
}
290+
199291
/// Get the number of active particles.
200292
pub fn particle_count(&self) -> usize {
201293
self.particles.len()

0 commit comments

Comments
 (0)