From 7eb72201c0fcaf15347f9b0a0f7c08ee26ea2ace Mon Sep 17 00:00:00 2001 From: Spencer Nelson Date: Wed, 18 Oct 2023 12:30:36 -0700 Subject: [PATCH] Delete unused code and remove private stuff from public APIs --- adam_core/constants.py | 15 +- adam_core/coordinates/__init__.py | 52 +--- adam_core/coordinates/cartesian.py | 6 +- adam_core/coordinates/cometary.py | 9 - adam_core/coordinates/conversions.py | 176 -------------- adam_core/coordinates/covariances.py | 281 +--------------------- adam_core/coordinates/keplerian.py | 9 - adam_core/coordinates/origin.py | 1 - adam_core/coordinates/spherical.py | 9 - adam_core/coordinates/tests/test_times.py | 60 ----- adam_core/coordinates/times.py | 158 ------------ adam_core/dynamics/__init__.py | 7 - adam_core/observations/__init__.py | 2 + adam_core/observers/tests/test_state.py | 2 +- adam_core/orbits/__init__.py | 2 + adam_core/orbits/query/__init__.py | 2 +- adam_core/tests/test_imports.py | 4 +- 17 files changed, 20 insertions(+), 775 deletions(-) delete mode 100644 adam_core/coordinates/conversions.py delete mode 100644 adam_core/coordinates/tests/test_times.py delete mode 100644 adam_core/coordinates/times.py diff --git a/adam_core/constants.py b/adam_core/constants.py index ef6e107a..2a07cdfc 100644 --- a/adam_core/constants.py +++ b/adam_core/constants.py @@ -4,7 +4,6 @@ "KM_P_AU", "S_P_DAY", "Constants", - "DE43X", "DE44X", ] @@ -35,18 +34,6 @@ def __init__(self, C=None, MU=None, R_Earth=None, Obliquity=None): return -DE43X_CONSTANTS = { - # Speed of Light : au / d (299792.458 km / s -- DE430/DE431) - "C": 299792.458 / KM_P_AU * S_P_DAY, - # Standard Gravitational Parameter -- Sun : au**3 / d**2 (0.295912208285591100E-3 -- DE431/DE430) - "MU": 0.295912208285591100e-3, - # Earth Equatorial Radius: au (6378.1363 km -- DE431/DE430) - "R_Earth": 6378.1363 / KM_P_AU, - # Mean Obliquity at J2000: radians (84381.448 arcseconds -- DE431/DE430) - "Obliquity": 84381.448 * np.pi / (180.0 * 3600.0), -} -Constants = DE43X = _Constants(**DE43X_CONSTANTS) - DE44X_CONSTANTS = { # Speed of Light : au / d (299792.458 km / s -- DE430/DE431) "C": 299792.458 / KM_P_AU * S_P_DAY, @@ -57,4 +44,4 @@ def __init__(self, C=None, MU=None, R_Earth=None, Obliquity=None): # Mean Obliquity at J2000: radians (84381.448 arcseconds -- DE431/DE430) "Obliquity": 84381.448 * np.pi / (180.0 * 3600.0), } -DE44X = _Constants(**DE44X_CONSTANTS) +DE44X = Constants = _Constants(**DE44X_CONSTANTS) diff --git a/adam_core/coordinates/__init__.py b/adam_core/coordinates/__init__.py index 62c36089..0c4277cf 100644 --- a/adam_core/coordinates/__init__.py +++ b/adam_core/coordinates/__init__.py @@ -1,43 +1,11 @@ # flake8: noqa: F401 -from .cartesian import CARTESIAN_COLS, CARTESIAN_UNITS, CartesianCoordinates -from .cometary import COMETARY_COLS, COMETARY_UNITS, CometaryCoordinates -from .conversions import convert_coordinates -from .covariances import ( - CoordinateCovariances, - covariances_from_df, - covariances_to_df, - covariances_to_table, - sample_covariance_random, - sample_covariance_sigma_points, - sigmas_from_df, - sigmas_to_df, - transform_covariances_jacobian, - transform_covariances_sampling, - weighted_covariance, - weighted_mean, -) -from .jacobian import calc_jacobian -from .keplerian import KEPLERIAN_COLS, KEPLERIAN_UNITS, KeplerianCoordinates -from .origin import Origin, OriginCodes, OriginGravitationalParameters -from .residuals import Residuals -from .spherical import SPHERICAL_COLS, SPHERICAL_UNITS, SphericalCoordinates -from .times import Times -from .transform import ( - _cartesian_to_cometary, - _cartesian_to_keplerian, - _cartesian_to_keplerian6, - _cartesian_to_spherical, - _cometary_to_cartesian, - _keplerian_to_cartesian_a, - _keplerian_to_cartesian_p, - _keplerian_to_cartesian_q, - _spherical_to_cartesian, - cartesian_to_cometary, - cartesian_to_keplerian, - cartesian_to_spherical, - cometary_to_cartesian, - keplerian_to_cartesian, - spherical_to_cartesian, - transform_coordinates, -) -from .variants import create_coordinate_variants +from .cartesian import CartesianCoordinates +from .cometary import CometaryCoordinates +from .covariances import CoordinateCovariances +from .keplerian import KeplerianCoordinates +from .origin import Origin, OriginCodes +from .spherical import SphericalCoordinates +from .transform import transform_coordinates + +# TODO: move this to an 'experimental' module +# from .residuals import Residuals diff --git a/adam_core/coordinates/cartesian.py b/adam_core/coordinates/cartesian.py index a6840c6b..8e8fc35b 100644 --- a/adam_core/coordinates/cartesian.py +++ b/adam_core/coordinates/cartesian.py @@ -3,7 +3,6 @@ import numpy as np import quivr as qv -from astropy import units as u from ..time import Timestamp from .covariances import CoordinateCovariances @@ -14,16 +13,13 @@ from .keplerian import KeplerianCoordinates from .spherical import SphericalCoordinates -__all__ = ["CartesianCoordinates", "CARTESIAN_COLS", "CARTESIAN_UNITS"] +__all__ = ["CartesianCoordinates"] CARTESIAN_COLS = {} -CARTESIAN_UNITS = {} for i in ["x", "y", "z"]: CARTESIAN_COLS[i] = i - CARTESIAN_UNITS[i] = u.au for i in ["vx", "vy", "vz"]: CARTESIAN_COLS[i] = i - CARTESIAN_UNITS[i] = u.au / u.d COVARIANCE_ROTATION_TOLERANCE = 1e-25 logger = logging.getLogger(__name__) diff --git a/adam_core/coordinates/cometary.py b/adam_core/coordinates/cometary.py index f5488b22..39946fd1 100644 --- a/adam_core/coordinates/cometary.py +++ b/adam_core/coordinates/cometary.py @@ -2,7 +2,6 @@ import numpy as np import quivr as qv -from astropy import units as u from ..time import Timestamp from .cartesian import CartesianCoordinates @@ -17,19 +16,11 @@ __all__ = [ "CometaryCoordinates", "COMETARY_COLS", - "COMETARY_UNITS", ] COMETARY_COLS = {} -COMETARY_UNITS = {} for i in ["q", "e", "i", "raan", "ap", "tp"]: COMETARY_COLS[i] = i -COMETARY_UNITS["q"] = u.au -COMETARY_UNITS["e"] = u.dimensionless_unscaled -COMETARY_UNITS["i"] = u.deg -COMETARY_UNITS["raan"] = u.deg -COMETARY_UNITS["ap"] = u.deg -COMETARY_UNITS["tp"] = u.d class CometaryCoordinates(qv.Table): diff --git a/adam_core/coordinates/conversions.py b/adam_core/coordinates/conversions.py deleted file mode 100644 index b2ed93c6..00000000 --- a/adam_core/coordinates/conversions.py +++ /dev/null @@ -1,176 +0,0 @@ -from copy import deepcopy -from typing import List, Union - -import numpy as np - - -def _convert_coordinates_units( - coords: Union[np.ndarray, np.ma.masked_array], units: List, desired_units: List -) -> Union[np.ndarray, np.ma.masked_array]: - """ - Convert coordinate units to desired units. - - Parameters - ---------- - coords : `~numpy.ndarray` or `~numpy.ma.masked_array` (N, D) - Coordinates that need to be converted. - units : List (D) - Current units for each coordinate dimension. - desired_units : List (D) - Desired units for each coordinate dimension. - - Returns - ------- - coords_converted : `~numpy.ndarray` or `~numpy.ma.masked_array` (N, D) - Coordinates converted to the desired coordinate units. - - Raises - ------ - ValueError : If units or desired_units do not have length D. - """ - N, D = coords.shape - coords_converted = coords.copy() - - if (len(units) != D) or (len(desired_units) != D): - err = f"Length of units or desired_units does not match the number of coordinate dimensions (D={D})" - raise ValueError(err) - - for i in range(D): - coords_converted[:, i] = coords[:, i] * units[i].to(desired_units[i]) - - return coords_converted - - -def _convert_covariances_units( - covariances: Union[np.ndarray, np.ma.masked_array], - units: np.ndarray, - desired_units: np.ndarray, -) -> Union[np.ndarray, np.ma.masked_array]: - """ - Convert covariance units to desired units. - - Parameters - ---------- - covariances : `~numpy.ndarray` or `~numpy.ma.masked_array` (N, D, D) - Covariances that need to be converted. - units : `~numpy.ndarray` (D) - Current units for each coordinate dimension. Note, these are not the units for - the elements of the covariance matrices but the actual units of the mean values/states to - which the covariance matrices belong. - desired_units : `~numpy.ndarray` (D) - Desired units for each coordinate dimension. - - Returns - ------- - covariances_converted : `~numpy.ndarray` or `~numpy.ma.masked_array` (N, D, D) - Covariances converted to the desired coordinate units. - - Raises - ------ - ValueError : If units or desired_units do not have length D. - """ - N, D, D = covariances.shape - - if (len(units) != D) or (len(desired_units) != D): - err = f"Length of units or desired_units does not match the number of coordinate dimensions (D={D})" - raise ValueError(err) - - coords_units_2d = units.copy().reshape(1, -1) - covariance_units = np.dot(coords_units_2d.T, coords_units_2d) - - desired_units_2d = desired_units.copy().reshape(1, -1) - desired_units = np.dot(desired_units_2d.T, desired_units_2d) - - conversion_matrix = np.zeros((D, D), dtype=np.float64) - for i in range(D): - for j in range(D): - conversion_matrix[i, j] = covariance_units[i, j].to(desired_units[i, j]) - - covariances_converted = conversion_matrix * covariances - - return covariances_converted - - -def convert_coordinates( - coords, - desired_units: Union[List, dict], -): - """ - Convert coordinates to desired units. - - Parameters - ---------- - coords : `~thor.coordinates.Coordinates` (N, D) - Coordinates that need to be converted. - desired_units : list, `~numpy.ndarray`, dict - Desired units for each coordinate dimension expressed as an array-like - or a dictionary keyed on coordinate dimensions and with values that represent - the desired units. If a dictionary is passed, then only the coordinate dimensions - that need to be converted need to be defined. - - desired_units = { - "x" : u.km - } - coordinates_converted = convert_coordinates(coords, desired_units) - - Returns - ------- - coords_converted : `~thor.coordinates.Coordinates` (N, D) - Coordinates converted to the desired coordinate units. - - Raises - ------ - ValueError : If units or desired_units do not have length D. - ValueError : If desired_units is not a list, `~numpy.ndarray`, dict - """ - N, D = coords.values.shape - - desired_units_ = {} - if isinstance(desired_units, dict): - for k, v in coords.units.items(): - if k not in desired_units: - desired_units_[k] = v - else: - desired_units_[k] = desired_units[k] - - elif isinstance(desired_units, (list, np.ndarray)): - if len(desired_units) != D: - err = ( - "Length of units or desired_units does not match the" - f" number of coordinate dimensions (D={D})" - ) - raise ValueError(err) - - for i, (k, v) in enumerate(coords.units.items()): - desired_units_[k] = desired_units[i] - - else: - err = "desired_units should be one of {list, '~numpy.ndarray`, dict}" - raise ValueError(err) - - # Make a copy of the input coordinates - coords_converted = deepcopy(coords) - desired_units_array = np.array(list(desired_units_.values())) - current_units = np.array(list(coords.units.values())) - - # Modify the underlying coordinates array - values_converted = _convert_coordinates_units( - coords.values, - current_units, - desired_units_array, - ) - coords_converted._values = values_converted - - # Modify the underlying covariance matrices - if coords.covariances is not None: - covariances_converted = _convert_covariances_units( - coords.covariances, - current_units, - desired_units_array, - ) - coords_converted._covariances = covariances_converted - - # Update the units dictionary to reflect the new units - coords_converted._units = desired_units_ - - return coords_converted diff --git a/adam_core/coordinates/covariances.py b/adam_core/coordinates/covariances.py index e2a91e25..548ff782 100644 --- a/adam_core/coordinates/covariances.py +++ b/adam_core/coordinates/covariances.py @@ -1,12 +1,9 @@ import logging -from typing import Callable, List, Tuple +from typing import Callable, Tuple import numpy as np -import pandas as pd import pyarrow as pa import quivr as qv -from astropy import units as u -from astropy.table import Table as AstropyTable from scipy.linalg import sqrtm from scipy.stats import multivariate_normal @@ -420,279 +417,3 @@ def transform_covariances_jacobian( jacobian = calc_jacobian(coords, _func, **kwargs) covariances = jacobian @ covariances @ np.transpose(jacobian, axes=(0, 2, 1)) return covariances - - -def sigmas_to_df( - sigmas: np.ndarray, - coord_names: List[str] = ["x", "y", "z", "vx", "vy", "vz"], -) -> pd.DataFrame: - """ - Place sigmas into a `pandas.DataFrame`. - - Parameters - ---------- - sigmas : `~numpy.ndarray` (N, D) - 1-sigma uncertainty values for each coordinate dimension D. - coord_names : List[str] - Names of the coordinate columns, will be used to determine column names for - each element in the triangular covariance matrix. - - Returns - ------- - df : `~pandas.DataFrame` - DataFrame containing covariances in either upper or lower triangular - form. - """ - N, D = sigmas.shape - - data = {} - for i in range(D): - data[f"sigma_{coord_names[i]}"] = sigmas[:, i] - - return pd.DataFrame(data) - - -def sigmas_from_df( - df: pd.DataFrame, - coord_names: List[str] = ["x", "y", "z", "vx", "vy", "vz"], -) -> np.ndarray: - """ - Read sigmas from a `~pandas.DataFrame`. - - Parameters - ---------- - df : `~pandas.DataFrame` - DataFrame containing covariances in either upper or lower triangular - form. - coord_names : List[str] - Names of the coordinate columns, will be used to determine column names for - each element in the triangular covariance matrix. - - Returns - ------- - sigmas : `~numpy.ndarray` (N, D) - 1-sigma uncertainty values for each coordinate dimension D. - """ - N = len(df) - D = len(coord_names) - sigmas = np.zeros((N, D), dtype=np.float64) - sigmas.fill(COVARIANCE_FILL_VALUE) - - for i in range(D): - try: - sigmas[:, i] = df[f"sigma_{coord_names[i]}"].values - - except KeyError: - logger.debug(f"No sigma column found for dimension {coord_names[i]}.") - - return sigmas - - -def covariances_to_df( - covariances: np.ndarray, - coord_names: List[str] = ["x", "y", "z", "vx", "vy", "vz"], - kind: str = "lower", -) -> pd.DataFrame: - """ - Place covariance matrices into a `pandas.DataFrame`. Splits the covariance matrices - into either upper or lower triangular form and then adds one column per dimension. - - Parameters - ---------- - covariances : `~numpy.ndarray` (N, D, D) - 3D array of covariance matrices. - coord_names : List[str] - Names of the coordinate columns, will be used to determine column names for - each element in the triangular covariance matrix. - kind : {'upper', 'lower'} - The orientation of the triangular representation. - - Returns - ------- - df : `~pandas.DataFrame` - DataFrame containing covariances in either upper or lower triangular - form. - - Raises - ------ - ValueError : If kind is not one of {'upper', 'lower'} - - """ - N, D, D = covariances.shape - - if kind == "upper": - ii, jj = np.triu_indices(D) - elif kind == "lower": - ii, jj = np.tril_indices(D) - else: - err = "kind should be one of {'upper', 'lower'}" - raise ValueError(err) - - data = {} - for i, j in zip(ii, jj): - data[f"cov_{coord_names[i]}_{coord_names[j]}"] = covariances[:, i, j] - - return pd.DataFrame(data) - - -def covariances_from_df( - df: pd.DataFrame, - coord_names: List[str] = ["x", "y", "z", "vx", "vy", "vz"], - kind: str = "lower", -) -> np.ndarray: - """ - Read covariance matrices from a `~pandas.DataFrame`. - - Parameters - ---------- - df : `~pandas.DataFrame` - DataFrame containing covariances in either upper or lower triangular - form. - coord_names : List[str] - Names of the coordinate columns, will be used to determine column names for - each element in the triangular covariance matrix. - kind : {'upper', 'lower'} - The orientation of the triangular representation. - - Returns - ------- - covariances : `~numpy.ndarray` (N, D, D) - 3D array of covariance matrices. - - Raises - ------ - ValueError : If kind is not one of {'upper', 'lower'} - """ - N = len(df) - D = len(coord_names) - covariances = np.zeros((N, D, D), dtype=np.float64) - covariances.fill(COVARIANCE_FILL_VALUE) - - if kind == "upper": - ii, jj = np.triu_indices(D) - elif kind == "lower": - ii, jj = np.tril_indices(D) - else: - err = "kind should be one of {'upper', 'lower'}" - raise ValueError(err) - - for i, j in zip(ii, jj): - try: - covariances[:, i, j] = df[f"cov_{coord_names[i]}_{coord_names[j]}"].values - covariances[:, j, i] = covariances[:, i, j] - except KeyError: - logger.debug( - "No covariance column found for dimensions" - f" {coord_names[i]},{coord_names[j]}." - ) - - return covariances - - -def covariances_to_table( - covariances: np.ma.masked_array, - coord_names: List[str] = ["x", "y", "z", "vx", "vy", "vz"], - coord_units=[u.au, u.au, u.au, u.au / u.d, u.au / u.d, u.au / u.d], - kind: str = "lower", -) -> AstropyTable: - """ - Place covariance matrices into a `astropy.table.table.Table`. Splits the covariance matrices - into either upper or lower triangular form and then adds one column per dimension. - - Parameters - ---------- - covariances : `~numpy.ma.masked_array` (N, D, D) - 3D array of covariance matrices. - coord_names : List[str] - Names of the coordinate columns, will be used to determine column names for - each element in the triangular covariance matrix. - coord_units : List[] - The unit for each coordinate, will be used to determination the units for - element in the triangular covariance matrix. - kind : {'upper', 'lower'} - The orientation of the triangular representation. - - Returns - ------- - table : `~astropy.table.table.Table` - Table containing covariances in either upper or lower triangular - form. - - Raises - ------ - ValueError : If kind is not one of {'upper', 'lower'} - """ - N, D, D = covariances.shape - - if kind == "upper": - ii, jj = np.triu_indices(D) - elif kind == "lower": - ii, jj = np.tril_indices(D) - else: - err = "kind should be one of {'upper', 'lower'}" - raise ValueError(err) - - data = {} - for i, j in zip(ii, jj): - data[f"cov_{coord_names[i]}_{coord_names[j]}"] = ( - covariances[:, i, j] * coord_units[i] * coord_units[j] - ) - - return AstropyTable(data) - - -def covariances_from_table( - table: AstropyTable, - coord_names: List[str] = ["x", "y", "z", "vx", "vy", "vz"], - kind: str = "lower", -) -> np.ma.masked_array: - """ - Read covariance matrices from a `~astropy.table.table.Table`. - - Parameters - ---------- - table : `~astropy.table.table.Table` - Table containing covariances in either upper or lower triangular - form. - coord_names : List[str] - Names of the coordinate columns, will be used to determine column names for - each element in the triangular covariance matrix. - kind : {'upper', 'lower'} - The orientation of the triangular representation. - - Returns - ------- - covariances : `~numpy.ma.masked_array` (N, D, D) - 3D array of covariance matrices. - - Raises - ------ - ValueError : If kind is not one of {'upper', 'lower'} - """ - N = len(table) - D = len(coord_names) - covariances = np.ma.zeros((N, D, D), dtype=np.float64) - covariances.fill_value = COVARIANCE_FILL_VALUE - covariances.mask = np.ones((N, D, D), dtype=bool) - - if kind == "upper": - ii, jj = np.triu_indices(D) - elif kind == "lower": - ii, jj = np.tril_indices(D) - else: - err = "kind should be one of {'upper', 'lower'}" - raise ValueError(err) - - for i, j in zip(ii, jj): - try: - covariances[:, i, j] = table[ - f"cov_{coord_names[i]}_{coord_names[j]}" - ].values - covariances[:, j, i] = covariances[:, i, j] - except KeyError: - logger.debug( - "No covariance column found for dimensions" - f" {coord_names[i]},{coord_names[j]}." - ) - - return covariances diff --git a/adam_core/coordinates/keplerian.py b/adam_core/coordinates/keplerian.py index 0d474b31..f5b6c831 100644 --- a/adam_core/coordinates/keplerian.py +++ b/adam_core/coordinates/keplerian.py @@ -2,7 +2,6 @@ import numpy as np import quivr as qv -from astropy import units as u from ..time import Timestamp from .cartesian import CartesianCoordinates @@ -17,19 +16,11 @@ __all__ = [ "KeplerianCoordinates", "KEPLERIAN_COLS", - "KEPLERIAN_UNITS", ] KEPLERIAN_COLS = {} -KEPLERIAN_UNITS = {} for i in ["a", "e", "i", "raan", "ap", "M"]: KEPLERIAN_COLS[i] = i -KEPLERIAN_UNITS["a"] = u.au -KEPLERIAN_UNITS["e"] = u.dimensionless_unscaled -KEPLERIAN_UNITS["i"] = u.deg -KEPLERIAN_UNITS["raan"] = u.deg -KEPLERIAN_UNITS["ap"] = u.deg -KEPLERIAN_UNITS["M"] = u.deg class KeplerianCoordinates(qv.Table): diff --git a/adam_core/coordinates/origin.py b/adam_core/coordinates/origin.py index a9fc8595..8ebedd75 100644 --- a/adam_core/coordinates/origin.py +++ b/adam_core/coordinates/origin.py @@ -84,7 +84,6 @@ def SOLAR_SYSTEM_BARYCENTER(cls) -> float: # TODO: Replace with DictionaryColumn or similar # Investigate whether this class is even necessary class Origin(qv.Table): - code = qv.StringColumn() def __eq__(self, other: object) -> np.ndarray: diff --git a/adam_core/coordinates/spherical.py b/adam_core/coordinates/spherical.py index fcff76e6..ecbba2cc 100644 --- a/adam_core/coordinates/spherical.py +++ b/adam_core/coordinates/spherical.py @@ -2,7 +2,6 @@ import numpy as np import quivr as qv -from astropy import units as u from ..time import Timestamp from .cartesian import CartesianCoordinates @@ -17,19 +16,11 @@ __all__ = [ "SphericalCoordinates", "SPHERICAL_COLS", - "SPHERICAL_UNITS", ] SPHERICAL_COLS = {} -SPHERICAL_UNITS = {} for i in ["rho", "lon", "lat", "vrho", "vlon", "vlat"]: SPHERICAL_COLS[i] = i -SPHERICAL_UNITS["rho"] = u.au -SPHERICAL_UNITS["lon"] = u.deg -SPHERICAL_UNITS["lat"] = u.deg -SPHERICAL_UNITS["vrho"] = u.au / u.d -SPHERICAL_UNITS["vlon"] = u.deg / u.d -SPHERICAL_UNITS["vlat"] = u.deg / u.d class SphericalCoordinates(qv.Table): diff --git a/adam_core/coordinates/tests/test_times.py b/adam_core/coordinates/tests/test_times.py deleted file mode 100644 index 9a15b405..00000000 --- a/adam_core/coordinates/tests/test_times.py +++ /dev/null @@ -1,60 +0,0 @@ -import numpy as np -import pytest -from astropy.time import Time - -from ..times import Times - - -@pytest.mark.parametrize("scale", ["tdb", "utc", "tt"]) -def test_Times_to_from_astropy_roundtrip(scale): - # Test that we can round trip to and from astropy Time objects - times_astropy = Time( - np.linspace(50000.0, 60000.0, 1000), - format="mjd", - scale=scale, - ) - times = Times.from_astropy(times_astropy) - assert times.scale == scale - - times_astropy_2 = times.to_astropy() - np.testing.assert_equal(times_astropy_2.mjd, times_astropy.mjd) - - -def test_Times_to_scale(): - # Test that we can convert between time scales correctly - times_tdb = Time(np.arange(59000, 60000), scale="tdb", format="mjd") - times_tdb = Times.from_astropy(times_tdb) - assert times_tdb.scale == "tdb" - - times_utc = times_tdb.to_scale("utc") - assert times_utc.scale == "utc" - np.testing.assert_equal(times_utc.to_astropy().mjd, times_tdb.to_astropy().utc.mjd) - - -def test_Times_from_jd(): - # Test that we can create a Times object correctly from julian dates and a time scale - times_jd = np.linspace(2450000.5, 2460000.5, 1000, dtype=np.double) - times = Times.from_jd(times_jd, "utc") - - assert times.scale == "utc" - np.testing.assert_equal(times.jd().to_numpy(), times_jd) - - -def test_Times_from_mjd(): - # Test that we can create a Times object correctly from modified julian dates and a time scale - times_mjd = np.linspace(50000.0, 60000.0, 1000, dtype=np.double) - times = Times.from_mjd(times_mjd, "utc") - - # Surprised we can't do better here - assert times.scale == "utc" - np.testing.assert_allclose(times.mjd().to_numpy(), times_mjd, atol=0, rtol=1e-9) - - -def test_Times_unique(): - # Test that we can get unique times - times_jd = np.array([2450000.5, 2450000.5, 2450001.5]) - times = Times.from_jd(times_jd, "utc") - - times_unique = times.unique() - assert len(times_unique) == 2 - np.testing.assert_equal(times_unique.jd().to_numpy(), np.unique(times_jd)) diff --git a/adam_core/coordinates/times.py b/adam_core/coordinates/times.py deleted file mode 100644 index 9db87b14..00000000 --- a/adam_core/coordinates/times.py +++ /dev/null @@ -1,158 +0,0 @@ -from typing import Union - -import numpy as np -import pyarrow as pa -import pyarrow.compute as pc -import quivr as qv -from astropy.time import Time, TimeDelta -from typing_extensions import Self - - -class Times(qv.Table): - - # Stores the time as a pair of float64 values in the same style as erfa/astropy: - # The first one is the day-part of a Julian date, and the second is - # the fractional day-part. - jd1 = qv.Float64Column() - jd2 = qv.Float64Column() - scale = qv.StringAttribute(default="utc") - - @classmethod - def from_astropy(cls, time: Time): - if time.isscalar == 1: - jd1 = [time.jd1] - jd2 = [time.jd2] - else: - jd1 = time.jd1 - jd2 = time.jd2 - return cls.from_kwargs(jd1=jd1, jd2=jd2, scale=time.scale) - - def to_astropy(self, format: str = "jd") -> Time: - t = Time( - val=self.jd1.to_numpy(), - val2=self.jd2.to_numpy(), - format="jd", - scale=self.scale, - ) - if format == "jd": - return t - t.format = format - return t - - def to_scale(self, scale: str) -> Self: - """ - Convert to a different time scale. - - Parameters - ---------- - scale : str - The time scale to convert to. - - Returns - ------- - times : `~adam_core.coordinates.times.Times` - The times in the new scale. - """ - time = self.to_astropy() - time._set_scale(scale) - return self.from_astropy(time) - - def unique(self) -> Self: - """ - Return unique Times. - - Returns - ------- - unique : `~adam_core.coordinates.times.Times` - Unique Times. - """ - unique_jd = self.jd().unique() - return self.from_jd(unique_jd, self.scale) - - @classmethod - def from_jd(cls, jd: Union[np.ndarray, pa.lib.DoubleArray], scale: str) -> Self: - """ - Create a Times table from an array of julian dates (JD). - - Warning! In the range 24,010,000.5 - 24,099,999.5 JD (10,000 - 99,999 MJD) can at - most be accurate to ~10 ms when represented as a single 64-bit float. - - Parameters - ---------- - jd : {`~numpy.ndarray`, `~pyarrow.DoubleArray`} - An array of julian dates. - scale : str - The time scale. - - Returns - ------- - times : `~adam_core.coordinates.times.Times` - The times. - """ - if isinstance(jd, np.ndarray): - if jd.dtype != np.double: - jd = jd.astype(np.double) - jd = pa.array(jd) - - jd1 = pc.floor(jd) - jd2 = pc.subtract(jd, jd1) - return cls.from_kwargs(jd1=jd1, jd2=jd2, scale=scale) - - @classmethod - def from_mjd(cls, mjd: Union[np.ndarray, pa.lib.DoubleArray], scale: str) -> Self: - """ - Create a Times table from an array of modified julian dates (MJD). - - Warning! In the range 10,000 - 99,999 MJD can at most be accurate to ~0.1 ms when - represented as a single 64-bit float. - - Parameters - ---------- - mjd : {`~numpy.ndarray`, `~pyarrow.DoubleArray`} - An array of modified julian dates. - scale : str - The time scale. - - Returns - ------- - times : `~adam_core.coordinates.times.Times` - The times. - """ - if isinstance(mjd, np.ndarray): - if mjd.dtype != np.double: - mjd = mjd.astype(np.double) - mjd = pa.array(mjd) - - jd = pc.add(mjd, 2400000.5) - return cls.from_jd(jd, scale) - - def jd(self) -> pa.lib.DoubleArray: - """ - Returns the times as a double-precision array of julian date values. - - Warning! In the range 24,010,000.5 - 24,099,999.5 JD (10,000 - 99,999 MJD) can at - most be accurate to ~10 ms when represented as a single 64-bit float. - - Returns - ------- - jd : `~pyarrow.DoubleArray` - The times as a double-precision array of julian date values. - """ - return pc.add(self.jd1, self.jd2) - - def mjd(self) -> pa.lib.DoubleArray: - """ - Returns the times as a double-precision array of modified julian date values. - - Warning! In the range 10,000 - 99,999 MJD can at most be accurate to ~0.1 ms when - represented as a single 64-bit float. - - Returns - ------- - mjd : `~pyarrow.DoubleArray` - The times as a double-precision array of modified julian date values. - """ - return pc.add(pc.add(self.jd1, -2400000.5), self.jd2) - - def add(self, timedelta: TimeDelta) -> "Times": - return Times.from_astropy(self.to_astropy() + timedelta) diff --git a/adam_core/dynamics/__init__.py b/adam_core/dynamics/__init__.py index 3e53667c..cc5129d9 100644 --- a/adam_core/dynamics/__init__.py +++ b/adam_core/dynamics/__init__.py @@ -1,10 +1,3 @@ # flake8: noqa: F401 -from .aberrations import add_light_time, add_stellar_aberration -from .barker import solve_barker -from .chi import calc_chi from .ephemeris import generate_ephemeris_2body -from .kepler import solve_kepler -from .lagrange import apply_lagrange_coefficients, calc_lagrange_coefficients from .propagation import propagate_2body -from .stumpff import calc_stumpff -from .tisserand import calc_tisserand_parameter diff --git a/adam_core/observations/__init__.py b/adam_core/observations/__init__.py index 085caa73..3b9cb736 100644 --- a/adam_core/observations/__init__.py +++ b/adam_core/observations/__init__.py @@ -1,4 +1,6 @@ # flake8: noqa: F401 + +# TODO: associations - should it be in the API? its useful for test helpers, but kind of niche from .associations import Associations from .detections import PointSourceDetections from .exposures import Exposures diff --git a/adam_core/observers/tests/test_state.py b/adam_core/observers/tests/test_state.py index f58d5997..b8b5e2ad 100644 --- a/adam_core/observers/tests/test_state.py +++ b/adam_core/observers/tests/test_state.py @@ -4,9 +4,9 @@ import pytest from ...constants import KM_P_AU, S_P_DAY -from ...coordinates import Residuals from ...coordinates.cartesian import CartesianCoordinates from ...coordinates.origin import OriginCodes +from ...coordinates.residuals import Residuals from ...observers import get_observer_state from ...time import Timestamp from ...utils import get_perturber_state diff --git a/adam_core/orbits/__init__.py b/adam_core/orbits/__init__.py index a7622b5f..add8182d 100644 --- a/adam_core/orbits/__init__.py +++ b/adam_core/orbits/__init__.py @@ -1,4 +1,6 @@ # flake8: noqa: F401 + +# TODO: calc_orbit_class does not work currently, but would be nice as a method on Orbits from .classification import calc_orbit_class from .ephemeris import Ephemeris from .orbits import Orbits diff --git a/adam_core/orbits/query/__init__.py b/adam_core/orbits/query/__init__.py index 4e1ce2d7..c7fc1337 100644 --- a/adam_core/orbits/query/__init__.py +++ b/adam_core/orbits/query/__init__.py @@ -1,3 +1,3 @@ # flake8: noqa: F401 -from .horizons import query_horizons, query_horizons_ephemeris +from .horizons import query_horizons from .sbdb import query_sbdb diff --git a/adam_core/tests/test_imports.py b/adam_core/tests/test_imports.py index 23f5fd0f..1f04adc7 100644 --- a/adam_core/tests/test_imports.py +++ b/adam_core/tests/test_imports.py @@ -9,7 +9,7 @@ def test_import_orbits(): def test_import_dynamics(): - from adam_core.dynamics import calc_chi, calc_stumpff, propagate_2body + from adam_core.dynamics import propagate_2body def test_import_coordinates(): @@ -20,9 +20,7 @@ def test_import_coordinates(): KeplerianCoordinates, Origin, OriginCodes, - Residuals, SphericalCoordinates, - Times, transform_coordinates, )