Skip to content
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
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added a new numerical integrator based on Picard-Chebyshev integration. This
integrator has only been added to the rust backend at this point, until more
testing can be done and it be made available on the frontend.
- Saving`SimultaneousStates` to parquet files can now optionally include a column
- Saving `SimultaneousStates` to parquet files can now optionally include a column
containing the TDB JD of when the state information was last updated. This allows
users to selectively update state vectors only when necessary.
- Added multi-core propagation support to rust backend.
- Added `kete_stats` as a new rust crate, moving some of the fitting and statistics
tools that have been in kete into their own crate. This is in support for some
upcoming changes, and is being used as a test case for breaking up kete into smaller
crates for easier consumption in the rust ecosystem.

### Changed

Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ license.workspace = true
repository.workspace = true

[workspace]
members = ["src/kete_core"]
default-members = ["src/kete_core"]
members = ["src/kete_core", "src/kete_stats"]
default-members = ["src/kete_core", "src/kete_stats"]

[workspace.package]
version = "2.1.5"
Expand All @@ -25,6 +25,7 @@ repository = "https://github.com/dahlend/kete"

[dependencies]
kete_core = { version = "*", path = "src/kete_core", features=["pyo3", "polars"]}
kete_stats = {version = "*", path = "src/kete_stats"}
pyo3 = { version = "^0.25.0", features = ["extension-module", "abi3-py39"] }
serde = { version = "^1.0.203", features = ["derive"] }
nalgebra = {version = "^0.33.0", features = ["rayon"]}
Expand Down
20 changes: 14 additions & 6 deletions src/kete/rust/fitting.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
//! Basic statistics
use kete_core::{fitting, stats};
use kete_stats::prelude::{Data, UncertainData};
use pyo3::{PyResult, pyfunction};

/// Perform a KS test between two vectors of values.
#[pyfunction]
#[pyo3(name = "ks_test")]
pub fn ks_test_py(sample_a: Vec<f64>, sample_b: Vec<f64>) -> PyResult<f64> {
let sample_a: stats::ValidData = sample_a.try_into()?;
let sample_b: stats::ValidData = sample_b.try_into()?;
Ok(sample_a.two_sample_ks_statistic(&sample_b)?)
let sample_a: Data<f64> = sample_a
.try_into()
.expect("Sample A did not contain valid data.");
let sample_b: Data<f64> = sample_b
.try_into()
.expect("Sample B did not contain valid data.");
Ok(sample_a
.into_sorted()
.two_sample_ks_statistic(&sample_b.into_sorted()))
}

/// Fit the reduced chi squared value for a collection of data with uncertainties.
#[pyfunction]
#[pyo3(name = "fit_chi2")]
pub fn fit_chi2_py(data: Vec<f64>, sigmas: Vec<f64>) -> f64 {
assert_eq!(data.len(), sigmas.len());
fitting::fit_reduced_chi2(&data, &sigmas).unwrap()
let data: UncertainData<f64> = (data, sigmas)
.try_into()
.expect("Data or sigmas did not contain valid data.");
data.fit_reduced_chi2().unwrap()
}
1 change: 1 addition & 0 deletions src/kete_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ chrono = "^0.4.38"
crossbeam = "^0.8.4"
directories = "^6.0"
itertools = "^0.14.0"
kete_stats = {version = "*", path = "../kete_stats"}
nalgebra = {version = "^0.33.0", features = ["rayon"]}
nom = "8.0.0"
polars = {version = "0.48.1", optional=true, features=["parquet", "polars-io"]}
Expand Down
85 changes: 0 additions & 85 deletions src/kete_core/src/fitting/reduced_chi2.rs

This file was deleted.

2 changes: 0 additions & 2 deletions src/kete_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ pub mod constants;
pub mod desigs;
pub mod elements;
pub mod errors;
pub mod fitting;
pub mod flux;
pub mod fov;
pub mod frames;
Expand All @@ -90,7 +89,6 @@ pub mod propagation;
pub mod simult_states;
pub mod spice;
pub mod state;
pub mod stats;
pub mod time;
pub mod util;

Expand Down
18 changes: 17 additions & 1 deletion src/kete_core/src/propagation/kepler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,36 @@

use crate::constants::{GMS, GMS_SQRT};
use crate::errors::Error;
use crate::fitting::newton_raphson;
use crate::frames::InertialFrame;
use crate::prelude::{CometElements, KeteResult};
use crate::state::State;
use crate::time::{Duration, TDB, Time};
use argmin::core::{CostFunction, Error as ArgminErr, Executor};
use argmin::solver::neldermead::NelderMead;
use core::f64;
use kete_stats::fitting::{ConvergenceError, newton_raphson};
use nalgebra::{ComplexField, Vector3};
use std::f64::consts::TAU;

/// How close to ecc=1 do we assume the orbit is parabolic
pub const PARABOLIC_ECC_LIMIT: f64 = 1e-4;

impl From<ConvergenceError> for Error {
fn from(err: ConvergenceError) -> Self {
match err {
ConvergenceError::Iterations => {
Self::Convergence("Maximum number of iterations reached without convergence".into())
}
ConvergenceError::NonFinite => {
Self::Convergence("Non-finite value encountered during evaluation".into())
}
ConvergenceError::ZeroDerivative => {
Self::Convergence("Zero derivative encountered during evaluation".into())
}
}
}
}

/// Compute the eccentric anomaly for all orbital classes.
///
/// # Arguments
Expand Down
9 changes: 5 additions & 4 deletions src/kete_core/src/spice/sclk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,13 +317,14 @@ impl Sclk {

let (exp_partition, partition_count) = self.partition_tick_count(tick)?;

if partition.is_some() && Some(exp_partition) != partition {
if let Some(partition) = partition
&& exp_partition != partition
{
return Err(Error::ValueError(format!(
"Partition mismatch: expected {}, found {}",
partition.unwrap(),
exp_partition
"Partition mismatch: expected {exp_partition}, found {partition}",
)));
}

tick += partition_count;
Ok((exp_partition, tick))
}
Expand Down
Loading