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: 3 additions & 3 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.11"]
python-version: ["3.14"]

name: Documentation tests
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ jobs:
fail-fast: false
matrix:
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
python-version: ["3.10", "3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
install-extras: ["base", "pysat_instruments", "dmsp_ssj"]

name: Python ${{ matrix.python-version }} on ${{ matrix.os }} with ${{ matrix.install-extras }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/pip_rc_install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ jobs:
fail-fast: false
matrix:
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
python-version: ["3.11"] # Keep this version at the highest supported Python version
python-version: ["3.14"] # Keep this version at the highest supported Python version

name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}

- name: Install standard dependencies
run: pip install -r requirements.txt

- name: Install pysat RC
- name: Install ocbpy RC
run: pip install --no-deps --pre -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ ocbpy

- name: Check that installation imports correctly
Expand Down
4 changes: 4 additions & 0 deletions Changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Summary of all changes made since the first stable release
0.7.0 (XX-XX-2025)
------------------
* ENH: Added the Gussenhoven (1983) model for the EAB
* DEP: Removed support for older versions of `zenodo_get`
* MAINT: Added support for Python 3.14
* MAINT: Updated GitHub CI actions
* MAINT: Updated numpy usage

0.6.0 (07-07-2025)
------------------
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ These routines may be used as a guide to write routines for other datasets.

# Python versions

This module currently supports Python version 3.10 - 3.13.
This module currently supports Python version 3.10 - 3.14.

# Dependencies

The listed dependecies were tested with the following versions:
* numpy
* aacgmv2
* pysat (3.2.1+)
* zenodo_get
* zenodo_get (2.0.0+)

Testing is performed using the python module, unittest. To limit dependency
issues, the pysat and zenodo_get dependencies are optional.
Expand Down
2 changes: 1 addition & 1 deletion docs/citing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ boundary method and data set are provided below.
* **SSJ Auroral Boundaries (2010-2014)**: Kilcommons, L., et al. (2019).
Defense Meteorology Satellite Program (DMSP) Electron Precipitation (SSJ)
Auroral Boundaries, 2010-2014 (Version 1.0.0) [Data set]. Zenodo.
http://doi.org/10.5281/zenodo.3373812
doi:10.5281/zenodo.3373812


.. _cite-starkov:
Expand Down
13 changes: 6 additions & 7 deletions docs/examples/ex_dmsp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@ need the
`ssj_auroral_boundary <https://github.com/lkilcommons/ssj_auroral_boundary>`__
package, but now we preferentially support using the
`zendodo_get <https://github.com/dvolgyes/zenodo_get>`__ package to obtain the
boundary files from their
`archive <https://zenodo.org/record/3373812>`__. Once installed,
you can download DMSP SSJ data and obtain a boundary file for a specified time
period (or all available times) using :py:mod:`ocbpy.boundaries.dmsp_ssj_files`.
For this example, we'll use a single day. You can download the files into any
directory, but this example will put them in the same directory as the other
boundary files.
boundary files from their archive at the website: zenodo.org/record/3373812.
Once installed, you can download DMSP SSJ data and obtain a boundary file for a
specified time period (or all available times) using
:py:mod:`ocbpy.boundaries.dmsp_ssj_files`. For this example, we'll use a single
day. You can download the files into any directory, but this example will put
them in the same directory as the other boundary files.

::

Expand Down
11 changes: 3 additions & 8 deletions ocbpy/boundaries/dmsp_ssj_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

.. [7] Kilcommons, L., Redmon, R., & Knipp, D. (2019). Defense Meteorology
Satellite Program (DMSP) Electron Precipitation (SSJ) Auroral Boundaries,
2010-2014 (1.0.0) [Data set]. Zenodo. https://doi.org/10.5281/zenodo.3373812
2010-2014 (1.0.0) [Data set]. Zenodo. doi:10.5281/zenodo.3373812

"""

Expand Down Expand Up @@ -113,13 +113,8 @@ def fetch_ssj_boundary_files(stime=None, etime=None, out_dir=None,
sys.stdout = zenodo_io
sys.stderr = zenodo_io

# TODO(#151): remove the old (second) way of calling zenodo_get
if hasattr(zenodo_get, "download"):
zenodo_get.download(doi=doi, output_dir=out_dir)
zenodo_checksum = None
else:
zenodo_get.zenodo_get([doi, '-o', out_dir])
zenodo_checksum = os.path.join(out_dir, 'md5sums.txt')
zenodo_get.download(doi=doi, output_dir=out_dir)
zenodo_checksum = None

# Parse the output and retrieve files from the zip archive
sys.stdout = sys.__stdout__
Expand Down
6 changes: 3 additions & 3 deletions ocbpy/ocb_scaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ def vect_mag(self, vect_mag):
self._vect_mag = vect_sqrt
else:
if np.any(np.greater(abs(vect_mag - vect_sqrt), 1.0e-3,
where=~np.isnan(vect_mag))):
where=~np.isnan(vect_mag), out=None)):
ocbpy.logger.warning("".join([
"inconsistent vector components with a maximum difference ",
"of {:} > 1.0e-3".format(abs(vect_mag - vect_sqrt).max())]))
Expand Down Expand Up @@ -1221,7 +1221,7 @@ def archav(hav):
alpha = np.full(shape=hav.shape, fill_value=np.nan)

# If the number is positive, calculate the angle
norm_mask = (np.greater_equal(hav, 1.0e-16, where=~np.isnan(hav))
norm_mask = (np.greater_equal(hav, 1.0e-16, where=~np.isnan(hav), out=None)
& ~np.isnan(hav))
if np.any(norm_mask):
if hav.shape == ():
Expand All @@ -1231,7 +1231,7 @@ def archav(hav):

# The number is small enough that machine precision may have changed
# the sign, but it's a single-precission zero
small_mask = (np.less(abs(hav), 1.0e-16, where=~np.isnan(hav))
small_mask = (np.less(abs(hav), 1.0e-16, where=~np.isnan(hav), out=None)
& ~np.isnan(hav))
if np.any(small_mask):
if hav.shape == ():
Expand Down
12 changes: 6 additions & 6 deletions ocbpy/ocb_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,19 +434,19 @@ def fix_range(values, min_val, max_val, val_range=None):

# Fix the values, allowing for deviations that are multiples of the
# value range. Also propagate NaNs
ibad = (np.greater_equal(fixed_vals, max_val, where=~np.isnan(fixed_vals))
& ~np.isnan(fixed_vals))
ibad = np.greater_equal(fixed_vals, max_val, where=~np.isnan(fixed_vals),
out=None) & ~np.isnan(fixed_vals)
while np.any(ibad):
fixed_vals[ibad] -= val_range
ibad = (np.greater_equal(fixed_vals, max_val,
where=~np.isnan(fixed_vals))
where=~np.isnan(fixed_vals), out=None)
& ~np.isnan(fixed_vals))

ibad = (np.less(fixed_vals, min_val, where=~np.isnan(fixed_vals))
ibad = (np.less(fixed_vals, min_val, where=~np.isnan(fixed_vals), out=None)
& ~np.isnan(fixed_vals))
while np.any(ibad):
fixed_vals[ibad] += val_range
ibad = (np.less(fixed_vals, min_val, where=~np.isnan(fixed_vals))
& ~np.isnan(fixed_vals))
ibad = np.less(fixed_vals, min_val, where=~np.isnan(fixed_vals),
out=None) & ~np.isnan(fixed_vals)

return fixed_vals
12 changes: 7 additions & 5 deletions ocbpy/tests/test_boundary_dual.py
Original file line number Diff line number Diff line change
Expand Up @@ -586,15 +586,15 @@ def eval_coords(self, hemisphere=1, tol=1.0e-7, ind=None, revert=False,
len(numpy.isnan(rlat)))
if not numpy.isnan(rlat).all():
self.assertTrue(
numpy.less(abs(self.out[0] - rlat), tol,
numpy.less(abs(self.out[0] - rlat), tol, out=None,
where=~numpy.isnan(rlat)).all(),
msg="unequal {:s}: {:} != {:}".format(lat_str, self.out[0],
rlat))
self.assertEqual(len(numpy.isnan(self.out[1])),
len(numpy.isnan(rmlt)))
if not numpy.isnan(rmlt).all():
self.assertTrue(
numpy.less(abs(self.out[1] - rmlt), tol,
numpy.less(abs(self.out[1] - rmlt), tol, out=None,
where=~numpy.isnan(rmlt)).all(),
msg="unequal {:s}: {:} != {:}".format(mlt_str, self.out[1],
rmlt))
Expand All @@ -605,7 +605,8 @@ def eval_coords(self, hemisphere=1, tol=1.0e-7, ind=None, revert=False,
if not numpy.isnan(self.out[2]).all():
self.assertTrue(
numpy.less(abs(self.out[2] - self.olat[hemisphere]),
tol, where=~numpy.isnan(self.out[2])).all(),
tol, where=~numpy.isnan(self.out[2]),
out=None).all(),
msg="unequal OCB latitude: {:} != {:}".format(
self.out[2], self.olat[hemisphere]))

Expand All @@ -615,7 +616,8 @@ def eval_coords(self, hemisphere=1, tol=1.0e-7, ind=None, revert=False,
else:
self.assertTrue(
numpy.less(abs(self.out[3] - self.rcorr), tol,
where=~numpy.isnan(self.out[3])).all(),
where=~numpy.isnan(self.out[3]),
out=None).all(),
msg="unequal radial correction: {:} != {:}".format(
self.out[3], self.rcorr))
else:
Expand Down Expand Up @@ -1119,7 +1121,7 @@ def test_get_current_aacgm_boundary_set(self):

# Ensure the expected values and fill values are returned
self.assertTrue(
numpy.less(abs(abound - self.bounds[i]), 1e-7,
numpy.less(abs(abound - self.bounds[i]), 1e-7, out=None,
where=~numpy.isnan(abound)).all(),
msg="unexpected boundary: {:} != {:}".format(
abound, self.bounds[i]))
Expand Down
16 changes: 8 additions & 8 deletions ocbpy/tests/test_boundary_ocb.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,11 +590,11 @@ def test_normal_coord_north_array(self):
self.out = self.ocb.normal_coord(self.lat, self.mlt)

self.assertTrue(numpy.all(numpy.less(abs(self.out[0] - self.ocb_lat),
1.0e-7,
1.0e-7, out=None,
where=~numpy.isnan(self.out[0]))
| numpy.isnan(self.out[0])))
self.assertTrue(numpy.all(numpy.less(abs(self.out[1] - self.ocb_mlt),
1.0e-7,
1.0e-7, out=None,
where=(~numpy.isnan(self.out[1])))
| numpy.isnan(self.out[1])))
self.assertTrue(numpy.where(numpy.isnan(self.out[0]))
Expand Down Expand Up @@ -679,11 +679,11 @@ def test_revert_coord_north_array(self):
self.r_corr)

self.assertTrue(numpy.all(numpy.less(abs(self.out[0] - self.lat),
1.0e-7,
1.0e-7, out=None,
where=~numpy.isnan(self.out[0]))
| (numpy.isnan(self.out[0]))))
self.assertTrue(numpy.all(numpy.less(abs(self.out[1] - self.mlt),
1.0e-7,
1.0e-7, out=None,
where=(~numpy.isnan(self.out[1])
& (self.lat < 90.0)))
| numpy.isnan(self.out[0])
Expand Down Expand Up @@ -984,10 +984,10 @@ def test_normal_coord_south_array(self):
self.out = self.ocb.normal_coord(self.lat, self.mlt)

self.assertTrue(numpy.all(numpy.less(abs(self.out[0] - self.ocb_lat),
1.0e-7,
1.0e-7, out=None,
where=~numpy.isnan(self.out[0]))))
self.assertTrue(numpy.all(numpy.less(abs(self.out[1] - self.ocb_mlt),
1.0e-7,
1.0e-7, out=None,
where=~numpy.isnan(self.out[1]))))
self.assertTrue(numpy.all(numpy.where(numpy.isnan(self.out[0]))[0]
== numpy.where(numpy.isnan(self.ocb_lat))[0]))
Expand Down Expand Up @@ -1041,11 +1041,11 @@ def test_revert_coord_south_array(self):
self.r_corr)

self.assertTrue(numpy.all(numpy.less(abs(self.out[0] - self.lat),
1.0e-7,
1.0e-7, out=None,
where=~numpy.isnan(self.out[0]))
| numpy.isnan(self.out[0])))
self.assertTrue(numpy.all(numpy.less(abs(self.out[1] - self.mlt),
1.0e-7,
1.0e-7, out=None,
where=(~numpy.isnan(self.out[1])
& (self.lat > -90.0)))
| numpy.isnan(self.out[0])
Expand Down
18 changes: 9 additions & 9 deletions ocbpy/tests/test_ocb_scaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -540,10 +540,10 @@ def test_update_loc_coords_float(self):

# Evaluate the output
self.assertAlmostEqual(
float(self.vdata.lat), mag_out[coord][0], places=4,
self.vdata.lat.item(), mag_out[coord][0], places=4,
msg="unexpected magnetic latitude")
self.assertAlmostEqual(
float(self.vdata.lt), mag_out[coord][1], places=4,
self.vdata.lt.item(), mag_out[coord][1], places=4,
msg="unexpected MLT")
self.assertRegex(self.vdata.loc_coord, "magnetic")

Expand All @@ -552,9 +552,9 @@ def test_update_loc_coords_float(self):
coord=coord)

# Evaluate the output; note the loss of precision
self.assertAlmostEqual(float(self.vdata.lat), 75.0, places=1,
self.assertAlmostEqual(self.vdata.lat.item(), 75.0, places=1,
msg="unexpected geographic latitude")
self.assertAlmostEqual(float(self.vdata.lt), 22.0, places=1,
self.assertAlmostEqual(self.vdata.lt.item(), 22.0, places=1,
msg="unexpected SLT")
self.assertRegex(self.vdata.loc_coord, coord)
return
Expand Down Expand Up @@ -722,26 +722,26 @@ def test_update_vect_and_loc_coords_float(self):

# Evaluate the output
self.assertAlmostEqual(
float(self.vdata.vect_n),
self.vdata.vect_n.item(),
mag_out[coord][loc_coord]['vect_n'],
places=4, msg="unexpected north component")
self.assertAlmostEqual(
float(self.vdata.vect_e),
self.vdata.vect_e.item(),
mag_out[coord][loc_coord]['vect_e'],
places=4, msg="unexpected east component")
self.assertAlmostEqual(
float(self.vdata.vect_z),
self.vdata.vect_z.item(),
mag_out[coord][loc_coord]['vect_z'],
places=4, msg="unexpected vertical component")
self.assertRegex(self.vdata.vect_coord, "magnetic")
self.assertRegex(self.vdata.loc_coord, "magnetic")

if loc_coord in mag_out.keys():
self.assertAlmostEqual(
float(self.vdata.lat), mag_out[loc_coord]['lat'],
self.vdata.lat.item(), mag_out[loc_coord]['lat'],
places=4, msg="unexpected magnetic latitude")
self.assertAlmostEqual(
float(self.vdata.lt), mag_out[loc_coord]['lt'],
self.vdata.lt.item(), mag_out[loc_coord]['lt'],
places=4, msg="unexpected MLT")
return

Expand Down
Loading
Loading