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

aacgmv2.wrapper   D

Complexity

Total Complexity 61

Size/Duplication

Total Lines 557
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 61
eloc 193
dl 0
loc 557
rs 4.054
c 0
b 0
f 0

8 Functions

Rating   Name   Duplication   Size   Complexity  
B set_coeff_path() 0 30 3
A get_aacgm_coord() 0 56 2
F convert_latlon() 0 103 13
B convert_str_to_bit() 0 38 3
A get_aacgm_coord_arr() 0 57 2
F convert_latlon_arr() 0 146 26
B convert_bool_to_bit() 0 37 6
B convert_mlt() 0 60 6

How to fix   Complexity   

Complexity

Complex classes like aacgmv2.wrapper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
"""Pythonic wrappers for AACGM-V2 C functions.
3
4
Functions
5
--------------
6
set_coeff_path : Set the coefficient paths using default or supplied values
7
convert_latlon : Converts scalar location
8
convert_latlon_arr : Converts array location
9
get_aacgm_coord : Get scalar magnetic lat, lon, mlt from geographic location
10
get_aacgm_coord_arr : Get array magnetic lat, lon, mlt from geographic location
11
convert_str_to_bit : Convert human readible AACGM flag to bits
12
convert_bool_to_bit : Convert boolian flags to bits
13
convert_mlt : Get array mlt
14
--------------
15
"""
16
17
from __future__ import division, absolute_import, unicode_literals
18
import datetime as dt
19
import numpy as np
0 ignored issues
show
introduced by
Unable to import 'numpy'
Loading history...
20
import logbook as logging
0 ignored issues
show
introduced by
Unable to import 'logbook'
Loading history...
21
22
def set_coeff_path(igrf_file=None, coeff_prefix=None):
23
    """This routine sets the two path variables.
24
25
    Parameters
26
    -----------
27
    igrf_file : (str or NoneType)
28
        Full filename of IGRF coefficient file or None to use
29
        aacgmv2.IGRF_12_COEFFS. (default=None)
30
    coeff_prefix : (str or NoneType)
31
        Location and file prefix for aacgm coefficient files or None to use
32
        aacgmv2.AACGM_V2_DAT_PREFIX. (default=None)
33
34
    Returns
35
    ---------
36
    igrf_file : (str)
37
        Full filename of IGRF coefficient file
38
    coeff_prefix : (str)
39
        Location and file prefix for aacgm coefficient files
40
    """
41
    import aacgmv2
42
43
    # Define coefficient file prefix if not supplied
44
    if coeff_prefix is None:
45
        coeff_prefix = aacgmv2.AACGM_V2_DAT_PREFIX
46
47
    # Define IGRF file if not supplied
48
    if igrf_file is None:
49
        igrf_file = aacgmv2.IGRF_12_COEFFS
50
51
    return igrf_file, coeff_prefix
52
53
def convert_latlon(in_lat, in_lon, height, dtime, code="G2A", igrf_file=None,
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
54
                   coeff_prefix=None):
55
    """Converts between geomagnetic coordinates and AACGM coordinates
56
57
    Parameters
58
    ------------
59
    in_lat : (float)
60
        Input latitude in degrees N (code specifies type of latitude)
61
    in_lon : (float)
62
        Input longitude in degrees E (code specifies type of longitude)
63
    height : (float)
64
        Altitude above the surface of the earth in km
65
    dtime : (datetime)
66
        Datetime for magnetic field
67
    code : (str or int)
68
        Bit code or string denoting which type(s) of conversion to perform
69
        G2A        - geographic (geodetic) to AACGM-v2
70
        A2G        - AACGM-v2 to geographic (geodetic)
71
        TRACE      - use field-line tracing, not coefficients
72
        ALLOWTRACE - use trace only above 2000 km
73
        BADIDEA    - use coefficients above 2000 km
74
        GEOCENTRIC - assume inputs are geocentric w/ RE=6371.2
75
        (default is "G2A")
76
    igrf_file : (str or NoneType)
77
        Full filename of IGRF coefficient file or None to use
78
        aacgmv2.IGRF_12_COEFFS. (default=None)
79
    coeff_prefix : (str or NoneType)
80
        Location and file prefix for aacgm coefficient files or None to use
81
        aacgmv2.AACGM_V2_DAT_PREFIX. (default=None)
82
83
    Returns
84
    -------
85
    out_lat : (float)
86
        Output latitude in degrees N
87
    out_lon : (float)
88
        Output longitude in degrees E
89
    out_r : (float)
90
        Geocentric radial distance (R_Earth) or altitude above the surface of
91
        the Earth (km)
92
    """
93
    import aacgmv2._aacgmv2 as c_aacgmv2
0 ignored issues
show
introduced by
Unable to import 'aacgmv2._aacgmv2'
Loading history...
94
95
    # Define coefficient file prefix if not supplied
96
    igrf_file, coeff_prefix = set_coeff_path(igrf_file=igrf_file,
97
                                             coeff_prefix=coeff_prefix)
98
99
    # Test time
100
    if isinstance(dtime, dt.date):
101
        dtime = dt.datetime.combine(dtime, dt.time(0))
102
103
    assert isinstance(dtime, dt.datetime), \
104
        logging.error('time must be specified as datetime object')
105
106
    # Test height
107
    if height < 0:
108
        logging.warn('conversion not intended for altitudes < 0 km')
109
110
    # Initialise output
111
    lat_out = np.nan
112
    lon_out = np.nan
113
    r_out = np.nan
114
115
    # Test code
116
    try:
117
        code = code.upper()
118
119
        if(height > 2000 and code.find("TRACE") < 0 and
120
           code.find("ALLOWTRACE") < 0 and code.find("BADIDEA")):
121
            estr = 'coefficients are not valid for altitudes above 2000 km. You'
122
            estr += ' must either use field-line tracing (trace=True '
123
            estr += 'or allowtrace=True) or indicate you know this '
124
            estr += 'is a bad idea'
125
            logging.error(estr)
126
            return lat_out, lon_out, r_out
127
128
        # make flag
129
        bit_code = convert_str_to_bit(code)
130
    except AttributeError:
131
        bit_code = code
132
133
    assert isinstance(bit_code, int), \
134
        logging.error("unknown code {:}".format(bit_code))
135
136
    # Test latitude range
137
    if abs(in_lat) > 90.0:
138
        assert abs(in_lat) <= 90.1, logging.error('unrealistic latitude')
139
        in_lat = np.sign(in_lat) * 90.0
140
141
    # Constrain longitudes between -180 and 180
142
    in_lon = ((in_lon + 180.0) % 360.0) - 180.0
143
144
    # Set current date and time
145
    c_aacgmv2.set_datetime(dtime.year, dtime.month, dtime.day, dtime.hour,
146
                           dtime.minute, dtime.second, coeff_prefix)
147
148
    # convert location
149
    try:
150
        lat_out, lon_out, r_out = c_aacgmv2.convert(in_lat, in_lon, height,
151
                                                    bit_code, igrf_file)
152
    except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
153
        pass
154
155
    return lat_out, lon_out, r_out
156
157
def convert_latlon_arr(in_lat, in_lon, height, dtime, code="G2A",
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
Comprehensibility introduced by
This function exceeds the maximum number of variables (17/15).
Loading history...
158
                       igrf_file=None, coeff_prefix=None):
159
    """Converts between geomagnetic coordinates and AACGM coordinates.  At least
160
    one of in_lat, in_lon, and height must be a list or array
161
162
    Parameters
163
    ------------
164
    in_lat : (np.ndarray or list or float)
165
        Input latitude in degrees N (code specifies type of latitude)
166
    in_lon : (np.ndarray or list or float)
167
        Input longitude in degrees E (code specifies type of longitude)
168
    height : (np.ndarray or list or float)
169
        Altitude above the surface of the earth in km
170
    dtime : (datetime)
171
        Single datetime object for magnetic field
172
    code : (int or str)
173
        Bit code or string denoting which type(s) of conversion to perform
174
        G2A        - geographic (geodetic) to AACGM-v2
175
        A2G        - AACGM-v2 to geographic (geodetic)
176
        TRACE      - use field-line tracing, not coefficients
177
        ALLOWTRACE - use trace only above 2000 km
178
        BADIDEA    - use coefficients above 2000 km
179
        GEOCENTRIC - assume inputs are geocentric w/ RE=6371.2
180
        (default = "G2A")
181
    igrf_file : (str or NoneType)
182
        Full filename of IGRF coefficient file or None to use
183
        aacgmv2.IGRF_12_COEFFS. (default=None)
184
    coeff_prefix : (str or NoneType)
185
        Location and file prefix for aacgm coefficient files or None to use
186
        aacgmv2.AACGM_V2_DAT_PREFIX. (default=None)
187
188
    Returns
189
    -------
190
    out_lat : (np.ndarray)
191
        Output latitudes in degrees N
192
    out_lon : (np.ndarray)
193
        Output longitudes in degrees E
194
    out_r : (np.ndarray)
195
        Geocentric radial distance (R_Earth) or altitude above the surface of
196
        the Earth (km)
197
    """
198
    import aacgmv2._aacgmv2 as c_aacgmv2
0 ignored issues
show
introduced by
Unable to import 'aacgmv2._aacgmv2'
Loading history...
199
200
    # If a list was entered instead of a numpy array, recast it here
201
    if isinstance(in_lat, list):
202
        in_lat = np.array(in_lat)
203
204
    if isinstance(in_lon, list):
205
        in_lon = np.array(in_lon)
206
207
    if isinstance(height, list):
208
        height = np.array(height)
209
210
    # If one or two of these elements is a float or int, create an array
211
    test_array = np.array([hasattr(in_lat, "shape"), hasattr(in_lon, "shape"),
212
                           hasattr(height, "shape")])
213
    if not test_array.all():
214
        if test_array.any():
215
            arr_shape = in_lat.shape if test_array.argmax() == 0 else \
216
                        (in_lon.shape if test_array.argmax() == 1 else
217
                         height.shape)
218
            if not test_array[0]:
219
                in_lat = np.ones(shape=arr_shape, dtype=float) * in_lat
220
            if not test_array[1]:
221
                in_lon = np.ones(shape=arr_shape, dtype=float) * in_lon
222
            if not test_array[2]:
223
                height = np.ones(shape=arr_shape, dtype=float) * height
224
        else:
225
            logging.info("for a single location, consider using convert_latlon")
226
            in_lat = np.array([in_lat])
227
            in_lon = np.array([in_lon])
228
            height = np.array([height])
229
230
    # Ensure that lat, lon, and height are the same length or if the lengths
231
    # differ that the different ones contain only a single value
232
    if not (in_lat.shape == in_lon.shape and in_lat.shape == height.shape):
233
        ulen = np.unique([in_lat.shape, in_lon.shape, height.shape])
234
        if ulen.min() != (1,):
235
            logging.error("mismatched input arrays")
236
            return None, None, None
237
238
    # Define coefficient file prefix if not supplied
239
    igrf_file, coeff_prefix = set_coeff_path(igrf_file=igrf_file,
240
                                             coeff_prefix=coeff_prefix)
241
242
    # Test time
243
    if isinstance(dtime, dt.date):
244
        dtime = dt.datetime.combine(dtime, dt.time(0))
245
246
    assert isinstance(dtime, dt.datetime), \
247
        logging.error('time must be specified as datetime object')
248
249
    # Test height
250
    if np.min(height) < 0:
251
        logging.warn('conversion not intended for altitudes < 0 km')
252
253
    # Initialise output
254
    lat_out = np.empty(shape=in_lat.shape, dtype=float) * np.nan
255
    lon_out = np.empty(shape=in_lon.shape, dtype=float) * np.nan
256
    r_out = np.empty(shape=height.shape, dtype=float) * np.nan
257
258
    # Test code
259
    try:
260
        code = code.upper()
261
262
        if(np.nanmax(height) > 2000 and code.find("TRACE") < 0 and
263
           code.find("ALLOWTRACE") < 0 and code.find("BADIDEA")):
264
            estr = 'coefficients are not valid for altitudes above 2000 km. You'
265
            estr += ' must either use field-line tracing (trace=True '
266
            estr += 'or allowtrace=True) or indicate you know this '
267
            estr += 'is a bad idea'
268
            logging.error(estr)
269
            return lat_out, lon_out, r_out
270
271
        # make flag
272
        bit_code = convert_str_to_bit(code)
273
    except AttributeError:
274
        bit_code = code
275
276
    assert isinstance(bit_code, int), \
277
        logging.error("unknown code {:}".format(bit_code))
278
279
    # Test latitude range
280
    if np.abs(in_lat).max() > 90.0:
281
        assert np.abs(in_lat).max() <= 90.1, \
282
            logging.error('unrealistic latitude')
283
        in_lat = np.clip(in_lat, -90.0, 90.0)
284
285
    # Constrain longitudes between -180 and 180
286
    in_lon = ((in_lon + 180.0) % 360.0) - 180.0
287
288
    # Set current date and time
289
    c_aacgmv2.set_datetime(dtime.year, dtime.month, dtime.day, dtime.hour,
290
                           dtime.minute, dtime.second, coeff_prefix)
291
292
    # Vectorise the AACGM code
293
    convert_vectorised = np.vectorize(c_aacgmv2.convert)
294
295
    # convert
296
    try:
297
        lat_out, lon_out, r_out = convert_vectorised(in_lat, in_lon, height,
298
                                                     bit_code, igrf_file)
299
    except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
300
        pass
301
302
    return lat_out, lon_out, r_out
303
304
def get_aacgm_coord(glat, glon, height, dtime, method="TRACE",
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
305
                    igrf_file=None, coeff_prefix=None):
306
    """Get AACGM latitude, longitude, and magnetic local time
307
308
    Parameters
309
    ------------
310
    glat : (float)
311
        Geodetic latitude in degrees N
312
    glon : (float)
313
        Geodetic longitude in degrees E
314
    height : (float)
315
        Altitude above the surface of the earth in km
316
    dtime : (datetime)
317
        Date and time to calculate magnetic location
318
    method : (str)
319
        String denoting which type(s) of conversion to perform
320
        TRACE      - use field-line tracing, not coefficients
321
        ALLOWTRACE - use trace only above 2000 km
322
        BADIDEA    - use coefficients above 2000 km
323
        GEOCENTRIC - assume inputs are geocentric w/ RE=6371.2
324
        (default = "TRACE")
325
    igrf_file : (str or NoneType)
326
        Full filename of IGRF coefficient file or None to use
327
        aacgmv2.IGRF_12_COEFFS. (default=None)
328
    coeff_prefix : (str or NoneType)
329
        Location and file prefix for aacgm coefficient files or None to use
330
        aacgmv2.AACGM_V2_DAT_PREFIX. (default=None)
331
332
    Returns
333
    -------
334
    mlat : (float)
335
        magnetic latitude in degrees N
336
    mlon : (float)
337
        magnetic longitude in degrees E
338
    mlt : (float)
339
        magnetic local time in hours
340
    """
341
    # Define coefficient file prefix if not supplied
342
    igrf_file, coeff_prefix = set_coeff_path(igrf_file=igrf_file,
343
                                             coeff_prefix=coeff_prefix)
344
345
    # Initialize code
346
    code = "G2A|{:s}".format(method)
347
348
    # Get magnetic lat and lon.
349
    mlat, mlon, _ = convert_latlon(glat, glon, height, dtime, code=code,
350
                                   igrf_file=igrf_file,
351
                                   coeff_prefix=coeff_prefix)
352
    # Get magnetic local time
353
    if np.isnan(mlon):
354
        mlt = np.nan
355
    else:
356
        mlt = convert_mlt(mlon, dtime, m2a=False, coeff_prefix=coeff_prefix,
357
                          igrf_file=igrf_file)
358
359
    return mlat, mlon, mlt
360
361
362
def get_aacgm_coord_arr(glat, glon, height, dtime, method="TRACE",
0 ignored issues
show
best-practice introduced by
Too many arguments (7/5)
Loading history...
363
                        igrf_file=None, coeff_prefix=None):
364
    """Get AACGM latitude, longitude, and magnetic local time
365
366
    Parameters
367
    ------------
368
    glat : (np.array or list)
369
        Geodetic latitude in degrees N
370
    glon : (np.array or list)
371
        Geodetic longitude in degrees E
372
    height : (np.array or list)
373
        Altitude above the surface of the earth in km
374
    dtime : (datetime)
375
        Date and time to calculate magnetic location
376
    method : (str)
377
        String denoting which type(s) of conversion to perform
378
        TRACE      - use field-line tracing, not coefficients
379
        ALLOWTRACE - use trace only above 2000 km
380
        BADIDEA    - use coefficients above 2000 km
381
        GEOCENTRIC - assume inputs are geocentric w/ RE=6371.2
382
        (default = "TRACE")
383
    igrf_file : (str or NoneType)
384
        Full filename of IGRF coefficient file or None to use
385
        aacgmv2.IGRF_12_COEFFS. (default=None)
386
    coeff_prefix : (str or NoneType)
387
        Location and file prefix for aacgm coefficient files or None to use
388
        aacgmv2.AACGM_V2_DAT_PREFIX. (default=None)
389
390
    Returns
391
    -------
392
    mlat : (float)
393
        magnetic latitude in degrees N
394
    mlon : (float)
395
        magnetic longitude in degrees E
396
    mlt : (float)
397
        magnetic local time in hours
398
    """
399
    # Define coefficient file prefix if not supplied
400
    igrf_file, coeff_prefix = set_coeff_path(igrf_file=igrf_file,
401
                                             coeff_prefix=coeff_prefix)
402
403
    # Initialize code
404
    code = "G2A|{:s}".format(method)
405
406
    # Get magnetic lat and lon.
407
    mlat, mlon, _ = convert_latlon_arr(glat, glon, height, dtime, code=code,
408
                                       igrf_file=igrf_file,
409
                                       coeff_prefix=coeff_prefix)
410
411
    if np.all(np.isnan(mlon)):
412
        mlt = np.empty(shape=mlat.shape, dtype=float) * np.nan
413
    else:
414
        # Get magnetic local time
415
        mlt = convert_mlt(mlon, dtime, m2a=False, coeff_prefix=coeff_prefix,
416
                          igrf_file=igrf_file)
417
418
    return mlat, mlon, mlt
419
420
def convert_str_to_bit(code):
421
    """convert string code specification to bit code specification
422
423
    Parameters
424
    ------------
425
    code : (str)
426
        Bitwise code for passing options into converter (default=0)
427
        G2A        - geographic (geodetic) to AACGM-v2
428
        A2G        - AACGM-v2 to geographic (geodetic)
429
        TRACE      - use field-line tracing, not coefficients
430
        ALLOWTRACE - use trace only above 2000 km
431
        BADIDEA    - use coefficients above 2000 km
432
        GEOCENTRIC - assume inputs are geocentric w/ RE=6371.2
433
434
    Returns
435
    --------
436
    bit_code : (int)
437
        code specification in bits
438
439
    Notes
440
    --------
441
    Multiple codes should be seperated by pipes '|'.  Invalid parts of the code
442
    are ignored and no code defaults to 'G2A'.
443
    """
444
    import aacgmv2._aacgmv2 as c_aacgmv2
0 ignored issues
show
introduced by
Unable to import 'aacgmv2._aacgmv2'
Loading history...
445
446
    convert_code = {"G2A": c_aacgmv2.G2A, "A2G": c_aacgmv2.A2G,
447
                    "TRACE": c_aacgmv2.TRACE, "BADIDEA": c_aacgmv2.BADIDEA,
448
                    "GEOCENTRIC": c_aacgmv2.GEOCENTRIC,
449
                    "ALLOWTRACE": c_aacgmv2.ALLOWTRACE}
450
451
    # Force upper case, remove any spaces, and split along pipes
452
    codes = code.upper().replace(" ", "").split("|")
453
454
    # Add the valid parts of the code, invalid elements are ignored
455
    bit_code = sum([convert_code[k] for k in codes if k in convert_code.keys()])
456
457
    return bit_code
458
459
def convert_bool_to_bit(a2g=False, trace=False, allowtrace=False,
460
                        badidea=False, geocentric=False):
461
    """convert boolian flags to bit code specification
462
463
    Parameters
464
    ----------
465
    a2g : (bool)
466
        True for AACGM-v2 to geographic (geodetic), False otherwise
467
        (default=False)
468
    trace : (bool)
469
        If True, use field-line tracing, not coefficients (default=False)
470
    allowtrace : (bool)
471
        If True, use trace only above 2000 km (default=False)
472
    badidea : (bool)
473
        If True, use coefficients above 2000 km (default=False)
474
    geocentric : (bool)
475
        True for geodetic, False for geocentric w/RE=6371.2 (default=False)
476
477
    Returns
478
    --------
479
    bit_code : (int)
480
        code specification in bits
481
    """
482
    import aacgmv2._aacgmv2 as c_aacgmv2
0 ignored issues
show
introduced by
Unable to import 'aacgmv2._aacgmv2'
Loading history...
483
484
    bit_code = c_aacgmv2.A2G if a2g else c_aacgmv2.G2A
485
486
    if trace:
487
        bit_code += c_aacgmv2.TRACE
488
    if allowtrace:
489
        bit_code += c_aacgmv2.ALLOWTRACE
490
    if badidea:
491
        bit_code += c_aacgmv2.BADIDEA
492
    if geocentric:
493
        bit_code += c_aacgmv2.GEOCENTRIC
494
495
    return bit_code
496
497
def convert_mlt(arr, dtime, m2a=False, coeff_prefix=None, igrf_file=None):
498
    """Converts between magnetic local time (MLT) and AACGM-v2 longitude
499
500
    Parameters
501
    ------------
502
    arr : (array_line or float)
503
        Magnetic longitudes (degrees E) or MLTs (hours) to convert
504
    dtime : (datetime.datetime)
505
        Date and time for MLT conversion in Universal Time (UT).
506
    m2a : (bool)
507
        Convert MLT to AACGM-v2 longitude (True) or magnetic longitude to MLT
508
        (False).  (default=False)
509
    coeff_prefix : (str or NoneType)
510
        Location and file prefix for aacgm coefficient files or None to use
511
        aacgmv2.AACGM_V2_DAT_PREFIX. (default=None)
512
    igrf_file : (str or NoneType)
513
        Full filename of IGRF coefficient file or None to use
514
        aacgmv2.IGRF_12_COEFFS. (default=None)
515
516
    Returns
517
    --------
518
    out : (np.ndarray)
519
        Converted coordinates/MLT in degrees E or hours (as appropriate)
520
521
    Notes
522
    -------
523
    This routine previously based on Laundal et al. 2016, but now uses the
524
    improved calculation available in AACGM-V2.4.
525
    """
526
    import aacgmv2._aacgmv2 as c_aacgmv2
0 ignored issues
show
introduced by
Unable to import 'aacgmv2._aacgmv2'
Loading history...
527
528
    # Define coefficient file prefix if not supplied
529
    igrf_file, coeff_prefix = set_coeff_path(igrf_file=igrf_file,
530
                                             coeff_prefix=coeff_prefix)
531
532
    # Test time
533
    if isinstance(dtime, dt.date):
534
        dtime = dt.datetime.combine(dtime, dt.time(0))
535
536
    assert isinstance(dtime, dt.datetime), \
537
        logging.error('time must be specified as datetime object')
538
539
    # Calculate desired location, C routines set date and time
540
    if m2a:
541
        # Get the magnetic longitude
542
        inv_vectorised = np.vectorize(c_aacgmv2.inv_mlt_convert)
543
        out = inv_vectorised(dtime.year, dtime.month, dtime.day, dtime.hour,
544
                             dtime.minute, dtime.second, arr, coeff_prefix,
545
                             igrf_file)
546
    else:
547
        # Get magnetic local time
548
        mlt_vectorised = np.vectorize(c_aacgmv2.mlt_convert)
549
        out = mlt_vectorised(dtime.year, dtime.month, dtime.day, dtime.hour,
550
                             dtime.minute, dtime.second, arr, coeff_prefix,
551
                             igrf_file)
552
553
    if hasattr(out, "shape") and out.shape == ():
554
        out = float(out)
555
556
    return out
557