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}