Beispiel #1
0
    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)
Beispiel #4
0
    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)
Beispiel #8
0
    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)
Beispiel #9
0
    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)
Beispiel #11
0
    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
Beispiel #12
0
    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)
Beispiel #13
0
    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)
Beispiel #18
0
    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.')
Beispiel #20
0
    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)