Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more thorough FOV tests #142

Merged
merged 4 commits into from
Oct 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- Added support for loading orbit information from JPL Horizons
- Added more complete testing for light delay computations in the various FOV checks.

### Changed

Expand All @@ -23,6 +24,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
assuming that the epoch time of the covariance fits is in UTC. This assumption is
now included in the covariance matrix sampling. This is different than their other
data products.
- Field of View checks for SPK checks was not returning the correct light delayed time,
it was returning the position/velocity at the observed position, but the time was
the instantaneous time.


## [v1.0.2]
Expand Down
4 changes: 4 additions & 0 deletions src/kete/rust/simult_states.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ use crate::{fovs::AllowedFOV, frame::PyFrames, state::PyState};
/// The main value in this is that also includes an optional Field of View.
/// If the FOV is provided, it is implied that the states which are present
/// in this file were objects seen by the FOV.
///
/// In the case where the FOV is provided, it is expected that the states
/// positions will include light delay, so an object which is ~1au away from
/// the FOV observer will have a JD which is offset by about 8 minutes.
///
#[pyclass(module = "kete", frozen, sequence, name = "SimultaneousStates")]
#[derive(Debug)]
Expand Down
8 changes: 4 additions & 4 deletions src/kete_core/src/flux/reflected.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use nalgebra::Vector3;
use serde::{Deserialize, Serialize};

/// This computes the phase curve correction using the IAU standard for the HG model.
///
///
/// Specifically page Page 550 - Equation (A4):
///
///
/// Asteroids II. University of Arizona Press, Tucson, pp. 524–556.
/// Bowell, E., Hapke, B., Domingue, D., Lumme, K., Peltoniemi, J., Harris,
/// A.W., 1989. Application of photometric models to asteroids, in: Binzel,
Expand All @@ -37,9 +37,9 @@ pub fn hg_phase_curve_correction(g_param: f64, phase: f64) -> f64 {
///
/// H, Albedo, and Diameter are all related by the relation:
/// diameter = c_hg / albedo.sqrt() * (10f64).powf(-h_mag / 5.0);
///
///
/// Specifically page Page 549 - Equation (A1) of:
///
///
/// Asteroids II. University of Arizona Press, Tucson, pp. 524–556.
/// Bowell, E., Hapke, B., Domingue, D., Lumme, K., Peltoniemi, J., Harris,
/// A.W., 1989. Application of photometric models to asteroids, in: Binzel,
Expand Down
6 changes: 3 additions & 3 deletions src/kete_core/src/fov/fov_like.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub trait FovLike: Sync + Sized {
let (idx, contains) = self.contains(&new_rel_pos);
let new_state = State::new(
state.desig.clone(),
obs.jd,
obs.jd + dt,
dahlend marked this conversation as resolved.
Show resolved Hide resolved
new_pos,
vel,
obs.frame,
Expand Down Expand Up @@ -203,8 +203,8 @@ pub trait FovLike: Sync + Sized {
.into_par_iter()
.filter_map(|&obj_id| {
match spk.try_get_state(obj_id, obs.jd, obs.center_id, obs.frame) {
Ok(state) => match self.check_linear(&state) {
(idx, Contains::Inside, state) => Some((idx, state)),
Ok(state) => match self.check_two_body(&state) {
Ok((idx, Contains::Inside, state)) => Some((idx, state)),
_ => None,
},
_ => None,
Expand Down
68 changes: 66 additions & 2 deletions src/kete_core/src/fov/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,12 +192,12 @@ impl FovLike for GenericCone {
#[cfg(test)]
mod tests {
use super::*;
use crate::constants::GMS_SQRT;
use crate::constants::{self, GMS_SQRT};
use crate::prelude::*;
use crate::state::Desig;

#[test]
fn test_check_visible() {
fn test_check_rectangle_visible() {
let circular = State::new(
Desig::Empty,
2451545.0,
Expand Down Expand Up @@ -237,4 +237,68 @@ mod tests {
.is_some());
}
}

/// Test the light delay computations for the different checks
#[test]
fn test_check_omni_visible() {
// Build an observer, and check the observability of ceres with different offsets from the observer time.
// this will exercise the position, velocity, and time offsets due to light delay.
let spk = get_spk_singleton().read().unwrap();
let observer = State::new(
Desig::Empty,
2451545.0,
[0.0, 1., 0.0].into(),
[-GMS_SQRT, 0.0, 0.0].into(),
Frame::Ecliptic,
10,
);

for offset in [-10.0, -5.0, 0.0, 5.0, 10.0] {
let ceres = spk
.try_get_state(20000001, observer.jd + offset, 10, Frame::Ecliptic)
.unwrap();

let fov = OmniDirectional::new(observer.clone());

// Check two body approximation calculation
let two_body = fov.check_two_body(&ceres);
assert!(two_body.is_ok());
let (_, _, two_body) = two_body.unwrap();
let dist = (Vector3::from(two_body.pos) - Vector3::from(observer.pos)).norm();
assert!((observer.jd - two_body.jd - dist * constants::C_AU_PER_DAY_INV).abs() < 1e-6);
let ceres_exact = spk
.try_get_state(20000001, two_body.jd, 10, Frame::Ecliptic)
.unwrap();
// check that we are within about 150km - not bad for 2 body
assert!((Vector3::from(two_body.pos) - Vector3::from(ceres_exact.pos)).norm() < 1e-6);

// Check n body approximation calculation
let n_body = fov.check_n_body(&ceres, false);
assert!(n_body.is_ok());
let (_, _, n_body) = n_body.unwrap();
assert!((observer.jd - n_body.jd - dist * constants::C_AU_PER_DAY_INV).abs() < 1e-6);
let ceres_exact = spk
.try_get_state(20000001, n_body.jd, 10, Frame::Ecliptic)
.unwrap();
// check that we are within about 150m
assert!((Vector3::from(n_body.pos) - Vector3::from(ceres_exact.pos)).norm() < 1e-9);

// Check spk queries
let spk_check = &fov.check_spks(&[20000001])[0];
assert!(spk_check.is_some());
let spk_check = &spk_check.as_ref().unwrap().states[0];
assert!((observer.jd - spk_check.jd - dist * constants::C_AU_PER_DAY_INV).abs() < 1e-6);
let ceres_exact = spk
.try_get_state(20000001, spk_check.jd, 10, Frame::Ecliptic)
.unwrap();
// check that we are within about 150 micron
assert!((Vector3::from(spk_check.pos) - Vector3::from(ceres_exact.pos)).norm() < 1e-12);

assert!(fov
.check_visible(&[ceres], 6.0, false)
.first()
.unwrap()
.is_some());
}
}
}