-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Map variables and streams from MPAS dycore names to MPAS-Analysis names #52
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
b0123b5
Add to_datetime and to_timedelta to the Date class
xylar 9f2a10c
Make time-series scripts use timeseries_yr1 & 2
xylar 04d4243
Add has_stream and find_stream to streams file reader
xylar a473604
Add support to mpas_xarray for a variable map
xylar 6bbc655
Add variable map test to mpas_xarray testing
xylar 2162604
Add ocean dicts mapping stream and variable names
xylar 086fa10
Add stream and var maps to run_analysis and to OHC
xylar 3d94d67
Add stream and variable maps to SST analysis
xylar 666978e
Add variable and stream maps to ocean/modelvsobs
xylar 0ed2b5c
Add variable and stream maps to sea-ice analysis
xylar 8de2a50
Update docstrings and formatting in analysis scripts
xylar 9b9434e
Update variable_map --> varmap in analysis scripts and test
xylar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,8 +3,8 @@ | |
General comparison of 2-d model fields against data. Currently only supports | ||
mixed layer depths (mld) and sea surface temperature (sst) | ||
|
||
Author: Luke Van Roekel, Milena Veneziani | ||
Last Modified: 10/24/2016 | ||
Author: Luke Van Roekel, Milena Veneziani, Xylar Asay-Davis | ||
Last Modified: 12/06/2016 | ||
""" | ||
|
||
import matplotlib.pyplot as plt | ||
|
@@ -14,22 +14,35 @@ | |
import xarray as xr | ||
import datetime | ||
from netCDF4 import Dataset as netcdf_dataset | ||
import os.path | ||
|
||
from ..shared.mpas_xarray.mpas_xarray import preprocess_mpas, remove_repeated_time_index | ||
from ..shared.mpas_xarray.mpas_xarray import preprocess_mpas, \ | ||
remove_repeated_time_index | ||
from ..shared.plot.plotting import plot_global_comparison | ||
from ..shared.interpolation.interpolate import interp_fields, init_tree | ||
from ..shared.constants import constants | ||
|
||
from ..shared.io import StreamsFile | ||
|
||
def ocn_modelvsobs(config, field): | ||
|
||
def ocn_modelvsobs(config, field, streamMap=None, variableMap=None): | ||
|
||
""" | ||
Plots a comparison of ACME/MPAS output to SST or MLD observations | ||
|
||
config is an instance of MpasAnalysisConfigParser containing configuration | ||
options. | ||
|
||
field is the name of a field to be analyize (currently one of 'mld' or | ||
'sst') | ||
|
||
If present, streamMap is a dictionary of MPAS-O stream names that map to | ||
their mpas_analysis counterparts. | ||
|
||
If present, variableMap is a dictionary of MPAS-O variable names that map | ||
to their mpas_analysis counterparts. | ||
|
||
Authors: Luke Van Roekel, Milena Veneziani, Xylar Asay-Davis | ||
Modified: 10/27/2016 | ||
Modified: 12/08/2016 | ||
""" | ||
|
||
# read parameters from config file | ||
|
@@ -42,70 +55,62 @@ def ocn_modelvsobs(config, field): | |
# reading only those that are between the start and end dates | ||
startDate = config.get('time', 'climo_start_date') | ||
endDate = config.get('time', 'climo_end_date') | ||
infiles = streams.readpath('timeSeriesStatsOutput', | ||
startDate=startDate, endDate=endDate) | ||
print 'Reading files {} through {}'.format(infiles[0],infiles[-1]) | ||
streamName = streams.find_stream(streamMap['timeSeriesStats']) | ||
infiles = streams.readpath(streamName, startDate=startDate, | ||
endDate=endDate) | ||
print 'Reading files {} through {}'.format(infiles[0], infiles[-1]) | ||
|
||
plots_dir = config.get('paths', 'plots_dir') | ||
obsdir = config.get('paths', 'obs_' + field.lower() + 'dir') | ||
obsdir = config.get('paths', 'obs_' + field + 'dir') | ||
casename = config.get('case', 'casename') | ||
meshfile = config.get('data', 'mpas_meshfile') | ||
climo_yr1 = config.getint('time', 'climo_yr1') | ||
climo_yr2 = config.getint('time', 'climo_yr2') | ||
yr_offset = config.getint('time', 'yr_offset') | ||
|
||
outputTimes = config.getExpression(field.lower() + '_modelvsobs', | ||
outputTimes = config.getExpression(field + '_modelvsobs', | ||
'comparisonTimes') | ||
|
||
f = netcdf_dataset(meshfile,mode='r') | ||
f = netcdf_dataset(meshfile, mode='r') | ||
lonCell = f.variables["lonCell"][:] | ||
latCell = f.variables["latCell"][:] | ||
|
||
if field.lower() == 'mld': | ||
obs_filename = "%s/holtetalley_mld_climatology.nc" % obsdir | ||
varList = [field] | ||
|
||
ds = xr.open_mfdataset(infiles, preprocess=lambda x: | ||
preprocess_mpas(x, yearoffset=yr_offset, | ||
timestr=['xtime_start', 'xtime_end'], | ||
onlyvars=['time_avg_dThreshMLD'])) | ||
ds = remove_repeated_time_index(ds) | ||
ds.rename({'time_avg_dThreshMLD':'mpasData'}, inplace = True) | ||
if field == 'mld': | ||
|
||
#Load MLD observational data | ||
selvals = None | ||
|
||
# Load MLD observational data | ||
obs_filename = "{}/holtetalley_mld_climatology.nc".format(obsdir) | ||
dsData = xr.open_mfdataset(obs_filename) | ||
|
||
#Increment month value to be consistent with the model output | ||
# Increment month value to be consistent with the model output | ||
dsData.iMONTH.values += 1 | ||
|
||
#Rename the time dimension to be consistent with the SST dataset | ||
dsData.rename({'month':'calmonth'}, inplace = True) | ||
dsData.rename({'iMONTH':'month'}, inplace = True) | ||
# Rename the time dimension to be consistent with the SST dataset | ||
dsData.rename({'month': 'calmonth'}, inplace=True) | ||
dsData.rename({'iMONTH': 'month'}, inplace=True) | ||
|
||
#rename appropriate observational data for compactness | ||
dsData.rename({'mld_dt_mean':'observationData'}, inplace = True) | ||
obsFieldName = 'mld_dt_mean' | ||
|
||
#Reorder dataset for consistence | ||
# Reorder dataset for consistence | ||
dsData = dsData.transpose('month', 'iLON', 'iLAT') | ||
|
||
#Set appropriate MLD figure labels | ||
# Set appropriate MLD figure labels | ||
obsTitleLabel = "Observations (HolteTalley density threshold MLD)" | ||
fileOutLabel = "mldHolteTalleyARGO" | ||
unitsLabel = 'm' | ||
|
||
elif field.lower() == 'sst': | ||
elif field == 'sst': | ||
|
||
ds = xr.open_mfdataset(infiles, preprocess=lambda x: | ||
preprocess_mpas(x, yearoffset=yr_offset, | ||
timestr=['xtime_start', 'xtime_end'], | ||
onlyvars=['time_avg_activeTracers_temperature'], | ||
selvals={'nVertLevels':0})) | ||
ds = remove_repeated_time_index(ds) | ||
ds.rename({'time_avg_activeTracers_temperature':'mpasData'}, inplace = True) | ||
selvals = {'nVertLevels': 0} | ||
|
||
obs_filename = "%s/MODEL.SST.HAD187001-198110.OI198111-201203.nc" % obsdir | ||
obs_filename = \ | ||
"{}/MODEL.SST.HAD187001-198110.OI198111-201203.nc".format(obsdir) | ||
dsData = xr.open_mfdataset(obs_filename) | ||
#Select years for averaging (pre-industrial or present-day) | ||
#This seems fragile as definitions can change | ||
# Select years for averaging (pre-industrial or present-day) | ||
# This seems fragile as definitions can change | ||
if yr_offset < 1900: | ||
time_start = datetime.datetime(1870, 1, 1) | ||
time_end = datetime.datetime(1900, 12, 31) | ||
|
@@ -118,15 +123,25 @@ def ocn_modelvsobs(config, field): | |
ds_tslice = dsData.sel(time=slice(time_start, time_end)) | ||
monthly_clim_data = ds_tslice.groupby('time.month').mean('time') | ||
|
||
#Rename the observation data for code compactness | ||
# Rename the observation data for code compactness | ||
dsData = monthly_clim_data.transpose('month', 'lon', 'lat') | ||
dsData.rename({'SST':'observationData'}, inplace = True) | ||
obsFieldName = 'SST' | ||
|
||
#Set appropriate figure labels for SST | ||
obsTitleLabel = "Observations (Hadley/OI, %s)" % preIndustrial_txt | ||
# Set appropriate figure labels for SST | ||
obsTitleLabel = \ | ||
"Observations (Hadley/OI, {})".format(preIndustrial_txt) | ||
fileOutLabel = "sstHADOI" | ||
unitsLabel = r'$^o$C' | ||
|
||
ds = xr.open_mfdataset( | ||
infiles, | ||
preprocess=lambda x: preprocess_mpas(x, yearoffset=yr_offset, | ||
timestr='Time', | ||
onlyvars=varList, | ||
selvals=selvals, | ||
varmap=variableMap)) | ||
ds = remove_repeated_time_index(ds) | ||
|
||
time_start = datetime.datetime(yr_offset+climo_yr1, 1, 1) | ||
time_end = datetime.datetime(yr_offset+climo_yr2, 12, 31) | ||
ds_tslice = ds.sel(Time=slice(time_start, time_end)) | ||
|
@@ -136,21 +151,30 @@ def ocn_modelvsobs(config, field): | |
latData = latData.flatten() | ||
lonData = lonData.flatten() | ||
|
||
daysarray = np.ones((12, dsData.observationData.values.shape[1], dsData.observationData.values.shape[2])) | ||
daysarray = np.ones((12, dsData[obsFieldName].values.shape[1], | ||
dsData[obsFieldName].values.shape[2])) | ||
|
||
for i, dval in enumerate(constants.dinmonth): | ||
daysarray[i, :, :] = dval | ||
inds = np.where(np.isnan(dsData.observationData[i, :, :].values)) | ||
inds = np.where(np.isnan(dsData[obsFieldName][i, :, :].values)) | ||
daysarray[i, inds[0], inds[1]] = np.NaN | ||
|
||
|
||
# initialize interpolation variables | ||
d2, inds2, lonTarg, latTarg = init_tree(np.rad2deg(lonCell), np.rad2deg(latCell), constants.lonmin, | ||
constants.lonmax, constants.latmin, constants.latmax, | ||
constants.dLongitude, constants.dLatitude) | ||
d, inds, lonTargD, latTargD = init_tree(lonData, latData, constants.lonmin, constants.lonmax, | ||
constants.latmin, constants.latmax, constants.dLongitude, | ||
constants.dLatitude) | ||
d2, inds2, lonTarg, latTarg = init_tree(np.rad2deg(lonCell), | ||
np.rad2deg(latCell), | ||
constants.lonmin, | ||
constants.lonmax, | ||
constants.latmin, | ||
constants.latmax, | ||
constants.dLongitude, | ||
constants.dLatitude) | ||
d, inds, lonTargD, latTargD = init_tree(lonData, latData, | ||
constants.lonmin, | ||
constants.lonmax, | ||
constants.latmin, | ||
constants.latmax, | ||
constants.dLongitude, | ||
constants.dLatitude) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! This is much easier to read now. |
||
nLon = lonTarg.shape[0] | ||
nLat = lonTarg.shape[1] | ||
|
||
|
@@ -163,50 +187,59 @@ def ocn_modelvsobs(config, field): | |
monthsvalue = constants.monthdictionary[timestring] | ||
|
||
if isinstance(monthsvalue, (int, long)): | ||
modeldata = monthly_clim.sel(month=monthsvalue).mpasData.values | ||
obsdata = dsData.sel(month = monthsvalue).observationData.values | ||
modeldata = monthly_clim.sel(month=monthsvalue)[field].values | ||
obsdata = dsData.sel(month=monthsvalue)[obsFieldName].values | ||
else: | ||
modeldata = np.sum(constants.dinmonth[monthsvalue-1]*monthly_clim.sel(month=monthsvalue). | ||
mpasData.values.T, axis=1) / np.sum(constants.dinmonth[monthsvalue-1]) | ||
obsdata = np.nansum(daysarray[monthsvalue-1, :, :]*dsData.sel(month = monthsvalue). | ||
observationData.values, axis=0) / np.nansum(daysarray[monthsvalue-1, :, :], | ||
axis=0) | ||
|
||
modeldata = (np.sum( | ||
constants.dinmonth[monthsvalue-1] * | ||
monthly_clim.sel(month=monthsvalue)[field].values.T, axis=1) / | ||
np.sum(constants.dinmonth[monthsvalue-1])) | ||
obsdata = (np.nansum( | ||
daysarray[monthsvalue-1, :, :] * | ||
dsData.sel(month=monthsvalue)[obsFieldName].values, axis=0) / | ||
np.nansum(daysarray[monthsvalue-1, :, :], axis=0)) | ||
|
||
modelOutput[i, :, :] = interp_fields(modeldata, d2, inds2, lonTarg) | ||
observations[i, :, :] = interp_fields(obsdata.flatten(), d, inds, lonTargD) | ||
observations[i, :, :] = interp_fields(obsdata.flatten(), d, inds, | ||
lonTargD) | ||
|
||
for i in range(len(outputTimes)): | ||
bias[i, :, :] = modelOutput[i, :, :] - observations[i, :, :] | ||
|
||
clevsModelObs = config.getExpression(field.lower() + '_modelvsobs', | ||
clevsModelObs = config.getExpression(field + '_modelvsobs', | ||
'clevsModelObs') | ||
cmap = plt.get_cmap(config.get(field.lower() + '_modelvsobs', | ||
cmap = plt.get_cmap(config.get(field + '_modelvsobs', | ||
'cmapModelObs')) | ||
cmapIndices = config.getExpression(field.lower() + '_modelvsobs', | ||
cmapIndices = config.getExpression(field + '_modelvsobs', | ||
'cmapIndicesModelObs') | ||
cmapModelObs = cols.ListedColormap(cmap(cmapIndices), "cmapModelObs") | ||
clevsDiff = config.getExpression(field.lower() + '_modelvsobs', | ||
clevsDiff = config.getExpression(field + '_modelvsobs', | ||
'clevsDiff') | ||
cmap = plt.get_cmap(config.get(field.lower() + '_modelvsobs', 'cmapDiff')) | ||
cmapIndices = config.getExpression(field.lower() + '_modelvsobs', | ||
cmap = plt.get_cmap(config.get(field + '_modelvsobs', 'cmapDiff')) | ||
cmapIndices = config.getExpression(field + '_modelvsobs', | ||
'cmapIndicesDiff') | ||
cmapDiff = cols.ListedColormap(cmap(cmapIndices), "cmapDiff") | ||
|
||
for i in range(len(outputTimes)): | ||
fileout = "{}/{}_{}_{}_years{:04d}-{:04d}.png".format( | ||
plots_dir, fileOutLabel, casename, outputTimes[i], climo_yr1, | ||
climo_yr2) | ||
title = "{} ({}, years {:04d}-{:04d})".format( | ||
field.upper(), outputTimes[i], climo_yr1, climo_yr2) | ||
plot_global_comparison(config, | ||
lonTarg, | ||
latTarg, | ||
modelOutput[i, :, :], | ||
observations[i, :, :], | ||
bias[i, :,:], | ||
bias[i, :, :], | ||
cmapModelObs, | ||
clevsModelObs, | ||
cmapDiff, | ||
clevsDiff, | ||
fileout = "%s/%s_%s_%s_years%04d-%04d.png" % (plots_dir, fileOutLabel, | ||
casename, outputTimes[i], climo_yr1, climo_yr2), | ||
title = "%s (%s, years %04d-%04d)" % (field.upper(), outputTimes[i], climo_yr1, climo_yr2), | ||
modelTitle = "%s" % casename, | ||
obsTitle = obsTitleLabel, | ||
diffTitle = "Model-Observations", | ||
cbarlabel = unitsLabel) | ||
fileout=fileout, | ||
title=title, | ||
modelTitle="{}".format(casename), | ||
obsTitle=obsTitleLabel, | ||
diffTitle="Model-Observations", | ||
cbarlabel=unitsLabel) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we have a description of
config
andfield
in the doc string? It will be helpful for people who aren't as familiar with the code.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit of mission creep but I'll do this.