Skip to content

Commit

Permalink
Improve error handling with snafu and eliminate panic calls (#273)
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristopherRabotin committed Jan 21, 2024
1 parent 519b6d4 commit b21c88d
Show file tree
Hide file tree
Showing 82 changed files with 1,784 additions and 1,759 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ pyo3-log = { version = "0.9.0", optional = true }
numpy = { version = "0.20", optional = true }
indicatif = { version = "0.17", features = ["rayon"] }
rstats = "2.0.1"
thiserror = "1.0"
parquet = { version = "50.0.0", default-features = false, features = [
"arrow",
"zstd",
Expand All @@ -76,6 +75,7 @@ enum-iterator = "1.4.0"
getrandom = { version = "0.2", features = ["js"] }
typed-builder = "0.18.0"
pythonize = { version = "0.20", optional = true }
snafu = { version = "0.8.0", features = ["backtrace"] }

[dev-dependencies]
polars = { version = "0.36.2", features = ["parquet"] }
Expand Down
20 changes: 16 additions & 4 deletions src/cosmic/bodies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,10 @@ impl TryFrom<String> for Bodies {
"uranus" | "uranus barycenter" => Ok(Self::UranusBarycenter),
"neptune" | "neptune barycenter" => Ok(Self::NeptuneBarycenter),
"pluto" | "pluto barycenter" => Ok(Self::PlutoBarycenter),
_ => Err(NyxError::ObjectNotFound(name, avail)),
_ => Err(NyxError::ObjectNotFound {
needle: name,
haystack: avail,
}),
}
}
}
Expand Down Expand Up @@ -164,15 +167,24 @@ impl TryFrom<Vec<usize>> for Bodies {
7 => Ok(Self::UranusBarycenter),
8 => Ok(Self::NeptuneBarycenter),
9 => Ok(Self::PlutoBarycenter),
_ => Err(NyxError::ObjectNotFound(format!("{ephem_path:?}"), avail)),
_ => Err(NyxError::ObjectNotFound {
needle: format!("{ephem_path:?}"),
haystack: avail,
}),
},
2 if ephem_path[0] == 3 => match ephem_path[1] {
// This only support the Earth system
0 => Ok(Self::Earth),
1 => Ok(Self::Luna),
_ => Err(NyxError::ObjectNotFound(format!("{ephem_path:?}"), avail)),
_ => Err(NyxError::ObjectNotFound {
needle: format!("{ephem_path:?}"),
haystack: avail,
}),
},
_ => Err(NyxError::ObjectNotFound(format!("{ephem_path:?}"), avail)),
_ => Err(NyxError::ObjectNotFound {
needle: format!("{ephem_path:?}"),
haystack: avail,
}),
}
}
}
50 changes: 23 additions & 27 deletions src/cosmic/bplane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

use super::{Frame, Orbit, OrbitDual, OrbitPartial};
use super::{AstroError, Frame, Orbit, OrbitDual, OrbitPartial};
use crate::linalg::{Matrix2, Matrix3, Vector2, Vector3};
use crate::md::objective::Objective;
use crate::md::StateParameter;
use crate::md::{AstroSnafu, StateParameter, TargetingError};
use crate::time::{Duration, Epoch, Unit};
use crate::utils::between_pm_180;
use crate::NyxError;
use hyperdual::linalg::norm;
use hyperdual::{Float, OHyperdual};
#[cfg(feature = "python")]
use pyo3::prelude::*;
use snafu::ResultExt;
use std::convert::From;
use std::fmt;

Expand All @@ -50,11 +50,9 @@ pub struct BPlane {

impl BPlane {
/// Returns a newly define B-Plane if the orbit is hyperbolic and already in Dual form
pub fn from_dual(orbit: OrbitDual) -> Result<Self, NyxError> {
pub fn from_dual(orbit: OrbitDual) -> Result<Self, AstroError> {
if orbit.ecc().real() <= 1.0 {
Err(NyxError::NotHyperbolic(
"Orbit is not hyperbolic. Convert to target object first".to_string(),
))
Err(AstroError::NotHyperbolic)
} else {
let one = OHyperdual::from(1.0);
let zero = OHyperdual::from(0.0);
Expand Down Expand Up @@ -128,7 +126,7 @@ impl BPlane {
}

/// Returns a newly defined B-Plane if the orbit is hyperbolic.
pub fn new(orbit: Orbit) -> Result<Self, NyxError> {
pub fn new(orbit: Orbit) -> Result<Self, AstroError> {
// Convert to OrbitDual so we can target it
Self::from_dual(OrbitDual::from(orbit))
}
Expand All @@ -154,7 +152,7 @@ impl BPlane {
}

/// Returns the Jacobian of the B plane (BT, BR) with respect to two of the velocity components
pub fn jacobian2(&self, invariant: StateParameter) -> Result<Matrix2<f64>, NyxError> {
pub fn jacobian2(&self, invariant: StateParameter) -> Result<Matrix2<f64>, AstroError> {
match invariant {
StateParameter::VX => Ok(Matrix2::new(
self.b_t.wtr_vy(),
Expand All @@ -174,9 +172,7 @@ impl BPlane {
self.b_r.wtr_vx(),
self.b_r.wtr_vy(),
)),
_ => Err(NyxError::CustomError(
"B Plane jacobian invariant must be either VX, VY or VZ".to_string(),
)),
_ => Err(AstroError::BPlaneInvariant),
}
}
}
Expand Down Expand Up @@ -321,7 +317,7 @@ impl fmt::Display for BPlaneTarget {
pub fn try_achieve_b_plane(
orbit: Orbit,
target: BPlaneTarget,
) -> Result<(Vector3<f64>, BPlane), NyxError> {
) -> Result<(Vector3<f64>, BPlane), TargetingError> {
let mut total_dv = Vector3::zeros();
let mut attempt_no = 0;
let max_iter = 10;
Expand All @@ -333,13 +329,11 @@ pub fn try_achieve_b_plane(
// If no LTOF is targeted, we'll solve this with a least squared approach.
loop {
if attempt_no > max_iter {
return Err(NyxError::MaxIterReached(format!(
"Error norm of {prev_b_plane_err} km after {max_iter} iterations",
)));
return Err(TargetingError::TooManyIterations);
}

// Build current B Plane
let b_plane = BPlane::new(real_orbit)?;
let b_plane = BPlane::new(real_orbit).with_context(|_| AstroSnafu)?;

// Check convergence
let br_err = target.b_r_km - b_plane.b_dot_r();
Expand All @@ -354,9 +348,11 @@ pub fn try_achieve_b_plane(

if b_plane_err.norm() >= prev_b_plane_err {
// If the error is not going down, we'll raise an error
return Err(NyxError::CorrectionIneffective(
format!("Delta-V correction is ineffective at reducing the B-Plane error:\nprev err norm: {prev_b_plane_err:.3} km\tcur err norm: {:.3} km", b_plane_err.norm())
));
return Err(TargetingError::CorrectionIneffective {
prev_val: prev_b_plane_err,
cur_val: b_plane_err.norm(),
action: "Delta-V correction is ineffective at reducing the B-Plane error",
});
}
prev_b_plane_err = b_plane_err.norm();

Expand All @@ -381,13 +377,11 @@ pub fn try_achieve_b_plane(
// The LTOF targeting seems to break often, but it's still implemented
loop {
if attempt_no > max_iter {
return Err(NyxError::MaxIterReached(format!(
"Error norm of {prev_b_plane_err} km after {max_iter} iterations",
)));
return Err(TargetingError::TooManyIterations);
}

// Build current B Plane
let b_plane = BPlane::new(real_orbit)?;
let b_plane = BPlane::new(real_orbit).with_context(|_| AstroSnafu)?;

// Check convergence
let br_err = target.b_r_km - b_plane.b_dot_r();
Expand All @@ -405,9 +399,11 @@ pub fn try_achieve_b_plane(
let b_plane_err = Vector3::new(bt_err, br_err, ltof_err);

if b_plane_err.norm() >= prev_b_plane_err {
return Err(NyxError::CorrectionIneffective(
format!("LTOF enabled correction is failing. Try to not set an LTOF target. Delta-V correction is ineffective are reducing the B-Plane error:\nprev err norm: {:.3} km\tcur err norm: {:.3} km", prev_b_plane_err, b_plane_err.norm()),
));
return Err(TargetingError::CorrectionIneffective {
prev_val: prev_b_plane_err,
cur_val: b_plane_err.norm(),
action: "LTOF enabled correction is failing. Try to not set an LTOF target. Delta-V correction is ineffective at reducing the B-Plane error",
});
}
prev_b_plane_err = b_plane_err.norm();

Expand Down
64 changes: 34 additions & 30 deletions src/cosmic/cosm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ impl FrameTree {
if f.name == name {
Ok(cur_path.to_vec())
} else if f.children.is_empty() {
Err(NyxError::ObjectNotFound(
name.to_string(),
f.children.iter().map(|c| c.name.clone()).collect(),
))
Err(NyxError::ObjectNotFound {
needle: name.to_string(),
haystack: f.children.iter().map(|c| c.name.clone()).collect(),
})
} else {
for (cno, child) in f.children.iter().enumerate() {
let mut this_path = cur_path.to_owned();
Expand All @@ -97,10 +97,10 @@ impl FrameTree {
}
}
// Could not find name in iteration, fail
Err(NyxError::ObjectNotFound(
name.to_string(),
f.children.iter().map(|c| c.name.clone()).collect(),
))
Err(NyxError::ObjectNotFound {
needle: name.to_string(),
haystack: f.children.iter().map(|c| c.name.clone()).collect(),
})
}
}
}
Expand Down Expand Up @@ -244,10 +244,10 @@ impl Cosm {
if f.name == frame_name {
Ok(cur_path.to_vec())
} else if f.children.is_empty() {
Err(NyxError::ObjectNotFound(
frame_name.to_string(),
f.children.iter().map(|c| c.name.clone()).collect(),
))
Err(NyxError::ObjectNotFound {
needle: frame_name.to_string(),
haystack: f.children.iter().map(|c| c.name.clone()).collect(),
})
} else {
for child in &f.children {
let this_path = cur_path.to_owned();
Expand All @@ -257,10 +257,10 @@ impl Cosm {
}
}
// Could not find name in iteration, fail
Err(NyxError::ObjectNotFound(
frame_name.to_string(),
f.children.iter().map(|c| c.name.clone()).collect(),
))
Err(NyxError::ObjectNotFound {
needle: frame_name.to_string(),
haystack: f.children.iter().map(|c| c.name.clone()).collect(),
})
}
}

Expand Down Expand Up @@ -410,7 +410,7 @@ impl Cosm {
let msg = format!("[frame.{}] - could not parse right_asc `{}` - are there any special characters? {}",
&name, &rot.right_asc, e);
error!("{}", msg);
return Err(NyxError::LoadingError(msg));
return Err(NyxError::LoadingError { msg });
}
};
let declin: Expr = match rot.declin.parse() {
Expand All @@ -419,7 +419,7 @@ impl Cosm {
let msg = format!("[frame.{}] - could not parse declin `{}` - are there any special characters? {}",
&name, &rot.declin, e);
error!("{}", msg);
return Err(NyxError::LoadingError(msg));
return Err(NyxError::LoadingError { msg });
}
};
let w_expr: Expr = match rot.w.parse() {
Expand All @@ -428,7 +428,7 @@ impl Cosm {
let msg = format!("[frame.{}] - could not parse w `{}` - are there any special characters? {}",
&name, &rot.w, e);
error!("{}", msg);
return Err(NyxError::LoadingError(msg));
return Err(NyxError::LoadingError { msg });
}
};

Expand Down Expand Up @@ -521,7 +521,9 @@ impl Cosm {
}
Err(e) => {
error!("{}", e);
Err(NyxError::LoadingError(format!("{e}")))
Err(NyxError::LoadingError {
msg: format!("{e}"),
})
}
}
}
Expand Down Expand Up @@ -660,24 +662,26 @@ impl Cosm {
let interp = ephem
.interpolator
.as_ref()
.ok_or_else(|| NyxError::NoInterpolationData(ephem.name.clone()))?;
.ok_or_else(|| NyxError::NoInterpolationData {
msg: ephem.name.clone(),
})?;

// the DE file epochs are all in ET mod julian
let start_mod_julian_f64 = ephem.start_epoch.as_ref().unwrap().as_raw();
let coefficient_count: usize = interp.position_degree as usize;
if coefficient_count <= 2 {
// Cf. https://gitlab.com/chrisrabotin/nyx/-/issues/131
return Err(NyxError::InvalidInterpolationData(format!(
"position_degree is less than 3 for XB {}",
ephem.name
)));
return Err(NyxError::InvalidInterpolationData {
msg: format!("position_degree is less than 3 for XB {}", ephem.name),
});
}

let exb_states = match interp
.state_data
.as_ref()
.ok_or_else(|| NyxError::NoStateData(ephem.name.clone()))?
{
.ok_or_else(|| NyxError::NoStateData {
msg: ephem.name.clone(),
})? {
EqualStates(states) => states,
VarwindowStates(_) => panic!("variable window not yet supported by Cosm"),
};
Expand All @@ -694,9 +698,9 @@ impl Cosm {
index -= 1;
offset = interval_length;
} else if index > exb_states.position.len() {
return Err(NyxError::NoInterpolationData(format!(
"No interpolation data for date {epoch}",
)));
return Err(NyxError::NoInterpolationData {
msg: format!("No interpolation data for date {epoch}",),
});
}
let pos_coeffs = &exb_states.position[index];

Expand Down
Loading

0 comments on commit b21c88d

Please sign in to comment.