Skip to content

Commit

Permalink
Merge pull request #364 from nyx-space/fix/gh-357-epa
Browse files Browse the repository at this point in the history
Fix Moon ME and Moon PA frames by searching for Euler Parameter datasets in rotations
  • Loading branch information
ChristopherRabotin authored Dec 22, 2024
2 parents 8b8bb8d + 7c8c403 commit 3505ba7
Show file tree
Hide file tree
Showing 22 changed files with 950 additions and 59 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ jobs:
wget -O data/pck08.pca http://public-data.nyxspace.com/anise/v0.5/pck08.pca
wget -O data/pck11.pca http://public-data.nyxspace.com/anise/v0.5/pck11.pca
wget -O data/moon_fk.epa http://public-data.nyxspace.com/anise/v0.5/moon_fk.epa
wget -O data/moon_fk_de440.epa http://public-data.nyxspace.com/anise/v0.5/moon_fk_de440.epa
wget -O data/moon_pa_de440_200625.bpc http://public-data.nyxspace.com/anise/moon_pa_de440_200625.bpc
wget -O data/gmat-hermite.bsp http://public-data.nyxspace.com/anise/ci/gmat-hermite.bsp
wget -O data/gmat-hermite-big-endian.bsp http://public-data.nyxspace.com/anise/ci/gmat-hermite-big-endian.bsp
Expand Down Expand Up @@ -192,6 +193,8 @@ jobs:
wget -O data/variable-seg-size-hermite.bsp http://public-data.nyxspace.com/anise/ci/variable-seg-size-hermite.bsp
wget -O data/earth_latest_high_prec.bpc http://public-data.nyxspace.com/anise/ci/earth_latest_high_prec-2023-09-08.bpc
wget -O data/lro.bsp http://public-data.nyxspace.com/nyx/examples/lrorg_2023349_2024075_v01_LE.bsp
wget -O data/moon_fk_de440.epa http://public-data.nyxspace.com/anise/v0.5/moon_fk_de440.epa
wget -O data/moon_pa_de440_200625.bpc http://public-data.nyxspace.com/anise/moon_pa_de440_200625.bpc
- name: Install stable toolchain
uses: dtolnay/rust-toolchain@stable
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,16 @@ For convenience, Nyx Space provides a few important SPICE files on a public buck
+ [de440.bsp](http://public-data.nyxspace.com/anise/de440.bsp): JPL's latest long-term ephemeris dataset
+ [pck08.pca](http://public-data.nyxspace.com/anise/v0.5/pck08.pca): planetary constants ANISE (`pca`) kernel, built from the JPL gravitational data [gm_de431.tpc](http://public-data.nyxspace.com/anise/gm_de431.tpc) and JPL's plantary constants file [pck00008.tpc](http://public-data.nyxspace.com/anise/pck00008.tpc)
+ [pck11.pca](http://public-data.nyxspace.com/anise/v0.5/pck11.pca): planetary constants ANISE (`pca`) kernel, built from the JPL gravitational data [gm_de431.tpc](http://public-data.nyxspace.com/anise/gm_de431.tpc) and JPL's plantary constants file [pck00011.tpc](http://public-data.nyxspace.com/anise/pck00011.tpc)
+ [moon_fk.epa](http://public-data.nyxspace.com/anise/v0.5/moon_fk.epa): Euler Parameter ANISE (`epa`) kernel, built from the JPL Moon Frame Kernel `moon_080317.txt`
+ [moon_fk_de440.epa](http://public-data.nyxspace.com/anise/v0.5/moon_fk_de440.epa): Euler Parameter ANISE (`epa`) kernel, built from the JPL Moon Frame Kernel `moon_080317.txt`

You may load any of these using the `load()` shortcut that will determine the file type upon loading, e.g. `let almanac = Almanac::new("pck08.pca").unwrap();` or in Python `almanac = Almanac("pck08.pca")`. To automatically download remote assets, from the Nyx Cloud or elsewhere, use the MetaAlmanac: `almanac = MetaAlmanac("ci_config.dhall").process()` in Python.

### Moon frames

Astrodynamicists use three main body fixed frames at the Moon, all suitable for computing latitude and longitude that represent fixed points on the surface of the Moon. The IAU Moon frame is a low-fidelity body-fixed frame. The Moon Principal Axes frames, Moon PA, is used to represent the mass concentrations of the Moon, and therefore is the frame to use for gravity fields defined as spherical harmonics at the Moon. Finally, the Moon Mean Earth frame, Moon ME, is the cartographic frame: images of the Moon centered on a latitude and longitude are almost always provided in the Moon ME frame.

As per the [`moon_de440_220930.txt`](./data/moon_de440_220930.txt) documentation, you should use the provided `moon_fk_de440.epa` file with the `moon_pa_de440_200625.bpc` and `de440.bsp` (or `de440s.bsp`).

## Contributing

Contributions to ANISE are welcome! Whether it's in the form of feature requests, bug reports, code contributions, or documentation improvements, every bit of help is greatly appreciated.
Expand Down
4 changes: 4 additions & 0 deletions anise-py/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ impl Frames {
#[classattr]
const MOON_ME_FRAME: Frame = MOON_ME_FRAME;
#[classattr]
const MOON_ME_DE421_FRAME: Frame = MOON_ME_DE421_FRAME;
#[classattr]
const MOON_PA_FRAME: Frame = MOON_PA_FRAME;
#[classattr]
const IAU_MOON_FRAME: Frame = IAU_MOON_FRAME;
Expand Down Expand Up @@ -102,6 +104,8 @@ impl Orientations {
#[classattr]
const MOON_ME: i32 = MOON_ME;
#[classattr]
const MOON_ME_DE421: i32 = MOON_ME_DE421;
#[classattr]
const MOON_PA: i32 = MOON_PA;
#[classattr]
const ITRF93: i32 = ITRF93;
Expand Down
2 changes: 1 addition & 1 deletion anise/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ For convenience, Nyx Space provides a few important SPICE files on a public buck
+ [de440.bsp](http://public-data.nyxspace.com/anise/de440.bsp): JPL's latest long-term ephemeris dataset
+ [pck08.pca](http://public-data.nyxspace.com/anise/v0.5/pck08.pca): planetary constants ANISE (`pca`) kernel, built from the JPL gravitational data [gm_de431.tpc](http://public-data.nyxspace.com/anise/gm_de431.tpc) and JPL's plantary constants file [pck00008.tpc](http://public-data.nyxspace.com/anise/pck00008.tpc)
+ [pck11.pca](http://public-data.nyxspace.com/anise/v0.5/pck11.pca): planetary constants ANISE (`pca`) kernel, built from the JPL gravitational data [gm_de431.tpc](http://public-data.nyxspace.com/anise/gm_de431.tpc) and JPL's plantary constants file [pck00011.tpc](http://public-data.nyxspace.com/anise/pck00011.tpc)
+ [moon_fk.epa](http://public-data.nyxspace.com/anise/v0.5/moon_fk.epa): Euler Parameter ANISE (`epa`) kernel, built from the JPL Moon Frame Kernel `moon_080317.txt`
+ [moon_fk_de440.epa](http://public-data.nyxspace.com/anise/v0.5/moon_fk_de440.epa): Euler Parameter ANISE (`epa`) kernel, built from the JPL Moon Frame Kernel `moon_080317.txt`

You may load any of these using the `load()` shortcut that will determine the file type upon loading, e.g. `let almanac = Almanac::new("pck08.pca").unwrap();` or in Python `almanac = Almanac("pck08.pca")`. To automatically download remote assets, from the Nyx Cloud or elsewhere, use the MetaAlmanac: `almanac = MetaAlmanac("ci_config.dhall").process(true)` in Python.

Expand Down
9 changes: 6 additions & 3 deletions anise/src/almanac/metaload/metaalmanac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ impl MetaAlmanac {
/// # File list
/// - <http://public-data.nyxspace.com/anise/de440s.bsp>
/// - <http://public-data.nyxspace.com/anise/v0.5/pck11.pca>
/// - <http://public-data.nyxspace.com/anise/v0.5/moon_fk.epa>
/// - <http://public-data.nyxspace.com/anise/v0.5/moon_fk_de440.epa>
/// - <http://public-data.nyxspace.com/anise/moon_pa_de440_200625.bpc>
/// - <https://naif.jpl.nasa.gov/pub/naif/generic_kernels/pck/earth_latest_high_prec.bpc>
///
Expand All @@ -265,8 +265,11 @@ impl Default for MetaAlmanac {
crc32: Some(0x8213b6e9),
},
MetaFile {
uri: nyx_cloud_stor.join("v0.5/moon_fk.epa").unwrap().to_string(),
crc32: Some(0xb93ba21),
uri: nyx_cloud_stor
.join("v0.5/moon_fk_de440.epa")
.unwrap()
.to_string(),
crc32: Some(0x6f0ad74c),
},
MetaFile {
uri: nyx_cloud_stor
Expand Down
4 changes: 2 additions & 2 deletions anise/src/almanac/metaload/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ mod meta_test {
, { crc32 = Some 0x8213b6e9
, uri = "http://public-data.nyxspace.com/anise/v0.5/pck11.pca"
}
, { crc32 = Some 0xb93ba21
, uri = "http://public-data.nyxspace.com/anise/v0.5/moon_fk.epa"
, { crc32 = Some 0x6f0ad74c
, uri = "http://public-data.nyxspace.com/anise/v0.5/moon_fk_de440.epa"
}
, { crc32 = Some 0xcde5ca7d
, uri = "http://public-data.nyxspace.com/anise/moon_pa_de440_200625.bpc"
Expand Down
34 changes: 23 additions & 11 deletions anise/src/almanac/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,12 @@ impl Almanac {
me
}

/// Loads the provides bytes as one of the data types supported in ANISE.
pub fn load_from_bytes(&self, bytes: Bytes) -> AlmanacResult<Self> {
self._load_from_bytes(bytes, None)
}

fn _load_from_bytes(&self, bytes: Bytes, path: Option<&str>) -> AlmanacResult<Self> {
// Try to load as a SPICE DAF first (likely the most typical use case)

// Load the header only
Expand All @@ -125,7 +130,7 @@ impl Almanac {
if let Ok(fileid) = file_record.identification() {
return match fileid {
"PCK" => {
info!("Loading as DAF/PCK");
info!("Loading {} as DAF/PCK", path.unwrap_or("bytes"));
let bpc = BPC::parse(bytes)
.context(BPCSnafu {
action: "parsing bytes",
Expand All @@ -138,7 +143,7 @@ impl Almanac {
})
}
"SPK" => {
info!("Loading as DAF/SPK");
info!("Loading {} as DAF/SPK", path.unwrap_or("bytes"));
let spk = SPK::parse(bytes)
.context(SPKSnafu {
action: "parsing bytes",
Expand Down Expand Up @@ -169,6 +174,10 @@ impl Almanac {
action: "loading as spacecraft data",
}
})?;
info!(
"Loading {} as ANISE spacecraft data",
path.unwrap_or("bytes")
);
Ok(self.with_spacecraft_data(dataset))
}
DataSetType::PlanetaryData => {
Expand All @@ -178,6 +187,7 @@ impl Almanac {
action: "loading as planetary data",
}
})?;
info!("Loading {} as ANISE/PCA", path.unwrap_or("bytes"));
Ok(self.with_planetary_data(dataset))
}
DataSetType::EulerParameterData => {
Expand All @@ -187,6 +197,7 @@ impl Almanac {
action: "loading Euler parameters",
}
})?;
info!("Loading {} as ANISE/EPA", path.unwrap_or("bytes"));
Ok(self.with_euler_parameters(dataset))
}
}
Expand All @@ -209,16 +220,17 @@ impl Almanac {
let bytes = file2heap!(path).context(LoadingSnafu {
path: path.to_string(),
})?;
info!("Loading almanac from {path}");
self.load_from_bytes(bytes).map_err(|e| match e {
AlmanacError::GenericError { err } => {
// Add the path to the error
AlmanacError::GenericError {
err: format!("with {path}: {err}"),

self._load_from_bytes(bytes, Some(path))
.map_err(|e| match e {
AlmanacError::GenericError { err } => {
// Add the path to the error
AlmanacError::GenericError {
err: format!("with {path}: {err}"),
}
}
}
_ => e,
})
_ => e,
})
}

/// Initializes a new Almanac from the provided file path, guessing at the file type
Expand Down
16 changes: 16 additions & 0 deletions anise/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,14 @@ pub mod orientations {
pub const MOON_ME: NaifId = 31001;
/// High fidelity Moon Principal Axes orientation frame (used for gravity field and mass concentrations), requires the Moon PA BPC kernel
pub const MOON_PA: NaifId = 31000;
/// High fidelity Moon Mean Earth orientation frame of the DE421 (used for cartography), requires the Moon PA BPC kernel
pub const MOON_ME_DE421: NaifId = 31007;
/// High fidelity Moon Mean Earth orientation frame of the DE440 (used for cartography), requires the Moon PA BPC kernel moon_pa_de440_200625.bpc.
pub const MOON_ME_DE440_ME421: NaifId = 31009;
/// High fidelity Moon Principal Axes orientation frame of the DE421 (used for gravity field and mass concentrations), requires the Moon PA BPC kernel
pub const MOON_PA_DE421: NaifId = 31008;
/// High fidelity Moon Principal Axes orientation frame of the DE440 (used for gravity field and mass concentrations), requires the Moon PA BPC kernel moon_pa_de440_200625. Note that the ID is the same as the MOON_PA_DE421.
pub const MOON_PA_DE440: NaifId = 31008;
pub const IAU_MARS: NaifId = 499;
pub const IAU_JUPITER: NaifId = 599;
pub const IAU_SATURN: NaifId = 699;
Expand Down Expand Up @@ -321,8 +329,16 @@ pub mod frames {
pub const IAU_MOON_FRAME: Frame = Frame::new(MOON, IAU_MOON);
/// High fidelity Moon Mean Earth equator body fixed frame (used for cartography), requires the Moon PA BPC kernel
pub const MOON_ME_FRAME: Frame = Frame::new(MOON, MOON_ME);
/// High fidelity Moon Mean Earth equator body fixed frame (used for cartography), requires the Moon PA BPC kernel
pub const MOON_ME_DE421_FRAME: Frame = Frame::new(MOON, MOON_ME_DE421);
/// High fidelity Moon Mean Earth equator body fixed frame of the DE440 (used for cartography), requires the Moon PA BPC kernel moon_pa_de440_200625.bpc.
pub const MOON_ME_DE440_ME421_FRAME: Frame = Frame::new(MOON, MOON_ME_DE440_ME421);
/// High fidelity Moon Principal Axes body fixed frame (used for gravity field and mass concentrations), requires the Moon PA BPC kernel
pub const MOON_PA_FRAME: Frame = Frame::new(MOON, MOON_PA);
/// High fidelity Moon Mean Earth equator body fixed frame (used for cartography), requires the Moon PA BPC kernel
pub const MOON_PA_DE421_FRAME: Frame = Frame::new(MOON, MOON_PA_DE421);
/// High fidelity Moon Mean Earth equator body fixed frame (used for cartography), requires the Moon PA BPC kernel moon_pa_de440_200625. Note that the ID is the same as the MOON_PA_DE421.
pub const MOON_PA_DE440_FRAME: Frame = Frame::new(MOON, MOON_PA_DE440);
pub const IAU_MARS_FRAME: Frame = Frame::new(MARS, IAU_MARS);
pub const IAU_JUPITER_FRAME: Frame = Frame::new(JUPITER, IAU_JUPITER);
pub const IAU_SATURN_FRAME: Frame = Frame::new(SATURN, IAU_SATURN);
Expand Down
42 changes: 39 additions & 3 deletions anise/src/naif/kpl/fk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ impl KPLItem for FKItem {
#[cfg(test)]
mod fk_ut {

use crate::naif::kpl::parser::convert_fk;
use crate::{
constants::orientations::{MOON_ME_DE421, MOON_ME_DE440_ME421},
naif::kpl::parser::convert_fk,
};

use super::{FKItem, KPLValue, Parameter};

Expand Down Expand Up @@ -200,10 +203,12 @@ mod fk_ut {
use crate::math::rotation::{r1, r2, r3, DCM};
let dataset = convert_fk("../data/moon_080317.txt", false).unwrap();

assert_eq!(dataset.len(), 3, "expected three items");
assert_eq!(dataset.len(), 5, "expected three items");

// Check that we've correctly set the names.
let moon_me = dataset.get_by_name("MOON_ME_DE421").unwrap();
let moon_me_by_id = dataset.get_by_id(MOON_ME_DE421).unwrap();
assert_eq!(moon_me_by_id, moon_me);
// From the file:
// TKFRAME_31007_ANGLES = (67.92 78.56 0.30 )
// TKFRAME_31007_AXES = (3, 2, 1 )
Expand All @@ -212,9 +217,40 @@ mod fk_ut {
* r2((78.56 / 3600.0_f64).to_radians())
* r1((0.30 / 3600.0_f64).to_radians());
assert!((DCM::from(moon_me).rot_mat - expected).norm() < 1e-10);
println!("{}", dataset.crc32());
println!("CRC32 = {}", dataset.crc32());
dataset
.save_as(&PathBuf::from_str("../data/moon_fk.epa").unwrap(), true)
.unwrap();
}

#[test]
fn build_de440_moon_fk() {
use std::path::PathBuf;
use std::str::FromStr;

use crate::math::rotation::{r1, r2, r3, DCM};
let dataset = convert_fk("../data/moon_de440_220930.txt", false).unwrap();

assert_eq!(dataset.len(), 4, "expected three items");

// Check that we've correctly set the names.
let moon_me = dataset.get_by_name("MOON_ME_DE440_ME421").unwrap();
let moon_me_by_id = dataset.get_by_id(MOON_ME_DE440_ME421).unwrap();
assert_eq!(moon_me_by_id, moon_me);
// From the file:
// TKFRAME_31009_ANGLES = ( 67.8526 78.6944 0.2785 )
// TKFRAME_31009_AXES = (3, 2, 1 )
// These angles are in arcseconds.
let expected = r3((67.8526 / 3600.0_f64).to_radians())
* r2((78.6944 / 3600.0_f64).to_radians())
* r1((0.2785 / 3600.0_f64).to_radians());
assert!((DCM::from(moon_me).rot_mat - expected).norm() < 1e-10);
println!("CRC32 = {}", dataset.crc32()); // 879707574
dataset
.save_as(
&PathBuf::from_str("../data/moon_fk_de440.epa").unwrap(),
true,
)
.unwrap();
}
}
7 changes: 7 additions & 0 deletions anise/src/naif/kpl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ impl KPLValue {
_ => whatever!("can only convert Integer to i32 but this is {self:?}"),
}
}

pub fn to_string(&self) -> Result<String, Whatever> {
match self {
KPLValue::String(data) => Ok(data.clone()),
_ => whatever!("can only convert Integer to i32 but this is {self:?}"),
}
}
}

impl From<f64> for KPLValue {
Expand Down
Loading

0 comments on commit 3505ba7

Please sign in to comment.