def datetime2Lgm(*args): '''Convenience function to convert Python datetime to Lgm date and utc format Parameters ---------- time_in: datetime.datetime the input time to convert to a different system Outputs ------- datelong: long LanlGeoMag long integer date representation (YYYYMMDD) utc: float LanlGeoMag floating point time-of-day (UTC) representation ''' if len(args) == 1: time_in = args[0] else: raise ValueError('Invalid arguments supplied in function call') if _spacepy: if isinstance(time_in, spt.Ticktock): raise NotImplementedError('SpacePy compatibility not yet enabled') try: datelong = Lgm_CTrans.dateToDateLong(time_in) utc = Lgm_CTrans.dateToFPHours(time_in) except AttributeError: raise TypeError("Date must be a datetime object") return datelong, utc
def test_dateToFPHours(self): """dateToFPHours should give known output for known input""" d1 = datetime.datetime(2000, 12, 12) self.assertEqual(0.0, Lgm_CTrans.dateToFPHours(d1)) for val in range(24): self.assertEqual(val, Lgm_CTrans.dateToFPHours(datetime.datetime(2000, 12, 12, val))) self.assertEqual(12.5, Lgm_CTrans.dateToFPHours([datetime.datetime(2000, 12, 12, 12, 30)])) self.assertEqual(12.5, Lgm_CTrans.dateToFPHours(datetime.datetime(2000, 12, 12, 12, 30))) self.assertEqual(12.25, Lgm_CTrans.dateToFPHours(datetime.datetime(2000, 12, 12, 12, 15))) self.assertEqual(12.75, Lgm_CTrans.dateToFPHours(datetime.datetime(2000, 12, 12, 12, 45))) d1 = datetime.datetime(2000, 12, 12, 12, 30) self.assertEqual([12.5, 12.5], Lgm_CTrans.dateToFPHours([d1, d1])) self.assertEqual([12.5, 12.5], Lgm_CTrans.dateToFPHours(numpy.array([d1, d1])).tolist())
def getLatLonRadfromTLE(epochs, TLEpath, options): """ Reads Latitude and Longitude from TLE. Parameters ========== epochs : List of Ticktock objects. TLEpath : Path to TLE file. options : optparse.Values Organized options from the command line. Returns ======= testlat, testlon, testrad : list, list, list Latitude, Longitude, and Radius, respectively, each being a list of float values. """ # now do Mike's setup for getting coords from TLE using SGP4 pos_in = [0, 0, 0] s = _SgpInfo() TLEs = _SgpTLE() # loop over all times testlat = np.asarray(epochs).copy() testlat.fill(0) testlon = testlat.copy() testrad = testlat.copy() testtdiff = testlat.copy() print('Fetching TLEs & converting for range {0} to {1}'.format( epochs[0].isoformat(), epochs[-1].isoformat())) for idx, c_date in enumerate(epochs): #print('Doing {0}'.format(c_date)) # put into JD as SGP4 needs serial time c = Lgm_init_ctrans(0) # now do Mike's setup for getting coords from TLE using SGP4 dstr = int(c_date.strftime('%Y%j')) + c_date.hour / 24.0 + \ c_date.minute / 1440.0 + c_date.second / 86400.0 globstat = os.path.join(TLEpath, '*.txt') TLEfiles = glob.glob(globstat) if not TLEfiles: raise IOError( 'No TLE files found in {0}. Aborting...'.format(TLEpath)) Line0, Line1, Line2 = fTLE.findTLEinfiles( TLEfiles, ParseMethod='UseSatelliteNumber', TargetEpoch=dstr, SatelliteNumber=options.SatNum, Verbose=False, PurgeDuplicates=True) # print("{0}\n{1}\n{2}\n\n".format(Line0,Line1,Line2)) nTLEs = c_int(0) LgmSgp_ReadTlesFromStrings(Line0, Line1, Line2, pointer(nTLEs), pointer(TLEs), 1) LgmSgp_SGP4_Init(pointer(s), pointer(TLEs)) date = Lgm_CTrans.dateToDateLong(c_date) utc = Lgm_CTrans.dateToFPHours(c_date) JD = Lgm_JD(c_date.year, c_date.month, c_date.day, utc, LGM_TIME_SYS_UTC, c) # Set up the trans matrices Lgm_Set_Coord_Transforms(date, utc, c) # get SGP4 output, needs minutes-since-TLE-epoch tsince = (JD - TLEs.JD) * 1440.0 LgmSgp_SGP4(tsince, pointer(s)) pos_in[0] = s.X pos_in[1] = s.Y pos_in[2] = s.Z Pin = Lgm_Vector.Lgm_Vector(*pos_in) Pout = Lgm_Vector.Lgm_Vector() Lgm_Convert_Coords(pointer(Pin), pointer(Pout), TEME_TO_GEO, c) PoutPy = Pout.tolist() PoutPy[0] /= WGS84_A PoutPy[1] /= WGS84_A PoutPy[2] /= WGS84_A nlat, nlon, nrad = Lgm_Vector.CartToSph(*PoutPy) testlat[idx] = nlat testlon[idx] = nlon testrad[idx] = nrad testtdiff[idx] = tsince / 1440.0 return testlat, testlon, testrad
def getLatLonRadfromTLE(epochs, TLEpath, options): """ Reads Latitude and Longitude from TLE. Parameters ========== epochs : List of Ticktock objects. TLEpath : Path to TLE file. options : optparse.Values Organized options from the command line. Returns ======= testlat, testlon, testrad : list, list, list Latitude, Longitude, and Radius, respectively, each being a list of float values. """ # now do Mike's setup for getting coords from TLE using SGP4 pos_in = [0, 0, 0] s = _SgpInfo() TLEs = _SgpTLE() # loop over all times testlat = np.asarray(epochs).copy() testlat.fill(0) testlon = testlat.copy() testrad = testlat.copy() testtdiff = testlat.copy() print('Fetching TLEs & converting for range {0} to {1}'.format( epochs[0].isoformat(), epochs[-1].isoformat())) for idx, c_date in enumerate(epochs): #print('Doing {0}'.format(c_date)) # put into JD as SGP4 needs serial time c = Lgm_init_ctrans(0) # now do Mike's setup for getting coords from TLE using SGP4 dstr = int(c_date.strftime('%Y%j')) + c_date.hour / 24.0 + \ c_date.minute / 1440.0 + c_date.second / 86400.0 globstat = os.path.join(TLEpath, '*.txt') TLEfiles = glob.glob(globstat) if not TLEfiles: raise IOError( 'No TLE files found in {0}. Aborting...'.format(TLEpath)) Line0, Line1, Line2 = fTLE.findTLEinfiles( TLEfiles, ParseMethod='UseSatelliteNumber', TargetEpoch=dstr, SatelliteNumber=options.SatNum, Verbose=False, PurgeDuplicates=True) # print("{0}\n{1}\n{2}\n\n".format(Line0,Line1,Line2)) nTLEs = c_int(0) LgmSgp_ReadTlesFromStrings( Line0, Line1, Line2, pointer(nTLEs), pointer(TLEs), 1) LgmSgp_SGP4_Init(pointer(s), pointer(TLEs)) date = Lgm_CTrans.dateToDateLong(c_date) utc = Lgm_CTrans.dateToFPHours(c_date) JD = Lgm_JD( c_date.year, c_date.month, c_date.day, utc, LGM_TIME_SYS_UTC, c) # Set up the trans matrices Lgm_Set_Coord_Transforms(date, utc, c) # get SGP4 output, needs minutes-since-TLE-epoch tsince = (JD - TLEs.JD) * 1440.0 LgmSgp_SGP4(tsince, pointer(s)) pos_in[0] = s.X pos_in[1] = s.Y pos_in[2] = s.Z Pin = Lgm_Vector.Lgm_Vector(*pos_in) Pout = Lgm_Vector.Lgm_Vector() Lgm_Convert_Coords(pointer(Pin), pointer(Pout), TEME_TO_GEO, c) PoutPy = Pout.tolist() PoutPy[0] /= WGS84_A PoutPy[1] /= WGS84_A PoutPy[2] /= WGS84_A nlat, nlon, nrad = Lgm_Vector.CartToSph(*PoutPy) testlat[idx] = nlat testlon[idx] = nlon testrad[idx] = nrad testtdiff[idx] = tsince / 1440.0 return testlat, testlon, testrad
def coordTrans(pos_in, time_in, in_sys, out_sys, de_eph=False): ''' Convert coordinates between almost any system using LanlGeoMag Parameters ---------- position : list a three element vector of positions in input coord system time : datetime a datimetime object representing the time at the desired conversion system_in : str a string giving the acronym for the input coordinate system system_out : str a string giving the acronym for the desired output coordinate system de_eph : bool or int (optional) a boolean stating whether JPL DE421 is to be used for Sun, etc. Returns ------- out : list 3-element list of the converted coordinate Examples -------- >>> from lgmpy import magcoords >>> import datetime >>> magcoords.coordTrans([-4,0,0], datetime.datetime(2009,1,1),'SM','GSM') [-3.60802691..., 2.5673907444...e-16, -1.72688788616...] >>> magcoords.coordTrans([-3.608026916281573, 2.5673907444456745e-16, -1.7268878861662329], datetime.datetime(2009,1,1),'GSM','SM') [-3.99999999..., 4.0592529337...e-16, 8.8817841970...3e-16] TODO ---- extend interface to get necessary args from a MagModel or cTrans structure ''' # change datetime to Lgm Datelong and UTC ct = Lgm_CTrans.Lgm_CTrans(0) if de_eph: Lgm_Set_CTrans_Options(LGM_EPH_DE, LGM_PN_IAU76, pointer(ct)) try: datelong = Lgm_CTrans.dateToDateLong(time_in) utc = Lgm_CTrans.dateToFPHours(time_in) Lgm_Set_Coord_Transforms( datelong, utc, pointer(ct)) # don't need pointer as it is one except AttributeError: raise(TypeError("Date must be a datetime object")) try: conv_val = trans_dict[in_sys]*100 + trans_dict[out_sys] except KeyError: raise KeyError('One of the specified coordinate systems is not recognised') ## do this as WGS uses Cartesian but needs to be converted from desired spherical input if 'WGS84' in in_sys: XYZ = Lgm_Vector.SphToCart(*pos_in) SPH = Lgm_Vector.Lgm_Vector(XYZ.x,XYZ.y, XYZ.z) Pout = _doConversion(SPH, conv_val, cTrans=ct) else: Pout = _doConversion(pos_in, conv_val, ct) if 'WGS84' in out_sys: nlat, nlon, nrad = Lgm_Vector.CartToSph(*Pout.tolist()) Pout = Lgm_Vector.Lgm_Vector(nlat, nlon, nrad) return Pout.tolist()
def Lvalue(*args, **kwargs): ''' Function to return the L-value of a position using either McIlwain or Hilton approximation Parameters ========== pos : list 3-element position int he specified coord_system time : datetime date and time for the calculation alpha : float, optional the pitch angle for the L calculation, default=90 Bfield : str, optional the magnetic field model to use, default=Lgm_B_T89 method : str, optional the L-value formula to use, McIlwain or Hilton, default=Hilton Kp : int Kp index value for the calculation coord_system : str the input coordinate system, default=GSM extended_out : bool keyword specifying short or extended output, default=False Returns ======= out : dict dictionary of the values, see examples for documentation of dictionary Examples ======== >>> from lgmpy import magcoords >>> import datetime >>> magcoords.Lvalue([3, 0, 1], datetime.datetime(2000, 1, 1), extended_out=False) {'I': 0.2434969602..., 'L': 3.195481841...} The ``extended_out=False`` output is: - I : I value at the given point - L : L value at the given point >>> from lgmpy import magcoords >>> import datetime >>> magcoords.Lvalue([3, 0, 1], datetime.datetime(2000, 1, 1), extended_out=True) {'Blocal': 1024.1142193703838, 'Bmin': 921.8869150..., 'Bmirr': 1024.1142193..., 'I': 0.24349696021..., 'L': 3.1954818410..., 'M': 30119.614287...} The ``extended_out=True`` output is: - I : I value at the given point - L : L value at the given point - Bmin : minimum B at the input position (nT) - Bmirror : mirror B at the input position (nT) - M : TODO what exactly and I, magnetic moment? ''' defaults = {'alpha': 90., 'Bfield': 'Lgm_B_T89', 'method': 'Hilton', 'Kp': 2, 'coord_system': 'GSM', 'extended_out': False} #replace missing kwargs with defaults for dkey in defaults: if dkey not in kwargs: kwargs[dkey] = defaults[dkey] method_dict = {'Hilton': 1, 'McIlwain': 0} # change datetime to Lgm Datelong and UTC mInfo = Lgm_MagModelInfo.Lgm_MagModelInfo() mInfo.Kp = kwargs['Kp'] try: Bfield_dict[kwargs['Bfield']](pointer(mInfo)) except KeyError: raise(NotImplementedError("Only Bfield=%s currently supported" % Bfield_dict.keys())) try: datelong = Lgm_CTrans.dateToDateLong(args[1]) utc = Lgm_CTrans.dateToFPHours(args[1]) Lgm_Set_Coord_Transforms( datelong, utc, mInfo.c) # dont need pointer as it is one except AttributeError: raise(TypeError("Date must be a datetime object")) #else: #ans['Epoch'] = datamodel.dmarray([args[1]]) if kwargs['coord_system'] != 'GSM': in_sys = kwargs['coord_system'] Pout = coordTrans(args[0], args[1], in_sys, 'GSM', de_eph=False) Pgsm = Lgm_Vector.Lgm_Vector(*Pout) else: Pgsm = Lgm_Vector.Lgm_Vector(*args[0]) Iout = c_double() Bm = c_double() M = c_double() ans = Lgm_McIlwain_L(datelong, utc, pointer(Pgsm), kwargs['alpha'], method_dict[kwargs['method']], pointer(Iout), pointer(Bm), pointer(M), pointer(mInfo)) #TODO: decide on format for output -- perhaps use datamodel and have method as attribute? #maybe only return I for extended_out flag=True if kwargs['extended_out']: sunPos_GSM = coordTrans(mInfo.c.contents.Sun, args[1], 'MOD', kwargs['coord_system']) SunMlon = np.rad2deg(np.arctan2( sunPos_GSM[1], sunPos_GSM[0])) SunMlon += 180.0 # flip to midnight MLON = np.rad2deg(np.arctan2( Pgsm.y, Pgsm.x)) if (MLON < 0.0): MLON += 360.0 MLT = np.mod( (MLON-SunMlon)/15.0+24.0, 24.0 ) return {'L': ans, 'I': Iout.value, 'Bmin': mInfo.Bmin, 'Blocal': mInfo.Blocal, 'Bmirr': mInfo.Bm, 'M': M.value, 'MLon':MLON, 'MLT':MLT} else: return {'L': ans, 'I': Iout.value}
def coordTrans(pos_in, time_in, in_sys, out_sys, de_eph=False): ''' Convert coordinates between almost any system using LanlGeoMag Parameters ---------- position : list a three element vector of positions in input coord system time : datetime a datimetime object representing the time at the desired conversion system_in : str a string giving the acronym for the input coordinate system system_out : str a string giving the acronym for the desired output coordinate system de_eph : bool or int (optional) a boolean stating whether JPL DE421 is to be used for Sun, etc. Returns ------- out : list 3-element list of the converted coordinate Examples -------- >>> from lgmpy import magcoords >>> import datetime >>> magcoords.coordTrans([-4,0,0], datetime.datetime(2009,1,1),'SM','GSM') [-3.60802691..., 2.5673907444...e-16, -1.72688788616...] >>> magcoords.coordTrans([-3.608026916281573, 2.5673907444456745e-16, -1.7268878861662329], datetime.datetime(2009,1,1),'GSM','SM') [-3.99999999..., 4.0592529337...e-16, 8.8817841970...3e-16] TODO ---- extend interface to get necessary args from a MagModel or cTrans structure ''' # change datetime to Lgm Datelong and UTC ct = Lgm_CTrans.Lgm_CTrans(0) if de_eph: Lgm_Set_CTrans_Options(LGM_EPH_DE, LGM_PN_IAU76, pointer(ct)) try: datelong = Lgm_CTrans.dateToDateLong(time_in) utc = Lgm_CTrans.dateToFPHours(time_in) Lgm_Set_Coord_Transforms( datelong, utc, pointer(ct)) # don't need pointer as it is one except AttributeError: raise (TypeError("Date must be a datetime object")) try: conv_val = trans_dict[in_sys] * 100 + trans_dict[out_sys] except KeyError: raise KeyError( 'One of the specified coordinate systems is not recognised') ## do this as WGS uses Cartesian but needs to be converted from desired spherical input if 'WGS84' in in_sys: XYZ = Lgm_Vector.SphToCart(*pos_in) SPH = Lgm_Vector.Lgm_Vector(XYZ.x, XYZ.y, XYZ.z) Pout = _doConversion(SPH, conv_val, cTrans=ct) else: Pout = _doConversion(pos_in, conv_val, ct) if 'WGS84' in out_sys: nlat, nlon, nrad = Lgm_Vector.CartToSph(*Pout.tolist()) Pout = Lgm_Vector.Lgm_Vector(nlat, nlon, nrad) return Pout.tolist()
def Lvalue(*args, **kwargs): ''' Function to return the L-value of a position using either McIlwain or Hilton approximation Parameters ========== pos : list 3-element position int he specified coord_system time : datetime date and time for the calculation alpha : float, optional the pitch angle for the L calculation, default=90 Bfield : str, optional the magnetic field model to use, default=Lgm_B_T89 method : str, optional the L-value formula to use, McIlwain or Hilton, default=Hilton Kp : int Kp index value for the calculation coord_system : str the input coordinate system, default=GSM extended_out : bool keyword specifying short or extended output, default=False Returns ======= out : dict dictionary of the values, see examples for documentation of dictionary Examples ======== >>> from lgmpy import magcoords >>> import datetime >>> magcoords.Lvalue([3, 0, 1], datetime.datetime(2000, 1, 1), extended_out=False) {'I': 0.2434969602..., 'L': 3.195481841...} The ``extended_out=False`` output is: - I : I value at the given point - L : L value at the given point >>> from lgmpy import magcoords >>> import datetime >>> magcoords.Lvalue([3, 0, 1], datetime.datetime(2000, 1, 1), extended_out=True) {'Blocal': 1024.1142193703838, 'Bmin': 921.8869150..., 'Bmirr': 1024.1142193..., 'I': 0.24349696021..., 'L': 3.1954818410..., 'M': 30119.614287...} The ``extended_out=True`` output is: - I : I value at the given point - L : L value at the given point - Bmin : minimum B at the input position (nT) - Bmirror : mirror B at the input position (nT) - M : TODO what exactly and I, magnetic moment? ''' defaults = { 'alpha': 90., 'Bfield': 'Lgm_B_T89', 'method': 'Hilton', 'Kp': 2, 'coord_system': 'GSM', 'extended_out': False } #replace missing kwargs with defaults for dkey in defaults: if dkey not in kwargs: kwargs[dkey] = defaults[dkey] method_dict = {'Hilton': 1, 'McIlwain': 0} # change datetime to Lgm Datelong and UTC mInfo = Lgm_MagModelInfo.Lgm_MagModelInfo() mInfo.Kp = kwargs['Kp'] try: Bfield_dict[kwargs['Bfield']](pointer(mInfo)) except KeyError: raise (NotImplementedError("Only Bfield=%s currently supported" % Bfield_dict.keys())) try: datelong = Lgm_CTrans.dateToDateLong(args[1]) utc = Lgm_CTrans.dateToFPHours(args[1]) Lgm_Set_Coord_Transforms(datelong, utc, mInfo.c) # dont need pointer as it is one except AttributeError: raise (TypeError("Date must be a datetime object")) #else: #ans['Epoch'] = datamodel.dmarray([args[1]]) if kwargs['coord_system'] != 'GSM': in_sys = kwargs['coord_system'] Pout = coordTrans(args[0], args[1], in_sys, 'GSM', de_eph=False) Pgsm = Lgm_Vector.Lgm_Vector(*Pout) else: Pgsm = Lgm_Vector.Lgm_Vector(*args[0]) Iout = c_double() Bm = c_double() M = c_double() ans = Lgm_McIlwain_L(datelong, utc, pointer(Pgsm), kwargs['alpha'], method_dict[kwargs['method']], pointer(Iout), pointer(Bm), pointer(M), pointer(mInfo)) #TODO: decide on format for output -- perhaps use datamodel and have method as attribute? #maybe only return I for extended_out flag=True if kwargs['extended_out']: sunPos_GSM = coordTrans(mInfo.c.contents.Sun, args[1], 'MOD', kwargs['coord_system']) SunMlon = np.rad2deg(np.arctan2(sunPos_GSM[1], sunPos_GSM[0])) SunMlon += 180.0 # flip to midnight MLON = np.rad2deg(np.arctan2(Pgsm.y, Pgsm.x)) if (MLON < 0.0): MLON += 360.0 MLT = np.mod((MLON - SunMlon) / 15.0 + 24.0, 24.0) return { 'L': ans, 'I': Iout.value, 'Bmin': mInfo.Bmin, 'Blocal': mInfo.Blocal, 'Bmirr': mInfo.Bm, 'M': M.value, 'MLon': MLON, 'MLT': MLT } else: return {'L': ans, 'I': Iout.value}