Skip to main content

roche/
sphere_eclipse.rs

1use std::f64::consts::TAU;
2use crate::Vec3;
3use pyo3::prelude::*;
4
5///
6/// sphere_eclipse tells you whether or not a given sphere will eclipse a 
7/// given point or not. If the answer is yes, it will also return with four 
8/// parameters to define the phase range and the multiplier range delimiting the
9/// region within which the spheres surface is crossed.
10/// These can then be used as the starting point for later computation.
11/// (The line of sight is described as the point in question plus a scalar multiplier
12/// times a unit vector pointing towards Earth -- this is the "multiplier" referred to above
13/// and below). The multiplier must be positive: in other words the routine does not
14/// project backwards. If the point in inside the sphere, phi1 will be set = 0, phi2 = 1,
15/// lam1 = 0, and lam2 = the largest value of the multiplier lambda
16///
17/// Arguments:
18/// 
19/// * `cosi`: cosine of orbital inclination
20/// * `sini`: sine of orbital inclination
21/// * `r`: the position vector of the point in question (units of binary separation)
22/// * `c`: the centre of the sphere enclosing the star (units of binary separation)
23/// * `rsphere`: the radius defining the sphere enclosing the star (units of binary separation)
24/// * `phi1`: if eclipse by the sphere, this is the start of the phase range (0 -1)
25/// * `phi2`: if eclipse by the sphere, this is the end of the phase range (least amount > phi1)
26/// * `lam1`: if eclipse by the sphere, this is the start of the multiplier range (>=0)
27/// * `lam2`: if eclipse by the sphere, this is the end of the multiplier range (>lam1)
28/// 
29/// Returns:
30/// 
31/// * false = not eclipsed; true = eclipsed.
32///
33pub fn sphere_eclipse(cosi: f64, sini: f64, r: &Vec3, c: &Vec3, rsphere: f64, phi1: &mut f64, phi2: &mut f64, lam1: &mut f64, lam2: &mut f64) -> bool {
34
35    let d: Vec3 = *r - *c;
36
37    let pdist: f64 = (d.x*d.x + d.y*d.y).sqrt();
38    let bquad: f64 = d.z*cosi - pdist*sini;
39    if bquad >= 0. {
40        return false;
41    }
42    let cquad: f64 = d.sqr() - rsphere*rsphere;
43
44    let mut fac: f64 = bquad*bquad - cquad;
45    if fac <= 0.0 {
46        return false
47    }
48    fac = fac.sqrt();
49
50    *lam2 = -bquad + fac;
51    *lam1 = 0_f64.max(cquad/(*lam2));
52
53    if cquad < 0. {
54        *phi1 = 0.;
55        *phi2 = 1.
56    }else {
57        let delta: f64 = ((cosi*d.z + cquad.sqrt())/(sini*pdist)).acos();
58        let phi: f64 = d.y.atan2(-d.x);
59        *phi1 = (phi - delta)/TAU;
60        *phi1 -= phi1.floor();
61        *phi2 = *phi1 + 2.*delta/TAU;
62    }
63    return true;
64
65}
66
67
68// wrapper of the above function to use with Python (e.g avoiding mutable arguments)
69
70///
71/// sphere_eclipse tells you whether or not a given sphere will eclipse a 
72/// given point or not. If the answer is yes, it will also return with four 
73/// parameters to define the phase range and the multiplier range delimiting the
74/// region within which the spheres surface is crossed.
75/// These can then be used as the starting point for later computation.
76/// (The line of sight is described as the point in question plus a scalar multiplier
77/// times a unit vector pointing towards Earth -- this is the "multiplier" referred to above
78/// and below). The multiplier must be positive: in other words the routine does not
79/// project backwards. If the point in inside the sphere, phi1 will be set = 0, phi2 = 1,
80/// lam1 = 0, and lam2 = the largest value of the multiplier lambda
81///
82/// Arguments:
83/// 
84/// * `cosi`:     cosine of orbital inclination
85/// * `sini`:     sine of orbital inclination
86/// * `r (Vec3)`: the position vector of the point in question (units of binary separation)
87/// * `c (Vec3)`: the centre of the sphere enclosing the star (units of binary separation)
88/// * `rsphere`:  the radius defining the sphere enclosing the star (units of binary separation)
89/// 
90/// Returns:
91/// 
92///  * (eclipsed, phi1, phi2, lam1, lam2)
93///
94#[pyfunction]
95#[pyo3(name = "sphere_eclipse")]
96pub fn sphere_eclipse_wrapper(cosi: f64, sini: f64, r: &Vec3, c: &Vec3, rsphere: f64) -> (bool, f64, f64, f64, f64) {
97
98    let mut phi1 = 0.0;
99    let mut phi2 = 0.0;
100    let mut lam1 = 0.0;
101    let mut lam2 = 0.0;
102
103    let eclipsed = sphere_eclipse(cosi, sini, r, c, rsphere, &mut phi1, &mut phi2, &mut lam1, &mut lam2);
104
105    (eclipsed, phi1, phi2, lam1, lam2)
106}
107
108
109///
110/// This version of sphere_eclipse tells you whether or not a given sphere will eclipse 
111/// a given point at a particular phase or not. If the answer is yes,
112/// it will also return with the multiplier values giving the cut points. These can then
113/// be used as starting points for Roche lobe computations. These can then be used as the 
114/// starting point for later computation. Points inside the sphere are regarded as being
115/// eclipsed with the lower mulitplier set = 0
116/// 
117/// Arguments:
118///
119/// * `earth`:   vector towards Earth
120/// * `r`:       the position vector of the point in question (units of binary separation)
121/// * `c`:       the centre of the sphere (units of binary separation)
122/// * `rsphere`: the radius defining the sphere enclosing the star (units of binary separation)
123/// * `lam1`:    if eclipse by the sphere, this is the start of the multiplier range
124/// * `lam2`:    if eclipse by the sphere, this is the end of the multiplier range
125/// 
126/// Returns:
127/// 
128/// * false = not eclipsed; true = eclipsed.
129///
130pub fn sphere_eclipse_vector(earth: &Vec3, r: &Vec3, c: &Vec3, rsphere: f64, lam1: &mut f64, lam2: &mut f64) -> bool {
131
132    let d: Vec3 = *r - *c;
133
134    let bquad: f64 = earth.dot(&d);
135    if bquad >= 0. {
136        return false;
137    }
138    let cquad: f64 = d.sqr() - rsphere*rsphere;
139
140    let mut fac: f64 = bquad*bquad - cquad;
141    if fac <= 0. {
142        return false
143    }
144    fac = fac.sqrt();
145
146    *lam2 = -bquad + fac;
147    *lam1 = 0_f64.max(cquad/(*lam2));
148    return true;
149}
150
151// wrapper of the above function to use with Python (e.g avoiding mutable arguments)
152
153///
154/// This version of sphere_eclipse tells you whether or not a given sphere will eclipse 
155/// a given point at a particular phase or not. If the answer is yes,
156/// it will also return with the multiplier values giving the cut points. These can then
157/// be used as starting points for Roche lobe computations. These can then be used as the 
158/// starting point for later computation. Points inside the sphere are regarded as being
159/// eclipsed with the lower multiplier set = 0.
160/// The multiplier along the line of sight is lambda, with the smallest and largest values
161/// returned as lam1 and lam2, respectively. 
162///
163/// Arguments:
164///
165/// * `earth`:   vector towards Earth
166/// * `r`:       the position vector of the point in question (units of binary separation)
167/// * `c`:       the centre of the sphere (units of binary separation)
168/// * `rsphere`: the radius defining the sphere enclosing the star (units of binary separation)
169/// 
170/// Returns:
171///
172/// * (eclipsed, lam1, lam2)
173///
174#[pyfunction]
175#[pyo3(name = "sphere_eclipse_vector")]
176pub fn sphere_eclipse_vector_wrapper(earth: &Vec3, r: &Vec3, c: &Vec3, rsphere: f64) -> (bool, f64, f64) {
177    let mut lam1 = 0.0;
178    let mut lam2 = 0.0;
179
180    let eclipsed = sphere_eclipse_vector(earth, r, c, rsphere, &mut lam1, &mut lam2);
181
182    (eclipsed, lam1, lam2)
183}