Skip to content

Commit 8ce472a

Browse files
committed
Add variable and stream maps to ocean/modelvsobs
1 parent 7abdfa5 commit 8ce472a

File tree

2 files changed

+106
-75
lines changed

2 files changed

+106
-75
lines changed

mpas_analysis/ocean/ocean_modelvsobs.py

Lines changed: 102 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
General comparison of 2-d model fields against data. Currently only supports
44
mixed layer depths (mld) and sea surface temperature (sst)
55
6-
Author: Luke Van Roekel, Milena Veneziani
7-
Last Modified: 10/24/2016
6+
Author: Luke Van Roekel, Milena Veneziani, Xylar Asay-Davis
7+
Last Modified: 12/06/2016
88
"""
99

1010
import matplotlib.pyplot as plt
@@ -14,24 +14,33 @@
1414
import xarray as xr
1515
import datetime
1616
from netCDF4 import Dataset as netcdf_dataset
17-
import os.path
1817

19-
from ..shared.mpas_xarray.mpas_xarray import preprocess_mpas, remove_repeated_time_index
18+
from ..shared.mpas_xarray.mpas_xarray import preprocess_mpas, \
19+
remove_repeated_time_index
2020
from ..shared.plot.plotting import plot_global_comparison
2121
from ..shared.interpolation.interpolate import interp_fields, init_tree
2222
from ..shared.constants import constants
2323

2424
from ..shared.io import StreamsFile
2525

26-
def ocn_modelvsobs(config, field):
26+
27+
def ocn_modelvsobs(config, field, streamMap=None, variableMap=None):
2728

2829
"""
2930
Plots a comparison of ACME/MPAS output to SST or MLD observations
3031
32+
If present, streamMap is a dictionary of MPAS-O stream names that map to
33+
their mpas_analysis counterparts.
34+
35+
If present, variableMap is a dictionary of MPAS-O variable names that map
36+
to their mpas_analysis counterparts.
37+
3138
Authors: Luke Van Roekel, Milena Veneziani, Xylar Asay-Davis
32-
Modified: 10/27/2016
39+
Modified: 12/07/2016
3340
"""
3441

42+
field = field.lower()
43+
3544
# read parameters from config file
3645
indir = config.get('paths', 'archive_dir_ocn')
3746

@@ -42,9 +51,10 @@ def ocn_modelvsobs(config, field):
4251
# reading only those that are between the start and end dates
4352
startDate = config.get('time', 'climo_start_date')
4453
endDate = config.get('time', 'climo_end_date')
45-
infiles = streams.readpath('timeSeriesStatsOutput',
46-
startDate=startDate, endDate=endDate)
47-
print 'Reading files {} through {}'.format(infiles[0],infiles[-1])
54+
streamName = streams.find_stream(streamMap['timeSeriesStats'])
55+
infiles = streams.readpath(streamName, startDate=startDate,
56+
endDate=endDate)
57+
print 'Reading files {} through {}'.format(infiles[0], infiles[-1])
4858

4959
plots_dir = config.get('paths', 'plots_dir')
5060
obsdir = config.get('paths', 'obs_' + field.lower() + 'dir')
@@ -57,55 +67,46 @@ def ocn_modelvsobs(config, field):
5767
outputTimes = config.getExpression(field.lower() + '_modelvsobs',
5868
'comparisonTimes')
5969

60-
f = netcdf_dataset(meshfile,mode='r')
70+
f = netcdf_dataset(meshfile, mode='r')
6171
lonCell = f.variables["lonCell"][:]
6272
latCell = f.variables["latCell"][:]
6373

64-
if field.lower() == 'mld':
65-
obs_filename = "%s/holtetalley_mld_climatology.nc" % obsdir
74+
varList = [field]
6675

67-
ds = xr.open_mfdataset(infiles, preprocess=lambda x:
68-
preprocess_mpas(x, yearoffset=yr_offset,
69-
timestr=['xtime_start', 'xtime_end'],
70-
onlyvars=['time_avg_dThreshMLD']))
71-
ds = remove_repeated_time_index(ds)
72-
ds.rename({'time_avg_dThreshMLD':'mpasData'}, inplace = True)
76+
if field == 'mld':
7377

74-
#Load MLD observational data
78+
selvals = None
79+
80+
# Load MLD observational data
81+
obs_filename = "{}/holtetalley_mld_climatology.nc".format(obsdir)
7582
dsData = xr.open_mfdataset(obs_filename)
7683

77-
#Increment month value to be consistent with the model output
84+
# Increment month value to be consistent with the model output
7885
dsData.iMONTH.values += 1
7986

80-
#Rename the time dimension to be consistent with the SST dataset
81-
dsData.rename({'month':'calmonth'}, inplace = True)
82-
dsData.rename({'iMONTH':'month'}, inplace = True)
87+
# Rename the time dimension to be consistent with the SST dataset
88+
dsData.rename({'month': 'calmonth'}, inplace=True)
89+
dsData.rename({'iMONTH': 'month'}, inplace=True)
8390

84-
#rename appropriate observational data for compactness
85-
dsData.rename({'mld_dt_mean':'observationData'}, inplace = True)
91+
obsFieldName = 'mld_dt_mean'
8692

87-
#Reorder dataset for consistence
93+
# Reorder dataset for consistence
8894
dsData = dsData.transpose('month', 'iLON', 'iLAT')
8995

90-
#Set appropriate MLD figure labels
96+
# Set appropriate MLD figure labels
9197
obsTitleLabel = "Observations (HolteTalley density threshold MLD)"
9298
fileOutLabel = "mldHolteTalleyARGO"
9399
unitsLabel = 'm'
94100

95-
elif field.lower() == 'sst':
101+
elif field == 'sst':
96102

97-
ds = xr.open_mfdataset(infiles, preprocess=lambda x:
98-
preprocess_mpas(x, yearoffset=yr_offset,
99-
timestr=['xtime_start', 'xtime_end'],
100-
onlyvars=['time_avg_activeTracers_temperature'],
101-
selvals={'nVertLevels':1}))
102-
ds = remove_repeated_time_index(ds)
103-
ds.rename({'time_avg_activeTracers_temperature':'mpasData'}, inplace = True)
103+
selvals = {'nVertLevels': 1}
104104

105-
obs_filename = "%s/MODEL.SST.HAD187001-198110.OI198111-201203.nc" % obsdir
105+
obs_filename = \
106+
"{}/MODEL.SST.HAD187001-198110.OI198111-201203.nc".format(obsdir)
106107
dsData = xr.open_mfdataset(obs_filename)
107-
#Select years for averaging (pre-industrial or present-day)
108-
#This seems fragile as definitions can change
108+
# Select years for averaging (pre-industrial or present-day)
109+
# This seems fragile as definitions can change
109110
if yr_offset < 1900:
110111
time_start = datetime.datetime(1870, 1, 1)
111112
time_end = datetime.datetime(1900, 12, 31)
@@ -118,15 +119,25 @@ def ocn_modelvsobs(config, field):
118119
ds_tslice = dsData.sel(time=slice(time_start, time_end))
119120
monthly_clim_data = ds_tslice.groupby('time.month').mean('time')
120121

121-
#Rename the observation data for code compactness
122+
# Rename the observation data for code compactness
122123
dsData = monthly_clim_data.transpose('month', 'lon', 'lat')
123-
dsData.rename({'SST':'observationData'}, inplace = True)
124+
obsFieldName = 'SST'
124125

125-
#Set appropriate figure labels for SST
126-
obsTitleLabel = "Observations (Hadley/OI, %s)" % preIndustrial_txt
126+
# Set appropriate figure labels for SST
127+
obsTitleLabel = \
128+
"Observations (Hadley/OI, {})".format(preIndustrial_txt)
127129
fileOutLabel = "sstHADOI"
128130
unitsLabel = r'$^o$C'
129131

132+
ds = xr.open_mfdataset(
133+
infiles,
134+
preprocess=lambda x: preprocess_mpas(x, yearoffset=yr_offset,
135+
timestr='Time',
136+
onlyvars=varList,
137+
selvals=selvals,
138+
variable_map=variableMap))
139+
ds = remove_repeated_time_index(ds)
140+
130141
time_start = datetime.datetime(yr_offset+climo_yr1, 1, 1)
131142
time_end = datetime.datetime(yr_offset+climo_yr2, 12, 31)
132143
ds_tslice = ds.sel(Time=slice(time_start, time_end))
@@ -136,21 +147,30 @@ def ocn_modelvsobs(config, field):
136147
latData = latData.flatten()
137148
lonData = lonData.flatten()
138149

139-
daysarray = np.ones((12, dsData.observationData.values.shape[1], dsData.observationData.values.shape[2]))
150+
daysarray = np.ones((12, dsData[obsFieldName].values.shape[1],
151+
dsData[obsFieldName].values.shape[2]))
140152

141153
for i, dval in enumerate(constants.dinmonth):
142154
daysarray[i, :, :] = dval
143-
inds = np.where(np.isnan(dsData.observationData[i, :, :].values))
155+
inds = np.where(np.isnan(dsData[obsFieldName][i, :, :].values))
144156
daysarray[i, inds[0], inds[1]] = np.NaN
145157

146-
147158
# initialize interpolation variables
148-
d2, inds2, lonTarg, latTarg = init_tree(np.rad2deg(lonCell), np.rad2deg(latCell), constants.lonmin,
149-
constants.lonmax, constants.latmin, constants.latmax,
150-
constants.dLongitude, constants.dLatitude)
151-
d, inds, lonTargD, latTargD = init_tree(lonData, latData, constants.lonmin, constants.lonmax,
152-
constants.latmin, constants.latmax, constants.dLongitude,
153-
constants.dLatitude)
159+
d2, inds2, lonTarg, latTarg = init_tree(np.rad2deg(lonCell),
160+
np.rad2deg(latCell),
161+
constants.lonmin,
162+
constants.lonmax,
163+
constants.latmin,
164+
constants.latmax,
165+
constants.dLongitude,
166+
constants.dLatitude)
167+
d, inds, lonTargD, latTargD = init_tree(lonData, latData,
168+
constants.lonmin,
169+
constants.lonmax,
170+
constants.latmin,
171+
constants.latmax,
172+
constants.dLongitude,
173+
constants.dLatitude)
154174
nLon = lonTarg.shape[0]
155175
nLat = lonTarg.shape[1]
156176

@@ -163,50 +183,59 @@ def ocn_modelvsobs(config, field):
163183
monthsvalue = constants.monthdictionary[timestring]
164184

165185
if isinstance(monthsvalue, (int, long)):
166-
modeldata = monthly_clim.sel(month=monthsvalue).mpasData.values
167-
obsdata = dsData.sel(month = monthsvalue).observationData.values
186+
modeldata = monthly_clim.sel(month=monthsvalue)[field].values
187+
obsdata = dsData.sel(month=monthsvalue)[obsFieldName].values
168188
else:
169-
modeldata = np.sum(constants.dinmonth[monthsvalue-1]*monthly_clim.sel(month=monthsvalue).
170-
mpasData.values.T, axis=1) / np.sum(constants.dinmonth[monthsvalue-1])
171-
obsdata = np.nansum(daysarray[monthsvalue-1, :, :]*dsData.sel(month = monthsvalue).
172-
observationData.values, axis=0) / np.nansum(daysarray[monthsvalue-1, :, :],
173-
axis=0)
189+
190+
modeldata = np.sum(
191+
constants.dinmonth[monthsvalue-1] *
192+
monthly_clim.sel(month=monthsvalue)[field].values.T,
193+
axis=1) / np.sum(constants.dinmonth[monthsvalue-1])
194+
obsdata = np.nansum(
195+
daysarray[monthsvalue-1, :, :] *
196+
dsData.sel(month=monthsvalue)[obsFieldName].values,
197+
axis=0) / np.nansum(daysarray[monthsvalue-1, :, :], axis=0)
174198

175199
modelOutput[i, :, :] = interp_fields(modeldata, d2, inds2, lonTarg)
176-
observations[i, :, :] = interp_fields(obsdata.flatten(), d, inds, lonTargD)
200+
observations[i, :, :] = interp_fields(obsdata.flatten(), d, inds,
201+
lonTargD)
177202

178203
for i in range(len(outputTimes)):
179204
bias[i, :, :] = modelOutput[i, :, :] - observations[i, :, :]
180205

181-
clevsModelObs = config.getExpression(field.lower() + '_modelvsobs',
206+
clevsModelObs = config.getExpression(field + '_modelvsobs',
182207
'clevsModelObs')
183-
cmap = plt.get_cmap(config.get(field.lower() + '_modelvsobs',
208+
cmap = plt.get_cmap(config.get(field + '_modelvsobs',
184209
'cmapModelObs'))
185-
cmapIndices = config.getExpression(field.lower() + '_modelvsobs',
210+
cmapIndices = config.getExpression(field + '_modelvsobs',
186211
'cmapIndicesModelObs')
187212
cmapModelObs = cols.ListedColormap(cmap(cmapIndices), "cmapModelObs")
188-
clevsDiff = config.getExpression(field.lower() + '_modelvsobs',
213+
clevsDiff = config.getExpression(field + '_modelvsobs',
189214
'clevsDiff')
190-
cmap = plt.get_cmap(config.get(field.lower() + '_modelvsobs', 'cmapDiff'))
191-
cmapIndices = config.getExpression(field.lower() + '_modelvsobs',
215+
cmap = plt.get_cmap(config.get(field + '_modelvsobs', 'cmapDiff'))
216+
cmapIndices = config.getExpression(field + '_modelvsobs',
192217
'cmapIndicesDiff')
193218
cmapDiff = cols.ListedColormap(cmap(cmapIndices), "cmapDiff")
194219

195220
for i in range(len(outputTimes)):
221+
fileout = "{}/{}_{}_{}_years{:04d}-{:04d}.png".format(
222+
plots_dir, fileOutLabel, casename, outputTimes[i], climo_yr1,
223+
climo_yr2)
224+
title = "{} ({}, years {:04d}-{:04d})".format(
225+
field.upper(), outputTimes[i], climo_yr1, climo_yr2)
196226
plot_global_comparison(config,
197227
lonTarg,
198228
latTarg,
199229
modelOutput[i, :, :],
200230
observations[i, :, :],
201-
bias[i, :,:],
231+
bias[i, :, :],
202232
cmapModelObs,
203233
clevsModelObs,
204234
cmapDiff,
205235
clevsDiff,
206-
fileout = "%s/%s_%s_%s_years%04d-%04d.png" % (plots_dir, fileOutLabel,
207-
casename, outputTimes[i], climo_yr1, climo_yr2),
208-
title = "%s (%s, years %04d-%04d)" % (field.upper(), outputTimes[i], climo_yr1, climo_yr2),
209-
modelTitle = "%s" % casename,
210-
obsTitle = obsTitleLabel,
211-
diffTitle = "Model-Observations",
212-
cbarlabel = unitsLabel)
236+
fileout=fileout,
237+
title=title,
238+
modelTitle="{}".format(casename),
239+
obsTitle=obsTitleLabel,
240+
diffTitle="Model-Observations",
241+
cbarlabel=unitsLabel)

run_analysis.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,15 @@ def analysis(config): # {{{
127127
print ""
128128
print "Plotting 2-d maps of SST climatologies..."
129129
from mpas_analysis.ocean.ocean_modelvsobs import ocn_modelvsobs
130-
ocn_modelvsobs(config, 'sst')
130+
ocn_modelvsobs(config, 'sst', streamMap=oceanStreamMap,
131+
variableMap=oceanVariableMap)
131132

132133
if config.getboolean('mld_modelvsobs', 'generate'):
133134
print ""
134135
print "Plotting 2-d maps of MLD climatologies..."
135136
from mpas_analysis.ocean.ocean_modelvsobs import ocn_modelvsobs
136-
ocn_modelvsobs(config, 'mld')
137+
ocn_modelvsobs(config, 'mld', streamMap=oceanStreamMap,
138+
variableMap=oceanVariableMap)
137139

138140
# GENERATE SEA-ICE DIAGNOSTICS
139141
if config.getboolean('seaice_timeseries', 'generate'):

0 commit comments

Comments
 (0)