siasiesiv.py 8.51 KB
Newer Older
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
# coding=utf-8
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
"""Compute the sea ice extent , area and volume  in both hemispheres or a specified region"""
import iris
import iris.analysis
import iris.coords
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
from bscearth.utils.log import Log
from earthdiagnostics.constants import Basins
from earthdiagnostics.diagnostic import Diagnostic, DiagnosticBasinListOption, DiagnosticBoolOption
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
from earthdiagnostics.modelingrealm import ModelingRealms
from earthdiagnostics.utils import Utils, TempFile
# noinspection PyUnresolvedReferences


Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    Compute the sea ice extent , area and volume  in both hemispheres or a specified region.

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    Parameters
    ----------
    data_manager: DataManager
    startdate: str
    member: int
    chunk: init
    domain: ModellingRealm
    variable: str
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    mask: numpy.array
    omit_vol: bool
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    """
    alias = 'siasiesiv'
    "Diagnostic alias for the configuration file"

    e1t = None
    e2t = None
    gphit = None

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    def __init__(self, data_manager, startdate, member, chunk, masks, var_manager, data_convention, omit_vol):
        Diagnostic.__init__(self, data_manager)
        self.startdate = startdate
        self.member = member
        self.chunk = chunk
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.generated = {}
        self.var_manager = var_manager
        self.omit_volume = omit_vol
        self.sic_varname = self.var_manager.get_variable('sic').short_name
        self.sit_varname = self.var_manager.get_variable('sit').short_name
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.data_convention = data_convention
        self.results = {}
        for var in ('siarean', 'siareas', 'sivoln', 'sivols', 'siextentn', 'siextents'):
            self.results[var] = {}

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    def __str__(self):
        return 'Siasiesiv Startdate: {0.startdate} Member: {0.member} Chunk: {0.chunk} ' \
               'Basins: {1} Omit volume: {0.omit_volume}'.format(self,
                                                                 ','.join(str(basin) for basin in self.masks.keys()))
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

    def generate_jobs(cls, diags, options):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        Create a job for each chunk to compute the diagnostic

        :param diags: Diagnostics manager class
        :type diags: Diags
        :param options: basin
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        :type options: list[str]
        options_available = (DiagnosticBasinListOption('basins', [Basins().Global]),
                             DiagnosticBoolOption('omit_volume', False))
        options = cls.process_options(options, options_available)
        basins = options['basins']
        if not basins:
        basins.sort()
        for basin in basins:
        for startdate, member, chunk in diags.config.experiment.get_chunk_list():
            job_list.append(Siasiesiv(diags.data_manager, startdate, member, chunk, masks,
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
                                      diags.config.var_manager, diags.config.data_convention,
                                      options['omit_volume']))

        e1t = iris.load_cube('mesh_hgr.nc', 'e1t')
        e2t = iris.load_cube('mesh_hgr.nc', 'e2t')
        Siasiesiv.area = e1t * e2t
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    def request_data(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Request data required by the diagnostic"""
        if not self.omit_volume:
            self.sit = self.request_chunk(ModelingRealms.seaIce, self.sit_varname,
                                          self.startdate, self.member, self.chunk)
        self.sic = self.request_chunk(ModelingRealms.seaIce, self.sic_varname,
                                      self.startdate, self.member, self.chunk)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

    def declare_data_generated(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Declare data to be generated by the diagnostic"""
        if not self.omit_volume:
            self._declare_var('sivols')
            self._declare_var('sivoln')

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self._declare_var('siareas')
        self._declare_var('siextents')

        self._declare_var('siarean')
        self._declare_var('siextentn')

    def _declare_var(self, var_name):
        self.generated[var_name] = self.declare_chunk(ModelingRealms.seaIce, var_name,
                                                      self.startdate, self.member, self.chunk)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Run the diagnostic"""
        coordinates = ' '.join(('time', 'leadtime', 'time_centered',
                                self.data_convention.lon_name, self.data_convention.lat_name))
        handler = Utils.open_cdf(self.sic.local_file)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        handler.variables[self.sic_varname].coordinates = coordinates
        handler.close()
        sic = iris.load_cube(self.sic.local_file)
        if sic.units.origin == '%' and sic.data.max() < 2:
        sic.convert_units('1.0')
        sic *= Siasiesiv.area.data
        extent = sic.data > 0.15
        if not self.omit_volume:
            handler = Utils.open_cdf(self.sit.local_file)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            handler.variables[self.sit_varname].coordinates = coordinates
            handler.close()
            sit = iris.load_cube(self.sic.local_file)
        for basin, mask in six.iteritems(self.masks):
            self.results['siarean'][basin] = self.sum(sic, mask, north=True)
            self.results['siareas'][basin] = self.sum(sic, mask, north=False)
            if not self.omit_volume:
                volume = sic * sit
                self.results['sivoln'][basin] = self.sum(volume, mask, north=True)
                self.results['sivols'][basin] = self.sum(volume, mask, north=False)
            extent_mask = mask * extent
            self.results['siextentn'][basin] = self.sum(sic, extent_mask, north=True)
            self.results['siextents'][basin] = self.sum(sic, extent_mask, north=False)
    def sum(self, data, mask, north=True):
        if north:
            condition = data.coord('latitude').points > 0
        else:
            condition = data.coord('latitude').points < 0
        weights = iris.util.broadcast_to_shape(condition, data.shape, data.coord_dims('latitude')) * mask
        return data.collapsed(('latitude', 'longitude'), iris.analysis.SUM, weights=weights)

    def save(self):
        for var, basins in six.iteritems(self.results):
            for basin, result in six.iteritems(basins):
                result.var_name = var
                if var.startswith('sivol'):
                    result.units = 'm^3'
                else:
                    result.units = 'm^2'
                result.add_aux_coord(iris.coords.AuxCoord(basin.name, var_name='region'))
            self._save_file(results.merge_cube(), var)
    def _save_file(self, data, var):
        generated_file = self.generated[var]
        region = data.coord('region').points
        data.remove_coord('region')
        iris.save(data, temp, zlib=True)
        if len(region) > 1:
            Utils.rename_variable(temp, 'dim0', 'region', False)
            handler = Utils.open_cdf(temp)
            var = handler.createVariable('region2', str, ('region',))
            var[...] = region
            handler.close()
            Utils.rename_variable(temp, 'region2', 'region', True)
        else:
            handler = Utils.open_cdf(temp)
            if 'region' not in handler.dimensions:
                new_file = TempFile.get()
                new_handler = Utils.open_cdf(new_file, 'w')

                new_handler.createDimension('region', 1)
                for dimension in handler.dimensions:
                    Utils.copy_dimension(handler, new_handler, dimension)

                for variable in handler.variables.keys():
                    if variable in (var, 'region'):
                        continue
                    Utils.copy_variable(handler, new_handler, variable)
                old_var = handler.variables[var]
                new_var = new_handler.createVariable(var, old_var.dtype, ('region',) + old_var.dimensions,
                                                     zlib=True, fill_value=1.0e20)
                Utils.copy_attributes(new_var, old_var)
                new_var[0, :] = old_var[:]

                new_var = new_handler.createVariable('region', str, ('region',))
                new_var[0] = region[0]

                new_handler.close()
                os.remove(temp)
                temp = new_file
            handler.close()
        generated_file.set_local_file(temp)