siasiesiv.py 7.21 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"""
sloosvel's avatar
sloosvel committed
import os
sloosvel's avatar
sloosvel committed
import six
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
import numpy as np

sloosvel's avatar
sloosvel committed
import netCDF4

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
sloosvel's avatar
sloosvel committed
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
sloosvel's avatar
sloosvel committed
import diagonals.siasie as siasie
from diagonals.mesh_helpers.nemo import Nemo

# noinspection PyUnresolvedReferences


sloosvel's avatar
sloosvel 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

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"

sloosvel's avatar
sloosvel 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
sloosvel's avatar
sloosvel committed
        for var in ('siarean', 'siareas', 'siextentn', 'siextents'):
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]
sloosvel's avatar
sloosvel committed
        options_available = (DiagnosticBasinListOption('basins',
                                                       [Basins().Global]),
sloosvel's avatar
sloosvel committed
                             DiagnosticBoolOption('omit_volume', True))
        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():
sloosvel's avatar
sloosvel committed
            job_list.append(Siasiesiv(diags.data_manager, startdate, member,
                                      chunk, masks, diags.config.var_manager,
                                      diags.config.data_convention,
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
                                      options['omit_volume']))
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"""
sloosvel's avatar
sloosvel committed
            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):
sloosvel's avatar
sloosvel committed
        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"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

        self._fix_coordinates_attribute(
            self.sic.local_file, self.sic_varname
        )
        sic = iris.load_cube(self.sic.local_file)
        if sic.units.origin == '%' and sic.data.max() < 2:
sloosvel's avatar
sloosvel committed
        sic_slices = []
        for sic_data in sic.slices_over('time'):
            sic_data.data = np.ma.filled(sic_data.data, 0.0).astype(np.float32)
            sic_slices.append(sic_data)
        mesh = Nemo('mesh_hgr.nc', 'mask_regions.nc')
        areacello = mesh.get_areacello(cell_point='T')
        gphit = mesh.get_grid_latitude(cell_point='T')

        if not self.omit_volume:
            sit = iris.load_cube(self.sit.local_file)
            self.results['siextentn'], self.results['siextents'], self.results['siarean'], self.results['siareas'], self.results['sivoln'], self.results['sivols'] = siasie.compute(gphit, areacello, sic_slices, self.masks, sit)
        else:
            self.results['siextentn'], self.results['siextents'], self.results['siarean'], self.results['siareas'] = siasie.compute(gphit, areacello, sic_slices, self.masks, None)

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    def _fix_coordinates_attribute(self, filepath, var_name):
        add_coordinates = {
            'time', 'leadtime', 'time_centered',
            self.data_convention.lon_name, self.data_convention.lat_name
        }
        handler = Utils.open_cdf(filepath)
        coordinates = handler.variables[var_name].coordinates.split()
        handler.variables[var_name].coordinates = \
            ' '.join(set(coordinates) | add_coordinates)
        handler.close()

        for var in self.results.keys():
            res = self.results[var]
            temp = TempFile.get()
            handler_source = Utils.open_cdf(self.sic.local_file)
            handler_temp = Utils.open_cdf(temp, 'w')
            Utils.copy_variable(handler_source, handler_temp, 'time', True, True)
            handler_temp.createDimension('region', len(self.masks))
            handler_temp.createDimension('region_length', 50)
            var_region = handler_temp.createVariable('region', 'S1',
                                                 ('region', 'region_length'))
            var_res = handler_temp.createVariable('{0}'.format(var), float,
                                                  ('time', 'region',))
            var_res.units = 'm^2'
            if var in ('voln', 'vols'):
                var_res.units = 'm^3'
            for i, basin in enumerate(self.masks):
                var_region[i, ...] = netCDF4.stringtoarr(str(basin), 50)
                var_res[..., i] = res[i, ...]
            handler_temp.close()
            self.generated[var].set_local_file(temp, diagnostic=self)