From e66345a00c0691eb9d7f6c7b2eaf49c4ee294013 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 28 Jun 2021 18:25:16 -0400 Subject: [PATCH 001/147] ENH: add keplerian inputs to sgp4 --- pysatMissions/instruments/__init__.py | 1 + pysatMissions/instruments/methods/__init__.py | 3 + pysatMissions/instruments/methods/orbits.py | 84 ++++++++++++++ pysatMissions/instruments/missions_sgp4.py | 104 +++++++++++++----- 4 files changed, 167 insertions(+), 25 deletions(-) create mode 100644 pysatMissions/instruments/methods/__init__.py create mode 100644 pysatMissions/instruments/methods/orbits.py diff --git a/pysatMissions/instruments/__init__.py b/pysatMissions/instruments/__init__.py index f8b8e3e5..0d649c1a 100644 --- a/pysatMissions/instruments/__init__.py +++ b/pysatMissions/instruments/__init__.py @@ -3,6 +3,7 @@ the instrument modules to be used with pysat """ +from pysatMissions.instruments import methods # noqa: F401 from pysatMissions.instruments import missions_ephem, missions_sgp4 __all__ = ['missions_ephem', 'missions_sgp4'] diff --git a/pysatMissions/instruments/methods/__init__.py b/pysatMissions/instruments/methods/__init__.py new file mode 100644 index 00000000..1040a7f4 --- /dev/null +++ b/pysatMissions/instruments/methods/__init__.py @@ -0,0 +1,3 @@ +from pysatMissions.instruments.methods import orbits + +__all__ = ['orbits'] diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py new file mode 100644 index 00000000..a20444b9 --- /dev/null +++ b/pysatMissions/instruments/methods/orbits.py @@ -0,0 +1,84 @@ +import numpy as np + + +def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='Earth'): + """Calculate orbital eccentricity from periapsis and apoapsis + + Parameters + ---------- + alt_periapsis : float + The lowest altitude from the mean planet surface along the orbit (km) + alt_apoapsis : float or NoneType + The highest altitude from the mean planet surface along the orbit (km) + If None, assumed to be equal to periapsis. (default=None) + planet : string + The name of the planet of interest. Used for radial calculations. + (default='Earth') + + Returns + ------- + eccentricity : float + The eccentricty of the orbit (unitless) + mean_motion : float + The mean angular speed of the orbit (rad/minute) + + """ + + radius = {'Earth': 6371} # km + mass = {'Earth': 5.9742e24} # kg + gravity = 6.6743e-11 # m**3 kg / s**2 + + if alt_apoapsis is None: + alt_apoapsis = alt_periapsis + + rad_apoapsis = alt_apoapsis + radius[planet] + rad_periapsis = alt_periapsis + radius[planet] + semimajor = 0.5 * (rad_apoapsis + rad_periapsis) + + eccentricity = ((rad_apoapsis - rad_periapsis) + / (rad_apoapsis + rad_periapsis)) + + # convert axis to m, mean_motion to rad / minute + mean_motion = np.sqrt(gravity * mass[planet] / (1000 * semimajor)**3) * 60 + + return eccentricity, mean_motion + + +def convert_from_keplerian(eccentricity, mean_motion, planet='Earth'): + """Calculate orbital eccentricity from periapsis and apoapsis + + Parameters + ---------- + eccentricity : float + The eccentricty of the orbit (unitless) + mean_motion : float + The mean angular speed of the orbit (rad/minute) + planet : string + The name of the planet of interest. Used for radial calculations. + (default='Earth') + + Returns + ------- + alt_periapsis : float + The lowest altitude from the mean planet surface along the orbit (km) + alt_apoapsis : float + The highest altitude from the mean planet surface along the orbit (km) + + """ + + radius = {'Earth': 6371} # km + mass = {'Earth': 5.9742e24} # kg + gravity = 6.6743e-11 # m**3 kg / s**2 + + # Convert mean_motion to rad / second before computing + semimajor = (gravity * mass[planet] / (mean_motion / 60)**2) + # Convert distance to km + semimajor = semimajor**(1 / 3) / 1000 + + rad_apoapsis = semimajor * (1 + eccentricity) + rad_periapsis = semimajor * (1 - eccentricity) + + alt_apoapsis = rad_apoapsis - radius[planet] + alt_periapsis = rad_periapsis - radius[planet] + + return alt_periapsis, alt_apoapsis diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index ad3b84ae..a471c0c4 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -18,11 +18,13 @@ import datetime as dt import functools +import numpy as np import pandas as pds import pysat from pysat.instruments.methods import testing as ps_meth from pysatMissions.instruments import _core as mcore +from pysatMissions.instruments.methods import orbits logger = pysat.logger @@ -64,7 +66,9 @@ def init(self): def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., - TLE1=None, TLE2=None, num_samples=None, cadence='1S'): + TLE1=None, TLE2=None, alt_periapsis=None, alt_apoapsis=None, + inclination=None, raan=None, arg_perigee=None, mean_anomaly=None, + drag_coeff=None, num_samples=None, cadence='1S'): """ Returns data and metadata in the format required by pysat. Generates position of satellite in ECI co-ordinates. @@ -94,6 +98,23 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., First string for Two Line Element. Must be in TLE format TLE2 : string Second string for Two Line Element. Must be in TLE format + alt_periapsis : float + The lowest altitude from the mean planet surface along the orbit (km) + alt_apoapsis : float or NoneType + The highest altitude from the mean planet surface along the orbit (km) + If None, assumed to be equal to periapsis. (default=None) + inclination : float + Orbital Inclination in degrees (default=None) + raan : float + Right Ascension of the Ascending Node in degrees (default=None) + arg_perigee : float + Argument of Perigee in degrees (default=None) + mean_anomaly : float + The fraction of an elliptical orbit's period that has elapsed since the + orbiting body passed periapsis + (default=None) + drag_coeff : float + Drag coefficient (default=None) num_samples : int Number of samples per day cadence : str @@ -121,13 +142,14 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., # wgs72 is the most commonly used gravity model in satellite tracking # community from sgp4.earth_gravity import wgs72 + from sgp4.api import jday, Satrec, SGP4_ERRORS, WGS72 from sgp4.io import twoline2rv # TLEs (Two Line Elements for ISS) # format of TLEs is fixed and available from wikipedia... # lines encode list of orbital elements of an Earth-orbiting object # for a given point in time - line1 = ('1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998') + line1 = ('1 25544U 98067A 18001.00000000 .00002728 00000-0 48567-4 0 9998') line2 = ('2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452') # use ISS defaults if not provided by user if TLE1 is not None: @@ -138,33 +160,65 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., if num_samples is None: num_samples = 100 - # Create satellite from TLEs and assuming a gravity model; - # according to module webpage, wgs72 is common - satellite = twoline2rv(line1, line2, wgs72) - # Extract list of times from filenames and inst_id times, index, dates = ps_meth.generate_times(fnames, num_samples, freq=cadence) + # Calculate epoch for orbital propagator + epoch = (dates[0] - dt.datetime(1949, 12, 31)).days + jd, _ = jday(dates[0].year, dates[0].month, dates[0].day, 0, 0, 0) - # Create list to hold satellite position, velocity - position = [] - velocity = [] - for timestep in index: - # orbit propagator - computes x,y,z position and velocity - pos, vel = satellite.propagate(timestep.year, timestep.month, - timestep.day, timestep.hour, - timestep.minute, timestep.second) - position.extend(pos) - velocity.extend(vel) - - # Put data into DataFrame - data = pds.DataFrame({'position_eci_x': position[::3], - 'position_eci_y': position[1::3], - 'position_eci_z': position[2::3], - 'velocity_eci_x': velocity[::3], - 'velocity_eci_y': velocity[1::3], - 'velocity_eci_z': velocity[2::3]}, - index=index) + # Create satellite from TLEs and assuming a gravity model; + # according to module webpage, wgs72 is common + if inclination: + # If an inclination is provided, specify by Keplerian elements + eccentricity, mean_motion = orbits.convert_to_keplerian(alt_periapsis, + alt_apoapsis) + satellite = Satrec() + satellite.sgp4init(WGS72, 'i', 0, epoch, drag_coeff, 0, 0, + eccentricity, np.radians(arg_perigee), + np.radians(inclination), np.radians(mean_anomaly), + mean_motion, np.radians(raan)) + jd = jd * np.ones(len(times)) + fr = times / 86400. + + err_code, position, velocity = satellite.sgp4_array(jd, fr) + + # Check all propagated values for errors in propagation + for i in range(1, 7): + if np.any(err_code == i): + raise ValueError(SGP4_ERRORS[i]) + + # Put data into DataFrame + data = pds.DataFrame({'position_eci_x': position[:, 0], + 'position_eci_y': position[:, 1], + 'position_eci_z': position[:, 2], + 'velocity_eci_x': velocity[:, 0], + 'velocity_eci_y': velocity[:, 1], + 'velocity_eci_z': velocity[:, 2]}, + index=index) + else: + # Otherwise, use TLEs + satellite = twoline2rv(line1, line2, wgs72) + + # Create list to hold satellite position, velocity + position = [] + velocity = [] + for timestep in index: + # orbit propagator - computes x,y,z position and velocity + pos, vel = satellite.propagate(timestep.year, timestep.month, + timestep.day, timestep.hour, + timestep.minute, timestep.second) + position.extend(pos) + velocity.extend(vel) + + # Put data into DataFrame + data = pds.DataFrame({'position_eci_x': position[::3], + 'position_eci_y': position[1::3], + 'position_eci_z': position[2::3], + 'velocity_eci_x': velocity[::3], + 'velocity_eci_y': velocity[1::3], + 'velocity_eci_z': velocity[2::3]}, + index=index) data.index.name = 'Epoch' # TODO: add call for GEI/ECEF translation here => #56 From 4688af546dd0a3e02f07caad9ca724d19d94457b Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 28 Jun 2021 18:25:28 -0400 Subject: [PATCH 002/147] DOC: update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbf804c1..57348978 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +## [0.3.0] - 2021-06-24 +* Add Keplerian orbital inputs into missions_sgp4 + ## [0.2.2] - 2021-06-18 * Migrate pyglow interface to pysatIncubator * Style updates for consistency with pysat 3.0 From 73311ad78251dab21922251666ccde20f46b5d14 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 30 Jun 2021 15:52:10 -0400 Subject: [PATCH 003/147] Update pysatMissions/instruments/missions_sgp4.py --- pysatMissions/instruments/missions_sgp4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index a471c0c4..9db57669 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -149,7 +149,7 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., # format of TLEs is fixed and available from wikipedia... # lines encode list of orbital elements of an Earth-orbiting object # for a given point in time - line1 = ('1 25544U 98067A 18001.00000000 .00002728 00000-0 48567-4 0 9998') + line1 = ('1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998') line2 = ('2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452') # use ISS defaults if not provided by user if TLE1 is not None: From 49a5e946ca22b30881c525e558433b3a8f1dbb76 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 7 Jul 2021 12:47:46 -0400 Subject: [PATCH 004/147] STY: remove python 2.7 imports --- pysatMissions/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pysatMissions/__init__.py b/pysatMissions/__init__.py index bf54ece0..a000347f 100644 --- a/pysatMissions/__init__.py +++ b/pysatMissions/__init__.py @@ -1,5 +1,3 @@ -from __future__ import print_function -from __future__ import absolute_import import logging import os From 62087da1de3e44540580d7dc366eb306da4bdb9f Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 7 Jul 2021 12:48:19 -0400 Subject: [PATCH 005/147] ENH: add orbital check --- pysatMissions/instruments/methods/orbits.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index a20444b9..380c9926 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -1,6 +1,15 @@ import numpy as np +def check_orbital_params(inclination=None, eccentricity=None, raan=None, + arg_perigee=None, mean_anomaly=None, mean_motion=None): + """Check that a complete set of orbital parameters exist""" + + params = [inclination, eccentricity, raan, arg_perigee, mean_anomaly, + mean_motion] + return not any(v is None for v in params) + + def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='Earth'): """Calculate orbital eccentricity from periapsis and apoapsis From 74ccad8a2a97495694b902a72b8dd932282b2087 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 7 Jul 2021 12:48:27 -0400 Subject: [PATCH 006/147] STY: strings --- pysatMissions/instruments/missions_sgp4.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 9db57669..6587a5fc 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -149,8 +149,8 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., # format of TLEs is fixed and available from wikipedia... # lines encode list of orbital elements of an Earth-orbiting object # for a given point in time - line1 = ('1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998') - line2 = ('2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452') + line1 = '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998' + line2 = '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452' # use ISS defaults if not provided by user if TLE1 is not None: line1 = TLE1 From 8bd4d6f1d0fdeaf8135b6c39cc79345fa1d579b4 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 10:39:43 -0400 Subject: [PATCH 007/147] TST: add docstring tests --- .github/workflows/main.yml | 2 +- setup.cfg | 5 ++++- test_requirements.txt | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3f1f5f0b..2b7ba1cb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,7 +36,7 @@ jobs: python -c "import pysat; pysat.params['data_dirs'] = 'pysatData'" - name: Test PEP8 compliance - run: flake8 . --count --select=E,F,W --show-source --statistics + run: flake8 . --count --select=D,E,F,W --show-source --statistics - name: Evaluate complexity run: flake8 . --count --exit-zero --max-complexity=10 --statistics diff --git a/setup.cfg b/setup.cfg index a258b972..7671151b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -52,7 +52,10 @@ install_requires = [flake8] max-line-length = 90 -ignore = W503 +ignore = + D200 + D202 + W503 [tool:pytest] markers = diff --git a/test_requirements.txt b/test_requirements.txt index 8091dd08..bac35e66 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,9 +1,9 @@ coveralls +flake8-docstrings ipython m2r2 numpydoc pytest-cov -pytest-flake8 pytest-ordering sphinx sphinx_rtd_theme From 9a057b73aea9da5bfd4b11468570257f507ffe2e Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 11:02:38 -0400 Subject: [PATCH 008/147] DOC: improve docstrings --- docs/conf.py | 15 +++++---- pysatMissions/__init__.py | 18 +++++++++-- pysatMissions/instruments/__init__.py | 3 +- pysatMissions/instruments/_core.py | 9 ++++-- pysatMissions/instruments/missions_ephem.py | 31 ++++++++++++------- pysatMissions/instruments/missions_sgp4.py | 12 ++++--- pysatMissions/methods/magcoord.py | 9 +++--- pysatMissions/methods/spacecraft.py | 7 ++--- pysatMissions/tests/__init__.py | 1 + pysatMissions/tests/test_instruments.py | 22 ++++++++++--- pysatMissions/tests/test_methods_magcoord.py | 12 ++++--- .../tests/test_methods_spacecraft.py | 27 +++++++++++++--- 12 files changed, 115 insertions(+), 51 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index ff9c01d7..1f8a6a7a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,10 +1,13 @@ # -*- coding: utf-8 -*- -# -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# https://www.sphinx-doc.org/en/master/config + +"""Configuration file for the Sphinx documentation builder. + +Note +---- +For a full list see the documentation: +https://www.sphinx-doc.org/en/master/config + +""" # -- Path setup -------------------------------------------------------------- diff --git a/pysatMissions/__init__.py b/pysatMissions/__init__.py index bf54ece0..77fa067e 100644 --- a/pysatMissions/__init__.py +++ b/pysatMissions/__init__.py @@ -1,5 +1,19 @@ -from __future__ import print_function -from __future__ import absolute_import +""" +Core library for pysatMissions. + +pysatMissions allows users to run build simulated satellites for Two-Line +Elements (TLE) and add empirical data. It includes the `missions_ephem` and +`mission_sgp4` instrument modules which can be imported into pysat. + +Main Features +------------- +- Simulate satellite orbits from TLEs and add data from empirical models +- Import ionosphere and thermosphere model values through pyglow +- Import magnetic coordinates through apexpy and aacgmv2 +- Import geomagnetic basis vectors through OMMBV + +""" + import logging import os diff --git a/pysatMissions/instruments/__init__.py b/pysatMissions/instruments/__init__.py index f8b8e3e5..afa8e754 100644 --- a/pysatMissions/instruments/__init__.py +++ b/pysatMissions/instruments/__init__.py @@ -1,6 +1,5 @@ """ -pysatMissions.instruments is a pysat module that provides -the instrument modules to be used with pysat +Provides the instrument modules to be used with pysat. """ from pysatMissions.instruments import missions_ephem, missions_sgp4 diff --git a/pysatMissions/instruments/_core.py b/pysatMissions/instruments/_core.py index 6545defb..5c3c2914 100644 --- a/pysatMissions/instruments/_core.py +++ b/pysatMissions/instruments/_core.py @@ -1,10 +1,15 @@ """ -Handles the default pysat functions for simulated instruments +Handles the default pysat functions for simulated instruments. """ def _clean(self): - """Cleaning function. Simple pass since data is generated locally. + """Pass through since cleaning is not needed. + + Note + ---- + Required for pysat standards compliance. + """ return diff --git a/pysatMissions/instruments/missions_ephem.py b/pysatMissions/instruments/missions_ephem.py index 11e3f466..be773ddc 100644 --- a/pysatMissions/instruments/missions_ephem.py +++ b/pysatMissions/instruments/missions_ephem.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- """ -Produces satellite orbit data. Orbit is simulated using -Two Line Elements (TLEs) and ephem. Satellite position is coupled -to several space science models to simulate the atmosphere the +Produce satellite orbit data. + +Orbit is simulated using Two Line Elements (TLEs) and ephem. Satellite position +is coupled to several space science models to simulate the atmosphere the satellite is in. Properties @@ -21,9 +22,13 @@ import datetime as dt import functools import numpy as np +import sys import ephem -import OMMBV +try: + import OMMBV +except ImportError: + pass import pandas as pds import pysat @@ -48,9 +53,9 @@ def init(self): """ - Adds custom calculations to orbit simulation. - This routine is run once, and only once, upon instantiation. + Add custom calculations to orbit simulation. + This routine is run once, and only once, upon instantiation. Adds custom routines for quasi-dipole coordinates, velocity calculation in ECEF coords, and attitude vectors of spacecraft (assuming x is ram pointing and z is generally nadir). @@ -68,7 +73,7 @@ def init(self): def preprocess(self): """ - Add modeled magnetic field values and attitude vectors to spacecraft + Add modeled magnetic field values and attitude vectors to spacecraft. Runs after load is invoked. @@ -89,9 +94,10 @@ def preprocess(self): def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., TLE1=None, TLE2=None, num_samples=None, cadence='1S'): """ - Returns data and metadata in the format required by pysat. Generates - position of satellite in both geographic and ECEF co-ordinates. + Generate position of satellite in both geographic and ECEF co-ordinates. + Note + ---- Routine is directly called by pysat and not the user. Parameters @@ -192,9 +198,10 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., lp['alt'] = sat.elevation / 1000.0 # Get ECEF position of satellite - lp['x'], lp['y'], lp['z'] = OMMBV.geodetic_to_ecef(lp['glat'], - lp['glong'], - lp['alt']) + if "OMMBV" in sys.modules: + lp['x'], lp['y'], lp['z'] = OMMBV.geodetic_to_ecef(lp['glat'], + lp['glong'], + lp['alt']) output_params.append(lp) output = pds.DataFrame(output_params, index=index) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index ad3b84ae..89585423 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- """ -Produces satellite orbit data. Orbit is simulated using -Two Line Elements (TLEs) and SGP4. +Produce satellite orbit data. + +Orbit is simulated using Two Line Elements (TLEs) and SGP4. Properties ---------- @@ -40,7 +41,7 @@ def init(self): """ - Initializes the Instrument object with required values. + Initialize the Instrument object with required values. Runs once upon instantiation. @@ -66,9 +67,10 @@ def init(self): def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., TLE1=None, TLE2=None, num_samples=None, cadence='1S'): """ - Returns data and metadata in the format required by pysat. Generates - position of satellite in ECI co-ordinates. + Generate position of satellite in ECI co-ordinates. + Note + ---- Routine is directly called by pysat and not the user. Parameters diff --git a/pysatMissions/methods/magcoord.py b/pysatMissions/methods/magcoord.py index a571b425..446257ef 100644 --- a/pysatMissions/methods/magcoord.py +++ b/pysatMissions/methods/magcoord.py @@ -1,6 +1,5 @@ -"""Provides default routines for projecting aacgmv2 and apexpy model values onto -locations from pysat instruments. - +""" +Routines for projecting aacgmv2 and apexpy model values onto pysat instruments. """ import aacgmv2 @@ -10,7 +9,7 @@ def add_aacgm_coordinates(inst, glat_label='glat', glong_label='glong', alt_label='alt'): """ - Uses AACGMV2 package to add AACGM coordinates to instrument object. + Add AACGM coordinates to instrument object via AACGMV2 package. The Altitude Adjusted Corrected Geomagnetic Coordinates library is used to calculate the latitude, longitude, and local time @@ -71,7 +70,7 @@ def add_aacgm_coordinates(inst, glat_label='glat', glong_label='glong', def add_quasi_dipole_coordinates(inst, glat_label='glat', glong_label='glong', alt_label='alt'): """ - Uses Apexpy package to add quasi-dipole coordinates to instrument object. + Add quasi-dipole coordinates to instrument object using Apexpy package. The Quasi-Dipole coordinate system includes both the tilt and offset of the geomagnetic field to calculate the latitude, longitude, and local time diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index 6600a6fb..0debad04 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -1,5 +1,4 @@ -"""Provides default routines for projecting values onto vectors -for pysat instruments. +"""Default routines for projecting values onto vectors for pysat instruments. """ @@ -136,7 +135,7 @@ def add_ram_pointing_sc_attitude_vectors(inst): def calculate_ecef_velocity(inst): """ - Calculates spacecraft velocity in ECEF frame. + Calculate spacecraft velocity in ECEF frame. Presumes that the spacecraft velocity in ECEF is in the input instrument object as position_ecef_*. Uses a symmetric @@ -187,7 +186,7 @@ def get_vel_from_pos(x): def project_ecef_vector_onto_sc(inst, x_label, y_label, z_label, new_x_label, new_y_label, new_z_label, meta=None): - """Express input vector using s/c attitude directions + """Express input vector using s/c attitude directions. x - ram pointing y - generally southward diff --git a/pysatMissions/tests/__init__.py b/pysatMissions/tests/__init__.py index e69de29b..6ddd2b0b 100644 --- a/pysatMissions/tests/__init__.py +++ b/pysatMissions/tests/__init__.py @@ -0,0 +1 @@ +"""Unit and Integration tests for pysatMissions.""" diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index 75499c01..69b612ee 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -1,3 +1,12 @@ +""" +Unit and Integration Tests for each instrument module. + +Note +---- +Imports test methods from pysat.tests.instrument_test_class + +""" + import datetime as dt import numpy as np import tempfile @@ -46,13 +55,18 @@ class TestInstruments(InstTestClass): - """Uses class level setup and teardown so that all tests use the same + """Main class for instrument tests. + + Note + ---- + Uses class level setup and teardown so that all tests use the same temporary directory. We do not want to geneate a new tempdir for each test, as the load tests need to be the same as the download tests. + """ def setup_class(self): - """Runs once before the tests to initialize the testing setup.""" + """Initialize the testing setup once before all tests are run.""" # Make sure to use a temporary directory so that the user's setup is not # altered self.tempdir = tempfile.TemporaryDirectory() @@ -64,7 +78,7 @@ def setup_class(self): self.inst_loc = pysatMissions.instruments def teardown_class(self): - """Runs once to clean up testing from this class.""" + """Clean up downloaded files and parameters from tests.""" pysat.params.data['data_dirs'] = self.saved_path self.tempdir.cleanup() del self.inst_loc, self.saved_path, self.tempdir @@ -74,7 +88,7 @@ def teardown_class(self): @pytest.mark.parametrize("inst_dict", [x for x in instruments['download']]) @pytest.mark.parametrize("kwarg,output", [(None, 1), ('10s', 10)]) def test_inst_cadence(self, inst_dict, kwarg, output): - """Test operation of cadence keyword, including default behavior""" + """Test operation of cadence keyword, including default behavior.""" if kwarg: self.test_inst = pysat.Instrument( diff --git a/pysatMissions/tests/test_methods_magcoord.py b/pysatMissions/tests/test_methods_magcoord.py index 1ed0e007..f5a646f8 100644 --- a/pysatMissions/tests/test_methods_magcoord.py +++ b/pysatMissions/tests/test_methods_magcoord.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Test some of the aacgmv2 method functions +"""Test some of the aacgmv2 method functions.""" import datetime as dt import numpy as np @@ -8,17 +8,19 @@ class TestBasics(): + """Main testing class for aacgmv2.""" + def setup(self): - """Runs before every method to create a clean testing setup.""" + """Create a clean testing setup before each method.""" self.testInst = pysat.Instrument(platform='pysat', name='testing', num_samples=100, clean_level='clean') def teardown(self): - """Clean up test environment after tests""" + """Clean up test environment after each method.""" del self def test_add_aacgm_coordinates(self): - """Test adding thermal plasma data to test inst""" + """Test adding thermal plasma data to test inst.""" self.testInst.custom_attach(mm_magcoord.add_aacgm_coordinates, kwargs={'glat_label': 'latitude', 'glong_label': 'longitude', @@ -33,7 +35,7 @@ def test_add_aacgm_coordinates(self): assert target in self.testInst.meta.data.index def test_add_quasi_dipole_coordinates(self): - """Test adding thermal plasma data to test inst""" + """Test adding thermal plasma data to test inst.""" self.testInst.custom_attach(mm_magcoord.add_quasi_dipole_coordinates, kwargs={'glat_label': 'latitude', 'glong_label': 'longitude', diff --git a/pysatMissions/tests/test_methods_spacecraft.py b/pysatMissions/tests/test_methods_spacecraft.py index b169acca..3ff65279 100644 --- a/pysatMissions/tests/test_methods_spacecraft.py +++ b/pysatMissions/tests/test_methods_spacecraft.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Test some of the spacecraft method functions +"""Test some of the spacecraft method functions.""" import datetime as dt import numpy as np @@ -8,7 +8,7 @@ def add_eci(inst): - """Add ECI position to pysat_testing instrument""" + """Add ECI position to pysat_testing instrument.""" inst['position_ecef_x'] = [-6197.135721, -6197.066687, -6196.990263, -6196.906991, -6196.816336, -6196.718347, @@ -19,26 +19,38 @@ def add_eci(inst): inst['position_ecef_z'] = [1716.528241, 1710.870004, 1705.209738, 1699.547245, 1693.882731, 1688.216005, 1682.547257, 1676.876312, 1671.203352] + return def add_fake_data(inst): + """Add arbitrary vector to pysat_testing instrument.""" + inst['ax'] = np.ones(9) inst['ay'] = np.zeros(9) inst['az'] = np.zeros(9) + return class TestBasics(): + """Unit tests for aacgmv2 methods.""" + def setup(self): - """Runs before every method to create a clean testing setup.""" + """Create a clean testing setup before each method.""" + self.testInst = pysat.Instrument(platform='pysat', name='testing', num_samples=9, clean_level='clean') self.testInst.custom_attach(add_eci) + return def teardown(self): - """Clean up test environment after tests""" + """Clean up test environment after tests.""" + del self + return def test_calculate_ecef_velocity(self): + """Test `calculate_ecef_velocity` helper function.""" + self.testInst.custom_attach(mm_sc.calculate_ecef_velocity) self.testInst.load(date=dt.datetime(2009, 1, 1)) targets = ['velocity_ecef_x', 'velocity_ecef_y', 'velocity_ecef_z'] @@ -51,8 +63,11 @@ def test_calculate_ecef_velocity(self): assert np.isnan(self.testInst[target][-1]) # Check if metadata is added assert target in self.testInst.meta.data.index + return def test_add_ram_pointing_sc_attitude_vectors(self): + """Test `add_ram_pointing_sc_attitude_vectors` helper function.""" + # TODO: check if calculations are correct self.testInst.custom_attach(mm_sc.calculate_ecef_velocity) self.testInst.custom_attach(mm_sc.add_ram_pointing_sc_attitude_vectors) @@ -69,8 +84,11 @@ def test_add_ram_pointing_sc_attitude_vectors(self): assert np.isnan(self.testInst[target][-1]) # Check if metadata is added assert target in self.testInst.meta.data.index + return def test_project_ecef_vector_onto_sc(self): + """Test `project_ecef_vector_onto_sc` helper function.""" + # TODO: check if calculations are correct self.testInst.custom_attach(mm_sc.calculate_ecef_velocity) self.testInst.custom_attach(mm_sc.add_ram_pointing_sc_attitude_vectors) @@ -88,3 +106,4 @@ def test_project_ecef_vector_onto_sc(self): assert np.isnan(self.testInst[target][-1]) # Check if metadata is added assert target in self.testInst.meta.data.index + return From 4905a2a2ac4a496cb64814ef05950661dfd75182 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 11:04:37 -0400 Subject: [PATCH 009/147] DOC: update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fbf804c1..63fcce48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). +## [0.3.0] - XXXX-XX-XX +* Documentation + * Improve docstrings throughout +* Testing + * Add style check for docstrings + ## [0.2.2] - 2021-06-18 * Migrate pyglow interface to pysatIncubator * Style updates for consistency with pysat 3.0 From 74d28b3e43f6432fa3ab1179ef6ba5dec8d51f85 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 11:06:55 -0400 Subject: [PATCH 010/147] DOC: update docstring --- pysatMissions/methods/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pysatMissions/methods/__init__.py b/pysatMissions/methods/__init__.py index 7375ae87..2ed80e14 100644 --- a/pysatMissions/methods/__init__.py +++ b/pysatMissions/methods/__init__.py @@ -1,6 +1,5 @@ """ -pysatMissions.methods is a module that provides -the methods to interface with numerous empirical model packages +Provides the methods to interface with numerous empirical model packages. """ from pysatMissions.methods import magcoord From 6f66a4ea30b6665d53e1d0bbbb92887cb80d1288 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 11:09:45 -0400 Subject: [PATCH 011/147] DOC: add docstring --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 0a47a6bc..a3ec39b4 100644 --- a/setup.py +++ b/setup.py @@ -3,6 +3,7 @@ # Copyright (C) 2021, Authors # Full license can be found in License.md # ----------------------------------------------------------------------------- +"""Setup routines for pysatMissions.""" from setuptools import setup From 6827ace9492869d1a8dc78ae8fda71d7858b8c22 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 11:16:17 -0400 Subject: [PATCH 012/147] BUG: revert changes from other branch --- pysatMissions/instruments/missions_ephem.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/pysatMissions/instruments/missions_ephem.py b/pysatMissions/instruments/missions_ephem.py index be773ddc..f22132b2 100644 --- a/pysatMissions/instruments/missions_ephem.py +++ b/pysatMissions/instruments/missions_ephem.py @@ -22,13 +22,9 @@ import datetime as dt import functools import numpy as np -import sys import ephem -try: - import OMMBV -except ImportError: - pass +import OMMBV import pandas as pds import pysat @@ -198,10 +194,9 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., lp['alt'] = sat.elevation / 1000.0 # Get ECEF position of satellite - if "OMMBV" in sys.modules: - lp['x'], lp['y'], lp['z'] = OMMBV.geodetic_to_ecef(lp['glat'], - lp['glong'], - lp['alt']) + lp['x'], lp['y'], lp['z'] = OMMBV.geodetic_to_ecef(lp['glat'], + lp['glong'], + lp['alt']) output_params.append(lp) output = pds.DataFrame(output_params, index=index) From a5265c8412c06f6fcc70c02d551e4fdf9798c063 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 11:18:11 -0400 Subject: [PATCH 013/147] Update pysatMissions/methods/magcoord.py --- pysatMissions/methods/magcoord.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/methods/magcoord.py b/pysatMissions/methods/magcoord.py index 446257ef..7db9b267 100644 --- a/pysatMissions/methods/magcoord.py +++ b/pysatMissions/methods/magcoord.py @@ -9,7 +9,7 @@ def add_aacgm_coordinates(inst, glat_label='glat', glong_label='glong', alt_label='alt'): """ - Add AACGM coordinates to instrument object via AACGMV2 package. + Add AACGM coordinates to instrument object using AACGMV2 package. The Altitude Adjusted Corrected Geomagnetic Coordinates library is used to calculate the latitude, longitude, and local time From fdd4e58ff1688419c2ee7babcc314df70f88a703 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 18:46:43 -0400 Subject: [PATCH 014/147] STY: reduce duplicate code --- pysatMissions/instruments/methods/orbits.py | 60 ++++++++++++++------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 380c9926..c196f5d7 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -3,15 +3,44 @@ def check_orbital_params(inclination=None, eccentricity=None, raan=None, arg_perigee=None, mean_anomaly=None, mean_motion=None): - """Check that a complete set of orbital parameters exist""" + """Check that a complete set of orbital parameters exist.""" params = [inclination, eccentricity, raan, arg_perigee, mean_anomaly, mean_motion] return not any(v is None for v in params) +def _get_params(planet='Earth'): + """Retrieve planetary constants for calculations. + + Parameters + ---------- + planet : string + The name of the planet of interest. + (default='Earth') + + Returns + ------- + radius : float (km) + The average radius to the surface of a planet. + mass : float (kg) + The avergae mass of the planet. + gravity : float (m**3 kg / s**2) + Newton's gravitational constant + """ + + radius = {'Earth': 6371} + mass = {'Earth': 5.9742e24} + gravity = 6.6743e-11 + + if planet not in radius.keys(): + raise KeyError('{:} is not yet a supported planet!'.format(planet)) + + return radius[planet], mass[planet], gravity + + def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='Earth'): - """Calculate orbital eccentricity from periapsis and apoapsis + """Calculate orbital eccentricity from periapsis and apoapsis. Parameters ---------- @@ -21,7 +50,8 @@ def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='Earth'): The highest altitude from the mean planet surface along the orbit (km) If None, assumed to be equal to periapsis. (default=None) planet : string - The name of the planet of interest. Used for radial calculations. + The name of the planet of interest. Used for radial calculations and + mass. (default='Earth') Returns @@ -33,28 +63,25 @@ def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='Earth'): """ - radius = {'Earth': 6371} # km - mass = {'Earth': 5.9742e24} # kg - gravity = 6.6743e-11 # m**3 kg / s**2 - + radius, mass, gravity = _get_params(planet) if alt_apoapsis is None: alt_apoapsis = alt_periapsis - rad_apoapsis = alt_apoapsis + radius[planet] - rad_periapsis = alt_periapsis + radius[planet] + rad_apoapsis = alt_apoapsis + radius + rad_periapsis = alt_periapsis + radius semimajor = 0.5 * (rad_apoapsis + rad_periapsis) eccentricity = ((rad_apoapsis - rad_periapsis) / (rad_apoapsis + rad_periapsis)) # convert axis to m, mean_motion to rad / minute - mean_motion = np.sqrt(gravity * mass[planet] / (1000 * semimajor)**3) * 60 + mean_motion = np.sqrt(gravity * mass / (1000 * semimajor)**3) * 60 return eccentricity, mean_motion def convert_from_keplerian(eccentricity, mean_motion, planet='Earth'): - """Calculate orbital eccentricity from periapsis and apoapsis + """Calculate orbital eccentricity from periapsis and apoapsis. Parameters ---------- @@ -75,19 +102,16 @@ def convert_from_keplerian(eccentricity, mean_motion, planet='Earth'): """ - radius = {'Earth': 6371} # km - mass = {'Earth': 5.9742e24} # kg - gravity = 6.6743e-11 # m**3 kg / s**2 - + radius, mass, gravity = _get_params(planet) # Convert mean_motion to rad / second before computing - semimajor = (gravity * mass[planet] / (mean_motion / 60)**2) + semimajor = (gravity * mass / (mean_motion / 60)**2) # Convert distance to km semimajor = semimajor**(1 / 3) / 1000 rad_apoapsis = semimajor * (1 + eccentricity) rad_periapsis = semimajor * (1 - eccentricity) - alt_apoapsis = rad_apoapsis - radius[planet] - alt_periapsis = rad_periapsis - radius[planet] + alt_apoapsis = rad_apoapsis - radius + alt_periapsis = rad_periapsis - radius return alt_periapsis, alt_apoapsis From cf624a4361d14b904667a1f2f5f733bdca57e543 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 18:47:05 -0400 Subject: [PATCH 015/147] TST: add tests for orbit methods --- .../tests/test_inst_methods_orbits.py | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 pysatMissions/tests/test_inst_methods_orbits.py diff --git a/pysatMissions/tests/test_inst_methods_orbits.py b/pysatMissions/tests/test_inst_methods_orbits.py new file mode 100644 index 00000000..44cbbf1f --- /dev/null +++ b/pysatMissions/tests/test_inst_methods_orbits.py @@ -0,0 +1,44 @@ +"""Unit tests for `pysatMissions.instruments.methods.orbits`.""" + +import pytest +import pysatMissions.instruments.methods.orbits as mm_orbits + + +class TestBasics(): + """Unit tests for conversion to/from Keplerian elements.""" + + def setup(self): + """Create a clean testing setup before each method.""" + self.orbit = {'inclination': 13, 'apogee': 850, 'perigee': 400, + 'eccentricity': 0.032161234991424, + 'mean_motion': 0.0647469462135} + return + + def teardown(self): + """Clean up test environment after each method.""" + del self.orbit + return + + def test_convert_wrong_planet(self): + """Test conversion routines with an unsupported planet.""" + with pytest.raises(KeyError) as kerr: + mm_orbits.convert_to_keplerian(self.orbit['perigee'], + self.orbit['apogee'], 'Hwae') + assert str(kerr).find("is not yet a supported planet!") >= 0 + return + + def test_convert_to_keplerian(self): + """Test conversion to keplerian elements.""" + ecc, mm, = mm_orbits.convert_to_keplerian(self.orbit['perigee'], + self.orbit['apogee'],) + assert abs(ecc - self.orbit['eccentricity']) / ecc < 1.e-6 + assert abs(mm - self.orbit['mean_motion']) / mm < 1.e-6 + return + + def test_convert_from_keplerian(self): + """Test conversion from keplerian elements.""" + per, apo, = mm_orbits.convert_from_keplerian(self.orbit['eccentricity'], + self.orbit['mean_motion'],) + assert abs(per - self.orbit['perigee']) / per < 1.e-6 + assert abs(apo - self.orbit['apogee']) / apo < 1.e-6 + return From 6cee8ce6be45db694842a66e922df72d9180a7f3 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 19:21:37 -0400 Subject: [PATCH 016/147] STY: use new sgp4 syntax, improve structure --- pysatMissions/instruments/missions_sgp4.py | 72 ++++++++-------------- 1 file changed, 24 insertions(+), 48 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 6587a5fc..94fa1472 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -25,6 +25,7 @@ from pysat.instruments.methods import testing as ps_meth from pysatMissions.instruments import _core as mcore from pysatMissions.instruments.methods import orbits +from sgp4.api import jday, Satrec, SGP4_ERRORS, WGS72 logger = pysat.logger @@ -139,19 +140,14 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., """ - # wgs72 is the most commonly used gravity model in satellite tracking - # community - from sgp4.earth_gravity import wgs72 - from sgp4.api import jday, Satrec, SGP4_ERRORS, WGS72 - from sgp4.io import twoline2rv - # TLEs (Two Line Elements for ISS) # format of TLEs is fixed and available from wikipedia... # lines encode list of orbital elements of an Earth-orbiting object # for a given point in time line1 = '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998' line2 = '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452' - # use ISS defaults if not provided by user + + # If provided, use user-specified TLEs. Otherwise use ISS defaults above. if TLE1 is not None: line1 = TLE1 if TLE2 is not None: @@ -167,58 +163,38 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., epoch = (dates[0] - dt.datetime(1949, 12, 31)).days jd, _ = jday(dates[0].year, dates[0].month, dates[0].day, 0, 0, 0) - # Create satellite from TLEs and assuming a gravity model; - # according to module webpage, wgs72 is common if inclination: # If an inclination is provided, specify by Keplerian elements eccentricity, mean_motion = orbits.convert_to_keplerian(alt_periapsis, alt_apoapsis) satellite = Satrec() + # according to module webpage, wgs72 is common satellite.sgp4init(WGS72, 'i', 0, epoch, drag_coeff, 0, 0, eccentricity, np.radians(arg_perigee), np.radians(inclination), np.radians(mean_anomaly), mean_motion, np.radians(raan)) - jd = jd * np.ones(len(times)) - fr = times / 86400. - - err_code, position, velocity = satellite.sgp4_array(jd, fr) - - # Check all propagated values for errors in propagation - for i in range(1, 7): - if np.any(err_code == i): - raise ValueError(SGP4_ERRORS[i]) - - # Put data into DataFrame - data = pds.DataFrame({'position_eci_x': position[:, 0], - 'position_eci_y': position[:, 1], - 'position_eci_z': position[:, 2], - 'velocity_eci_x': velocity[:, 0], - 'velocity_eci_y': velocity[:, 1], - 'velocity_eci_z': velocity[:, 2]}, - index=index) else: # Otherwise, use TLEs - satellite = twoline2rv(line1, line2, wgs72) - - # Create list to hold satellite position, velocity - position = [] - velocity = [] - for timestep in index: - # orbit propagator - computes x,y,z position and velocity - pos, vel = satellite.propagate(timestep.year, timestep.month, - timestep.day, timestep.hour, - timestep.minute, timestep.second) - position.extend(pos) - velocity.extend(vel) - - # Put data into DataFrame - data = pds.DataFrame({'position_eci_x': position[::3], - 'position_eci_y': position[1::3], - 'position_eci_z': position[2::3], - 'velocity_eci_x': velocity[::3], - 'velocity_eci_y': velocity[1::3], - 'velocity_eci_z': velocity[2::3]}, - index=index) + satellite = Satrec.twoline2rv(line1, line2) + + jd = jd * np.ones(len(times)) + fr = times / 86400. + + err_code, position, velocity = satellite.sgp4_array(jd, fr) + + # Check all propagated values for errors in propagation + for i in range(1, 7): + if np.any(err_code == i): + raise ValueError(SGP4_ERRORS[i]) + + # Put data into DataFrame + data = pds.DataFrame({'position_eci_x': position[:, 0], + 'position_eci_y': position[:, 1], + 'position_eci_z': position[:, 2], + 'velocity_eci_x': velocity[:, 0], + 'velocity_eci_y': velocity[:, 1], + 'velocity_eci_z': velocity[:, 2]}, + index=index) data.index.name = 'Epoch' # TODO: add call for GEI/ECEF translation here => #56 From dc8ed18d9e2d2df0060b6c44daacc65f14f87529 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 19:22:06 -0400 Subject: [PATCH 017/147] STY: improve kwargs --- pysatMissions/instruments/missions_sgp4.py | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 94fa1472..70753089 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -66,13 +66,12 @@ def init(self): clean = mcore._clean -def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., +def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, alt_periapsis=None, alt_apoapsis=None, - inclination=None, raan=None, arg_perigee=None, mean_anomaly=None, + inclination=None, raan=None, arg_periapsis=None, mean_anomaly=None, drag_coeff=None, num_samples=None, cadence='1S'): """ - Returns data and metadata in the format required by pysat. Generates - position of satellite in ECI co-ordinates. + Generate position of satellite in ECI co-ordinates. Routine is directly called by pysat and not the user. @@ -86,15 +85,6 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., Instrument satellite ID (accepts '' or a number (i.e., '10'), which specifies the number of seconds to simulate the satellite) (default='') - obs_long: float - Longitude of the observer on the Earth's surface - (default=0.) - obs_lat: float - Latitude of the observer on the Earth's surface - (default=0.) - obs_alt: float - Altitude of the observer on the Earth's surface - (default=0.) TLE1 : string First string for Two Line Element. Must be in TLE format TLE2 : string @@ -108,8 +98,8 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., Orbital Inclination in degrees (default=None) raan : float Right Ascension of the Ascending Node in degrees (default=None) - arg_perigee : float - Argument of Perigee in degrees (default=None) + arg_periapsis : float + Argument of Periapsis in degrees (default=None) mean_anomaly : float The fraction of an elliptical orbit's period that has elapsed since the orbiting body passed periapsis @@ -170,7 +160,7 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., satellite = Satrec() # according to module webpage, wgs72 is common satellite.sgp4init(WGS72, 'i', 0, epoch, drag_coeff, 0, 0, - eccentricity, np.radians(arg_perigee), + eccentricity, np.radians(arg_periapsis), np.radians(inclination), np.radians(mean_anomaly), mean_motion, np.radians(raan)) else: From ebb217508bdb5a9f83d9d510dd42c262df1bda33 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 19:22:17 -0400 Subject: [PATCH 018/147] STY: docstring --- pysatMissions/instruments/missions_sgp4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 70753089..b643a908 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -43,7 +43,7 @@ def init(self): """ - Initializes the Instrument object with required values. + Initialize the Instrument object with required values. Runs once upon instantiation. From 6172d67426400d7f2be5f4997c35e590074faf7d Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 19:23:36 -0400 Subject: [PATCH 019/147] ENH: regenerate metadata with each load #55 --- pysatMissions/instruments/missions_sgp4.py | 67 +++++++++++----------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index b643a908..87e7631f 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -187,44 +187,43 @@ def load(fnames, tag=None, inst_id=None, index=index) data.index.name = 'Epoch' + # Create metadata corresponding to variables in load routine + meta = pysat.Meta() + meta['Epoch'] = { + meta.labels.units: 'Milliseconds since 1970-1-1', + meta.labels.notes: 'UTC time at middle of geophysical measurement.', + meta.labels.desc: 'UTC seconds', + meta.labels.name: 'Time index in milliseconds'} + meta['position_eci_x'] = { + meta.labels.units: 'km', + meta.labels.name: 'ECI x-position', + meta.labels.desc: 'Earth Centered Inertial x-position of satellite.'} + meta['position_eci_y'] = { + meta.labels.units: 'km', + meta.labels.name: 'ECI y-position', + meta.labels.desc: 'Earth Centered Inertial y-position of satellite.'} + meta['position_eci_z'] = { + meta.labels.units: 'km', + meta.labels.name: 'ECI z-position', + meta.labels.desc: 'Earth Centered Inertial z-position of satellite.'} + meta['velocity_eci_x'] = { + meta.labels.units: 'km/s', + meta.labels.desc: 'Satellite velocity along ECI-x', + meta.labels.name: 'Satellite velocity ECI-x'} + meta['velocity_eci_y'] = { + meta.labels.units: 'km/s', + meta.labels.desc: 'Satellite velocity along ECI-y', + meta.labels.name: 'Satellite velocity ECI-y'} + meta['velocity_eci_z'] = { + meta.labels.units: 'km/s', + meta.labels.desc: 'Satellite velocity along ECI-z', + meta.labels.name: 'Satellite velocity ECI-z'} + # TODO: add call for GEI/ECEF translation here => #56 - return data, meta.copy() + return data, meta list_files = functools.partial(ps_meth.list_files, test_dates=_test_dates) download = functools.partial(ps_meth.download) clean = functools.partial(mcore._clean) - -# Create metadata corresponding to variables in load routine just above -# made once here rather than regenerate every load call -meta = pysat.Meta() -meta['Epoch'] = { - meta.labels.units: 'Milliseconds since 1970-1-1', - meta.labels.notes: 'UTC time at middle of geophysical measurement.', - meta.labels.desc: 'UTC seconds', - meta.labels.name: 'Time index in milliseconds'} -meta['position_eci_x'] = { - meta.labels.units: 'km', - meta.labels.name: 'ECI x-position', - meta.labels.desc: 'Earth Centered Inertial x-position of satellite.'} -meta['position_eci_y'] = { - meta.labels.units: 'km', - meta.labels.name: 'ECI y-position', - meta.labels.desc: 'Earth Centered Inertial y-position of satellite.'} -meta['position_eci_z'] = { - meta.labels.units: 'km', - meta.labels.name: 'ECI z-position', - meta.labels.desc: 'Earth Centered Inertial z-position of satellite.'} -meta['velocity_eci_x'] = { - meta.labels.units: 'km/s', - meta.labels.desc: 'Satellite velocity along ECI-x', - meta.labels.name: 'Satellite velocity ECI-x'} -meta['velocity_eci_y'] = { - meta.labels.units: 'km/s', - meta.labels.desc: 'Satellite velocity along ECI-y', - meta.labels.name: 'Satellite velocity ECI-y'} -meta['velocity_eci_z'] = { - meta.labels.units: 'km/s', - meta.labels.desc: 'Satellite velocity along ECI-z', - meta.labels.name: 'Satellite velocity ECI-z'} From 1712025a71ebc7ad33cf5c19156ac42bbbd17f75 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 19:28:18 -0400 Subject: [PATCH 020/147] MAINT: update requirements --- README.md | 2 +- docs/installation.rst | 2 +- requirements.txt | 2 +- setup.cfg | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 394390f8..94710e07 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Python 3.7+. | numpy | aacgmv2 | | pandas | apexpy | | pyEphem | OMMBV | -| sgp4 | pysat>=3.0 | +| sgp4>=2.7 | pysat>=3.0 | One way to install is through pip. Just type diff --git a/docs/installation.rst b/docs/installation.rst index ff497dc3..6c46823b 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -23,7 +23,7 @@ Python 3.7+ and pysat 3.0.0+. numpy aacgmv2 pandas apexpy pyEphem OMMBV - sgp4 pysat>=3.0 + sgp4>=2.7 pysat>=3.0 ================ ================== diff --git a/requirements.txt b/requirements.txt index 1b1faea6..5dd7b2ae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,4 @@ numpy pandas pysat>=3.0 pyEphem -sgp4 +sgp4>=2.7 diff --git a/setup.cfg b/setup.cfg index a258b972..79c6bb96 100644 --- a/setup.cfg +++ b/setup.cfg @@ -45,7 +45,7 @@ install_requires = pandas pysat>=3.0 pyEphem - sgp4 + sgp4>=2.7 [coverage:report] From 11426ac05832525833d51370451473d7243a9929 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 20:27:07 -0400 Subject: [PATCH 021/147] ENH: add oribtal kwarg collection check --- pysatMissions/instruments/methods/orbits.py | 21 +++++++++++++++------ pysatMissions/instruments/missions_sgp4.py | 2 ++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index c196f5d7..a8638b25 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -1,14 +1,23 @@ import numpy as np +import warnings -def check_orbital_params(inclination=None, eccentricity=None, raan=None, - arg_perigee=None, mean_anomaly=None, mean_motion=None): - """Check that a complete set of orbital parameters exist.""" +def _check_orbital_params(kwargs=None): + """Check that a complete set of unconflicted orbital parameters exist.""" - params = [inclination, eccentricity, raan, arg_perigee, mean_anomaly, - mean_motion] - return not any(v is None for v in params) + elements = list(kwargs['load'].keys()) + keplerians = ['alt_periapsis', 'alt_apoapsis', 'inclination', 'drag_coeff', + 'arg_periapsis', 'raan', 'mean_anomaly'] + tles = ['TLE1', 'TLE2'] + errmsg = 'Insufficient kwargs. Kwarg group requires {:}' + for group in [tles, keplerians]: + if any(v in elements for v in group): + if not all(v in elements for v in group): + raise KeyError(errmsg.format(', '.join(group))) + if all(v in elements for v in tles) and all(v in elements for v in keplerians): + warnings.warn(' '.join(['Cannot use both Keplerians and TLEs.', + 'Defaulting to Keplerians.'])) def _get_params(planet='Earth'): """Retrieve planetary constants for calculations. diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 87e7631f..80ab11b8 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -49,6 +49,8 @@ def init(self): """ + orbits._check_orbital_params(self.kwargs) + self.acknowledgements = ' '.join(( 'The project uses the sgp4 library available at', 'https://github.com/brandon-rhodes/python-sgp4')) From 2355fd7890718795b7dfae1f0b6dd410c58067f7 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 20:27:19 -0400 Subject: [PATCH 022/147] STY: rename function --- pysatMissions/instruments/methods/orbits.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index a8638b25..d3b512e2 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -19,7 +19,8 @@ def _check_orbital_params(kwargs=None): warnings.warn(' '.join(['Cannot use both Keplerians and TLEs.', 'Defaulting to Keplerians.'])) -def _get_params(planet='Earth'): + +def _get_constants(planet='Earth'): """Retrieve planetary constants for calculations. Parameters @@ -72,7 +73,7 @@ def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='Earth'): """ - radius, mass, gravity = _get_params(planet) + radius, mass, gravity = _get_constants(planet) if alt_apoapsis is None: alt_apoapsis = alt_periapsis @@ -111,7 +112,7 @@ def convert_from_keplerian(eccentricity, mean_motion, planet='Earth'): """ - radius, mass, gravity = _get_params(planet) + radius, mass, gravity = _get_constants(planet) # Convert mean_motion to rad / second before computing semimajor = (gravity * mass / (mean_motion / 60)**2) # Convert distance to km From ad6f826976add062892307f1f3b4b26c1c2057d0 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 20:27:43 -0400 Subject: [PATCH 023/147] TST: add instrument tests for initialization checks --- pysatMissions/tests/test_instruments.py | 59 +++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index 75499c01..644f2c16 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -1,6 +1,7 @@ import datetime as dt import numpy as np import tempfile +import warnings import pytest @@ -62,19 +63,20 @@ def setup_class(self): # to point to their own subpackage location, e.g., # self.inst_loc = mypackage.instruments self.inst_loc = pysatMissions.instruments + self.stime = pysatMissions.instruments.missions_sgp4._test_dates[''][''] def teardown_class(self): """Runs once to clean up testing from this class.""" pysat.params.data['data_dirs'] = self.saved_path self.tempdir.cleanup() - del self.inst_loc, self.saved_path, self.tempdir + del self.inst_loc, self.saved_path, self.tempdir, self.stime # Custom package unit tests can be added here @pytest.mark.parametrize("inst_dict", [x for x in instruments['download']]) @pytest.mark.parametrize("kwarg,output", [(None, 1), ('10s', 10)]) def test_inst_cadence(self, inst_dict, kwarg, output): - """Test operation of cadence keyword, including default behavior""" + """Test operation of cadence keyword, including default behavior.""" if kwarg: self.test_inst = pysat.Instrument( @@ -83,6 +85,57 @@ def test_inst_cadence(self, inst_dict, kwarg, output): self.test_inst = pysat.Instrument( inst_module=inst_dict['inst_module']) - self.test_inst.load(2019, 1) + self.test_inst.load(date=self.stime) cadence = np.diff(self.test_inst.data.index.to_pydatetime()) assert np.all(cadence == dt.timedelta(seconds=output)) + + @pytest.mark.parametrize( + "kw_dict", + [{'inclination': 13, 'alt_periapsis': 400, 'alt_apoapsis': 850, + 'drag_coeff': 0, 'arg_periapsis': 0., 'raan': 0., 'mean_anomaly': 0.}, + {'TLE1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998', + 'TLE2': '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452'} + ]) + def test_sgp4_options(self, kw_dict): + """Test optional keywords for sgp4.""" + + target = 'Fake Data to be cleared' + self.test_inst = pysat.Instrument( + inst_module=pysatMissions.instruments.missions_sgp4, + **kw_dict) + self.test_inst.data = [target] + self.test_inst.load(date=self.stime) + # If target is cleared, load has run successfully + assert target not in self.test_inst.data + + @pytest.mark.parametrize( + "kw_dict", + [{'inclination': 13, 'alt_periapsis': 400, 'alt_apoapsis': 850}, + {'TLE1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998'} + ]) + def test_sgp4_options_errors(self, kw_dict): + """Test optional keyword combos for sgp4 that generate errors.""" + + with pytest.raises(KeyError) as kerr: + self.test_inst = pysat.Instrument( + inst_module=pysatMissions.instruments.missions_sgp4, + **kw_dict) + assert str(kerr).find('Insufficient kwargs') >= 0 + + @pytest.mark.parametrize( + "kw_dict", + [{'inclination': 13, 'alt_periapsis': 400, 'alt_apoapsis': 850, + 'drag_coeff': 0, 'arg_periapsis': 0., 'raan': 0., 'mean_anomaly': 0., + 'TLE1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998', + 'TLE2': '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452'} + ]) + def test_sgp4_options_warnings(self, kw_dict): + """Test optional keyword combos for sgp4 that generate warnings.""" + + with warnings.catch_warnings(record=True) as war: + self.test_inst = pysat.Instrument( + inst_module=pysatMissions.instruments.missions_sgp4, + **kw_dict) + assert len(war) >= 1 + categories = [war[j].category for j in range(0, len(war))] + assert UserWarning in categories From d188460cce2ea0f18a135389cb74245f0e1adad6 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 20:28:49 -0400 Subject: [PATCH 024/147] DOC: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57348978..63291607 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [0.3.0] - 2021-06-24 * Add Keplerian orbital inputs into missions_sgp4 +* Update sgp4 interface to use new syntax for initialization from TLEs ## [0.2.2] - 2021-06-18 * Migrate pyglow interface to pysatIncubator From 8d106566b14c9f914f783947ad55cb8074b00ac2 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 20:29:37 -0400 Subject: [PATCH 025/147] DOC: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63291607..089aa0e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [0.3.0] - 2021-06-24 * Add Keplerian orbital inputs into missions_sgp4 * Update sgp4 interface to use new syntax for initialization from TLEs +* Improve metadata generation in missions_sgp4 ## [0.2.2] - 2021-06-18 * Migrate pyglow interface to pysatIncubator From 2eea93da5cf58a86a067e26acd9749917cbb744a Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 20:38:01 -0400 Subject: [PATCH 026/147] STY: doc and code style --- pysatMissions/instruments/methods/orbits.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index d3b512e2..6fb0a3b4 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -3,7 +3,15 @@ def _check_orbital_params(kwargs=None): - """Check that a complete set of unconflicted orbital parameters exist.""" + """Check that a complete set of unconflicted orbital parameters exist. + + Parameters + ---------- + kwargs : dict + Dictionary of optional kwargs passed through upon initialization + of pysat instrument. + + """ elements = list(kwargs['load'].keys()) @@ -19,6 +27,8 @@ def _check_orbital_params(kwargs=None): warnings.warn(' '.join(['Cannot use both Keplerians and TLEs.', 'Defaulting to Keplerians.'])) + return + def _get_constants(planet='Earth'): """Retrieve planetary constants for calculations. From 8ec752f1f7d31bf13acf398f0bf0926e75a6d0f7 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 20:39:38 -0400 Subject: [PATCH 027/147] ENH: pass through gravity constant --- pysatMissions/instruments/missions_sgp4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 80ab11b8..da5ab4f8 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -167,7 +167,7 @@ def load(fnames, tag=None, inst_id=None, mean_motion, np.radians(raan)) else: # Otherwise, use TLEs - satellite = Satrec.twoline2rv(line1, line2) + satellite = Satrec.twoline2rv(line1, line2, whichconst=WGS72) jd = jd * np.ones(len(times)) fr = times / 86400. From aed2c5dee995c167c13a03da0abcc6159fc0d61b Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 Aug 2021 20:41:24 -0400 Subject: [PATCH 028/147] BUG: no kwargs for sgp4 --- pysatMissions/instruments/missions_sgp4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index da5ab4f8..c0300f6d 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -167,7 +167,7 @@ def load(fnames, tag=None, inst_id=None, mean_motion, np.radians(raan)) else: # Otherwise, use TLEs - satellite = Satrec.twoline2rv(line1, line2, whichconst=WGS72) + satellite = Satrec.twoline2rv(line1, line2, WGS72) jd = jd * np.ones(len(times)) fr = times / 86400. From 6748358b8d246f3040e89889b5235cf649e69240 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 5 Aug 2021 11:21:09 -0400 Subject: [PATCH 029/147] ENH: add geodetic conversions --- pysatMissions/instruments/missions_sgp4.py | 77 ++++++++++++++-------- setup.cfg | 1 + 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index c0300f6d..3ab305bd 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -26,6 +26,8 @@ from pysatMissions.instruments import _core as mcore from pysatMissions.instruments.methods import orbits from sgp4.api import jday, Satrec, SGP4_ERRORS, WGS72 +from geospacepy import terrestrial_spherical as conv_sph +from geospacepy import terrestrial_ellipsoidal as conv_ell logger = pysat.logger @@ -146,7 +148,7 @@ def load(fnames, tag=None, inst_id=None, line2 = TLE2 if num_samples is None: - num_samples = 100 + num_samples = 86400 # Extract list of times from filenames and inst_id times, index, dates = ps_meth.generate_times(fnames, num_samples, @@ -179,13 +181,27 @@ def load(fnames, tag=None, inst_id=None, if np.any(err_code == i): raise ValueError(SGP4_ERRORS[i]) + # Add ECEF values to instrument. + + ecef = conv_sph.eci2ecef(position, (jd + fr)) + + # Convert to latitude, longitude, altitude. + # Ellipsoidal conversions require input in meters. + lat, lon, alt = conv_ell.ecef_cart2geodetic(ecef * 1000.) + # Put data into DataFrame data = pds.DataFrame({'position_eci_x': position[:, 0], 'position_eci_y': position[:, 1], 'position_eci_z': position[:, 2], 'velocity_eci_x': velocity[:, 0], 'velocity_eci_y': velocity[:, 1], - 'velocity_eci_z': velocity[:, 2]}, + 'velocity_eci_z': velocity[:, 2], + 'position_ecef_x': ecef[:, 0], + 'position_ecef_y': ecef[:, 1], + 'position_ecef_z': ecef[:, 2], + 'latitude': lat, + 'longitude': lon, + 'altitude': alt / 1000.}, # Convert altitude to km index=index) data.index.name = 'Epoch' @@ -196,32 +212,39 @@ def load(fnames, tag=None, inst_id=None, meta.labels.notes: 'UTC time at middle of geophysical measurement.', meta.labels.desc: 'UTC seconds', meta.labels.name: 'Time index in milliseconds'} - meta['position_eci_x'] = { - meta.labels.units: 'km', - meta.labels.name: 'ECI x-position', - meta.labels.desc: 'Earth Centered Inertial x-position of satellite.'} - meta['position_eci_y'] = { - meta.labels.units: 'km', - meta.labels.name: 'ECI y-position', - meta.labels.desc: 'Earth Centered Inertial y-position of satellite.'} - meta['position_eci_z'] = { + for v in ['x', 'y', 'z']: + meta['position_eci_{:}'.format(v)] = { + meta.labels.units: 'km', + meta.labels.name: 'ECI {:}-position'.format(v), + meta.labels.desc: 'Earth Centered Inertial {:}-position'.format(v)} + meta['velocity_eci_{:}'.format(v)] = { + meta.labels.units: 'km/s', + meta.labels.name: 'Satellite velocity ECI-{:}'.format(v), + meta.labels.desc: 'Satellite velocity along ECI-{:}'.format(v)} + meta['position_ecef_{:}'.format(v)] = { + meta.labels.units: 'km', + meta.labels.notes: 'Calculated using geospacepy-lite', + meta.labels.name: 'ECEF {:}-position'.format(v), + meta.labels.desc: 'Earth Centered Earth Fixed {:}-position'.format(v)} + meta['latitude'] = { + meta.labels.units: 'degrees', + meta.labels.notes: 'Calculated using geospacepy-lite', + meta.labels.name: 'Geodetic Latitude', + meta.labels.desc: 'Geodetic Latitude of satellite', + meta.labels.min_val: -90., + meta.labels.max_val: 90.} + meta['longitude'] = { + meta.labels.units: 'degrees', + meta.labels.notes: 'Calculated using geospacepy-lite', + meta.labels.name: 'Geodetic Longitude', + meta.labels.desc: 'Geodetic Longitude of satellite', + meta.labels.min_value: -180., + meta.labels.max_value: 180.} + meta['altitude'] = { meta.labels.units: 'km', - meta.labels.name: 'ECI z-position', - meta.labels.desc: 'Earth Centered Inertial z-position of satellite.'} - meta['velocity_eci_x'] = { - meta.labels.units: 'km/s', - meta.labels.desc: 'Satellite velocity along ECI-x', - meta.labels.name: 'Satellite velocity ECI-x'} - meta['velocity_eci_y'] = { - meta.labels.units: 'km/s', - meta.labels.desc: 'Satellite velocity along ECI-y', - meta.labels.name: 'Satellite velocity ECI-y'} - meta['velocity_eci_z'] = { - meta.labels.units: 'km/s', - meta.labels.desc: 'Satellite velocity along ECI-z', - meta.labels.name: 'Satellite velocity ECI-z'} - - # TODO: add call for GEI/ECEF translation here => #56 + meta.labels.notes: 'Calculated using geospacepy-lite', + meta.labels.name: 'Altitude', + meta.labels.desc: 'Altitude of satellite above an ellipsoidal Earth'} return data, meta diff --git a/setup.cfg b/setup.cfg index 79c6bb96..4a899521 100644 --- a/setup.cfg +++ b/setup.cfg @@ -40,6 +40,7 @@ packages = find: install_requires = aacgmv2 apexpy + geospacepy-lite numpy OMMBV pandas From bb59557af17fd1b3a0d5a941f4a6433d6c17d5f8 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 5 Aug 2021 11:22:56 -0400 Subject: [PATCH 030/147] DOC: update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 089aa0e4..5deb8c9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,10 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -## [0.3.0] - 2021-06-24 +## [0.3.0] - 2021-08-05 * Add Keplerian orbital inputs into missions_sgp4 * Update sgp4 interface to use new syntax for initialization from TLEs +* Include conversions to geodetic latitude / longitude / altitude for sgp4 * Improve metadata generation in missions_sgp4 ## [0.2.2] - 2021-06-18 From c39033b11d91fa775b6213858c5962eb34b4c224 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 5 Aug 2021 14:46:11 -0400 Subject: [PATCH 031/147] ENH: add ECEF velocity --- pysatMissions/instruments/missions_sgp4.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 3ab305bd..169bb771 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -183,11 +183,12 @@ def load(fnames, tag=None, inst_id=None, # Add ECEF values to instrument. - ecef = conv_sph.eci2ecef(position, (jd + fr)) + pos_ecef = conv_sph.eci2ecef(position, (jd + fr)) + vel_ecef = conv_sph.eci2ecef(velocity, (jd + fr)) # Convert to latitude, longitude, altitude. # Ellipsoidal conversions require input in meters. - lat, lon, alt = conv_ell.ecef_cart2geodetic(ecef * 1000.) + lat, lon, alt = conv_ell.ecef_cart2geodetic(pos_ecef * 1000.) # Put data into DataFrame data = pds.DataFrame({'position_eci_x': position[:, 0], @@ -196,9 +197,12 @@ def load(fnames, tag=None, inst_id=None, 'velocity_eci_x': velocity[:, 0], 'velocity_eci_y': velocity[:, 1], 'velocity_eci_z': velocity[:, 2], - 'position_ecef_x': ecef[:, 0], - 'position_ecef_y': ecef[:, 1], - 'position_ecef_z': ecef[:, 2], + 'position_ecef_x': pos_ecef[:, 0], + 'position_ecef_y': pos_ecef[:, 1], + 'position_ecef_z': pos_ecef[:, 2], + 'velocity_ecef_x': vel_ecef[:, 0], + 'velocity_ecef_y': vel_ecef[:, 1], + 'velocity_ecef_z': vel_ecef[:, 2], 'latitude': lat, 'longitude': lon, 'altitude': alt / 1000.}, # Convert altitude to km From 43c33a25ea52f9635bbcd4b1db5d937109bd91a7 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 5 Aug 2021 14:46:29 -0400 Subject: [PATCH 032/147] STY: improve metadata --- pysatMissions/instruments/missions_sgp4.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 169bb771..1867ab67 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -227,26 +227,31 @@ def load(fnames, tag=None, inst_id=None, meta.labels.desc: 'Satellite velocity along ECI-{:}'.format(v)} meta['position_ecef_{:}'.format(v)] = { meta.labels.units: 'km', - meta.labels.notes: 'Calculated using geospacepy-lite', + meta.labels.notes: 'Calculated using geospacepy.terrestrial_spherical', meta.labels.name: 'ECEF {:}-position'.format(v), meta.labels.desc: 'Earth Centered Earth Fixed {:}-position'.format(v)} + meta['velocity_ecef_{:}'.format(v)] = { + meta.labels.units: 'km', + meta.labels.notes: 'Calculated using geospacepy.terrestrial_spherical', + meta.labels.name: 'ECEF {:}-velocity'.format(v), + meta.labels.desc: 'Earth Centered Earth Fixed {:}-velocity'.format(v)} meta['latitude'] = { meta.labels.units: 'degrees', - meta.labels.notes: 'Calculated using geospacepy-lite', + meta.labels.notes: 'Calculated using geospacepy.terrestrial_ellipsoidal', meta.labels.name: 'Geodetic Latitude', meta.labels.desc: 'Geodetic Latitude of satellite', meta.labels.min_val: -90., meta.labels.max_val: 90.} meta['longitude'] = { meta.labels.units: 'degrees', - meta.labels.notes: 'Calculated using geospacepy-lite', + meta.labels.notes: 'Calculated using geospacepy.terrestrial_ellipsoidal', meta.labels.name: 'Geodetic Longitude', meta.labels.desc: 'Geodetic Longitude of satellite', - meta.labels.min_value: -180., - meta.labels.max_value: 180.} + meta.labels.min_val: -180., + meta.labels.max_val: 180.} meta['altitude'] = { meta.labels.units: 'km', - meta.labels.notes: 'Calculated using geospacepy-lite', + meta.labels.notes: 'Calculated using geospacepy.terrestrial_ellipsoidal', meta.labels.name: 'Altitude', meta.labels.desc: 'Altitude of satellite above an ellipsoidal Earth'} From 46faece33a4d4b9ff6d79265a6efa9c04c7dc987 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 5 Aug 2021 14:48:35 -0400 Subject: [PATCH 033/147] DOC: improve comments --- pysatMissions/instruments/missions_sgp4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 1867ab67..2f5fde36 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -186,7 +186,7 @@ def load(fnames, tag=None, inst_id=None, pos_ecef = conv_sph.eci2ecef(position, (jd + fr)) vel_ecef = conv_sph.eci2ecef(velocity, (jd + fr)) - # Convert to latitude, longitude, altitude. + # Convert to geodetic latitude, longitude, altitude. # Ellipsoidal conversions require input in meters. lat, lon, alt = conv_ell.ecef_cart2geodetic(pos_ecef * 1000.) From cd10299a8499dc5640988c2eefa5192f4eb66424 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 5 Aug 2021 14:50:38 -0400 Subject: [PATCH 034/147] TST: manual install of geospacepy-lite on github actions --- .github/workflows/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3f1f5f0b..4d0235ee 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,6 +29,11 @@ jobs: pip install -r requirements.txt # Manual install of OMMBV pip install --no-binary :OMMBV: OMMBV + # Manual install of geospacepy-lite + git clone https://github.com/lkilcommons/geospacepy-lite.git + cd geospacepy-lite + python setup.py install + cd .. - name: Set up pysat run: | From f37b1f68d4122c53f73e4d6ada7aea47c2cb2a8e Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 5 Aug 2021 14:56:27 -0400 Subject: [PATCH 035/147] TST: only scan pysatMissions for flake8 --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4d0235ee..8b932615 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,10 +41,10 @@ jobs: python -c "import pysat; pysat.params['data_dirs'] = 'pysatData'" - name: Test PEP8 compliance - run: flake8 . --count --select=E,F,W --show-source --statistics + run: flake8 ./pysatMissions/* --count --select=E,F,W --show-source --statistics - name: Evaluate complexity - run: flake8 . --count --exit-zero --max-complexity=10 --statistics + run: flake8 ./pysatMissions/* --count --exit-zero --max-complexity=10 --statistics - name: Test with pytest run: | From a43fcfd5e2a0ceecc3cd76f2333c97489e0080b6 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 09:06:16 -0400 Subject: [PATCH 036/147] Apply suggestions from code review Co-authored-by: Angeline Burrell --- pysatMissions/tests/test_instruments.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index 69b612ee..9d66af29 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -1,5 +1,4 @@ -""" -Unit and Integration Tests for each instrument module. +"""Unit and Integration Tests for each instrument module. Note ---- From 15dc5e23223b77b3ce830cb50d3daa65232eeb40 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 09:11:14 -0400 Subject: [PATCH 037/147] ENH: adjust default kwargs --- pysatMissions/instruments/methods/orbits.py | 5 ++--- pysatMissions/instruments/missions_sgp4.py | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 6fb0a3b4..970e673c 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -15,8 +15,7 @@ def _check_orbital_params(kwargs=None): elements = list(kwargs['load'].keys()) - keplerians = ['alt_periapsis', 'alt_apoapsis', 'inclination', 'drag_coeff', - 'arg_periapsis', 'raan', 'mean_anomaly'] + keplerians = ['alt_periapsis', 'inclination'] tles = ['TLE1', 'TLE2'] errmsg = 'Insufficient kwargs. Kwarg group requires {:}' for group in [tles, keplerians]: @@ -49,7 +48,7 @@ def _get_constants(planet='Earth'): Newton's gravitational constant """ - radius = {'Earth': 6371} + radius = {'Earth': 6371.2} mass = {'Earth': 5.9742e24} gravity = 6.6743e-11 diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 2f5fde36..59f821b7 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -72,8 +72,8 @@ def init(self): def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, alt_periapsis=None, alt_apoapsis=None, - inclination=None, raan=None, arg_periapsis=None, mean_anomaly=None, - drag_coeff=None, num_samples=None, cadence='1S'): + inclination=None, raan=0., arg_periapsis=0., mean_anomaly=0., + drag_coeff=0., num_samples=None, cadence='1S'): """ Generate position of satellite in ECI co-ordinates. From 8631493c3f8b05885e60daa59405dcca44127305 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 09:14:59 -0400 Subject: [PATCH 038/147] STY: docstrings --- pysatMissions/__init__.py | 3 +-- pysatMissions/instruments/__init__.py | 4 +--- pysatMissions/instruments/_core.py | 4 +--- pysatMissions/instruments/missions_ephem.py | 12 ++++-------- pysatMissions/instruments/missions_sgp4.py | 6 ++---- pysatMissions/methods/__init__.py | 4 +--- pysatMissions/methods/spacecraft.py | 10 +++------- 7 files changed, 13 insertions(+), 30 deletions(-) diff --git a/pysatMissions/__init__.py b/pysatMissions/__init__.py index 77fa067e..185b37a1 100644 --- a/pysatMissions/__init__.py +++ b/pysatMissions/__init__.py @@ -1,5 +1,4 @@ -""" -Core library for pysatMissions. +"""Core library for pysatMissions. pysatMissions allows users to run build simulated satellites for Two-Line Elements (TLE) and add empirical data. It includes the `missions_ephem` and diff --git a/pysatMissions/instruments/__init__.py b/pysatMissions/instruments/__init__.py index afa8e754..7c946936 100644 --- a/pysatMissions/instruments/__init__.py +++ b/pysatMissions/instruments/__init__.py @@ -1,6 +1,4 @@ -""" -Provides the instrument modules to be used with pysat. -""" +"""Provides the instrument modules to be used with pysat.""" from pysatMissions.instruments import missions_ephem, missions_sgp4 diff --git a/pysatMissions/instruments/_core.py b/pysatMissions/instruments/_core.py index 5c3c2914..913eca26 100644 --- a/pysatMissions/instruments/_core.py +++ b/pysatMissions/instruments/_core.py @@ -1,6 +1,4 @@ -""" -Handles the default pysat functions for simulated instruments. -""" +"""Handles the default pysat functions for simulated instruments.""" def _clean(self): diff --git a/pysatMissions/instruments/missions_ephem.py b/pysatMissions/instruments/missions_ephem.py index f22132b2..33d7a52b 100644 --- a/pysatMissions/instruments/missions_ephem.py +++ b/pysatMissions/instruments/missions_ephem.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -""" -Produce satellite orbit data. +"""Produce satellite orbit data. Orbit is simulated using Two Line Elements (TLEs) and ephem. Satellite position is coupled to several space science models to simulate the atmosphere the @@ -48,8 +47,7 @@ def init(self): - """ - Add custom calculations to orbit simulation. + """Add custom calculations to orbit simulation. This routine is run once, and only once, upon instantiation. Adds custom routines for quasi-dipole coordinates, velocity calculation in @@ -68,8 +66,7 @@ def init(self): def preprocess(self): - """ - Add modeled magnetic field values and attitude vectors to spacecraft. + """Add modeled magnetic field values and attitude vectors to spacecraft. Runs after load is invoked. @@ -89,8 +86,7 @@ def preprocess(self): def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., TLE1=None, TLE2=None, num_samples=None, cadence='1S'): - """ - Generate position of satellite in both geographic and ECEF co-ordinates. + """Generate position of satellite in both geographic and ECEF co-ordinates. Note ---- diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 89585423..46414cb4 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -""" -Produce satellite orbit data. +"""Produce satellite orbit data. Orbit is simulated using Two Line Elements (TLEs) and SGP4. @@ -66,8 +65,7 @@ def init(self): def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., TLE1=None, TLE2=None, num_samples=None, cadence='1S'): - """ - Generate position of satellite in ECI co-ordinates. + """Generate position of satellite in ECI co-ordinates. Note ---- diff --git a/pysatMissions/methods/__init__.py b/pysatMissions/methods/__init__.py index 2ed80e14..97dbd4c2 100644 --- a/pysatMissions/methods/__init__.py +++ b/pysatMissions/methods/__init__.py @@ -1,6 +1,4 @@ -""" -Provides the methods to interface with numerous empirical model packages. -""" +"""Provides the methods to interface with numerous empirical model packages.""" from pysatMissions.methods import magcoord from pysatMissions.methods import spacecraft diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index 0debad04..408557f7 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -1,14 +1,11 @@ -"""Default routines for projecting values onto vectors for pysat instruments. - -""" +"""Default routines for projecting values onto vectors for pysat instruments.""" import numpy as np import OMMBV def add_ram_pointing_sc_attitude_vectors(inst): - """ - Add attitude vectors for spacecraft assuming ram pointing. + """Add attitude vectors for spacecraft assuming ram pointing. Presumes spacecraft is pointed along the velocity vector (x), z is generally nadir pointing (positive towards Earth), and y completes the @@ -134,8 +131,7 @@ def add_ram_pointing_sc_attitude_vectors(inst): def calculate_ecef_velocity(inst): - """ - Calculate spacecraft velocity in ECEF frame. + """Calculate spacecraft velocity in ECEF frame. Presumes that the spacecraft velocity in ECEF is in the input instrument object as position_ecef_*. Uses a symmetric From 868f31cc2f52230acceebdb6ecc86324b925ad57 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 09:15:08 -0400 Subject: [PATCH 039/147] STY: return in tests --- pysatMissions/tests/test_instruments.py | 3 +++ pysatMissions/tests/test_methods_magcoord.py | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index 9d66af29..a27ba842 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -75,12 +75,14 @@ def setup_class(self): # to point to their own subpackage location, e.g., # self.inst_loc = mypackage.instruments self.inst_loc = pysatMissions.instruments + return def teardown_class(self): """Clean up downloaded files and parameters from tests.""" pysat.params.data['data_dirs'] = self.saved_path self.tempdir.cleanup() del self.inst_loc, self.saved_path, self.tempdir + return # Custom package unit tests can be added here @@ -99,3 +101,4 @@ def test_inst_cadence(self, inst_dict, kwarg, output): self.test_inst.load(2019, 1) cadence = np.diff(self.test_inst.data.index.to_pydatetime()) assert np.all(cadence == dt.timedelta(seconds=output)) + return diff --git a/pysatMissions/tests/test_methods_magcoord.py b/pysatMissions/tests/test_methods_magcoord.py index f5a646f8..cfd4e0cf 100644 --- a/pysatMissions/tests/test_methods_magcoord.py +++ b/pysatMissions/tests/test_methods_magcoord.py @@ -14,10 +14,12 @@ def setup(self): """Create a clean testing setup before each method.""" self.testInst = pysat.Instrument(platform='pysat', name='testing', num_samples=100, clean_level='clean') + return def teardown(self): """Clean up test environment after each method.""" del self + return def test_add_aacgm_coordinates(self): """Test adding thermal plasma data to test inst.""" @@ -33,6 +35,7 @@ def test_add_aacgm_coordinates(self): assert not np.isnan(self.testInst[target]).any() # Check if metadata is added assert target in self.testInst.meta.data.index + return def test_add_quasi_dipole_coordinates(self): """Test adding thermal plasma data to test inst.""" @@ -48,3 +51,4 @@ def test_add_quasi_dipole_coordinates(self): assert not np.isnan(self.testInst[target]).any() # Check if metadata is added assert target in self.testInst.meta.data.index + return From eb4afa4e3400cfd9a22953b9f1a6c72b001ed236 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 10:57:36 -0400 Subject: [PATCH 040/147] STY: docstrings --- pysatMissions/instruments/missions_sgp4.py | 3 +-- pysatMissions/methods/magcoord.py | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 46414cb4..ba143106 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -39,8 +39,7 @@ def init(self): - """ - Initialize the Instrument object with required values. + """Initialize the Instrument object with required values. Runs once upon instantiation. diff --git a/pysatMissions/methods/magcoord.py b/pysatMissions/methods/magcoord.py index 7db9b267..f70fa696 100644 --- a/pysatMissions/methods/magcoord.py +++ b/pysatMissions/methods/magcoord.py @@ -8,8 +8,7 @@ def add_aacgm_coordinates(inst, glat_label='glat', glong_label='glong', alt_label='alt'): - """ - Add AACGM coordinates to instrument object using AACGMV2 package. + """Add AACGM coordinates to instrument object using AACGMV2 package. The Altitude Adjusted Corrected Geomagnetic Coordinates library is used to calculate the latitude, longitude, and local time @@ -69,8 +68,7 @@ def add_aacgm_coordinates(inst, glat_label='glat', glong_label='glong', def add_quasi_dipole_coordinates(inst, glat_label='glat', glong_label='glong', alt_label='alt'): - """ - Add quasi-dipole coordinates to instrument object using Apexpy package. + """Add quasi-dipole coordinates to instrument object using Apexpy package. The Quasi-Dipole coordinate system includes both the tilt and offset of the geomagnetic field to calculate the latitude, longitude, and local time From 7f76bb55808719f127bd4f0c1172bdbb0ad8b78f Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 10:57:54 -0400 Subject: [PATCH 041/147] DOC: add issue numbers to TODO comments --- pysatMissions/methods/spacecraft.py | 2 +- pysatMissions/tests/test_methods_spacecraft.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index 408557f7..7b39abc6 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -206,7 +206,7 @@ def project_ecef_vector_onto_sc(inst, x_label, y_label, z_label, Dicts contain metadata to be assigned. """ - # TODO: add checks for existence of ecef labels in inst + # TODO: add checks for existence of ecef labels in inst => #65 x, y, z = OMMBV.project_ecef_vector_onto_basis( inst[x_label], inst[y_label], inst[z_label], diff --git a/pysatMissions/tests/test_methods_spacecraft.py b/pysatMissions/tests/test_methods_spacecraft.py index 3ff65279..bbfbf495 100644 --- a/pysatMissions/tests/test_methods_spacecraft.py +++ b/pysatMissions/tests/test_methods_spacecraft.py @@ -68,7 +68,7 @@ def test_calculate_ecef_velocity(self): def test_add_ram_pointing_sc_attitude_vectors(self): """Test `add_ram_pointing_sc_attitude_vectors` helper function.""" - # TODO: check if calculations are correct + # TODO: check if calculations are correct => #64 self.testInst.custom_attach(mm_sc.calculate_ecef_velocity) self.testInst.custom_attach(mm_sc.add_ram_pointing_sc_attitude_vectors) self.testInst.load(date=dt.datetime(2009, 1, 1)) @@ -89,7 +89,7 @@ def test_add_ram_pointing_sc_attitude_vectors(self): def test_project_ecef_vector_onto_sc(self): """Test `project_ecef_vector_onto_sc` helper function.""" - # TODO: check if calculations are correct + # TODO: check if calculations are correct => #64 self.testInst.custom_attach(mm_sc.calculate_ecef_velocity) self.testInst.custom_attach(mm_sc.add_ram_pointing_sc_attitude_vectors) self.testInst.custom_attach(add_fake_data) From 5608d990b6295f7b8680f0f249fdafb5f822ed72 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 12:41:34 -0400 Subject: [PATCH 042/147] Apply suggestions from code review Co-authored-by: Russell Stoneback --- pysatMissions/instruments/methods/orbits.py | 4 ++-- pysatMissions/instruments/missions_sgp4.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 6fb0a3b4..1f6112a0 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -35,7 +35,7 @@ def _get_constants(planet='Earth'): Parameters ---------- - planet : string + planet : str The name of the planet of interest. (default='Earth') @@ -69,7 +69,7 @@ def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='Earth'): alt_apoapsis : float or NoneType The highest altitude from the mean planet surface along the orbit (km) If None, assumed to be equal to periapsis. (default=None) - planet : string + planet : str The name of the planet of interest. Used for radial calculations and mass. (default='Earth') diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index c0300f6d..0b9e1a06 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -155,7 +155,7 @@ def load(fnames, tag=None, inst_id=None, epoch = (dates[0] - dt.datetime(1949, 12, 31)).days jd, _ = jday(dates[0].year, dates[0].month, dates[0].day, 0, 0, 0) - if inclination: + if inclination is not None: # If an inclination is provided, specify by Keplerian elements eccentricity, mean_motion = orbits.convert_to_keplerian(alt_periapsis, alt_apoapsis) From e5b6dc28ca5b04c6eda40bae56d2a5d20ae06128 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 13:06:40 -0400 Subject: [PATCH 043/147] STY: use bstar as kwarg --- pysatMissions/instruments/methods/orbits.py | 2 +- pysatMissions/instruments/missions_sgp4.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 1f6112a0..f33f2d9e 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -15,7 +15,7 @@ def _check_orbital_params(kwargs=None): elements = list(kwargs['load'].keys()) - keplerians = ['alt_periapsis', 'alt_apoapsis', 'inclination', 'drag_coeff', + keplerians = ['alt_periapsis', 'alt_apoapsis', 'inclination', 'bstar', 'arg_periapsis', 'raan', 'mean_anomaly'] tles = ['TLE1', 'TLE2'] errmsg = 'Insufficient kwargs. Kwarg group requires {:}' diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 0b9e1a06..f96547b3 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -71,7 +71,7 @@ def init(self): def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, alt_periapsis=None, alt_apoapsis=None, inclination=None, raan=None, arg_periapsis=None, mean_anomaly=None, - drag_coeff=None, num_samples=None, cadence='1S'): + bstar=None, num_samples=None, cadence='1S'): """ Generate position of satellite in ECI co-ordinates. @@ -106,8 +106,9 @@ def load(fnames, tag=None, inst_id=None, The fraction of an elliptical orbit's period that has elapsed since the orbiting body passed periapsis (default=None) - drag_coeff : float - Drag coefficient (default=None) + bstar : float + Inverse of the ballistic coefficient. Used to model satellite drag. + Measured in inverse distance (1 / earth radius). (default=None) num_samples : int Number of samples per day cadence : str @@ -161,7 +162,7 @@ def load(fnames, tag=None, inst_id=None, alt_apoapsis) satellite = Satrec() # according to module webpage, wgs72 is common - satellite.sgp4init(WGS72, 'i', 0, epoch, drag_coeff, 0, 0, + satellite.sgp4init(WGS72, 'i', 0, epoch, bstar, 0, 0, eccentricity, np.radians(arg_periapsis), np.radians(inclination), np.radians(mean_anomaly), mean_motion, np.radians(raan)) From cabc35e6f88d74668fc7f75c330506e64aefae96 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 13:06:49 -0400 Subject: [PATCH 044/147] DOC: update definitions --- pysatMissions/instruments/missions_sgp4.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index f96547b3..7a85b1ab 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -99,12 +99,22 @@ def load(fnames, tag=None, inst_id=None, inclination : float Orbital Inclination in degrees (default=None) raan : float - Right Ascension of the Ascending Node in degrees (default=None) + Right Ascension of the Ascending Node (RAAN) in degrees. This defines + the orientation of the orbital plane to the generalized reference frame. + The Ascending Node is the point in the orbit where the spacecraft passes + through the plane of reference moving northward. For Earth orbits, the + location of the RAAN is defined as the angle eastward of the First Point + of Aries. + (default=None) arg_periapsis : float - Argument of Periapsis in degrees (default=None) + Argument of Periapsis in degrees. This defines the orientation of the + ellipse in the orbital plane, as an angle measured from the ascending + node to the periapsis (default=None) mean_anomaly : float The fraction of an elliptical orbit's period that has elapsed since the - orbiting body passed periapsis + orbiting body passed periapsis. Note that this is a "fictitious angle" + (input in degrees) which defines the location of the spacecraft in the + orbital plane based on the orbital period. (default=None) bstar : float Inverse of the ballistic coefficient. Used to model satellite drag. From b2957768e104bad974ec57f2c1a397d6e368cd1b Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 13:10:27 -0400 Subject: [PATCH 045/147] BUG: bstar in tests --- pysatMissions/tests/test_instruments.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index 644f2c16..c9071ada 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -92,7 +92,7 @@ def test_inst_cadence(self, inst_dict, kwarg, output): @pytest.mark.parametrize( "kw_dict", [{'inclination': 13, 'alt_periapsis': 400, 'alt_apoapsis': 850, - 'drag_coeff': 0, 'arg_periapsis': 0., 'raan': 0., 'mean_anomaly': 0.}, + 'bstar': 0, 'arg_periapsis': 0., 'raan': 0., 'mean_anomaly': 0.}, {'TLE1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998', 'TLE2': '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452'} ]) @@ -125,7 +125,7 @@ def test_sgp4_options_errors(self, kw_dict): @pytest.mark.parametrize( "kw_dict", [{'inclination': 13, 'alt_periapsis': 400, 'alt_apoapsis': 850, - 'drag_coeff': 0, 'arg_periapsis': 0., 'raan': 0., 'mean_anomaly': 0., + 'bstar': 0, 'arg_periapsis': 0., 'raan': 0., 'mean_anomaly': 0., 'TLE1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998', 'TLE2': '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452'} ]) From ee93307e1ec6c1d51e6c74ed5e273febe1444ea6 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 13:43:38 -0400 Subject: [PATCH 046/147] STY: update metadata --- pysatMissions/instruments/missions_ephem.py | 62 ++++++++++---------- pysatMissions/methods/spacecraft.py | 65 +++++---------------- 2 files changed, 46 insertions(+), 81 deletions(-) diff --git a/pysatMissions/instruments/missions_ephem.py b/pysatMissions/instruments/missions_ephem.py index 11e3f466..20228859 100644 --- a/pysatMissions/instruments/missions_ephem.py +++ b/pysatMissions/instruments/missions_ephem.py @@ -213,38 +213,38 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., index=index) data.index.name = 'Epoch' - return data, meta.copy() + meta = pysat.Meta() + meta['Epoch'] = { + meta.labels.units: 'Milliseconds since 1970-1-1', + meta.labels.notes: 'UTC time at middle of geophysical measurement.', + meta.labels.desc: 'UTC seconds', + meta.labels.name: 'Time index in milliseconds'} + meta['glong'] = {meta.labels.units: 'degrees', + meta.labels.desc: 'WGS84 geodetic longitude'} + meta['glat'] = {meta.labels.units: 'degrees', + meta.labels.desc: 'WGS84 geodetic latitude'} + meta['alt'] = {meta.labels.units: 'km', + meta.labels.desc: "WGS84 height above Earth's surface"} + for v in ['x', 'y', 'z']: + meta['position_ecef_{:}'.format(v)] = { + meta.labels.units: 'km', + meta.labels.name: 'ECEF {:}-position'.format(v), + meta.labels.desc: 'Earth Centered Earth Fixed {:}-position'.format(v)} + meta['obs_sat_az_angle'] = { + meta.labels.units: 'degrees', + meta.labels.name: 'Satellite Azimuth Angle', + meta.labels.desc: 'Azimuth of satellite from ground station'} + meta['obs_sat_el_angle'] = { + meta.labels.units: 'degrees', + meta.labels.name: 'Satellite Elevation Angle', + meta.labels.desc: 'Elevation of satellite from ground station'} + meta['obs_sat_slant_range'] = { + meta.labels.units: 'km', + meta.labels.name: 'Satellite Slant Distance', + meta.labels.desc: 'Distance of satellite from ground station'} + + return data, meta list_files = functools.partial(ps_meth.list_files, test_dates=_test_dates) download = functools.partial(ps_meth.download) - -# Create metadata corresponding to variables in load routine just above. -# Defined here here rather than above to avoid regeneration at every load call. -meta = pysat.Meta() -meta['Epoch'] = { - meta.labels.units: 'Milliseconds since 1970-1-1', - meta.labels.notes: 'UTC time at middle of geophysical measurement.', - meta.labels.desc: 'UTC seconds', - meta.labels.name: 'Time index in milliseconds'} -meta['glong'] = {meta.labels.units: 'degrees', - meta.labels.desc: 'WGS84 geodetic longitude'} -meta['glat'] = {meta.labels.units: 'degrees', - meta.labels.desc: 'WGS84 geodetic latitude'} -meta['alt'] = {meta.labels.units: 'km', - meta.labels.desc: "WGS84 height above Earth's surface"} -meta['position_ecef_x'] = {meta.labels.units: 'km', - meta.labels.desc: 'ECEF x co-ordinate of satellite'} -meta['position_ecef_y'] = {meta.labels.units: 'km', - meta.labels.desc: 'ECEF y co-ordinate of satellite'} -meta['position_ecef_z'] = {meta.labels.units: 'km', - meta.labels.desc: 'ECEF z co-ordinate of satellite'} -meta['obs_sat_az_angle'] = { - meta.labels.units: 'degrees', - meta.labels.desc: 'Azimuth of satellite from ground station'} -meta['obs_sat_el_angle'] = { - meta.labels.units: 'degrees', - meta.labels.desc: 'Elevation of satellite from ground station'} -meta['obs_sat_slant_range'] = { - meta.labels.units: 'km', - meta.labels.desc: 'Distance of satellite from ground station'} diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index 6600a6fb..decb9bf7 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -83,44 +83,15 @@ def add_ram_pointing_sc_attitude_vectors(inst): inst['sc_yhat_ecef_z']) # Adding metadata - inst.meta['sc_xhat_ecef_x'] = { - 'units': '', - 'desc': ' '.join(('S/C attitude (x-direction, ram) unit vector,', - 'expressed in ECEF basis, x-component'))} - inst.meta['sc_xhat_ecef_y'] = { - 'units': '', - 'desc': ' '.join(('S/C attitude (x-direction, ram) unit vector,', - 'expressed in ECEF basis, y-component'))} - inst.meta['sc_xhat_ecef_z'] = { - 'units': '', - 'desc': ' '.join(('S/C attitude (x-direction, ram) unit vector,', - 'expressed in ECEF basis, z-component'))} - - inst.meta['sc_zhat_ecef_x'] = { - 'units': '', - 'desc': ' '.join(('S/C attitude (z-direction, generally nadir) unit', - 'vector, expressed in ECEF basis, x-component'))} - inst.meta['sc_zhat_ecef_y'] = { - 'units': '', - 'desc': ' '.join(('S/C attitude (z-direction, generally nadir) unit', - 'vector, expressed in ECEF basis, y-component'))} - inst.meta['sc_zhat_ecef_z'] = { - 'units': '', - 'desc': ' '.join(('S/C attitude (z-direction, generally nadir) unit', - 'vector, expressed in ECEF basis, z-component'))} - - inst.meta['sc_yhat_ecef_x'] = { - 'units': '', - 'desc': ' '.join(('S/C attitude (y-direction, generally south) unit', - 'vector, expressed in ECEF basis, x-component'))} - inst.meta['sc_yhat_ecef_y'] = { - 'units': '', - 'desc': ' '.join(('S/C attitude (y-direction, generally south) unit', - 'vector, expressed in ECEF basis, y-component'))} - inst.meta['sc_yhat_ecef_z'] = { - 'units': '', - 'desc': ' '.join(('S/C attitude (y-direction, generally south) unit', - 'vector, expressed in ECEF basis, z-component'))} + for v in ['x', 'y', 'z']: + for u in ['x', 'y', 'z']: + inst.meta['sc_{:}hat_ecef_{:}'.format(v, u)] = { + inst.meta.labels.units: '', + inst.meta.labels.name: 'SC {:}-unit vector, ECEF-{:}'.format(v, u), + inst.meta.labels.desc: ' '.join(('S/C attitude ({:}'.format(v), + '-direction, ram) unit vector,', + 'expressed in ECEF basis,', + '{:}-component'.format(u)))} # check what magnitudes we get mag = np.sqrt(inst['sc_zhat_ecef_x']**2 + inst['sc_zhat_ecef_y']**2 @@ -169,18 +140,12 @@ def get_vel_from_pos(x): inst[1:-1, 'velocity_ecef_y'] = vel_y inst[1:-1, 'velocity_ecef_z'] = vel_z - inst.meta['velocity_ecef_x'] = {'units': 'km/s', - 'desc': ' '.join(('Velocity of satellite', - 'calculated with respect', - 'to ECEF frame.'))} - inst.meta['velocity_ecef_y'] = {'units': 'km/s', - 'desc': ' '.join(('Velocity of satellite', - 'calculated with respect', - 'to ECEF frame.'))} - inst.meta['velocity_ecef_z'] = {'units': 'km/s', - 'desc': ' '.join(('Velocity of satellite', - 'calculated with respect', - 'to ECEF frame.'))} + for v in ['x', 'y', 'z']: + inst.meta['velocity_ecef_{:}'.format(v)] = { + inst.meta.labels.units: 'km/s', + inst.meta.labels.name: 'ECEF {:}-velocity'.format(v), + inst.meta.labels.desc: ' '.join(('Velocity of satellite calculated', + 'with respect to ECEF frame.'))} return From 4a9301213f74d692716d23fde5e5d8f9a7551d01 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 14:35:48 -0400 Subject: [PATCH 047/147] ENH: add spherical coords --- pysatMissions/instruments/missions_sgp4.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 59f821b7..189b7d85 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -186,9 +186,11 @@ def load(fnames, tag=None, inst_id=None, pos_ecef = conv_sph.eci2ecef(position, (jd + fr)) vel_ecef = conv_sph.eci2ecef(velocity, (jd + fr)) + # Convert to geocentric latitude, longitude, altitude. + lat, lon, rad = conv_sph.ecef_cart2spherical(pos_ecef) # Convert to geodetic latitude, longitude, altitude. # Ellipsoidal conversions require input in meters. - lat, lon, alt = conv_ell.ecef_cart2geodetic(pos_ecef * 1000.) + geod_lat, geod_lon, geod_alt = conv_ell.ecef_cart2geodetic(pos_ecef * 1000.) # Put data into DataFrame data = pds.DataFrame({'position_eci_x': position[:, 0], @@ -205,7 +207,10 @@ def load(fnames, tag=None, inst_id=None, 'velocity_ecef_z': vel_ecef[:, 2], 'latitude': lat, 'longitude': lon, - 'altitude': alt / 1000.}, # Convert altitude to km + 'mean_altitude': rad - 6371.2, + 'geod_latitude': geod_lat, + 'geod_longitude': geod_lon, + 'geod_altitude': geod_alt / 1000.}, # Convert altitude to km index=index) data.index.name = 'Epoch' From 1f23230697d92abf9f1405531b584c19f2c6f9a8 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 15:02:11 -0400 Subject: [PATCH 048/147] TST: use pip install for geospacepy --- .github/workflows/main.yml | 9 ++------- requirements.txt | 1 + setup.cfg | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8b932615..3f1f5f0b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,11 +29,6 @@ jobs: pip install -r requirements.txt # Manual install of OMMBV pip install --no-binary :OMMBV: OMMBV - # Manual install of geospacepy-lite - git clone https://github.com/lkilcommons/geospacepy-lite.git - cd geospacepy-lite - python setup.py install - cd .. - name: Set up pysat run: | @@ -41,10 +36,10 @@ jobs: python -c "import pysat; pysat.params['data_dirs'] = 'pysatData'" - name: Test PEP8 compliance - run: flake8 ./pysatMissions/* --count --select=E,F,W --show-source --statistics + run: flake8 . --count --select=E,F,W --show-source --statistics - name: Evaluate complexity - run: flake8 ./pysatMissions/* --count --exit-zero --max-complexity=10 --statistics + run: flake8 . --count --exit-zero --max-complexity=10 --statistics - name: Test with pytest run: | diff --git a/requirements.txt b/requirements.txt index 5dd7b2ae..a296180a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ aacgmv2 apexpy +geospacepy numpy pandas pysat>=3.0 diff --git a/setup.cfg b/setup.cfg index 4a899521..f631681d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -40,7 +40,7 @@ packages = find: install_requires = aacgmv2 apexpy - geospacepy-lite + geospacepy numpy OMMBV pandas From b1e379228b7811a0660ae3fdfb7f604f7f30c077 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 15:19:32 -0400 Subject: [PATCH 049/147] BUG: update test parameters --- pysatMissions/tests/test_inst_methods_orbits.py | 4 ++-- pysatMissions/tests/test_instruments.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pysatMissions/tests/test_inst_methods_orbits.py b/pysatMissions/tests/test_inst_methods_orbits.py index 44cbbf1f..d31a9b17 100644 --- a/pysatMissions/tests/test_inst_methods_orbits.py +++ b/pysatMissions/tests/test_inst_methods_orbits.py @@ -10,8 +10,8 @@ class TestBasics(): def setup(self): """Create a clean testing setup before each method.""" self.orbit = {'inclination': 13, 'apogee': 850, 'perigee': 400, - 'eccentricity': 0.032161234991424, - 'mean_motion': 0.0647469462135} + 'eccentricity': 0.032160315599897085, + 'mean_motion': 0.06474416985702029} return def teardown(self): diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index c9071ada..8b769382 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -110,7 +110,7 @@ def test_sgp4_options(self, kw_dict): @pytest.mark.parametrize( "kw_dict", - [{'inclination': 13, 'alt_periapsis': 400, 'alt_apoapsis': 850}, + [{'inclination': 13, 'alt_apoapsis': 850}, {'TLE1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998'} ]) def test_sgp4_options_errors(self, kw_dict): From 110f565566746b1767b086901106e8b2990a40ad Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 Aug 2021 16:44:40 -0400 Subject: [PATCH 050/147] ENH: option to output single orbit --- pysatMissions/instruments/missions_sgp4.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 8f0bc2fd..fc4ed725 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -70,10 +70,10 @@ def init(self): clean = mcore._clean -def load(fnames, tag=None, inst_id=None, - TLE1=None, TLE2=None, alt_periapsis=None, alt_apoapsis=None, +def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, + alt_periapsis=None, alt_apoapsis=None, inclination=None, raan=0., arg_periapsis=0., mean_anomaly=0., - bstar=0., num_samples=None, cadence='1S'): + bstar=0., one_orbit=False, num_samples=None, cadence='1S'): """ Generate position of satellite in ECI co-ordinates. @@ -121,6 +121,9 @@ def load(fnames, tag=None, inst_id=None, bstar : float Inverse of the ballistic coefficient. Used to model satellite drag. Measured in inverse distance (1 / earth radius). (default=None) + one_orbit : bool + Flag to override num_samples and only provide a single orbit. + (default=False) num_samples : int Number of samples per day cadence : str @@ -158,7 +161,7 @@ def load(fnames, tag=None, inst_id=None, if TLE2 is not None: line2 = TLE2 - if num_samples is None: + if (num_samples is None) or one_orbit: num_samples = 86400 # Extract list of times from filenames and inst_id @@ -181,6 +184,12 @@ def load(fnames, tag=None, inst_id=None, else: # Otherwise, use TLEs satellite = Satrec.twoline2rv(line1, line2, WGS72) + mean_motion = satellite.mean_motion + + if one_orbit: + ind = times <= (2 * np.pi / mean_motion * 60) + times = times[ind] + index = index[ind] jd = jd * np.ones(len(times)) fr = times / 86400. From 3b9b771767c6cba722709183c9a269bd89e1f9a2 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 9 Aug 2021 09:50:52 -0400 Subject: [PATCH 051/147] Apply suggestions from code review Co-authored-by: Angeline Burrell --- pysatMissions/instruments/missions_sgp4.py | 4 +--- pysatMissions/methods/magcoord.py | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index ba143106..ed41c2af 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- -"""Produce satellite orbit data. - -Orbit is simulated using Two Line Elements (TLEs) and SGP4. +"""Simulate satellite orbit data using Two Line Elements (TLEs) and SGP4. Properties ---------- diff --git a/pysatMissions/methods/magcoord.py b/pysatMissions/methods/magcoord.py index f70fa696..93a6075f 100644 --- a/pysatMissions/methods/magcoord.py +++ b/pysatMissions/methods/magcoord.py @@ -1,5 +1,4 @@ -""" -Routines for projecting aacgmv2 and apexpy model values onto pysat instruments. +"""Routines for projecting aacgmv2 and apexpy model values onto pysat instruments. """ import aacgmv2 From f268a5151b8a0e05ddcfda6178bfaea4025e430c Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 9 Aug 2021 14:46:32 -0400 Subject: [PATCH 052/147] DOC: add note and example for tests --- pysatMissions/tests/__init__.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/pysatMissions/tests/__init__.py b/pysatMissions/tests/__init__.py index 6ddd2b0b..96d5f6ef 100644 --- a/pysatMissions/tests/__init__.py +++ b/pysatMissions/tests/__init__.py @@ -1 +1,20 @@ -"""Unit and Integration tests for pysatMissions.""" +"""Unit and Integration tests for pysatMissions. + +Note +---- +This file must remain empty of code for pytest to function. + +Example +------- +To run all tests: +:: + + pytest + + To run a specific test, include the filename (with the full path if not in the + test directory), class, and test name: + :: + + pytest test_instruments.py::TestInstruments::test_inst_cadence + +""" From 7a74b185034daa34549e433a816d21a40869bce7 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 10:34:45 -0400 Subject: [PATCH 053/147] DOC: Improve metadata --- pysatMissions/instruments/missions_sgp4.py | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index fc4ed725..c9e09bf8 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -261,20 +261,39 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, meta.labels.name: 'ECEF {:}-velocity'.format(v), meta.labels.desc: 'Earth Centered Earth Fixed {:}-velocity'.format(v)} meta['latitude'] = { + meta.labels.units: 'degrees', + meta.labels.notes: 'Calculated using geospacepy.terrestrial_spherical', + meta.labels.name: 'Geocentric Latitude', + meta.labels.desc: 'Geocentric Latitude of satellite', + meta.labels.min_val: -90., + meta.labels.max_val: 90.} + meta['longitude'] = { + meta.labels.units: 'degrees', + meta.labels.notes: 'Calculated using geospacepy.terrestrial_spherical', + meta.labels.name: 'Geocentric Longitude', + meta.labels.desc: 'Geocentric Longitude of satellite', + meta.labels.min_val: -180., + meta.labels.max_val: 180.} + meta['mean_altitude'] = { + meta.labels.units: 'km', + meta.labels.notes: 'Calculated using geospacepy.terrestrial_spherical', + meta.labels.name: 'Altitude', + meta.labels.desc: 'Altitude of satellite above an ellipsoidal Earth'} + meta['geod_latitude'] = { meta.labels.units: 'degrees', meta.labels.notes: 'Calculated using geospacepy.terrestrial_ellipsoidal', meta.labels.name: 'Geodetic Latitude', meta.labels.desc: 'Geodetic Latitude of satellite', meta.labels.min_val: -90., meta.labels.max_val: 90.} - meta['longitude'] = { + meta['geod_longitude'] = { meta.labels.units: 'degrees', meta.labels.notes: 'Calculated using geospacepy.terrestrial_ellipsoidal', meta.labels.name: 'Geodetic Longitude', meta.labels.desc: 'Geodetic Longitude of satellite', meta.labels.min_val: -180., meta.labels.max_val: 180.} - meta['altitude'] = { + meta['geod_altitude'] = { meta.labels.units: 'km', meta.labels.notes: 'Calculated using geospacepy.terrestrial_ellipsoidal', meta.labels.name: 'Altitude', From b2889ab1e9f6402e2d4f6addbae378d75d426a2c Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 10:39:01 -0400 Subject: [PATCH 054/147] STY: import order --- pysatMissions/instruments/__init__.py | 3 ++- pysatMissions/tests/test_instruments.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pysatMissions/instruments/__init__.py b/pysatMissions/instruments/__init__.py index 7c946936..3e1d3a76 100644 --- a/pysatMissions/instruments/__init__.py +++ b/pysatMissions/instruments/__init__.py @@ -1,5 +1,6 @@ """Provides the instrument modules to be used with pysat.""" -from pysatMissions.instruments import missions_ephem, missions_sgp4 +from pysatMissions.instruments import missions_ephem +from pysatMissions.instruments import missions_sgp4 __all__ = ['missions_ephem', 'missions_sgp4'] diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index a27ba842..ec9b0802 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -18,8 +18,8 @@ import pysatMissions # Import the test classes from pysat -from pysat.utils import generate_instrument_list from pysat.tests.instrument_test_class import InstTestClass +from pysat.utils import generate_instrument_list saved_path = pysat.params['data_dirs'] From 6081e9f015a7bbb72e047ee21ceaaa7179b20302 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 10:39:21 -0400 Subject: [PATCH 055/147] DOC: TODO statements --- pysatMissions/instruments/missions_sgp4.py | 2 +- pysatMissions/methods/spacecraft.py | 2 +- pysatMissions/tests/test_methods_spacecraft.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index ed41c2af..c6d9e533 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -164,7 +164,7 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., index=index) data.index.name = 'Epoch' - # TODO: add call for GEI/ECEF translation here => #56 + # TODO(#56): add call for GEI/ECEF translation here return data, meta.copy() diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index 7b39abc6..f6673c56 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -206,7 +206,7 @@ def project_ecef_vector_onto_sc(inst, x_label, y_label, z_label, Dicts contain metadata to be assigned. """ - # TODO: add checks for existence of ecef labels in inst => #65 + # TODO(#65): add checks for existence of ecef labels in inst x, y, z = OMMBV.project_ecef_vector_onto_basis( inst[x_label], inst[y_label], inst[z_label], diff --git a/pysatMissions/tests/test_methods_spacecraft.py b/pysatMissions/tests/test_methods_spacecraft.py index bbfbf495..45ad0479 100644 --- a/pysatMissions/tests/test_methods_spacecraft.py +++ b/pysatMissions/tests/test_methods_spacecraft.py @@ -68,7 +68,7 @@ def test_calculate_ecef_velocity(self): def test_add_ram_pointing_sc_attitude_vectors(self): """Test `add_ram_pointing_sc_attitude_vectors` helper function.""" - # TODO: check if calculations are correct => #64 + # TODO(#64): check if calculations are correct self.testInst.custom_attach(mm_sc.calculate_ecef_velocity) self.testInst.custom_attach(mm_sc.add_ram_pointing_sc_attitude_vectors) self.testInst.load(date=dt.datetime(2009, 1, 1)) @@ -89,7 +89,7 @@ def test_add_ram_pointing_sc_attitude_vectors(self): def test_project_ecef_vector_onto_sc(self): """Test `project_ecef_vector_onto_sc` helper function.""" - # TODO: check if calculations are correct => #64 + # TODO(#64): check if calculations are correct self.testInst.custom_attach(mm_sc.calculate_ecef_velocity) self.testInst.custom_attach(mm_sc.add_ram_pointing_sc_attitude_vectors) self.testInst.custom_attach(add_fake_data) From e65202396fc5cb353ac10cae8000166a4029b762 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 10:39:32 -0400 Subject: [PATCH 056/147] STY: whitespace --- pysatMissions/tests/test_instruments.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index ec9b0802..aa4fd331 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -66,6 +66,7 @@ class TestInstruments(InstTestClass): def setup_class(self): """Initialize the testing setup once before all tests are run.""" + # Make sure to use a temporary directory so that the user's setup is not # altered self.tempdir = tempfile.TemporaryDirectory() @@ -79,6 +80,7 @@ def setup_class(self): def teardown_class(self): """Clean up downloaded files and parameters from tests.""" + pysat.params.data['data_dirs'] = self.saved_path self.tempdir.cleanup() del self.inst_loc, self.saved_path, self.tempdir From 445ecb9850dd4785996900d59eca729d0cf39086 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 10:39:42 -0400 Subject: [PATCH 057/147] STY: class declaration --- pysatMissions/tests/test_methods_magcoord.py | 2 +- pysatMissions/tests/test_methods_spacecraft.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pysatMissions/tests/test_methods_magcoord.py b/pysatMissions/tests/test_methods_magcoord.py index cfd4e0cf..142ea8eb 100644 --- a/pysatMissions/tests/test_methods_magcoord.py +++ b/pysatMissions/tests/test_methods_magcoord.py @@ -7,7 +7,7 @@ import pysatMissions.methods.magcoord as mm_magcoord -class TestBasics(): +class TestBasics(object): """Main testing class for aacgmv2.""" def setup(self): diff --git a/pysatMissions/tests/test_methods_spacecraft.py b/pysatMissions/tests/test_methods_spacecraft.py index 45ad0479..5ebfe6af 100644 --- a/pysatMissions/tests/test_methods_spacecraft.py +++ b/pysatMissions/tests/test_methods_spacecraft.py @@ -31,7 +31,7 @@ def add_fake_data(inst): return -class TestBasics(): +class TestBasics(object): """Unit tests for aacgmv2 methods.""" def setup(self): From f12f004d4fe4922e6813637e2c99c6dced5f5f5c Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 10:40:06 -0400 Subject: [PATCH 058/147] TST: add hacking to tests --- .github/workflows/main.yml | 2 +- test_requirements.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2b7ba1cb..1da4db40 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,7 +36,7 @@ jobs: python -c "import pysat; pysat.params['data_dirs'] = 'pysatData'" - name: Test PEP8 compliance - run: flake8 . --count --select=D,E,F,W --show-source --statistics + run: flake8 . --count --select=D,E,F,H,W --show-source --statistics - name: Evaluate complexity run: flake8 . --count --exit-zero --max-complexity=10 --statistics diff --git a/test_requirements.txt b/test_requirements.txt index bac35e66..9a78f43b 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,5 +1,6 @@ coveralls flake8-docstrings +hacking ipython m2r2 numpydoc From f649e72b0d62694793a86ed56e7fdac00db81d20 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 12:14:15 -0400 Subject: [PATCH 059/147] Update pysatMissions/tests/test_methods_spacecraft.py Co-authored-by: Angeline Burrell --- pysatMissions/tests/test_methods_spacecraft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/tests/test_methods_spacecraft.py b/pysatMissions/tests/test_methods_spacecraft.py index 5ebfe6af..21a67e6d 100644 --- a/pysatMissions/tests/test_methods_spacecraft.py +++ b/pysatMissions/tests/test_methods_spacecraft.py @@ -23,7 +23,7 @@ def add_eci(inst): def add_fake_data(inst): - """Add arbitrary vector to pysat_testing instrument.""" + """Add an arbitrary vector to a pysat_testing instrument.""" inst['ax'] = np.ones(9) inst['ay'] = np.zeros(9) From ba00757e8f79a693f0ff7658fc1e214a4a8929bc Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 14:18:04 -0400 Subject: [PATCH 060/147] STY: typo --- pysatMissions/instruments/methods/orbits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 891a3077..ab0de5ce 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -43,7 +43,7 @@ def _get_constants(planet='Earth'): radius : float (km) The average radius to the surface of a planet. mass : float (kg) - The avergae mass of the planet. + The average mass of the planet. gravity : float (m**3 kg / s**2) Newton's gravitational constant """ From 93e1b202337a33525d3e4bd335d5607b475fdd20 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 14:30:32 -0400 Subject: [PATCH 061/147] DOC: add docstrings --- pysatMissions/instruments/methods/__init__.py | 2 ++ pysatMissions/instruments/methods/orbits.py | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pysatMissions/instruments/methods/__init__.py b/pysatMissions/instruments/methods/__init__.py index 1040a7f4..2fa11425 100644 --- a/pysatMissions/instruments/methods/__init__.py +++ b/pysatMissions/instruments/methods/__init__.py @@ -1,3 +1,5 @@ +"""Methods to support multiple instrument files.""" + from pysatMissions.instruments.methods import orbits __all__ = ['orbits'] diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index f33f2d9e..84cad0d2 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -1,3 +1,5 @@ +"""Methods to convert orbital information for propagators.""" + import numpy as np import warnings @@ -15,8 +17,7 @@ def _check_orbital_params(kwargs=None): elements = list(kwargs['load'].keys()) - keplerians = ['alt_periapsis', 'alt_apoapsis', 'inclination', 'bstar', - 'arg_periapsis', 'raan', 'mean_anomaly'] + keplerians = ['alt_periapsis', 'inclination'] tles = ['TLE1', 'TLE2'] errmsg = 'Insufficient kwargs. Kwarg group requires {:}' for group in [tles, keplerians]: @@ -44,12 +45,12 @@ def _get_constants(planet='Earth'): radius : float (km) The average radius to the surface of a planet. mass : float (kg) - The avergae mass of the planet. + The average mass of the planet. gravity : float (m**3 kg / s**2) Newton's gravitational constant """ - radius = {'Earth': 6371} + radius = {'Earth': 6371.2} mass = {'Earth': 5.9742e24} gravity = 6.6743e-11 From 8237bda0d42b844391f10da915598f4633ccec9e Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 14:58:21 -0400 Subject: [PATCH 062/147] STY: new standards --- pysatMissions/instruments/missions_sgp4.py | 12 ++++++------ pysatMissions/tests/test_inst_methods_orbits.py | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 007bc662..62981d1e 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -23,7 +23,7 @@ from pysat.instruments.methods import testing as ps_meth from pysatMissions.instruments import _core as mcore from pysatMissions.instruments.methods import orbits -from sgp4.api import jday, Satrec, SGP4_ERRORS, WGS72 +from sgp4.api import api as sapi logger = pysat.logger @@ -162,21 +162,21 @@ def load(fnames, tag=None, inst_id=None, freq=cadence) # Calculate epoch for orbital propagator epoch = (dates[0] - dt.datetime(1949, 12, 31)).days - jd, _ = jday(dates[0].year, dates[0].month, dates[0].day, 0, 0, 0) + jd, _ = sapi.jday(dates[0].year, dates[0].month, dates[0].day, 0, 0, 0) if inclination is not None: # If an inclination is provided, specify by Keplerian elements eccentricity, mean_motion = orbits.convert_to_keplerian(alt_periapsis, alt_apoapsis) - satellite = Satrec() + satellite = sapi.Satrec() # according to module webpage, wgs72 is common - satellite.sgp4init(WGS72, 'i', 0, epoch, bstar, 0, 0, + satellite.sgp4init(sapi.WGS72, 'i', 0, epoch, bstar, 0, 0, eccentricity, np.radians(arg_periapsis), np.radians(inclination), np.radians(mean_anomaly), mean_motion, np.radians(raan)) else: # Otherwise, use TLEs - satellite = Satrec.twoline2rv(line1, line2, WGS72) + satellite = sapi.Satrec.twoline2rv(line1, line2, sapi.WGS72) jd = jd * np.ones(len(times)) fr = times / 86400. @@ -186,7 +186,7 @@ def load(fnames, tag=None, inst_id=None, # Check all propagated values for errors in propagation for i in range(1, 7): if np.any(err_code == i): - raise ValueError(SGP4_ERRORS[i]) + raise ValueError(sapi.SGP4_ERRORS[i]) # Put data into DataFrame data = pds.DataFrame({'position_eci_x': position[:, 0], diff --git a/pysatMissions/tests/test_inst_methods_orbits.py b/pysatMissions/tests/test_inst_methods_orbits.py index 44cbbf1f..129c8a8b 100644 --- a/pysatMissions/tests/test_inst_methods_orbits.py +++ b/pysatMissions/tests/test_inst_methods_orbits.py @@ -1,17 +1,17 @@ """Unit tests for `pysatMissions.instruments.methods.orbits`.""" -import pytest import pysatMissions.instruments.methods.orbits as mm_orbits +import pytest -class TestBasics(): +class TestBasics(object): """Unit tests for conversion to/from Keplerian elements.""" def setup(self): """Create a clean testing setup before each method.""" self.orbit = {'inclination': 13, 'apogee': 850, 'perigee': 400, - 'eccentricity': 0.032161234991424, - 'mean_motion': 0.0647469462135} + 'eccentricity': 0.032160315599897085, + 'mean_motion': 0.06474416985702029} return def teardown(self): From f26d346b44d9ef1e3233a5601e04907077884901 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 15:01:38 -0400 Subject: [PATCH 063/147] BUG: typo --- pysatMissions/instruments/missions_sgp4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 62981d1e..143f8ad8 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -23,7 +23,7 @@ from pysat.instruments.methods import testing as ps_meth from pysatMissions.instruments import _core as mcore from pysatMissions.instruments.methods import orbits -from sgp4.api import api as sapi +from sgp4 import api as sapi logger = pysat.logger From 4fbae33fe1bbf7d4d50929933ccaa102ea813267 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 15:03:57 -0400 Subject: [PATCH 064/147] BUG: changing tests --- pysatMissions/tests/test_instruments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index d7494768..23da5ab0 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -129,7 +129,7 @@ def test_sgp4_options(self, kw_dict): @pytest.mark.parametrize( "kw_dict", - [{'inclination': 13, 'alt_periapsis': 400, 'alt_apoapsis': 850}, + [{'inclination': 13, 'alt_apoapsis': 850}, {'TLE1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998'} ]) def test_sgp4_options_errors(self, kw_dict): From bf1404ff7e9744c2664dac1536a9493e610bd759 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 11 Aug 2021 15:10:25 -0400 Subject: [PATCH 065/147] BUG: wrong variable name --- pysatMissions/instruments/missions_sgp4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 02522a16..60d96f5c 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -183,7 +183,7 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, else: # Otherwise, use TLEs satellite = sapi.Satrec.twoline2rv(line1, line2, sapi.WGS72) - mean_motion = satellite.mean_motion + mean_motion = satellite.mm if one_orbit: ind = times <= (2 * np.pi / mean_motion * 60) From c6c5503b4635342eb0be6bb7a3c656ff2119d5c5 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 13 Aug 2021 16:07:41 -0400 Subject: [PATCH 066/147] STY: import order --- pysatMissions/instruments/missions_sgp4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 60d96f5c..a9edf275 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -24,8 +24,8 @@ from pysatMissions.instruments import _core as mcore from pysatMissions.instruments.methods import orbits -from geospacepy import terrestrial_spherical as conv_sph from geospacepy import terrestrial_ellipsoidal as conv_ell +from geospacepy import terrestrial_spherical as conv_sph from sgp4 import api as sapi logger = pysat.logger From 06607cde29dbbf1692595d85b21707650d347ce3 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 1 Sep 2021 12:21:59 -0400 Subject: [PATCH 067/147] TST: adjust codeclimate --- .codeclimate.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 70344671..fd9932a8 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -2,8 +2,6 @@ plugins: radon: enabled: true - pep8: - enabled: true sonar-python: enabled: true ratings: @@ -11,7 +9,6 @@ ratings: - "**.py" exclude_paths: - ".github/**/*" - - "pysatMissions/tests/**/*" - "docs/**/*" - "setup.py" - ".*" From d099aa941de9c72f84134720bf07ac3a3edbc262 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 1 Sep 2021 13:00:05 -0400 Subject: [PATCH 068/147] STY: streamline tests --- pysatMissions/tests/test_methods_magcoord.py | 56 ++++++++++--------- .../tests/test_methods_spacecraft.py | 55 ++++++++---------- 2 files changed, 53 insertions(+), 58 deletions(-) diff --git a/pysatMissions/tests/test_methods_magcoord.py b/pysatMissions/tests/test_methods_magcoord.py index 142ea8eb..421c7000 100644 --- a/pysatMissions/tests/test_methods_magcoord.py +++ b/pysatMissions/tests/test_methods_magcoord.py @@ -3,6 +3,8 @@ import datetime as dt import numpy as np +import pytest + import pysat import pysatMissions.methods.magcoord as mm_magcoord @@ -12,43 +14,43 @@ class TestBasics(object): def setup(self): """Create a clean testing setup before each method.""" + self.testInst = pysat.Instrument(platform='pysat', name='testing', num_samples=100, clean_level='clean') + self.kwargs = {'glat_label': 'latitude', + 'glong_label': 'longitude', + 'alt_label': 'altitude'} + self.reftime = dt.datetime(2009, 1, 1) return def teardown(self): """Clean up test environment after each method.""" - del self + + del self.testInst, self.kwargs, self.reftime return - def test_add_aacgm_coordinates(self): - """Test adding thermal plasma data to test inst.""" - self.testInst.custom_attach(mm_magcoord.add_aacgm_coordinates, - kwargs={'glat_label': 'latitude', - 'glong_label': 'longitude', - 'alt_label': 'altitude'}) - self.testInst.load(date=dt.datetime(2009, 1, 1)) - targets = ['aacgm_lat', 'aacgm_long', 'aacgm_mlt'] + def eval_targets(self, targets): + """Evaluate addition of new data targets to instrument.""" + for target in targets: - # Check if data is added - assert target in self.testInst.data.keys() - assert not np.isnan(self.testInst[target]).any() - # Check if metadata is added - assert target in self.testInst.meta.data.index + assert target in self.testInst.data.keys(), \ + "{:s} not found in data".format(target) + assert not np.isnan(self.testInst[target]).any(), \ + "NaN values found in {:s}".format(target) + assert target in self.testInst.meta.data.index, \ + "{:s} not found in metadata".format(target) return - def test_add_quasi_dipole_coordinates(self): + @pytest.mark.parametrize("func,targets", + [('add_aacgm_coordinates', + ['aacgm_lat', 'aacgm_long', 'aacgm_mlt']), + ('add_quasi_dipole_coordinates', + ['qd_lat', 'qd_long', 'mlt'])]) + def test_add_coordinates(self, func, targets): """Test adding thermal plasma data to test inst.""" - self.testInst.custom_attach(mm_magcoord.add_quasi_dipole_coordinates, - kwargs={'glat_label': 'latitude', - 'glong_label': 'longitude', - 'alt_label': 'altitude'}) - self.testInst.load(date=dt.datetime(2009, 1, 1)) - targets = ['qd_lat', 'qd_long', 'mlt'] - for target in targets: - # Check if data is added - assert target in self.testInst.data.keys() - assert not np.isnan(self.testInst[target]).any() - # Check if metadata is added - assert target in self.testInst.meta.data.index + + self.testInst.custom_attach(getattr(mm_magcoord, func), + kwargs=self.kwargs) + self.testInst.load(date=self.reftime) + self.eval_targets(targets) return diff --git a/pysatMissions/tests/test_methods_spacecraft.py b/pysatMissions/tests/test_methods_spacecraft.py index 21a67e6d..37ed5eaf 100644 --- a/pysatMissions/tests/test_methods_spacecraft.py +++ b/pysatMissions/tests/test_methods_spacecraft.py @@ -40,29 +40,38 @@ def setup(self): self.testInst = pysat.Instrument(platform='pysat', name='testing', num_samples=9, clean_level='clean') self.testInst.custom_attach(add_eci) + self.reftime = dt.datetime(2009, 1, 1) return def teardown(self): """Clean up test environment after tests.""" - del self + del self.testInst, self.reftime + return + + def eval_targets(self, targets): + """Evaluate addition of new data targets to instrument.""" + + for target in targets: + assert target in self.testInst.data.keys(), \ + "{:s} not found in data".format(target) + assert not np.isnan(self.testInst[target][1:-1]).any(), \ + "NaN values found in {:s}".format(target) + assert np.isnan(self.testInst[target][0]), \ + "First value of {:s} should be NaN".format(target) + assert np.isnan(self.testInst[target][-1]), \ + "Last value of {:s} should be NaN".format(target) + assert target in self.testInst.meta.data.index, \ + "{:s} not found in metadata".format(target) return def test_calculate_ecef_velocity(self): """Test `calculate_ecef_velocity` helper function.""" self.testInst.custom_attach(mm_sc.calculate_ecef_velocity) - self.testInst.load(date=dt.datetime(2009, 1, 1)) + self.testInst.load(date=self.reftime) targets = ['velocity_ecef_x', 'velocity_ecef_y', 'velocity_ecef_z'] - for target in targets: - # Check if data is added - assert target in self.testInst.data.keys() - assert not np.isnan(self.testInst[target][1:-1]).any() - # Endpoints should be NaN - assert np.isnan(self.testInst[target][0]) - assert np.isnan(self.testInst[target][-1]) - # Check if metadata is added - assert target in self.testInst.meta.data.index + self.eval_targets(targets) return def test_add_ram_pointing_sc_attitude_vectors(self): @@ -71,19 +80,11 @@ def test_add_ram_pointing_sc_attitude_vectors(self): # TODO(#64): check if calculations are correct self.testInst.custom_attach(mm_sc.calculate_ecef_velocity) self.testInst.custom_attach(mm_sc.add_ram_pointing_sc_attitude_vectors) - self.testInst.load(date=dt.datetime(2009, 1, 1)) + self.testInst.load(date=self.reftime) targets = ['sc_xhat_ecef_x', 'sc_xhat_ecef_y', 'sc_xhat_ecef_z', 'sc_yhat_ecef_x', 'sc_yhat_ecef_y', 'sc_yhat_ecef_z', 'sc_zhat_ecef_x', 'sc_zhat_ecef_y', 'sc_zhat_ecef_z'] - for target in targets: - # Check if data is added - assert target in self.testInst.data.keys() - assert not np.isnan(self.testInst[target][1:-1]).any() - # Endpoints should be NaN - assert np.isnan(self.testInst[target][0]) - assert np.isnan(self.testInst[target][-1]) - # Check if metadata is added - assert target in self.testInst.meta.data.index + self.eval_targets(targets) return def test_project_ecef_vector_onto_sc(self): @@ -95,15 +96,7 @@ def test_project_ecef_vector_onto_sc(self): self.testInst.custom_attach(add_fake_data) self.testInst.custom_attach(mm_sc.project_ecef_vector_onto_sc, args=['ax', 'ay', 'az', 'bx', 'by', 'bz']) - self.testInst.load(date=dt.datetime(2009, 1, 1)) + self.testInst.load(date=self.reftime) targets = ['bx', 'by', 'bz'] - for target in targets: - # Check if data is added - assert target in self.testInst.data.keys() - assert not np.isnan(self.testInst[target][1:-1]).any() - # Endpoints should be NaN - assert np.isnan(self.testInst[target][0]) - assert np.isnan(self.testInst[target][-1]) - # Check if metadata is added - assert target in self.testInst.meta.data.index + self.eval_targets(targets) return From acebfa847682b152437d49e9c9a8ae5ffc1570d9 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 1 Sep 2021 13:07:32 -0400 Subject: [PATCH 069/147] STY: simplify methods --- pysatMissions/instruments/methods/orbits.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 84cad0d2..12e8e20c 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -21,9 +21,10 @@ def _check_orbital_params(kwargs=None): tles = ['TLE1', 'TLE2'] errmsg = 'Insufficient kwargs. Kwarg group requires {:}' for group in [tles, keplerians]: - if any(v in elements for v in group): - if not all(v in elements for v in group): - raise KeyError(errmsg.format(', '.join(group))) + bools = [v in elements for v in group] + # Check if group is incomplete. + if any(bools) and not all(bools): + raise KeyError(errmsg.format(', '.join(group))) if all(v in elements for v in tles) and all(v in elements for v in keplerians): warnings.warn(' '.join(['Cannot use both Keplerians and TLEs.', 'Defaulting to Keplerians.'])) From 41bd2a9cdf527bee2063faf629aa789c0ab001d3 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 1 Sep 2021 13:13:30 -0400 Subject: [PATCH 070/147] STY: reduce duplication --- pysatMissions/tests/test_inst_methods_orbits.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/pysatMissions/tests/test_inst_methods_orbits.py b/pysatMissions/tests/test_inst_methods_orbits.py index 129c8a8b..df33f17a 100644 --- a/pysatMissions/tests/test_inst_methods_orbits.py +++ b/pysatMissions/tests/test_inst_methods_orbits.py @@ -9,6 +9,7 @@ class TestBasics(object): def setup(self): """Create a clean testing setup before each method.""" + self.orbit = {'inclination': 13, 'apogee': 850, 'perigee': 400, 'eccentricity': 0.032160315599897085, 'mean_motion': 0.06474416985702029} @@ -16,11 +17,19 @@ def setup(self): def teardown(self): """Clean up test environment after each method.""" + del self.orbit return + def eval_output(self, value, label): + """Evaluate output value from calculations.""" + + assert abs(value - self.orbit[label]) / value < 1.e-6 + return + def test_convert_wrong_planet(self): """Test conversion routines with an unsupported planet.""" + with pytest.raises(KeyError) as kerr: mm_orbits.convert_to_keplerian(self.orbit['perigee'], self.orbit['apogee'], 'Hwae') @@ -29,16 +38,20 @@ def test_convert_wrong_planet(self): def test_convert_to_keplerian(self): """Test conversion to keplerian elements.""" + ecc, mm, = mm_orbits.convert_to_keplerian(self.orbit['perigee'], self.orbit['apogee'],) - assert abs(ecc - self.orbit['eccentricity']) / ecc < 1.e-6 - assert abs(mm - self.orbit['mean_motion']) / mm < 1.e-6 + self.eval_output(ecc, 'eccentricity') + self.eval_output(mm, 'mean_motion') return def test_convert_from_keplerian(self): """Test conversion from keplerian elements.""" + per, apo, = mm_orbits.convert_from_keplerian(self.orbit['eccentricity'], self.orbit['mean_motion'],) assert abs(per - self.orbit['perigee']) / per < 1.e-6 assert abs(apo - self.orbit['apogee']) / apo < 1.e-6 + self.eval_output(per, 'perigee') + self.eval_output(apo, 'apogee') return From 6f736f86900d957c77f49353783b8d93e7c45763 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 1 Sep 2021 13:17:49 -0400 Subject: [PATCH 071/147] STY: remove duplicate code --- pysatMissions/tests/test_inst_methods_orbits.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pysatMissions/tests/test_inst_methods_orbits.py b/pysatMissions/tests/test_inst_methods_orbits.py index df33f17a..5e223d3a 100644 --- a/pysatMissions/tests/test_inst_methods_orbits.py +++ b/pysatMissions/tests/test_inst_methods_orbits.py @@ -50,8 +50,6 @@ def test_convert_from_keplerian(self): per, apo, = mm_orbits.convert_from_keplerian(self.orbit['eccentricity'], self.orbit['mean_motion'],) - assert abs(per - self.orbit['perigee']) / per < 1.e-6 - assert abs(apo - self.orbit['apogee']) / apo < 1.e-6 self.eval_output(per, 'perigee') self.eval_output(apo, 'apogee') return From c755f62b4edf8dca3b5fdc245a8800ffda517487 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 1 Sep 2021 13:23:33 -0400 Subject: [PATCH 072/147] DOC: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a342a3d..a5d61cb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Improve docstrings throughout * Testing * Add style check for docstrings + * Improve checks in codeclimate ## [0.2.2] - 2021-06-18 * Migrate pyglow interface to pysatIncubator From 7c0f6f048c31e9d1b2d6aa0c1c7e2b718988d894 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 1 Sep 2021 13:41:15 -0400 Subject: [PATCH 073/147] STY: simplify error handling --- pysatMissions/instruments/missions_sgp4.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 143f8ad8..e2259b7b 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -184,9 +184,10 @@ def load(fnames, tag=None, inst_id=None, err_code, position, velocity = satellite.sgp4_array(jd, fr) # Check all propagated values for errors in propagation - for i in range(1, 7): - if np.any(err_code == i): - raise ValueError(sapi.SGP4_ERRORS[i]) + errors = np.unique(err_code[err_code > 0]) + if len(errors) > 0: + # Raise highest priority error. + raise ValueError(sapi.SGP4_ERRORS[errors[0]]) # Put data into DataFrame data = pds.DataFrame({'position_eci_x': position[:, 0], From 5db9b7774d9722a1846d4fbf32ab11592f1b7fe5 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 1 Sep 2021 14:28:45 -0400 Subject: [PATCH 074/147] STY: remove unused code --- pysatMissions/tests/test_instruments.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index 23da5ab0..8c06855c 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -23,8 +23,6 @@ from pysat.utils import generate_instrument_list -saved_path = pysat.params['data_dirs'] - # Developers for instrument libraries should update the following line to # point to their own subpackage location # e.g., From ccae8b86d7e5f31fc657d53c88a8b45626c2db14 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 1 Sep 2021 14:33:09 -0400 Subject: [PATCH 075/147] STY: remove endpoint test --- pysatMissions/tests/test_methods_spacecraft.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pysatMissions/tests/test_methods_spacecraft.py b/pysatMissions/tests/test_methods_spacecraft.py index 37ed5eaf..3a29ba8d 100644 --- a/pysatMissions/tests/test_methods_spacecraft.py +++ b/pysatMissions/tests/test_methods_spacecraft.py @@ -55,12 +55,9 @@ def eval_targets(self, targets): for target in targets: assert target in self.testInst.data.keys(), \ "{:s} not found in data".format(target) + # By default, endpoints will be NaNs. Ignore these. assert not np.isnan(self.testInst[target][1:-1]).any(), \ "NaN values found in {:s}".format(target) - assert np.isnan(self.testInst[target][0]), \ - "First value of {:s} should be NaN".format(target) - assert np.isnan(self.testInst[target][-1]), \ - "Last value of {:s} should be NaN".format(target) assert target in self.testInst.meta.data.index, \ "{:s} not found in metadata".format(target) return From b78117b5fa37e23a11952b985db238b978198715 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 29 Oct 2021 15:34:56 -0400 Subject: [PATCH 076/147] DOC: update docstrings --- pysatMissions/instruments/missions_sgp4.py | 35 ++++++++++++++-------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index a9edf275..454f7cbb 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -89,42 +89,51 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, specifies the number of seconds to simulate the satellite) (default='') TLE1 : string - First string for Two Line Element. Must be in TLE format + First string for Two Line Element. Must be in TLE format. TLE1 and TLE2 + both required if instantiating instrument by TLEs. (defalt=None) TLE2 : string - Second string for Two Line Element. Must be in TLE format + Second string for Two Line Element. Must be in TLE format. TLE1 and TLE2 + both required if instantiating instrument by TLEs. (defalt=None) alt_periapsis : float - The lowest altitude from the mean planet surface along the orbit (km) + The lowest altitude from the mean planet surface along the orbit (km). + Required along with inclination if instantiating via orbital elements. + (defalt=None) alt_apoapsis : float or NoneType The highest altitude from the mean planet surface along the orbit (km) - If None, assumed to be equal to periapsis. (default=None) + If None, assumed to be equal to periapsis (ie, circular orbit). Optional + when instantiating via orbital elements. (default=None) inclination : float - Orbital Inclination in degrees (default=None) + Orbital Inclination in degrees. Required along with alt_periapsis if + instantiating via orbital elements. (default=None) raan : float Right Ascension of the Ascending Node (RAAN) in degrees. This defines the orientation of the orbital plane to the generalized reference frame. The Ascending Node is the point in the orbit where the spacecraft passes through the plane of reference moving northward. For Earth orbits, the location of the RAAN is defined as the angle eastward of the First Point - of Aries. - (default=None) + of Aries. Optional when instantiating via orbital elements. + (default=0.) arg_periapsis : float Argument of Periapsis in degrees. This defines the orientation of the ellipse in the orbital plane, as an angle measured from the ascending - node to the periapsis (default=None) + node to the periapsis. Optional when instantiating via orbital elements. + (default=0.) mean_anomaly : float The fraction of an elliptical orbit's period that has elapsed since the orbiting body passed periapsis. Note that this is a "fictitious angle" (input in degrees) which defines the location of the spacecraft in the - orbital plane based on the orbital period. - (default=None) + orbital plane based on the orbital period. Optional when instantiating + via orbital elements. + (default=0.) bstar : float Inverse of the ballistic coefficient. Used to model satellite drag. - Measured in inverse distance (1 / earth radius). (default=None) + Measured in inverse distance (1 / earth radius). Optional when + instantiating via orbital elements. (default=0.) one_orbit : bool Flag to override num_samples and only provide a single orbit. (default=False) num_samples : int - Number of samples per day + Number of samples per day. (default=None) cadence : str Uses pandas.frequency string formatting ('1S', etc) (default='1S') @@ -229,7 +238,7 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, 'mean_altitude': rad - 6371.2, 'geod_latitude': geod_lat, 'geod_longitude': geod_lon, - 'geod_altitude': geod_alt / 1000.}, # Convert altitude to km + 'geod_altitude': geod_alt / 1000.}, # Convert to km index=index) data.index.name = 'Epoch' From e30e101f7becf68e0f6f91522ebeb0861dd6e013 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 29 Oct 2021 15:40:15 -0400 Subject: [PATCH 077/147] TST: test for options --- pysatMissions/tests/test_instruments.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index 23da5ab0..1a023207 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -109,7 +109,8 @@ def test_inst_cadence(self, inst_dict, kwarg, output): @pytest.mark.parametrize( "kw_dict", - [{'inclination': 13, 'alt_periapsis': 400, 'alt_apoapsis': 850, + [{'one_orbit': True}, + {'inclination': 13, 'alt_periapsis': 400, 'alt_apoapsis': 850, 'bstar': 0, 'arg_periapsis': 0., 'raan': 0., 'mean_anomaly': 0.}, {'TLE1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998', 'TLE2': '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452'} From cf120f28b1df23e6dcd3cd83f162dbffe9e34d9e Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 09:19:19 -0600 Subject: [PATCH 078/147] Update pysatMissions/tests/test_methods_magcoord.py --- pysatMissions/tests/test_methods_magcoord.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pysatMissions/tests/test_methods_magcoord.py b/pysatMissions/tests/test_methods_magcoord.py index 421c7000..ab444fac 100644 --- a/pysatMissions/tests/test_methods_magcoord.py +++ b/pysatMissions/tests/test_methods_magcoord.py @@ -3,6 +3,7 @@ import datetime as dt import numpy as np + import pytest import pysat From 62110ad5b5d0ba184c62645d17473c6eb5ce3bfe Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 11:01:30 -0500 Subject: [PATCH 079/147] DEP: deprecate missions_ephem --- pysatMissions/instruments/missions_ephem.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pysatMissions/instruments/missions_ephem.py b/pysatMissions/instruments/missions_ephem.py index 6264baf6..0b1a31cd 100644 --- a/pysatMissions/instruments/missions_ephem.py +++ b/pysatMissions/instruments/missions_ephem.py @@ -1,6 +1,12 @@ # -*- coding: utf-8 -*- """Produce satellite orbit data. +.. deprecated:: 0.3.0 + pyephem is no longer updated, and the code maintainers suggest skyfield + as a replacement. The functionality of the instrument will be replaced by + the new `missions_sgp4` instrument. `missions_ephem` will be removed in + versions 0.4.0+ + Orbit is simulated using Two Line Elements (TLEs) and ephem. Satellite position is coupled to several space science models to simulate the atmosphere the satellite is in. @@ -21,6 +27,7 @@ import datetime as dt import functools import numpy as np +import warnings import ephem import OMMBV @@ -62,6 +69,11 @@ def init(self): self.references = 'Please contact the pyephem project for references' logger.info(self.acknowledgements) + warnings.warn(' '.join(("`missions_ephem` has been deprecated and will be", + "removed in pysatMissions 0.4.0+.", + "Use `missions_sgp4` instead.")), + DeprecationWarning, stacklevel=2) + return From 5450fc2de1b39601ee34b238efd7bf221a95211c Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 11:01:49 -0500 Subject: [PATCH 080/147] TST: test DeprecationWarning --- pysatMissions/tests/test_deprecation.py | 50 +++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 pysatMissions/tests/test_deprecation.py diff --git a/pysatMissions/tests/test_deprecation.py b/pysatMissions/tests/test_deprecation.py new file mode 100644 index 00000000..74d060f5 --- /dev/null +++ b/pysatMissions/tests/test_deprecation.py @@ -0,0 +1,50 @@ +"""Unit tests for deprecated methods an objects in pysatMissions.""" + +import warnings + +import pysat +from pysatMissions.instruments import missions_ephem + + +class TestDeprecation(object): + """Unit tests for deprecations.""" + + def setup(self): + """Create a clean testing setup before each method.""" + + warnings.simplefilter("always", DeprecationWarning) + return + + def teardown(self): + """Clean up test environment after each method.""" + return + + def eval_deprecation(self, warns, check_msgs): + """Evaluate whether message is contained in DeprecationWarning. + + Parameters + ---------- + warns : list + List of warnings.WarningMessage objects + check_msgs : list + List of strings containing the expected warning messages + + """ + + # Ensure the minimum number of warnings were raised + assert len(warns) >= len(check_msgs) + + # Test the warning messages, ensuring each attribute is present + pysat.utils.testing.eval_warnings(warns, check_msgs) + return + + def test_ephem_deprecation(self): + """Test that instatiating missions_ephem will give DeprecationWarning.""" + + with warnings.catch_warnings(record=True) as war: + pysat.Instrument(inst_module=missions_ephem) + + warn_msgs = ["`missions_ephem` has been deprecated"] + + self.eval_deprecation(war, warn_msgs) + return From 413d4498c0fb2fdb49feab9a8f7e415c1dab9e4f Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 11:02:21 -0500 Subject: [PATCH 081/147] DOC: update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14a549d6..4357a8c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Improve metadata generation in missions_sgp4 * Documentation * Improve docstrings throughout +* Deprecations + * Deprecated missions_ephem, as pyephem will no longer be updated * Testing * Add style check for docstrings From 3e250e4529215318156517c57946d14e5b7b1e6a Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 11:11:32 -0500 Subject: [PATCH 082/147] BUG: copy function from unreleased pysat --- pysatMissions/tests/test_deprecation.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/pysatMissions/tests/test_deprecation.py b/pysatMissions/tests/test_deprecation.py index 74d060f5..62c0a452 100644 --- a/pysatMissions/tests/test_deprecation.py +++ b/pysatMissions/tests/test_deprecation.py @@ -1,5 +1,6 @@ """Unit tests for deprecated methods an objects in pysatMissions.""" +import numpy as np import warnings import pysat @@ -19,7 +20,7 @@ def teardown(self): """Clean up test environment after each method.""" return - def eval_deprecation(self, warns, check_msgs): + def eval_deprecation(self, warns, check_msgs, warn_type=DeprecationWarning): """Evaluate whether message is contained in DeprecationWarning. Parameters @@ -28,14 +29,27 @@ def eval_deprecation(self, warns, check_msgs): List of warnings.WarningMessage objects check_msgs : list List of strings containing the expected warning messages + warn_type : type + Type for the warning messages (default=DeprecationWarning) """ # Ensure the minimum number of warnings were raised assert len(warns) >= len(check_msgs) + # Initialize the output + found_msgs = [False for msg in check_msgs] + # Test the warning messages, ensuring each attribute is present - pysat.utils.testing.eval_warnings(warns, check_msgs) + for iwar in warns: + for i, msg in enumerate(check_msgs): + if str(iwar.message).find(msg) >= 0: + assert iwar.category == warn_type, \ + "bad warning type for message: {:}".format(msg) + found_msgs[i] = True + + assert np.all(found_msgs), "did not find {:d} expected {:}".format( + len(found_msgs) - np.sum(found_msgs), repr(warn_type)) return def test_ephem_deprecation(self): From 88a2c7ea80c29c6ca7f39c7c84923934922d5187 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 13:21:42 -0500 Subject: [PATCH 083/147] BUG: use consistent epoch --- pysatMissions/instruments/missions_sgp4.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 454f7cbb..cb2973cc 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -61,6 +61,9 @@ def init(self): 'August 21–24.')) logger.info(self.acknowledgements) + if 'epoch' not in self.kwargs['load'].keys(): + self.kwargs['load']['epoch'] = self.files.files.index[0] + return @@ -71,7 +74,7 @@ def init(self): def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, alt_periapsis=None, alt_apoapsis=None, inclination=None, raan=0., arg_periapsis=0., mean_anomaly=0., - bstar=0., one_orbit=False, num_samples=None, cadence='1S'): + epoch=None, bstar=0., one_orbit=False, num_samples=None, cadence='1S'): """Generate position of satellite in ECI co-ordinates. Note @@ -125,6 +128,10 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, orbital plane based on the orbital period. Optional when instantiating via orbital elements. (default=0.) + epoch : dt.datetime or NoneType + The epoch used for calculating orbital propagation from Keplerians. + If None, then use the first date in the file list for consistency across + multiple days. Note that this will be set at init. (default=None) bstar : float Inverse of the ballistic coefficient. Used to model satellite drag. Measured in inverse distance (1 / earth radius). Optional when @@ -176,7 +183,7 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, times, index, dates = ps_meth.generate_times(fnames, num_samples, freq=cadence) # Calculate epoch for orbital propagator - epoch = (dates[0] - dt.datetime(1949, 12, 31)).days + epoch_days = (epoch - dt.datetime(1949, 12, 31)).days jd, _ = sapi.jday(dates[0].year, dates[0].month, dates[0].day, 0, 0, 0) if inclination is not None: @@ -185,7 +192,7 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, alt_apoapsis) satellite = sapi.Satrec() # according to module webpage, wgs72 is common - satellite.sgp4init(sapi.WGS72, 'i', 0, epoch, bstar, 0, 0, + satellite.sgp4init(sapi.WGS72, 'i', 0, epoch_days, bstar, 0, 0, eccentricity, np.radians(arg_periapsis), np.radians(inclination), np.radians(mean_anomaly), mean_motion, np.radians(raan)) From 6655f4257186a86161fe8142079f7cd4fe3bf513 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 13:21:59 -0500 Subject: [PATCH 084/147] TST: test for consistency between days --- pysatMissions/tests/test_instruments.py | 33 +++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index 1a023207..3b5fd3d2 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -90,6 +90,39 @@ def teardown_class(self): # Custom package unit tests can be added here + @pytest.mark.parametrize("kwargs", [{}, {'epoch': dt.datetime(2019, 1, 1)}]) + def test_sgp4_data_continuity(self, kwargs): + """Test that data is continuous for sequential days. + + Parameters + ---------- + kwargs : dict + Optional kwargs to pass through. + """ + + # Define sat with custom Keplerian inputs + sat = pysat.Instrument('missions', 'sgp4', inclination=20, + alt_periapsis=400, **kwargs) + + # Get last 10 points of day 1 + sat.load(2018, 1) + day1 = sat.data[-10:] + + # Get first 10 points of day 2 + sat.load(2018, 2) + day2 = sat.data[:10] + + average_gradient = day1.diff().mean() + std_gradient = day1.diff().std() + gradient_between_days = day2.iloc[0] - day1.iloc[-1] + + # Check that the jump between days is within 3 sigma of average gradient + for key in average_gradient.keys(): + del_g = np.abs(average_gradient[key] - gradient_between_days[key]) + assert del_g < 3. * std_gradient[key] + + return + @pytest.mark.parametrize("inst_dict", [x for x in instruments['download']]) @pytest.mark.parametrize("kwarg,output", [(None, 1), ('10s', 10)]) def test_inst_cadence(self, inst_dict, kwarg, output): From 6b62c1bc83fdf0094d648e386af169e9ff70a53a Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 14:20:54 -0500 Subject: [PATCH 085/147] TST: add parametrize --- pysatMissions/tests/test_instruments.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index 3b5fd3d2..d5186a1b 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -90,7 +90,12 @@ def teardown_class(self): # Custom package unit tests can be added here - @pytest.mark.parametrize("kwargs", [{}, {'epoch': dt.datetime(2019, 1, 1)}]) + @pytest.mark.parametrize("kwargs", + [{}, + {'inclination': 20, 'alt_periapsis': 400}, + {'inclination': 80, 'alt_periapsis': 500, + 'alt_apoapsis': 600, + 'epoch': dt.datetime(2019, 1, 1)}]) def test_sgp4_data_continuity(self, kwargs): """Test that data is continuous for sequential days. @@ -101,8 +106,9 @@ def test_sgp4_data_continuity(self, kwargs): """ # Define sat with custom Keplerian inputs - sat = pysat.Instrument('missions', 'sgp4', inclination=20, - alt_periapsis=400, **kwargs) + sat = pysat.Instrument( + inst_module=pysatMissions.instruments.missions_sgp4, + **kwargs) # Get last 10 points of day 1 sat.load(2018, 1) From 7af5d655f8a90df5e6232b25844e76ec57f5db3f Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 15:06:57 -0500 Subject: [PATCH 086/147] STY: simplify --- pysatMissions/tests/test_instruments.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index d5186a1b..3894f242 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -123,9 +123,8 @@ def test_sgp4_data_continuity(self, kwargs): gradient_between_days = day2.iloc[0] - day1.iloc[-1] # Check that the jump between days is within 3 sigma of average gradient - for key in average_gradient.keys(): - del_g = np.abs(average_gradient[key] - gradient_between_days[key]) - assert del_g < 3. * std_gradient[key] + del_g = np.abs(average_gradient - gradient_between_days) + assert np.all(del_g < (3. * std_gradient)) return From f1a41c3c48cfb3fd3bfb34f99140f1a343b52ee6 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 15:11:58 -0500 Subject: [PATCH 087/147] TST: clean up workflow / nep29 --- .github/workflows/main.yml | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1da4db40..23023b57 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,8 +11,13 @@ jobs: strategy: fail-fast: false matrix: - python-version: [3.7, 3.8, 3.9] + python-version: ["3.9", "3.10"] os: [ubuntu-latest] + numpy_ver: ["latest"] + include: + - python-version: "3.8" + numpy_ver: "1.19" + os: ubuntu-latest name: Python ${{ matrix.python-version }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} @@ -22,13 +27,22 @@ jobs: uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies + + - name: Install requirements for testing setup run: | python -m pip install --upgrade pip pip install -r test_requirements.txt + + - name: Install dependencies + run: | pip install -r requirements.txt - # Manual install of OMMBV - pip install --no-binary :OMMBV: OMMBV + # Manual install of OMMBV required for 0.5.5 + pip install OMMBV + + - name: Install NEP29 dependencies + if: ${{ matrix.numpy_ver != 'latest'}} + run: | + pip install --no-binary :numpy: numpy==${{ matrix.numpy_ver }} - name: Set up pysat run: | From cb77eda1e0b498d3ad19006daf638ce388d47481 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 15:14:28 -0500 Subject: [PATCH 088/147] STY: update numpy test versions --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 23023b57..7afc92b2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,10 +16,10 @@ jobs: numpy_ver: ["latest"] include: - python-version: "3.8" - numpy_ver: "1.19" + numpy_ver: "1.20" os: ubuntu-latest - name: Python ${{ matrix.python-version }} on ${{ matrix.os }} + name: Python ${{ matrix.python-version }} on ${{ matrix.os }} with numpy ${{ matrix.numpy_ver }} runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v2 From 915dd26454404433b68c72f03c0928e39dbd903a Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 15:17:14 -0500 Subject: [PATCH 089/147] STY: numpy install order --- .github/workflows/main.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7afc92b2..1a90ddcf 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: numpy_ver: ["latest"] include: - python-version: "3.8" - numpy_ver: "1.20" + numpy_ver: "1.19" os: ubuntu-latest name: Python ${{ matrix.python-version }} on ${{ matrix.os }} with numpy ${{ matrix.numpy_ver }} @@ -33,17 +33,17 @@ jobs: python -m pip install --upgrade pip pip install -r test_requirements.txt + - name: Install NEP29 dependencies + if: ${{ matrix.numpy_ver != 'latest'}} + run: | + pip install --no-binary :numpy: numpy==${{ matrix.numpy_ver }} + - name: Install dependencies run: | pip install -r requirements.txt # Manual install of OMMBV required for 0.5.5 pip install OMMBV - - name: Install NEP29 dependencies - if: ${{ matrix.numpy_ver != 'latest'}} - run: | - pip install --no-binary :numpy: numpy==${{ matrix.numpy_ver }} - - name: Set up pysat run: | mkdir pysatData From 27fb149926683743909497169c16c3da235c23fb Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 15:21:36 -0500 Subject: [PATCH 090/147] MAINT: use numpy 1.20 --- .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 1a90ddcf..18b580af 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: numpy_ver: ["latest"] include: - python-version: "3.8" - numpy_ver: "1.19" + numpy_ver: "1.20" os: ubuntu-latest name: Python ${{ matrix.python-version }} on ${{ matrix.os }} with numpy ${{ matrix.numpy_ver }} From 638f36d5bd5e928b1ece331bcb33bbb0e4ccc37f Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 15:22:22 -0500 Subject: [PATCH 091/147] DOC: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14a549d6..bf93408a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Improve docstrings throughout * Testing * Add style check for docstrings + * Include support for testing against multiple versions of numpy ## [0.2.2] - 2021-06-18 * Migrate pyglow interface to pysatIncubator From e099ac99dbbe51c1b1a6d1f4f5546cb5f2ef9c25 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 23 Dec 2021 15:26:21 -0500 Subject: [PATCH 092/147] DOC: improve comments --- pysatMissions/tests/test_instruments.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index 3894f242..7c56fd38 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -102,7 +102,9 @@ def test_sgp4_data_continuity(self, kwargs): Parameters ---------- kwargs : dict - Optional kwargs to pass through. + Optional kwargs to pass through. If empty, instrument will be + default TLEs. + """ # Define sat with custom Keplerian inputs @@ -124,7 +126,8 @@ def test_sgp4_data_continuity(self, kwargs): # Check that the jump between days is within 3 sigma of average gradient del_g = np.abs(average_gradient - gradient_between_days) - assert np.all(del_g < (3. * std_gradient)) + assert np.all(del_g < (3. * std_gradient)), \ + "Gap between days outside of 3 sigma" return From 8e8bf2cb959878b533e283002afb2c14ec0004d4 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 3 Jan 2022 14:36:18 -0500 Subject: [PATCH 093/147] Update requirements.txt --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index a296180a..f295c8d3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,7 @@ aacgmv2 apexpy geospacepy numpy +OMMBV pandas pysat>=3.0 pyEphem From 27056a0e2f4216b58c42813d47a03e5a806db189 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 3 Jan 2022 14:37:09 -0500 Subject: [PATCH 094/147] Update main.yml --- .github/workflows/main.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 18b580af..ad7761f1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,8 +41,6 @@ jobs: - name: Install dependencies run: | pip install -r requirements.txt - # Manual install of OMMBV required for 0.5.5 - pip install OMMBV - name: Set up pysat run: | From c5ea38148afa66cd68ef0837073d78f3dadc4712 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 4 Jan 2022 18:31:48 -0500 Subject: [PATCH 095/147] STY: update function name --- pysatMissions/methods/spacecraft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index 7f77c664..82a0a21a 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -173,7 +173,7 @@ def project_ecef_vector_onto_sc(inst, x_label, y_label, z_label, # TODO(#65): add checks for existence of ecef labels in inst - x, y, z = OMMBV.project_ecef_vector_onto_basis( + x, y, z = OMMBV.project_ECEF_vector_onto_basis( inst[x_label], inst[y_label], inst[z_label], inst['sc_xhat_ecef_x'], inst['sc_xhat_ecef_y'], inst['sc_xhat_ecef_z'], inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'], From 80ec480057558a3a61a8e21973fb4405d37af8e9 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 4 Jan 2022 18:37:48 -0500 Subject: [PATCH 096/147] MAINT: update ommbv calls --- pysatMissions/methods/spacecraft.py | 44 ++++++++++++++--------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index 82a0a21a..17e77e95 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -38,9 +38,9 @@ def add_ram_pointing_sc_attitude_vectors(inst): # Ram pointing is along velocity vector inst['sc_xhat_ecef_x'], inst['sc_xhat_ecef_y'], inst['sc_xhat_ecef_z'] = \ - OMMBV.normalize_vector(inst['velocity_ecef_x'], - inst['velocity_ecef_y'], - inst['velocity_ecef_z']) + OMMBV.vector.normalize_vector(inst['velocity_ecef_x'], + inst['velocity_ecef_y'], + inst['velocity_ecef_z']) # Begin with z along Nadir (towards Earth) # if orbit isn't perfectly circular, then the s/c z vector won't @@ -48,35 +48,35 @@ def add_ram_pointing_sc_attitude_vectors(inst): # to the true z (in the orbital plane) that we can use it to get y, # and use x and y to get the real z inst['sc_zhat_ecef_x'], inst['sc_zhat_ecef_y'], inst['sc_zhat_ecef_z'] = \ - OMMBV.normalize_vector(-inst['position_ecef_x'], - -inst['position_ecef_y'], - -inst['position_ecef_z']) + OMMBV.vector.normalize_vector(-inst['position_ecef_x'], + -inst['position_ecef_y'], + -inst['position_ecef_z']) # get y vector assuming right hand rule # Z x X = Y inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'] = \ - OMMBV.cross_product(inst['sc_zhat_ecef_x'], - inst['sc_zhat_ecef_y'], - inst['sc_zhat_ecef_z'], - inst['sc_xhat_ecef_x'], - inst['sc_xhat_ecef_y'], - inst['sc_xhat_ecef_z']) + OMMBV.vector.cross_product(inst['sc_zhat_ecef_x'], + inst['sc_zhat_ecef_y'], + inst['sc_zhat_ecef_z'], + inst['sc_xhat_ecef_x'], + inst['sc_xhat_ecef_y'], + inst['sc_xhat_ecef_z']) # Normalize since Xhat and Zhat from above may not be orthogonal inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'] = \ - OMMBV.normalize_vector(inst['sc_yhat_ecef_x'], - inst['sc_yhat_ecef_y'], - inst['sc_yhat_ecef_z']) + OMMBV.vector.normalize_vector(inst['sc_yhat_ecef_x'], + inst['sc_yhat_ecef_y'], + inst['sc_yhat_ecef_z']) # Strictly, need to recalculate Zhat so that it is consistent with RHS # just created # Z = X x Y inst['sc_zhat_ecef_x'], inst['sc_zhat_ecef_y'], inst['sc_zhat_ecef_z'] = \ - OMMBV.cross_product(inst['sc_xhat_ecef_x'], - inst['sc_xhat_ecef_y'], - inst['sc_xhat_ecef_z'], - inst['sc_yhat_ecef_x'], - inst['sc_yhat_ecef_y'], - inst['sc_yhat_ecef_z']) + OMMBV.vector.cross_product(inst['sc_xhat_ecef_x'], + inst['sc_xhat_ecef_y'], + inst['sc_xhat_ecef_z'], + inst['sc_yhat_ecef_x'], + inst['sc_yhat_ecef_y'], + inst['sc_yhat_ecef_z']) # Adding metadata for v in ['x', 'y', 'z']: @@ -173,7 +173,7 @@ def project_ecef_vector_onto_sc(inst, x_label, y_label, z_label, # TODO(#65): add checks for existence of ecef labels in inst - x, y, z = OMMBV.project_ECEF_vector_onto_basis( + x, y, z = OMMBV.vector.project_ECEF_vector_onto_basis( inst[x_label], inst[y_label], inst[z_label], inst['sc_xhat_ecef_x'], inst['sc_xhat_ecef_y'], inst['sc_xhat_ecef_z'], inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'], From ad45a2540876056409fb4e18a684a11a35e82b44 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 4 Jan 2022 18:38:12 -0500 Subject: [PATCH 097/147] MAINT: version limit for OMMBV --- requirements.txt | 2 +- setup.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index f295c8d3..8afd879d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ aacgmv2 apexpy geospacepy numpy -OMMBV +OMMBV>=1.0 pandas pysat>=3.0 pyEphem diff --git a/setup.cfg b/setup.cfg index 2add97b2..aae1a689 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,7 +42,7 @@ install_requires = apexpy geospacepy numpy - OMMBV + OMMBV>1.0 pandas pysat>=3.0 pyEphem From e42cd37edbafcb1196fcf204de124e77f8ae39f1 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 4 Jan 2022 19:00:16 -0500 Subject: [PATCH 098/147] TST: manual install of apexpy --- .github/workflows/docs.yml | 2 ++ .github/workflows/main.yml | 2 ++ requirements.txt | 1 - 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9772e71a..c663654b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -27,6 +27,8 @@ jobs: python -m pip install --upgrade pip pip install -r requirements.txt pip install -r test_requirements.txt + # Manual install of apexpy + pip install --no-binary :apexpy: apexpy - name: Check documentation build run: sphinx-build -E -b html docs dist/docs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ad7761f1..ace1fffb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,6 +41,8 @@ jobs: - name: Install dependencies run: | pip install -r requirements.txt + # Manual install of apexpy + pip install --no-binary :apexpy: apexpy - name: Set up pysat run: | diff --git a/requirements.txt b/requirements.txt index 8afd879d..779989a9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ aacgmv2 -apexpy geospacepy numpy OMMBV>=1.0 From baffa2027317d9f91efce91227f0fe15ac7ad142 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 4 Jan 2022 19:06:56 -0500 Subject: [PATCH 099/147] BUG: deprecation ommbv --- pysatMissions/methods/spacecraft.py | 44 ++++++++++++++--------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index 17e77e95..82a0a21a 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -38,9 +38,9 @@ def add_ram_pointing_sc_attitude_vectors(inst): # Ram pointing is along velocity vector inst['sc_xhat_ecef_x'], inst['sc_xhat_ecef_y'], inst['sc_xhat_ecef_z'] = \ - OMMBV.vector.normalize_vector(inst['velocity_ecef_x'], - inst['velocity_ecef_y'], - inst['velocity_ecef_z']) + OMMBV.normalize_vector(inst['velocity_ecef_x'], + inst['velocity_ecef_y'], + inst['velocity_ecef_z']) # Begin with z along Nadir (towards Earth) # if orbit isn't perfectly circular, then the s/c z vector won't @@ -48,35 +48,35 @@ def add_ram_pointing_sc_attitude_vectors(inst): # to the true z (in the orbital plane) that we can use it to get y, # and use x and y to get the real z inst['sc_zhat_ecef_x'], inst['sc_zhat_ecef_y'], inst['sc_zhat_ecef_z'] = \ - OMMBV.vector.normalize_vector(-inst['position_ecef_x'], - -inst['position_ecef_y'], - -inst['position_ecef_z']) + OMMBV.normalize_vector(-inst['position_ecef_x'], + -inst['position_ecef_y'], + -inst['position_ecef_z']) # get y vector assuming right hand rule # Z x X = Y inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'] = \ - OMMBV.vector.cross_product(inst['sc_zhat_ecef_x'], - inst['sc_zhat_ecef_y'], - inst['sc_zhat_ecef_z'], - inst['sc_xhat_ecef_x'], - inst['sc_xhat_ecef_y'], - inst['sc_xhat_ecef_z']) + OMMBV.cross_product(inst['sc_zhat_ecef_x'], + inst['sc_zhat_ecef_y'], + inst['sc_zhat_ecef_z'], + inst['sc_xhat_ecef_x'], + inst['sc_xhat_ecef_y'], + inst['sc_xhat_ecef_z']) # Normalize since Xhat and Zhat from above may not be orthogonal inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'] = \ - OMMBV.vector.normalize_vector(inst['sc_yhat_ecef_x'], - inst['sc_yhat_ecef_y'], - inst['sc_yhat_ecef_z']) + OMMBV.normalize_vector(inst['sc_yhat_ecef_x'], + inst['sc_yhat_ecef_y'], + inst['sc_yhat_ecef_z']) # Strictly, need to recalculate Zhat so that it is consistent with RHS # just created # Z = X x Y inst['sc_zhat_ecef_x'], inst['sc_zhat_ecef_y'], inst['sc_zhat_ecef_z'] = \ - OMMBV.vector.cross_product(inst['sc_xhat_ecef_x'], - inst['sc_xhat_ecef_y'], - inst['sc_xhat_ecef_z'], - inst['sc_yhat_ecef_x'], - inst['sc_yhat_ecef_y'], - inst['sc_yhat_ecef_z']) + OMMBV.cross_product(inst['sc_xhat_ecef_x'], + inst['sc_xhat_ecef_y'], + inst['sc_xhat_ecef_z'], + inst['sc_yhat_ecef_x'], + inst['sc_yhat_ecef_y'], + inst['sc_yhat_ecef_z']) # Adding metadata for v in ['x', 'y', 'z']: @@ -173,7 +173,7 @@ def project_ecef_vector_onto_sc(inst, x_label, y_label, z_label, # TODO(#65): add checks for existence of ecef labels in inst - x, y, z = OMMBV.vector.project_ECEF_vector_onto_basis( + x, y, z = OMMBV.project_ECEF_vector_onto_basis( inst[x_label], inst[y_label], inst[z_label], inst['sc_xhat_ecef_x'], inst['sc_xhat_ecef_y'], inst['sc_xhat_ecef_z'], inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'], From ed83f02db6c81509f90a0f7c7663c0a16c12376d Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 4 Jan 2022 19:14:23 -0500 Subject: [PATCH 100/147] MAINT: drop nep29 --- .github/workflows/docs.yml | 2 -- .github/workflows/main.yml | 4 +--- requirements.txt | 1 + 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c663654b..9772e71a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -27,8 +27,6 @@ jobs: python -m pip install --upgrade pip pip install -r requirements.txt pip install -r test_requirements.txt - # Manual install of apexpy - pip install --no-binary :apexpy: apexpy - name: Check documentation build run: sphinx-build -E -b html docs dist/docs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ace1fffb..5a39b042 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ jobs: numpy_ver: ["latest"] include: - python-version: "3.8" - numpy_ver: "1.20" + numpy_ver: "latest" os: ubuntu-latest name: Python ${{ matrix.python-version }} on ${{ matrix.os }} with numpy ${{ matrix.numpy_ver }} @@ -41,8 +41,6 @@ jobs: - name: Install dependencies run: | pip install -r requirements.txt - # Manual install of apexpy - pip install --no-binary :apexpy: apexpy - name: Set up pysat run: | diff --git a/requirements.txt b/requirements.txt index 779989a9..8afd879d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ aacgmv2 +apexpy geospacepy numpy OMMBV>=1.0 From b652ce76a845f5156e6b94545a1ce288939e520e Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 4 Jan 2022 18:23:58 -0600 Subject: [PATCH 101/147] Apply suggestions from code review --- .github/workflows/main.yml | 11 +---------- CHANGELOG.md | 1 - setup.cfg | 2 +- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5a39b042..2405da1a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,13 +11,9 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.9", "3.10"] + python-version: ["3.8", "3.9", "3.10"] os: [ubuntu-latest] numpy_ver: ["latest"] - include: - - python-version: "3.8" - numpy_ver: "latest" - os: ubuntu-latest name: Python ${{ matrix.python-version }} on ${{ matrix.os }} with numpy ${{ matrix.numpy_ver }} runs-on: ${{ matrix.os }} @@ -33,11 +29,6 @@ jobs: python -m pip install --upgrade pip pip install -r test_requirements.txt - - name: Install NEP29 dependencies - if: ${{ matrix.numpy_ver != 'latest'}} - run: | - pip install --no-binary :numpy: numpy==${{ matrix.numpy_ver }} - - name: Install dependencies run: | pip install -r requirements.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index bf93408a..14a549d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,6 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Improve docstrings throughout * Testing * Add style check for docstrings - * Include support for testing against multiple versions of numpy ## [0.2.2] - 2021-06-18 * Migrate pyglow interface to pysatIncubator diff --git a/setup.cfg b/setup.cfg index aae1a689..44256856 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,7 +42,7 @@ install_requires = apexpy geospacepy numpy - OMMBV>1.0 + OMMBV>=1.0 pandas pysat>=3.0 pyEphem From 3a4c23db029b7d30080e0782d8495af1931be39e Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 5 Jan 2022 08:31:19 -0600 Subject: [PATCH 102/147] Update pysatMissions/methods/spacecraft.py Co-authored-by: Russell Stoneback --- pysatMissions/methods/spacecraft.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index 82a0a21a..3e2723da 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -173,7 +173,7 @@ def project_ecef_vector_onto_sc(inst, x_label, y_label, z_label, # TODO(#65): add checks for existence of ecef labels in inst - x, y, z = OMMBV.project_ECEF_vector_onto_basis( + x, y, z = OMMBV.vector.project_onto_basis( inst[x_label], inst[y_label], inst[z_label], inst['sc_xhat_ecef_x'], inst['sc_xhat_ecef_y'], inst['sc_xhat_ecef_z'], inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'], From abfb53849e4b4ca2880ef8a871bc0f79222ec5a7 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 5 Jan 2022 09:34:01 -0500 Subject: [PATCH 103/147] MAINT: update ommbv syntax --- pysatMissions/methods/spacecraft.py | 42 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index 3e2723da..770855ee 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -38,9 +38,9 @@ def add_ram_pointing_sc_attitude_vectors(inst): # Ram pointing is along velocity vector inst['sc_xhat_ecef_x'], inst['sc_xhat_ecef_y'], inst['sc_xhat_ecef_z'] = \ - OMMBV.normalize_vector(inst['velocity_ecef_x'], - inst['velocity_ecef_y'], - inst['velocity_ecef_z']) + OMMBV.vector.normalize_vector(inst['velocity_ecef_x'], + inst['velocity_ecef_y'], + inst['velocity_ecef_z']) # Begin with z along Nadir (towards Earth) # if orbit isn't perfectly circular, then the s/c z vector won't @@ -48,35 +48,35 @@ def add_ram_pointing_sc_attitude_vectors(inst): # to the true z (in the orbital plane) that we can use it to get y, # and use x and y to get the real z inst['sc_zhat_ecef_x'], inst['sc_zhat_ecef_y'], inst['sc_zhat_ecef_z'] = \ - OMMBV.normalize_vector(-inst['position_ecef_x'], - -inst['position_ecef_y'], - -inst['position_ecef_z']) + OMMBV.vector.normalize_vector(-inst['position_ecef_x'], + -inst['position_ecef_y'], + -inst['position_ecef_z']) # get y vector assuming right hand rule # Z x X = Y inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'] = \ - OMMBV.cross_product(inst['sc_zhat_ecef_x'], - inst['sc_zhat_ecef_y'], - inst['sc_zhat_ecef_z'], - inst['sc_xhat_ecef_x'], - inst['sc_xhat_ecef_y'], - inst['sc_xhat_ecef_z']) + OMMBV.vector.cross_product(inst['sc_zhat_ecef_x'], + inst['sc_zhat_ecef_y'], + inst['sc_zhat_ecef_z'], + inst['sc_xhat_ecef_x'], + inst['sc_xhat_ecef_y'], + inst['sc_xhat_ecef_z']) # Normalize since Xhat and Zhat from above may not be orthogonal inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'] = \ - OMMBV.normalize_vector(inst['sc_yhat_ecef_x'], - inst['sc_yhat_ecef_y'], - inst['sc_yhat_ecef_z']) + OMMBV.vector.normalize_vector(inst['sc_yhat_ecef_x'], + inst['sc_yhat_ecef_y'], + inst['sc_yhat_ecef_z']) # Strictly, need to recalculate Zhat so that it is consistent with RHS # just created # Z = X x Y inst['sc_zhat_ecef_x'], inst['sc_zhat_ecef_y'], inst['sc_zhat_ecef_z'] = \ - OMMBV.cross_product(inst['sc_xhat_ecef_x'], - inst['sc_xhat_ecef_y'], - inst['sc_xhat_ecef_z'], - inst['sc_yhat_ecef_x'], - inst['sc_yhat_ecef_y'], - inst['sc_yhat_ecef_z']) + OMMBV.vector.cross_product(inst['sc_xhat_ecef_x'], + inst['sc_xhat_ecef_y'], + inst['sc_xhat_ecef_z'], + inst['sc_yhat_ecef_x'], + inst['sc_yhat_ecef_y'], + inst['sc_yhat_ecef_z']) # Adding metadata for v in ['x', 'y', 'z']: From 38b6b887d1de41191c002bd67f4a19b5d8c1a9a0 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 5 Jan 2022 15:18:09 -0600 Subject: [PATCH 104/147] Apply suggestions from code review Co-authored-by: Russell Stoneback --- pysatMissions/methods/spacecraft.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index 770855ee..d310adca 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -48,7 +48,7 @@ def add_ram_pointing_sc_attitude_vectors(inst): # to the true z (in the orbital plane) that we can use it to get y, # and use x and y to get the real z inst['sc_zhat_ecef_x'], inst['sc_zhat_ecef_y'], inst['sc_zhat_ecef_z'] = \ - OMMBV.vector.normalize_vector(-inst['position_ecef_x'], + OMMBV.vector.normalize(-inst['position_ecef_x'], -inst['position_ecef_y'], -inst['position_ecef_z']) @@ -63,7 +63,7 @@ def add_ram_pointing_sc_attitude_vectors(inst): inst['sc_xhat_ecef_z']) # Normalize since Xhat and Zhat from above may not be orthogonal inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'] = \ - OMMBV.vector.normalize_vector(inst['sc_yhat_ecef_x'], + OMMBV.vector.normalize(inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z']) From 7fd7b655a46279bcf5cdb70e06d06fd1d9a0492c Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 5 Jan 2022 16:18:57 -0500 Subject: [PATCH 105/147] STY: tabs --- pysatMissions/methods/spacecraft.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index d310adca..e9a4d8bd 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -49,8 +49,8 @@ def add_ram_pointing_sc_attitude_vectors(inst): # and use x and y to get the real z inst['sc_zhat_ecef_x'], inst['sc_zhat_ecef_y'], inst['sc_zhat_ecef_z'] = \ OMMBV.vector.normalize(-inst['position_ecef_x'], - -inst['position_ecef_y'], - -inst['position_ecef_z']) + -inst['position_ecef_y'], + -inst['position_ecef_z']) # get y vector assuming right hand rule # Z x X = Y @@ -64,8 +64,8 @@ def add_ram_pointing_sc_attitude_vectors(inst): # Normalize since Xhat and Zhat from above may not be orthogonal inst['sc_yhat_ecef_x'], inst['sc_yhat_ecef_y'], inst['sc_yhat_ecef_z'] = \ OMMBV.vector.normalize(inst['sc_yhat_ecef_x'], - inst['sc_yhat_ecef_y'], - inst['sc_yhat_ecef_z']) + inst['sc_yhat_ecef_y'], + inst['sc_yhat_ecef_z']) # Strictly, need to recalculate Zhat so that it is consistent with RHS # just created From ccd0ddfbb867fc6c4bf10e9f5a645978ee8d01ff Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 5 Jan 2022 18:27:58 -0500 Subject: [PATCH 106/147] BUG: ommbv syntax --- pysatMissions/methods/spacecraft.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pysatMissions/methods/spacecraft.py b/pysatMissions/methods/spacecraft.py index e9a4d8bd..56848955 100644 --- a/pysatMissions/methods/spacecraft.py +++ b/pysatMissions/methods/spacecraft.py @@ -38,9 +38,9 @@ def add_ram_pointing_sc_attitude_vectors(inst): # Ram pointing is along velocity vector inst['sc_xhat_ecef_x'], inst['sc_xhat_ecef_y'], inst['sc_xhat_ecef_z'] = \ - OMMBV.vector.normalize_vector(inst['velocity_ecef_x'], - inst['velocity_ecef_y'], - inst['velocity_ecef_z']) + OMMBV.vector.normalize(inst['velocity_ecef_x'], + inst['velocity_ecef_y'], + inst['velocity_ecef_z']) # Begin with z along Nadir (towards Earth) # if orbit isn't perfectly circular, then the s/c z vector won't From 563cccbecabd3ec2f759319a560c44262b6ff842 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 5 Jan 2022 18:28:14 -0500 Subject: [PATCH 107/147] MAINT: ommbv syntax --- pysatMissions/instruments/missions_ephem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pysatMissions/instruments/missions_ephem.py b/pysatMissions/instruments/missions_ephem.py index 6264baf6..e507ec90 100644 --- a/pysatMissions/instruments/missions_ephem.py +++ b/pysatMissions/instruments/missions_ephem.py @@ -190,9 +190,9 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., lp['alt'] = sat.elevation / 1000.0 # Get ECEF position of satellite - lp['x'], lp['y'], lp['z'] = OMMBV.geodetic_to_ecef(lp['glat'], - lp['glong'], - lp['alt']) + lp['x'], lp['y'], lp['z'] = OMMBV.trans.geodetic_to_ecef(lp['glat'], + lp['glong'], + lp['alt']) output_params.append(lp) output = pds.DataFrame(output_params, index=index) From 2f68d00a48e950c52ca74142f06faff2a25d6c3e Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 5 Jan 2022 18:28:48 -0500 Subject: [PATCH 108/147] DOC: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14a549d6..8443eacd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Update sgp4 interface to use new syntax for initialization from TLEs * Include conversions to geodetic latitude / longitude / altitude for sgp4 * Improve metadata generation in missions_sgp4 +* Update syntax to be compliant with OMMBV 1.0 * Documentation * Improve docstrings throughout * Testing From 416142f5af6c91a35466424afe3c669c1615735d Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 14 Jan 2022 14:25:58 -0500 Subject: [PATCH 109/147] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4357a8c7..8dd9e0ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Deprecated missions_ephem, as pyephem will no longer be updated * Testing * Add style check for docstrings + * Added checks for deprecation warnings ## [0.2.2] - 2021-06-18 * Migrate pyglow interface to pysatIncubator From 48e6c1c5334eb80810af79b48c1e6b9d6003e854 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 21 Jan 2022 09:59:56 -0500 Subject: [PATCH 110/147] Update pysatMissions/instruments/missions_sgp4.py Co-authored-by: Russell Stoneback --- pysatMissions/instruments/missions_sgp4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index cb2973cc..7a9bfb74 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -131,7 +131,7 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, epoch : dt.datetime or NoneType The epoch used for calculating orbital propagation from Keplerians. If None, then use the first date in the file list for consistency across - multiple days. Note that this will be set at init. (default=None) + multiple days. Note that this will be set in `init`. (default=None) bstar : float Inverse of the ballistic coefficient. Used to model satellite drag. Measured in inverse distance (1 / earth radius). Optional when From b66415a06e6921aa20d026b2b4db9a7f3c81c25d Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 1 Feb 2022 13:29:04 -0500 Subject: [PATCH 111/147] DOC: update version --- pysatMissions/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/version.txt b/pysatMissions/version.txt index ee1372d3..0d91a54c 100644 --- a/pysatMissions/version.txt +++ b/pysatMissions/version.txt @@ -1 +1 @@ -0.2.2 +0.3.0 From 537fe571f98458e5a7e572717ed36911dd51f0f4 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 1 Feb 2022 13:29:36 -0500 Subject: [PATCH 112/147] MAINT: update hacking usage --- test_requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_requirements.txt b/test_requirements.txt index 9a78f43b..df589a83 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,6 +1,6 @@ coveralls flake8-docstrings -hacking +hacking>=1.0 ipython m2r2 numpydoc From ffea78e4002a79c919488e6a4cabcc5479732531 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 1 Feb 2022 13:31:21 -0500 Subject: [PATCH 113/147] DOC: update package metadata --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 44256856..2da50506 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,9 +20,9 @@ classifiers = Intended Audience :: Science/Research License :: OSI Approved :: BSD License Natural Language :: English - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Operating System :: MacOS :: MacOS X Operating System :: POSIX :: Linux license_file = LICENSE From 46180c02c16eed70e16c0dc62f2137e69ac5f4db Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 1 Feb 2022 13:51:32 -0500 Subject: [PATCH 114/147] DOC: temp release date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91fb0b00..6e1933f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -## [0.3.0] - 2021-08-05 +## [0.3.0] - 2022-XX-XX * Add Keplerian orbital inputs into missions_sgp4 * Update sgp4 interface to use new syntax for initialization from TLEs * Include conversions to geodetic latitude / longitude / altitude for sgp4 From 0c080b778c4c87f90da202aea98bdede95a98e43 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 1 Feb 2022 13:55:41 -0500 Subject: [PATCH 115/147] DOC: Update stoneback affil --- .zenodo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.zenodo.json b/.zenodo.json index baee59a6..04b1ee81 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -6,7 +6,7 @@ "orcid": "0000-0001-8321-6074" }, { - "affiliation": "The University of Texas at Dallas", + "affiliation": "Stoneris", "name": "Stoneback, Russell", "orcid": "0000-0001-7216-4336" }, From b3da01bc816460e8787896826929c6469790ce7e Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Tue, 1 Feb 2022 14:13:35 -0500 Subject: [PATCH 116/147] DOC: update ommbv versions --- README.md | 2 +- docs/installation.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 94710e07..ebca6953 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Python 3.7+. | -------------- | ----------------- | | numpy | aacgmv2 | | pandas | apexpy | -| pyEphem | OMMBV | +| pyEphem | OMMBV>=1.0 | | sgp4>=2.7 | pysat>=3.0 | diff --git a/docs/installation.rst b/docs/installation.rst index 6c46823b..85ae6708 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -22,7 +22,7 @@ Python 3.7+ and pysat 3.0.0+. ================ ================== numpy aacgmv2 pandas apexpy - pyEphem OMMBV + pyEphem OMMBV>=1.0 sgp4>=2.7 pysat>=3.0 ================ ================== From 13dc7a26bd85bf15485914d5c1325353b85f7b2c Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 16 Feb 2022 15:58:45 -0500 Subject: [PATCH 117/147] Apply suggestions from code review Co-authored-by: Angeline Burrell --- pysatMissions/instruments/methods/orbits.py | 7 +++---- setup.cfg | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 12e8e20c..5b80985e 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -51,8 +51,8 @@ def _get_constants(planet='Earth'): Newton's gravitational constant """ - radius = {'Earth': 6371.2} - mass = {'Earth': 5.9742e24} + radius = {'earth': 6371.2} + mass = {'earth': 5.9742e24} gravity = 6.6743e-11 if planet not in radius.keys(): @@ -73,8 +73,7 @@ def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='Earth'): If None, assumed to be equal to periapsis. (default=None) planet : str The name of the planet of interest. Used for radial calculations and - mass. - (default='Earth') + mass. (default='Earth') Returns ------- diff --git a/setup.cfg b/setup.cfg index 2da50506..faf48e8f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -42,11 +42,11 @@ install_requires = apexpy geospacepy numpy - OMMBV>=1.0 + OMMBV pandas pysat>=3.0 pyEphem - sgp4>=2.7 + sgp4 [coverage:report] From f2510dcf120194a47d5e95f20a68d67bd009d0b0 Mon Sep 17 00:00:00 2001 From: jklenzing Date: Wed, 16 Feb 2022 16:31:42 -0500 Subject: [PATCH 118/147] BUG: lowercase strings --- pysatMissions/instruments/methods/orbits.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 5b80985e..40e7dd74 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -32,14 +32,14 @@ def _check_orbital_params(kwargs=None): return -def _get_constants(planet='Earth'): +def _get_constants(planet='earth'): """Retrieve planetary constants for calculations. Parameters ---------- planet : str The name of the planet of interest. - (default='Earth') + (default='earth') Returns ------- @@ -61,7 +61,7 @@ def _get_constants(planet='Earth'): return radius[planet], mass[planet], gravity -def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='Earth'): +def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='earth'): """Calculate orbital eccentricity from periapsis and apoapsis. Parameters @@ -73,7 +73,7 @@ def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='Earth'): If None, assumed to be equal to periapsis. (default=None) planet : str The name of the planet of interest. Used for radial calculations and - mass. (default='Earth') + mass. (default='earth') Returns ------- @@ -101,7 +101,7 @@ def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='Earth'): return eccentricity, mean_motion -def convert_from_keplerian(eccentricity, mean_motion, planet='Earth'): +def convert_from_keplerian(eccentricity, mean_motion, planet='earth'): """Calculate orbital eccentricity from periapsis and apoapsis. Parameters @@ -112,7 +112,7 @@ def convert_from_keplerian(eccentricity, mean_motion, planet='Earth'): The mean angular speed of the orbit (rad/minute) planet : string The name of the planet of interest. Used for radial calculations. - (default='Earth') + (default='earth') Returns ------- From 70341373e4f559f740e3ecb525d81d1e2b9575eb Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 16 Mar 2022 15:24:22 -0400 Subject: [PATCH 119/147] DOC: update comments about pyglow --- README.md | 1 - pysatMissions/__init__.py | 1 - 2 files changed, 2 deletions(-) diff --git a/README.md b/README.md index ebca6953..a23c0f4b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,6 @@ pysatMissions allows users to run build simulated satellites for Two-Line Elemen Main Features ------------- - Simulate satellite orbits from TLEs and add data from empirical models -- Import ionosphere and thermosphere model values through pyglow - Import magnetic coordinates through apexpy and aacgmv2 - Import geomagnetic basis vectors through OMMBV diff --git a/pysatMissions/__init__.py b/pysatMissions/__init__.py index 185b37a1..e2de92fd 100644 --- a/pysatMissions/__init__.py +++ b/pysatMissions/__init__.py @@ -7,7 +7,6 @@ Main Features ------------- - Simulate satellite orbits from TLEs and add data from empirical models -- Import ionosphere and thermosphere model values through pyglow - Import magnetic coordinates through apexpy and aacgmv2 - Import geomagnetic basis vectors through OMMBV From 228bbb5c4e73c75d28682bc672d2b3944d60dee8 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 21 Apr 2022 15:16:03 -0400 Subject: [PATCH 120/147] STY: update tests --- pysatMissions/tests/test_inst_methods_orbits.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pysatMissions/tests/test_inst_methods_orbits.py b/pysatMissions/tests/test_inst_methods_orbits.py index 5e223d3a..91b770bd 100644 --- a/pysatMissions/tests/test_inst_methods_orbits.py +++ b/pysatMissions/tests/test_inst_methods_orbits.py @@ -32,7 +32,8 @@ def test_convert_wrong_planet(self): with pytest.raises(KeyError) as kerr: mm_orbits.convert_to_keplerian(self.orbit['perigee'], - self.orbit['apogee'], 'Hwae') + self.orbit['apogee'], + 'Sanctuary Moon') assert str(kerr).find("is not yet a supported planet!") >= 0 return From c63ebe2db494b28ce000344e075788502b77c4df Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 21 Apr 2022 15:30:10 -0400 Subject: [PATCH 121/147] DOC: update docstring --- pysatMissions/instruments/missions_sgp4.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 76d7202a..8cee6021 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -152,6 +152,12 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, meta : pysat.Meta Object containing metadata such as column names and units + Note + ---- + Altitude accuracy expected to be on the order of 10 km in Low Earth Orbit. + Efforts to improve accuracy documented under issue #79. + + Example ------- :: From cb594cb3935d905e8dda20b599fad6d13ddaee9b Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 21 Apr 2022 15:30:19 -0400 Subject: [PATCH 122/147] BUG: earth mass --- pysatMissions/instruments/methods/orbits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 40e7dd74..8f02eeb4 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -52,7 +52,7 @@ def _get_constants(planet='earth'): """ radius = {'earth': 6371.2} - mass = {'earth': 5.9742e24} + mass = {'earth': 5.9722e24} gravity = 6.6743e-11 if planet not in radius.keys(): From 48bf303f049659c433ded98495c8ef9ac476cc17 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Thu, 21 Apr 2022 17:25:43 -0400 Subject: [PATCH 123/147] BUG: update test criteria --- pysatMissions/tests/test_inst_methods_orbits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/tests/test_inst_methods_orbits.py b/pysatMissions/tests/test_inst_methods_orbits.py index 91b770bd..336964c2 100644 --- a/pysatMissions/tests/test_inst_methods_orbits.py +++ b/pysatMissions/tests/test_inst_methods_orbits.py @@ -12,7 +12,7 @@ def setup(self): self.orbit = {'inclination': 13, 'apogee': 850, 'perigee': 400, 'eccentricity': 0.032160315599897085, - 'mean_motion': 0.06474416985702029} + 'mean_motion': 0.0647333316545142} return def teardown(self): From 639f26b4f508bfedddb6e3312ef8bd80eaaf040f Mon Sep 17 00:00:00 2001 From: Jeff Klenzing <19592220+jklenzing@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:02:43 -0400 Subject: [PATCH 124/147] Apply suggestions from code review Co-authored-by: Russell Stoneback --- pysatMissions/instruments/methods/orbits.py | 11 +++++++---- pysatMissions/instruments/missions_sgp4.py | 15 ++++++++------- pysatMissions/tests/test_deprecation.py | 2 +- pysatMissions/tests/test_instruments.py | 1 + 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 8f02eeb4..9b5981a2 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -9,9 +9,9 @@ def _check_orbital_params(kwargs=None): Parameters ---------- - kwargs : dict + kwargs : dict or NoneType Dictionary of optional kwargs passed through upon initialization - of pysat instrument. + of pysat instrument. (default=None) """ @@ -22,6 +22,7 @@ def _check_orbital_params(kwargs=None): errmsg = 'Insufficient kwargs. Kwarg group requires {:}' for group in [tles, keplerians]: bools = [v in elements for v in group] + # Check if group is incomplete. if any(bools) and not all(bools): raise KeyError(errmsg.format(', '.join(group))) @@ -95,7 +96,7 @@ def convert_to_keplerian(alt_periapsis, alt_apoapsis=None, planet='earth'): eccentricity = ((rad_apoapsis - rad_periapsis) / (rad_apoapsis + rad_periapsis)) - # convert axis to m, mean_motion to rad / minute + # Convert axis to m, mean_motion to rad / minute mean_motion = np.sqrt(gravity * mass / (1000 * semimajor)**3) * 60 return eccentricity, mean_motion @@ -110,7 +111,7 @@ def convert_from_keplerian(eccentricity, mean_motion, planet='earth'): The eccentricty of the orbit (unitless) mean_motion : float The mean angular speed of the orbit (rad/minute) - planet : string + planet : str The name of the planet of interest. Used for radial calculations. (default='earth') @@ -124,8 +125,10 @@ def convert_from_keplerian(eccentricity, mean_motion, planet='earth'): """ radius, mass, gravity = _get_constants(planet) + # Convert mean_motion to rad / second before computing semimajor = (gravity * mass / (mean_motion / 60)**2) + # Convert distance to km semimajor = semimajor**(1 / 3) / 1000 diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 8cee6021..365f8135 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -91,21 +91,21 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, Instrument satellite ID (accepts '' or a number (i.e., '10'), which specifies the number of seconds to simulate the satellite) (default='') - TLE1 : string + TLE1 : str or NoneType First string for Two Line Element. Must be in TLE format. TLE1 and TLE2 both required if instantiating instrument by TLEs. (defalt=None) - TLE2 : string + TLE2 : str or NoneType Second string for Two Line Element. Must be in TLE format. TLE1 and TLE2 - both required if instantiating instrument by TLEs. (defalt=None) - alt_periapsis : float + both required if instantiating instrument by TLEs. (default=None) + alt_periapsis : float or NoneType The lowest altitude from the mean planet surface along the orbit (km). Required along with inclination if instantiating via orbital elements. - (defalt=None) + (default=None) alt_apoapsis : float or NoneType The highest altitude from the mean planet surface along the orbit (km) If None, assumed to be equal to periapsis (ie, circular orbit). Optional when instantiating via orbital elements. (default=None) - inclination : float + inclination : float or NoneType Orbital Inclination in degrees. Required along with alt_periapsis if instantiating via orbital elements. (default=None) raan : float @@ -197,7 +197,7 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, eccentricity, mean_motion = orbits.convert_to_keplerian(alt_periapsis, alt_apoapsis) satellite = sapi.Satrec() - # according to module webpage, wgs72 is common + # According to module webpage, wgs72 is common satellite.sgp4init(sapi.WGS72, 'i', 0, epoch_days, bstar, 0, 0, eccentricity, np.radians(arg_periapsis), np.radians(inclination), np.radians(mean_anomaly), @@ -230,6 +230,7 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, # Convert to geocentric latitude, longitude, altitude. lat, lon, rad = conv_sph.ecef_cart2spherical(pos_ecef) + # Convert to geodetic latitude, longitude, altitude. # Ellipsoidal conversions require input in meters. geod_lat, geod_lon, geod_alt = conv_ell.ecef_cart2geodetic(pos_ecef * 1000.) diff --git a/pysatMissions/tests/test_deprecation.py b/pysatMissions/tests/test_deprecation.py index 62c0a452..5f9135cf 100644 --- a/pysatMissions/tests/test_deprecation.py +++ b/pysatMissions/tests/test_deprecation.py @@ -1,4 +1,4 @@ -"""Unit tests for deprecated methods an objects in pysatMissions.""" +"""Unit tests for deprecated methods and objects in pysatMissions.""" import numpy as np import warnings diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index 820251cf..ff5c0bfc 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -163,6 +163,7 @@ def test_sgp4_options(self, kw_dict): **kw_dict) self.test_inst.data = [target] self.test_inst.load(date=self.stime) + # If target is cleared, load has run successfully assert target not in self.test_inst.data return From ed1d15a89698a5f6a7afb23b9c578f248a7886bd Mon Sep 17 00:00:00 2001 From: Jeff Klenzing <19592220+jklenzing@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:04:27 -0400 Subject: [PATCH 125/147] DOC: add post-installation discussion --- docs/installation.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/installation.rst b/docs/installation.rst index 85ae6708..11fb023c 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -55,3 +55,27 @@ Python 3.7+ and pysat 3.0.0+. python setup.py develop --user + + +.. _post-install: +Post Installation +----------------- + +After installation, you may register the :py:mod:`pysatMissions` +:py:class:`Instrument` sub-modules with pysat. If this is your first time using +pysat, check out the `quickstart guide +`_ for pysat. Once pysat +is set up, you may choose to register the the :py:mod:`pysatMissions` +:py:class:`Instruments` sub-modules by: + +.. code:: python + + + import pysat + import pysatMissions + + pysat.utils.registry.register_by_module(pysatMissions.instruments) + +You may then use the pysat :py:attr:`platform` and :py:attr:`name` keywords to +initialize the model :py:class:`Instrument` instead of the +:py:attr:`inst_module` keyword argument. From 58ef75d8d1e5af7b91b62a8c398d87688ca04ecb Mon Sep 17 00:00:00 2001 From: Jeff Klenzing <19592220+jklenzing@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:06:20 -0400 Subject: [PATCH 126/147] Update references.rst --- docs/references.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/references.rst b/docs/references.rst index b7bd48e1..189af216 100644 --- a/docs/references.rst +++ b/docs/references.rst @@ -38,5 +38,8 @@ calculating magnetic apex coordinates. OMMBV ------------ +.. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.1299374.svg + :target: https://doi.org/10.5281/zenodo.1299374 + `OMMBV `_ calculates Orthogonal Multipole Magnetic Basis Vectors for the earth's magnetic field. From 2795b68da0295d73960bddd283092060e1a1b0b2 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing <19592220+jklenzing@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:12:20 -0400 Subject: [PATCH 127/147] Update CONTRIBUTING.md --- CONTRIBUTING.md | 118 +++++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 57 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 317bf714..0e9cae3b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,13 +7,13 @@ appreciated! pysatMissions is a community-driven project and welcomes both feed Short version ------------- -* Submit bug reports and feature requests at `GitHub `_ +* Submit bug reports and feature requests at [GitHub](https://github.com/pysat/pysatMissions/issues) * Make pull requests to the ``develop`` branch Bug reports ----------- -When `reporting a bug `_ please +When [reporting a bug](https://github.com/pysat/pysatMissions/issues) please include: * Your operating system name and version @@ -24,7 +24,7 @@ Feature requests and feedback ----------------------------- The best way to send feedback is to file an issue at -`GitHub `_. +[GitHub](https://github.com/pysat/pysatMissions/issues). If you are proposing a feature: @@ -38,14 +38,16 @@ Development To set up `pysatMissions` for local development: -1. `Fork pysat on GitHub `_. -2. Clone your fork locally:: +1. [Fork pysat on GitHub](https://github.com/pysat/pysatMissions/fork). - git clone git@github.com:your_name_here/pysatMissions.git +3. Clone your fork locally: + ``` + git clone git@github.com:your_name_here/pysatMissions.git -3. Create a branch for local development:: - - git checkout -b name-of-your-bugfix-or-feature +3. Create a branch for local development: + ``` + git checkout -b name-of-your-bugfix-or-feature + ``` Now you can make your changes locally. Tests for new instruments are performed automatically. Tests for custom functions should be added to @@ -55,19 +57,21 @@ To set up `pysatMissions` for local development: ``test_``. 4. When you're done making changes, run all the checks to ensure that nothing - is broken on your local system:: - - pytest -vs + is broken on your local system: + ``` + pytest -vs + ``` 5. Update/add documentation (in ``docs``), if relevant -5. Commit your changes and push your branch to GitHub:: - +6. Commit your changes and push your branch to GitHub: + ``` git add . git commit -m "Brief description of your changes" git push origin name-of-your-bugfix-or-feature + ``` -6. Submit a pull request through the GitHub website. Pull requests should be +7. Submit a pull request through the GitHub website. Pull requests should be made to the ``develop`` branch. Pull Request Guidelines @@ -81,45 +85,45 @@ For merging, you should: 1. Include an example for use 2. Add a note to ``CHANGELOG.md`` about the changes 3. Ensure that all checks passed (current checks include GitHub Actions - and Coveralls) [1]_ - -.. [1] If you don't have all the necessary Python versions available locally or - have trouble building all the testing environments, you can rely on - GitHub Actions to run the tests for each change you add in the pull - request. Because testing here will delay tests by other developers, - please ensure that the code passes all tests on your local system first. - - Project Style Guidelines - ^^^^^^^^^^^^^^^^^^^^^^^^ - - In general, pysat follows PEP8 and numpydoc guidelines. Pytest runs the unit - and integration tests, flake8 checks for style, and sphinx-build performs - documentation tests. However, there are certain additional style elements that - have been settled on to ensure the project maintains a consistent coding style. - These include: - - * Line breaks should occur before a binary operator (ignoring flake8 W503) - * Combine long strings using `join` - * Preferably break long lines on open parentheses rather than using `\` - * Use no more than 80 characters per line - * Avoid using Instrument class key attribute names as unrelated variable names: - `platform`, `name`, `tag`, and `inst_id` - * The pysat logger is imported into each sub-module and provides status updates - at the info and warning levels (as appropriate) - * Several dependent packages have common nicknames, including: - * `import datetime as dt` - * `import numpy as np` - * `import pandas as pds` - * `import xarray as xr` - * All classes should have `__repr__` and `__str__` functions - * Docstrings use `Note` instead of `Notes` - * Try to avoid creating a try/except statement where except passes - * Use setup and teardown in test classes - * Use pytest parametrize in test classes when appropriate - * Provide testing class methods with informative failure statements and - descriptive, one-line docstrings - * Block and inline comments should use proper English grammar and punctuation - with the exception of single sentences in a block, which may then omit the - final period - * When casting is necessary, use `np.int64` and `np.float64` to ensure operating - system agnosticism + and Coveralls) + +If you don't have all the necessary Python versions available locally or +have trouble building all the testing environments, you can rely on +GitHub Actions to run the tests for each change you add in the pull +request. Because testing here will delay tests by other developers, +please ensure that the code passes all tests on your local system first. + +Project Style Guidelines +^^^^^^^^^^^^^^^^^^^^^^^^ + +In general, pysat follows PEP8 and numpydoc guidelines. Pytest runs the unit +and integration tests, flake8 checks for style, and sphinx-build performs +documentation tests. However, there are certain additional style elements that +have been settled on to ensure the project maintains a consistent coding style. +These include: + +* Line breaks should occur before a binary operator (ignoring flake8 W503) +* Combine long strings using `join` +* Preferably break long lines on open parentheses rather than using `\` +* Use no more than 80 characters per line +* Avoid using Instrument class key attribute names as unrelated variable names: + `platform`, `name`, `tag`, and `inst_id` +* The pysat logger is imported into each sub-module and provides status updates + at the info and warning levels (as appropriate) +* Several dependent packages have common nicknames, including: + * `import datetime as dt` + * `import numpy as np` + * `import pandas as pds` + * `import xarray as xr` +* All classes should have `__repr__` and `__str__` functions +* Docstrings use `Note` instead of `Notes` +* Try to avoid creating a try/except statement where except passes +* Use setup and teardown in test classes +* Use pytest parametrize in test classes when appropriate +* Provide testing class methods with informative failure statements and + descriptive, one-line docstrings +* Block and inline comments should use proper English grammar and punctuation + with the exception of single sentences in a block, which may then omit the + final period +* When casting is necessary, use `np.int64` and `np.float64` to ensure operating + system agnosticism From 5f25f5826d2bec5212ea851e7eea556eba6531f0 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing <19592220+jklenzing@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:17:41 -0400 Subject: [PATCH 128/147] Update CONTRIBUTING.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0e9cae3b..3e168df7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,6 +43,7 @@ To set up `pysatMissions` for local development: 3. Clone your fork locally: ``` git clone git@github.com:your_name_here/pysatMissions.git + ``` 3. Create a branch for local development: ``` From 060881a35a74576354c88b90fe488217f134fb9f Mon Sep 17 00:00:00 2001 From: Jeff Klenzing <19592220+jklenzing@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:23:19 -0400 Subject: [PATCH 129/147] Update conf.py --- docs/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/conf.py b/docs/conf.py index 1f8a6a7a..1a0a802f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -55,6 +55,8 @@ 'sphinx.ext.imgmath', 'sphinx.ext.autosummary', 'sphinx.ext.napoleon', + 'sphinx.ext.githubpages', + 'sphinx.ext.autosectionlabel', 'numpydoc', 'IPython.sphinxext.ipython_console_highlighting', 'm2r2'] From 3245983eb08c529e82abf9b3404fbe43b38fe158 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing <19592220+jklenzing@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:26:07 -0400 Subject: [PATCH 130/147] Update conf.py --- docs/conf.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 1a0a802f..001c6fef 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ title = '{:s} Documentation'.format(project) zenodo = json.loads(open('../.zenodo.json').read()) author = ', '.join([x['name'] for x in zenodo['creators']]) -copyright = ', '.join(['2021', author]) +copyright = ', '.join(['2022', author]) description = 'Tools for generating simulated instruments in pysat.' # The short X.Y version @@ -61,7 +61,8 @@ 'IPython.sphinxext.ipython_console_highlighting', 'm2r2'] -numpydoc_show_class_members = False +autosectionlabel_prefix_document = True +autosectionlabel_maxdepth = 3 # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] From 87a563ed42b790f9c6488726ac83cd467b1345a2 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 2 May 2022 12:31:37 -0400 Subject: [PATCH 131/147] DOC: update metadat --- pysatMissions/instruments/missions_ephem.py | 35 +++++++++++++---- pysatMissions/instruments/missions_sgp4.py | 42 ++++++++++++++++----- 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/pysatMissions/instruments/missions_ephem.py b/pysatMissions/instruments/missions_ephem.py index 74561505..e2e1cd58 100644 --- a/pysatMissions/instruments/missions_ephem.py +++ b/pysatMissions/instruments/missions_ephem.py @@ -230,28 +230,49 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., meta.labels.desc: 'UTC seconds', meta.labels.name: 'Time index in milliseconds'} meta['glong'] = {meta.labels.units: 'degrees', - meta.labels.desc: 'WGS84 geodetic longitude'} + meta.labels.desc: 'WGS84 geodetic longitude', + meta.labels.min_val: -180.0, + meta.labels.max_val: 180.0, + meta.labels.fill_val: np.nan} meta['glat'] = {meta.labels.units: 'degrees', - meta.labels.desc: 'WGS84 geodetic latitude'} + meta.labels.desc: 'WGS84 geodetic latitude', + meta.labels.min_val: -90.0, + meta.labels.max_val: 90.0, + meta.labels.fill_val: np.nan} meta['alt'] = {meta.labels.units: 'km', - meta.labels.desc: "WGS84 height above Earth's surface"} + meta.labels.desc: "WGS84 height above Earth's surface", + meta.labels.min_val: 0.0, + meta.labels.max_val: np.inf, + meta.labels.fill_val: np.nan} for v in ['x', 'y', 'z']: meta['position_ecef_{:}'.format(v)] = { meta.labels.units: 'km', meta.labels.name: 'ECEF {:}-position'.format(v), - meta.labels.desc: 'Earth Centered Earth Fixed {:}-position'.format(v)} + meta.labels.desc: 'Earth Centered Earth Fixed {:}-position'.format(v), + meta.labels.min_val: -np.inf, + meta.labels.max_val: np.inf, + meta.labels.fill_val: np.nan} meta['obs_sat_az_angle'] = { meta.labels.units: 'degrees', meta.labels.name: 'Satellite Azimuth Angle', - meta.labels.desc: 'Azimuth of satellite from ground station'} + meta.labels.desc: 'Azimuth of satellite from ground station', + meta.labels.min_val: -np.inf, + meta.labels.max_val: np.inf, + meta.labels.fill_val: np.nan} meta['obs_sat_el_angle'] = { meta.labels.units: 'degrees', meta.labels.name: 'Satellite Elevation Angle', - meta.labels.desc: 'Elevation of satellite from ground station'} + meta.labels.desc: 'Elevation of satellite from ground station', + meta.labels.min_val: -np.inf, + meta.labels.max_val: np.inf, + meta.labels.fill_val: np.nan} meta['obs_sat_slant_range'] = { meta.labels.units: 'km', meta.labels.name: 'Satellite Slant Distance', - meta.labels.desc: 'Distance of satellite from ground station'} + meta.labels.desc: 'Distance of satellite from ground station', + meta.labels.min_val: -np.inf, + meta.labels.max_val: np.inf, + meta.labels.fill_val: np.nan} return data, meta diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 365f8135..008d5445 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -268,59 +268,81 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, meta['position_eci_{:}'.format(v)] = { meta.labels.units: 'km', meta.labels.name: 'ECI {:}-position'.format(v), - meta.labels.desc: 'Earth Centered Inertial {:}-position'.format(v)} + meta.labels.desc: 'Earth Centered Inertial {:}-position'.format(v), + meta.labels.min_val: -np.inf, + meta.labels.max_val: np.inf, + meta.labels.fill_val: np.nan} meta['velocity_eci_{:}'.format(v)] = { meta.labels.units: 'km/s', meta.labels.name: 'Satellite velocity ECI-{:}'.format(v), - meta.labels.desc: 'Satellite velocity along ECI-{:}'.format(v)} + meta.labels.desc: 'Satellite velocity along ECI-{:}'.format(v), + meta.labels.min_val: -np.inf, + meta.labels.max_val: np.inf, + meta.labels.fill_val: np.nan} meta['position_ecef_{:}'.format(v)] = { meta.labels.units: 'km', meta.labels.notes: 'Calculated using geospacepy.terrestrial_spherical', meta.labels.name: 'ECEF {:}-position'.format(v), - meta.labels.desc: 'Earth Centered Earth Fixed {:}-position'.format(v)} + meta.labels.desc: 'Earth Centered Earth Fixed {:}-position'.format(v), + meta.labels.min_val: -np.inf, + meta.labels.max_val: np.inf, + meta.labels.fill_val: np.nan} meta['velocity_ecef_{:}'.format(v)] = { meta.labels.units: 'km', meta.labels.notes: 'Calculated using geospacepy.terrestrial_spherical', meta.labels.name: 'ECEF {:}-velocity'.format(v), - meta.labels.desc: 'Earth Centered Earth Fixed {:}-velocity'.format(v)} + meta.labels.desc: 'Earth Centered Earth Fixed {:}-velocity'.format(v), + meta.labels.min_val: -np.inf, + meta.labels.max_val: np.inf, + meta.labels.fill_val: np.nan} meta['latitude'] = { meta.labels.units: 'degrees', meta.labels.notes: 'Calculated using geospacepy.terrestrial_spherical', meta.labels.name: 'Geocentric Latitude', meta.labels.desc: 'Geocentric Latitude of satellite', meta.labels.min_val: -90., - meta.labels.max_val: 90.} + meta.labels.max_val: 90., + meta.labels.fill_val: np.nan} meta['longitude'] = { meta.labels.units: 'degrees', meta.labels.notes: 'Calculated using geospacepy.terrestrial_spherical', meta.labels.name: 'Geocentric Longitude', meta.labels.desc: 'Geocentric Longitude of satellite', meta.labels.min_val: -180., - meta.labels.max_val: 180.} + meta.labels.max_val: 180., + meta.labels.fill_val: np.nan} meta['mean_altitude'] = { meta.labels.units: 'km', meta.labels.notes: 'Calculated using geospacepy.terrestrial_spherical', meta.labels.name: 'Altitude', - meta.labels.desc: 'Altitude of satellite above an ellipsoidal Earth'} + meta.labels.desc: 'Altitude of satellite above an ellipsoidal Earth', + meta.labels.min_val: 0, + meta.labels.max_val: np.inf, + meta.labels.fill_val: np.nan} meta['geod_latitude'] = { meta.labels.units: 'degrees', meta.labels.notes: 'Calculated using geospacepy.terrestrial_ellipsoidal', meta.labels.name: 'Geodetic Latitude', meta.labels.desc: 'Geodetic Latitude of satellite', meta.labels.min_val: -90., - meta.labels.max_val: 90.} + meta.labels.max_val: 90., + meta.labels.fill_val: np.nan} meta['geod_longitude'] = { meta.labels.units: 'degrees', meta.labels.notes: 'Calculated using geospacepy.terrestrial_ellipsoidal', meta.labels.name: 'Geodetic Longitude', meta.labels.desc: 'Geodetic Longitude of satellite', meta.labels.min_val: -180., - meta.labels.max_val: 180.} + meta.labels.max_val: 180., + meta.labels.fill_val: np.nan} meta['geod_altitude'] = { meta.labels.units: 'km', meta.labels.notes: 'Calculated using geospacepy.terrestrial_ellipsoidal', meta.labels.name: 'Altitude', - meta.labels.desc: 'Altitude of satellite above an ellipsoidal Earth'} + meta.labels.desc: 'Altitude of satellite above an ellipsoidal Earth', + meta.labels.min_val: -np.inf, + meta.labels.max_val: np.inf, + meta.labels.fill_val: np.nan} return data, meta From 7944555e52aff9d38a8a0aa878081ba0979e754f Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 2 May 2022 12:52:09 -0400 Subject: [PATCH 132/147] BUG: readthedocs install --- docs/installation.rst | 1 + docs/requirements.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/installation.rst b/docs/installation.rst index 11fb023c..887cf268 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -58,6 +58,7 @@ Python 3.7+ and pysat 3.0.0+. .. _post-install: + Post Installation ----------------- diff --git a/docs/requirements.txt b/docs/requirements.txt index b0dcb5e1..3183e060 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,4 @@ ipython m2r2 +numpy numpydoc From afd155981057106c81903ed04f636341368e031d Mon Sep 17 00:00:00 2001 From: Jeff Klenzing <19592220+jklenzing@users.noreply.github.com> Date: Mon, 2 May 2022 12:59:27 -0400 Subject: [PATCH 133/147] Apply suggestions from code review Co-authored-by: Angeline Burrell --- CONTRIBUTING.md | 2 +- docs/conf.py | 2 +- pysatMissions/instruments/methods/orbits.py | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3e168df7..3547d9b6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -90,7 +90,7 @@ For merging, you should: If you don't have all the necessary Python versions available locally or have trouble building all the testing environments, you can rely on -GitHub Actions to run the tests for each change you add in the pull +the project's Continuous Integration (CI) service to run the tests for each change you add in the pull request. Because testing here will delay tests by other developers, please ensure that the code passes all tests on your local system first. diff --git a/docs/conf.py b/docs/conf.py index 001c6fef..6ca919d1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -25,7 +25,7 @@ project = 'pysatMissions' title = '{:s} Documentation'.format(project) zenodo = json.loads(open('../.zenodo.json').read()) -author = ', '.join([x['name'] for x in zenodo['creators']]) +author = ', '.join([creator['name'] for creator in zenodo['creators']]) copyright = ', '.join(['2022', author]) description = 'Tools for generating simulated instruments in pysat.' diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 9b5981a2..205c84ee 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -50,6 +50,7 @@ def _get_constants(planet='earth'): The average mass of the planet. gravity : float (m**3 kg / s**2) Newton's gravitational constant + """ radius = {'earth': 6371.2} From 161c0476b75374d8ad9af6171b904ac070330162 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 2 May 2022 13:20:18 -0400 Subject: [PATCH 134/147] STY: apply code review Co-Authored-By: Angeline Burrell --- pysatMissions/instruments/methods/orbits.py | 13 ++++---- pysatMissions/instruments/missions_ephem.py | 20 +++++------ pysatMissions/instruments/missions_sgp4.py | 33 +++++++++---------- pysatMissions/tests/test_deprecation.py | 6 ++++ .../tests/test_inst_methods_orbits.py | 1 + 5 files changed, 39 insertions(+), 34 deletions(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 205c84ee..28b7a01d 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -4,29 +4,30 @@ import warnings -def _check_orbital_params(kwargs=None): +def _check_orbital_params(kwargs): """Check that a complete set of unconflicted orbital parameters exist. Parameters ---------- kwargs : dict or NoneType Dictionary of optional kwargs passed through upon initialization - of pysat instrument. (default=None) + of pysat instrument. """ - elements = list(kwargs['load'].keys()) + req_elements = list(kwargs['load'].keys()) keplerians = ['alt_periapsis', 'inclination'] tles = ['TLE1', 'TLE2'] errmsg = 'Insufficient kwargs. Kwarg group requires {:}' for group in [tles, keplerians]: - bools = [v in elements for v in group] + bools = [item in req_elements for item in group] # Check if group is incomplete. if any(bools) and not all(bools): raise KeyError(errmsg.format(', '.join(group))) - if all(v in elements for v in tles) and all(v in elements for v in keplerians): + if (all(item in req_elements for item in tles) + and all(item in req_elements for item in keplerians)): warnings.warn(' '.join(['Cannot use both Keplerians and TLEs.', 'Defaulting to Keplerians.'])) @@ -50,7 +51,7 @@ def _get_constants(planet='earth'): The average mass of the planet. gravity : float (m**3 kg / s**2) Newton's gravitational constant - + """ radius = {'earth': 6371.2} diff --git a/pysatMissions/instruments/missions_ephem.py b/pysatMissions/instruments/missions_ephem.py index e2e1cd58..18d2949e 100644 --- a/pysatMissions/instruments/missions_ephem.py +++ b/pysatMissions/instruments/missions_ephem.py @@ -97,7 +97,7 @@ def preprocess(self): def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., - TLE1=None, TLE2=None, num_samples=None, cadence='1S'): + tle1=None, tle2=None, num_samples=None, cadence='1S'): """Generate position of satellite in both geographic and ECEF co-ordinates. Note @@ -123,9 +123,9 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., obs_alt: float Altitude of the observer on the Earth's surface (default=0.) - TLE1 : string or NoneType + tle1 : string or NoneType First string for Two Line Element. Must be in TLE format (default=None) - TLE2 : string or NoneType + tle2 : string or NoneType Second string for Two Line Element. Must be in TLE format (default=None) num_samples : int or NoneType Number of samples per day (default=None) @@ -144,9 +144,9 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., ------- :: - TLE1='1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998' - TLE2='2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452' - inst = pysat.Instrument('pysat', 'ephem', TLE1=TLE1, TLE2=TLE2) + tle1='1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998' + tle2='2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452' + inst = pysat.Instrument('pysat', 'ephem', tle1=tle1, tle2=tle2) inst.load(2018, 1) """ @@ -161,10 +161,10 @@ def load(fnames, tag=None, inst_id=None, obs_long=0., obs_lat=0., obs_alt=0., '15.54059185113452')) # Use ISS defaults if not provided by user - if TLE1 is not None: - line1 = TLE1 - if TLE2 is not None: - line2 = TLE2 + if tle1 is not None: + line1 = tle1 + if tle2 is not None: + line2 = tle2 if num_samples is None: num_samples = 100 diff --git a/pysatMissions/instruments/missions_sgp4.py b/pysatMissions/instruments/missions_sgp4.py index 008d5445..bc48338c 100644 --- a/pysatMissions/instruments/missions_sgp4.py +++ b/pysatMissions/instruments/missions_sgp4.py @@ -71,16 +71,12 @@ def init(self): clean = mcore._clean -def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, +def load(fnames, tag=None, inst_id=None, tle1=None, tle2=None, alt_periapsis=None, alt_apoapsis=None, inclination=None, raan=0., arg_periapsis=0., mean_anomaly=0., epoch=None, bstar=0., one_orbit=False, num_samples=None, cadence='1S'): """Generate position of satellite in ECI co-ordinates. - Note - ---- - Routine is directly called by pysat and not the user. - Parameters ---------- fnames : list-like collection @@ -91,11 +87,11 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, Instrument satellite ID (accepts '' or a number (i.e., '10'), which specifies the number of seconds to simulate the satellite) (default='') - TLE1 : str or NoneType - First string for Two Line Element. Must be in TLE format. TLE1 and TLE2 + tle1 : str or NoneType + First string for Two Line Element. Must be in TLE format. tle1 and tle2 both required if instantiating instrument by TLEs. (defalt=None) - TLE2 : str or NoneType - Second string for Two Line Element. Must be in TLE format. TLE1 and TLE2 + tle2 : str or NoneType + Second string for Two Line Element. Must be in TLE format. tle1 and tle2 both required if instantiating instrument by TLEs. (default=None) alt_periapsis : float or NoneType The lowest altitude from the mean planet surface along the orbit (km). @@ -154,17 +150,18 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, Note ---- - Altitude accuracy expected to be on the order of 10 km in Low Earth Orbit. - Efforts to improve accuracy documented under issue #79. + * Routine is directly called by pysat and not the user. + * Altitude accuracy expected to be on the order of 10 km in Low Earth Orbit. + Efforts to improve accuracy documented under issue #79. Example ------- :: - TLE1='1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998' - TLE2='2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452' - inst = pysat.Instrument('pysat', 'sgp4', TLE1=TLE1, TLE2=TLE2) + tle1='1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998' + tle2='2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452' + inst = pysat.Instrument('pysat', 'sgp4', tle1=tle1, tle2=tle2) inst.load(2018, 1) """ @@ -177,10 +174,10 @@ def load(fnames, tag=None, inst_id=None, TLE1=None, TLE2=None, line2 = '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452' # If provided, use user-specified TLEs. Otherwise use ISS defaults above. - if TLE1 is not None: - line1 = TLE1 - if TLE2 is not None: - line2 = TLE2 + if tle1 is not None: + line1 = tle1 + if tle2 is not None: + line2 = tle2 if (num_samples is None) or one_orbit: num_samples = 86400 diff --git a/pysatMissions/tests/test_deprecation.py b/pysatMissions/tests/test_deprecation.py index 5f9135cf..7ef08553 100644 --- a/pysatMissions/tests/test_deprecation.py +++ b/pysatMissions/tests/test_deprecation.py @@ -34,6 +34,9 @@ def eval_deprecation(self, warns, check_msgs, warn_type=DeprecationWarning): """ + # TODO(#82): Remove when pysat 3.0.2 is released. Replace with + # pysat.utils.testing.eval_warnings + # Ensure the minimum number of warnings were raised assert len(warns) >= len(check_msgs) @@ -60,5 +63,8 @@ def test_ephem_deprecation(self): warn_msgs = ["`missions_ephem` has been deprecated"] + # TODO(#82): Replace with pysat.utils.testing.eval_warnings when pysat + # 3.0.2 is released. + self.eval_deprecation(war, warn_msgs) return diff --git a/pysatMissions/tests/test_inst_methods_orbits.py b/pysatMissions/tests/test_inst_methods_orbits.py index 336964c2..0a08e2ce 100644 --- a/pysatMissions/tests/test_inst_methods_orbits.py +++ b/pysatMissions/tests/test_inst_methods_orbits.py @@ -1,6 +1,7 @@ """Unit tests for `pysatMissions.instruments.methods.orbits`.""" import pysatMissions.instruments.methods.orbits as mm_orbits + import pytest From 153ad13ece6d5902e05c1069ce6d2cffd1834bb3 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 2 May 2022 13:25:07 -0400 Subject: [PATCH 135/147] BUG: add all requirements --- docs/requirements.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 3183e060..f7183e75 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,12 @@ ipython m2r2 -numpy numpydoc +aacgmv2 +apexpy +geospacepy +numpy +OMMBV>=1.0 +pandas +pysat>=3.0 +pyEphem +sgp4>=2.7 From 52e29a891a2a63f7f074062346310cef573b475e Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 2 May 2022 16:14:00 -0400 Subject: [PATCH 136/147] BUG: update standards --- pysatMissions/tests/test_instruments.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pysatMissions/tests/test_instruments.py b/pysatMissions/tests/test_instruments.py index ff5c0bfc..7618cb9d 100644 --- a/pysatMissions/tests/test_instruments.py +++ b/pysatMissions/tests/test_instruments.py @@ -151,8 +151,8 @@ def test_inst_cadence(self, inst_dict, kwarg, output): [{'one_orbit': True}, {'inclination': 13, 'alt_periapsis': 400, 'alt_apoapsis': 850, 'bstar': 0, 'arg_periapsis': 0., 'raan': 0., 'mean_anomaly': 0.}, - {'TLE1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998', - 'TLE2': '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452'} + {'tle1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998', + 'tle2': '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452'} ]) def test_sgp4_options(self, kw_dict): """Test optional keywords for sgp4.""" @@ -171,7 +171,7 @@ def test_sgp4_options(self, kw_dict): @pytest.mark.parametrize( "kw_dict", [{'inclination': 13, 'alt_apoapsis': 850}, - {'TLE1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998'} + {'tle1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998'} ]) def test_sgp4_options_errors(self, kw_dict): """Test optional keyword combos for sgp4 that generate errors.""" @@ -187,8 +187,8 @@ def test_sgp4_options_errors(self, kw_dict): "kw_dict", [{'inclination': 13, 'alt_periapsis': 400, 'alt_apoapsis': 850, 'bstar': 0, 'arg_periapsis': 0., 'raan': 0., 'mean_anomaly': 0., - 'TLE1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998', - 'TLE2': '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452'} + 'tle1': '1 25544U 98067A 18135.61844383 .00002728 00000-0 48567-4 0 9998', + 'tle2': '2 25544 51.6402 181.0633 0004018 88.8954 22.2246 15.54059185113452'} ]) def test_sgp4_options_warnings(self, kw_dict): """Test optional keyword combos for sgp4 that generate warnings.""" From 49e4ff6e5ae4c3213872440685af42f335ef065f Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 2 May 2022 18:28:03 -0400 Subject: [PATCH 137/147] BUG: revenge of the TLE --- pysatMissions/instruments/methods/orbits.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pysatMissions/instruments/methods/orbits.py b/pysatMissions/instruments/methods/orbits.py index 28b7a01d..20d05754 100644 --- a/pysatMissions/instruments/methods/orbits.py +++ b/pysatMissions/instruments/methods/orbits.py @@ -18,7 +18,7 @@ def _check_orbital_params(kwargs): req_elements = list(kwargs['load'].keys()) keplerians = ['alt_periapsis', 'inclination'] - tles = ['TLE1', 'TLE2'] + tles = ['tle1', 'tle2'] errmsg = 'Insufficient kwargs. Kwarg group requires {:}' for group in [tles, keplerians]: bools = [item in req_elements for item in group] From fcf57b8bcaefe6b16d1d4be4906f8b77d628fe05 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 2 May 2022 18:43:50 -0400 Subject: [PATCH 138/147] DOC: update contributing info --- CONTRIBUTING.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3547d9b6..503963db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,14 +65,22 @@ To set up `pysatMissions` for local development: 5. Update/add documentation (in ``docs``), if relevant -6. Commit your changes and push your branch to GitHub: +6. Commit your changes: ``` - git add . - git commit -m "Brief description of your changes" - git push origin name-of-your-bugfix-or-feature + git add . + git commit -m "AAA: Brief description of your changes" ``` + Where AAA is a standard shorthand for the type of change (eg, BUG or DOC). + `pysat` follows the [numpy development workflow](https://numpy.org/doc/stable/dev/development_workflow.html), + see the discussion there for a full list of this shorthand notation. -7. Submit a pull request through the GitHub website. Pull requests should be +7. Once you are happy with the local changes, push to Github: + ``` + git push origin name-of-your-bugfix-or-feature + ``` + Note that each push will trigger the Continuous Integration workflow. + +8. Submit a pull request through the GitHub website. Pull requests should be made to the ``develop`` branch. Pull Request Guidelines From 22dd53a4c93728f16014af1d105d4f9257508bf8 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Mon, 2 May 2022 18:59:35 -0400 Subject: [PATCH 139/147] BUG: readthedocs --- pysatMissions/methods/magcoord.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pysatMissions/methods/magcoord.py b/pysatMissions/methods/magcoord.py index 93a6075f..593bed15 100644 --- a/pysatMissions/methods/magcoord.py +++ b/pysatMissions/methods/magcoord.py @@ -2,7 +2,16 @@ """ import aacgmv2 -import apexpy +import pysat + +try: + # Warn user if apexpy is not configured. Bypass needed to function on + # readthedocs. + import apexpy +except ImportError as ierr: + pysat.logger.warning("".join(["apexpy module could not be imported. ", + "apexpy interface won't work.", + "Failed with error: ", str(ierr)])) def add_aacgm_coordinates(inst, glat_label='glat', glong_label='glong', From 40ab1ea81c7a33bb20e3c59c770bb797385b20fa Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Wed, 4 May 2022 10:51:33 -0400 Subject: [PATCH 140/147] DOC: update contributing --- CONTRIBUTING.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 503963db..be2930dd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,6 +4,11 @@ Contributing Bug reports, feature suggestions and other contributions are greatly appreciated! pysatMissions is a community-driven project and welcomes both feedback and contributions. +Come join us on Slack! An invitation to the pysat workspace is available +in the 'About' section of the +[pysat GitHub Repository.](https://github.com/pysat/pysat) Development meetings +are generally held fortnightly. + Short version ------------- @@ -65,7 +70,9 @@ To set up `pysatMissions` for local development: 5. Update/add documentation (in ``docs``), if relevant -6. Commit your changes: +6. Add your name to the .zenodo.json file as an author + +7. Commit your changes: ``` git add . git commit -m "AAA: Brief description of your changes" @@ -74,13 +81,13 @@ To set up `pysatMissions` for local development: `pysat` follows the [numpy development workflow](https://numpy.org/doc/stable/dev/development_workflow.html), see the discussion there for a full list of this shorthand notation. -7. Once you are happy with the local changes, push to Github: +8. Once you are happy with the local changes, push to Github: ``` git push origin name-of-your-bugfix-or-feature ``` Note that each push will trigger the Continuous Integration workflow. -8. Submit a pull request through the GitHub website. Pull requests should be +9. Submit a pull request through the GitHub website. Pull requests should be made to the ``develop`` branch. Pull Request Guidelines From f39977e0d564ab66ad6719a24eb7e65884119c69 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 May 2022 13:54:56 -0400 Subject: [PATCH 141/147] DOC: comments --- pysatMissions/methods/magcoord.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pysatMissions/methods/magcoord.py b/pysatMissions/methods/magcoord.py index 593bed15..94b7f968 100644 --- a/pysatMissions/methods/magcoord.py +++ b/pysatMissions/methods/magcoord.py @@ -6,12 +6,13 @@ try: # Warn user if apexpy is not configured. Bypass needed to function on - # readthedocs. + # readthedocs. Use of apexpy functions elsewhere in code will produce + # errors. import apexpy except ImportError as ierr: - pysat.logger.warning("".join(["apexpy module could not be imported. ", - "apexpy interface won't work.", - "Failed with error: ", str(ierr)])) + pysat.logger.warning(" ".join(["apexpy module could not be imported.", + "apexpy interface won't work.", + "Failed with error:", str(ierr)])) def add_aacgm_coordinates(inst, glat_label='glat', glong_label='glong', From 6189f819af5747c9c244c0cde4289ac6f8487b39 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 6 May 2022 13:55:40 -0400 Subject: [PATCH 142/147] DOC: update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e1933f0..2a109456 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). * Update syntax to be compliant with OMMBV 1.0 * Documentation * Improve docstrings throughout + * Added bypass for apexpy for readthedocs build * Deprecations * Deprecated missions_ephem, as pyephem will no longer be updated * Testing From ebcec364e9c1176d35bcb40b128937b84aa69214 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 13 May 2022 13:02:06 -0400 Subject: [PATCH 143/147] DOC: update tutorial --- docs/tutorial.rst | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 90a9b709..9dbc23e4 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -62,20 +62,21 @@ Empirical Models A number of methods are included to invoke several python wrappers for empirical models. This includes the aacgmv2, apexpy, and OMMBV models. These methods can be added to any pysat instrument using the `custom` functions in -pysat. The example below adds the aacgmv2 coordinates to one of the test -instruments in the core pysat package. +pysat. The example below adds the aacgmv2 coordinates to sgp4 instrument. .. code:: python import pysat from pysatMissions.methods import magcoord - inst = pysat.Instrument(platform='pysat', name='testing') - inst.custom_attach(magcoord.add_aacgm_coordinates, - kwargs={'glat_label': 'latitude', - 'glong_label': 'longitude', - 'alt_label': 'altitude'}) + sgp4 = pysat.Instrument(inst_module=missions_sgp4, num_samples=3600) + sgp4.custom_attach(magcoord.add_aacgm_coordinates, + kwargs={'glat_label': 'geod_latitude', + 'glong_label': 'geod_longitude', + 'alt_label': 'geod_altitude'}) + sgp4.load(2019, 1) Note that the latitude, longitude, and altitude variable names of the instrument should be specified since the dataset may use different variable -names from those in the custom function. +names from those in the custom function. The method to add these empirical +functions to a pysat instrument is identical across the pysat ecosystem. From bf49cdd9214683a33ac14af5119a34181e28299f Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 13 May 2022 13:05:53 -0400 Subject: [PATCH 144/147] DOC: add methods api --- docs/index.rst | 1 + docs/methods.rst | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 docs/methods.rst diff --git a/docs/index.rst b/docs/index.rst index 7481ba08..e70257dc 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -14,6 +14,7 @@ as well as apply geomagnetic field models to existing pysat instruments. installation.rst citing.rst supported_instruments.rst + methods.rst tutorial.rst references.rst develop_guide.rst diff --git a/docs/methods.rst b/docs/methods.rst new file mode 100644 index 00000000..d638048c --- /dev/null +++ b/docs/methods.rst @@ -0,0 +1,34 @@ +.. _methods: + +Utilities +========= + + +.. _methods-magcoord: + +magcoord +--------- +.. automodule:: pysatMissions.methods.magcoord + :members: + + +.. _methods-spacecraft: + +spacecraft +---------- +.. automodule:: pysatMissions.methods.spacecraft + :members: + + +.. _inst-methods: + +Instrument Methods +================== + + +.. _inst-methods-orbits: + +Orbits +------- +.. automodule:: pysatMissions.instruments.methods.orbits + :members: From 4671c2f15db783a4a9ad136beee9062d9b064a23 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 13 May 2022 13:08:52 -0400 Subject: [PATCH 145/147] BUG: update doc --- docs/methods.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/methods.rst b/docs/methods.rst index d638048c..86171193 100644 --- a/docs/methods.rst +++ b/docs/methods.rst @@ -1,7 +1,7 @@ .. _methods: -Utilities -========= +Methods +======= .. _methods-magcoord: From 0ce8c3379b8fd208eb21af82bea9d10f2c3c55c2 Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 13 May 2022 13:09:12 -0400 Subject: [PATCH 146/147] DOC: add release date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a109456..6899c024 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/). -## [0.3.0] - 2022-XX-XX +## [0.3.0] - 2022-05-13 * Add Keplerian orbital inputs into missions_sgp4 * Update sgp4 interface to use new syntax for initialization from TLEs * Include conversions to geodetic latitude / longitude / altitude for sgp4 From b22165362907f27abdb4892d07e58a35ced0cc4a Mon Sep 17 00:00:00 2001 From: Jeff Klenzing Date: Fri, 13 May 2022 13:31:17 -0400 Subject: [PATCH 147/147] DOC: update reqs --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a23c0f4b..99948a2a 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Documentation pysatMissions uses common Python modules, as well as modules developed by and for the Space Physics community. This module officially supports -Python 3.7+. +Python 3.8+. | Common modules | Community modules | | -------------- | ----------------- |