1use crate::errors::RocheError;
2use crate::x_l1;
3use crate::{Vec3, vel_transform, strinit, stradv, strmnx, rocacc, OrbitalSystem};
4use bulirsch::{self, Integrator};
5use pyo3::prelude::*;
6
7
8
9pub fn vstream(q: f64, step: f64, n_points: usize, transform_type: i32) -> Result<(Vec<f64>, Vec<f64>, Vec<f64>), RocheError> {
32
33 if n_points < 2 {
34 return Err(RocheError::ParameterError(
35 "Need at least 2 points in the stream.".to_string(),
36 ));
37 }
38
39 let mut vx_arr: Vec<f64> = vec![];
40 let mut vy_arr: Vec<f64> = vec![];
41 let mut r_arr: Vec<f64> = vec![];
42 let mut frac: f64;
43 let mut acc: f64;
44 let mut ar_x: f64;
45 let mut ar_y: f64;
46
47 let rl1: f64 = x_l1(q)?;
49 let (mut r, mut v) = strinit(q)?;
50
51 let (mut tvx, mut tvy) = vel_transform(q, transform_type, rl1, 0.0, 0.0, 0.0)?;
53 vx_arr.push(tvx);
54 vy_arr.push(tvy);
55 let mut lp: usize = 0;
56
57 (tvx, tvy) = vel_transform(q, transform_type, r.x, r.y, v.x, v.y)?;
61 let mut delta_velocity: f64 = (tvx - vx_arr[0]).hypot(tvy - vy_arr[0]);
62 if delta_velocity > step {
63 frac = step / delta_velocity;
64 vx_arr.push(vx_arr[0] + (tvx - vx_arr[0]) * frac);
65 vy_arr.push(vy_arr[0] + (tvy - vy_arr[0]) * frac);
66 r_arr.push(r.x.hypot(r.y));
67 lp += 1;
68 }
69
70 let mut delta_t: f64 = 1.0e-3;
71 let smax: f64 = 1.0e-3_f64.min(step / 2.0);
72
73 let system = OrbitalSystem { q };
75 let mut integrator = Integrator::default()
76 .with_abs_tol(1.0e-8)
77 .with_rel_tol(1.0e-8)
78 .into_adaptive();
79 let mut y = ndarray::array![r.x, r.y, r.z, v.x, v.y, v.z];
81 let mut y_next = ndarray::Array::zeros(y.raw_dim());
82
83 while lp < n_points - 1 {
84
85 integrator
86 .step(&system, delta_t, y.view(), y_next.view_mut())
87 .unwrap();
88 y.assign(&y_next);
89
90 r.set(y[0], y[1], y[2]);
91 v.set(y[3], y[4], y[5]);
92 (tvx, tvy) = vel_transform(q, transform_type, r.x, r.y, v.x, v.y)?;
93 delta_velocity = (tvx - vx_arr[lp]).hypot(tvy - vy_arr[lp]);
94 if delta_velocity > step {
95 frac = step / delta_velocity;
96 vx_arr.push(vx_arr[lp] + (tvx - vx_arr[lp]) * frac);
97 vy_arr.push(vy_arr[lp] + (tvy - vy_arr[lp]) * frac);
98 r_arr.push(r.x.hypot(r.y));
99 lp += 1;
100 }
101 (ar_x, ar_y, _) = rocacc(q, &r, &v);
102 acc = ar_x.hypot(ar_y);
103 delta_t = delta_t.min(smax/acc);
104 }
105
106 Ok((vx_arr, vy_arr, r_arr))
107
108}
109
110#[pyfunction]
111#[pyo3(name = "vstream")]
112#[pyo3(signature = (q, step=0.01, n_points=60, transform_type=1))]
113pub fn vstream_reg(q: f64, step: f64, n_points: usize, transform_type: i32) -> Result<(Vec<f64>, Vec<f64>), RocheError> {
114
115 const TLOC: f64 = 1.0e-8;
116 const RLOC: f64 = 1.0e-8;
117
118 if n_points < 2 {
119 return Err(RocheError::ParameterError(
120 "Need at least 2 points in the stream.".to_string(),
121 ));
122 }
123
124 let mut rm: Vec3;
125 let mut vm: Vec3;
126 let mut r_end: f64;
127 let mut vx_arr: Vec<f64> = vec![];
128 let mut vy_arr: Vec<f64> = vec![];
129
130 let rl1: f64 = x_l1(q)?;
131
132 let (mut tvx, mut tvy) = vel_transform(q, transform_type, rl1, 0.0, 0.0, 0.0)?;
133 vx_arr.push(tvx);
134 vy_arr.push(tvy);
135
136 let mut np: usize = 1;
137 let mut r_next: f64 = rl1 * (1.0 - step);
138 let mut r_decreasing: bool = true;
139
140 let (mut r, mut v) = strinit(q)?;
142
143 while np < n_points {
144
145 stradv(q, &mut r, &mut v, r_next, RLOC, 1.0e-3);
147 (tvx, tvy) = vel_transform(q, transform_type, r.x, r.y, v.x, v.y)?;
148 vx_arr.push(tvx);
149 vy_arr.push(tvy);
150 np += 1;
151 r_next = if r_decreasing {r_next - rl1 * step} else {r_next + rl1 * step};
152
153 rm = r;
155 vm = v;
156 strmnx(q, &mut rm, &mut vm, TLOC)?;
157 r_end = rm.length();
158
159 while np < n_points && ((r_decreasing && r_next > r_end) || (!r_decreasing && r_next < r_end)) {
161 stradv(q, &mut r, &mut v, r_next, RLOC, 1.0e-3);
162 (tvx, tvy) = vel_transform(q, transform_type, r.x, r.y, v.x, v.y)?;
163 vx_arr.push(tvx);
164 vy_arr.push(tvy);
165 np += 1;
166 r_next = if r_decreasing {r_next - rl1 * step} else {r_next + rl1 * step};
167 }
168
169 r = rm;
171 v = vm;
172 r_decreasing = !r_decreasing;
173 r_next = if r_decreasing {r_next - rl1 * step} else {r_next + rl1 * step};
174 }
175
176 Ok((vx_arr, vy_arr))
177}
178
179