#!/usr/bin/env python
# -*- coding: utf-8 -*-
# DOI: 10.5281/zenodo.1179230
# Full license can be found in License.md
#
# DISTRIBUTION STATEMENT A: Approved for public release. Distribution is
# unlimited.
# ----------------------------------------------------------------------------
"""Functions that specify the boundary location as a function of MLT.
References
----------
.. [4] Burrell, A. G. et al.: AMPERE Polar Cap Boundaries, Ann. Geophys., 38,
481-490, doi:10.5194/angeo-38-481-2020, 2020.
.. [6] Chisham, G. et al. (2022) Ionospheric Boundaries Derived from Auroral
Images. JGR Space Physics, 127, 7, e2022JA030622, doi:10.1029/2022JA030622.
"""
import numpy as np
from ocbpy.ocb_time import hr2rad
[docs]
def circular(mlt, r_add=0.0):
"""Return a circular boundary correction.
Parameters
----------
mlt : float or array-like
Magnetic local time in hours (not actually used)
r_add : float
Offset added to default radius in degrees. Positive values shift the
boundary equatorward, whilst negative values shift the boundary
poleward. (default=0.0)
Returns
-------
r_corr : float or array-like
Radius correction in degrees at this MLT
"""
mlt = np.asarray(mlt)
r_corr = np.full(shape=mlt.shape, fill_value=r_add)
return r_corr
[docs]
def elliptical(mlt, instrument='ampere', method='median'):
"""Return the results of an elliptical correction to the data boundary.
Parameters
----------
mlt : float or array-like
Magnetic local time in hours
instrument : str
Data set's instrument name (default='ampere')
method : str
Method used to calculate the elliptical correction, accepts
'median' or 'gaussian'. (default='median')
Returns
-------
r_corr : float or array-like
Radius correction in degrees at this MLT
References
----------
Prefered AMPERE boundary correction validated in [4]_.
"""
if instrument.lower() != 'ampere':
raise ValueError("no elliptical correction for {:}".format(instrument))
method = method.lower()
coeff = {"median": {"a": 4.01, "e": 0.55, "t": -0.92},
"gaussian": {"a": 4.41, "e": 0.51, "t": -0.95}}
if method not in coeff.keys():
raise ValueError("unknown coefficient computation method")
mlt_rad = hr2rad(mlt)
r_corr = (coeff[method]["a"] * (1.0 - coeff[method]["e"]**2)
/ (1.0 + coeff[method]["e"] * np.cos(mlt_rad
- coeff[method]["t"])))
# Because this is a poleward correction, return the negative
return -r_corr
[docs]
def harmonic(mlt, instrument='ampere', method='median'):
"""Return the results of a harmonic fit correction to the data boundary.
Parameters
----------
mlt : float or array-like
Magnetic local time in hours
instrument : str
Data set's instrument name (default='ampere')
method : str
Method used to determine coefficients; accepts 'median' or
'gaussian' when `instrument` is 'ampere'. Otherwise, accepts 'eab' or
'ocb'. (default='median')
Returns
-------
r_corr : float or array-like
Radius correction in degrees at this MLT
References
----------
AMPERE boundaries obtained from [4]_. IMAGE boundaries obtained from [6]_.
"""
# Define the harmonic coefficients for each instrument and method/location
coeff = {'ampere': {'median': [3.31000535, -0.5452934, -1.24389141,
2.42619653, -0.66677988, -1.03467488,
-0.30763009, 0.52426756, 0.04359299,
0.60201848, 0.50618522, 1.04360529,
0.25186405],
'gaussian': [3.80100827, 0.98555723, -3.43760943,
1.85084271, -0.36730751, -0.81975654,
-1.02823832, 1.30637288, -0.53599218,
0.40380183, -1.22462708, -1.2733629,
-0.62743381]},
'si12': {'ocb': [0.0405, -1.5078, 1.0, 0.5095, 1.0, 0.9371, 1.0,
0.0708, 1.0, 0.0, 1.0, 0.0, 1.0],
'eab': [-0.1447, -1.9779, 1.0, 2.6799, 1.0, 0.5778, 1.0,
-1.2297, 1.0, 0.0, 1.0, 0.0, 1.0]},
'si13': {'ocb': [0.5797, -0.6837, 1.0, -0.5020, 1.0, 0.2971, 1.0,
-0.4173, 1.0, 0.0, 1.0, 0.0, 1.0],
'eab': [0.2500, -2.9931, 1.0, 0.8818, 1.0, 0.8511, 1.0,
-0.6300, 1.0, 0.0, 1.0, 0.0, 1.0]},
'wic': {'ocb': [1.0298, -1.1249, 1.0, -0.7380, 1.0, 0.1838, 1.0,
-0.6171, 1.0, 0.0, 1.0, 0.0, 1.0],
'eab': [-0.4935, -2.1186, 1.0, 0.3188, 1.0, 0.5749, 1.0,
-0.3118, 1.0, 0.0, 1.0, 0.0, 1.0]}}
# Check the inputs
inst = instrument.lower()
if inst not in coeff.keys():
raise ValueError("no harmonic correction for {:}".format(instrument))
method = method.lower()
if method not in coeff[inst].keys():
raise ValueError("".join(["unknown coefficient computation method, ",
"expects one of: {:}".format(
coeff[inst].keys())]))
# Calculate the offset
rad_mlt = hr2rad(mlt)
r_corr = coeff[inst][method][0] \
+ coeff[inst][method][1] * np.cos(rad_mlt + coeff[inst][method][2]) \
+ coeff[inst][method][3] * np.sin(rad_mlt + coeff[inst][method][4]) \
+ coeff[inst][method][5] * np.cos(2.0 * (
rad_mlt + coeff[inst][method][6])) \
+ coeff[inst][method][7] * np.sin(2.0 * (
rad_mlt + coeff[inst][method][8])) \
+ coeff[inst][method][9] * np.cos(3.0 * (
rad_mlt + coeff[inst][method][10])) \
+ coeff[inst][method][11] * np.sin(3.0 * (
rad_mlt + coeff[inst][method][12]))
# Because this is a poleward shift, return the negative of the correction
return -r_corr