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/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 }} diff --git a/.github/workflows/pip_rc_install.yml b/.github/workflows/pip_rc_install.yml index 1124b9ba..70aa2e53 100644 --- a/.github/workflows/pip_rc_install.yml +++ b/.github/workflows/pip_rc_install.yml @@ -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 diff --git a/Changelog.rst b/Changelog.rst index 66184879..e01a1845 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -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) ------------------ 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. 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 74279af7..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 """ @@ -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__ 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: diff --git a/pyproject.toml b/pyproject.toml index e843883a..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" @@ -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', @@ -55,14 +56,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]",