1pub type FlowFn = fn(edge_idx: usize, t: f64) -> f64;
3
4pub fn flow_constant(_edge: usize, _t: f64) -> f64 {
6 1.0
7}
8
9pub fn flow_sinusoidal(edge: usize, t: f64) -> f64 {
11 1.0 + 0.5 * (0.5 * t + edge as f64 * 0.3).sin()
12}
13
14pub fn flow_pulse(edge: usize, t: f64) -> f64 {
16 let period = 4.0;
17 let phase = t.rem_euclid(period);
18 let pw = 0.3 + 0.05 * (edge % 5) as f64;
19 if phase < pw { 3.0 } else { 0.5 }
20}
21
22pub fn flow_random_walk(edge: usize, t: f64) -> f64 {
24 let seed = (t * 100.0) as i64 + edge as i64 * 137;
25 let s = (seed.wrapping_mul(2654435761)) as u64;
27 let s = ((s >> 16) ^ s).wrapping_mul(0x45d9f3b);
28 let s = ((s >> 16) ^ s).wrapping_mul(0x45d9f3b);
29 let s = (s >> 16) ^ s;
30 0.5 + (s & 0x7FFF_FFFF) as f64 / 0x7FFF_FFFF as f64
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36
37 #[test]
38 fn test_constant_flow() {
39 let v = flow_constant(0, 0.0);
40 assert!((v - 1.0).abs() < 1e-12);
41 let v = flow_constant(5, 100.0);
42 assert!((v - 1.0).abs() < 1e-12);
43 }
44
45 #[test]
46 fn test_sinusoidal_range() {
47 for edge in 0..10 {
48 for t in [0.0, 1.0, 10.0, 100.0] {
49 let v = flow_sinusoidal(edge, t);
50 assert!(v >= 0.5 && v <= 1.5, "sinusoidal in [0.5, 1.5]");
51 }
52 }
53 }
54
55 #[test]
56 fn test_pulse_oscillation() {
57 let v_low = flow_pulse(0, 0.0);
58 let v_high = flow_pulse(0, 0.15);
59 let v_low2 = flow_pulse(0, 2.0);
60 assert!(v_high >= v_low, "pulse has high and low phases");
61 assert!((v_low - 0.5).abs() < 1e-6 || (v_low - 3.0).abs() < 1e-6);
62 assert!((v_low2 - 0.5).abs() < 1e-6);
63 }
64
65 #[test]
66 fn test_random_walk_range() {
67 for edge in 0..5 {
68 for t in [0.0, 1.0, 10.0] {
69 let v = flow_random_walk(edge, t);
70 assert!(v >= 0.5 && v < 1.5, "random walk in [0.5, 1.5)");
71 }
72 }
73 }
74
75 #[test]
76 fn test_random_walk_deterministic() {
77 let v1 = flow_random_walk(3, 7.0);
78 let v2 = flow_random_walk(3, 7.0);
79 assert!((v1 - v2).abs() < 1e-12, "deterministic walk");
80 }
81}