siasiesiv.py 7.96 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"""
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
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor 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
    """
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    alias = "siasiesiv"
    "Diagnostic alias for the configuration file"

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
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        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
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        for var in ("siarean", "siareas", "siextentn", "siextents"):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    def __str__(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        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 __hash__(self):
        return hash(str(self))

    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]
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        options_available = (
            DiagnosticBasinListOption("basins", [Basins().Global]),
            DiagnosticBoolOption("omit_volume", True),
        )
        options = cls.process_options(options, options_available)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        basins = options["basins"]
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            Log.error("Basins not recognized")
        basins.sort()
        for basin in basins:
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        for (
            startdate,
            member,
            chunk,
        ) in diags.config.experiment.get_chunk_list():
            job_list.append(
                Siasiesiv(
                    diags.data_manager,
                    startdate,
                    member,
                    chunk,
                    masks,
                    diags.config.var_manager,
                    diags.config.data_convention,
                    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"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor 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"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            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")
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self._declare_var("siarean")
        self._declare_var("siextentn")
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

    def _declare_var(self, var_name):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor 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

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)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        if sic.units.origin != "%":
            sic.convert_units("%")
sloosvel's avatar
sloosvel committed
        sic_slices = []
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        for sic_data in sic.slices_over("time"):
sloosvel's avatar
sloosvel committed
            sic_data.data = np.ma.filled(sic_data.data, 0.0).astype(np.float32)
            sic_data.data[np.isinf(sic_data.data)] = 0.0
sloosvel's avatar
sloosvel committed
            sic_slices.append(sic_data)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        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)
            sit_slices = []
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            for sit_data in sit.slices_over("time"):
                sit_data.data = np.ma.filled(sit_data.data, 0.0).astype(
                    np.float32
                )
                sit_data.data[np.isinf(sit_data.data)] = 0.0
                sit_slices.append(sit_data)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            results = siasie.compute(
                gphit, areacello, sic_slices, self.masks, sit_slices
            )
            self.results["siextentn"] = results[0]
            self.results["siextents"] = results[1]
            self.results["siarean"] = results[2]
            self.results["siareas"] = results[3]
            self.results["sivoln"] = results[4]
            self.results["sivols"] = results[5]
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            results = siasie.compute(
                gphit, areacello, sic_slices, self.masks, None
            )
            self.results["siextentn"] = results[0]
            self.results["siextents"] = results[1]
            self.results["siarean"] = results[2]
            self.results["siareas"] = results[3]
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    def _fix_coordinates_attribute(self, filepath, var_name):
        add_coordinates = {
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            "time",
            "leadtime",
            "time_centered",
            self.data_convention.lon_name,
            self.data_convention.lat_name,
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        }
        handler = Utils.open_cdf(filepath)
        coordinates = handler.variables[var_name].coordinates.split()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        handler.variables[var_name].coordinates = " ".join(
            set(coordinates) | add_coordinates
        )
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        handler.close()

        for var in self.results.keys():
            res = self.results[var]
            temp = TempFile.get()
            handler_source = Utils.open_cdf(self.sic.local_file)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            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(
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
                "region", "S1", ("region", "region_length")
            )
            var_res = handler_temp.createVariable(
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
                "{0}".format(var), float, ("time", "region",)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            if var in ("sivoln", "sivols"):
                var_res.units = "m^3"
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
                var_res.units = "m^2"
            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)