Skip to content

Commit

Permalink
WIP on #4
Browse files Browse the repository at this point in the history
  • Loading branch information
KCollins committed Sep 14, 2024
1 parent a0ea04b commit a1d84d6
Showing 1 changed file with 106 additions and 70 deletions.
176 changes: 106 additions & 70 deletions conjugate_map/conjCalcFunctions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,23 @@
import plotly.express as px
import plotly.graph_objects as go


###############################################################################
def findconj(lat, lon, ut=dt.datetime.utcnow(), is_verbose=False, method='aacgm', limit=60):
def findconj(lat, lon, ut=dt.datetime.utcnow(),
is_verbose=False, method='aacgm', limit=60):

"""
Calculate the geographic latitudes and longitudes of conjugate point for a
given set of coordinates.
Arguments:
lat : geographic latitude of station whose conjugate point we're finding
lon : geographic longitude of station whose conjugate point we're finding
lat : geographic latitude of station
lon : geographic longitude of station
ut : datetime used in conversion
is_verbose : if set to True, prints debugging text
method : method used in conversion. Options are 'auto', 'geopack', which uses IGRF + T89 to run field line traces, or 'aacgm'.
method : method used in conversion. Options are 'auto', 'geopack',
which uses IGRF + T89 to run field line traces,
or 'aacgm', which uses AACGM v2.
limit : latitude limit, in degrees, used to switch between
methods in auto mode. Default: 60.
AACGM will converge above 35 degrees, but may be
Expand All @@ -35,78 +39,96 @@ def findconj(lat, lon, ut=dt.datetime.utcnow(), is_verbose=False, method='aacgm'
Returns:
lat, lon : latitude, longitude of conjugate points
"""
method = method.lower() # Cast method as lowercase, in case someone uses capitals.
method = method.lower() # Cast method as lowercase

if method == 'auto':
if(abs(lat) > limit): method = 'aacgm'
if abs(lat) > limit:
method = 'aacgm'
else:
method = 'geopack'
if(is_verbose): print("Setting method according to latitude limits: " + method)
if is_verbose:
print("Setting method according to latitude limits: " + method)

if(method == 'geopack'):
if method == 'geopack':
ut = ut.timestamp()
ps = gp.recalc(ut)
if is_verbose: print('............................................Calculating conjugate point for ' + str(lat) + ', '+ str(lon) + ' at ' + str(ut) + ' with geopack: ')
if is_verbose:
print('............................................Calculating conjugate point for ' + str(lat) + ', ' + str(lon) + ' at ' + str(ut) + ' with geopack: ')

r, theta, phi = [1, 90-lat, lon] # r is Earth radii; theta is colatitude (i.e., in degrees from 0 (North Pole) to 360 (South Pole)); phi is longitude in degrees
r, theta, phi = [1, 90-lat, lon]
# r is Earth radii; theta is colatitude (i.e., in degrees from 0 (North
# Pole) to 360 (South Pole)); phi is longitude in degrees.

theta, phi = np.deg2rad([theta, phi])
if is_verbose: print('r, theta, phi: ')
if is_verbose: print(r, theta, phi)
if is_verbose:
print('r, theta, phi: ')
print(r, theta, phi)
xgeo, ygeo, zgeo = gp.sphcar(r, theta, phi, 1)
if is_verbose: print('Cartesian output: ')
if is_verbose: print(xgeo, ygeo, zgeo)
if is_verbose: print('Sum of squares (should be 1):')
if is_verbose: print(xgeo**2 + ygeo**2 + zgeo**2)
if is_verbose: print('GSM coordinates: ')
xgsm,ygsm,zgsm = gp.geogsm(xgeo,ygeo,zgeo, 1)
if is_verbose: print(xgsm,ygsm,zgsm)
if is_verbose: print('Sum of squares (should be 1):')
if is_verbose: print(xgsm**2 + ygsm**2 + zgsm**2)

# Now let's try running the field line trace: See help(gp.trace) for documentation.
if is_verbose:
print('Cartesian output: ')
print(xgeo, ygeo, zgeo)
print('Sum of squares (should be 1):')
print(xgeo**2 + ygeo**2 + zgeo**2)
print('GSM coordinates: ')
xgsm, ygsm, zgsm = gp.geogsm(xgeo, ygeo, zgeo, 1)
if is_verbose:
print(xgsm, ygsm, zgsm)
print('Sum of squares (should be 1):')
print(xgsm**2 + ygsm**2 + zgsm**2)

# Now let's try running the field line trace: help(gp.trace) for doc.
rlim, r0 = [1000, .9]

#

foo= gp.trace(xgsm,ygsm,zgsm, dir=-1, rlim=rlim, r0=r0, parmod=2, exname='t89', inname='igrf')
foo = gp.trace(xgsm, ygsm, zgsm, dir=-1, rlim=rlim, r0=r0, parmod=2,
exname='t89', inname='igrf')

# if is_verbose: print(x1gsm,y1gsm,z1gsm)

x1gsm,y1gsm,z1gsm = foo[0:3]
if is_verbose: print('Traced GSM Coordinates, Cartesian: ')
if is_verbose: print(x1gsm,y1gsm,z1gsm)
if is_verbose: print(str(len(foo[4])) + ' points in traced vector.')
if is_verbose: print('Sum of squares (should be 1):')
if is_verbose: print(x1gsm**2 + y1gsm**2 + z1gsm**2)
x1gsm, y1gsm, z1gsm = foo[0:3]
if is_verbose:
print('Traced GSM Coordinates, Cartesian: ')
print(x1gsm, y1gsm, z1gsm)
print(str(len(foo[4])) + ' points in traced vector.')
print('Sum of squares (should be 1):')
print(x1gsm**2 + y1gsm**2 + z1gsm**2)

# geogsm
x1geo, y1geo, z1geo = gp.geogsm(x1gsm,y1gsm,z1gsm,-1)
if is_verbose: print('Geographic coordinates, Cartesian: ')
if is_verbose: print(x1geo, y1geo, z1geo)
if is_verbose: print('Sum of squares (should be 1):')
if is_verbose: print(x1geo**2 + y1geo**2 + z1geo**2)
x1geo, y1geo, z1geo = gp.geogsm(x1gsm, y1gsm, z1gsm, -1)
if is_verbose:
print('Geographic coordinates, Cartesian: ')
print(x1geo, y1geo, z1geo)
print('Sum of squares (should be 1):')
print(x1geo**2 + y1geo**2 + z1geo**2)

# convert back to spherical
if is_verbose: print('Geographic coordinates, spherical: ')
[x1_r, x1_theta, x1_phi] = gp.sphcar(x1geo,y1geo,z1geo,-1)
if is_verbose: print(x1_r, x1_theta, x1_phi)
if is_verbose:
print('Geographic coordinates, spherical: ')
[x1_r, x1_theta, x1_phi] = gp.sphcar(x1geo, y1geo, z1geo, -1)
if is_verbose:
print(x1_r, x1_theta, x1_phi)

# back to lat/long:
x1_theta, x1_phi = np.rad2deg([x1_theta, x1_phi])
if is_verbose: print('Lat/lon of conjugate point: ')
if is_verbose:
print('Lat/lon of conjugate point: ')
lat = 90-x1_theta
lon = x1_phi
if is_verbose: print(lat, lon)
if is_verbose:
print(lat, lon)
return lat, lon

elif(method == "aacgm"):
if is_verbose: print('............................................Calculating conjugate point for ' + str(lat) + ', '+ str(lon) + ' at ' + str(ut) + ' with AACGMV2: ')
mlat,mlon,_ = aacgmv2.convert_latlon(lat,lon,0,ut,'G2A')
if is_verbose: print('Magnetic lat/lon: ' + str([mlat, mlon]))
glat_con,glon_con,_ = aacgmv2.convert_latlon(-1.*mlat,mlon,0,ut,'A2G')
if is_verbose: print('Conjugate geographic lat/lon: ' + str([glat_con,glon_con]))
return glat_con,glon_con
elif method == "aacgm":
if is_verbose:
print('............................................Calculating conjugate point for ' + str(lat) + ', ' + str(lon) + ' at ' + str(ut) + ' with AACGMV2: ')
mlat, mlon, _ = aacgmv2.convert_latlon(lat, lon, 0, ut, 'G2A')
if is_verbose:
print('Magnetic lat/lon: ' + str([mlat, mlon]))
glat_con, glon_con, _ = aacgmv2.convert_latlon(-1.*mlat, mlon, 0, ut, 'A2G')
if is_verbose:
print('Conjugate geographic lat/lon: ' + str([glat_con, glon_con]))
return glat_con, glon_con

# foo = aacgmv2.wrapper.convert_latlon(lat, lon, 300, ut, method_code="trace")
# return foo[0], foo[1]
Expand All @@ -116,7 +138,9 @@ def findconj(lat, lon, ut=dt.datetime.utcnow(), is_verbose=False, method='aacgm'

###############################################################################

def conjcalc(gdf, latname="GLAT", lonname="GLON", dtime = dt.datetime.utcnow(), is_verbose = False, method = 'aacgm', mode = 'S2N', is_saved = False, directory='output/', name = 'stations'):
def conjcalc(gdf, latname="GLAT", lonname="GLON", dtime=dt.datetime.utcnow(),
is_verbose=False, method='aacgm', mode='S2N', is_saved=False,
directory='output/', name='stations'):
"""
Calculate the geographic latitudes and longitudes of conjugate points for
all points in a dataframe. Calls findconj().
Expand All @@ -140,7 +164,7 @@ def conjcalc(gdf, latname="GLAT", lonname="GLON", dtime = dt.datetime.utcnow(),
for northern. Map appears over
the Antarctic.
'flip' : Return conjugate coordinates for
all points regardless of hemisphere.
points regardless of hemisphere.
is_saved : Boolean dictating whether the final .csv is saved to
the output directory.
directory : Name of local directory to which .csv is saved;
Expand All @@ -161,9 +185,11 @@ def conjcalc(gdf, latname="GLAT", lonname="GLON", dtime = dt.datetime.utcnow(),
try:
lat = row[latname]
lon = row[lonname]
if is_verbose: print('Checking hemisphere.')
if is_verbose:
print('Checking hemisphere.')
if type(lon) == str:
if is_verbose: print('Longitude encoded as string. Fixing...')
if is_verbose:
print('Longitude encoded as string. Fixing...')
try:
lon = lon.replace('−', '-')
lon = float(lon)
Expand All @@ -180,31 +206,36 @@ def conjcalc(gdf, latname="GLAT", lonname="GLON", dtime = dt.datetime.utcnow(),
print(e)
continue
# print(type(lon))
if lon>180: lon = lon-360
if lon > 180:
lon = lon-360
try:
[clat, clon] = findconj(lat, lon, dtime, is_verbose = is_verbose, method = method)
if is_verbose: print('Conjugate latitude and longitude: '), print([clat, clon])
gdf.loc[index, 'PLAT'],gdf.loc[index, 'PLON'] = [clat, clon]
[clat, clon] = findconj(lat, lon, dtime, is_verbose=is_verbose,
method=method)
if is_verbose:
print('Conjugate latitude and longitude: '),
print([clat, clon])
gdf.loc[index, 'PLAT'], gdf.loc[index, 'PLON'] = [clat, clon]
except Exception as e:
print('Ran into a problem with ' + index)
print(e)


# Figure out what coordinates we ultimately want to plot:
if lat>0:
if is_verbose: print('Setting Northern hemisphere for GLAT of ' + str(lat) + ' on station ' + index)
if lat > 0:
if is_verbose:
print('Setting Northern hemisphere for GLAT of ' + str(lat) + ' on station ' + index)
gdf.loc[index, 'Hemisphere'] = 'N'
if((mode == 'N2S') or (mode == 'flip')):
if (mode == 'N2S' or mode == 'flip'):
gdf.loc[index, 'PLAT'] = clat
gdf.loc[index, 'PLON'] = clon
else:
gdf.loc[index, 'PLAT'] = lat
gdf.loc[index, 'PLON'] = lon

else:
if is_verbose: print('Setting Southern hemisphere for GLAT of ' + str(lat) + ' on station ' + index)
if is_verbose:
print('Setting Southern hemisphere for GLAT of ' + str(lat) + ' on station ' + index)
gdf.loc[index, 'Hemisphere'] = 'S'
if((mode == 'S2N') or (mode == 'flip')):
if (mode == 'S2N' or mode == 'flip'):
gdf.loc[index, 'PLAT'] = clat
gdf.loc[index, 'PLON'] = clon
else:
Expand All @@ -217,14 +248,15 @@ def conjcalc(gdf, latname="GLAT", lonname="GLON", dtime = dt.datetime.utcnow(),
continue

if is_saved:
filename = name + '_' + mode + '-'+ method + '-'+ str(dtime)
gdf.to_csv(directory + filename +'.csv') #save as .csv
filename = name + '_' + mode + '-' + method + '-' + str(dtime)
gdf.to_csv(directory + filename + '.csv') # save as .csv

return gdf

###############################################################################

def calc_mlat_rings(mlats,ut=dt.datetime.utcnow(), is_verbose = False, is_saved = 'False'):

def calc_mlat_rings(mlats, ut=dt.datetime.utcnow(), is_verbose=False, is_saved='False'):
"""
Calculate the geographic latitudes and longitudes of a circle of points
for a list of magnetic latitudes.
Expand All @@ -240,10 +272,13 @@ def calc_mlat_rings(mlats,ut=dt.datetime.utcnow(), is_verbose = False, is_saved
mlats_dct: dictionary with geographic latitude and longitude
points for each of the specified magnetic latitudes
Example use: Saves .gpx magnetic graticules for 1 January 2020 every 5 degrees latitude.
rings = calc_mlat_rings(list(range(-90, 90, 5)), ut = dt.datetime(2020, 1, 1), is_saved = True)
Example use: Saves .gpx magnetic graticules for 1 January 2020 every 5
degrees latitude:
rings = calc_mlat_rings(list(range(-90, 90, 5)), ut =
dt.datetime(2020, 1, 1), is_saved = True)
"""
mlons = np.arange(0,360)
mlons = np.arange(0, 360)
mlats_dct = {}
for mlat in mlats:
glats = []
Expand All @@ -253,10 +288,11 @@ def calc_mlat_rings(mlats,ut=dt.datetime.utcnow(), is_verbose = False, is_saved
glats.append(result[0])
glons.append(result[1])

mlats_dct[mlat] = {'glats':glats, 'glons':glons}
mlats_dct[mlat] = {'glats': glats, 'glons': glons}

if(is_saved == True):
if is_verbose: print('Saving magnetic graticule for ' + str(mlat) + ' degrees magnetic latitude.')
if is_saved is True:
if is_verbose:
print('Saving magnetic graticule for ' + str(mlat) + ' degrees magnetic latitude.')
filename = 'Graticule_ ' + str(mlat) + '_' + str(ut)
directory = 'output/'
df = pd.DataFrame({'MLAT': mlats_dct[mlat]['glats'], 'MLON': mlats_dct[mlat]['glons']})
Expand Down

0 comments on commit a1d84d6

Please sign in to comment.