Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5a331bd
Merge pull request #155 from aburrell/main
aburrell Aug 11, 2025
6bf7134
ENH: added Gussenhoven model
aburrell Sep 12, 2025
96a47b8
DOC: updated changelog
aburrell Sep 12, 2025
9879d47
BUG: fixed for list input
aburrell Sep 12, 2025
73f9793
TST: added Gussenhoven unit tests
aburrell Sep 12, 2025
d6dfd62
STY: removed whitespace
aburrell Sep 17, 2025
b5adeb0
DOC: added Gussenhoven model to docs
aburrell Sep 17, 2025
026cd27
BUG: fixed doc reference
aburrell Sep 17, 2025
aa81268
BUG: fixed angle range
aburrell Sep 17, 2025
a89d510
BUG: coveralls implementation
aburrell Sep 18, 2025
67ee049
Merge pull request #157 from aburrell/gussenhoven_model
aburrell Sep 18, 2025
cdefb24
MAINT: removed support for old zenodo_get
aburrell Apr 1, 2026
57cb632
MAINT: added a version limit
aburrell Apr 1, 2026
4e91faa
MAINT: added Python 3.14
aburrell Apr 1, 2026
2c3d75c
MAINT: added support for Python 3.14
aburrell Apr 1, 2026
3b0e1d1
MAINT: updated GitHub Action versions
aburrell Apr 1, 2026
0ab8802
DOC: update changelog
aburrell Apr 1, 2026
cc6c368
DOC: update supported versions
aburrell Apr 1, 2026
351e7c2
MAINT: numpy deprecation warnings
aburrell Apr 1, 2026
8614940
DOC: added numpy changes to changelog
aburrell Apr 1, 2026
fc6d4d1
MAINT: fixed broken links
aburrell Apr 1, 2026
1d58586
MAINT: update pandas access
aburrell Apr 1, 2026
fa97ed8
Revert "MAINT: update pandas access"
aburrell Apr 1, 2026
7995ff9
BUG: fixed program name
aburrell Apr 2, 2026
d1732d3
BUG: test code with AACGMV2 release candidate
aburrell Apr 2, 2026
2422f15
BUG: remove uninstall line
aburrell Apr 2, 2026
b36cb8d
BUG: fix aacgmv2 rc install
aburrell Apr 2, 2026
dabaa5f
BUG: fixed typo
aburrell Apr 2, 2026
82e9029
BUG: re-added extra flags
aburrell Apr 2, 2026
37f99de
TST: remove the aacgmv2 test installation
aburrell Apr 7, 2026
74c6533
MAINT: set lower limit for aacgmv2
aburrell Apr 7, 2026
726edb2
Merge pull request #159 from aburrell/version_updates
aburrell May 11, 2026
bf06e8e
ENH: added the CHAMP auroral boundary model
aburrell May 11, 2026
dea5016
TST: added CHAMP unit tests
aburrell May 11, 2026
a654879
DOC: added CHAMP documentation
aburrell May 11, 2026
1f0a0c7
DOC: updated changelog
aburrell May 11, 2026
e903b6d
Merge pull request #160 from aburrell/ch_aurora_2014_model
aburrell May 12, 2026
4872b47
DOC: added AI policy
aburrell May 12, 2026
4ab3a82
DOC: updated pull request template
aburrell May 12, 2026
648e898
DOC: updated changelog
aburrell May 12, 2026
62e6dc2
MAINT: updated `zenodo_get` download checks
aburrell May 13, 2026
da02ef7
BUG: debug statement
aburrell May 13, 2026
8a379ae
BUG: fix coveralls implementation
aburrell May 14, 2026
fc59136
BUG: re-add pysat
aburrell May 14, 2026
3f8d076
BUG: fixed `install-extras` name
aburrell May 22, 2026
fddd88e
Merge pull request #161 from aburrell/ai_policy
aburrell May 22, 2026
92da111
REL: updated version number
aburrell May 22, 2026
7c50542
REL: set target release date
aburrell May 22, 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
1 change: 1 addition & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import ocbpy
- [ ] Make sure you are merging into the ``develop`` (not ``main``) branch
- [ ] My commits are formatted appropriately (following the SciPy/NumPy style)
- [ ] My code follows the style guidelines of this project
- [ ] I assert that I have not used AI in the development of this pull request
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
Expand Down
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
57 changes: 20 additions & 37 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,20 @@ jobs:
fail-fast: false
matrix:
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
python-version: ["3.10", "3.11", "3.12", "3.13"]
install-extras: ["base", "pysat_instruments", "dmsp_ssj"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
install-extras: ["base", "dmsp_ssj"]
include:
# Pysat test for only pysat-passing Python version
- python-version: "3.10"
os: "ubuntu-latest"
install-extras: "pysat_instruments"

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 Expand Up @@ -50,43 +55,21 @@ jobs:
coverage report
coverage xml --rcfile=pyproject.toml

- name: Install and run Coveralls Reporter(Linux)
if: startsWith(matrix.os, 'ubuntu')
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
COVERALLS_PARALLEL: true
run: |
curl -sL https://coveralls.io/coveralls-linux.tar.gz | tar -xz
./coveralls report -f coverage.xml --parallel --repo-token=${{ secrets.COVERALLS_REPO_TOKEN }} --build-number ${{ github.run_number }}

- name: Install and run Coveralls Reporter (Windows)
if: startsWith(matrix.os, 'windows')
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
COVERALLS_PARALLEL: true
run: |
curl -L https://github.com/coverallsapp/coverage-reporter/releases/latest/download/coveralls-windows.exe -o coveralls.exe
./coveralls.exe report -f coverage.xml --parallel --repo-token=${{ secrets.COVERALLS_REPO_TOKEN }} --build-number ${{ github.run_number }}

- name: Report and run Coveralls (macOS)
if: startsWith(matrix.os, 'macos')
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
COVERALLS_PARALLEL: true
run: |
brew tap coverallsapp/coveralls --quiet
brew install coveralls --quiet
coveralls report -f coverage.xml --parallel --repo-token=${{ secrets.COVERALLS_REPO_TOKEN }} --build-number ${{ github.run_number }}
- name: Coveralls Parallel
uses: coverallsapp/github-action@v2
with:
flag-name: run=${{ join(matrix.*, '-') }}
parallel: true
format: cobertura
debug: true

finish:
name: Finish Coverage Analysis
needs: build
runs-on: "ubuntu-latest"
steps:
- name: Coveralls Finished
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
COVERALLS_PARALLEL: true
run: |
curl -sL https://coveralls.io/coveralls-linux.tar.gz | tar -xz
./coveralls done --build-number ${{ github.run_number }}
uses: coverallsapp/github-action@v2
with:
parallel-finished: true
carryforward: "all"
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
14 changes: 14 additions & 0 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,17 @@ To run a subset of tests from the test directory for a specific environment::
To run all the tests for a specific environment::

python -m unittest discover

Use of 'AI'
-----------

This project is human centered and developers do not use Artificial Inteligence
(AI) tools such as large language models in its creation or maintenance.
The purpose of this tool is to improve high-latitude science, and thus values
interactions with scientists and scientific programmers. Code generated by a
large language model or similar technology, such as Anthropic’s Claude,
GitHub/Microsoft’s Copilot, OpenAI’s ChatGPT, Facebook/Meta’s Code Llama et al.,
is not compliant with the covenants and representations of OCBpy’s Contributor’s
Agreement, and is thus not acceptable as code for OCBpy.


11 changes: 11 additions & 0 deletions Changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ Changelog

Summary of all changes made since the first stable release

0.7.0 (05-29-2026)
------------------
* ENH: Added the Gussenhoven (1983) model for the EAB
* ENH: Added the CH-Aurora-2014 model for the OCB and EAB
* ENH: Added an AI usage policy (no AI use allowed)
* DEP: Removed support for older versions of `zenodo_get`, updated download
checks to account for breaking changes made in the newer versions
* MAINT: Added support for Python 3.14
* MAINT: Updated GitHub CI actions
* MAINT: Updated numpy usage

0.6.0 (07-07-2025)
------------------
* ENH: Updated the AMPERE boundaries to include 2022-2024, inclusive
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
36 changes: 35 additions & 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 All @@ -112,3 +112,37 @@ when publishing your work.

* Starkov, G. V. (1994) Mathematical model of the auroral boundaries,
Geomagnetism and Aeronomy, English Translation, 34(3), 331-336.


.. _cite-guss:

Gussenhoven Model
-----------------

The Gussenhoven mathematical diffuse auroral boundary model is described in the
following article. If you use this model please cite both it and your Kp data
source when publishing your work.

* Gussenhoven, M. S. et al. (1983) Systematics of the Equatorward Diffuse
Auroral Boundary, J. Geophys. Res, 88(A7), 5692-5708.


.. _cite-xiong:

CH-Aurora-2014 Model
--------------------

The CH-Aurora-2014 auroral boundary model provides either a mathematical
description of the poleward and equatorward auroral boundaries in each
hemisphere or an assimilated location based on FAC observations of the auroral
boundaries in that hemisphere. The data that may be used to adjust the model
are described in the first article below, while the model itself is described in
the second article. If you use this model please cite both it and your Newell
Couping Function data source when publishing your work.

* Xiong, C., et al. (2014) Determining the boundaries of the auroral oval from
CHAMP field-aligned current signatures - Part 1, Ann. Geophys., 32,
pp 609-622, doi:10.5194/angeo-32-609-2014.
* Xiong, C. and H. Luhr (2014) An empirical model of the auroral oval derived
from CHAMP field-aligned current signatures - Part 2, Ann. Geophys., 32,
pp 623-631, doi:10.5194/angeo-32-623-2014
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
2 changes: 1 addition & 1 deletion docs/examples/ex_model_boundaries.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ be calculated for a set of MLTs using the

This provides the AACGMV2 magnetic latitude for the entire range of MLT at the
specified AL values. We can plot these boundaries, using the formatting function
previously defined in Example :ref:`format-polar-axes`.
previously defined in :ref:`set_up_polar_plot <format-polar-axes>`.

::

Expand Down
26 changes: 26 additions & 0 deletions docs/ocb_models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ in the code here using the boundary keyworkds: 'ocb', 'eab', and 'diffuse',
respectively.


.. _bound-model-guss:

Gussenhoven
-----------

The Gussenhoven 1983 model (see :ref:`cite-guss`) uses a mathematical
formulation based on DMSP data and the Kp index. They specify a single boundary:
the equatorward edge of the diffuse aurora. As this model defines the boundary
using separate linear fits for different MLT bins, the results may be returned
at the binned times ('binned'), at the nearest binned time ('closest'), or at
the requested times using a circle fit to all of binned times ('circle').


.. _bound-model-champ:

CH-Aurora-2014
--------------

The CH-Aurora-2014 model (see :ref:`cite-xiong`) uses a mathematical
formulation based on CHAMP field-aligned current (FAC) data and a delayed
time-history of the Newell Coupling Function. They specify both auroral
boundaries in each hemisphere. Although this model may be driven entirely by
the Newell Coupling Function, the authors recommend adjusting the model output
with CHAMP measurements of the FAC boundaries.


.. _bound-model-module:

Boundary Models Module
Expand Down
69 changes: 30 additions & 39 deletions ocbpy/boundaries/dmsp_ssj_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,14 @@

.. [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

"""

import datetime as dt
from io import StringIO
import hashlib
import numpy as np
import os
import sys
import zipfile

import aacgmv2
Expand Down Expand Up @@ -108,50 +107,42 @@ def fetch_ssj_boundary_files(stime=None, etime=None, out_dir=None,
if not os.path.isdir(out_dir):
raise ValueError("can't find the output directory")

# Download the zenodo archive, capturing the output
zenodo_io = StringIO()
sys.stdout = zenodo_io
sys.stderr = zenodo_io
# Download the zenodo archive
zenodo_get.download(doi=doi, output_dir=out_dir)

# 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')
# Get the checksum file (does not download)
zenodo_get.download(doi=doi, output_dir=out_dir, md5=True)
zenodo_checksum = os.path.join(out_dir, "md5sums.txt")

# Parse the output and retrieve files from the zip archive
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
zen_msg = zenodo_io.getvalue()
zen_split = zen_msg.split()
# Verify the checksum and retrieve the zip archive name
if os.path.isfile(zenodo_checksum):
with open(zenodo_checksum, 'r') as zcheck:
csum, zip_name = zcheck.read().split()

if zen_msg.find('Checksum is correct') < 0 and zen_msg.find(
'already downloaded correctly') < 0:
raise IOError('Bad checksum: {:s}'.format(zen_msg))
# Set the archive name
archive_name = os.path.join(out_dir, zip_name)

# Remove the checksum file if the download problem wasn't found there
if zenodo_checksum is not None:
os.remove(zenodo_checksum)
if not os.path.isfile(archive_name):
raise IOError(
'error downloading archive to output dir: {:}'.format(
archive_name))

# Get the archive name from the output
try:
link_ind = zen_split.index('Link:') + 1
# Get the archive checkshum
with open(os.path.join(out_dir, archive_name), 'rb') as afile:
asum = hashlib.md5(afile.read()).hexdigest()

# If the archive is already available, message may differ
zip_name = os.path.split(zen_split[link_ind])
while zip_name[-1].find(".zip") <= 0:
zip_name = os.path.split(zip_name[0])
zen_msg = "Checksum is correct" if asum == csum else "Corrupted data"
else:
zen_msg = "Checksum file not created"

# Set the archive name
archive_name = os.path.join(out_dir, zip_name[-1])
except (ValueError, IndexError):
raise IOError('unable to identify zenodo archive: {:}'.format(zen_msg))
# Remove the checksum file
if zenodo_checksum is not None:
os.remove(zenodo_checksum)

if not os.path.isfile(archive_name):
raise IOError('error downloading archive to output dir: {:}'.format(
archive_name))
# Evaluate checksum output
if zen_msg.find('Checksum is correct') < 0 and zen_msg.find(
'already downloaded correctly') < 0:
raise IOError('Bad checksum: {:s}'.format(zen_msg))

# Access the zip archive
with zipfile.ZipFile(archive_name, 'r') as zref:
Expand Down
Loading
Loading