def run_task(self): # {{{ ''' Computes NINO34 index and plots the time series and power spectrum with 95 and 99% confidence bounds ''' # Authors # ------- # Luke Van Roekel, Xylar Asay-Davis config = self.config calendar = self.calendar regionToPlot = config.get('indexNino34', 'region') ninoIndexNumber = regionToPlot[4:] self.logger.info("\nPlotting El Nino {} Index time series and power " "spectrum....".format(ninoIndexNumber)) self.logger.info(' Load SST data...') fieldName = 'nino' startDate = self.config.get('index', 'startDate') endDate = self.config.get('index', 'endDate') startYear = self.config.getint('index', 'startYear') endYear = self.config.getint('index', 'endYear') dataSource = config.get('indexNino34', 'observationData') observationsDirectory = build_obs_path( config, 'ocean', '{}Subdirectory'.format(fieldName)) # specify obsTitle based on data path # These are the only data sets supported if dataSource == 'HADIsst': dataPath = "{}/HADIsst_nino34_20180710.nc".format( observationsDirectory) obsTitle = 'HADSST' refDate = '1870-01-01' elif dataSource == 'ERS_SSTv4': dataPath = "{}/ERS_SSTv4_nino34_20180710.nc".format( observationsDirectory) obsTitle = 'ERS SSTv4' refDate = '1800-01-01' else: raise ValueError('Bad value for config option observationData {} ' 'in [indexNino34] section.'.format(dataSource)) mainRunName = config.get('runs', 'mainRunName') # regionIndex should correspond to NINO34 in surface weighted Average # AM regions = config.getExpression('regions', 'regions') regionToPlot = config.get('indexNino34', 'region') regionIndex = regions.index(regionToPlot) # Load data: ds = open_mpas_dataset(fileName=self.inputFile, calendar=calendar, variableList=self.variableList, startDate=startDate, endDate=endDate) # Observations have been processed to the nino34Index prior to reading dsObs = xr.open_dataset(dataPath, decode_cf=False, decode_times=False) # add the days between 0001-01-01 and the refDate so we have a new # reference date of 0001-01-01 (like for the model Time) dsObs["Time"] = dsObs.Time + \ string_to_days_since_date(dateString=refDate, calendar=calendar) nino34Obs = dsObs.sst self.logger.info( ' Compute El Nino {} Index...'.format(ninoIndexNumber)) varName = self.variableList[0] regionSST = ds[varName].isel(nOceanRegions=regionIndex) nino34Main = self._compute_nino34_index(regionSST, calendar) # Compute the observational index over the entire time range # nino34Obs = compute_nino34_index(dsObs.sst, calendar) self.logger.info( ' Computing El Nino {} power spectra...'.format(ninoIndexNumber)) spectraMain = self._compute_nino34_spectra(nino34Main) # Compute the observational spectra over the whole record spectraObs = self._compute_nino34_spectra(nino34Obs) # Compute the observational spectra over the last 30 years for # comparison. Only saving the spectra subsetEndYear = 2016 if self.controlConfig is None: subsetStartYear = 1976 else: # make the subset the same length as the input data set subsetStartYear = subsetEndYear - (endYear - startYear) time_start = datetime_to_days(datetime.datetime(subsetStartYear, 1, 1), calendar=calendar) time_end = datetime_to_days(datetime.datetime(subsetEndYear, 12, 31), calendar=calendar) nino34Subset = nino34Obs.sel(Time=slice(time_start, time_end)) spectraSubset = self._compute_nino34_spectra(nino34Subset) if self.controlConfig is None: nino34s = [nino34Obs[2:-3], nino34Subset, nino34Main[2:-3]] titles = [ '{} (Full Record)'.format(obsTitle), '{} ({} - {})'.format(obsTitle, subsetStartYear, subsetEndYear), mainRunName ] spectra = [spectraObs, spectraSubset, spectraMain] else: baseDirectory = build_config_full_path(self.controlConfig, 'output', 'timeSeriesSubdirectory') refFileName = '{}/{}.nc'.format( baseDirectory, self.mpasTimeSeriesTask.fullTaskName) dsRef = open_mpas_dataset(fileName=refFileName, calendar=calendar, variableList=self.variableList) regionSSTRef = dsRef[varName].isel(nOceanRegions=regionIndex) nino34Ref = self._compute_nino34_index(regionSSTRef, calendar) nino34s = [nino34Subset, nino34Main[2:-3], nino34Ref[2:-3]] controlRunName = self.controlConfig.get('runs', 'mainRunName') spectraRef = self._compute_nino34_spectra(nino34Ref) titles = [ '{} ({} - {})'.format(obsTitle, subsetStartYear, subsetEndYear), mainRunName, 'Control: {}'.format(controlRunName) ] spectra = [spectraSubset, spectraMain, spectraRef] # Convert frequencies to period in years for s in spectra: s['period'] = \ 1.0 / (constants.eps + s['f'] * constants.sec_per_year) self.logger.info( ' Plot El Nino {} index and spectra...'.format(ninoIndexNumber)) outFileName = '{}/nino{}_{}.png'.format(self.plotsDirectory, ninoIndexNumber, mainRunName) self._nino34_timeseries_plot( nino34s=nino34s, title=u'El Niño {} Index'.format(ninoIndexNumber), panelTitles=titles, outFileName=outFileName) self._write_xml(filePrefix='nino{}_{}'.format(ninoIndexNumber, mainRunName), plotType='Time Series', ninoIndexNumber=ninoIndexNumber) outFileName = '{}/nino{}_spectra_{}.png'.format( self.plotsDirectory, ninoIndexNumber, mainRunName) self._nino34_spectra_plot( spectra=spectra, title=u'El Niño {} power spectrum'.format(ninoIndexNumber), panelTitles=titles, outFileName=outFileName) self._write_xml(filePrefix='nino{}_spectra_{}'.format( ninoIndexNumber, mainRunName), plotType='Spectra', ninoIndexNumber=ninoIndexNumber)
def run_task(self): # {{{ """ Compute time-series output of properties in an ocean region. """ # Authors # ------- # Xylar Asay-Davis self.logger.info("\nAveraging T and S for {}...".format( self.regionName)) obsDict = self.obsDict config = self.config regionGroup = self.regionGroup timeSeriesName = regionGroup[0].lower() + \ regionGroup[1:].replace(' ', '') sectionSuffix = regionGroup[0].upper() + \ regionGroup[1:].replace(' ', '') sectionName = 'timeSeries{}'.format(sectionSuffix) outputDirectory = '{}/{}/'.format( build_config_full_path(self.config, 'output', 'timeseriesSubdirectory'), timeSeriesName) try: os.makedirs(outputDirectory) except OSError: pass outFileName = '{}/TS_{}_{}.nc'.format(outputDirectory, obsDict['suffix'], self.prefix) if os.path.exists(outFileName): return regionMaskFileName = obsDict['maskTask'].maskFileName print(regionMaskFileName) print(xarray.open_dataset(regionMaskFileName)) dsRegionMask = \ xarray.open_dataset(regionMaskFileName).stack( nCells=(obsDict['latVar'], obsDict['lonVar'])) dsRegionMask = dsRegionMask.reset_index('nCells').drop_vars( [obsDict['latVar'], obsDict['lonVar']]) maskRegionNames = decode_strings(dsRegionMask.regionNames) regionIndex = maskRegionNames.index(self.regionName) dsMask = dsRegionMask.isel(nRegions=regionIndex) cellMask = dsMask.regionCellMasks == 1 if config.has_option(sectionName, 'zmin'): zmin = config.getfloat(sectionName, 'zmin') else: zmin = dsMask.zminRegions.values if config.has_option(sectionName, 'zmax'): zmax = config.getfloat(sectionName, 'zmax') else: zmax = dsMask.zmaxRegions.values TVarName = obsDict['TVar'] SVarName = obsDict['SVar'] zVarName = obsDict['zVar'] lonVarName = obsDict['lonVar'] latVarName = obsDict['latVar'] volVarName = obsDict['volVar'] tDim = obsDict['tDim'] obsFileName = build_obs_path(config, component=self.componentName, relativePath=obsDict['TFileName']) self.logger.info(' Reading from {}...'.format(obsFileName)) ds = xarray.open_dataset(obsFileName) if obsDict['SFileName'] != obsDict['TFileName']: obsFileName = build_obs_path(config, component=self.componentName, relativePath=obsDict['SFileName']) self.logger.info(' Reading from {}...'.format(obsFileName)) dsS = xarray.open_dataset(obsFileName) ds[SVarName] = dsS[SVarName] if obsDict['volFileName'] is None: # compute volume from lat, lon, depth bounds self.logger.info(' Computing volume...'.format(obsFileName)) latBndsName = ds[latVarName].attrs['bounds'] lonBndsName = ds[lonVarName].attrs['bounds'] zBndsName = ds[zVarName].attrs['bounds'] latBnds = ds[latBndsName] lonBnds = ds[lonBndsName] zBnds = ds[zBndsName] dLat = numpy.deg2rad(latBnds[:, 1] - latBnds[:, 0]) dLon = numpy.deg2rad(lonBnds[:, 1] - lonBnds[:, 0]) lat = numpy.deg2rad(ds[latVarName]) dz = zBnds[:, 1] - zBnds[:, 0] radius = 6378137.0 area = radius**2 * numpy.cos(lat) * dLat * dLon volume = dz * area ds[volVarName] = volume elif obsDict['volFileName'] != obsDict['TFileName']: obsFileName = build_obs_path(config, component=self.componentName, relativePath=obsDict['volFileName']) self.logger.info(' Reading from {}...'.format(obsFileName)) dsVol = xarray.open_dataset(obsFileName) ds[volVarName] = dsVol[volVarName] if 'positive' in ds[zVarName].attrs and \ ds[zVarName].attrs['positive'] == 'down': attrs = ds[zVarName].attrs ds[zVarName] = -ds[zVarName] ds[zVarName].attrs = attrs ds[zVarName].attrs['positive'] = 'up' TMean = numpy.zeros(ds.sizes[tDim]) SMean = numpy.zeros(ds.sizes[tDim]) depthMask = numpy.logical_and(ds[zVarName] >= zmin, ds[zVarName] <= zmax) for tIndex in range(ds.sizes[tDim]): dsMonth = ds.isel({tDim: tIndex}) dsMonth = dsMonth.stack(nCells=(obsDict['latVar'], obsDict['lonVar'])) dsMonth = dsMonth.reset_index('nCells').drop_vars( [obsDict['latVar'], obsDict['lonVar']]) dsMonth = dsMonth.where(cellMask, drop=True) dsMonth = dsMonth.where(depthMask) mask = dsMonth[TVarName].notnull() TSum = (dsMonth[TVarName] * dsMonth[volVarName]).sum(dim=('nCells', zVarName)) volSum = (mask * dsMonth[volVarName]).sum(dim=('nCells', zVarName)) TMean[tIndex] = TSum / volSum mask = dsMonth[SVarName].notnull() SSum = (dsMonth[SVarName] * dsMonth[volVarName]).sum(dim=('nCells', zVarName)) volSum = (mask * dsMonth[volVarName]).sum(dim=('nCells', zVarName)) SMean[tIndex] = SSum / volSum dsOut = xarray.Dataset() dsOut['temperature'] = ('Time', TMean) dsOut['salinity'] = ('Time', SMean) dsOut['zbounds'] = ('nBounds', [zmin, zmax]) dsOut['month'] = ('Time', numpy.array(ds.month.values, dtype=float)) dsOut['year'] = ('Time', numpy.ones(ds.sizes[tDim])) write_netcdf(dsOut, outFileName)
def __init__(self, config, mpasClimatologyTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Xylar Asay-Davis fieldName = 'meltRate' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapAntarcticMelt, self).__init__( config=config, taskName='climatologyMapAntarcticMelt', componentName='ocean', tags=['climatology', 'horizontalMap', fieldName, 'landIceCavities', 'antarctic']) sectionName = self.taskName mpasFieldName = 'timeMonthly_avg_landIceFreshwaterFlux' iselValues = None # read in what seasons we want to plot seasons = config.getExpression(sectionName, 'seasons') if len(seasons) == 0: raise ValueError('config section {} does not contain valid list ' 'of seasons'.format(sectionName)) comparisonGridNames = config.getExpression(sectionName, 'comparisonGrids') if len(comparisonGridNames) == 0: raise ValueError('config section {} does not contain valid list ' 'of comparison grids'.format(sectionName)) # the variable 'timeMonthly_avg_landIceFreshwaterFlux' will be added to # mpasClimatologyTask along with the seasons. remapClimatologySubtask = RemapMpasAntarcticMeltClimatology( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName=fieldName, variableList=[mpasFieldName], comparisonGridNames=comparisonGridNames, seasons=seasons, iselValues=iselValues) if controlConfig is None: refTitleLabel = \ 'Observations (Rignot et al, 2013)' observationsDirectory = build_obs_path( config, 'ocean', 'meltSubdirectory') obsFileName = \ '{}/Rignot_2013_melt_rates_6000.0x6000.0km_10.0km_' \ 'Antarctic_stereo.nc'.format(observationsDirectory) refFieldName = 'meltRate' outFileLabel = 'meltRignot' galleryName = 'Observations: Rignot et al. (2013)' remapObservationsSubtask = RemapObservedAntarcticMeltClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, outFilePrefix=refFieldName, comparisonGridNames=comparisonGridNames) self.add_subtask(remapObservationsSubtask) diffTitleLabel = 'Model - Observations' else: remapObservationsSubtask = None controlRunName = controlConfig.get('runs', 'mainRunName') galleryName = None refTitleLabel = 'Control: {}'.format(controlRunName) refFieldName = mpasFieldName outFileLabel = 'melt' diffTitleLabel = 'Main - Control' for comparisonGridName in comparisonGridNames: for season in seasons: # make a new subtask for this season and comparison grid subtask = PlotClimatologyMapSubtask( self, season, comparisonGridName, remapClimatologySubtask, remapObservationsSubtask, controlConfig=controlConfig) subtask.set_plot_info( outFileLabel=outFileLabel, fieldNameInTitle='Melt Rate', mpasFieldName=mpasFieldName, refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'm a$^{-1}$', imageCaption='Antarctic Melt Rate', galleryGroup='Melt Rate', groupSubtitle=None, groupLink='antarctic_melt', galleryName=galleryName) self.add_subtask(subtask)
def _add_obs_tasks(self, seasons, comparisonGridNames, hemisphere, hemisphereLong, remapClimatologySubtask, mpasFieldName): # {{{ config = self.config obsFieldName = 'seaIceConc' sectionName = self.taskName observationPrefixes = config.getExpression(sectionName, 'observationPrefixes') for prefix in observationPrefixes: for season in seasons: observationTitleLabel = \ 'Observations (SSM/I {})'.format(prefix) obsFileName = build_obs_path( config, 'seaIce', relativePathOption='concentration{}{}_{}'.format( prefix, hemisphere, season), relativePathSection=sectionName) remapObservationsSubtask = RemapObservedConcClimatology( parentTask=self, seasons=[season], fileName=obsFileName, outFilePrefix='{}{}{}_{}'.format(obsFieldName, prefix, hemisphere, season), comparisonGridNames=comparisonGridNames, subtaskName='remapObservations_{}{}'.format( prefix, season)) self.add_subtask(remapObservationsSubtask) for comparisonGridName in comparisonGridNames: imageDescription = \ '{} Climatology Map of {}-Hemisphere Sea-Ice ' \ 'Concentration'.format(season, hemisphereLong) imageCaption = \ '{}. <br> Observations: SSM/I {}'.format( imageDescription, prefix) galleryGroup = \ '{}-Hemisphere Sea-Ice Concentration'.format( hemisphereLong) # make a new subtask for this season and comparison # grid subtask = PlotClimatologyMapSubtask( self, hemisphere, season, comparisonGridName, remapClimatologySubtask, remapObsClimatologySubtask=remapObservationsSubtask, subtaskSuffix=prefix) subtask.set_plot_info( outFileLabel='iceconc{}{}'.format(prefix, hemisphere), fieldNameInTitle='Sea ice concentration', mpasFieldName=mpasFieldName, refFieldName=obsFieldName, refTitleLabel=observationTitleLabel, diffTitleLabel='Model - Observations', unitsLabel=r'fraction', imageDescription=imageDescription, imageCaption=imageCaption, galleryGroup=galleryGroup, groupSubtitle=None, groupLink='{}_conc'.format(hemisphere.lower()), galleryName='Observations: SSM/I {}'.format(prefix)) self.add_subtask(subtask)
def __init__(self, config, regionMasksTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options regionMasksTask : ``ComputeRegionMasks`` A task for computing region masks controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Xylar Asay-Davis # first, call the constructor from the base class (AnalysisTask) super(TimeSeriesOceanRegions, self).__init__(config=config, taskName='timeSeriesOceanRegions', componentName='ocean', tags=['timeSeries', 'regions', 'antarctic']) startYear = config.getint('timeSeries', 'startYear') endYear = config.get('timeSeries', 'endYear') if endYear == 'end': # a valid end year wasn't found, so likely the run was not found, # perhaps because we're just listing analysis tasks endYear = startYear else: endYear = int(endYear) regionGroups = config.getExpression(self.taskName, 'regionGroups') obsDicts = { 'SOSE': { 'suffix': 'SOSE', 'gridName': 'SouthernOcean_0.167x0.167degree', 'gridFileName': 'SOSE/SOSE_2005-2010_monthly_pot_temp_' 'SouthernOcean_0.167x0.167degree_20180710.nc', 'TFileName': 'SOSE/SOSE_2005-2010_monthly_pot_temp_' 'SouthernOcean_0.167x0.167degree_20180710.nc', 'SFileName': 'SOSE/SOSE_2005-2010_monthly_salinity_' 'SouthernOcean_0.167x0.167degree_20180710.nc', 'volFileName': 'SOSE/SOSE_volume_' 'SouthernOcean_0.167x0.167degree_20190815.nc', 'lonVar': 'lon', 'latVar': 'lat', 'TVar': 'theta', 'SVar': 'salinity', 'volVar': 'volume', 'zVar': 'z', 'tDim': 'Time', 'legend': 'SOSE 2005-2010 ANN mean' }, 'WOA18': { 'suffix': 'WOA18', 'gridName': 'Global_0.25x0.25degree', 'gridFileName': 'WOA18/woa18_decav_04_TS_mon_20190829.nc', 'TFileName': 'WOA18/woa18_decav_04_TS_mon_20190829.nc', 'SFileName': 'WOA18/woa18_decav_04_TS_mon_20190829.nc', 'volFileName': None, 'lonVar': 'lon', 'latVar': 'lat', 'TVar': 't_an', 'SVar': 's_an', 'volVar': 'volume', 'zVar': 'depth', 'tDim': 'month', 'legend': 'WOA18 1955-2017 ANN mean' } } for regionGroup in regionGroups: sectionSuffix = regionGroup[0].upper() + \ regionGroup[1:].replace(' ', '') sectionName = 'timeSeries{}'.format(sectionSuffix) regionNames = config.getExpression(sectionName, 'regionNames') if len(regionNames) == 0: # no regions in this group were requested continue masksSubtask = regionMasksTask.add_mask_subtask( regionGroup=regionGroup) regionNames = masksSubtask.expand_region_names(regionNames) years = list(range(startYear, endYear + 1)) obsList = config.getExpression(sectionName, 'obs') groupObsDicts = {} for obsName in obsList: localObsDict = dict(obsDicts[obsName]) obsFileName = build_obs_path( config, component=self.componentName, relativePath=localObsDict['gridFileName']) obsMasksSubtask = regionMasksTask.add_mask_subtask( regionGroup=regionGroup, obsFileName=obsFileName, lonVar=localObsDict['lonVar'], latVar=localObsDict['latVar'], meshName=localObsDict['gridName']) obsDicts[obsName]['maskTask'] = obsMasksSubtask localObsDict['maskTask'] = obsMasksSubtask groupObsDicts[obsName] = localObsDict # in the end, we'll combine all the time series into one, but we # create this task first so it's easier to tell it to run after all # the compute tasks combineSubtask = CombineRegionalProfileTimeSeriesSubtask( self, startYears=years, endYears=years, regionGroup=regionGroup) depthMasksSubtask = ComputeRegionDepthMasksSubtask( self, masksSubtask=masksSubtask, regionGroup=regionGroup, regionNames=regionNames) depthMasksSubtask.run_after(masksSubtask) # run one subtask per year for year in years: computeSubtask = ComputeRegionTimeSeriesSubtask( self, startYear=year, endYear=year, masksSubtask=masksSubtask, regionGroup=regionGroup, regionNames=regionNames) self.add_subtask(computeSubtask) computeSubtask.run_after(depthMasksSubtask) computeSubtask.run_after(masksSubtask) combineSubtask.run_after(computeSubtask) self.add_subtask(combineSubtask) for index, regionName in enumerate(regionNames): fullSuffix = sectionSuffix + '_' + regionName[0].lower() + \ regionName[1:].replace(' ', '') obsSubtasks = {} for obsName in obsList: localObsDict = dict(groupObsDicts[obsName]) obsSubtask = ComputeObsRegionalTimeSeriesSubtask( self, regionGroup, regionName, fullSuffix, localObsDict) obsSubtasks[obsName] = obsSubtask plotRegionSubtask = PlotRegionTimeSeriesSubtask( self, regionGroup, regionName, index, controlConfig, sectionName, fullSuffix, obsSubtasks, masksSubtask.geojsonFileName) plotRegionSubtask.run_after(combineSubtask) self.add_subtask(plotRegionSubtask)
def __init__(self, config, mpasClimatologyTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) Authors ------- Phillip J. Wolfram, Riley X. Brady, Xylar Asay-Davis """ # call the constructor from the base class (AnalysisTask) bgcVars = config.getExpression('climatologyMapBGC', 'variables') super(ClimatologyMapBGC, self).__init__( config=config, taskName='climatologyMapBGC', componentName='ocean', tags=['climatology', 'horizontalMap', 'BGC'] + bgcVars) sectionName = 'climatologyMapBGC' # read in what seasons we want to plot seasons = config.getExpression(sectionName, 'seasons') if len(seasons) == 0: raise ValueError('config section {} does not contain valid list ' 'of seasons'.format(sectionName)) comparisonGridNames = config.getExpression(sectionName, 'comparisonGrids') if len(comparisonGridNames) == 0: raise ValueError('config section {} does not contain valid list ' 'of comparison grids'.format(sectionName)) preindustrial = config.getboolean(sectionName, 'preindustrial') obsFileDict = { 'Chl': 'Chl_SeaWIFS_20180702.nc', 'CO2_gas_flux': 'CO2_gas_flux_1.0x1.0degree_20180628.nc', 'SiO3': 'SiO3_1.0x1.0degree_20180628.nc', 'PO4': 'PO4_1.0x1.0degree_20180628.nc', 'ALK': 'ALK_1.0x1.0degree_20180629.nc', 'NO3': 'NO3_1.0x1.0degree_20180628.nc', 'pCO2surface': 'pCO2surface_1.0x1.0degree_20180629.nc', 'O2': 'O2_1.0x1.0degree_20180628.nc', 'pH_3D': 'pH_3D_1.0x1.0degree_20180629.nc' } # If user wants to compare to preindustrial data, make sure # that we load in the right DIC field. if preindustrial: obsFileDict['DIC'] = 'PI_DIC_1.0x1.0degree_20180629.nc' else: obsFileDict['DIC'] = 'DIC_1.0x1.0degree_20180629.nc' for fieldName in bgcVars: fieldSectionName = '{}_{}'.format(sectionName, fieldName) prefix = config.get(fieldSectionName, 'filePrefix') mpasFieldName = '{}{}'.format(prefix, fieldName) # CO2 flux and pCO2 has no vertical levels, throws error if you try # to select any. Can add any other flux-like variables to this # list. if fieldName not in ['CO2_gas_flux', 'pCO2surface']: iselValues = {'nVertLevels': 0} else: iselValues = None # Read in units (since BGC units are variable) units = config.get(fieldSectionName, 'units') # Pass multiple variables if working with Chlorophyll to sum # them to total chlorophyll if fieldName == 'Chl': prefix = 'timeMonthly_avg_ecosysTracers_' variableList = [ prefix + 'spChl', prefix + 'diatChl', prefix + 'diazChl', prefix + 'phaeoChl' ] plotField = 'Chl' else: variableList = [mpasFieldName] plotField = mpasFieldName remapClimatologySubtask = RemapBGCClimatology( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName=fieldName, variableList=variableList, comparisonGridNames=comparisonGridNames, seasons=seasons, iselValues=iselValues, subtaskName='remapMpasClimatology_{}'.format(fieldName)) if controlConfig is None: refTitleLabel = 'Observations' if preindustrial and 'DIC' in fieldName: refTitleLabel += ' (Preindustrial)' observationsDirectory = build_obs_path( config, 'ocean', '{}Subdirectory'.format(fieldName)) obsFileName = "{}/{}".format(observationsDirectory, obsFileDict[fieldName]) observationsLabel = config.get(fieldSectionName, 'observationsLabel') refFieldName = fieldName outFileLabel = fieldName + observationsLabel galleryLabel = config.get(fieldSectionName, 'galleryLabel') galleryName = '{} (Compared to {})'.format( galleryLabel, observationsLabel) remapObservationsSubtask = RemapObservedBGCClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, outFilePrefix=refFieldName, comparisonGridNames=comparisonGridNames, subtaskName='remapObservations_{}'.format(fieldName)) self.add_subtask(remapObservationsSubtask) diffTitleLabel = 'Model - Observations' # Certain BGC observations are only available at annual # resolution. Need to ensure that the user is aware that their # seasonal or monthly climatology is being compared to ANN. # Currently, this is just with GLODAP. if observationsLabel == 'GLODAPv2': diffTitleLabel += ' (Compared to ANN)' else: remapObservationsSubtask = None controlRunName = controlConfig.get('runs', 'mainRunName') galleryName = None refTitleLabel = 'Control: {}'.format(controlRunName) refFieldName = mpasFieldName outFileLabel = fieldName diffTitleLabel = 'Main - Control' for comparisonGridName in comparisonGridNames: for season in seasons: # make a new subtask for this season and comparison grid subtask = PlotClimatologyMapSubtask( self, season, comparisonGridName, remapClimatologySubtask, remapObservationsSubtask, controlConfig=controlConfig, subtaskName='plot{}_{}_{}'.format( fieldName, season, comparisonGridName)) subtask.set_plot_info( outFileLabel=outFileLabel, fieldNameInTitle=fieldName, mpasFieldName=plotField, refFieldName=refFieldName, refTitleLabel=refTitleLabel, unitsLabel=units, imageCaption='Mean ' + fieldName, galleryGroup='Sea Surface Biogeochemistry', groupSubtitle=None, groupLink=fieldName, galleryName=galleryName, diffTitleLabel=diffTitleLabel, configSectionName=fieldSectionName) self.add_subtask(subtask)
def __init__(self, config, mpasClimatologyTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Xylar Asay-Davis fieldName = 'mld' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapMLD, self).__init__( config=config, taskName='climatologyMapMLD', componentName='ocean', tags=['climatology', 'horizontalMap', fieldName, 'publicObs']) sectionName = self.taskName mpasFieldName = 'timeMonthly_avg_dThreshMLD' iselValues = None # read in what seasons we want to plot seasons = config.getExpression(sectionName, 'seasons') if len(seasons) == 0: raise ValueError('config section {} does not contain valid list ' 'of seasons'.format(sectionName)) comparisonGridNames = config.getExpression(sectionName, 'comparisonGrids') if len(comparisonGridNames) == 0: raise ValueError('config section {} does not contain valid list ' 'of comparison grids'.format(sectionName)) # the variable 'timeMonthly_avg_dThreshMLD' will be added to # mpasClimatologyTask along with the seasons. remapClimatologySubtask = RemapMpasClimatologySubtask( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName=fieldName, variableList=[mpasFieldName], comparisonGridNames=comparisonGridNames, seasons=seasons, iselValues=iselValues) if controlConfig is None: observationsDirectory = build_obs_path( config, 'ocean', '{}Subdirectory'.format(fieldName)) obsFileName = "{}/holtetalley_mld_climatology_20180710.nc".format( observationsDirectory) refFieldName = 'mld' outFileLabel = 'mldHolteTalleyARGO' remapObservationsSubtask = RemapObservedMLDClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, outFilePrefix=refFieldName, comparisonGridNames=comparisonGridNames) self.add_subtask(remapObservationsSubtask) galleryName = 'Observations: Holte-Talley ARGO' refTitleLabel = \ 'Observations (HolteTalley density threshold MLD)' diffTitleLabel = 'Model - Observations' else: remapObservationsSubtask = None controlRunName = controlConfig.get('runs', 'mainRunName') galleryName = None refTitleLabel = 'Control: {}'.format(controlRunName) refFieldName = mpasFieldName outFileLabel = 'mld' diffTitleLabel = 'Main - Control' for comparisonGridName in comparisonGridNames: for season in seasons: # make a new subtask for this season and comparison grid subtask = PlotClimatologyMapSubtask( self, season, comparisonGridName, remapClimatologySubtask, remapObservationsSubtask, controlConfig=controlConfig) subtask.set_plot_info(outFileLabel=outFileLabel, fieldNameInTitle='MLD', mpasFieldName=mpasFieldName, refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'm', imageCaption='Mean Mixed-Layer Depth', galleryGroup='Mixed-Layer Depth', groupSubtitle=None, groupLink='mld', galleryName=galleryName) self.add_subtask(subtask)
def run_task(self): # {{{ """ Performs analysis of time series of sea-ice properties. """ # Authors # ------- # Xylar Asay-Davis, Milena Veneziani self.logger.info("\nPlotting sea-ice area and volume time series...") config = self.config calendar = self.calendar sectionName = self.taskName plotTitles = {'iceArea': 'Sea-ice area', 'iceVolume': 'Sea-ice volume', 'iceThickness': 'Sea-ice mean thickness'} units = {'iceArea': '[km$^2$]', 'iceVolume': '[10$^3$ km$^3$]', 'iceThickness': '[m]'} obsFileNames = { 'iceArea': {'NH': build_obs_path( config, 'seaIce', relativePathOption='areaNH', relativePathSection=sectionName), 'SH': build_obs_path( config, 'seaIce', relativePathOption='areaSH', relativePathSection=sectionName)}, 'iceVolume': {'NH': build_obs_path( config, 'seaIce', relativePathOption='volNH', relativePathSection=sectionName), 'SH': build_obs_path( config, 'seaIce', relativePathOption='volSH', relativePathSection=sectionName)}} # Some plotting rules titleFontSize = config.get('timeSeriesSeaIceAreaVol', 'titleFontSize') mainRunName = config.get('runs', 'mainRunName') preprocessedReferenceRunName = \ config.get('runs', 'preprocessedReferenceRunName') preprocessedReferenceDirectory = \ config.get('seaIcePreprocessedReference', 'baseDirectory') compareWithObservations = config.getboolean('timeSeriesSeaIceAreaVol', 'compareWithObservations') movingAveragePoints = config.getint('timeSeriesSeaIceAreaVol', 'movingAveragePoints') polarPlot = config.getboolean('timeSeriesSeaIceAreaVol', 'polarPlot') outputDirectory = build_config_full_path(config, 'output', 'timeseriesSubdirectory') make_directories(outputDirectory) self.logger.info(' Load sea-ice data...') # Load mesh dsTimeSeries = self._compute_area_vol() yearStart = days_to_datetime(dsTimeSeries['NH'].Time.min(), calendar=calendar).year yearEnd = days_to_datetime(dsTimeSeries['NH'].Time.max(), calendar=calendar).year timeStart = date_to_days(year=yearStart, month=1, day=1, calendar=calendar) timeEnd = date_to_days(year=yearEnd, month=12, day=31, calendar=calendar) if preprocessedReferenceRunName != 'None': # determine if we're beyond the end of the preprocessed data # (and go ahead and cache the data set while we're checking) outFolder = '{}/preprocessed'.format(outputDirectory) make_directories(outFolder) inFilesPreprocessed = '{}/icevol.{}.year*.nc'.format( preprocessedReferenceDirectory, preprocessedReferenceRunName) outFileName = '{}/iceVolume.nc'.format(outFolder) combine_time_series_with_ncrcat(inFilesPreprocessed, outFileName, logger=self.logger) dsPreprocessed = open_mpas_dataset(fileName=outFileName, calendar=calendar, timeVariableNames='xtime') preprocessedYearEnd = days_to_datetime(dsPreprocessed.Time.max(), calendar=calendar).year if yearStart <= preprocessedYearEnd: dsPreprocessedTimeSlice = \ dsPreprocessed.sel(Time=slice(timeStart, timeEnd)) else: self.logger.warning('Preprocessed time series ends before the ' 'timeSeries startYear and will not be ' 'plotted.') preprocessedReferenceRunName = 'None' if self.controlConfig is not None: dsTimeSeriesRef = {} baseDirectory = build_config_full_path( self.controlConfig, 'output', 'timeSeriesSubdirectory') controlRunName = self.controlConfig.get('runs', 'mainRunName') for hemisphere in ['NH', 'SH']: inFileName = '{}/seaIceAreaVol{}.nc'.format(baseDirectory, hemisphere) dsTimeSeriesRef[hemisphere] = xr.open_dataset(inFileName) norm = {'iceArea': 1e-6, # m^2 to km^2 'iceVolume': 1e-12, # m^3 to 10^3 km^3 'iceThickness': 1.} xLabel = 'Time [years]' galleryGroup = 'Time Series' groupLink = 'timeseries' obs = {} preprocessed = {} figureNameStd = {} figureNamePolar = {} title = {} plotVars = {} obsLegend = {} plotVarsRef = {} for hemisphere in ['NH', 'SH']: self.logger.info(' Make {} plots...'.format(hemisphere)) for variableName in ['iceArea', 'iceVolume']: key = (hemisphere, variableName) # apply the norm to each variable plotVars[key] = (norm[variableName] * dsTimeSeries[hemisphere][variableName]) if self.controlConfig is not None: plotVarsRef[key] = norm[variableName] * \ dsTimeSeriesRef[hemisphere][variableName] prefix = '{}/{}{}_{}'.format(self.plotsDirectory, variableName, hemisphere, mainRunName) figureNameStd[key] = '{}.png'.format(prefix) figureNamePolar[key] = '{}_polar.png'.format(prefix) title[key] = '{} ({})'.format(plotTitles[variableName], hemisphere) if compareWithObservations: key = (hemisphere, 'iceArea') obsLegend[key] = 'SSM/I observations, annual cycle ' if hemisphere == 'NH': key = (hemisphere, 'iceVolume') obsLegend[key] = 'PIOMAS, annual cycle (blue)' if preprocessedReferenceRunName != 'None': for variableName in ['iceArea', 'iceVolume']: key = (hemisphere, variableName) if compareWithObservations: outFolder = '{}/obs'.format(outputDirectory) make_directories(outFolder) outFileName = '{}/iceArea{}.nc'.format(outFolder, hemisphere) combine_time_series_with_ncrcat( obsFileNames['iceArea'][hemisphere], outFileName, logger=self.logger) dsObs = open_mpas_dataset(fileName=outFileName, calendar=calendar, timeVariableNames='xtime') key = (hemisphere, 'iceArea') obs[key] = self._replicate_cycle(plotVars[key], dsObs.IceArea, calendar) key = (hemisphere, 'iceVolume') if hemisphere == 'NH': outFileName = '{}/iceVolume{}.nc'.format(outFolder, hemisphere) combine_time_series_with_ncrcat( obsFileNames['iceVolume'][hemisphere], outFileName, logger=self.logger) dsObs = open_mpas_dataset(fileName=outFileName, calendar=calendar, timeVariableNames='xtime') obs[key] = self._replicate_cycle(plotVars[key], dsObs.IceVol, calendar) else: obs[key] = None if preprocessedReferenceRunName != 'None': outFolder = '{}/preprocessed'.format(outputDirectory) inFilesPreprocessed = '{}/icearea.{}.year*.nc'.format( preprocessedReferenceDirectory, preprocessedReferenceRunName) outFileName = '{}/iceArea.nc'.format(outFolder) combine_time_series_with_ncrcat(inFilesPreprocessed, outFileName, logger=self.logger) dsPreprocessed = open_mpas_dataset(fileName=outFileName, calendar=calendar, timeVariableNames='xtime') dsPreprocessedTimeSlice = dsPreprocessed.sel( Time=slice(timeStart, timeEnd)) key = (hemisphere, 'iceArea') preprocessed[key] = dsPreprocessedTimeSlice[ 'icearea_{}'.format(hemisphere.lower())] inFilesPreprocessed = '{}/icevol.{}.year*.nc'.format( preprocessedReferenceDirectory, preprocessedReferenceRunName) outFileName = '{}/iceVolume.nc'.format(outFolder) combine_time_series_with_ncrcat(inFilesPreprocessed, outFileName, logger=self.logger) dsPreprocessed = open_mpas_dataset(fileName=outFileName, calendar=calendar, timeVariableNames='xtime') dsPreprocessedTimeSlice = dsPreprocessed.sel( Time=slice(timeStart, timeEnd)) key = (hemisphere, 'iceVolume') preprocessed[key] = dsPreprocessedTimeSlice[ 'icevolume_{}'.format(hemisphere.lower())] for variableName in ['iceArea', 'iceVolume']: key = (hemisphere, variableName) dsvalues = [plotVars[key]] legendText = [mainRunName] lineColors = ['k'] lineWidths = [3] if compareWithObservations and key in obsLegend.keys(): dsvalues.append(obs[key]) legendText.append(obsLegend[key]) lineColors.append('b') lineWidths.append(1.2) if preprocessedReferenceRunName != 'None': dsvalues.append(preprocessed[key]) legendText.append(preprocessedReferenceRunName) lineColors.append('purple') lineWidths.append(1.2) if self.controlConfig is not None: dsvalues.append(plotVarsRef[key]) legendText.append(controlRunName) lineColors.append('r') lineWidths.append(1.2) if config.has_option(sectionName, 'firstYearXTicks'): firstYearXTicks = config.getint(sectionName, 'firstYearXTicks') else: firstYearXTicks = None if config.has_option(sectionName, 'yearStrideXTicks'): yearStrideXTicks = config.getint(sectionName, 'yearStrideXTicks') else: yearStrideXTicks = None # separate plots for nothern and southern hemispheres timeseries_analysis_plot(config, dsvalues, movingAveragePoints, title[key], xLabel, units[variableName], calendar=calendar, lineColors=lineColors, lineWidths=lineWidths, legendText=legendText, titleFontSize=titleFontSize, firstYearXTicks=firstYearXTicks, yearStrideXTicks=yearStrideXTicks) savefig(figureNameStd[key]) filePrefix = '{}{}_{}'.format(variableName, hemisphere, mainRunName) thumbnailDescription = '{} {}'.format( hemisphere, plotTitles[variableName]) caption = 'Running mean of {}'.format( thumbnailDescription) write_image_xml( config, filePrefix, componentName='Sea Ice', componentSubdirectory='sea_ice', galleryGroup=galleryGroup, groupLink=groupLink, thumbnailDescription=thumbnailDescription, imageDescription=caption, imageCaption=caption) if (polarPlot): timeseries_analysis_plot_polar( config, dsvalues, movingAveragePoints, title[key], lineColors=lineColors, lineWidths=lineWidths, legendText=legendText, titleFontSize=titleFontSize) savefig(figureNamePolar[key]) filePrefix = '{}{}_{}_polar'.format(variableName, hemisphere, mainRunName) write_image_xml( config, filePrefix, componentName='Sea Ice', componentSubdirectory='sea_ice', galleryGroup=galleryGroup, groupLink=groupLink, thumbnailDescription=thumbnailDescription, imageDescription=caption, imageCaption=caption)
def __init__(self, config, mpasClimatologyTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Xylar Asay-Davis fieldName = 'sst' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapSST, self).__init__( config=config, taskName='climatologyMapSST', componentName='ocean', tags=['climatology', 'horizontalMap', fieldName, 'publicObs']) mpasFieldName = 'timeMonthly_avg_activeTracers_temperature' iselValues = {'nVertLevels': 0} sectionName = self.taskName climStartYear = config.getint(sectionName, 'obsStartYear') climEndYear = config.getint(sectionName, 'obsEndYear') # read in what seasons we want to plot seasons = config.getExpression(sectionName, 'seasons') if len(seasons) == 0: raise ValueError('config section {} does not contain valid list ' 'of seasons'.format(sectionName)) comparisonGridNames = config.getExpression(sectionName, 'comparisonGrids') if len(comparisonGridNames) == 0: raise ValueError('config section {} does not contain valid list ' 'of comparison grids'.format(sectionName)) # the variable mpasFieldName will be added to mpasClimatologyTask # along with the seasons. remapClimatologySubtask = RemapMpasClimatologySubtask( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName=fieldName, variableList=[mpasFieldName], comparisonGridNames=comparisonGridNames, seasons=seasons, iselValues=iselValues) if controlConfig is None: if climStartYear < 1925: period = 'pre-industrial' else: period = 'present-day' refTitleLabel = \ 'Observations (Hadley/OI, {} {:04d}-{:04d})'.format( period, climStartYear, climEndYear) observationsDirectory = build_obs_path( config, 'ocean', '{}Subdirectory'.format(fieldName)) obsFileName = \ "{}/MODEL.SST.HAD187001-198110.OI198111-201203_" \ "20180710.nc".format(observationsDirectory) refFieldName = 'sst' outFileLabel = 'sstHADOI' galleryName = 'Observations: Hadley-NOAA-OI' remapObservationsSubtask = RemapObservedSSTClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, outFilePrefix=refFieldName, comparisonGridNames=comparisonGridNames) self.add_subtask(remapObservationsSubtask) diffTitleLabel = 'Model - Observations' else: remapObservationsSubtask = None controlRunName = controlConfig.get('runs', 'mainRunName') galleryName = None refTitleLabel = 'Control: {}'.format(controlRunName) refFieldName = mpasFieldName outFileLabel = 'sst' diffTitleLabel = 'Main - Control' for comparisonGridName in comparisonGridNames: for season in seasons: # make a new subtask for this season and comparison grid subtask = PlotClimatologyMapSubtask( self, season, comparisonGridName, remapClimatologySubtask, remapObservationsSubtask, controlConfig=controlConfig) subtask.set_plot_info( outFileLabel=outFileLabel, fieldNameInTitle='SST', mpasFieldName=mpasFieldName, refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'$^o$C', imageCaption='Mean Sea Surface Temperature', galleryGroup='Sea Surface Temperature', groupSubtitle=None, groupLink='sst', galleryName=galleryName) self.add_subtask(subtask)
def __init__(self, config, mpasClimatologyTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Xylar Asay-Davis fields = \ [{'prefix': 'temperature', 'mpas': '******', 'units': r'$\degree$C', 'obs': 'botTheta', 'title': 'Potential Temperature'}, {'prefix': 'salinity', 'mpas': '******', 'units': r'PSU', 'obs': 'botSalinity', 'title': 'Salinity'}, {'prefix': 'potentialDensity', 'mpas': '******', 'units': r'kg m$^{-3}$', 'obs': 'botPotentialDensity', 'title': 'Potential Density'}] tags = ['climatology', 'horizontalMap', 'antarctic'] \ + [field['prefix'] for field in fields] # call the constructor from the base class (AnalysisTask) super(ClimatologyMapSchmidtko, self).__init__(config=config, taskName='climatologyMapSchmidtko', componentName='ocean', tags=tags) sectionName = self.taskName # read in what seasons we want to plot seasons = config.getExpression(sectionName, 'seasons') if len(seasons) == 0: raise ValueError('config section {} does not contain valid list ' 'of seasons'.format(sectionName)) comparisonGridNames = config.getExpression(sectionName, 'comparisonGrids') if len(comparisonGridNames) == 0: raise ValueError('config section {} does not contain valid list ' 'of comparison grids'.format(sectionName)) observationsDirectory = build_obs_path(config, 'ocean', 'schmidtkoSubdirectory') obsFileName = '{}/Schmidtko_et_al_2014_bottom_PT_S_PD_' \ '6000.0x6000.0km_10.0km_Antarctic_stereo.nc' \ ''.format(observationsDirectory) # the variable 'timeMonthly_avg_landIceFreshwaterFlux' will be added to # mpasClimatologyTask along with the seasons. remapClimatologySubtask = RemapDepthSlicesSubtask( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName='schmidtko', variableList=[field['mpas'] for field in fields], seasons=seasons, depths=['bot'], comparisonGridNames=comparisonGridNames) if controlConfig is None: refTitleLabel = 'Observations: Schmidtko et al. (2014)' diffTitleLabel = 'Model - Observations' groupSubtitle = refTitleLabel else: controlRunName = controlConfig.get('runs', 'mainRunName') refTitleLabel = 'Control: {}'.format(controlRunName) diffTitleLabel = 'Main - Control' groupSubtitle = None for field in fields: fieldPrefix = field['prefix'] upperFieldPrefix = fieldPrefix[0].upper() + fieldPrefix[1:] if controlConfig is None: refFieldName = field['obs'] outFileLabel = '{}Schmidtko'.format(fieldPrefix) remapObservationsSubtask = RemapSchmidtko( parentTask=self, seasons=seasons, fileName=obsFileName, outFilePrefix='{}Schmidtko'.format(fieldPrefix), fieldName=refFieldName, comparisonGridNames=comparisonGridNames, subtaskName='remapObservations{}'.format(upperFieldPrefix)) self.add_subtask(remapObservationsSubtask) else: remapObservationsSubtask = None refFieldName = field['mpas'] outFileLabel = '{}Bottom'.format(fieldPrefix) diffTitleLabel = 'Main - Control' for comparisonGridName in comparisonGridNames: for season in seasons: subtask = PlotClimatologyMapSubtask( parentTask=self, season=season, comparisonGridName=comparisonGridName, remapMpasClimatologySubtask=remapClimatologySubtask, remapObsClimatologySubtask=remapObservationsSubtask, controlConfig=controlConfig, depth='bot', subtaskName='plot{}_{}_{}'.format( upperFieldPrefix, season, comparisonGridName)) subtask.set_plot_info( outFileLabel=outFileLabel, fieldNameInTitle=field['title'], mpasFieldName=field['mpas'], refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=field['units'], imageCaption=field['title'], galleryGroup='Seafloor Maps', groupSubtitle=groupSubtitle, groupLink='seafloor', galleryName=field['title'], configSectionName='climatologyMapSchmidtko{}'.format( upperFieldPrefix)) self.add_subtask(subtask)
def setup_and_check(self): # {{{ ''' Perform steps to set up the analysis and check for errors in the setup. ''' # Authors # ------- # Mark Petersen, Milena Veneziani, Xylar Asay-Davis # first, call setup_and_check from the base class (AnalysisTask), # which will perform some common setup, including storing: # self.runDirectory , self.historyDirectory, self.plotsDirectory, # self.namelist, self.runStreams, self.historyStreams, # self.calendar super(MeridionalHeatTransport, self).setup_and_check() self.startYear = self.mpasClimatologyTask.startYear self.startDate = self.mpasClimatologyTask.startDate self.endYear = self.mpasClimatologyTask.endYear self.endDate = self.mpasClimatologyTask.endDate config = self.config self.check_analysis_enabled( analysisOptionName='config_am_meridionalheattransport_enable', raiseException=True) self.sectionName = 'meridionalHeatTransport' # Read in obs file information compareWithObs = config.getboolean(self.sectionName, 'compareWithObservations') self.observationsFile = None if compareWithObs: observationsDirectory = build_obs_path(config, 'ocean', 'mhtSubdirectory') observationsFile = config.get(self.sectionName, 'observationData') observationsFile = '{}/{}'.format(observationsDirectory, observationsFile) if os.path.exists(observationsFile): self.observationsFile = observationsFile else: print('Warning: No MHT observations file found: skip plotting ' 'obs') mainRunName = self.config.get('runs', 'mainRunName') variableList = [ 'timeMonthly_avg_meridionalHeatTransportLat', 'timeMonthly_avg_meridionalHeatTransportLatZ' ] self.mpasClimatologyTask.add_variables(variableList=variableList, seasons=['ANN']) self.xmlFileNames = [] self.filePrefixes = {} prefixes = ['mht'] if config.getboolean(self.sectionName, 'plotVerticalSection'): prefixes.append('mhtZ') for prefix in prefixes: filePrefix = '{}_{}_years{:04d}-{:04d}'.format( prefix, mainRunName, self.startYear, self.endYear) self.xmlFileNames.append('{}/{}.xml'.format( self.plotsDirectory, filePrefix)) self.filePrefixes[prefix] = filePrefix
def __init__(self, config, mpasClimatologyTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Milena Veneziani fields = \ [{'prefix': 'temperature', 'mpas': '******', 'units': r'$\degree$C', 'titleName': 'Potential Temperature', 'obsFieldName': 't_an'}, {'prefix': 'salinity', 'mpas': '******', 'units': r'PSU', 'titleName': 'Salinity', 'obsFieldName': 's_an'}] tags = ['climatology', 'horizontalMap', 'woa', 'publicObs'] + \ [field['prefix'] for field in fields] # call the constructor from the base class (AnalysisTask) super(ClimatologyMapWoa, self).__init__(config=config, taskName='climatologyMapWoa', componentName='ocean', tags=tags) sectionName = self.taskName fieldList = config.getExpression(sectionName, 'fieldList') fields = [field for field in fields if field['prefix'] in fieldList] # read in what seasons we want to plot seasons = config.getExpression(sectionName, 'seasons') if len(seasons) == 0: raise ValueError('config section {} does not contain valid list ' 'of seasons'.format(sectionName)) comparisonGridNames = config.getExpression(sectionName, 'comparisonGrids') if len(comparisonGridNames) == 0: raise ValueError('config section {} does not contain valid list ' 'of comparison grids'.format(sectionName)) depths = config.getExpression(sectionName, 'depths') if len(depths) == 0: raise ValueError('config section {} does not contain valid ' 'list of depths'.format(sectionName)) variableList = [field['mpas'] for field in fields] shallowVsDeepColormapDepth = config.getfloat( sectionName, 'shallowVsDeepColormapDepth') shallow = [] for depth in depths: if depth == 'top': shallow.append(True) elif depth == 'bot': shallow.append(False) else: shallow.append(depth >= shallowVsDeepColormapDepth) remapMpasSubtask = RemapDepthSlicesSubtask( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName='WOA', variableList=variableList, seasons=seasons, depths=depths, comparisonGridNames=comparisonGridNames, iselValues=None) remapAnnObsSubtask = None remapMonObsSubtask = None if controlConfig is None: # Since we have a WOA18 annual climatology file and # another file containing the 12 WOA18 monthly climatologies, # do the remapping for each season separately observationsDirectory = build_obs_path(config, 'ocean', 'woa18Subdirectory') refFieldNames = [field['obsFieldName'] for field in fields] if 'ANN' in seasons: obsFileName = \ '{}/woa18_decav_04_TS_ann_20190829.nc'.format( observationsDirectory) remapAnnObsSubtask = RemapWoaClimatology( parentTask=self, seasons=['ANN'], fileName=obsFileName, outFilePrefix='woa18_ann', fieldNames=refFieldNames, depths=depths, comparisonGridNames=comparisonGridNames, subtaskName='remapObservationsAnn') self.add_subtask(remapAnnObsSubtask) seasonsMinusAnn = list(seasons) if 'ANN' in seasonsMinusAnn: seasonsMinusAnn.remove('ANN') if len(seasonsMinusAnn) > 0: obsFileName = \ '{}/woa18_decav_04_TS_mon_20190829.nc'.format( observationsDirectory) remapMonObsSubtask = RemapWoaClimatology( parentTask=self, seasons=seasonsMinusAnn, fileName=obsFileName, outFilePrefix='woa18_mon', fieldNames=refFieldNames, depths=depths, comparisonGridNames=comparisonGridNames, subtaskName='remapObservationsMon') self.add_subtask(remapMonObsSubtask) for field in fields: fieldPrefix = field['prefix'] upperFieldPrefix = fieldPrefix[0].upper() + fieldPrefix[1:] sectionName = '{}{}'.format(self.taskName, upperFieldPrefix) if controlConfig is None: refTitleLabel = 'WOA18 Climatology' refFieldName = field['obsFieldName'] outFileLabel = '{}WOA18'.format(fieldPrefix) galleryName = 'WOA18 Climatology' diffTitleLabel = 'Model - Climatology' else: controlRunName = controlConfig.get('runs', 'mainRunName') galleryName = 'Control: {}'.format(controlRunName) refTitleLabel = galleryName refFieldName = field['mpas'] outFileLabel = '{}WOA18'.format(fieldPrefix) diffTitleLabel = 'Main - Control' for comparisonGridName in comparisonGridNames: for depthIndex, depth in enumerate(depths): for season in seasons: if season == 'ANN': remapObsSubtask = remapAnnObsSubtask else: remapObsSubtask = remapMonObsSubtask subtaskName = 'plot{}_{}_{}_depth_{}'.format( upperFieldPrefix, season, comparisonGridName, depth) subtask = PlotClimatologyMapSubtask( parentTask=self, season=season, comparisonGridName=comparisonGridName, remapMpasClimatologySubtask=remapMpasSubtask, remapObsClimatologySubtask=remapObsSubtask, controlConfig=controlConfig, depth=depth, subtaskName=subtaskName) configSectionName = 'climatologyMapWoa{}'.format( upperFieldPrefix) # if available, use a separate color map for shallow # and deep if depth is not None: if shallow[depthIndex]: suffix = 'Shallow' else: suffix = 'Deep' testSectionName = '{}{}'.format( configSectionName, suffix) if config.has_section(testSectionName): configSectionName = testSectionName subtask.set_plot_info( outFileLabel=outFileLabel, fieldNameInTitle=field['titleName'], mpasFieldName=field['mpas'], refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=field['units'], imageCaption=field['titleName'], galleryGroup=field['titleName'], groupSubtitle=None, groupLink='{}_woa'.format(fieldPrefix), galleryName=galleryName, configSectionName=configSectionName) self.add_subtask(subtask)
def __init__(self, config, mpasClimatologyTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Xylar Asay-Davis, Kevin Rosa fieldName = 'eke' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapEKE, self).__init__( config=config, taskName='climatologyMapEKE', componentName='ocean', tags=['climatology', 'horizontalMap', fieldName, 'publicObs']) mpasFieldName = 'eke' iselValues = {'nVertLevels': 0} sectionName = self.taskName # read in what seasons we want to plot seasons = config.getExpression(sectionName, 'seasons') # EKE observations are annual climatology so only accept annual # climatology **should move this to setup_and_check() if seasons != ['ANN']: raise ValueError('config section {} does not contain valid list ' 'of seasons. For EKE, may only request annual ' 'climatology'.format(sectionName)) comparisonGridNames = config.getExpression(sectionName, 'comparisonGrids') if len(comparisonGridNames) == 0: raise ValueError('config section {} does not contain valid list ' 'of comparison grids'.format(sectionName)) # the variables in variableList will be added to mpasClimatologyTask # along with the seasons. variableList = ['timeMonthly_avg_velocityZonal', 'timeMonthly_avg_velocityMeridional', 'timeMonthly_avg_velocityZonalSquared', 'timeMonthly_avg_velocityMeridionalSquared'] remapClimatologySubtask = RemapMpasEKEClimatology( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName=fieldName, variableList=variableList, comparisonGridNames=comparisonGridNames, seasons=seasons, iselValues=iselValues) # to compare to observations: if controlConfig is None: refTitleLabel = \ 'Observations (Surface EKE from Drifter Data)' observationsDirectory = build_obs_path( config, 'ocean', '{}Subdirectory'.format(fieldName)) obsFileName = \ "{}/drifter_variance_20180804.nc".format( observationsDirectory) refFieldName = 'eke' outFileLabel = 'ekeDRIFTER' galleryName = 'Observations: EKE from Drifters' remapObservationsSubtask = RemapObservedEKEClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, outFilePrefix=refFieldName, comparisonGridNames=comparisonGridNames) self.add_subtask(remapObservationsSubtask) diffTitleLabel = 'Model - Observations' # compare with previous run: else: remapObservationsSubtask = None controlRunName = controlConfig.get('runs', 'mainRunName') galleryName = None refTitleLabel = 'Control: {}'.format(controlRunName) refFieldName = mpasFieldName outFileLabel = 'eke' diffTitleLabel = 'Main - Control' for comparisonGridName in comparisonGridNames: for season in seasons: # make a new subtask for this season and comparison grid subtask = PlotClimatologyMapSubtask( self, season, comparisonGridName, remapClimatologySubtask, remapObservationsSubtask, controlConfig=controlConfig) subtask.set_plot_info( outFileLabel=outFileLabel, fieldNameInTitle='EKE', mpasFieldName=mpasFieldName, refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'cm$^2$/s$^2$', imageCaption='Mean Surface Eddy Kinetic Energy', galleryGroup='Eddy Kinetic Energy', groupSubtitle=None, groupLink='eke', galleryName=galleryName) self.add_subtask(subtask)
def __init__(self, config, mpasClimatologyTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Luke Van Roekel, Xylar Asay-Davis fieldName = 'temperatureArgo' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapArgoTemperature, self).__init__(config=config, taskName='climatologyMapArgoTemperature', componentName='ocean', tags=[ 'climatology', 'horizontalMap', 'argo', 'temperature', 'publicObs' ]) sectionName = self.taskName mpasFieldName = 'timeMonthly_avg_activeTracers_temperature' iselValues = None # read in what seasons we want to plot seasons = config.getExpression(sectionName, 'seasons') if len(seasons) == 0: raise ValueError('config section {} does not contain valid list ' 'of seasons'.format(sectionName)) comparisonGridNames = config.getExpression(sectionName, 'comparisonGrids') if len(comparisonGridNames) == 0: raise ValueError('config section {} does not contain valid list ' 'of comparison grids'.format(sectionName)) depths = config.getExpression(sectionName, 'depths') if len(depths) == 0: raise ValueError('config section {} does not contain valid ' 'list of depths'.format(sectionName)) # the variable 'timeMonthly_avg_landIceFreshwaterFlux' will be added to # mpasClimatologyTask along with the seasons. remapClimatologySubtask = RemapDepthSlicesSubtask( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName=fieldName, variableList=[mpasFieldName], seasons=seasons, depths=depths, comparisonGridNames=comparisonGridNames, iselValues=iselValues) if controlConfig is None: refTitleLabel = 'Roemmich-Gilson Argo Climatology: Potential ' \ 'Temperature' observationsDirectory = build_obs_path(config, 'ocean', 'argoSubdirectory') obsFileName = \ '{}/ArgoClimatology_TS_20180710.nc'.format( observationsDirectory) refFieldName = 'theta' outFileLabel = 'tempArgo' galleryName = 'Roemmich-Gilson Climatology: Argo' diffTitleLabel = 'Model - Argo' remapObservationsSubtask = RemapArgoClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, outFilePrefix='{}Argo'.format(refFieldName), fieldName=refFieldName, depths=depths, comparisonGridNames=comparisonGridNames) self.add_subtask(remapObservationsSubtask) else: remapObservationsSubtask = None controlRunName = controlConfig.get('runs', 'mainRunName') galleryName = 'Control: {}'.format(controlRunName) refTitleLabel = galleryName refFieldName = mpasFieldName outFileLabel = 'temp' diffTitleLabel = 'Main - Control' for comparisonGridName in comparisonGridNames: for season in seasons: for depth in depths: subtask = PlotClimatologyMapSubtask( parentTask=self, season=season, comparisonGridName=comparisonGridName, remapMpasClimatologySubtask=remapClimatologySubtask, remapObsClimatologySubtask=remapObservationsSubtask, controlConfig=controlConfig, depth=depth) subtask.set_plot_info( outFileLabel=outFileLabel, fieldNameInTitle='Potential Temperature', mpasFieldName=mpasFieldName, refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'$\degree$C', imageCaption='Model potential temperature compared ' 'with Argo observations', galleryGroup='Argo Potential Temperature', groupSubtitle=None, groupLink='tempArgo', galleryName=galleryName) self.add_subtask(subtask)
def run_task(self): # {{{ """ Plots time-series output of properties in an ocean region. """ # Authors # ------- # Xylar Asay-Davis if os.path.exists(self.fileName): return config = self.config obsDict = self.obsDict season = self.season obsFileName = build_obs_path( config, component=self.componentName, relativePath=obsDict['preprocessedFileTemplate'].format(season)) if os.path.exists(obsFileName): # we already pre-processed this data so no need to redo it! os.symlink(obsFileName, self.fileName) return with dask.config.set(schedular='threads', pool=ThreadPool(self.daskThreads)): self.logger.info("\n computing T S climatogy for {}...".format( self.obsName)) chunk = {obsDict['tVar']: 6} TVarName = obsDict['TVar'] SVarName = obsDict['SVar'] zVarName = obsDict['zVar'] lonVarName = obsDict['lonVar'] latVarName = obsDict['latVar'] volVarName = obsDict['volVar'] obsFileName = build_obs_path(config, component=self.componentName, relativePath=obsDict['TFileName']) self.logger.info(' Reading from {}...'.format(obsFileName)) ds = xarray.open_dataset(obsFileName, chunks=chunk) if obsDict['SFileName'] != obsDict['TFileName']: obsFileName = build_obs_path(config, component=self.componentName, relativePath=obsDict['SFileName']) self.logger.info(' Reading from {}...'.format(obsFileName)) dsS = xarray.open_dataset(obsFileName, chunks=chunk) ds[SVarName] = dsS[SVarName] if obsDict['volFileName'] is None: # compute volume from lat, lon, depth bounds self.logger.info(' Computing volume...'.format(obsFileName)) latBndsName = ds[latVarName].attrs['bounds'] lonBndsName = ds[lonVarName].attrs['bounds'] zBndsName = ds[zVarName].attrs['bounds'] latBnds = ds[latBndsName] lonBnds = ds[lonBndsName] zBnds = ds[zBndsName] dLat = numpy.deg2rad(latBnds[:, 1] - latBnds[:, 0]) dLon = numpy.deg2rad(lonBnds[:, 1] - lonBnds[:, 0]) lat = numpy.deg2rad(ds[latVarName]) dz = zBnds[:, 1] - zBnds[:, 0] radius = 6378137.0 area = radius**2 * numpy.cos(lat) * dLat * dLon ds[volVarName] = dz * area elif obsDict['volFileName'] != obsDict['TFileName']: obsFileName = build_obs_path( config, component=self.componentName, relativePath=obsDict['volFileName']) self.logger.info(' Reading from {}...'.format(obsFileName)) dsVol = xarray.open_dataset(obsFileName) ds[volVarName] = dsVol[volVarName] temp_file_name = self._get_file_name(obsDict, suffix='_combined') temp_files = [temp_file_name] self.logger.info(' computing the dataset') ds.compute() self.logger.info( ' writing temp file {}...'.format(temp_file_name)) write_netcdf(ds, temp_file_name) chunk = {obsDict['latVar']: 400, obsDict['lonVar']: 400} self.logger.info( ' Reading back from {}...'.format(temp_file_name)) ds = xarray.open_dataset(temp_file_name, chunks=chunk) if obsDict['tVar'] in ds.dims: if obsDict['tVar'] != 'Time': if obsDict['tVar'] == 'month': ds = ds.rename({obsDict['tVar']: 'Time'}) ds.coords['month'] = ds['Time'] else: ds = ds.rename({obsDict['tVar']: 'Time'}) if 'year' not in ds: ds.coords['year'] = numpy.ones(ds.sizes['Time'], int) monthValues = constants.monthDictionary[season] self.logger.info(' Computing climatology...') ds = compute_climatology(ds, monthValues, maskVaries=True) temp_file_name = self._get_file_name(obsDict, suffix='_clim') temp_files.append(temp_file_name) self.logger.info(' computing the dataset') ds.compute() self.logger.info( ' writing temp file {}...'.format(temp_file_name)) write_netcdf(ds, temp_file_name) self.logger.info( ' Reading back from {}...'.format(temp_file_name)) ds = xarray.open_dataset(temp_file_name, chunks=chunk) self.logger.info(' Broadcasting z coordinate...') if 'positive' in ds[zVarName].attrs and \ ds[zVarName].attrs['positive'] == 'down': attrs = ds[zVarName].attrs ds[zVarName] = -ds[zVarName] ds[zVarName].attrs = attrs ds[zVarName].attrs['positive'] = 'up' T, S, z = xarray.broadcast(ds[TVarName], ds[SVarName], ds[zVarName]) ds['zBroadcast'] = z self.logger.info(' computing the dataset') ds.compute() self.logger.info(' writing {}...'.format(self.fileName)) write_netcdf(ds, self.fileName) for file_name in temp_files: self.logger.info(' Deleting temp file {}'.format(file_name)) os.remove(file_name) self.logger.info(' Done!')
def __init__(self, config, mpasClimatologyTask, controlConfig=None): # {{{ ''' Construct the analysis task and adds it as a subtask of the ``parentTask``. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted as a transect controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) ''' # Authors # ------- # Xylar Asay-Davis tags = ['climatology', 'transect', 'woce'] # call the constructor from the base class (AnalysisTask) super(WoceTransects, self).__init__(config=config, taskName='woceTransects', componentName='ocean', tags=tags) sectionName = self.taskName seasons = config.getExpression(sectionName, 'seasons') horizontalResolution = config.get(sectionName, 'horizontalResolution') verticalComparisonGridName = config.get(sectionName, 'verticalComparisonGridName') if verticalComparisonGridName in ['mpas', 'obs']: verticalComparisonGrid = None else: verticalComparisonGrid = config.getExpression( sectionName, 'verticalComparisonGrid', usenumpyfunc=True) horizontalBounds = config.getExpression(sectionName, 'horizontalBounds') observationsDirectory = build_obs_path(config, 'ocean', 'woceSubdirectory') obsFileNames = OrderedDict() obsFileNames['WOCE_A21'] = \ 'WOCE_A21_Drake_Passage_20181126.nc' obsFileNames['WOCE_A23'] = \ 'WOCE_A23_South_Atlantic_20181126.nc' obsFileNames['WOCE_A12'] = \ 'WOCE_A12_Prime_Meridian_20181126.nc' for transectName in obsFileNames: fileName = '{}/{}'.format(observationsDirectory, obsFileNames[transectName]) obsFileNames[transectName] = fileName fields = \ {'temperature': {'mpas': '******', 'obs': 'potentialTemperature', 'titleName': 'Potential Temperature', 'units': r'$\degree$C'}, 'salinity': {'mpas': '******', 'obs': 'salinity', 'titleName': 'Salinity', 'units': r'PSU'}, 'potentialDensity': {'mpas': '******', 'obs': 'potentialDensity', 'titleName': 'Potential Density', 'units': r'kg m$^{-3}$'}} transectCollectionName = 'WOCE_transects' if horizontalResolution != 'obs': transectCollectionName = '{}_{}km'.format(transectCollectionName, horizontalResolution) transectsObservations = TransectsObservations(config, obsFileNames, horizontalResolution, transectCollectionName) computeTransectsSubtask = ComputeTransectsSubtask( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName='WOCE', transectCollectionName=transectCollectionName, variableList=[field['mpas'] for field in fields.values()], seasons=seasons, obsDatasets=transectsObservations, verticalComparisonGridName=verticalComparisonGridName, verticalComparisonGrid=verticalComparisonGrid) plotObs = controlConfig is None if plotObs: refTitleLabel = 'Observations (WOCE)' diffTitleLabel = 'Model - Observations' else: controlRunName = controlConfig.get('runs', 'mainRunName') refTitleLabel = 'Control: {}'.format(controlRunName) diffTitleLabel = 'Main - Control' fieldNameDict = { 'temperature': 'temperatureTransect', 'salinity': 'salinityTransect', 'potentialDensity': 'potentialDensityTransect' } for fieldName in fields: for transectName in obsFileNames: for season in seasons: outFileLabel = fieldNameDict[fieldName] if plotObs: refFieldName = fields[fieldName]['obs'] else: refFieldName = fields[fieldName]['mpas'] fieldNameUpper = fieldName[0].upper() + fieldName[1:] titleName = fields[fieldName]['titleName'] fieldNameInTytle = '{} from {}'.format( titleName, transectName.replace('_', ' ')) # make a new subtask for this season and comparison grid subtask = PlotTransectSubtask( self, season, transectName, fieldName, computeTransectsSubtask, plotObs, controlConfig, horizontalBounds[transectName]) subtask.set_plot_info( outFileLabel=outFileLabel, fieldNameInTitle=fieldNameInTytle, mpasFieldName=fields[fieldName]['mpas'], refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=fields[fieldName]['units'], imageCaption='{} {}'.format(fieldNameInTytle, season), galleryGroup='WOCE Transects', groupSubtitle=None, groupLink='woce', galleryName=titleName, configSectionName='woce{}Transects'.format( fieldNameUpper)) self.add_subtask(subtask)
def __init__(self, config, mpasClimatologyTask, regionMasksTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted regionMasksTask : ``ComputeRegionMasks`` A task for computing region masks controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Xylar Asay-Davis # first, call the constructor from the base class (AnalysisTask) super(RegionalTSDiagrams, self).__init__(config=config, taskName='regionalTSDiagrams', componentName='ocean', tags=['climatology', 'regions', 'publicObs']) self.run_after(mpasClimatologyTask) self.mpasClimatologyTask = mpasClimatologyTask regionGroups = config.getExpression(self.taskName, 'regionGroups') self.seasons = config.getExpression(self.taskName, 'seasons') obsDicts = { 'SOSE': { 'suffix': 'SOSE', 'gridName': 'SouthernOcean_0.167x0.167degree', 'gridFileName': 'SOSE/SOSE_2005-2010_monthly_pot_temp_' 'SouthernOcean_0.167x0.167degree_20180710.nc', 'TFileName': 'SOSE/SOSE_2005-2010_monthly_pot_temp_' 'SouthernOcean_0.167x0.167degree_20180710.nc', 'SFileName': 'SOSE/SOSE_2005-2010_monthly_salinity_' 'SouthernOcean_0.167x0.167degree_20180710.nc', 'volFileName': 'SOSE/SOSE_volume_' 'SouthernOcean_0.167x0.167degree_20190815.nc', 'preprocessedFileTemplate': 'SOSE/SOSE_{}_T_S_z_vol_' 'SouthernOcean_0.167x0.167degree_20200514.nc', 'lonVar': 'lon', 'latVar': 'lat', 'TVar': 'theta', 'SVar': 'salinity', 'volVar': 'volume', 'zVar': 'z', 'tVar': 'Time' }, 'WOA18': { 'suffix': 'WOA18', 'gridName': 'Global_0.25x0.25degree', 'gridFileName': 'WOA18/woa18_decav_04_TS_mon_20190829.nc', 'TFileName': 'WOA18/woa18_decav_04_TS_mon_20190829.nc', 'SFileName': 'WOA18/woa18_decav_04_TS_mon_20190829.nc', 'volFileName': None, 'preprocessedFileTemplate': 'WOA18/woa18_{}_T_S_z_vol_20200514.nc', 'lonVar': 'lon', 'latVar': 'lat', 'TVar': 't_an', 'SVar': 's_an', 'volVar': 'volume', 'zVar': 'depth', 'tVar': 'month' } } allObsUsed = [] for regionGroup in regionGroups: sectionSuffix = regionGroup[0].upper() + \ regionGroup[1:].replace(' ', '') sectionName = 'TSDiagramsFor{}'.format(sectionSuffix) obsList = config.getExpression(sectionName, 'obs') allObsUsed = allObsUsed + obsList allObsUsed = set(allObsUsed) for obsName in allObsUsed: obsDict = obsDicts[obsName] obsDicts[obsName]['climatologyTask'] = {} for season in self.seasons: climatologySubtask = ComputeObsTSClimatology(self, obsName, obsDict, season=season) obsDicts[obsName]['climatologyTask'][season] = \ climatologySubtask self.add_subtask(climatologySubtask) for regionGroup in regionGroups: sectionSuffix = regionGroup[0].upper() + \ regionGroup[1:].replace(' ', '') sectionName = 'TSDiagramsFor{}'.format(sectionSuffix) regionMaskSuffix = config.getExpression(sectionName, 'regionMaskSuffix') regionMaskFile = get_region_mask( config, '{}.geojson'.format(regionMaskSuffix)) regionNames = config.getExpression(sectionName, 'regionNames') if 'all' in regionNames and os.path.exists(regionMaskFile): regionNames = get_feature_list(regionMaskFile) mpasMasksSubtask = regionMasksTask.add_mask_subtask( regionMaskFile, outFileSuffix=regionMaskSuffix) obsList = config.getExpression(sectionName, 'obs') groupObsDicts = {} for obsName in obsList: localObsDict = dict(obsDicts[obsName]) obsFileName = build_obs_path( config, component=self.componentName, relativePath=localObsDict['gridFileName']) obsMasksSubtask = regionMasksTask.add_mask_subtask( regionMaskFile, outFileSuffix=regionMaskSuffix, obsFileName=obsFileName, lonVar=localObsDict['lonVar'], latVar=localObsDict['latVar'], meshName=localObsDict['gridName']) obsDicts[obsName]['maskTask'] = obsMasksSubtask localObsDict['maskTask'] = obsMasksSubtask groupObsDicts[obsName] = localObsDict for regionName in regionNames: fullSuffix = sectionSuffix + '_' + \ regionName[0].lower() + \ regionName[1:].replace(' ', '') for season in self.seasons: computeRegionSubtask = ComputeRegionTSSubtask( self, regionGroup, regionName, controlConfig, sectionName, fullSuffix, mpasClimatologyTask, mpasMasksSubtask, groupObsDicts, season) computeRegionSubtask.run_after(mpasMasksSubtask) for obsName in obsList: task = \ obsDicts[obsName]['climatologyTask'][season] computeRegionSubtask.run_after(task) task = obsDicts[obsName]['maskTask'] computeRegionSubtask.run_after(task) self.add_subtask(computeRegionSubtask) plotRegionSubtask = PlotRegionTSDiagramSubtask( self, regionGroup, regionName, controlConfig, sectionName, fullSuffix, mpasClimatologyTask, mpasMasksSubtask, groupObsDicts, season) plotRegionSubtask.run_after(computeRegionSubtask) self.add_subtask(plotRegionSubtask)
def run_task(self): # {{{ """ Plots time-series output of Antarctic sub-ice-shelf melt rates. """ # Authors # ------- # Xylar Asay-Davis, Stephen Price self.logger.info("\nPlotting Antarctic melt rate time series for " "{}...".format(self.iceShelf)) self.logger.info(' Load melt rate data...') config = self.config calendar = self.calendar iceShelfMasksFile = self.iceShelfMasksFile fcAll = read_feature_collection(iceShelfMasksFile) fc = FeatureCollection() for feature in fcAll.features: if feature['properties']['name'] == self.iceShelf: fc.add_feature(feature) break totalMeltFlux, meltRates = self._load_ice_shelf_fluxes(config) plotControl = self.controlConfig is not None if plotControl: controlRunName = self.controlConfig.get('runs', 'mainRunName') refTotalMeltFlux, refMeltRates = \ self._load_ice_shelf_fluxes(self.controlConfig) # Load observations from multiple files and put in dictionary based # on shelf keyname observationsDirectory = build_obs_path(config, 'ocean', 'meltSubdirectory') obsFileNameDict = {'Rignot et al. (2013)': 'Rignot_2013_melt_rates_20200623.csv', 'Rignot et al. (2013) SS': 'Rignot_2013_melt_rates_SS_20200623.csv'} obsDict = {} # dict for storing dict of obs data for obsName in obsFileNameDict: obsFileName = '{}/{}'.format(observationsDirectory, obsFileNameDict[obsName]) obsDict[obsName] = {} obsFile = csv.reader(open(obsFileName, 'rU')) next(obsFile, None) # skip the header line for line in obsFile: # some later useful values commented out shelfName = line[0] if shelfName != self.iceShelf: continue # surveyArea = line[1] meltFlux = float(line[2]) meltFluxUncertainty = float(line[3]) meltRate = float(line[4]) meltRateUncertainty = float(line[5]) # actualArea = float( line[6] ) # actual area here is in sq km # build dict of obs. keyed to filename description # (which will be used for plotting) obsDict[obsName] = { 'meltFlux': meltFlux, 'meltFluxUncertainty': meltFluxUncertainty, 'meltRate': meltRate, 'meltRateUncertainty': meltRateUncertainty} break # If areas from obs file used need to be converted from sq km to sq m mainRunName = config.get('runs', 'mainRunName') movingAverageMonths = config.getint('timeSeriesAntarcticMelt', 'movingAverageMonths') outputDirectory = build_config_full_path(config, 'output', 'timeseriesSubdirectory') make_directories(outputDirectory) self.logger.info(' Make plots...') # get obs melt flux and unc. for shelf (similar for rates) obsMeltFlux = [] obsMeltFluxUnc = [] obsMeltRate = [] obsMeltRateUnc = [] for obsName in obsDict: if len(obsDict[obsName]) > 0: obsMeltFlux.append( obsDict[obsName]['meltFlux']) obsMeltFluxUnc.append( obsDict[obsName]['meltFluxUncertainty']) obsMeltRate.append( obsDict[obsName]['meltRate']) obsMeltRateUnc.append( obsDict[obsName]['meltRateUncertainty']) else: # append NaN so this particular obs won't plot self.logger.warning('{} observations not available for ' '{}'.format(obsName, self.iceShelf)) obsMeltFlux.append(None) obsMeltFluxUnc.append(None) obsMeltRate.append(None) obsMeltRateUnc.append(None) title = self.iceShelf.replace('_', ' ') xLabel = 'Time (yr)' yLabel = 'Melt Flux (GT/yr)' timeSeries = totalMeltFlux.isel(nRegions=self.regionIndex) filePrefix = 'melt_flux_{}'.format(self.iceShelf.replace(' ', '_')) outFileName = '{}/{}.png'.format(self.plotsDirectory, filePrefix) fields = [timeSeries] lineColors = ['k'] lineWidths = [2.5] legendText = [mainRunName] if plotControl: fields.append(refTotalMeltFlux.isel(nRegions=self.regionIndex)) lineColors.append('r') lineWidths.append(1.2) legendText.append(controlRunName) fig = timeseries_analysis_plot(config, fields, calendar=calendar, title=title, xlabel=xLabel, ylabel=yLabel, movingAveragePoints=movingAverageMonths, lineColors=lineColors, lineWidths=lineWidths, legendText=legendText, obsMean=obsMeltFlux, obsUncertainty=obsMeltFluxUnc, obsLegend=list(obsDict.keys())) # do this before the inset because otherwise it moves the inset # and cartopy doesn't play too well with tight_layout anyway plt.tight_layout() add_inset(fig, fc, width=2.0, height=2.0) savefig(outFileName) caption = 'Running Mean of Total Melt Flux under Ice ' \ 'Shelves in the {} Region'.format(title) write_image_xml( config=config, filePrefix=filePrefix, componentName='Ocean', componentSubdirectory='ocean', galleryGroup='Antarctic Melt Time Series', groupLink='antmelttime', gallery='Total Melt Flux', thumbnailDescription=title, imageDescription=caption, imageCaption=caption) xLabel = 'Time (yr)' yLabel = 'Melt Rate (m/yr)' timeSeries = meltRates.isel(nRegions=self.regionIndex) filePrefix = 'melt_rate_{}'.format(self.iceShelf.replace(' ', '_')) outFileName = '{}/{}.png'.format(self.plotsDirectory, filePrefix) fields = [timeSeries] lineColors = ['k'] lineWidths = [2.5] legendText = [mainRunName] if plotControl: fields.append(refMeltRates.isel(nRegions=self.regionIndex)) lineColors.append('r') lineWidths.append(1.2) legendText.append(controlRunName) if config.has_option(self.taskName, 'firstYearXTicks'): firstYearXTicks = config.getint(self.taskName, 'firstYearXTicks') else: firstYearXTicks = None if config.has_option(self.taskName, 'yearStrideXTicks'): yearStrideXTicks = config.getint(self.taskName, 'yearStrideXTicks') else: yearStrideXTicks = None fig = timeseries_analysis_plot(config, fields, calendar=calendar, title=title, xlabel=xLabel, ylabel=yLabel, movingAveragePoints=movingAverageMonths, lineColors=lineColors, lineWidths=lineWidths, legendText=legendText, firstYearXTicks=firstYearXTicks, yearStrideXTicks=yearStrideXTicks, obsMean=obsMeltRate, obsUncertainty=obsMeltRateUnc, obsLegend=list(obsDict.keys())) # do this before the inset because otherwise it moves the inset # and cartopy doesn't play too well with tight_layout anyway plt.tight_layout() add_inset(fig, fc, width=2.0, height=2.0) savefig(outFileName) caption = 'Running Mean of Area-averaged Melt Rate under Ice ' \ 'Shelves in the {} Region'.format(title) write_image_xml( config=config, filePrefix=filePrefix, componentName='Ocean', componentSubdirectory='ocean', galleryGroup='Antarctic Melt Time Series', groupLink='antmelttime', gallery='Area-averaged Melt Rate', thumbnailDescription=title, imageDescription=caption, imageCaption=caption)
def combine_observations(self): # {{{ ''' Combine SOSE oservations into a single file ''' # Authors # ------- # Xylar Asay-Davis config = self.config longitudes = sorted( config.getExpression('soseTransects', 'longitudes', usenumpyfunc=True)) observationsDirectory = build_obs_path(config, 'ocean', 'soseSubdirectory') outObsDirectory = build_config_full_path( config=config, section='output', relativePathOption='climatologySubdirectory', relativePathSection='oceanObservations') make_directories(outObsDirectory) combinedFileName = '{}/{}.nc'.format(outObsDirectory, self.transectCollectionName) obsFileNames = OrderedDict() for lon in longitudes: transectName = 'lon_{}'.format(lon) obsFileNames[transectName] = combinedFileName self.obsFileNames = obsFileNames if os.path.exists(combinedFileName): return print('Preprocessing SOSE transect data...') minLat = config.getfloat('soseTransects', 'minLat') maxLat = config.getfloat('soseTransects', 'maxLat') dsObs = None for field in self.fields: prefix = field['obsFilePrefix'] fieldName = field['obsFieldName'] if prefix is None: continue print(' {}'.format(field['prefix'])) fileName = '{}/SOSE_2005-2010_monthly_{}_SouthernOcean' \ '_0.167x0.167degree_20180710.nc'.format( observationsDirectory, prefix) dsLocal = xr.open_dataset(fileName) lat = dsLocal.lat.values mask = numpy.logical_and(lat >= minLat, lat <= maxLat) indices = numpy.argwhere(mask) dsLocal = dsLocal.isel(lat=slice(indices[0][0], indices[-1][0])) dsLocal.load() if fieldName == 'zonalVel': # need to average in longitude nLon = dsLocal.sizes['lon'] lonIndicesP1 = numpy.mod(numpy.arange(nLon) + 1, nLon) dsLocal = 0.5 * (dsLocal + dsLocal.isel(lon=lonIndicesP1)) if fieldName == 'meridVel': # need to average in latitude nLat = dsLocal.sizes['lat'] latIndicesP1 = numpy.mod(numpy.arange(nLat) + 1, nLat) dsLocal = 0.5 * (dsLocal + dsLocal.isel(lat=latIndicesP1)) dsLocal = dsLocal.sel(lon=longitudes, method=str('nearest')) if dsObs is None: dsObs = dsLocal else: dsLocal['lon'] = dsObs.lon dsLocal['lat'] = dsObs.lat dsObs[fieldName] = dsLocal[fieldName] dsLocal.close() if 'zonalVel' in dsObs and 'meridVel' in dsObs: # compute the velocity magnitude print(' velMag') description = 'Monthly velocity magnitude climatologies ' \ 'from 2005-2010 average of the Southern Ocean ' \ 'State Estimate (SOSE)' dsObs['velMag'] = numpy.sqrt(dsObs.zonalVel**2 + dsObs.meridVel**2) dsObs.velMag.attrs['units'] = 'm s$^{-1}$' dsObs.velMag.attrs['description'] = description write_netcdf(dsObs, combinedFileName) print(' Done.')
def __init__(self, config, mpasClimatologyTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Xylar Asay-Davis fieldName = 'sss' # call the constructor from the base class (AnalysisTask) super(ClimatologyMapSSS, self).__init__( config=config, taskName='climatologyMapSSS', componentName='ocean', tags=['climatology', 'horizontalMap', fieldName, 'publicObs']) mpasFieldName = 'timeMonthly_avg_activeTracers_salinity' iselValues = {'nVertLevels': 0} sectionName = self.taskName # read in what seasons we want to plot seasons = config.getExpression(sectionName, 'seasons') if len(seasons) == 0: raise ValueError('config section {} does not contain valid list ' 'of seasons'.format(sectionName)) comparisonGridNames = config.getExpression(sectionName, 'comparisonGrids') if len(comparisonGridNames) == 0: raise ValueError('config section {} does not contain valid list ' 'of comparison grids'.format(sectionName)) # the variable self.mpasFieldName will be added to mpasClimatologyTask # along with the seasons. remapClimatologySubtask = RemapMpasClimatologySubtask( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName=fieldName, variableList=[mpasFieldName], comparisonGridNames=comparisonGridNames, seasons=seasons, iselValues=iselValues) if controlConfig is None: refTitleLabel = \ 'Observations (Aquarius, 2011-2014)' observationsDirectory = build_obs_path( config, 'ocean', '{}Subdirectory'.format(fieldName)) obsFileName = \ "{}/Aquarius_V3_SSS_Monthly_20180710.nc".format( observationsDirectory) refFieldName = 'sss' outFileLabel = 'sssAquarius' galleryName = 'Observations: Aquarius' remapObservationsSubtask = RemapObservedSSSClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, outFilePrefix=refFieldName, comparisonGridNames=comparisonGridNames) self.add_subtask(remapObservationsSubtask) diffTitleLabel = 'Model - Observations' else: remapObservationsSubtask = None controlRunName = controlConfig.get('runs', 'mainRunName') galleryName = None refTitleLabel = 'Control: {}'.format(controlRunName) refFieldName = mpasFieldName outFileLabel = 'sss' diffTitleLabel = 'Main - Control' for comparisonGridName in comparisonGridNames: for season in seasons: # make a new subtask for this season and comparison grid subtask = PlotClimatologyMapSubtask( self, season, comparisonGridName, remapClimatologySubtask, remapObservationsSubtask, controlConfig=controlConfig) subtask.set_plot_info( outFileLabel=outFileLabel, fieldNameInTitle='SSS', mpasFieldName=mpasFieldName, refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'PSU', imageCaption='Mean Sea Surface Salinity', galleryGroup='Sea Surface Salinity', groupSubtitle=None, groupLink='sss', galleryName=galleryName) self.add_subtask(subtask)
def __init__(self, config, mpasClimatologyTask, hemisphere, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted hemisphere : {'NH', 'SH'} The hemisphere to plot controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Darin Comeau, Xylar Asay-Davis taskName = 'climatologyMapIcebergConc{}'.format(hemisphere) fieldName = 'IcebergConc' tags = ['icebergs', 'climatology', 'horizontalMap', fieldName] if hemisphere == 'NH': tags = tags + ['arctic'] else: tags = tags + ['antarctic'] # call the constructor from the base class (AnalysisTask) super(ClimatologyMapIcebergConc, self).__init__(config=config, taskName=taskName, componentName='seaIce', tags=tags) mpasFieldName = 'timeMonthly_avg_bergAreaCell' iselValues = None sectionName = taskName if hemisphere == 'NH': hemisphereLong = 'Northern' else: hemisphereLong = 'Southern' # read in what seasons we want to plot seasons = config.getExpression(sectionName, 'seasons') if len(seasons) == 0: raise ValueError('config section {} does not contain valid list ' 'of seasons'.format(sectionName)) comparisonGridNames = config.getExpression(sectionName, 'comparisonGrids') if len(comparisonGridNames) == 0: raise ValueError('config section {} does not contain valid list ' 'of comparison grids'.format(sectionName)) # the variable self.mpasFieldName will be added to mpasClimatologyTask # along with the seasons. remapClimatologySubtask = RemapMpasClimatologySubtask( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName='{}{}'.format(fieldName, hemisphere), variableList=[mpasFieldName], comparisonGridNames=comparisonGridNames, seasons=seasons, iselValues=iselValues) if controlConfig is None: refTitleLabel = 'Observations (Altiberg)' galleryName = 'Observations: Altiberg' diffTitleLabel = 'Model - Observations' refFieldName = 'icebergConc' obsFileName = build_obs_path( config, 'iceberg', 'concentrationAltiberg{}'.format(hemisphere)) remapObservationsSubtask = RemapAltibergConcClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, outFilePrefix='{}{}'.format(refFieldName, hemisphere), comparisonGridNames=comparisonGridNames) self.add_subtask(remapObservationsSubtask) else: controlRunName = controlConfig.get('runs', 'mainRunName') galleryName = None refTitleLabel = 'Control: {}'.format(controlRunName) refFieldName = mpasFieldName diffTitleLabel = 'Main - Control' remapObservationsSubtask = None for season in seasons: for comparisonGridName in comparisonGridNames: imageDescription = \ '{} Climatology Map of {}-Hemisphere Iceberg ' \ 'Concentration.'.format(season, hemisphereLong) imageCaption = imageDescription galleryGroup = \ '{}-Hemisphere Iceberg Concentration'.format( hemisphereLong) # make a new subtask for this season and comparison grid subtask = PlotClimatologyMapSubtask(self, hemisphere, season, comparisonGridName, remapClimatologySubtask, remapObservationsSubtask, controlConfig) subtask.set_plot_info( outFileLabel='bergconc{}'.format(hemisphere), fieldNameInTitle='Iceberg concentration', mpasFieldName=mpasFieldName, refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=r'fraction', imageDescription=imageDescription, imageCaption=imageCaption, galleryGroup=galleryGroup, groupSubtitle=None, groupLink='{}_conc'.format(hemisphere.lower()), galleryName=galleryName, maskValue=None) self.add_subtask(subtask)
def __init__(self, config, mpasClimatologyTask, controlConfig=None): # {{{ """ Construct the analysis task. Parameters ---------- config : ``MpasAnalysisConfigParser`` Configuration options mpasClimatologyTask : ``MpasClimatologyTask`` The task that produced the climatology to be remapped and plotted controlConfig : ``MpasAnalysisConfigParser``, optional Configuration options for a control run (if any) """ # Authors # ------- # Xylar Asay-Davis fields = \ [{'prefix': 'temperature', 'mpas': '******', 'units': r'$\degree$C', 'titleName': 'Potential Temperature', '3D': True, 'obsFilePrefix': 'pot_temp', 'obsFieldName': 'theta', 'obsBotFieldName': 'botTheta'}, {'prefix': 'salinity', 'mpas': '******', 'units': r'PSU', 'titleName': 'Salinity', '3D': True, 'obsFilePrefix': 'salinity', 'obsFieldName': 'salinity', 'obsBotFieldName': 'botSalinity'}, {'prefix': 'potentialDensity', 'mpas': '******', 'units': r'kg m$^{-3}$', 'titleName': 'Potential Density', '3D': True, 'obsFilePrefix': 'pot_den', 'obsFieldName': 'potentialDensity', 'obsBotFieldName': 'botPotentialDensity'}, {'prefix': 'mixedLayerDepth', 'mpas': '******', 'units': r'm', 'titleName': 'Mixed Layer Depth', '3D': False, 'obsFilePrefix': 'mld', 'obsFieldName': 'mld', 'obsBotFieldName': None}, {'prefix': 'zonalVelocity', 'mpas': '******', 'units': r'm s$^{-1}$', 'titleName': 'Zonal Velocity', '3D': True, 'obsFilePrefix': 'zonal_vel', 'obsFieldName': 'zonalVel', 'obsBotFieldName': 'botZonalVel'}, {'prefix': 'meridionalVelocity', 'mpas': '******', 'units': r'm s$^{-1}$', 'titleName': 'Meridional Velocity', '3D': True, 'obsFilePrefix': 'merid_vel', 'obsFieldName': 'meridVel', 'obsBotFieldName': 'botMeridVel'}, {'prefix': 'velocityMagnitude', 'mpas': '******', 'units': r'm s$^{-1}$', 'titleName': 'Velocity Magnitude', '3D': True, 'obsFilePrefix': 'vel_mag', 'obsFieldName': 'velMag', 'obsBotFieldName': 'botVelMag'}] tags = ['climatology', 'horizontalMap', 'sose', 'publicObs'] \ + [field['prefix'] for field in fields] # call the constructor from the base class (AnalysisTask) super(ClimatologyMapSose, self).__init__(config=config, taskName='climatologyMapSose', componentName='ocean', tags=tags) sectionName = self.taskName fileSuffix = config.get(sectionName, 'fileSuffix') if fileSuffix.endswith('.nc'): fileSuffix = fileSuffix.strip('.nc') fieldList = config.getExpression(sectionName, 'fieldList') fields = [field for field in fields if field['prefix'] in fieldList] # read in what seasons we want to plot seasons = config.getExpression(sectionName, 'seasons') if len(seasons) == 0: raise ValueError('config section {} does not contain valid ' 'list of seasons'.format(sectionName)) comparisonGridNames = config.getExpression(sectionName, 'comparisonGrids') if len(comparisonGridNames) == 0: raise ValueError('config section {} does not contain valid ' 'list of comparison grids'.format(sectionName)) if not numpy.any([field['3D'] for field in fields]): depths = None else: depths = config.getExpression(sectionName, 'depths') if len(depths) == 0: raise ValueError('config section {} does not contain valid ' 'list of depths'.format(sectionName)) variableList = [ field['mpas'] for field in fields if field['mpas'] != 'velMag' ] if depths is None: remapMpasSubtask = RemapMpasClimatologySubtask( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName='SOSE', variableList=variableList, seasons=seasons, comparisonGridNames=comparisonGridNames, iselValues=None) else: remapMpasSubtask = RemapMpasVelMagClimatology( mpasClimatologyTask=mpasClimatologyTask, parentTask=self, climatologyName='SOSE', variableList=variableList, seasons=seasons, depths=depths, comparisonGridNames=comparisonGridNames, iselValues=None) for field in fields: fieldPrefix = field['prefix'] upperFieldPrefix = fieldPrefix[0].upper() + fieldPrefix[1:] sectionName = '{}{}'.format(self.taskName, upperFieldPrefix) if field['3D']: fieldDepths = depths else: fieldDepths = None if controlConfig is None: refTitleLabel = 'State Estimate (SOSE)' observationsDirectory = build_obs_path(config, 'ocean', 'soseSubdirectory') obsFileName = '{}/SOSE_2005-2010_monthly_{}_{}.nc'.format( observationsDirectory, field['obsFilePrefix'], fileSuffix) refFieldName = field['obsFieldName'] outFileLabel = '{}SOSE'.format(fieldPrefix) galleryName = 'State Estimate: SOSE' diffTitleLabel = 'Model - State Estimate' remapObsSubtask = RemapSoseClimatology( parentTask=self, seasons=seasons, fileName=obsFileName, outFilePrefix='{}SOSE'.format(refFieldName), fieldName=refFieldName, botFieldName=field['obsBotFieldName'], depths=fieldDepths, comparisonGridNames=comparisonGridNames, subtaskName='remapObservations{}'.format(upperFieldPrefix)) self.add_subtask(remapObsSubtask) else: remapObsSubtask = None controlRunName = controlConfig.get('runs', 'mainRunName') galleryName = 'Control: {}'.format(controlRunName) refTitleLabel = galleryName refFieldName = field['mpas'] outFileLabel = fieldPrefix diffTitleLabel = 'Main - Control' if field['3D']: fieldDepths = depths else: fieldDepths = [None] for comparisonGridName in comparisonGridNames: for season in seasons: for depth in fieldDepths: subtaskName = 'plot{}_{}_{}'.format( upperFieldPrefix, season, comparisonGridName) if depth is not None: subtaskName = '{}_depth_{}'.format( subtaskName, depth) subtask = PlotClimatologyMapSubtask( parentTask=self, season=season, comparisonGridName=comparisonGridName, remapMpasClimatologySubtask=remapMpasSubtask, remapObsClimatologySubtask=remapObsSubtask, controlConfig=controlConfig, depth=depth, subtaskName=subtaskName) subtask.set_plot_info( outFileLabel=outFileLabel, fieldNameInTitle=field['titleName'], mpasFieldName=field['mpas'], refFieldName=refFieldName, refTitleLabel=refTitleLabel, diffTitleLabel=diffTitleLabel, unitsLabel=field['units'], imageCaption=field['titleName'], galleryGroup=field['titleName'], groupSubtitle=None, groupLink='{}Sose'.format(fieldPrefix), galleryName=galleryName, configSectionName='climatologyMapSose{}'.format( upperFieldPrefix)) self.add_subtask(subtask)