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

Better error logging with snafu #115

Merged
merged 36 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
afee0e7
Initial snafu impl
ChristopherRabotin Sep 12, 2023
92cacf9
Must convert AniseError to snafu
ChristopherRabotin Sep 12, 2023
cd2e768
Lifetime issues in the &str of snafu =(
ChristopherRabotin Sep 12, 2023
cda532d
Had to use a String for the error
ChristopherRabotin Sep 14, 2023
59a3a45
Add backtrace but I'm not sure this is very helpful to be frank
ChristopherRabotin Sep 14, 2023
e104aff
Fix error in epoch check for chebyshev
ChristopherRabotin Sep 14, 2023
7f918bd
Various clean ups
ChristopherRabotin Sep 14, 2023
0f2ac48
Slowly replacing all AniseErrors by relevant errors
ChristopherRabotin Sep 15, 2023
85f85c1
Update copyright year
ChristopherRabotin Sep 15, 2023
a111156
Nearly done migrting all errors to snafu
ChristopherRabotin Sep 15, 2023
beedb3e
Oops, I sure needed the structure module
ChristopherRabotin Sep 15, 2023
c1fda5e
Removed the unused structure
ChristopherRabotin Sep 15, 2023
33859d5
Need to merge Frame and remove anise from file loading
ChristopherRabotin Sep 15, 2023
47e0322
Snafu'd myself
ChristopherRabotin Sep 15, 2023
9757cca
Fix error checking in MRP and EP
ChristopherRabotin Sep 15, 2023
6032f15
Clippy
ChristopherRabotin Sep 15, 2023
0e415c8
Minor coverage improvements
ChristopherRabotin Sep 16, 2023
bd4e4e7
Wrap up frame fix
ChristopherRabotin Sep 17, 2023
b9c5b1e
Create FrameUid to pass around a small thing
ChristopherRabotin Sep 17, 2023
2142f1f
Switched to returning CartesianState when querying parent translation
ChristopherRabotin Sep 17, 2023
967cb31
Removed erroneous unit conversion with translate_to_from
ChristopherRabotin Sep 17, 2023
cb9fc1a
Fix leftover unit conversion in test
ChristopherRabotin Sep 17, 2023
e68abfe
Bye bye AniseError
ChristopherRabotin Sep 17, 2023
c289b62
Usability is not there.
ChristopherRabotin Sep 18, 2023
70e26c9
Architectural change in Almanac, DAF, and DataSet
ChristopherRabotin Sep 19, 2023
9f4f29c
Reset epoch in translation test
ChristopherRabotin Sep 19, 2023
c4303ee
Fix num_entries in NameRecord
ChristopherRabotin Sep 20, 2023
498ead8
Merge branch 'master' into 32-better-error-logging
ChristopherRabotin Sep 20, 2023
be33064
Fixed bug where TPC data was not serialized
ChristopherRabotin Sep 20, 2023
d24f418
Add SPICE frames
ChristopherRabotin Sep 21, 2023
f729759
Improve test coverage for DAF
ChristopherRabotin Sep 21, 2023
b5a0011
Enable orbit testing
ChristopherRabotin Sep 21, 2023
7fbde03
Reenable GMAT validation of orbital computations
ChristopherRabotin Sep 21, 2023
cea2357
Final improvements and cleanups
ChristopherRabotin Sep 21, 2023
ae35e70
Slightly more test coverage, and remove old C demo
ChristopherRabotin Sep 21, 2023
d2898fb
Allow for automatic loading of frame info if it exists
ChristopherRabotin Sep 21, 2023
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
8 changes: 4 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,13 @@ jobs:

- name: Rust-SPICE JPL DE validation
run: |
RUST_BACKTRACE=1 RUST_LOG=debug cargo test validate_jplde_de440s --features validation --release -- --nocapture --ignored
RUST_BACKTRACE=1 RUST_LOG=debug cargo test validate_jplde_de440_full --features validation --release -- --nocapture --ignored
RUST_BACKTRACE=1 RUST_LOG=debug cargo test validate_jplde_de440s --features spkezr_validation --release -- --nocapture --ignored
RUST_BACKTRACE=1 RUST_LOG=debug cargo test validate_jplde_de440_full --features spkezr_validation --release -- --nocapture --ignored

- name: Rust-SPICE hermite validation
run: |
RUST_BACKTRACE=1 RUST_LOG=debug cargo test validate_hermite_type13_from_gmat --features validation --release -- --nocapture --ignored
RUST_BACKTRACE=1 RUST_LOG=debug cargo test validate_hermite_type13_with_varying_segment_sizes --features validation --release -- --nocapture --ignored
RUST_BACKTRACE=1 RUST_LOG=debug cargo test validate_hermite_type13_from_gmat --features spkezr_validation --release -- --nocapture --ignored
RUST_BACKTRACE=1 RUST_LOG=debug cargo test validate_hermite_type13_with_varying_segment_sizes --features spkezr_validation --release -- --nocapture --ignored

# Now analyze the results and create pretty plots
- uses: actions/setup-python@v4
Expand Down
18 changes: 10 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description = "ANISE provides a toolkit and files for Attitude, Navigation, Inst
homepage = "https://github.com/anise-toolkit/"
documentation = "https://docs.rs/anise/"
repository = "https://github.com/anise-toolkit/anise.rs"
keywords = ["attitude","navigation","instrument", "spacecraft", "ephemeris"]
keywords = ["attitude", "navigation", "instrument", "spacecraft", "ephemeris"]
categories = ["science", "simulation"]
readme = "README.md"
license = "MPL-2.0"
Expand All @@ -19,33 +19,35 @@ exclude = ["cspice"]
hifitime = "3.8"
memmap2 = "0.7.0"
crc32fast = "1.3.0"
der = {version = "0.7.8", features = ["derive", "alloc", "real"]}
clap = {version = "3.1", features = ["derive"]}
der = { version = "0.7.8", features = ["derive", "alloc", "real"] }
clap = { version = "3.1", features = ["derive"] }
thiserror = "1.0"
log = "0.4"
pretty_env_logger = "0.5"
tabled = "0.14"
const_format = "0.2"
nalgebra = "0.32"
approx = "0.5.1"
zerocopy = {version = "0.7.3", features = ["derive"]}
zerocopy = { version = "0.7.3", features = ["derive"] }
bytes = "1.4.0"
snafu = "0.7.4"
snafu = { version = "0.7.4", features = ["backtrace"] }
lexical-core = "0.8.5"
heapless = "0.7.16"
rstest = "0.18.2"

[dev-dependencies]
rust-spice = "0.7.4"
parquet = "46.0.0"
arrow = "46.0.0"
criterion = "0.5"
iai = "0.1"
polars = {version = "0.33", features = ["lazy", "parquet"]}
polars = { version = "0.33", features = ["lazy", "parquet"] }
rayon = "1.7"

[features]
default = ["validation"]
validation = [] # Enabling this flag significantly reduces compilation times due to Arrow and Polars.
default = ["spkezr_validation"]
# Enabling this flag significantly reduces compilation times due to Arrow and Polars.
spkezr_validation = []

[profile.bench]
debug = true
Expand Down
6 changes: 2 additions & 4 deletions benches/crit_jpl_ephemerides.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ use anise::{
};
use criterion::{black_box, criterion_group, criterion_main, Criterion};

use spice;

const NUM_QUERIES_PER_PAIR: f64 = 100.0;

fn benchmark_spice_single_hop_type2_cheby(time_it: TimeSeries) {
Expand All @@ -24,7 +22,7 @@ fn benchmark_spice_single_hop_type2_cheby(time_it: TimeSeries) {
fn benchmark_anise_single_hop_type2_cheby(ctx: &Almanac, time_it: TimeSeries) {
for epoch in time_it {
black_box(
ctx.translate_from_to_km_s_geometric(EARTH_J2000, LUNA_J2000, epoch)
ctx.translate_from_to_geometric(EARTH_J2000, LUNA_J2000, epoch)
.unwrap(),
);
}
Expand All @@ -40,7 +38,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let path = "./data/de440s.bsp";
let buf = file2heap!(path).unwrap();
let spk = SPK::parse(buf).unwrap();
let ctx = Almanac::from_spk(&spk).unwrap();
let ctx = Almanac::from_spk(spk).unwrap();

// Load SPICE data
spice::furnsh("data/de440s.bsp");
Expand Down
8 changes: 3 additions & 5 deletions benches/crit_spacecraft_ephemeris.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ use anise::{constants::frames::EARTH_J2000, file2heap, prelude::*};

use criterion::{black_box, criterion_group, criterion_main, Criterion};

use spice;

const NUM_QUERIES: f64 = 100.0;

fn benchmark_spice_single_hop_type13_hermite(time_it: TimeSeries) {
Expand All @@ -27,7 +25,7 @@ fn benchmark_anise_single_hop_type13_hermite(ctx: &Almanac, time_it: TimeSeries)
let my_sc_j2k = Frame::from_ephem_j2000(-10000001);
for epoch in time_it {
black_box(
ctx.translate_from_to_km_s_geometric(my_sc_j2k, EARTH_J2000, epoch)
ctx.translate_from_to_geometric(my_sc_j2k, EARTH_J2000, epoch)
.unwrap(),
);
}
Expand All @@ -46,9 +44,9 @@ pub fn criterion_benchmark(c: &mut Criterion) {
let buf = file2heap!("data/gmat-hermite.bsp").unwrap();
let spacecraft = SPK::parse(buf).unwrap();

let ctx = Almanac::from_spk(&spk)
let ctx = Almanac::from_spk(spk)
.unwrap()
.load_spk(&spacecraft)
.load_spk(spacecraft)
.unwrap();

// Load SPICE data
Expand Down
5 changes: 2 additions & 3 deletions benches/iai_jpl_ephemerides.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use anise::{
};

use iai::black_box;
use spice;

const NUM_QUERIES_PER_PAIR: f64 = 100.0;

Expand Down Expand Up @@ -40,11 +39,11 @@ fn benchmark_anise_single_hop_type2_cheby() {
let path = "./data/de440s.bsp";
let buf = file2heap!(path).unwrap();
let spk = SPK::parse(buf).unwrap();
let ctx = Almanac::from_spk(&spk).unwrap();
let ctx = Almanac::from_spk(spk).unwrap();

for epoch in time_it {
black_box(
ctx.translate_from_to_km_s_geometric(EARTH_J2000, LUNA_J2000, epoch)
ctx.translate_from_to_geometric(EARTH_J2000, LUNA_J2000, epoch)
.unwrap(),
);
}
Expand Down
7 changes: 3 additions & 4 deletions benches/iai_spacecraft_ephemeris.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use anise::{constants::frames::EARTH_J2000, file2heap, prelude::*};

use iai::black_box;
use spice;

fn benchmark_spice_single_hop_type13_hermite() {
let epoch = Epoch::from_gregorian_hms(2000, 1, 1, 14, 0, 0, TimeScale::UTC);
Expand Down Expand Up @@ -30,15 +29,15 @@ fn benchmark_anise_single_hop_type13_hermite() {
let buf = file2heap!("data/gmat-hermite.bsp").unwrap();
let spacecraft = SPK::parse(buf).unwrap();

let ctx = Almanac::from_spk(&spk)
let ctx = Almanac::from_spk(spk)
.unwrap()
.load_spk(&spacecraft)
.load_spk(spacecraft)
.unwrap();

let my_sc_j2k = Frame::from_ephem_j2000(-10000001);

black_box(
ctx.translate_from_to_km_s_geometric(my_sc_j2k, EARTH_J2000, epoch)
ctx.translate_from_to_geometric(my_sc_j2k, EARTH_J2000, epoch)
.unwrap(),
);
}
Expand Down
104 changes: 81 additions & 23 deletions src/almanac/bpc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* ANISE Toolkit
* Copyright (C) 2021-2022 Christopher Rabotin <[email protected]> et al. (cf. AUTHORS.md)
* Copyright (C) 2021-2023 Christopher Rabotin <[email protected]> et al. (cf. AUTHORS.md)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
Expand All @@ -10,16 +10,17 @@

use hifitime::Epoch;

use crate::errors::AniseError;
use crate::naif::daf::DAFError;
use crate::naif::pck::BPCSummaryRecord;
use crate::naif::BPC;
use crate::orientations::OrientationError;
use log::error;

use super::{Almanac, MAX_LOADED_BPCS};

impl<'a: 'b, 'b> Almanac<'a> {
/// Loads a Binary Planetary Constants kernel.
pub fn load_bpc(&self, bpc: &'b BPC) -> Result<Almanac<'b>, AniseError> {
pub fn load_bpc(&self, bpc: BPC) -> Result<Almanac<'b>, OrientationError> {
// This is just a bunch of pointers so it doesn't use much memory.
let mut me = self.clone();
let mut data_idx = MAX_LOADED_BPCS;
Expand All @@ -30,15 +31,17 @@
}
}
if data_idx == MAX_LOADED_BPCS {
return Err(AniseError::StructureIsFull);
return Err(OrientationError::StructureIsFull {
max_slots: MAX_LOADED_BPCS,
});

Check warning on line 36 in src/almanac/bpc.rs

View check run for this annotation

Codecov / codecov/patch

src/almanac/bpc.rs#L34-L36

Added lines #L34 - L36 were not covered by tests
}
me.bpc_data[data_idx] = Some(bpc);
Ok(me)
}

pub fn num_loaded_bpc(&self) -> usize {
let mut count = 0;
for maybe in self.bpc_data {
for maybe in &self.bpc_data {
if maybe.is_none() {
break;
} else {
Expand All @@ -54,93 +57,148 @@
&self,
name: &str,
epoch: Epoch,
) -> Result<(&BPCSummaryRecord, usize, usize), AniseError> {
) -> Result<(&BPCSummaryRecord, usize, usize), OrientationError> {
for (no, maybe_bpc) in self
.bpc_data
.iter()
.take(self.num_loaded_bpc())
.rev()
.enumerate()
{
let bpc = maybe_bpc.unwrap();
let bpc = maybe_bpc.as_ref().unwrap();

Check warning on line 68 in src/almanac/bpc.rs

View check run for this annotation

Codecov / codecov/patch

src/almanac/bpc.rs#L68

Added line #L68 was not covered by tests
if let Ok((summary, idx_in_bpc)) = bpc.summary_from_name_at_epoch(name, epoch) {
return Ok((summary, no, idx_in_bpc));
}
}

// If we're reached this point, there is no relevant summary at this epoch.
error!("Context: No summary {name} valid at epoch {epoch}");
Err(AniseError::MissingInterpolationData(epoch))
error!("Almanac: No summary {name} valid at epoch {epoch}");
Err(OrientationError::BPC {
action: "searching for BPC summary",
source: DAFError::SummaryNameAtEpochError {
kind: "BPC",
name: name.to_string(),
epoch,
},
})
}

/// Returns the summary given the name of the summary record if that summary has data defined at the requested epoch
pub fn bpc_summary_at_epoch(
&self,
id: i32,
epoch: Epoch,
) -> Result<(&BPCSummaryRecord, usize, usize), AniseError> {
// TODO: Consider a return type here
) -> Result<(&BPCSummaryRecord, usize, usize), OrientationError> {
for (no, maybe_bpc) in self
.bpc_data
.iter()
.take(self.num_loaded_bpc())
.rev()
.enumerate()
{
let bpc = maybe_bpc.unwrap();
let bpc = maybe_bpc.as_ref().unwrap();

Check warning on line 99 in src/almanac/bpc.rs

View check run for this annotation

Codecov / codecov/patch

src/almanac/bpc.rs#L99

Added line #L99 was not covered by tests
if let Ok((summary, idx_in_bpc)) = bpc.summary_from_id_at_epoch(id, epoch) {
// NOTE: We're iterating backward, so the correct BPC number is "total loaded" minus "current iteration".
return Ok((summary, self.num_loaded_bpc() - no - 1, idx_in_bpc));
}
}

error!("Context: No summary {id} valid at epoch {epoch}");
error!("Almanac: No summary {id} valid at epoch {epoch}");
// If we're reached this point, there is no relevant summary at this epoch.
Err(AniseError::MissingInterpolationData(epoch))
Err(OrientationError::BPC {
action: "searching for BPC summary",
source: DAFError::SummaryIdAtEpochError {
kind: "BPC",
id,
epoch,
},
})
}

/// Returns the summary given the name of the summary record.
pub fn bpc_summary_from_name(
&self,
name: &str,
) -> Result<(&BPCSummaryRecord, usize, usize), AniseError> {
) -> Result<(&BPCSummaryRecord, usize, usize), OrientationError> {
for (bpc_no, maybe_bpc) in self
.bpc_data
.iter()
.take(self.num_loaded_bpc())
.rev()
.enumerate()
{
let bpc = maybe_bpc.unwrap();
let bpc = maybe_bpc.as_ref().unwrap();

Check warning on line 130 in src/almanac/bpc.rs

View check run for this annotation

Codecov / codecov/patch

src/almanac/bpc.rs#L130

Added line #L130 was not covered by tests
if let Ok((summary, idx_in_bpc)) = bpc.summary_from_name(name) {
return Ok((summary, bpc_no, idx_in_bpc));
}
}

// If we're reached this point, there is no relevant summary at this epoch.
error!("Context: No summary {name} valid");
Err(AniseError::NoInterpolationData)
error!("Almanac: No summary {name} valid");
Err(OrientationError::BPC {
action: "searching for BPC summary",
source: DAFError::SummaryNameError {
kind: "BPC",
name: name.to_string(),
},
})
}

/// Returns the summary given the name of the summary record if that summary has data defined at the requested epoch
pub fn bpc_summary(&self, id: i32) -> Result<(&BPCSummaryRecord, usize, usize), AniseError> {
// TODO: Consider a return type here
pub fn bpc_summary(
&self,
id: i32,
) -> Result<(&BPCSummaryRecord, usize, usize), OrientationError> {
for (no, maybe_bpc) in self
.bpc_data
.iter()
.take(self.num_loaded_bpc())
.rev()
.enumerate()
{
let bpc = maybe_bpc.unwrap();
let bpc = maybe_bpc.as_ref().unwrap();

Check warning on line 159 in src/almanac/bpc.rs

View check run for this annotation

Codecov / codecov/patch

src/almanac/bpc.rs#L159

Added line #L159 was not covered by tests
if let Ok((summary, idx_in_bpc)) = bpc.summary_from_id(id) {
// NOTE: We're iterating backward, so the correct BPC number is "total loaded" minus "current iteration".
return Ok((summary, self.num_loaded_bpc() - no - 1, idx_in_bpc));
}
}

error!("Context: No summary {id} valid");
error!("Almanac: No summary {id} valid");
// If we're reached this point, there is no relevant summary
Err(AniseError::NoInterpolationData)
Err(OrientationError::BPC {
action: "searching for BPC summary",
source: DAFError::SummaryIdError { kind: "BPC", id },
})
}
}

#[cfg(test)]
mod ut_almanac_bpc {
use crate::prelude::{Almanac, Epoch};

#[test]
fn summaries_nothing_loaded() {
let almanac = Almanac::default();

let e = Epoch::now().unwrap();

assert!(
almanac.bpc_summary(0).is_err(),
"empty Almanac should report an error"

Check warning on line 187 in src/almanac/bpc.rs

View check run for this annotation

Codecov / codecov/patch

src/almanac/bpc.rs#L187

Added line #L187 was not covered by tests
);
assert!(
almanac.bpc_summary_at_epoch(0, e).is_err(),
"empty Almanac should report an error"

Check warning on line 191 in src/almanac/bpc.rs

View check run for this annotation

Codecov / codecov/patch

src/almanac/bpc.rs#L191

Added line #L191 was not covered by tests
);
assert!(
almanac.bpc_summary_from_name("invalid name").is_err(),
"empty Almanac should report an error"

Check warning on line 195 in src/almanac/bpc.rs

View check run for this annotation

Codecov / codecov/patch

src/almanac/bpc.rs#L195

Added line #L195 was not covered by tests
);
assert!(
almanac
.bpc_summary_from_name_at_epoch("invalid name", e)
.is_err(),
"empty Almanac should report an error"

Check warning on line 201 in src/almanac/bpc.rs

View check run for this annotation

Codecov / codecov/patch

src/almanac/bpc.rs#L201

Added line #L201 was not covered by tests
);
}
}
Loading
Loading