From cdefb2428394e056831dc94abb0945bc85b2cc98 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 14:37:13 -0400 Subject: [PATCH 01/20] MAINT: removed support for old zenodo_get Removed the support for the old zenodo_get downloading formulation. --- ocbpy/boundaries/dmsp_ssj_files.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ocbpy/boundaries/dmsp_ssj_files.py b/ocbpy/boundaries/dmsp_ssj_files.py index 74279af7..b171f4e0 100644 --- a/ocbpy/boundaries/dmsp_ssj_files.py +++ b/ocbpy/boundaries/dmsp_ssj_files.py @@ -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__ From 57cb632ba621bbdf2a6bf5e0b95a87584a789219 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 14:37:45 -0400 Subject: [PATCH 02/20] MAINT: added a version limit Added a lower limit for zenodo_get. --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e843883a..57023e4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,14 +55,14 @@ classifiers = [ [project.optional-dependencies] pysat_instruments = [ "pysat>=3.2.1" ] -dmsp_ssj = [ "zenodo-get" ] +dmsp_ssj = [ "zenodo-get>=2.0.0" ] doc = [ "numpydoc", "pyproject-parser", "pysat>=3.2.1", "sphinx>=1.3", "sphinx-rtd-theme", - "zenodo-get", + "zenodo-get>=2.0.0", ] test = [ "coverage[toml]", From 4e91faaf6bdbfa805b91526a533b9190af5ae900 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 14:43:16 -0400 Subject: [PATCH 03/20] MAINT: added Python 3.14 Added support for Python 3.14 --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 57023e4c..d9ed3035 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,6 +46,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", 'Operating System :: Unix', 'Operating System :: POSIX', 'Operating System :: POSIX :: Linux', From 2c3d75c7fce8af1b552db97fd15e70bf437f36fd Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 14:43:45 -0400 Subject: [PATCH 04/20] MAINT: added support for Python 3.14 Added testing for Python 3.14 and updated GitHub action versions. --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1d0bb489..1a07e83d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -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 }} From 3b0e1d103cd6e56a0b7e8cbb19acf5de4f4a9a26 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 14:44:21 -0400 Subject: [PATCH 05/20] MAINT: updated GitHub Action versions Updated the general and Python GitHub action versions to the most recent ones. --- .github/workflows/docs.yml | 6 +++--- .github/workflows/pip_rc_install.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 78e36ed9..c7a1634c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -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 }} diff --git a/.github/workflows/pip_rc_install.yml b/.github/workflows/pip_rc_install.yml index 1124b9ba..d54da2ba 100644 --- a/.github/workflows/pip_rc_install.yml +++ b/.github/workflows/pip_rc_install.yml @@ -13,14 +13,14 @@ 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 }} From 0ab8802581edefa3d6e988a24d7aa82f500e3e78 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 14:45:52 -0400 Subject: [PATCH 06/20] DOC: update changelog Add a summary of changes to the changelog. --- Changelog.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Changelog.rst b/Changelog.rst index 66184879..a066ae82 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -6,6 +6,9 @@ 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 0.6.0 (07-07-2025) ------------------ From cc6c36870f54a48374d3be9e55d4aa6fa84046b4 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 14:48:00 -0400 Subject: [PATCH 07/20] DOC: update supported versions Update the supported versions for Python and dependencies in the docs. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1abf5c72..4e767f25 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ 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 @@ -53,7 +53,7 @@ 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. From 351e7c2c01940c5192047306376026ce801ccc16 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 16:51:37 -0400 Subject: [PATCH 08/20] MAINT: numpy deprecation warnings Addressed numpy deprecation warnings for: - not providing output location in greater/less evaluations, and - extracting an item from a zero-sized array. --- ocbpy/ocb_scaling.py | 6 +-- ocbpy/ocb_time.py | 12 ++--- ocbpy/tests/test_boundary_dual.py | 12 ++--- ocbpy/tests/test_boundary_ocb.py | 16 +++---- ocbpy/tests/test_ocb_scaling.py | 18 ++++---- ocbpy/vectors.py | 74 +++++++++++++++++-------------- 6 files changed, 74 insertions(+), 64 deletions(-) diff --git a/ocbpy/ocb_scaling.py b/ocbpy/ocb_scaling.py index 0378157a..965a7f32 100644 --- a/ocbpy/ocb_scaling.py +++ b/ocbpy/ocb_scaling.py @@ -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())])) @@ -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 == (): @@ -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 == (): diff --git a/ocbpy/ocb_time.py b/ocbpy/ocb_time.py index db915b27..9d0b46b7 100644 --- a/ocbpy/ocb_time.py +++ b/ocbpy/ocb_time.py @@ -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 diff --git a/ocbpy/tests/test_boundary_dual.py b/ocbpy/tests/test_boundary_dual.py index 5982e5ae..b64c8da3 100644 --- a/ocbpy/tests/test_boundary_dual.py +++ b/ocbpy/tests/test_boundary_dual.py @@ -586,7 +586,7 @@ 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)) @@ -594,7 +594,7 @@ def eval_coords(self, hemisphere=1, tol=1.0e-7, ind=None, revert=False, 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)) @@ -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])) @@ -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: @@ -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])) diff --git a/ocbpy/tests/test_boundary_ocb.py b/ocbpy/tests/test_boundary_ocb.py index 467ed8c1..993b6da3 100644 --- a/ocbpy/tests/test_boundary_ocb.py +++ b/ocbpy/tests/test_boundary_ocb.py @@ -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])) @@ -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]) @@ -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])) @@ -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]) diff --git a/ocbpy/tests/test_ocb_scaling.py b/ocbpy/tests/test_ocb_scaling.py index f2936023..e326ff97 100644 --- a/ocbpy/tests/test_ocb_scaling.py +++ b/ocbpy/tests/test_ocb_scaling.py @@ -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") @@ -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 @@ -722,15 +722,15 @@ 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") @@ -738,10 +738,10 @@ def test_update_vect_and_loc_coords_float(self): 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 diff --git a/ocbpy/vectors.py b/ocbpy/vectors.py index d176eb79..83427c4d 100644 --- a/ocbpy/vectors.py +++ b/ocbpy/vectors.py @@ -98,10 +98,10 @@ def calc_vec_pole_angle(data_lt, data_lat, pole_lt, pole_lat): else: flat_mask = (((del_long == 0) | (abs(del_long) == np.pi)) & np.greater(abs(data_lat), abs(pole_lat), - where=~np.isnan(del_long))) + where=~np.isnan(del_long), out=None)) zero_mask = (((del_long == 0) | (abs(del_long) == np.pi)) & np.less_equal(abs(data_lat), abs(pole_lat), - where=~np.isnan(del_long))) + where=~np.isnan(del_long), out=None)) pole_angle[flat_mask] = 180.0 pole_angle[zero_mask] = 0.0 @@ -176,39 +176,43 @@ def define_pole_quadrants(data_lt, pole_lt, pole_angle): pole_quad = np.zeros(shape=np.asarray(del_lt).shape) # Determine which differences need to be - neg_mask = np.less(del_lt, 0.0, where=~np.isnan(del_lt)) & ~np.isnan(del_lt) + neg_mask = np.less(del_lt, 0.0, where=~np.isnan(del_lt), + out=None) & ~np.isnan(del_lt) while np.any(neg_mask): if len(del_lt.shape) == 0: del_lt += 24.0 - neg_mask = np.less(del_lt, 0.0) # Has one finite value + neg_mask = np.less(del_lt, 0.0, out=None) # Has one finite value else: del_lt[neg_mask] += 24.0 - neg_mask = np.less(del_lt, 0.0, + neg_mask = np.less(del_lt, 0.0, out=None, where=~np.isnan(del_lt)) & ~np.isnan(del_lt) - large_mask = np.greater_equal(abs(del_lt), 24.0, + large_mask = np.greater_equal(abs(del_lt), 24.0, out=None, where=~np.isnan(del_lt)) & ~np.isnan(del_lt) while np.any(large_mask): if len(del_lt.shape) == 0: del_lt -= 24.0 * np.sign(del_lt) - large_mask = np.greater_equal(abs(del_lt), 24.0) # One finite value + # One finite value + large_mask = np.greater_equal(abs(del_lt), 24.0, out=None) else: del_lt[large_mask] -= 24.0 * np.sign(del_lt[large_mask]) - large_mask = np.greater_equal(abs(del_lt), 24.0, + large_mask = np.greater_equal(abs(del_lt), 24.0, out=None, where=~np.isnan(del_lt)) & ~np.isnan( del_lt) # Find the quadrant in which the OCB pole lies nan_mask = ~np.isnan(pole_angle) & ~np.isnan(del_lt) - quad1_mask = np.less(pole_angle, 90.0, where=nan_mask) & np.less( - del_lt, 12.0, where=nan_mask) & nan_mask - quad2_mask = np.less(pole_angle, 90.0, where=nan_mask) & np.greater_equal( - del_lt, 12.0, where=nan_mask) & nan_mask + quad1_mask = np.less(pole_angle, 90.0, where=nan_mask, out=None) & np.less( + del_lt, 12.0, where=nan_mask, out=None) & nan_mask + quad2_mask = np.less( + pole_angle, 90.0, where=nan_mask, out=None) & np.greater_equal( + del_lt, 12.0, where=nan_mask, out=None) & nan_mask quad3_mask = np.greater_equal( - pole_angle, 90.0, where=nan_mask) & np.greater_equal( - del_lt, 12.0, where=nan_mask) & nan_mask - quad4_mask = np.greater_equal(pole_angle, 90.0, where=nan_mask) & np.less( - del_lt, 12.0, where=nan_mask) & nan_mask + pole_angle, 90.0, where=nan_mask, out=None) & np.greater_equal( + del_lt, 12.0, where=nan_mask, out=None) & nan_mask + quad4_mask = np.greater_equal( + pole_angle, 90.0, where=nan_mask, out=None) & np.less( + del_lt, 12.0, where=nan_mask, out=None) & nan_mask if len(pole_quad.shape) == 0: if np.all(quad1_mask): @@ -255,14 +259,16 @@ def define_vect_quadrants(vect_n, vect_e): # Get the masks for non-fill values in each quadrant nan_mask = ~np.isnan(vect_n) & ~np.isnan(vect_e) quad1_mask = np.greater_equal( - vect_n, 0.0, where=nan_mask) & np.greater_equal( - vect_e, 0.0, where=nan_mask) & nan_mask - quad2_mask = np.greater_equal(vect_n, 0.0, where=nan_mask) & np.less( - vect_e, 0.0, where=nan_mask) & nan_mask - quad3_mask = np.less(vect_n, 0.0, where=nan_mask) & np.less( - vect_e, 0.0, where=nan_mask) & nan_mask - quad4_mask = np.less(vect_n, 0.0, where=nan_mask) & np.greater_equal( - vect_e, 0.0, where=nan_mask) & nan_mask + vect_n, 0.0, where=nan_mask, out=None) & np.greater_equal( + vect_e, 0.0, where=nan_mask, out=None) & nan_mask + quad2_mask = np.greater_equal( + vect_n, 0.0, where=nan_mask, out=None) & np.less( + vect_e, 0.0, where=nan_mask, out=None) & nan_mask + quad3_mask = np.less(vect_n, 0.0, where=nan_mask, out=None) & np.less( + vect_e, 0.0, where=nan_mask, out=None) & nan_mask + quad4_mask = np.less( + vect_n, 0.0, where=nan_mask, out=None) & np.greater_equal( + vect_e, 0.0, where=nan_mask, out=None) & nan_mask # Initialize the output vect_quad = np.zeros(shape=nan_mask.shape) @@ -466,13 +472,14 @@ def calc_dest_vec_sign(pole_quad, vect_quad, base_naz_angle, pole_angle, pmask = (quads[1][1] | quads[2][2] | quads[3][3] | quads[4][4] | ((quads[1][4] | quads[2][3]) & np.less_equal( - base_naz_angle, pole_plus, where=nan_mask)) + base_naz_angle, pole_plus, where=nan_mask, out=None)) | ((quads[1][2] | quads[2][1]) & np.less_equal( - base_naz_angle, minus_pole, where=nan_mask)) + base_naz_angle, minus_pole, where=nan_mask, out=None)) | ((quads[3][4] | quads[4][3]) & np.greater_equal( - base_naz_angle, 180.0 - pole_minus, where=nan_mask)) + base_naz_angle, 180.0 - pole_minus, where=nan_mask, + out=None)) | ((quads[3][2] | quads[4][1]) & np.greater_equal( - base_naz_angle, pole_minus, where=nan_mask))) + base_naz_angle, pole_minus, where=nan_mask, out=None))) if np.any(pmask): if len(vsigns["north"].shape) == 0: @@ -491,13 +498,13 @@ def calc_dest_vec_sign(pole_quad, vect_quad, base_naz_angle, pole_angle, pmask = (quads[1][4] | quads[2][1] | quads[3][2] | quads[4][3] | ((quads[1][1] | quads[4][4]) & np.greater_equal( - base_naz_angle, pole_angle, where=nan_mask)) + base_naz_angle, pole_angle, where=nan_mask, out=None)) | ((quads[3][1] | quads[2][4]) & np.less_equal( - base_naz_angle, minus_pole, where=nan_mask)) + base_naz_angle, minus_pole, where=nan_mask, out=None)) | ((quads[4][2] | quads[1][3]) & np.greater_equal( - base_naz_angle, minus_pole, where=nan_mask)) + base_naz_angle, minus_pole, where=nan_mask, out=None)) | ((quads[2][2] | quads[3][3]) & np.less_equal( - base_naz_angle, pole_angle, where=nan_mask))) + base_naz_angle, pole_angle, where=nan_mask, out=None))) if np.any(pmask): if len(vsigns["east"].shape) == 0: @@ -618,7 +625,8 @@ def adjust_vector(vect_lt, vect_lat, vect_n, vect_e, vect_z, vect_quad, # Determine if the measurement is on or between the poles. This does # not affect the vertical direction sign_mask = (pole_angle == 0.0) & np.greater_equal( - vect_lat, pole_lat, where=~np.isnan(vect_lat)) & ~np.isnan(vect_lat) + vect_lat, pole_lat, where=~np.isnan(vect_lat), + out=None) & ~np.isnan(vect_lat) if np.any(sign_mask): if len(out_shape) == 0: From 861494074d5058776f9cfe1b49a733b5be92883f Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 16:52:34 -0400 Subject: [PATCH 09/20] DOC: added numpy changes to changelog Added the numpy changes to the changelog. --- Changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.rst b/Changelog.rst index a066ae82..e01a1845 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -9,6 +9,7 @@ Summary of all changes made since the first stable release * 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) ------------------ From fc6d4d1789979a8f149de2e2f57a5aae47821c7f Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 17:03:12 -0400 Subject: [PATCH 10/20] MAINT: fixed broken links Zenodo has disabled checks by sphinx-build, so remove the active linking in the docs. --- docs/citing.rst | 2 +- docs/examples/ex_dmsp.rst | 13 ++++++------- ocbpy/boundaries/dmsp_ssj_files.py | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/citing.rst b/docs/citing.rst index 1e4fd674..5367259d 100644 --- a/docs/citing.rst +++ b/docs/citing.rst @@ -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: diff --git a/docs/examples/ex_dmsp.rst b/docs/examples/ex_dmsp.rst index 069037ad..8ad12287 100644 --- a/docs/examples/ex_dmsp.rst +++ b/docs/examples/ex_dmsp.rst @@ -13,13 +13,12 @@ need the `ssj_auroral_boundary `__ package, but now we preferentially support using the `zendodo_get `__ package to obtain the -boundary files from their -`archive `__. 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. :: diff --git a/ocbpy/boundaries/dmsp_ssj_files.py b/ocbpy/boundaries/dmsp_ssj_files.py index b171f4e0..e556fc2a 100644 --- a/ocbpy/boundaries/dmsp_ssj_files.py +++ b/ocbpy/boundaries/dmsp_ssj_files.py @@ -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 """ From 1d585865df89868ce72711a7d2b33cf086ba407a Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 17:31:56 -0400 Subject: [PATCH 11/20] MAINT: update pandas access Update the pandas index access to use `iloc`. --- ocbpy/instruments/pysat_instruments.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ocbpy/instruments/pysat_instruments.py b/ocbpy/instruments/pysat_instruments.py index 1c139f88..fdb8dd12 100644 --- a/ocbpy/instruments/pysat_instruments.py +++ b/ocbpy/instruments/pysat_instruments.py @@ -494,7 +494,7 @@ def add_ocb_to_data(pysat_inst, mlat_name='', mlt_name='', height_name='', vname = vector_names[eattr][ikey] if vname in pysat_inst.variables: if time_mask is None: - vector_init[ikey] = pysat_inst[vname][iout] + vector_init[ikey] = pysat_inst[vname].iloc[iout] else: vector_init[ikey] = reshape_pad_mask_flatten( pysat_inst[vname], time_mask) @@ -529,7 +529,7 @@ def add_ocb_to_data(pysat_inst, mlat_name='', mlt_name='', height_name='', for eattr in scale_names: oattr = "{:s}_{:s}".format(eattr, bname) if time_mask is None: - evar = pysat_inst[eattr][iout] + evar = pysat_inst[eattr].iloc[iout] else: evar = reshape_pad_mask_flatten(pysat_inst[eattr], time_mask) From fa97ed825a0fac713331ddcd3d25e9f4ed48e371 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Wed, 1 Apr 2026 17:43:04 -0400 Subject: [PATCH 12/20] Revert "MAINT: update pandas access" This reverts commit 1d585865df89868ce72711a7d2b33cf086ba407a. --- ocbpy/instruments/pysat_instruments.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ocbpy/instruments/pysat_instruments.py b/ocbpy/instruments/pysat_instruments.py index fdb8dd12..1c139f88 100644 --- a/ocbpy/instruments/pysat_instruments.py +++ b/ocbpy/instruments/pysat_instruments.py @@ -494,7 +494,7 @@ def add_ocb_to_data(pysat_inst, mlat_name='', mlt_name='', height_name='', vname = vector_names[eattr][ikey] if vname in pysat_inst.variables: if time_mask is None: - vector_init[ikey] = pysat_inst[vname].iloc[iout] + vector_init[ikey] = pysat_inst[vname][iout] else: vector_init[ikey] = reshape_pad_mask_flatten( pysat_inst[vname], time_mask) @@ -529,7 +529,7 @@ def add_ocb_to_data(pysat_inst, mlat_name='', mlt_name='', height_name='', for eattr in scale_names: oattr = "{:s}_{:s}".format(eattr, bname) if time_mask is None: - evar = pysat_inst[eattr].iloc[iout] + evar = pysat_inst[eattr][iout] else: evar = reshape_pad_mask_flatten(pysat_inst[eattr], time_mask) From 7995ff9329de3839113b929c2d7943bf84e826a5 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Thu, 2 Apr 2026 16:11:58 -0400 Subject: [PATCH 13/20] BUG: fixed program name Updated the program name in the pip workflow to be correct. --- .github/workflows/pip_rc_install.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pip_rc_install.yml b/.github/workflows/pip_rc_install.yml index d54da2ba..70aa2e53 100644 --- a/.github/workflows/pip_rc_install.yml +++ b/.github/workflows/pip_rc_install.yml @@ -27,7 +27,7 @@ jobs: - 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 From d1732d36b891f31363ea080c74deee5ed1aee923 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Thu, 2 Apr 2026 16:12:40 -0400 Subject: [PATCH 14/20] BUG: test code with AACGMV2 release candidate Test this code with the AACGMV2 release candidate. --- .github/workflows/main.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1a07e83d..03651881 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,6 +38,12 @@ jobs: mkdir pysatData python -c "import pysat; pysat.params['data_dirs'] = 'pysatData'" + - name: Install AACGMV2 RC + run: | + pip uninstall aacgmv2 + pip install --no-deps --pre -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ aacgmv2 + python -c "import aacgmv2; print(aacgmv2.__version__)" + - name: Test PEP8 compliance run: flake8 . --count --show-source --statistics From 2422f151f8825d3f0eaa110861ef9261ff6702ac Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Thu, 2 Apr 2026 16:24:12 -0400 Subject: [PATCH 15/20] BUG: remove uninstall line Removed the uninstall line, just install the newer version. --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 03651881..f1b50d15 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,7 +40,6 @@ jobs: - name: Install AACGMV2 RC run: | - pip uninstall aacgmv2 pip install --no-deps --pre -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ aacgmv2 python -c "import aacgmv2; print(aacgmv2.__version__)" From b36cb8d1b1683933e653ffd0b0969dd1d2fed87c Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Thu, 2 Apr 2026 16:28:47 -0400 Subject: [PATCH 16/20] BUG: fix aacgmv2 rc install Specify the version number. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f1b50d15..310938e2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,7 +40,7 @@ jobs: - name: Install AACGMV2 RC run: | - pip install --no-deps --pre -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ aacgmv2 + pip install pip install -i https://test.pypi.org/simple/ aacgmv2==2.7.1rc1 python -c "import aacgmv2; print(aacgmv2.__version__)" - name: Test PEP8 compliance From dabaa5f19338ba55281dbf294adfc0a4fb4280b5 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Thu, 2 Apr 2026 16:33:59 -0400 Subject: [PATCH 17/20] BUG: fixed typo Fixed a typo in the TestPyPi install line. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 310938e2..465fac83 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,7 +40,7 @@ jobs: - name: Install AACGMV2 RC run: | - pip install pip install -i https://test.pypi.org/simple/ aacgmv2==2.7.1rc1 + pip install --no-deps -i https://test.pypi.org/simple/ aacgmv2==2.7.1rc1 python -c "import aacgmv2; print(aacgmv2.__version__)" - name: Test PEP8 compliance From 82e9029a6689a446155f0ff547aeff3263d622a3 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Thu, 2 Apr 2026 16:39:35 -0400 Subject: [PATCH 18/20] BUG: re-added extra flags Hopefully the install will go better and it won't try to install the dependencies. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 465fac83..cbb65c50 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,7 +40,7 @@ jobs: - name: Install AACGMV2 RC run: | - pip install --no-deps -i https://test.pypi.org/simple/ aacgmv2==2.7.1rc1 + pip install --no-deps --pre -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ aacgmv2==2.7.1rc1 python -c "import aacgmv2; print(aacgmv2.__version__)" - name: Test PEP8 compliance From 37f99de34888dff7b75132944b80150f22f6fe05 Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Tue, 7 Apr 2026 16:39:28 -0400 Subject: [PATCH 19/20] TST: remove the aacgmv2 test installation Now that the new version of AACGMV2 has been released, remove the test installation case. --- .github/workflows/main.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cbb65c50..1a07e83d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,11 +38,6 @@ jobs: mkdir pysatData python -c "import pysat; pysat.params['data_dirs'] = 'pysatData'" - - name: Install AACGMV2 RC - run: | - pip install --no-deps --pre -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ aacgmv2==2.7.1rc1 - python -c "import aacgmv2; print(aacgmv2.__version__)" - - name: Test PEP8 compliance run: flake8 . --count --show-source --statistics From 74c6533dd0cdc0f10b02deb4d2500680775480ce Mon Sep 17 00:00:00 2001 From: "Angeline G. Burrell" Date: Tue, 7 Apr 2026 16:39:51 -0400 Subject: [PATCH 20/20] MAINT: set lower limit for aacgmv2 Set a lower limit for AACGMV2, set to the most recent version. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d9ed3035..82e41de0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ maintainers = [ ] requires-python = ">=3.10" dependencies = [ - "aacgmv2", + "aacgmv2>=2.7.1", "numpy", ] readme = "README.md"