Skip to main content

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}