rust_roche/potential.rs
1use std::f64::consts::PI;
2use crate::{Vec3, Star};
3
4
5
6///
7/// rpot_val computes the value of the Roche potential for a specific value of phi & lambda.
8/// phi refers to the orbital phase, lambda to a multiplier that specified the position
9/// of a point from an origin plus the multiplier time lambda.
10///
11/// Arguments:
12///
13/// * `q`: mass ratio = M2/M1.
14/// * `star`: which star (is relevant for asynchronism).
15/// * `spin`: ratio of spin to orbital frequency.
16/// * `earth`: vector towards earth (defined by phase and inclination).
17/// * `p`: position of origin (units of separation).
18/// * `lam`: multiplier.
19///
20/// Returns:
21///
22/// * Roche potential at point.
23///
24pub fn rpot_val(q: f64, star: Star, spin: f64, earth: &Vec3, p: &Vec3, lam: f64) -> f64 {
25
26 let r: Vec3 = *p + lam* *earth;
27 match star {
28 Star::Primary => rpot1(q, spin, &r),
29 Star::Secondary => rpot2(q, spin, &r),
30 }
31}
32
33
34///
35/// rpot_val_grad computes the value & gradient in phi, lambda space of the Roche potential.
36/// phi orbital phase, lambda a multiplier that specified the position
37/// of a point from an origin plus the multiplier times lambda.
38///
39/// Arguments:
40///
41/// * `q`: mass ratio = M2/M1.
42/// * `star`: which star (is relevant for asynchronism).
43/// * `spin`: ratio of spin to orbital frequency.
44/// * `earth`: vector towards earth (defined by phase and inclination).
45/// * `p`: position of origin (units of separation).
46/// * `lam`: multiplier.
47///
48/// Returns:
49///
50/// * `rpot`: the Roche potential
51/// * `dphi`: first derivative of the Roche potential wrt phi
52/// * `dlam`: first derivative of the Roche potential wrt lambda
53///
54pub fn rpot_val_grad(q: f64, star: Star, spin: f64, earth: &Vec3, p: &Vec3, lam: f64) -> (f64, f64, f64) {
55
56 let r: Vec3 = *p + lam* *earth;
57 let d: Vec3 = match star {
58 Star::Primary => drpot1(q, spin, &r),
59 Star::Secondary => drpot2(q, spin, &r),
60 };
61 let rpot: f64 = match star {
62 Star::Primary => rpot1(q, spin, &r),
63 Star::Secondary => rpot2(q, spin, &r),
64 };
65 let ed: Vec3 = Vec3::new(earth.y, -earth.x, 0.);
66 let dphi: f64 = 2.*PI*lam*d.dot(&ed);
67 let dlam: f64 = d.dot(earth);
68
69 (rpot, dphi, dlam)
70 }
71
72
73///
74/// rpot_grad computes the gradient in phi, lambda space of the Roche potential.
75/// phi refers to the orbital phase, lambda to a multiplier that specified the position
76/// of a point from an origin plus the multiplier time lambda.
77///
78/// Arguments:
79///
80/// * `q`: mass ratio = M2/M1.
81/// * `star`: which star (is relevant for asynchronism).
82/// * `spin`: ratio of spin to orbital frequency.
83/// * `earth`: vector towards earth (defined by phase and inclination).
84/// * `p`: position of origin (units of separation).
85/// * `lam`: multiplier.
86///
87/// Returns:
88///
89/// * `dphi`: first derivative of the Roche potential wrt phi
90/// * `dlam`: first derivative of the Roche potential wrt lambda
91///
92pub fn rpot_grad(
93 q: f64,
94 star: Star,
95 spin: f64,
96 earth: &Vec3,
97 p: &Vec3,
98 lam: f64
99) -> (f64, f64) {
100
101 let r: Vec3 = *p + lam * *earth;
102
103 let d: Vec3 = match star {
104 Star::Primary => drpot1(q, spin, &r),
105 Star::Secondary => drpot2(q, spin, &r),
106 };
107
108 let ed: Vec3 = Vec3::new(earth.y, -earth.x, 0.);
109
110 let dphi: f64 = 2.*PI * lam*d.dot(&ed);
111 let dlam: f64 = d.dot(earth);
112
113 (dphi, dlam)
114}
115
116
117///
118/// rpot computes the Roche potential at a given point. This is for the standard synchronised Roche geometry
119///
120/// Arguments:
121///
122/// * `q`: mass ratio = M2/M1.
123/// * `p`: the point in question (units scaled by separation).
124///
125/// Returns:
126///
127/// * the Roche potential.
128///
129pub fn rpot(q: f64, p: &Vec3) -> f64 {
130 if q <= 0. {
131 panic!("q = {} <= 0", q);
132 }
133 let mu: f64 = q/(1. + q);
134 let comp: f64 = 1. - mu;
135 let x2y2: f64 = p.x*p.x + p.y*p.y;
136 let z2: f64 = p.z*p.z;
137 let r1sq: f64 = x2y2+z2;
138 let r1: f64 = r1sq.sqrt();
139 let r2: f64 = (r1sq + 1. - 2.*p.x).sqrt();
140 -comp/r1 - mu/r2 - (x2y2 + mu*(mu - 2.*p.x))/2.
141}
142
143
144///
145/// rpot1 computes the Roche potential at a given point allowing for non-synchronous rotation of the primary.
146///
147/// Arguments:
148///
149/// * `q`: mass ratio = M2/M1.
150/// * `spin`: ratio of spin to orbital frequency.
151/// * `p`: the point in question (units scaled by separation).
152///
153/// Returns:
154///
155/// * the Roche potential.
156///
157pub fn rpot1(q: f64, spin: f64, p: &Vec3) -> f64 {
158 if q <= 0. {
159 panic!("q = {} <= 0", q);
160 }
161 let mu: f64 = q/(1. + q);
162 let comp: f64 = 1. - mu;
163 let x2y2: f64 = p.x*p.x + p.y*p.y;
164 let z2: f64 = p.z*p.z;
165 let r1sq: f64 = x2y2+z2;
166 let r1: f64 = r1sq.sqrt();
167 let r2: f64 = (r1sq + 1. - 2.*p.x).sqrt();
168 -comp/r1 - mu/r2 - spin*spin*x2y2/2. + mu*p.x
169}
170
171
172///
173/// rpot2 computes the Roche potential at a given point allowing for non-synchronous rotation of the secondary.
174///
175/// Arguments:
176///
177/// * `q`: mass ratio = M2/M1.
178/// * `spin`: ratio of spin to orbital frequency.
179/// * `p`: the point in question (units scaled by separation).
180///
181/// Returns:
182///
183/// * the Roche potential.
184///
185pub fn rpot2(q: f64, spin: f64, p: &Vec3) -> f64 {
186 if q <= 0. {
187 panic!("q = {} <= 0", q);
188 }
189 let mu: f64 = q/(1. + q);
190 let comp: f64 = 1. - mu;
191 let x2y2: f64 = p.x*p.x + p.y*p.y;
192 let z2: f64 = p.z*p.z;
193 let r1sq: f64 = x2y2+z2;
194 let r1: f64 = r1sq.sqrt();
195 let r2: f64 = (r1sq + 1. - 2.*p.x).sqrt();
196 -comp/r1 - mu/r2 - spin*spin*(0.5 + 0.5*x2y2 - p.x) - comp*p.x
197}
198
199
200///
201/// drpot computes partial derivatives of Roche potential with respect
202/// to position at p for mass ratio q.
203///
204/// Arguments:
205///
206/// * `q`: mass ratio = M2/M1.
207/// * `p`: the point in question (units scaled by separation).
208///
209/// Returns:
210///
211/// * The partial derivative of the Roche potential wrt the position.
212///
213pub fn drpot(q: f64, p: &Vec3) -> Vec3 {
214 if q <= 0. {
215 panic!("q = {} <= 0", q);
216 }
217 let r1sq: f64 = p.sqr();
218 let r1: f64 = r1sq.sqrt();
219 let r2sq: f64 = r1sq + 1. - 2.*p.x;
220 let r2: f64 = r2sq.sqrt();
221 let mu: f64 = q/(1. + q);
222 let mu1: f64 = mu/r2/r2sq;
223 let comp: f64 = (1. - mu)/r1/r1sq;
224 Vec3::new(comp*p.x + mu1*(p.x - 1.) - p.x + mu,
225 comp*p.y + mu1*p.y - p.y,
226 comp*p.z + mu1*p.z)
227}
228
229
230///
231/// drpot1 computes partial derivatives of asynchronous Roche potential with respect
232/// to position at p for mass ratio q.
233///
234/// Arguments:
235///
236/// * `q`: mass ratio = M2/M1.
237/// * `spin`: ratio of spin to orbital frequency.
238/// * `p`: the point in question (units scaled by separation).
239///
240/// Returns:
241///
242/// * The partial derivative of the Roche potential wrt the position.
243///
244pub fn drpot1(q: f64, spin: f64, p: &Vec3) -> Vec3 {
245 if q <= 0. {
246 panic!("q = {} <= 0", q);
247 }
248 let r1sq: f64 = p.sqr();
249 let r1: f64 = r1sq.sqrt();
250 let r2sq: f64 = r1sq + 1. - 2.*p.x;
251 let r2: f64 = r2sq.sqrt();
252 let mu: f64 = q/(1. + q);
253 let mu1: f64 = mu/r2/r2sq;
254 let comp: f64 = (1. - mu)/r1/r1sq;
255 let ssq: f64 = spin*spin;
256 Vec3::new(comp*p.x + mu1*(p.x - 1.) - ssq*p.x + mu,
257 comp*p.y + mu1*p.y - ssq*p.y,
258 comp*p.z + mu1*p.z)
259}
260
261
262///
263/// drpot2 computes partial derivatives of asynchronous Roche potential with respect
264/// to position at p for mass ratio q.
265///
266/// Arguments:
267///
268/// * `q`: mass ratio = M2/M1.
269/// * `spin`: ratio of spin to orbital frequency.
270/// * `p`: the point in question (units scaled by separation).
271///
272/// Returns:
273///
274/// * The partial derivative of the Roche potential wrt the position.
275///
276pub fn drpot2(q: f64, spin: f64, p: &Vec3) -> Vec3 {
277 if q <= 0. {
278 panic!("q = {} <= 0", q);
279 }
280 let r1sq: f64 = p.sqr();
281 let r1: f64 = r1sq.sqrt();
282 let r2sq: f64 = r1sq + 1. - 2.*p.x;
283 let r2: f64 = r2sq.sqrt();
284 let mu: f64 = q/(1. + q);
285 let mu1: f64 = mu/r2/r2sq;
286 let comp: f64 = (1. - mu)/r1/r1sq;
287 let ssq: f64 = spin*spin;
288 Vec3::new(comp*p.x + mu1*(p.x - 1.) - ssq*(p.x - 1.) + mu - 1.,
289 comp*p.y + mu1*p.y - ssq*p.y,
290 comp*p.z + mu1*p.z)
291}