Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
6c9b363
refactor many classes for gp
ptgrogan Jul 25, 2026
9745f8b
work in progress
ptgrogan Jul 25, 2026
1762172
wip
ptgrogan Jul 26, 2026
b8e4ab3
wip
ptgrogan Jul 26, 2026
9a1ebf4
fix unit tests
ptgrogan Jul 26, 2026
cfe22e2
drop support for < 3.10
ptgrogan Jul 26, 2026
f87b993
bump actions versions
ptgrogan Jul 26, 2026
6319791
fix examples and docs
ptgrogan Jul 26, 2026
a6fdd89
increment to version 3.5.0
ptgrogan Jul 28, 2026
a98ed34
remove unused var
ptgrogan Jul 28, 2026
f026bb4
interpolate ro sample by elevation
ptgrogan Jul 28, 2026
6d8e08b
use find_discrete to efficiently search for valid ro profiles
ptgrogan Jul 28, 2026
2f0d772
vectorize profile sampling to improve performance
ptgrogan Jul 28, 2026
a4b3e6e
rename tle lazy load to gp orbit
ptgrogan Jul 28, 2026
a429c0a
add alternative orbit track interface that reuses skyfield type to im…
ptgrogan Jul 28, 2026
4dd9ddf
share expensive init altitude between methods
ptgrogan Jul 28, 2026
6864e0e
make tangent point velocity calculation optional
ptgrogan Jul 28, 2026
fa66980
disable repeat behavior for orbit tracks to avoid inertial frame prob…
ptgrogan Jul 28, 2026
a4abb05
remove unnecessary comment
ptgrogan Jul 28, 2026
a13b317
resolve typing issues
ptgrogan Jul 28, 2026
8855938
add pylint and pytest tool configuration
ptgrogan Jul 30, 2026
8099b0b
fix typing issues
ptgrogan Jul 30, 2026
bf70123
set default values
ptgrogan Jul 30, 2026
2654409
Merge pull request #140 from code-lab-org/132-use-interpolation-to-es…
ptgrogan Jul 30, 2026
0d5df61
refactor unit test structure
ptgrogan Jul 30, 2026
bd7486b
correctly parse timezone datetimes in numpy
ptgrogan Jul 30, 2026
8403705
improve formatting.zero_pad tests
ptgrogan Jul 30, 2026
6501aac
improve project_polygon_to_elevation unit tests
ptgrogan Jul 30, 2026
371a08b
update utils.geometry unit tests
ptgrogan Jul 30, 2026
afd30e3
clean up utils.geometry to test public function and remove thin wrappers
ptgrogan Jul 30, 2026
1aed72c
improve observation utils unit tests
ptgrogan Jul 30, 2026
fb0361a
improve observation unit tests
ptgrogan Jul 31, 2026
22e7760
update orbital unit tests
ptgrogan Jul 31, 2026
05aab7d
update projection unit tests
ptgrogan Jul 31, 2026
b18d20b
update surface unit tests
ptgrogan Jul 31, 2026
f240bfc
pin black version
ptgrogan Jul 31, 2026
503a4eb
improve unit tests for config and fix bug in loading defaults from re…
ptgrogan Jul 31, 2026
1126ac2
update j2 value
ptgrogan Jul 31, 2026
44e189e
update generation module
ptgrogan Jul 31, 2026
5f8bcca
update schema.surface unit tests
ptgrogan Jul 31, 2026
7a06779
update orbits unit tests
ptgrogan Aug 1, 2026
adb80f7
enforce positive distance
ptgrogan Aug 1, 2026
686327f
set runtime configuration as lazy singleton
ptgrogan Aug 1, 2026
1d5062c
update orbits
ptgrogan Aug 1, 2026
363adf5
add instrument unit tests
ptgrogan Aug 1, 2026
6bce7aa
add geodetic distance
ptgrogan Aug 1, 2026
1f5f657
improved tests for space package
ptgrogan Aug 1, 2026
95e4c3f
updated unit tests for track.py
ptgrogan Aug 1, 2026
13d1a6e
clean up coverage methods
ptgrogan Aug 6, 2026
927c782
add unit tests for dop
ptgrogan Aug 7, 2026
3c53ee3
improve latency unit tests and docstrings
ptgrogan Aug 7, 2026
3c375b5
update ro coverage unit tests
ptgrogan Aug 7, 2026
280803c
update examples for grid_ functions
ptgrogan Aug 7, 2026
4be8267
clear results
ptgrogan Aug 8, 2026
913d228
reduce verboseness of docstrings
ptgrogan Aug 8, 2026
d2f84ea
update docs
ptgrogan Aug 8, 2026
9545011
start of change log
ptgrogan Aug 8, 2026
a1e1553
improve change log
ptgrogan Aug 13, 2026
3308ca7
files reformatted with black
Aug 13, 2026
f047904
rename geostationary to geosynchronous
ptgrogan Aug 13, 2026
ca85b6b
Merge branch 'prepare-version-3.5' of github.com:code-lab-org/tatc in…
ptgrogan Aug 13, 2026
f8e1d57
add zenodo action
ptgrogan Aug 13, 2026
c4f2cb9
add action to auto publish to pypi
ptgrogan Aug 13, 2026
1f85333
black does not auto commit formatting changes
ptgrogan Aug 13, 2026
cad082d
install missing pylint-pydantic dependency
ptgrogan Aug 13, 2026
241ab6d
update changelog
ptgrogan Aug 13, 2026
4ad2e14
run unit tests on PR
ptgrogan Aug 13, 2026
1551f84
resolves #124 about license format
ptgrogan Aug 13, 2026
a1513d4
pin python version for actions
ptgrogan Aug 13, 2026
c288135
test support for python 3.14
ptgrogan Aug 13, 2026
a2d1b58
update changelog
ptgrogan Aug 13, 2026
b00df1f
update project team
ptgrogan Aug 13, 2026
ed533c3
add badges, improve documentation
ptgrogan Aug 13, 2026
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
52 changes: 14 additions & 38 deletions .github/workflows/black-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,29 @@ on:
branches:
- main

concurrency:
group: black-check-${{ github.ref }}
cancel-in-progress: true

jobs:
black-format:
runs-on: ubuntu-latest

steps:
- name: Check out the repo
uses: actions/checkout@v3
uses: actions/checkout@v7

- name: Set up Python
uses: actions/setup-python@v3
uses: actions/setup-python@v7
with:
python-version: '3.x'

- name: Install Black
run: pip install black

- name: Run Black
run: |
black . --exclude "\.ipynb$" || exit 1

- name: Check if Black modified any files
id: check_black_changes
run: |
if [[ $(git status --porcelain) ]]; then
echo "true" > black_changed.txt
else
echo "false" > black_changed.txt
fi

- name: Setup environment file
run: echo "BLACK_CHANGED=$(cat black_changed.txt)" >> $GITHUB_ENV
python-version: '3.13'
cache: 'pip'
cache-dependency-path: pyproject.toml

- name: setup git config
- name: Install dependencies
run: |
git config user.name "GitHub Actions Bot"
git config user.email "<>"

- name: Fetch all branches
run: git fetch --all
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Checkout PR branch
run: git checkout "${{ github.head_ref }}"

- name: Commit changes if modified by Black
if: env.BLACK_CHANGED == 'true'
run: |
rm black_changed.txt
git add .
git commit -m "files reformatted with black"
git push origin "${{ github.head_ref }}" --quiet --follow-tags
- name: Check formatting with Black
run: black . --check --diff --exclude "\.ipynb$"
27 changes: 8 additions & 19 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Set up Python
uses: actions/setup-python@v3
uses: actions/setup-python@v7
with:
python-version: '3.9'
python-version: '3.10'
cache: 'pip'
cache-dependency-path: pyproject.toml

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .
pip install pylint
pip install -e ".[dev]"

- name: Run pylint
run: |
pylint_output=$(pylint --rcfile=.pylintrc src/tatc --exit-zero)
if echo "$pylint_output" | grep -q 'Your code has been rated at'; then
score=$(echo "$pylint_output" | grep 'Your code has been rated at' | awk '{print $NF}' | cut -d'/' -f1) # Extract numeric part
if (( $(echo "$score < 9.0" | bc -l) )); then
echo "Found critical errors with score $score. Please fix and try again."
exit 1
else
echo "No critical errors found. Score: $score"
fi
else
echo "No pylint output found. Passing the build."
fi
run: pylint --rcfile=.pylintrc --fail-under=9.0 src/tatc
67 changes: 67 additions & 0 deletions .github/workflows/pypi-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Publish to PyPI

on:
release:
types: [published]

jobs:
verify-version:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Check release tag matches package version
env:
TAG: ${{ github.event.release.tag_name }}
run: |
PKG_VERSION=$(grep -oP '(?<=__version__ = ")[^"]+' src/tatc/__init__.py)
TAG_VERSION="${TAG#v}"
echo "Release tag: $TAG (version $TAG_VERSION)"
echo "Package version: $PKG_VERSION"
if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then
echo "::error::Release tag $TAG (version $TAG_VERSION) does not match tatc.__version__ ($PKG_VERSION)"
exit 1
fi

build:
needs: verify-version
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: '3.13'

- name: Install build tooling
run: python -m pip install --upgrade build

- name: Build sdist and wheel
run: python -m build

- name: Upload distributions
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

publish:
needs: [verify-version, build]
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/project/tatc/
permissions:
id-token: write
steps:
- name: Download distributions
uses: actions/download-artifact@v4
with:
name: dist
path: dist/

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
19 changes: 13 additions & 6 deletions .github/workflows/unit-test.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
name: Run Python Unit Tests

on:
push:
pull_request:
branches:
- '*'
- main

concurrency:
group: unit-test-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v7

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: pyproject.toml

- name: Install project in editable mode
run: |
pip install -e .

- name: Run unit tests
run: python -m unittest
run: python -m unittest
134 changes: 134 additions & 0 deletions .github/workflows/zenodo-doi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
name: Update Zenodo DOI

# Zenodo's GitHub webhook integration automatically archives every published
# GitHub Release and mints a new DOI, but it does not touch this repo. This
# workflow polls Zenodo for that new deposit and opens a PR with the
# resulting version/date/DOI update to CITATION.cff (main is branch
# protected, so it cannot push directly).

on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: "Release tag to look up (defaults to the latest release)"
required: false

permissions:
contents: write
pull-requests: write

jobs:
update-citation:
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v7
with:
ref: main

- name: Determine release tag
id: tag
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
INPUT_TAG: ${{ github.event.inputs.tag }}
run: |
if [ -n "$INPUT_TAG" ]; then
TAG="$INPUT_TAG"
elif [ -n "${{ github.event.release.tag_name }}" ]; then
TAG="${{ github.event.release.tag_name }}"
else
TAG=$(gh release view --json tagName -q .tagName)
fi
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "version=${TAG#v}" >> "$GITHUB_OUTPUT"

- name: Poll Zenodo for the matching deposit
id: zenodo
env:
ZENODO_TOKEN: ${{ secrets.ZENODO_TOKEN }}
TAG: ${{ steps.tag.outputs.tag }}
REPO_URL: https://github.com/${{ github.repository }}/tree/${{ steps.tag.outputs.tag }}
run: |
set +e
for i in $(seq 1 20); do
RESPONSE=$(curl -s -w '\n%{http_code}' -H "Authorization: Bearer ${ZENODO_TOKEN}" \
"https://zenodo.org/api/deposit/depositions?status=published&sort=mostrecent&size=10")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
BODY=$(echo "$RESPONSE" | sed '$d')

if [ "$HTTP_CODE" = "401" ] || [ "$HTTP_CODE" = "403" ]; then
echo "Zenodo rejected the request (HTTP $HTTP_CODE) - check the ZENODO_TOKEN secret." >&2
exit 1
fi

IS_ARRAY=$(echo "$BODY" | jq -e 'type == "array"' 2>/dev/null)
if [ "$HTTP_CODE" = "200" ] && [ "$IS_ARRAY" = "true" ]; then
MATCH=$(echo "$BODY" | jq -c --arg url "$REPO_URL" --arg tag "$TAG" '
[.[] | select(
(.metadata.related_identifiers // [] | any(.identifier == $url))
or (.title // "" | contains($tag))
)][0]')
if [ "$MATCH" != "null" ] && [ -n "$MATCH" ]; then
echo "Found matching Zenodo deposit for $TAG"
echo "doi=$(echo "$MATCH" | jq -r '.doi')" >> "$GITHUB_OUTPUT"
echo "date=$(echo "$MATCH" | jq -r '.metadata.publication_date')" >> "$GITHUB_OUTPUT"
exit 0
fi
else
echo "Unexpected response from Zenodo (HTTP $HTTP_CODE), retrying..." >&2
fi

echo "No matching Zenodo deposit yet for $TAG, retrying in 30s ($i/20)..."
sleep 30
done
echo "Timed out waiting for Zenodo to archive $TAG" >&2
exit 1

- name: Update CITATION.cff
env:
VERSION: ${{ steps.tag.outputs.version }}
DOI: ${{ steps.zenodo.outputs.doi }}
DATE: ${{ steps.zenodo.outputs.date }}
run: |
sed -i \
-e "s/^version: .*/version: ${VERSION}/" \
-e "s/^date-released: .*/date-released: ${DATE}/" \
-e "s#^doi: .*#doi: ${DOI}#" \
CITATION.cff
if ! grep -q "^doi:" CITATION.cff; then
echo "doi: ${DOI}" >> CITATION.cff
fi
cat CITATION.cff

- name: Open pull request
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ steps.tag.outputs.tag }}
VERSION: ${{ steps.tag.outputs.version }}
DOI: ${{ steps.zenodo.outputs.doi }}
run: |
if git diff --quiet -- CITATION.cff; then
echo "CITATION.cff already up to date."
exit 0
fi

BRANCH="zenodo-doi-${TAG}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git checkout -B "$BRANCH"
git add CITATION.cff
git commit -m "chore: update CITATION.cff DOI for ${TAG}"
git push -f origin "$BRANCH"

EXISTING_PR=$(gh pr list --head "$BRANCH" --state open --json number -q '.[0].number')
if [ -n "$EXISTING_PR" ]; then
echo "Updated existing PR #${EXISTING_PR}"
else
gh pr create \
--base main \
--head "$BRANCH" \
--title "Update CITATION.cff DOI for ${TAG}" \
--body "Automated update from the Zenodo deposit created for release ${TAG}: DOI \`${DOI}\`, version \`${VERSION}\`."
fi
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,42 @@
# TAT-C Change Log

## 3.5.0

Major refactoring that focused on completing unit tests to approach full code coverage. Drops support for Python < 3.10 to improve compatibility with modern libraries. Replaces the `TwoLineElements` schema with `GeneralPerturbationsOrbit` to support modern orbit specifications including OMM CSV and JSON. Drops the CRS-based buffering approach to determine ground track in favor of geometric projections using the SPICE library. During refactoring, a few bug fixes and breaking changes were also made.

Added:
- Added `GeosynchronousOrbit` orbit schema.
- Support for Python 3.14.

Changed:
- Changed the default orbit epoch from `datetime.now()` to `2020-01-01T00:00:00Z`.
- Refactored all orbit schemas to inherit uniform getters from `OrbitBase`.
- Replaced `TwoLineElements` with a more general `GeneralPerturbationsOrbit` to accommodate post-TLE GP data formats.
- Improved `TundraOrbit` and `MolniyaOrbit` schemas to consider J2 perturbations when calculating orbit period.
- Fixed a bug where SPICE projected instrument footprints around the geocentric, rather than geodetic, pointing vector, leading to ~2 km positioning errors.
- Fixed `TrainConstellation` member right ascension of ascending node spacing to be based on a sidereal day, rather than a solar day.
- Fixed `SOCConstellation` member generation to use hexagonal spacing with a non-zero `relative_spacing` value.
- Fixed `MOGConstellation` member generation to use the mean anomaly of the reference orbit.
- Fixed a bug in `config.py` where default configurations (`defaults.yml`) were never provided in wheels.
- Fixed `collect_orbit_track` to only assign the `EPSG:4326` CRS to output when requesting WGS84 coordinates, rather than for all coordinate systems.
- Fixed `collect_orbit_track` to use a proper East/North/Up velocity when requesting WGS84 coordinates.
- Improved `collect_observations` to use the apogee altitude, rather than the initial altitude, to determine the maximum access duration.
- Fixed a bug where `collect_multi_observations` could crash on an empty satellite list.
- Fixed a bug in `grid_observations` and `grid_latencies` where spatial aggregation never actually worked.
- Fixed a bug in `compute_dop` where the latitude and longitude were reversed in output geometry.
- Improved `compute_dop` to use the nearest GP element to each time rather than the first one specified for an orbit.
- Fixed the definition of binormal unit vector in `ro_coverage.py` to accommodate eccentric orbits.
- Improved `collect_ro_observations` to interpolate among samples closest to target elevation.
- Improved performance of `collect_ro_observations` through vectorized profile sampling, a more direct interface to Skyfield for orbit track computation, and making tangent point velocity calculation optional.
- Fixed a bug where `collect_ro_observations` could use incorrect inertial positions for repeat track orbits more than 1 cycle after epoch.
- Added utility methods: `compute_apoapsis_radius` and `geodesic_distance`.
- Requires `setuptools >= 77.0.0` and switches `project.license` to an SPDX expression string to resolve a build metadata deprecation warning (issue #124).

Removed
- Support for Python < 3.10.
- Removed the `TwoLineElements` orbit schema.
- Removed the legacy `crs` and `method` parameters from `collect_ground_track` and `compute_ground_track`; all instrument projection now uses the SPICE library.

## 3.4.10

Added:
Expand Down
Loading