use photom::{
observation_dataset::{ObsDatasetError, ObsId},
TrajId,
};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum OutfitError {
#[error("Invalid JPL string format: {0}")]
InvalidJPLStringFormat(String),
#[error("Invalid JPL ephemeris file source: {0}")]
InvalidJPLEphemFileSource(String),
#[error("Invalid JPL ephemeris file version: {0}")]
InvalidJPLEphemFileVersion(String),
#[error("Invalid URL string: {0}")]
InvalidUrl(String),
#[error("HTTP request failed (ureq): {0}")]
UreqHttpError(#[from] ureq::Error),
#[error("Filesystem I/O error: {0}")]
IoError(#[from] std::io::Error),
#[error("HTTP request failed (reqwest): {0}")]
ReqwestError(#[from] reqwest::Error),
#[error("Failed to create base directory for JPL ephemeris file: {0}")]
UnableToCreateBaseDir(String),
#[error("Filesystem path is not valid UTF-8: {0}")]
Utf8PathError(String),
#[error("JPL ephemeris file not found: {0}")]
JPLFileNotFound(String),
#[error("Numerical root finding failed: {0}")]
RootFindingError(#[from] roots::SearchError),
#[error("Observation not found at index: {0}")]
ObservationNotFound(usize),
#[error("Invalid error model identifier: {0}")]
InvalidErrorModel(String),
#[error("Invalid error model file path: {0}")]
InvalidErrorModelFilePath(String),
#[error("Parsing error (nom): {0}")]
NomParsingError(String),
#[error("Gaussian noise generation failed: {0:?}")]
NoiseInjectionError(rand_distr::NormalError),
#[error("Singular direction matrix (cannot invert); observations may be coplanar")]
SingularDirectionMatrix,
#[error("Polynomial root finding failed (Aberth–Ehrlich method did not converge)")]
PolynomialRootFindingFailed,
#[error("Spurious root detected (negative or near-zero geocentric distance)")]
SpuriousRootDetected,
#[error("Initial orbit determination (Gauss method) failed to find valid roots")]
GaussNoRootsFound,
#[error("Invalid SPK segment data type: {0}")]
InvalidSpkDataType(i32),
#[error("Invalid parameter for initial orbit determination: {0}")]
InvalidIODParameter(String),
#[error("Invalid reference system: {0}")]
InvalidRefSystem(String),
#[error("Velocity correction procedure failed: {0}")]
VelocityCorrectionError(String),
#[error("Invalid orbital state or inconsistent elements: {0}")]
InvalidOrbit(String),
#[error("Invalid input conversion: {0}")]
InvalidConversion(String),
#[error("Invalid floating-point value (NaN encountered): {0}")]
InvalidFloatValue(ordered_float::FloatIsNan),
#[error("RMS computation failed: {0}")]
RmsComputationFailed(String),
#[error("Gauss preliminary orbit determination failed: {0}")]
GaussPrelimOrbitFailed(String),
#[error("No viable orbit could be determined after {attempts} attempts: {cause}")]
NoViableOrbit {
cause: Box<OutfitError>,
attempts: usize,
},
#[error(
"No feasible triplets (span={span:.6} d, n_obs={n_obs}, dt_min={dt_min}, dt_max={dt_max})"
)]
NoFeasibleTriplets {
span: f64,
n_obs: usize,
dt_min: f64,
dt_max: f64,
},
#[error("Non-finite score encountered: {0}")]
NonFiniteScore(f64),
#[error("The provided observation {0} has no associated observer (ObserverId is None)")]
ObserverIdIsNone(ObsId),
#[error(transparent)]
ObsDatasetError(#[from] ObsDatasetError),
#[error("Observer dataset error: {0}")]
ObsDatasetErrorRef(String),
#[error("Trajectory ID not found in dataset: {0}")]
TrajectoryIdNotFound(TrajId),
#[error("No trajectory index available in the dataset")]
NoTrajectoryIndex,
#[error("Differential correction produced a physically implausible (bizarre) orbit")]
BizarreOrbit,
#[error("Differential correction diverged (RMS increased beyond the divergence threshold)")]
DifferentialCorrectionDiverged,
#[error("Differential correction failed: {0}")]
DifferentialCorrectionFailed(String),
#[error("Ephemeris body not supported by this backend: {0}")]
EphemerisBodyNotSupported(String),
#[error("N-body propagation failed: {0}")]
NBodyPropagationFailed(String),
}
impl From<&ObsDatasetError> for OutfitError {
fn from(e: &ObsDatasetError) -> Self {
OutfitError::ObsDatasetErrorRef(e.to_string())
}
}
impl From<rand_distr::NormalError> for OutfitError {
fn from(err: rand_distr::NormalError) -> Self {
OutfitError::NoiseInjectionError(err)
}
}
impl From<ordered_float::FloatIsNan> for OutfitError {
fn from(err: ordered_float::FloatIsNan) -> Self {
OutfitError::InvalidFloatValue(err)
}
}
impl PartialEq for OutfitError {
fn eq(&self, other: &Self) -> bool {
use OutfitError::*;
match (self, other) {
(InvalidJPLStringFormat(a), InvalidJPLStringFormat(b)) => a == b,
(InvalidJPLEphemFileSource(a), InvalidJPLEphemFileSource(b)) => a == b,
(InvalidJPLEphemFileVersion(a), InvalidJPLEphemFileVersion(b)) => a == b,
(InvalidUrl(a), InvalidUrl(b)) => a == b,
(UreqHttpError(_), UreqHttpError(_)) => true,
(IoError(_), IoError(_)) => true,
(ReqwestError(_), ReqwestError(_)) => true,
(UnableToCreateBaseDir(a), UnableToCreateBaseDir(b)) => a == b,
(Utf8PathError(a), Utf8PathError(b)) => a == b,
(JPLFileNotFound(a), JPLFileNotFound(b)) => a == b,
(RootFindingError(a), RootFindingError(b)) => a == b,
(ObservationNotFound(a), ObservationNotFound(b)) => a == b,
(InvalidErrorModel(a), InvalidErrorModel(b)) => a == b,
(InvalidErrorModelFilePath(a), InvalidErrorModelFilePath(b)) => a == b,
(NomParsingError(a), NomParsingError(b)) => a == b,
(NoiseInjectionError(a), NoiseInjectionError(b)) => a == b,
(InvalidSpkDataType(a), InvalidSpkDataType(b)) => a == b,
(InvalidIODParameter(a), InvalidIODParameter(b)) => a == b,
(InvalidRefSystem(a), InvalidRefSystem(b)) => a == b,
(VelocityCorrectionError(a), VelocityCorrectionError(b)) => a == b,
(InvalidOrbit(a), InvalidOrbit(b)) => a == b,
(InvalidConversion(a), InvalidConversion(b)) => a == b,
(InvalidFloatValue(a), InvalidFloatValue(b)) => a == b,
(RmsComputationFailed(a), RmsComputationFailed(b)) => a == b,
(GaussPrelimOrbitFailed(a), GaussPrelimOrbitFailed(b)) => a == b,
(NonFiniteScore(a), NonFiniteScore(b)) => a == b,
(
NoViableOrbit {
cause: a,
attempts: na,
},
NoViableOrbit {
cause: b,
attempts: nb,
},
) => a == b && na == nb,
(
NoFeasibleTriplets {
span: a,
n_obs: na,
dt_min: da,
dt_max: ma,
},
NoFeasibleTriplets {
span: b,
n_obs: nb,
dt_min: db,
dt_max: mb,
},
) => a == b && na == nb && da == db && ma == mb,
(SingularDirectionMatrix, SingularDirectionMatrix) => true,
(PolynomialRootFindingFailed, PolynomialRootFindingFailed) => true,
(SpuriousRootDetected, SpuriousRootDetected) => true,
(GaussNoRootsFound, GaussNoRootsFound) => true,
(BizarreOrbit, BizarreOrbit) => true,
(DifferentialCorrectionDiverged, DifferentialCorrectionDiverged) => true,
(DifferentialCorrectionFailed(a), DifferentialCorrectionFailed(b)) => a == b,
(EphemerisBodyNotSupported(a), EphemerisBodyNotSupported(b)) => a == b,
(NBodyPropagationFailed(a), NBodyPropagationFailed(b)) => a == b,
_ => false,
}
}
}