# Copyright 2017 Regents of the University of Colorado. All Rights Reserved.
# Released under the MIT license.
# This software was developed at the University of Colorado's Laboratory for Atmospheric and Space Physics.
# Verify current version before use at: https://github.com/MAVENSDC/Pydivide
import math
import numpy as np
[docs]def read_model_results(file):
"""
Reads results of specified simulation into a dictionary object containing
sub-directories for metadata, dimension information, and model tracers.
This function can read any of the models currently on the MAVEN SDC
website with the .nc extension, which can be found here:
https://lasp.colorado.edu/maven/sdc/public/pages/models.html
The desired model must be downloaded prior to running this procedure
Parameters:
file: str
Simulation result file name to be read
Returns:
Dictionary roughly structured as follows
\_ meta ()
\_ longsubsol
\_ ls
\_ etc
\_ dim
\_ lat/x
\_ lon/y
\_ alt/z
\_ variable1
\_ dim_order (x,y,z or z,y,x for example)
\_ data
\_ variable2
\_ dim_order
\_ data
...
\_ variableN
Examples:
>>> # Read the University of Michigan group’s ionospheric model for mean solar activity (F10.7 = 130).
>>> model = pydivide.read_model_results('<dir_path>/MGITM_LS270_F130_150519.nc')
"""
try:
import netCDF4
except:
print("Install the python library netCDF4 to read model results")
print("pip install netCDF4")
return
import collections
# Create dictionaries for the metadata and dimensions
meta = collections.OrderedDict()
dim = collections.OrderedDict()
# Create a dictionary for the above dictionaries
results = collections.OrderedDict()
model = netCDF4.Dataset(file, "r+", format="NETCDF4")
lat_size = None
lon_size = None
alt_size = None
x_size = None
y_size = None
z_size = None
for unit in model.dimensions:
if unit.lower() == 'latitude':
lat_size = model.dimensions[unit].size
if unit.lower() == 'longitude':
lon_size = model.dimensions[unit].size
if unit.lower() == 'altitude':
alt_size = model.dimensions[unit].size
if unit.lower() == 'size_x' or unit.lower() == 'x':
x_size = model.dimensions[unit].size
if unit.lower() == 'size_y' or unit.lower() == 'y':
y_size = model.dimensions[unit].size
if unit.lower() == 'size_z' or unit.lower() == 'z':
z_size = model.dimensions[unit].size
if lat_size is not None:
if lon_size is None or alt_size is None:
print("Couldn't find all dimensions: LATITUDE,LONGITUDE,ALTITUDE")
dimension_type = "latlonalt"
elif x_size is not None:
if y_size is None or z_size is None:
print("Couldn't find all dimensions: X,Y,Z")
dimension_type = "xyz"
else:
print("Problem finding either cartesian (X,Y,Z) or Lat Lon Alt dimensions")
return
for var in model.variables:
if var.lower() == 'latitude':
dim['lat'] = model.variables[var][0:lat_size]
elif var.lower() == 'longitude':
lon_temp = model.variables[var][0:lon_size]
if np.max(lon_temp) > 180 and np.min(lon_temp) > 0:
lon_temp = np.array([(a - 360) if a > 180 else a for a in lon_temp])
dim['lon'] = lon_temp
elif var.lower() == 'altitude':
dim['alt'] = model.variables[var][0:alt_size]
elif var.lower() == 'x':
dim['x'] = model.variables[var][0:x_size]
elif var.lower() == 'y':
dim['y'] = model.variables[var][0:y_size]
elif var.lower() == 'z':
dim['z'] = model.variables[var][0:z_size]
elif var.lower() == 'coordinate_system':
if (model.variables[var]).dtype == np.dtype('S1'):
meta['coord_sys'] = ''.join([n.decode("utf-8") for n in model.variables[var]])
else:
meta['coord_sys'] = model.variables[var][0].strip()
elif var.lower() == 'ls':
if abs(model.variables[var][0]) >= 2 * math.pi:
meta['ls'] = model.variables[var][0]
else:
if 'units' in model.variables[var].__dict__:
if model.variables[var].__dict__['units'].lower == 'rad':
meta['ls'] = math.degrees(model.variables[var][0])
else:
meta['ls'] = model.variables[var][0]
else:
meta['ls'] = model.variables[var][0]
elif var.lower() == 'longsubsol':
import re
string = str(model.variables[var][0])
num = float((re.findall("[-+]?\d+[\.]?\d*[eE]?[-+]?\d*", string))[0])
if abs(num) >= 2 * math.pi:
meta['longsubsol'] = num
else:
if 'units' in model.variables[var].__dict__:
if model.variables[var].__dict__['units'].lower == 'rad':
meta['longsubsol'] = math.degrees(num)
else:
meta['longsubsol'] = num
else:
meta['longsubsol'] = num
elif var.lower() == 'dec':
if abs(model.variables[var][0]) >= 2 * math.pi:
meta['dec'] = model.variables[var][0]
else:
if 'units' in model.variables[var].__dict__:
if model.variables[var].__dict__['units'].lower == 'rad':
meta['dec'] = math.degrees(model.variables[var][0])
else:
meta['dec'] = model.variables[var][0]
else:
meta['dec'] = model.variables[var][0]
elif var.lower() == 'mars_radius':
meta['mars_radius'] = model.variables[var][0]
elif var.lower() == 'altitude_from':
meta['altitude_from'] = model.variables[var][0]
else:
if (len(model.variables[var].shape) == 3) or (len(model.variables[var].shape) == 4):
data = {}
if model.variables[var].units == 'm-3':
value = model.variables[var][:] / 1000000.0
else:
value = model.variables[var][:]
dim_order = model.variables[var].dimensions
dim_order = [dim.replace('size_x', 'x') for dim in dim_order]
dim_order = [dim.replace('size_y', 'y') for dim in dim_order]
dim_order = [dim.replace('size_z', 'z') for dim in dim_order]
data['data'] = value
data['dim_order'] = dim_order
results[var] = data
# Create a dictionary of dictionaries for the model results
results['meta'] = meta
results['dim'] = dim
return results