Skip to content

Commit

Permalink
Merge branch 'develop' into sty/streamline_cdf_tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jklenzing committed Sep 7, 2022
2 parents 124d431 + 0d4deca commit 8c94ece
Show file tree
Hide file tree
Showing 7 changed files with 428 additions and 181 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ This project adheres to [Semantic Versioning](https://semver.org/).
* Fixed a bug in metadata when loading GOLD Nmax data.
* Fixed a bug in user feedback for `methods.cdaweb.download`
* Fixed a bug in loading ICON IVM data (added multi_file_day = True)
* Allow for array-like OMNI HRO meta data
* Fixed date handling for OMNI HRO downloads
* Maintenance
* Reduce duplication of code in instrument modules
* Include flake8 linting of docstrings and style in Github Actions
* Move OMNI HRO custom functions to a methods module
* Deprecate OMNI HRO custom functions in instrument module
* Documentation
* New logo added

Expand Down
4 changes: 2 additions & 2 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ Project maintainers who do not follow or enforce the Code of Conduct in good fai

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version]

[homepage]: https://contributor-covenant.org
[version]: https://contributor-covenant.org/version/1/4/
[homepage]: https://www.contributor-covenant.org
[version]: https://www.contributor-covenant.org/version/1/4/
4 changes: 2 additions & 2 deletions pysatNASA/instruments/cnofs_vefi.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
System (C/NOFS) satellite. Downloads data from the
NASA Coordinated Data Analysis Web (CDAWeb).
Description from CDAWeb:
Description from CDAWeb (with updated link):
The DC vector magnetometer on the CNOFS spacecraft is a three axis, fluxgate
sensor with active thermal control situated on a 0.6m boom. This magnetometer
Expand All @@ -15,7 +15,7 @@
spacecraft is to enable an accurate V x B measurement along the spacecraft
trajectory. In order to provide an in-flight calibration of the magnetic field
data, we compare the most recent POMME model (the POtsdam Magnetic Model of the
Earth, http://geomag.org/models/pomme5.html) with the actual magnetometer
Earth, https://geomag.us/models/pomme5.html) with the actual magnetometer
measurements to help determine a set of calibration parameters for the gains,
offsets, and non-orthogonality matrix of the sensor axes. The calibrated
magnetic field measurements are provided in the data file here. The VEFI
Expand Down
1 change: 1 addition & 0 deletions pysatNASA/instruments/methods/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
from pysatNASA.instruments.methods import de2 # noqa F401
from pysatNASA.instruments.methods import general # noqa F401
from pysatNASA.instruments.methods import icon # noqa F401
from pysatNASA.instruments.methods import omni # noqa F401
199 changes: 199 additions & 0 deletions pysatNASA/instruments/methods/omni.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# -*- coding: utf-8 -*-
"""Module for the OMNI HRO supporting functions."""


import numpy as np
import pandas as pds
from scipy import stats
import warnings

from pysat import logger


def time_shift_to_magnetic_poles(inst):
"""Shift OMNI times to intersection with the magnetic pole.
Parameters
----------
inst : Instrument class object
Instrument with OMNI HRO data
Note
----
- Time shift calculated using distance to bow shock nose (BSN)
and velocity of solar wind along x-direction.
- OMNI data is time-shifted to bow shock. Time shifted again
to intersections with magnetic pole.
Warnings
--------
Use at own risk.
"""

# Need to fill in Vx to get an estimate of what is going on.
inst['Vx'] = inst['Vx'].interpolate('nearest')
inst['Vx'] = inst['Vx'].fillna(method='backfill')
inst['Vx'] = inst['Vx'].fillna(method='pad')

inst['BSN_x'] = inst['BSN_x'].interpolate('nearest')
inst['BSN_x'] = inst['BSN_x'].fillna(method='backfill')
inst['BSN_x'] = inst['BSN_x'].fillna(method='pad')

# Make sure there are no gaps larger than a minute.
inst.data = inst.data.resample('1T').interpolate('time')

time_x = inst['BSN_x'] * 6371.2 / -inst['Vx']
idx, = np.where(np.isnan(time_x))
if len(idx) > 0:
logger.info(time_x[idx])
logger.info(time_x)
time_x_offset = [pds.DateOffset(seconds=time)
for time in time_x.astype(int)]
new_index = []
for i, time in enumerate(time_x_offset):
new_index.append(inst.data.index[i] + time)
inst.data.index = new_index
inst.data = inst.data.sort_index()

return


def calculate_clock_angle(inst):
"""Calculate IMF clock angle and magnitude of IMF in GSM Y-Z plane.
Parameters
-----------
inst : pysat.Instrument
Instrument with OMNI HRO data
"""

# Calculate clock angle in degrees
clock_angle = np.degrees(np.arctan2(inst['BY_GSM'], inst['BZ_GSM']))
clock_angle[clock_angle < 0.0] += 360.0
inst['clock_angle'] = pds.Series(clock_angle, index=inst.data.index)

# Calculate magnitude of IMF in Y-Z plane
inst['BYZ_GSM'] = pds.Series(np.sqrt(inst['BY_GSM']**2
+ inst['BZ_GSM']**2),
index=inst.data.index)

return


def calculate_imf_steadiness(inst, steady_window=15, min_window_frac=0.75,
max_clock_angle_std=(90.0 / np.pi),
max_bmag_cv=0.5):
"""Calculate IMF steadiness and add parameters to instrument data.
Parameters
----------
inst : pysat.Instrument
Instrument with OMNI HRO data
steady_window : int
Window for calculating running statistical moments in min (default=15)
min_window_frac : float
Minimum fraction of points in a window for steadiness to be calculated
(default=0.75)
max_clock_angle_std : float
Maximum standard deviation of the clock angle in degrees (default=22.5)
max_bmag_cv : float
Maximum coefficient of variation of the IMF magnitude in the GSM
Y-Z plane (default=0.5)
Note
----
Uses clock angle standard deviation and the coefficient of variation of
the IMF magnitude in the GSM Y-Z plane
"""

# We are not going to interpolate through missing values
rates = {'': 1, '1min': 1, '5min': 5}
sample_rate = int(rates[inst.tag])
max_wnum = np.floor(steady_window / sample_rate)
if max_wnum != steady_window / sample_rate:
steady_window = max_wnum * sample_rate
logger.warning("sample rate is not a factor of the statistical window")
logger.warning("new statistical window is {:.1f}".format(steady_window))

min_wnum = int(np.ceil(max_wnum * min_window_frac))

# Calculate the running coefficient of variation of the BYZ magnitude
byz_mean = inst['BYZ_GSM'].rolling(min_periods=min_wnum, center=True,
window=steady_window).mean()
byz_std = inst['BYZ_GSM'].rolling(min_periods=min_wnum, center=True,
window=steady_window).std()
inst['BYZ_CV'] = pds.Series(byz_std / byz_mean, index=inst.data.index)

# Calculate the running circular standard deviation of the clock angle
circ_kwargs = {'high': 360.0, 'low': 0.0, 'nan_policy': 'omit'}
try:
ca_std = \
inst['clock_angle'].rolling(min_periods=min_wnum,
window=steady_window,
center=True).apply(stats.circstd,
kwargs=circ_kwargs,
raw=True)
except TypeError:
warnings.warn(' '.join(['To automatically remove NaNs from the',
'calculation, please upgrade to scipy 1.4 or',
'newer']))
circ_kwargs.pop('nan_policy')
ca_std = \
inst['clock_angle'].rolling(min_periods=min_wnum,
window=steady_window,
center=True).apply(stats.circstd,
kwargs=circ_kwargs,
raw=True)
inst['clock_angle_std'] = pds.Series(ca_std, index=inst.data.index)

# Determine how long the clock angle and IMF magnitude are steady
imf_steady = np.zeros(shape=inst.data.index.shape)

steady = False
for i, cv in enumerate(inst.data['BYZ_CV']):
if steady:
del_min = int((inst.data.index[i]
- inst.data.index[i - 1]).total_seconds() / 60.0)
if np.isnan(cv) or np.isnan(ca_std[i]) or del_min > sample_rate:
# Reset the steadiness flag if fill values are encountered, or
# if an entry is missing
steady = False

if cv <= max_bmag_cv and ca_std[i] <= max_clock_angle_std:
# Steadiness conditions have been met
if steady:
imf_steady[i] = imf_steady[i - 1]

imf_steady[i] += sample_rate
steady = True

inst['IMF_Steady'] = pds.Series(imf_steady, index=inst.data.index)
return


def calculate_dayside_reconnection(inst):
"""Calculate the dayside reconnection rate (Milan et al. 2014).
Parameters
----------
inst : pysat.Instrument
Instrument with OMNI HRO data, requires BYZ_GSM and clock_angle
Note
----
recon_day = 3.8 Re (Vx / 4e5 m/s)^1/3 Vx B_yz (sin(theta/2))^9/2
"""

rearth = 6371008.8 # Earth radius in m
sin_htheta = np.power(np.sin(np.radians(0.5 * inst['clock_angle'])), 4.5)
byz = inst['BYZ_GSM'] * 1.0e-9 # Convert from nT to T
vx = inst['flow_speed'] * 1000.0 # Convert to m/s from km/s

recon_day = 3.8 * rearth * vx * byz * sin_htheta * np.power((vx / 4.0e5),
1.0 / 3.0)
inst['recon_day'] = pds.Series(recon_day, index=inst.data.index)
return

0 comments on commit 8c94ece

Please sign in to comment.