From a23da8ff1323591b028e32d08f9fdf71de172b7a Mon Sep 17 00:00:00 2001 From: Milena Veneziani Date: Fri, 1 Jun 2018 14:21:00 -0700 Subject: [PATCH 1/4] Add script for online MOC --- .../ocean/meridional_heat_transport.py | 2 +- mpas_analysis/ocean/streamfunction_moc.py | 320 ++++++++++++++++-- 2 files changed, 293 insertions(+), 29 deletions(-) diff --git a/mpas_analysis/ocean/meridional_heat_transport.py b/mpas_analysis/ocean/meridional_heat_transport.py index 1ec05483f..b0e5bce82 100644 --- a/mpas_analysis/ocean/meridional_heat_transport.py +++ b/mpas_analysis/ocean/meridional_heat_transport.py @@ -203,7 +203,7 @@ def run_task(self): # {{{ binBoundaryMerHeatTrans = None # first try timeSeriesStatsMonthly for bin boundaries, then try - # meridionalHeatTranspor steram as a backup option + # meridionalHeatTransport stream as a backup option for streamName in ['timeSeriesStatsMonthlyOutput', 'meridionalHeatTransportOutput']: try: diff --git a/mpas_analysis/ocean/streamfunction_moc.py b/mpas_analysis/ocean/streamfunction_moc.py index 7a06c4ca4..26557bd8b 100644 --- a/mpas_analysis/ocean/streamfunction_moc.py +++ b/mpas_analysis/ocean/streamfunction_moc.py @@ -123,17 +123,22 @@ def setup_and_check(self): # {{{ self.sectionName = 'streamfunctionMOC' - self.includeBolus = config.getboolean(self.sectionName, 'includeBolus') - if self.includeBolus: - # only add the bolus velocity if GM is enabled - self.includeBolus = self.namelist.getbool('config_use_standardgm') - - self.variableList = ['timeMonthly_avg_normalVelocity', - 'timeMonthly_avg_vertVelocityTop'] - if self.includeBolus: - self.variableList.extend( - ['timeMonthly_avg_normalGMBolusVelocity', - 'timeMonthly_avg_vertGMBolusVelocityTop']) + if self.mocAnalysisMemberEnabled: + # I think the bolus velocity should always be included if GM is on + self.includeBolus = config.getboolean(self.sectionName, 'includeBolus') + if self.includeBolus: + # only add the bolus velocity if GM is enabled + self.includeBolus = self.namelist.getbool('config_use_standardgm') + + self.variableList = ['timeMonthly_avg_normalVelocity', + 'timeMonthly_avg_vertVelocityTop'] + if self.includeBolus: + self.variableList.extend( + ['timeMonthly_avg_normalGMBolusVelocity', + 'timeMonthly_avg_vertGMBolusVelocityTop']) + else: + self.variableList = ['timeMonthly_avg_mocStreamvalLatAndDepth', + 'timeMonthly_avg_mocStreamvalLatAndDepthRegion'] self.mpasClimatologyTask.add_variables(variableList=self.variableList, seasons=['ANN']) @@ -181,18 +186,12 @@ def run_task(self): # {{{ # **** Compute MOC **** # Check whether MOC Analysis Member is enabled if self.mocAnalysisMemberEnabled: - # Add a moc_analisysMember_processing - self.logger.info('*** MOC Analysis Member is on ***') - # (mocDictClimo, mocDictTseries) = \ - # self._compute_moc_analysismember(config, streams, calendar, - # sectionName, dictClimo, - # dictTseries) - - # delete the following 3 lines after analysis of the MOC AM is - # supported - self.logger.info('...but not yet supported. Using offline MOC') - self._compute_moc_climo_postprocess() - dsMOCTimeSeries = self._compute_moc_time_series_postprocess() + #(mocDictClimo, mocDictTseries) = \ + # self._compute_moc_analysismember(config, streams, calendar, + # sectionName, dictClimo, + # dictTseries) + self._compute_moc_climo_analysismember() + dsMOCTimeSeries = self._compute_moc_time_series() else: self._compute_moc_climo_postprocess() dsMOCTimeSeries = self._compute_moc_time_series_postprocess() @@ -338,6 +337,274 @@ def _load_mesh(self): # {{{ refTopDepth, refLayerThickness # }}} + def _compute_moc_climo_analysismember(self): # {{{ + + '''compute mean MOC streamfunction from analysis member''' + + config = self.config + + # Read in depth and bin latitudes + try: + restartFileName = self.runStreams.readpath('restart')[0] + except ValueError: + raise IOError('No MPAS-O restart file found: need at least ' + 'one for MHT calcuation') + + with xr.open_dataset(restartFileName) as dsRestart: + refBottomDepth = dsRestart.refBottomDepth.values + + nVertLevels = len(refBottomDepth) + refLayerThickness = np.zeros(nVertLevels) + refLayerThickness[0] = refBottomDepth[0] + refLayerThickness[1:nVertLevels] = \ + refBottomDepth[1:nVertLevels] - refBottomDepth[0:nVertLevels-1] + + refZMid = -refBottomDepth + 0.5*refLayerThickness + + binBoundaryMocStreamfunction = None + # first try timeSeriesStatsMonthly for bin boundaries, then try + # mocStreamfunctionOutput stream as a backup option + for streamName in ['timeSeriesStatsMonthlyOutput', + 'mocStreamfunctionOutput']: + try: + inputFile = self.historyStreams.readpath(streamName)[0] + except ValueError: + raise IOError('At least one file from stream {} is needed ' + 'to compute MOC'.format(streamName)) + + with xr.open_dataset(inputFile) as ds: + if 'binBoundaryMocStreamfunction' in ds.data_vars: + binBoundaryMocStreamfunction = \ + ds.binBoundaryMocStreamfunction.values + break + + if binBoundaryMocStreamfunction is None: + raise ValueError('Could not find binBoundaryMocStreamfunction in ' + 'either timeSeriesStatsMonthlyOutput or ' + 'mocStreamfunctionOutput streams') + + binBoundaryMocStreamfunction = np.rad2deg(binBoundaryMocStreamfunction) + + # Compute and plot annual climatology of MOC streamfunction + self.logger.info('\n Compute and/or plot post-processed MOC ' + 'climatological streamfunction...') + outputDirectory = build_config_full_path(config, 'output', + 'mpasClimatologySubdirectory') + + make_directories(outputDirectory) + + outputFileClimo = '{}/mocStreamfunction_years{:04d}-{:04d}.nc'.format( + outputDirectory, self.startYearClimo, + self.endYearClimo) + if not os.path.exists(outputFileClimo): + self.logger.info(' Load data...') + + climatologyFileName = self.mpasClimatologyTask.get_file_name( + season='ANN') + annualClimatology = xr.open_dataset(climatologyFileName) + annualClimatology = annualClimatology.isel(Time=0) + + # rename some variables for convenience + annualClimatology = annualClimatology.rename( + {'timeMonthly_avg_mocStreamvalLatAndDepth': 'avgMocStreamfunGlobal', + 'timeMonthly_avg_mocStreamvalLatAndDepthRegion': 'avgMocStreamfunRegional'}) + + # Create dictionary for MOC climatology (NB: need this form + # in order to convert it to xarray dataset later in the script) + self.depth = refZMid + self.lat = {} + self.moc = {} + for region in self.regionNames: + self.logger.info(' Compute {} MOC...'.format(region)) + if region == 'Global': + mocTop = annualClimatology.avgMocStreamfunGlobal.values + else: + # hard-wire region=0 (Atlantic) for now + indRegion = 0 + mocTop = annualClimatology.avgMocStreamfunRegional[indRegion, :, :].values + # Store computed MOC to dictionary + self.lat[region] = binBoundaryMocStreamfunction + self.moc[region] = mocTop + + # Save to file + self.logger.info(' Save global and regional MOC to file...') + ncFile = netCDF4.Dataset(outputFileClimo, mode='w') + # create dimensions + ncFile.createDimension('nz', len(refTopDepth)) + for region in self.regionNames: + latBins = self.lat[region] + mocTop = self.moc[region] + ncFile.createDimension('nx{}'.format(region), len(latBins)) + # create variables + x = ncFile.createVariable('lat{}'.format(region), 'f4', + ('nx{}'.format(region),)) + x.description = 'latitude bins for MOC {}'\ + ' streamfunction'.format(region) + x.units = 'degrees (-90 to 90)' + y = ncFile.createVariable('moc{}'.format(region), 'f4', + ('nz', 'nx{}'.format(region))) + y.description = 'MOC {} streamfunction, annual'\ + ' climatology'.format(region) + y.units = 'Sv (10^6 m^3/s)' + # save variables + x[:] = latBins + y[:, :] = mocTop + depth = ncFile.createVariable('depth', 'f4', ('nz',)) + depth.description = 'depth' + depth.units = 'meters' + depth[:] = self.depth + ncFile.close() + else: + # Read from file + self.logger.info(' Read previously computed MOC streamfunction ' + 'from file...') + ncFile = netCDF4.Dataset(outputFileClimo, mode='r') + self.depth = ncFile.variables['depth'][:] + self.lat = {} + self.moc = {} + for region in self.regionNames: + self.lat[region] = ncFile.variables['lat{}'.format(region)][:] + self.moc[region] = \ + ncFile.variables['moc{}'.format(region)][:, :] + ncFile.close() + # }}} + + def _compute_moc_time_series_analysismember(self): # {{{ + + '''compute MOC time series from analysis member''' + + # Compute and plot time series of Atlantic MOC at 26.5N (RAPID array) + self.logger.info('\n Compute Atlantic MOC time series from analysis member...') + self.logger.info(' Load data...') + + outputDirectory = build_config_full_path(self.config, 'output', + 'timeseriesSubdirectory') + try: + os.makedirs(outputDirectory) + except OSError: + pass + + outputFileTseries = '{}/mocTimeSeries.nc'.format(outputDirectory) + + streamName = 'timeSeriesStatsMonthlyOutput' + + # Get bin latitudes and index of 26.5N + binBoundaryMocStreamfunction = None + # first try timeSeriesStatsMonthly for bin boundaries, then try + # mocStreamfunctionOutput stream as a backup option + for streamName in ['timeSeriesStatsMonthlyOutput', + 'mocStreamfunctionOutput']: + try: + inputFile = self.historyStreams.readpath(streamName)[0] + except ValueError: + raise IOError('At least one file from stream {} is needed ' + 'to compute MOC'.format(streamName)) + + with xr.open_dataset(inputFile) as ds: + if 'binBoundaryMocStreamfunction' in ds.data_vars: + binBoundaryMocStreamfunction = \ + ds.binBoundaryMocStreamfunction.values + break + + if binBoundaryMocStreamfunction is None: + raise ValueError('Could not find binBoundaryMocStreamfunction in ' + 'either timeSeriesStatsMonthlyOutput or ' + 'mocStreamfunctionOutput streams') + + binBoundaryMocStreamfunction = np.rad2deg(binBoundaryMocStreamfunction) + dLat = binBoundaryMocStreamfunction - 26.5 + indlat26 = np.where(dLat == np.amin(np.abs(dLat))) + + inputFilesTseries = sorted(self.historyStreams.readpath( + streamName, startDate=self.startDateTseries, + endDate=self.endDateTseries, calendar=self.calendar)) + + years, months = get_files_year_month(inputFilesTseries, + self.historyStreams, + 'timeSeriesStatsMonthlyOutput') + + mocRegion = np.zeros(len(inputFilesTseries)) + times = np.zeros(len(inputFilesTseries)) + computed = np.zeros(len(inputFilesTseries), bool) + + continueOutput = os.path.exists(outputFileTseries) + if continueOutput: + self.logger.info(' Read in previously computed MOC time series') + with open_mpas_dataset(fileName=outputFileTseries, + calendar=self.calendar, + timeVariableNames=None, + variableList=['mocAtlantic26'], + startDate=self.startDateTseries, + endDate=self.endDateTseries) as dsMOCIn: + + dsMOCIn.load() + + # first, copy all computed data + for inIndex in range(dsMOCIn.dims['Time']): + + mask = np.logical_and( + dsMOCIn.year[inIndex].values == years, + dsMOCIn.month[inIndex].values == months) + + outIndex = np.where(mask)[0][0] + + mocRegion[outIndex] = dsMOCIn.mocAtlantic26[inIndex] + times[outIndex] = dsMOCIn.Time[inIndex] + computed[outIndex] = True + + if np.all(computed): + # no need to waste time writing out the data set again + return dsMOCIn + + for timeIndex, fileName in enumerate(inputFilesTseries): + if computed[timeIndex]: + continue + + dsLocal = open_mpas_dataset( + fileName=fileName, + calendar=self.calendar, + variableList=self.variableList, + startDate=self.startDateTseries, + endDate=self.endDateTseries) + dsLocal = dsLocal.isel(Time=0) + time = dsLocal.Time.values + times[timeIndex] = time + date = days_to_datetime(time, calendar=self.calendar) + + self.logger.info(' date: {:04d}-{:02d}'.format(date.year, + date.month)) + + # hard-wire region=0 (Atlantic) for now + indRegion = 0 + mocTop = dsLocal.timeMonthly_avg_mocStreamvalLatAndDepthRegion[timeIndex, indRegion, :, :].values + mocRegion[timeIndex] = np.amax(mocTop[:, indlat26]) + + description = 'Max MOC Atlantic streamfunction nearest to RAPID ' \ + 'Array latitude (26.5N)' + + dictonary = {'dims': ['Time'], + 'coords': {'Time': + {'dims': ('Time'), + 'data': times, + 'attrs': {'units': 'days since 0001-01-01'}}, + 'year': + {'dims': ('Time'), + 'data': years, + 'attrs': {'units': 'year'}}, + 'month': + {'dims': ('Time'), + 'data': months, + 'attrs': {'units': 'month'}}}, + 'data_vars': {'mocAtlantic26': + {'dims': ('Time'), + 'data': mocRegion, + 'attrs': {'units': 'Sv (10^6 m^3/s)', + 'description': description}}}} + dsMOCTimeSeries = xr.Dataset.from_dict(dictonary) + write_netcdf(dsMOCTimeSeries, outputFileTseries) + + return dsMOCTimeSeries # }}} + def _compute_moc_climo_postprocess(self): # {{{ '''compute mean MOC streamfunction as a post-process''' @@ -518,6 +785,7 @@ def _compute_moc_climo_postprocess(self): # {{{ # }}} def _compute_moc_time_series_postprocess(self): # {{{ + '''compute MOC time series as a post-process''' # Compute and plot time series of Atlantic MOC at 26.5N (RAPID array) @@ -658,11 +926,7 @@ def _compute_moc_time_series_postprocess(self): # {{{ dsMOCTimeSeries = xr.Dataset.from_dict(dictonary) write_netcdf(dsMOCTimeSeries, outputFileTseries) - return dsMOCTimeSeries - - # def _compute_moc_analysismember(self): - # - # return + return dsMOCTimeSeries # }}} def _compute_transport(self, maxEdgesInTransect, transectEdgeGlobalIDs, transectEdgeMaskSigns, nz, dvEdge, From a321f7f1361f7f3ecd8e64c6ffa11b23fac81e34 Mon Sep 17 00:00:00 2001 From: Milena Veneziani Date: Mon, 4 Jun 2018 13:58:16 -0700 Subject: [PATCH 2/4] Removed use of bolus as option if GM is on --- mpas_analysis/ocean/streamfunction_moc.py | 34 ++++++++++++----------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/mpas_analysis/ocean/streamfunction_moc.py b/mpas_analysis/ocean/streamfunction_moc.py index 26557bd8b..fea6eb307 100644 --- a/mpas_analysis/ocean/streamfunction_moc.py +++ b/mpas_analysis/ocean/streamfunction_moc.py @@ -124,21 +124,18 @@ def setup_and_check(self): # {{{ self.sectionName = 'streamfunctionMOC' if self.mocAnalysisMemberEnabled: - # I think the bolus velocity should always be included if GM is on - self.includeBolus = config.getboolean(self.sectionName, 'includeBolus') - if self.includeBolus: - # only add the bolus velocity if GM is enabled - self.includeBolus = self.namelist.getbool('config_use_standardgm') - + self.variableList = ['timeMonthly_avg_mocStreamvalLatAndDepth', + 'timeMonthly_avg_mocStreamvalLatAndDepthRegion'] + else: self.variableList = ['timeMonthly_avg_normalVelocity', 'timeMonthly_avg_vertVelocityTop'] + + # Add the bolus velocity if GM is enabled + self.includeBolus = self.namelist.getbool('config_use_standardgm') if self.includeBolus: self.variableList.extend( ['timeMonthly_avg_normalGMBolusVelocity', 'timeMonthly_avg_vertGMBolusVelocityTop']) - else: - self.variableList = ['timeMonthly_avg_mocStreamvalLatAndDepth', - 'timeMonthly_avg_mocStreamvalLatAndDepthRegion'] self.mpasClimatologyTask.add_variables(variableList=self.variableList, seasons=['ANN']) @@ -191,7 +188,7 @@ def run_task(self): # {{{ # sectionName, dictClimo, # dictTseries) self._compute_moc_climo_analysismember() - dsMOCTimeSeries = self._compute_moc_time_series() + dsMOCTimeSeries = self._compute_moc_time_series_analysismember() else: self._compute_moc_climo_postprocess() dsMOCTimeSeries = self._compute_moc_time_series_postprocess() @@ -343,6 +340,11 @@ def _compute_moc_climo_analysismember(self): # {{{ config = self.config + self.regionNames = config.getExpression(self.sectionName, + 'regionNames') + self.regionNames.append('Global') + + # Read in depth and bin latitudes try: restartFileName = self.runStreams.readpath('restart')[0] @@ -359,7 +361,7 @@ def _compute_moc_climo_analysismember(self): # {{{ refLayerThickness[1:nVertLevels] = \ refBottomDepth[1:nVertLevels] - refBottomDepth[0:nVertLevels-1] - refZMid = -refBottomDepth + 0.5*refLayerThickness + refZMid = refBottomDepth - 0.5*refLayerThickness binBoundaryMocStreamfunction = None # first try timeSeriesStatsMonthly for bin boundaries, then try @@ -430,7 +432,7 @@ def _compute_moc_climo_analysismember(self): # {{{ self.logger.info(' Save global and regional MOC to file...') ncFile = netCDF4.Dataset(outputFileClimo, mode='w') # create dimensions - ncFile.createDimension('nz', len(refTopDepth)) + ncFile.createDimension('nz', nVertLevels) for region in self.regionNames: latBins = self.lat[region] mocTop = self.moc[region] @@ -513,7 +515,7 @@ def _compute_moc_time_series_analysismember(self): # {{{ binBoundaryMocStreamfunction = np.rad2deg(binBoundaryMocStreamfunction) dLat = binBoundaryMocStreamfunction - 26.5 - indlat26 = np.where(dLat == np.amin(np.abs(dLat))) + indlat26 = np.where(np.abs(dLat) == np.amin(np.abs(dLat))) inputFilesTseries = sorted(self.historyStreams.readpath( streamName, startDate=self.startDateTseries, @@ -576,7 +578,7 @@ def _compute_moc_time_series_analysismember(self): # {{{ # hard-wire region=0 (Atlantic) for now indRegion = 0 - mocTop = dsLocal.timeMonthly_avg_mocStreamvalLatAndDepthRegion[timeIndex, indRegion, :, :].values + mocTop = dsLocal.timeMonthly_avg_mocStreamvalLatAndDepthRegion[indRegion, :, :].values mocRegion[timeIndex] = np.amax(mocTop[:, indlat26]) description = 'Max MOC Atlantic streamfunction nearest to RAPID ' \ @@ -767,7 +769,7 @@ def _compute_moc_climo_postprocess(self): # {{{ depth = ncFile.createVariable('depth', 'f4', ('nz',)) depth.description = 'depth' depth.units = 'meters' - depth[:] = refTopDepth + depth[:] = self.depth ncFile.close() else: # Read from file @@ -807,7 +809,7 @@ def _compute_moc_time_series_postprocess(self): # {{{ latAtlantic = self.lat['Atlantic'] dLat = latAtlantic - 26.5 - indlat26 = np.where(dLat == np.amin(np.abs(dLat))) + indlat26 = np.where(np.abs(dLat) == np.amin(np.abs(dLat))) dictRegion = self.dictRegion['Atlantic'] maxEdgesInTransect = dictRegion['maxEdgesInTransect'] From 1d830483207f6e4306a7a1432d5669c90ff4938c Mon Sep 17 00:00:00 2001 From: Milena Veneziani Date: Tue, 5 Jun 2018 08:45:56 -0700 Subject: [PATCH 3/4] Added tmp config option 'usePostprocessingScript' --- ...0170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil | 13 +- ...20180129.DECKv1b_piControl.ne30_oEC.edison | 13 +- ..._oRRS30to10v3wLI.cori-knl.afterSalinityFix | 1 - .../edison/config.20180514.G.oQU240wLI.edison | 13 +- ..._res_ice_shelves_1696_JWolfe_layout_Edison | 12 ++ ...3.beta1.A_WCYCL1850S.ne30_oECv3_ICG.edison | 20 +- ...5.beta2.A_WCYCL1850S.ne30_oECv3_ICG.edison | 20 +- ...GMPAS-IAF.T62_oEC60to30v3wLI.60layer.theta | 11 ++ ...10.A_WCYCL1950_HR.ne120_oRRS18v3_ICG.theta | 182 ++++++++++++++++++ mpas_analysis/config.default | 11 +- mpas_analysis/ocean/streamfunction_moc.py | 15 +- 11 files changed, 278 insertions(+), 33 deletions(-) create mode 100644 configs/theta/config.20180410.A_WCYCL1950_HR.ne120_oRRS18v3_ICG.theta diff --git a/configs/anvil/config.20170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil b/configs/anvil/config.20170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil index 035d50c55..8717586be 100644 --- a/configs/anvil/config.20170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil +++ b/configs/anvil/config.20170926.FCT2.A_WCYCL1850S.ne30_oECv3.anvil @@ -117,7 +117,6 @@ mldSubdirectory = MLD ninoSubdirectory = Nino mhtSubdirectory = MHT - [oceanPreprocessedReference] ## options related to preprocessed ocean reference run with which the results ## will be compared (e.g. a POP, CESM or ACME v0 run) @@ -150,3 +149,15 @@ polarPlot = False # Directory for region mask files regionMaskDirectory = /lcrc/group/acme/mpas_analysis/region_masks + +[streamfunctionMOC] +## options related to plotting the streamfunction of the meridional overturning +## circulation (MOC) + +# Use postprocessing script to compute the MOC? You want this to be True +# for low-resolution simulations that use GM to parameterize eddies, because +# the online MOC analysis member currently does not include the bolus velocity +# in its calculation, whereas the postprocessing script does. +# NOTE: this is a temporary option that will be removed once the online +# MOC takes into account the bolus velocity when GM is on. +usePostprocessingScript = True diff --git a/configs/edison/config.20180129.DECKv1b_piControl.ne30_oEC.edison b/configs/edison/config.20180129.DECKv1b_piControl.ne30_oEC.edison index 70767c20f..f3d918e3e 100644 --- a/configs/edison/config.20180129.DECKv1b_piControl.ne30_oEC.edison +++ b/configs/edison/config.20180129.DECKv1b_piControl.ne30_oEC.edison @@ -137,7 +137,6 @@ mldSubdirectory = MLD ninoSubdirectory = Nino mhtSubdirectory = MHT - [oceanPreprocessedReference] ## options related to preprocessed ocean reference run with which the results ## will be compared (e.g. a POP, CESM or ACME v0 run) @@ -170,3 +169,15 @@ polarPlot = False # Directory for region mask files regionMaskDirectory = /global/project/projectdirs/acme/mpas_analysis/region_masks + +[streamfunctionMOC] +## options related to plotting the streamfunction of the meridional overturning +## circulation (MOC) + +# Use postprocessing script to compute the MOC? You want this to be True +# for low-resolution simulations that use GM to parameterize eddies, because +# the online MOC analysis member currently does not include the bolus velocity +# in its calculation, whereas the postprocessing script does. +# NOTE: this is a temporary option that will be removed once the online +# MOC takes into account the bolus velocity when GM is on. +usePostprocessingScript = True diff --git a/configs/edison/config.20180209.GMPAS-IAF.T62_oRRS30to10v3wLI.cori-knl.afterSalinityFix b/configs/edison/config.20180209.GMPAS-IAF.T62_oRRS30to10v3wLI.cori-knl.afterSalinityFix index c6c7daa44..dfb6f5691 100644 --- a/configs/edison/config.20180209.GMPAS-IAF.T62_oRRS30to10v3wLI.cori-knl.afterSalinityFix +++ b/configs/edison/config.20180209.GMPAS-IAF.T62_oRRS30to10v3wLI.cori-knl.afterSalinityFix @@ -137,7 +137,6 @@ mldSubdirectory = MLD ninoSubdirectory = Nino mhtSubdirectory = MHT - [oceanPreprocessedReference] ## options related to preprocessed ocean reference run with which the results ## will be compared (e.g. a POP, CESM or ACME v0 run) diff --git a/configs/edison/config.20180514.G.oQU240wLI.edison b/configs/edison/config.20180514.G.oQU240wLI.edison index 76e2d456a..20563c58f 100644 --- a/configs/edison/config.20180514.G.oQU240wLI.edison +++ b/configs/edison/config.20180514.G.oQU240wLI.edison @@ -136,7 +136,6 @@ mldSubdirectory = MLD ninoSubdirectory = Nino mhtSubdirectory = MHT - [oceanPreprocessedReference] ## options related to preprocessed ocean reference run with which the results ## will be compared (e.g. a POP, CESM or ACME v0 run) @@ -169,3 +168,15 @@ polarPlot = False # Directory for region mask files regionMaskDirectory = /global/project/projectdirs/acme/mpas_analysis/region_masks + +[streamfunctionMOC] +## options related to plotting the streamfunction of the meridional overturning +## circulation (MOC) + +# Use postprocessing script to compute the MOC? You want this to be True +# for low-resolution simulations that use GM to parameterize eddies, because +# the online MOC analysis member currently does not include the bolus velocity +# in its calculation, whereas the postprocessing script does. +# NOTE: this is a temporary option that will be removed once the online +# MOC takes into account the bolus velocity when GM is on. +usePostprocessingScript = True diff --git a/configs/edison/config.B_low_res_ice_shelves_1696_JWolfe_layout_Edison b/configs/edison/config.B_low_res_ice_shelves_1696_JWolfe_layout_Edison index 1b0fb93c7..361209672 100644 --- a/configs/edison/config.B_low_res_ice_shelves_1696_JWolfe_layout_Edison +++ b/configs/edison/config.B_low_res_ice_shelves_1696_JWolfe_layout_Edison @@ -195,3 +195,15 @@ polarPlot = False # Directory for region mask files regionMaskDirectory = /global/project/projectdirs/acme/mpas_analysis/region_masks + +[streamfunctionMOC] +## options related to plotting the streamfunction of the meridional overturning +## circulation (MOC) + +# Use postprocessing script to compute the MOC? You want this to be True +# for low-resolution simulations that use GM to parameterize eddies, because +# the online MOC analysis member currently does not include the bolus velocity +# in its calculation, whereas the postprocessing script does. +# NOTE: this is a temporary option that will be removed once the online +# MOC takes into account the bolus velocity when GM is on. +usePostprocessingScript = True diff --git a/configs/olcf/config.20170313.beta1.A_WCYCL1850S.ne30_oECv3_ICG.edison b/configs/olcf/config.20170313.beta1.A_WCYCL1850S.ne30_oECv3_ICG.edison index 3d93c3a80..be5301066 100644 --- a/configs/olcf/config.20170313.beta1.A_WCYCL1850S.ne30_oECv3_ICG.edison +++ b/configs/olcf/config.20170313.beta1.A_WCYCL1850S.ne30_oECv3_ICG.edison @@ -137,16 +137,20 @@ baseDirectory = /lustre/atlas/proj-shared/cli115/observations/SeaIce # directory where ocean reference simulation results are stored baseDirectory = /lustre/atlas/proj-shared/cli115/milena/ACMEv0_lowres/B1850C5_ne30_v0.4/ice/postprocessing -[streamfunctionMOC] -## options related to plotting the streamfunction of the meridional overturning -## circulation (MOC) - -# Region names for basin MOC calculation. -# Supported options are Atlantic and IndoPacific -regionNames = ['Atlantic'] - [regions] ## options related to ocean regions used in several analysis modules # Directory for region mask files regionMaskDirectory = /lustre/atlas/proj-shared/cli115/mpas_analysis/region_masks/ + +[streamfunctionMOC] +## options related to plotting the streamfunction of the meridional overturning +## circulation (MOC) + +# Use postprocessing script to compute the MOC? You want this to be True +# for low-resolution simulations that use GM to parameterize eddies, because +# the online MOC analysis member currently does not include the bolus velocity +# in its calculation, whereas the postprocessing script does. +# NOTE: this is a temporary option that will be removed once the online +# MOC takes into account the bolus velocity when GM is on. +usePostprocessingScript = True diff --git a/configs/olcf/config.20170915.beta2.A_WCYCL1850S.ne30_oECv3_ICG.edison b/configs/olcf/config.20170915.beta2.A_WCYCL1850S.ne30_oECv3_ICG.edison index ceb34c0e2..fb309cdff 100644 --- a/configs/olcf/config.20170915.beta2.A_WCYCL1850S.ne30_oECv3_ICG.edison +++ b/configs/olcf/config.20170915.beta2.A_WCYCL1850S.ne30_oECv3_ICG.edison @@ -147,16 +147,20 @@ baseDirectory = /lustre/atlas/proj-shared/cli115/observations/SeaIce # directory where ocean reference simulation results are stored baseDirectory = /lustre/atlas/proj-shared/cli115/milena/ACMEv0_lowres/B1850C5_ne30_v0.4/ice/postprocessing -[streamfunctionMOC] -## options related to plotting the streamfunction of the meridional overturning -## circulation (MOC) - -# Region names for basin MOC calculation. -# Supported options are Atlantic and IndoPacific -regionNames = ['Atlantic'] - [regions] ## options related to ocean regions used in several analysis modules # Directory for region mask files regionMaskDirectory = /lustre/atlas/proj-shared/cli115/mpas_analysis/region_masks + +[streamfunctionMOC] +## options related to plotting the streamfunction of the meridional overturning +## circulation (MOC) + +# Use postprocessing script to compute the MOC? You want this to be True +# for low-resolution simulations that use GM to parameterize eddies, because +# the online MOC analysis member currently does not include the bolus velocity +# in its calculation, whereas the postprocessing script does. +# NOTE: this is a temporary option that will be removed once the online +# MOC takes into account the bolus velocity when GM is on. +usePostprocessingScript = True diff --git a/configs/theta/config.20171031.tenYearTest.GMPAS-IAF.T62_oEC60to30v3wLI.60layer.theta b/configs/theta/config.20171031.tenYearTest.GMPAS-IAF.T62_oEC60to30v3wLI.60layer.theta index fc6750d66..3b19d5a18 100644 --- a/configs/theta/config.20171031.tenYearTest.GMPAS-IAF.T62_oEC60to30v3wLI.60layer.theta +++ b/configs/theta/config.20171031.tenYearTest.GMPAS-IAF.T62_oEC60to30v3wLI.60layer.theta @@ -155,6 +155,17 @@ polarPlot = False # Directory containing mask files for ocean basins and ice shelves regionMaskDirectory = /projects/ccsm/acme/diagnostics_data/region_masks +[streamfunctionMOC] +## options related to plotting the streamfunction of the meridional overturning +## circulation (MOC) + +# Use postprocessing script to compute the MOC? You want this to be True +# for low-resolution simulations that use GM to parameterize eddies, because +# the online MOC analysis member currently does not include the bolus velocity +# in its calculation, whereas the postprocessing script does. +# NOTE: this is a temporary option that will be removed once the online +# MOC takes into account the bolus velocity when GM is on. +usePostprocessingScript = True [climatologyMapSoseTemperature] ## options related to plotting climatology maps of Antarctic diff --git a/configs/theta/config.20180410.A_WCYCL1950_HR.ne120_oRRS18v3_ICG.theta b/configs/theta/config.20180410.A_WCYCL1950_HR.ne120_oRRS18v3_ICG.theta new file mode 100644 index 000000000..c7d44b4b4 --- /dev/null +++ b/configs/theta/config.20180410.A_WCYCL1950_HR.ne120_oRRS18v3_ICG.theta @@ -0,0 +1,182 @@ +[runs] +## options related to the run to be analyzed and reference runs to be +## compared against + +# mainRunName is a name that identifies the simulation being analyzed. +mainRunName = 20180410.A_WCYCL1950_HR.ne120_oRRS18v3_ICG.theta + +# preprocessedReferenceRunName is the name of a reference run that has been +# preprocessed to compare against (or None to turn off comparison). Reference +# runs of this type would have preprocessed results because they were not +# performed with MPAS components (so they cannot be easily ingested by +# MPAS-Analysis) +preprocessedReferenceRunName = None + +# config file for a reference run to which this run will be compared. The +# analysis should have already been run to completion once with this config +# file, so that the relevant MPAS climatologies already exist and have been +# remapped to the comparison grid. Leave this option commented out if no +# reference run is desired. +# referenceRunConfigFile = /path/to/config/file + +[execute] +## options related to executing parallel tasks + +# the number of parallel tasks (1 means tasks run in serial, the default) +parallelTaskCount = 4 + +# the parallelism mode in ncclimo ("serial" or "bck") +# Set this to "bck" (background parallelism) if running on a machine that can +# handle 12 simultaneous processes, one for each monthly climatology. +ncclimoParallelMode = bck + +[input] +## options related to reading in the results to be analyzed + +# directory containing model results +baseDirectory = /projects/ClimateEnergy_2/azamatm/E3SM_simulations/20180410.A_WCYCL1950_HR.ne120_oRRS18v3_ICG.theta/run + +# names of ocean and sea ice meshes (e.g. oEC60to30v3, oQU240v3, oRRS30to10v3, etc.) +mpasMeshName = oRRS18to6v3 + +# Directory for mapping files (if they have been generated already). If mapping +# files needed by the analysis are not found here, they will be generated and +# placed in the output mappingSubdirectory +mappingDirectory = /projects/ccsm/acme/diagnostics_data/mapping + +# names of namelist and streams files, either a path relative to baseDirectory +# or an absolute path. +oceanNamelistFileName = mpas-o_in +oceanStreamsFileName = streams.ocean +seaIceNamelistFileName = mpas-cice_in +seaIceStreamsFileName = streams.cice + +[output] +## options related to writing out plots, intermediate cached data sets, logs, +## etc. + +# directory where analysis should be written +baseDirectory = /dir/to/analysis/output + +# a list of analyses to generate. Valid names can be seen by running: +# ./run_mpas_analysis --list +# This command also lists tags for each analysis. +# Shortcuts exist to generate (or not generate) several types of analysis. +# These include: +# 'all' -- all analyses will be run +# 'all_' -- all analysis with a particular tag will be run +# 'all_' -- all analyses from a given component (either 'ocean' +# or 'seaIce') will be run +# 'only_', 'only_' -- all analysis from this component or +# with this tag will be run, and all +# analysis for other components or +# without the tag will be skipped +# 'no_' -- skip the given task +# 'no_', 'no_' -- in analogy to 'all_*', skip all analysis +# tasks from the given compoonent or with +# the given tag. Do +# ./run_mpas_analysis --list +# to list all task names and their tags +# an equivalent syntax can be used on the command line to override this +# option: +# ./run_mpas_analysis config.analysis --generate \ +# all,no_ocean,all_timeSeries +generate = ['all', 'no_landIceCavities'] + +[climatology] +## options related to producing climatologies, typically to compare against +## observations and previous runs + +# the first year over which to average climatalogies +startYear = 10 +# the last year over which to average climatalogies +endYear = 10 + +[timeSeries] +## options related to producing time series plots, often to compare against +## observations and previous runs + +# start and end years for timeseries analysis. Using out-of-bounds values +# like start_year = 1 and end_year = 9999 will be clipped to the valid range +# of years, and is a good way of insuring that all values are used. +startYear = 8 +endYear = 10 + +[index] +## options related to producing nino index. + +# start and end years for the nino 3.4 analysis. Using out-of-bounds values +# like start_year = 1 and end_year = 9999 will be clipped to the valid range +# of years, and is a good way of insuring that all values are used. +# For valid statistics, index times should include at least 30 years +startYear = 1 +endYear = 9999 + +[oceanObservations] +## options related to ocean observations with which the results will be compared + +# directory where ocean observations are stored +baseDirectory = /projects/ccsm/acme/diagnostics_data/observations/Ocean +sstSubdirectory = SST +sssSubdirectory = SSS +mldSubdirectory = MLD +ninoSubdirectory = Nino +mhtSubdirectory = MHT +soseSubdirectory = SOSE + +[oceanPreprocessedReference] +## options related to preprocessed ocean reference run with which the results +## will be compared (e.g. a POP, CESM or ACME v0 run) + +# directory where ocean reference simulation results are stored +baseDirectory = /projects/ccsm/acme/diagnostics_data/reference_runs/ACMEv0_lowres/B1850C5_ne30_v0.4/ocn/postprocessing + +[seaIceObservations] +## options related to sea ice observations with which the results will be +## compared + +# directory where sea ice observations are stored +baseDirectory = /projects/ccsm/acme/diagnostics_data/observations/SeaIce + +[seaIcePreprocessedReference] +## options related to preprocessed sea ice reference run with which the results +## will be compared (e.g. a CICE, CESM or ACME v0 run) + +# directory where ocean reference simulation results are stored +baseDirectory = /projects/ccsm/acme/diagnostics_data/reference_runs/ACMEv0_lowres/B1850C5_ne30_v0.4/ice/postprocessing + +[timeSeriesSeaIceAreaVol] +## options related to plotting time series of sea ice area and volume + +# plot on polar plot +polarPlot = False + +[regions] +# Directory containing mask files for ocean basins and ice shelves +regionMaskDirectory = /projects/ccsm/acme/diagnostics_data/region_masks + +[climatologyMapSoseTemperature] +## options related to plotting climatology maps of Antarctic +## potential temperature at various levels, including the sea floor against +## reference model results and SOSE reanalysis data + +# Times for comparison times (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, +# Nov, Dec, JFM, AMJ, JAS, OND, ANN) +seasons = ['JFM', 'JAS', 'ANN'] + +# list of depths in meters (positive up) at which to analyze, 'top' for the +# sea surface, 'bot' for the sea floor +depths = ['top', -200, -400, -600, -800, 'bot'] + +[climatologyMapSoseSalinity] +## options related to plotting climatology maps of Antarctic +## salinity at various levels, including the sea floor against +## reference model results and SOSE reanalysis data + +# Times for comparison times (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, +# Nov, Dec, JFM, AMJ, JAS, OND, ANN) +seasons = ['JFM', 'JAS', 'ANN'] + +# list of depths in meters (positive up) at which to analyze, 'top' for the +# sea surface, 'bot' for the sea floor +depths = ['top', -200, -400, -600, -800, 'bot'] diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index 72240ce0d..08da60ade 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -506,10 +506,13 @@ movingAveragePoints = 1 ## options related to plotting the streamfunction of the meridional overturning ## circulation (MOC) -# Include the bolus velocity from the Gent-McWilliams parameterization? This -# only needs to be disabled if the simulation was run with GM turned on but -# the MOC shouldn't include the bolus term -includeBolus = True +# Use postprocessing script to compute the MOC? You want this to be True +# for low-resolution simulations that use GM to parameterize eddies, because +# the online MOC analysis member currently does not include the bolus velocity +# in its calculation, whereas the postprocessing script does. +# NOTE: this is a temporary option that will be removed once the online +# MOC takes into account the bolus velocity when GM is on. +usePostprocessingScript = False # Region names for basin MOC calculation. # Supported options are Atlantic and IndoPacific diff --git a/mpas_analysis/ocean/streamfunction_moc.py b/mpas_analysis/ocean/streamfunction_moc.py index fea6eb307..41afdc658 100644 --- a/mpas_analysis/ocean/streamfunction_moc.py +++ b/mpas_analysis/ocean/streamfunction_moc.py @@ -37,7 +37,7 @@ class StreamfunctionMOC(AnalysisTask): # {{{ Computation and plotting of model meridional overturning circulation. Will eventually support: - * MOC streamfunction, post-processed (currently supported) + * MOC streamfunction, post-processed * MOC streamfunction, from MOC analysis member * MOC time series (max value at 24.5N), post-processed * MOC time series (max value at 24.5N), from MOC analysis member @@ -123,7 +123,10 @@ def setup_and_check(self): # {{{ self.sectionName = 'streamfunctionMOC' - if self.mocAnalysisMemberEnabled: + self.usePostprocessing = config.getExpression(self.sectionName, + 'usePostprocessingScript') + + if not self.usePostprocessing and self.mocAnalysisMemberEnabled: self.variableList = ['timeMonthly_avg_mocStreamvalLatAndDepth', 'timeMonthly_avg_mocStreamvalLatAndDepthRegion'] else: @@ -181,12 +184,7 @@ def run_task(self): # {{{ config = self.config # **** Compute MOC **** - # Check whether MOC Analysis Member is enabled - if self.mocAnalysisMemberEnabled: - #(mocDictClimo, mocDictTseries) = \ - # self._compute_moc_analysismember(config, streams, calendar, - # sectionName, dictClimo, - # dictTseries) + if not self.usePostprocessing and self.mocAnalysisMemberEnabled: self._compute_moc_climo_analysismember() dsMOCTimeSeries = self._compute_moc_time_series_analysismember() else: @@ -344,7 +342,6 @@ def _compute_moc_climo_analysismember(self): # {{{ 'regionNames') self.regionNames.append('Global') - # Read in depth and bin latitudes try: restartFileName = self.runStreams.readpath('restart')[0] From e918458ebfb10408580cd81b9719f4d3e84626ee Mon Sep 17 00:00:00 2001 From: Milena Veneziani Date: Tue, 5 Jun 2018 17:24:10 -0700 Subject: [PATCH 4/4] Add latitude min/max for better plotting of MOC --- mpas_analysis/config.default | 11 +++++++++++ mpas_analysis/ocean/streamfunction_moc.py | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/mpas_analysis/config.default b/mpas_analysis/config.default index 08da60ade..d9433e548 100644 --- a/mpas_analysis/config.default +++ b/mpas_analysis/config.default @@ -518,7 +518,18 @@ usePostprocessingScript = False # Supported options are Atlantic and IndoPacific regionNames = ['Atlantic'] +# Minium value of latitudinal extent for MOC streamfunction plot +latBinMinGlobal = -80. +latBinMinAtlantic = -35. +latBinMinIndoPacific = -80. + +# Maximum value of latitudinal extent for MOC streamfunction plot +latBinMaxGlobal = 80. +latBinMaxAtlantic = 70. +latBinMaxIndoPacific = 70. + # Size of latitude bins over which MOC streamfunction is integrated +# (this is only relevant for the postprocessing MOC script) latBinSizeGlobal = 1. latBinSizeAtlantic = 0.5 latBinSizeIndoPacific = 0.5 diff --git a/mpas_analysis/ocean/streamfunction_moc.py b/mpas_analysis/ocean/streamfunction_moc.py index 41afdc658..92d831888 100644 --- a/mpas_analysis/ocean/streamfunction_moc.py +++ b/mpas_analysis/ocean/streamfunction_moc.py @@ -214,6 +214,15 @@ def run_task(self): # {{{ x = self.lat[region] y = self.depth z = self.moc[region] + # Subset lat range + minLat = config.getExpression(self.sectionName, + 'latBinMin{}'.format(region)) + maxLat = config.getExpression(self.sectionName, + 'latBinMax{}'.format(region)) + indLat = np.logical_and(x >= minLat, x <= maxLat) + x = x[indLat] + z = z[:, indLat] + plot_vertical_section(config, x, y, z, self.sectionName, suffix=region, colorbarLabel=colorbarLabel, title=title, xlabel=xLabel, ylabel=yLabel,