Completed
Push — master ( e4d4aa...7735e4 )
by Angeline
13s queued 11s
created

aacgmv2.deprecated   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 253
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 13
eloc 85
dl 0
loc 253
rs 10
c 0
b 0
f 0

4 Functions

Rating   Name   Duplication   Size   Complexity  
A igrf_dipole_axis() 0 71 3
B convert() 0 54 5
B subsol() 0 86 4
A gc2gd_lat() 0 15 1
1
# -*- coding: utf-8 -*-
0 ignored issues
show
Bug introduced by
There seems to be a cyclic import (aacgmv2 -> aacgmv2.wrapper).

Cyclic imports may cause partly loaded modules to be returned. This might lead to unexpected runtime behavior which is hard to debug.

Loading history...
Bug introduced by
There seems to be a cyclic import (aacgmv2 -> aacgmv2.deprecated).

Cyclic imports may cause partly loaded modules to be returned. This might lead to unexpected runtime behavior which is hard to debug.

Loading history...
2
"""Pythonic wrappers for AACGM-V2 C functions that were depricated in the
3
change from version 2.0.0 to version 2.0.2
4
5
Functions
6
-------------------------------------------------------------------------------
7
convert : Converts array location
8
subsol : finds subsolar geocentric longitude and latitude
9
gc2gd_lat : Convert between geocentric and geodetic coordinates
10
igrf_dipole_axis : Get Cartesian unit vector pointing at the IGRF north dipole
11
------------------------------------------------------------------------------
12
13
References
14
-------------------------------------------------------------------------------
15
Laundal, K. M. and A. D. Richmond (2016), Magnetic Coordinate Systems, Space
16
 Sci. Rev., doi:10.1007/s11214-016-0275-y.
17
-------------------------------------------------------------------------------
18
"""
19
20
from __future__ import division, absolute_import, unicode_literals
21
import numpy as np
0 ignored issues
show
introduced by
Unable to import 'numpy'
Loading history...
22
import logbook as logging
0 ignored issues
show
introduced by
Unable to import 'logbook'
Loading history...
23
24
def convert(lat, lon, alt, date=None, a2g=False, trace=False, allowtrace=False,
0 ignored issues
show
best-practice introduced by
Too many arguments (9/5)
Loading history...
25
            badidea=False, geocentric=False):
26
    """Converts between geomagnetic coordinates and AACGM coordinates
27
28
    Parameters
29
    ------------
30
    lat : (float)
31
        Input latitude in degrees N (code specifies type of latitude)
32
    lon : (float)
33
        Input longitude in degrees E (code specifies type of longitude)
34
    alt : (float)
35
        Altitude above the surface of the earth in km
36
    date : (datetime)
37
        Datetime for magnetic field
38
    a2g : (bool)
39
        True for AACGM-v2 to geographic (geodetic), False otherwise
40
        (default=False)
41
    trace : (bool)
42
        If True, use field-line tracing, not coefficients (default=False)
43
    allowtrace : (bool)
44
        If True, use trace only above 2000 km (default=False)
45
    badidea : (bool)
46
        If True, use coefficients above 2000 km (default=False)
47
    geocentric : (bool)
48
        True for geodetic, False for geocentric w/RE=6371.2 (default=False)
49
50
    Returns
51
    -------
52
    lat_out : (float)
53
        Output latitude in degrees N
54
    lon_out : (float)
55
        Output longitude in degrees E
56
    """
57
    import aacgmv2
58
59
    if(np.array(alt).max() > 2000 and not trace and not allowtrace and
60
       badidea):
61
        estr = 'coefficients are not valid for altitudes above 2000 km. You'
62
        estr += ' must either use field-line tracing (trace=True '
63
        estr += 'or allowtrace=True) or indicate you know this is a bad idea'
64
        logging.error(estr)
65
        raise ValueError
66
67
    # construct a code from the boolian flags
68
    bit_code = aacgmv2.convert_bool_to_bit(a2g=a2g, trace=trace,
69
                                           allowtrace=allowtrace,
70
                                           badidea=badidea,
71
                                           geocentric=geocentric)
72
73
    # convert location
74
    lat_out, lon_out, _ = aacgmv2.convert_latlon_arr(lat, lon, alt, date,
75
                                                     code=bit_code)
76
77
    return lat_out, lon_out
78
79
def subsol(year, doy, utime):
0 ignored issues
show
Comprehensibility introduced by
This function exceeds the maximum number of variables (20/15).
Loading history...
80
    """Finds subsolar geocentric longitude and latitude.
81
82
    Parameters
83
    ------------
84
    year : (int)
85
        Calendar year between 1601 and 2100
86
    doy : (int)
87
        Day of year between 1-365/366
88
    utime : (float)
89
        Seconds since midnight on the specified day
90
91
    Returns
92
    ---------
93
    sbsllon : (float)
94
        Subsolar longitude in degrees E for the given date/time
95
    sbsllat : (float)
96
        Subsolar latitude in degrees N for the given date/time
97
98
    Notes
99
    --------
100
    Based on formulas in Astronomical Almanac for the year 1996, p. C24.
101
    (U.S. Government Printing Office, 1994). Usable for years 1601-2100,
102
    inclusive. According to the Almanac, results are good to at least 0.01
103
    degree latitude and 0.025 degrees longitude between years 1950 and 2050.
104
    Accuracy for other years has not been tested. Every day is assumed to have
105
    exactly 86400 seconds; thus leap seconds that sometimes occur on December
106
    31 are ignored (their effect is below the accuracy threshold of the
107
    algorithm).
108
    After Fortran code by A. D. Richmond, NCAR. Translated from IDL
109
    by K. Laundal.
110
    """
111
    yr2 = year - 2000
112
113
    if year >= 2101:
114
        logging.error('subsol invalid after 2100. Input year is:', year)
115
116
    nleap = np.floor((year - 1601) / 4)
117
    nleap = nleap - 99
118
    if year <= 1900:
119
        if year <= 1600:
120
            print('subsol.py: subsol invalid before 1601. Input year is:', year)
121
        ncent = np.floor((year - 1601) / 100)
122
        ncent = 3 - ncent
123
        nleap = nleap + ncent
124
125
    l_0 = -79.549 + (-0.238699 * (yr2 - 4 * nleap) + 3.08514e-2 * nleap)
126
    g_0 = -2.472 + (-0.2558905 * (yr2 - 4 * nleap) - 3.79617e-2 * nleap)
127
128
    # Days (including fraction) since 12 UT on January 1 of IYR2:
129
    dfrac = (utime / 86400 - 1.5) + doy
130
131
    # Mean longitude of Sun:
132
    l_sun = l_0 + 0.9856474 * dfrac
133
134
    # Mean anomaly:
135
    grad = np.radians(g_0 + 0.9856003 * dfrac)
136
137
    # Ecliptic longitude:
138
    lmrad = np.radians(l_sun + 1.915 * np.sin(grad) + 0.020 * np.sin(2 * grad))
139
    sinlm = np.sin(lmrad)
140
141
    # Days (including fraction) since 12 UT on January 1 of 2000:
142
    epoch_day = dfrac + 365.0 * yr2 + nleap
143
144
    # Obliquity of ecliptic:
145
    epsrad = np.radians(23.439 - 4.0e-7 * epoch_day)
146
147
    # Right ascension:
148
    alpha = np.degrees(np.arctan2(np.cos(epsrad) * sinlm, np.cos(lmrad)))
149
150
    # Declination, which is the subsolar latitude:
151
    sbsllat = np.degrees(np.arcsin(np.sin(epsrad) * sinlm))
152
153
    # Equation of time (degrees):
154
    etdeg = l_sun - alpha
155
    etdeg = etdeg - 360.0 * np.round(etdeg / 360.0)
156
157
    # Apparent time (degrees):
158
    aptime = utime / 240.0 + etdeg    # Earth rotates one degree every 240 s.
159
160
    # Subsolar longitude:
161
    sbsllon = 180.0 - aptime
162
    sbsllon = sbsllon - 360.0 * np.round(sbsllon / 360.0)
163
164
    return sbsllon, sbsllat
165
166
def gc2gd_lat(gc_lat):
167
    """Convert geocentric latitude to geodetic latitude using WGS84.
168
169
    Parameters
170
    -----------
171
    gc_lat : (array_like or float)
172
        Geocentric latitude in degrees N
173
174
    Returns
175
    ---------
176
    gd_lat : (same as input)
177
        Geodetic latitude in degrees N
178
    """
179
    wgs84_e2 = 0.006694379990141317 - 1.0
180
    return np.rad2deg(-np.arctan(np.tan(np.deg2rad(gc_lat)) / wgs84_e2))
181
182
def igrf_dipole_axis(date):
0 ignored issues
show
Comprehensibility introduced by
This function exceeds the maximum number of variables (18/15).
Loading history...
183
    """Get Cartesian unit vector pointing at dipole pole in the north,
184
    according to IGRF
185
186
    Parameters
187
    -------------
188
    date : (dt.datetime)
189
        Date and time
190
191
    Returns
192
    ----------
193
    m_0: (np.ndarray)
194
        Cartesian 3 element unit vector pointing at dipole pole in the north
195
        (geocentric coords)
196
197
    Notes
198
    ----------
199
    IGRF coefficients are read from the igrf12coeffs.txt file. It should also
200
    work after IGRF updates.  The dipole coefficients are interpolated to the
201
    date, or extrapolated if date > latest IGRF model
202
    """
203
    import datetime as dt
204
    import aacgmv2
205
206
    # get time in years, as float:
207
    year = date.year
208
    doy = date.timetuple().tm_yday
209
    year_days = int(dt.date(date.year, 12, 31).strftime("%j"))
210
    year = year + doy / year_days
211
212
    # read the IGRF coefficients
213
    with open(aacgmv2.IGRF_12_COEFFS, 'r') as f_igrf:
214
        lines = f_igrf.readlines()
215
216
    years = lines[3].split()[3:][:-1]
217
    years = np.array(years, dtype=float)  # time array
218
219
    g10 = lines[4].split()[3:]
220
    g11 = lines[5].split()[3:]
221
    h11 = lines[6].split()[3:]
222
223
    # secular variation coefficients (for extrapolation)
224
    g10sv = np.float32(g10[-1])
225
    g11sv = np.float32(g11[-1])
226
    h11sv = np.float32(h11[-1])
227
228
    # model coefficients:
229
    g10 = np.array(g10[:-1], dtype=float)
230
    g11 = np.array(g11[:-1], dtype=float)
231
    h11 = np.array(h11[:-1], dtype=float)
232
233
    # get the gauss coefficient at given time:
234
    if year <= years[-1]:
235
        # regular interpolation
236
        g10 = np.interp(year, years, g10)
237
        g11 = np.interp(year, years, g11)
238
        h11 = np.interp(year, years, h11)
239
    else:
240
        # extrapolation
241
        dyear = year - years[-1]
242
        g10 = g10[-1] + g10sv * dyear
243
        g11 = g11[-1] + g11sv * dyear
244
        h11 = h11[-1] + h11sv * dyear
245
246
    # calculate pole position
247
    B_0 = np.sqrt(g10**2 + g11**2 + h11**2)
0 ignored issues
show
Coding Style Naming introduced by
The name B_0 does not conform to the variable naming conventions ((([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
248
249
    # Calculate output
250
    m_0 = -np.array([g11, h11, g10]) / B_0
251
252
    return m_0
253