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
9 changes: 9 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Commits listed here are skipped by `git blame`.
#
# To enable locally:
# git config blame.ignoreRevsFile .git-blame-ignore-revs
#
# GitHub's web blame view honors this file automatically.

# Mass cargo fmt across the workspace
447b2427f2b52629986bef5b819601b9cedaf49e
11 changes: 11 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ on:
- "LICENSE"

jobs:
lint:
name: rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check

rust:
name: rust build and test (${{ matrix.os }})
strategy:
Expand Down
5 changes: 4 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ fn main() {
.args(["describe", "--tags"])
.output()
.unwrap();
println!("cargo:rustc-env=GIT_TAG={}", String::from_utf8(output.stdout).unwrap());
println!(
"cargo:rustc-env=GIT_TAG={}",
String::from_utf8(output.stdout).unwrap()
);
}

fn build_date_iso8601() -> String {
Expand Down
5 changes: 2 additions & 3 deletions python/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ mod pykepler;
mod pylpephem_moon;
mod pylpephem_planets;
mod pylpephem_sun;
mod pytlefitstatus;
mod pynrlmsise;
mod pypropresult;
mod pyquaternion;
mod pysatstate;
mod pysgp4;
mod pysolarsystem;
mod pytle;
mod pytlefitstatus;
//mod pyukf;

mod pylambert;
Expand Down Expand Up @@ -126,8 +126,7 @@ fn frametransform(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(pyft::pyeop, m)?).unwrap();
m.add_function(wrap_pyfunction!(pyft::disable_eop_time_warning, m)?)
.unwrap();
m.add_function(wrap_pyfunction!(pyft::to_gcrf, m)?)
.unwrap();
m.add_function(wrap_pyfunction!(pyft::to_gcrf, m)?).unwrap();
m.add_function(wrap_pyfunction!(pyft::from_gcrf, m)?)
.unwrap();
m.add_function(wrap_pyfunction!(pyft::itrf_to_gcrf_state, m)?)
Expand Down
17 changes: 6 additions & 11 deletions python/src/pyduration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,25 +196,20 @@ impl PyDuration {
Self(Duration::from_seconds(self.0.as_seconds() * other))
}

fn __truediv__(&self, other: &Bound<'_, PyAny>) ->PyResult<Py<PyAny>> {
fn __truediv__(&self, other: &Bound<'_, PyAny>) -> PyResult<Py<PyAny>> {
if other.is_instance_of::<Self>() {
let dur = other
.extract::<Self>()
.map_err(|e| anyhow::anyhow!("Invalid duration: {}", e))?;
pyo3::Python::attach(|py| (self.0.as_seconds() / dur.0.as_seconds()).into_py_any(py))
}
else if other.is_instance_of::<pyo3::types::PyFloat>() {
} else if other.is_instance_of::<pyo3::types::PyFloat>() {
let scalar = other
.extract::<f64>()
.map_err(|e| anyhow::anyhow!("Invalid scalar: {}", e))?;
pyo3::Python::attach(|py|
PyDuration(
Duration::from_seconds(self.0.as_seconds() / scalar)
).into_py_any(py)
)

}
else {
pyo3::Python::attach(|py| {
PyDuration(Duration::from_seconds(self.0.as_seconds() / scalar)).into_py_any(py)
})
} else {
Err(anyhow::anyhow!("Invalid right-hand side").into())
}
}
Expand Down
2 changes: 1 addition & 1 deletion python/src/pyframes.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use satkit::Frame;
use pyo3::prelude::*;
use satkit::Frame;

#[derive(Clone, PartialEq, Eq)]
#[pyclass(name = "frame", module = "satkit", eq, eq_int, from_py_object)]
Expand Down
21 changes: 14 additions & 7 deletions python/src/pyframetransform.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::pyinstant::ToTimeVec;
use crate::pyutils::*;
use crate::PyInstant;
use numpy as np;
use numpy::{PyArrayMethods, PyUntypedArrayMethods};
use pyo3::prelude::*;
use pyo3::IntoPyObjectExt;
use satkit::frametransform as ft;
use satkit::mathtypes::*;
use satkit::Instant;
use pyo3::prelude::*;
use pyo3::IntoPyObjectExt;
use numpy as np;
use numpy::{PyArrayMethods, PyUntypedArrayMethods};

use anyhow::{bail, Result};

Expand Down Expand Up @@ -465,19 +465,26 @@ fn state_transform_batch(
let vshape = varr.shape();
let n = pshape[0];
if pshape[1] != 3 {
bail!("pos must have shape (N, 3), got ({}, {})", pshape[0], pshape[1]);
bail!(
"pos must have shape (N, 3), got ({}, {})",
pshape[0],
pshape[1]
);
}
if vshape[0] != n || vshape[1] != 3 {
bail!(
"vel must have same shape as pos ({}, 3), got ({}, {})",
n, vshape[0], vshape[1]
n,
vshape[0],
vshape[1]
);
}
let tm = time.to_time_vec()?;
if tm.len() != n {
bail!(
"time array length ({}) must match number of states ({})",
tm.len(), n
tm.len(),
n
);
}
let pa = parr.as_array();
Expand Down
30 changes: 20 additions & 10 deletions python/src/pygravity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ use pyo3::prelude::*;
use satkit::earthgravity::{accel, accel_and_partials, GravityModel};

use crate::pyitrfcoord::PyITRFCoord;
use satkit::itrfcoord::ITRFCoord;
use satkit::mathtypes::*;
use numpy as np;
use numpy::PyArrayMethods;
use satkit::itrfcoord::ITRFCoord;
use satkit::mathtypes::*;

use pyo3::types::PyDict;
use pyo3::IntoPyObjectExt;
Expand Down Expand Up @@ -85,9 +85,10 @@ pub fn gravity(pos: &Bound<'_, PyAny>, kwds: Option<&Bound<'_, PyDict>>) -> Resu
.map_err(|e| anyhow::anyhow!("Failed to extract degree: {}", e))?;
}
if let Some(v) = kw.get_item("order")? {
order = Some(v
.extract::<usize>()
.map_err(|e| anyhow::anyhow!("Failed to extract order: {}", e))?);
order = Some(
v.extract::<usize>()
.map_err(|e| anyhow::anyhow!("Failed to extract order: {}", e))?,
);
}
}
let order = order.unwrap_or(degree);
Expand Down Expand Up @@ -156,9 +157,10 @@ pub fn gravity_and_partials(
.map_err(|e| anyhow::anyhow!("Failed to extract degree: {}", e))?;
}
if let Some(v) = kw.get_item("order")? {
order = Some(v
.extract::<usize>()
.map_err(|e| anyhow::anyhow!("Failed to extract order: {}", e))?);
order = Some(
v.extract::<usize>()
.map_err(|e| anyhow::anyhow!("Failed to extract order: {}", e))?,
);
}
}
let order = order.unwrap_or(degree);
Expand All @@ -173,7 +175,11 @@ pub fn gravity_and_partials(
let gpy = np::PyArray1::<f64>::from_slice(py, g.as_slice());
let ppy = unsafe { np::PyArray2::<f64>::new(py, [3, 3], false) };
unsafe {
std::ptr::copy_nonoverlapping(p.as_slice().as_ptr(), ppy.as_raw_array_mut().as_mut_ptr(), 9);
std::ptr::copy_nonoverlapping(
p.as_slice().as_ptr(),
ppy.as_raw_array_mut().as_mut_ptr(),
9,
);
}
Ok((gpy.into_py_any(py)?, ppy.into_py_any(py)?))
})
Expand All @@ -188,7 +194,11 @@ pub fn gravity_and_partials(
let gpy = np::PyArray1::<f64>::from_slice(py, g.as_slice());
let ppy = unsafe { np::PyArray2::<f64>::new(py, [3, 3], false) };
unsafe {
std::ptr::copy_nonoverlapping(p.as_slice().as_ptr(), ppy.as_raw_array_mut().as_mut_ptr(), 9);
std::ptr::copy_nonoverlapping(
p.as_slice().as_ptr(),
ppy.as_raw_array_mut().as_mut_ptr(),
9,
);
}
Ok((gpy.into_py_any(py)?, ppy.into_py_any(py)?))
})
Expand Down
7 changes: 3 additions & 4 deletions python/src/pyjplephem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::pysolarsystem;
use crate::pyutils::*;
use satkit::jplephem;
use satkit::mathtypes::*;
use satkit::SolarSystem;
use satkit::Instant;
use satkit::SolarSystem;

use anyhow::Result;

Expand All @@ -23,9 +23,8 @@ pub fn geocentric_state(
tm: &Bound<'_, PyAny>,
) -> PyResult<Py<PyAny>> {
let rbody: SolarSystem = body.into();
let f = |tm: &Instant| -> Result<(Vector3, Vector3)> {
Ok(jplephem::geocentric_state(rbody, tm)?)
};
let f =
|tm: &Instant| -> Result<(Vector3, Vector3)> { Ok(jplephem::geocentric_state(rbody, tm)?) };
tuple_func_of_time_arr(f, tm)
}

Expand Down
2 changes: 1 addition & 1 deletion python/src/pylpephem_moon.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::pyutils;
use pyo3::prelude::*;
use satkit::lpephem::moon;
use satkit::Instant;
use pyo3::prelude::*;

#[derive(PartialEq, Eq)]
#[pyclass(name = "moonphase", eq, eq_int)]
Expand Down
4 changes: 2 additions & 2 deletions python/src/pylpephem_planets.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::pyutils;
use satkit::lpephem;
use crate::pysolarsystem::SolarSystem;
use crate::pyutils;
use pyo3::prelude::*;
use satkit::lpephem;

use anyhow::Result;

Expand Down
18 changes: 8 additions & 10 deletions python/src/pylpephem_sun.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::pyinstant::PyInstant;
use crate::pyitrfcoord::PyITRFCoord;
use crate::pyutils;
use satkit::lpephem::sun;
use pyo3::prelude::*;
use anyhow::Result;
use pyo3::prelude::*;
use satkit::lpephem::sun;

/// Sun position in the Geocentric Celestial Reference Frame (GCRF)
///
Expand Down Expand Up @@ -61,14 +61,12 @@ pub fn rise_set(
sigma: Option<f64>,
) -> PyResult<(Py<PyAny>, Py<PyAny>)> {
match sun::riseset(&time.0, &coord.0, sigma) {
Ok((rise, set)) => {
pyo3::Python::attach(|py| {
Ok((
crate::pyinstant::instant_into_py(rise, py),
crate::pyinstant::instant_into_py(set, py),
))
})
}
Ok((rise, set)) => pyo3::Python::attach(|py| {
Ok((
crate::pyinstant::instant_into_py(rise, py),
crate::pyinstant::instant_into_py(set, py),
))
}),
Err(e) => Err(pyo3::exceptions::PyRuntimeError::new_err(e.to_string())),
}
}
Expand Down
30 changes: 17 additions & 13 deletions python/src/pypropresult.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,7 @@ fn to_string<const T: usize>(r: &PropagationResult<T>) -> String {
)
.as_str(),
);
s.push_str(
format!(
" Vel: [{:.3}, {:.3}, {:.3}] m/s\n",
se[3], se[4], se[5]
)
.as_str(),
);
s.push_str(format!(" Vel: [{:.3}, {:.3}, {:.3}] m/s\n", se[3], se[4], se[5]).as_str());
s.push_str(" Stats:\n");
s.push_str(format!(" Function Evaluations: {}\n", r.num_eval).as_str());
s.push_str(format!(" Accepted Steps: {}\n", r.accepted_steps).as_str());
Expand Down Expand Up @@ -318,28 +312,38 @@ impl PyPropResult {
// Batch interpolation — returns Nx6 numpy array
match &self.0 {
PyPropResultType::R1(r) => {
let results = r.interp_batch(&times)
let results = r
.interp_batch(&times)
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
pyo3::Python::attach(|py| {
let n = results.len();
let flat: Vec<f64> = results.iter().flat_map(|r| r.as_slice().iter().copied().take(6)).collect();
let flat: Vec<f64> = results
.iter()
.flat_map(|r| r.as_slice().iter().copied().take(6))
.collect();
slice2py2d(py, &flat, n, 6)
})
}
PyPropResultType::R7(r) => {
let results = r.interp_batch(&times)
let results = r
.interp_batch(&times)
.map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
pyo3::Python::attach(|py| {
let n = results.len();
let flat: Vec<f64> = results.iter().flat_map(|r| r.as_slice().iter().copied().take(6)).collect();
let flat: Vec<f64> = results
.iter()
.flat_map(|r| r.as_slice().iter().copied().take(6))
.collect();
slice2py2d(py, &flat, n, 6)
})
}
}
} else if is_list {
// Fallback for output_phi=true — need per-element processing
let results: PyResult<Vec<Py<PyAny>>> =
times.iter().map(|t| self.interp_at(t, output_phi)).collect();
let results: PyResult<Vec<Py<PyAny>>> = times
.iter()
.map(|t| self.interp_at(t, output_phi))
.collect();
pyo3::Python::attach(|py| results?.into_py_any(py))
} else {
self.interp_at(&times[0], output_phi)
Expand Down
4 changes: 3 additions & 1 deletion python/src/pyquaternion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,9 @@ impl PyQuaternion {
let qmat = rot.transpose();

Ok(pyo3::Python::attach(|py| -> PyResult<Py<PyAny>> {
let nd = unsafe { np::ndarray::ArrayView2::from_shape_ptr((3, 3), qmat.as_slice().as_ptr()) };
let nd = unsafe {
np::ndarray::ArrayView2::from_shape_ptr((3, 3), qmat.as_slice().as_ptr())
};
let res = v.readonly().as_array().dot(&nd).to_pyarray(py);

res.into_py_any(py)
Expand Down
Loading
Loading