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