Skip to content

Commit ebf33ab

Browse files
committed
optional astropy
test pandas and xarray time conversion remove pypy from travis since travis pypy3 is old
1 parent edb5d62 commit ebf33ab

File tree

11 files changed

+105
-37
lines changed

11 files changed

+105
-37
lines changed

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ git:
88
python:
99
- 3.6
1010
- 3.5
11-
- pypy3
1211

1312
os:
1413
- linux

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ Includes some relevant
2727
## Prerequisites
2828

2929
* Python ≥ 3.5 or PyPy3
30-
* [AstroPy](http://www.astropy.org/) (optional, used for ECI coordinates)
30+
31+
References to AstroPy are optional, algorithms from Vallado and Meeus are used if AstroPy is not present.
3132

3233

3334
## Install
@@ -39,7 +40,7 @@ pip install pymap3d
3940
or for the latest development code:
4041
```sh
4142
git clone https://github.com/scivision/pymap3d
42-
43+
cd pymap3d
4344
pip install -e .
4445
```
4546

pymap3d/aer.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ def aer2geodetic(az: float, el: float, srange: float,
7878

7979
def eci2aer(eci: Tuple[float, float, float],
8080
lat0: float, lon0: float, h0: float,
81-
t: datetime) -> Tuple[float, float, float]:
81+
t: datetime,
82+
useastropy: bool=True) -> Tuple[float, float, float]:
8283
"""
8384
Observer => Point
8485
@@ -95,14 +96,15 @@ def eci2aer(eci: Tuple[float, float, float],
9596
azimuth, elevation (degrees/radians) [0,360),[0,90]
9697
slant range [meters] [0,Infinity)
9798
"""
98-
ecef = np.atleast_2d(eci2ecef(eci, t))
99+
ecef = np.atleast_2d(eci2ecef(eci, t, useastropy))
99100

100101
return ecef2aer(ecef[:, 0], ecef[:, 1], ecef[:, 2], lat0, lon0, h0)
101102

102103

103104
def aer2eci(az: float, el: float, srange: float,
104105
lat0: float, lon0: float, h0: float, t: datetime,
105-
ell=None, deg: bool=True) -> np.ndarray:
106+
ell=None, deg: bool=True,
107+
useastropy: bool=True) -> np.ndarray:
106108
"""
107109
108110
input
@@ -120,7 +122,7 @@ def aer2eci(az: float, el: float, srange: float,
120122
"""
121123
x, y, z = aer2ecef(az, el, srange, lat0, lon0, h0, ell, deg)
122124

123-
return ecef2eci(np.column_stack((x, y, z)), t)
125+
return ecef2eci(np.column_stack((x, y, z)), t, useastropy)
124126

125127

126128
def aer2ecef(az: float, el: float, srange: float,

pymap3d/azelradec.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from datetime import datetime
66
import numpy as np
77
from .vallado import azel2radec as vazel2radec, radec2azel as vradec2azel
8+
from .timeconv import str2dt # astropy can't handle xarray times (yet)
89
try:
910
from astropy.time import Time
1011
from astropy import units as u
@@ -36,7 +37,7 @@ def azel2radec(az_deg: float, el_deg: float,
3637

3738
obs = EarthLocation(lat=lat_deg * u.deg, lon=lon_deg * u.deg)
3839

39-
direc = AltAz(location=obs, obstime=Time(time),
40+
direc = AltAz(location=obs, obstime=Time(str2dt(time)),
4041
az=az_deg * u.deg, alt=el_deg * u.deg)
4142

4243
sky = SkyCoord(direc.transform_to(ICRS()))
@@ -77,6 +78,6 @@ def radec2azel(ra_deg: float, dec_deg: float,
7778
Angle(dec, unit=u.deg),
7879
equinox='J2000.0')
7980

80-
altaz = points.transform_to(AltAz(location=obs, obstime=Time(time)))
81+
altaz = points.transform_to(AltAz(location=obs, obstime=Time(str2dt(time))))
8182

8283
return altaz.az.degree, altaz.alt.degree

pymap3d/ecef.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ def uvw2enu(u: float, v: float, w: float,
236236
return East, North, Up
237237

238238

239-
def eci2geodetic(eci: np.ndarray, t: datetime) -> Tuple[float, float, float]:
239+
def eci2geodetic(eci: np.ndarray, t: datetime,
240+
useastropy: bool=True) -> Tuple[float, float, float]:
240241
"""
241242
convert ECI to geodetic coordinates
242243
@@ -257,7 +258,7 @@ def eci2geodetic(eci: np.ndarray, t: datetime) -> Tuple[float, float, float]:
257258
258259
eci2geodetic() a.k.a. eci2lla()
259260
"""
260-
ecef = np.atleast_2d(eci2ecef(eci, t))
261+
ecef = np.atleast_2d(eci2ecef(eci, t, useastropy))
261262

262263
return np.asarray(ecef2geodetic(ecef[:, 0], ecef[:, 1], ecef[:, 2])).squeeze()
263264

pymap3d/eci.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
from datetime import datetime
22
import numpy as np
3+
from .datetime2hourangle import datetime2sidereal
34
try:
45
from astropy.time import Time
56
except ImportError as e:
67
Time = None
78

89

910
def eci2ecef(eci: np.ndarray,
10-
time: datetime) -> np.ndarray:
11+
time: datetime,
12+
useastropy: bool=True) -> np.ndarray:
1113
"""
1214
Observer => Point
1315
@@ -20,10 +22,13 @@ def eci2ecef(eci: np.ndarray,
2022
------
2123
x,y,z [meters] target ECEF location [0,Infinity)
2224
"""
23-
if Time is None:
24-
raise ImportError('eci2ecef requires Numpy and AstroPy')
25+
useastropy = useastropy and Time
26+
27+
if useastropy:
28+
gst = Time(time).sidereal_time('apparent', 'greenwich').radian
29+
else:
30+
gst = datetime2sidereal(time, 0.)
2531

26-
gst = Time(time).sidereal_time('apparent', 'greenwich').radian
2732
gst = np.atleast_1d(gst)
2833
assert gst.ndim == 1 and isinstance(gst[0], float) # must be in radians!
2934

@@ -43,7 +48,8 @@ def eci2ecef(eci: np.ndarray,
4348

4449

4550
def ecef2eci(ecef: np.ndarray,
46-
time: datetime) -> np.ndarray:
51+
time: datetime,
52+
useastropy: bool=True) -> np.ndarray:
4753
"""
4854
Point => Point
4955
@@ -57,10 +63,13 @@ def ecef2eci(ecef: np.ndarray,
5763
------
5864
eci x,y,z (meters)
5965
"""
60-
if Time is None:
61-
raise ImportError('ecef2eci requires AstroPy')
66+
useastropy = useastropy and Time
67+
68+
if useastropy:
69+
gst = Time(time).sidereal_time('apparent', 'greenwich').radian
70+
else:
71+
gst = datetime2sidereal(time, 0.)
6272

63-
gst = Time(time).sidereal_time('apparent', 'greenwich').radian
6473
gst = np.atleast_1d(gst)
6574
assert gst.ndim == 1 and isinstance(gst[0], float) # must be in radians!
6675

pymap3d/timeconv.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ def str2dt(time: datetime) -> np.ndarray:
1414
return time
1515
elif isinstance(time, str):
1616
return parse(time)
17-
elif isinstance(time[0], str):
18-
return [parse(t) for t in time]
19-
else:
20-
return time.values.astype('datetime64[us]').astype(datetime)
17+
else: # some sort of iterable
18+
try:
19+
return [parse(t) for t in time]
20+
except TypeError:
21+
return time.values.astype('datetime64[us]').astype(datetime)

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = pymap3d
3-
version = 1.7.9
3+
version = 1.7.10
44
author = Michael Hirsch, Ph.D.
55
author_email = [email protected]
66
description = pure Python coordinate conversions, following convention of several popular Matlab routines.

tests/test_astropy.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def test_anglesep_meeus():
3939
assert pmh.anglesep_meeus(35, 23, 84, 20) == approx(ha)
4040

4141

42-
def test_eci():
42+
def test_eci_astropy():
4343
pytest.importorskip('astropy')
4444

4545
t = '2013-01-15T12:00:05'
@@ -60,7 +60,7 @@ def test_eci():
6060
pm.aer2eci(aer1[0], aer1[1], -1, 42, -100, 0, t)
6161

6262

63-
def test_eci_times():
63+
def test_eci_times_astropy():
6464
pytest.importorskip('astropy')
6565

6666
with pytest.raises(AssertionError):
@@ -73,5 +73,36 @@ def test_eci_times():
7373
assert pm.ecef2eci(pm.eci2ecef(eci0s, [t0] * 2), [t0] * 2) == approx(eci0s)
7474

7575

76+
def test_eci_vallado():
77+
t = '2013-01-15T12:00:05'
78+
lla = pm.eci2geodetic(eci0, t, useastropy=False)
79+
assert lla == approx(lla0, rel=0.2)
80+
81+
eci1 = pm.eci2ecef(eci0, t, useastropy=False)
82+
assert eci1 == approx([649012.04640917, -4697980.55129606, 4250818.82815207], rel=0.001)
83+
84+
assert pm.ecef2eci(eci1, t, useastropy=False) == approx(eci0, rel=0.001)
85+
86+
aer1 = pm.eci2aer(eci0, 42, -100, 0, t, useastropy=False)
87+
assert aer1 == approx([83.73050, -6.614478, 1.473510e6], rel=0.001)
88+
89+
assert pm.aer2eci(*aer1, 42, -100, 0, t, useastropy=False) == approx(eci0, rel=0.001)
90+
91+
with pytest.raises(ValueError):
92+
pm.aer2eci(aer1[0], aer1[1], -1, 42, -100, 0, t, useastropy=False)
93+
94+
95+
def test_eci_times_vallado():
96+
with pytest.raises(AssertionError):
97+
pm.eci2ecef(eci0, [t0, t0], useastropy=False)
98+
99+
with pytest.raises(AssertionError):
100+
pm.ecef2eci(eci0, [t0, t0], useastropy=False)
101+
102+
eci0s = np.stack((eci0, eci0))
103+
assert pm.ecef2eci(pm.eci2ecef(eci0s, [t0] * 2, useastropy=False),
104+
[t0] * 2, useastropy=False) == approx(eci0s, rel=0.001)
105+
106+
76107
if __name__ == '__main__':
77108
pytest.main(['-xrsv', __file__])

tests/test_main.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@
66
"""
77
import pytest
88
from pytest import approx
9-
from datetime import datetime
109
import numpy as np
1110
import pymap3d as pm
12-
from pymap3d.timeconv import str2dt
1311

1412
pi = np.pi
1513
nan = np.nan
@@ -46,15 +44,6 @@ def test_ellipsoid():
4644
assert pm.ecef2geodetic(*xyz0, ell=pm.Ellipsoid('moon')) == approx([41.808706, -82., 4.630807e6])
4745

4846

49-
def test_str2dt():
50-
51-
assert str2dt(datetime(2014, 4, 6, 8)) == datetime(2014, 4, 6, 8) # passthrough
52-
assert str2dt('2014-04-06T08:00:00') == datetime(2014, 4, 6, 8)
53-
ti = [str2dt('2014-04-06T08:00:00'), str2dt('2014-04-06T08:01:02')]
54-
to = [datetime(2014, 4, 6, 8), datetime(2014, 4, 6, 8, 1, 2)]
55-
assert ti == to # even though ti is numpy array of datetime and to is list of datetime
56-
57-
5847
def test_losint():
5948

6049
pytest.importorskip('pytest', minversion='3.5')

0 commit comments

Comments
 (0)