moc.py 5.98 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 MOC for oceanic basins"""
import numpy as np
from bscearth.utils.log import Log
import iris
import iris.analysis

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

import netCDF4

from earthdiagnostics.constants import Basins
from earthdiagnostics.diagnostic import Diagnostic, DiagnosticBasinListOption
from earthdiagnostics.modelingrealm import ModelingRealms
from earthdiagnostics.utils import Utils, TempFile
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
import diagonals.moc as moc
from diagonals.mesh_helpers.nemo import Nemo


class Moc(Diagnostic):
    """
    Compute the MOC for oceanic basins
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

    :original author: Virginie Guemas <virginie.guemas@bsc.es>
    :contributor: Javier Vegas-Regidor<javier.vegas@bsc.es>

    :created: March 2012
    :last modified: June 2016

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    :param data_manager: data management object
    :type data_manager: DataManager
    :param startdate: startdate
    :type startdate: str
    :param member: member number
    :type member: int
    :param chunk: chunk's number
    :type chunk: int
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    alias = "moc"
    "Diagnostic alias for the configuration file"

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    vsftmyz = "vsftmyz"
    def __init__(self, data_manager, startdate, member, chunk, basins):
        Diagnostic.__init__(self, data_manager)
        self.data_convention = data_manager.convention
        self.startdate = startdate
        self.member = member
        self.chunk = chunk
        self.basins = basins
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.results = {}

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    def __str__(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        basins.extend(self.basins)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        return (
            "MOC Startdate: {0.startdate} Member: {0.member} "
            "Chunk: {0.chunk} Basins: {1}".format(self, basins)
        )
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

    def __hash__(self):
        return hash(str(self))

    def __eq__(self, other):
        if self._different_type(other):
            return False
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            self.startdate == other.startdate
            and self.member == other.member
            and self.chunk == other.chunk
    @classmethod
    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: None
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        :type options: list[str]
        basins = Basins()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        options_available = (DiagnosticBasinListOption("basins", "glob"),)

        options = cls.process_options(options, options_available)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        basins = options["basins"]
        if not basins:
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            Log.error("Basins not recognized")
            return ()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        basins.sort()
        job_list = list()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        for (
            startdate,
            member,
            chunk,
        ) in diags.config.experiment.get_chunk_list():
            job_list.append(
                Moc(diags.data_manager, startdate, member, chunk, basins)
            )
    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.variable_file = self.request_chunk(
            ModelingRealms.ocean, "vo", self.startdate, self.member, self.chunk
        )

    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.results = self.declare_chunk(
            ModelingRealms.ocean,
            Moc.vsftmyz,
            self.startdate,
            self.member,
            self.chunk,
        )
    def compute(self):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """Run the diagnostic"""
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        vo_cube = iris.load_cube(self.variable_file.local_file)
        vo = np.ma.filled(vo_cube.data, 0.0).astype(np.float32)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        mesh = Nemo("mesh_hgr.nc", "mask_regions.nc")
        e1v = mesh.get_i_length(cell_point="V")
        e3v = mesh.get_k_length(cell_point="V")
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

        masks = {}
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        self.basins
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        for basin in self.basins:
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            if basin == Basins().Global:
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
                global_mask = mesh.get_landsea_mask(cell_point="V")
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
                global_mask[..., 0] = 0.0
                global_mask[..., -1] = 0.0
                masks[basin] = global_mask
            else:
                masks[basin] = Utils.get_mask(basin)

        moc_results = moc.compute(masks, e1v, e3v, vo)
        del vo, e1v, e3v
        self._save_result(moc_results, mesh)

    def _save_result(self, result, mesh):
        temp = TempFile.get()
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        handler_source = Utils.open_cdf(self.variable_file.local_file)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        handler_temp = Utils.open_cdf(temp, "w")
        gphiv = np.squeeze(mesh.get_grid_latitude(cell_point="V"))
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        max_gphiv = np.unravel_index(np.argmax(gphiv), gphiv.shape)[1]

Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        Utils.copy_variable(handler_source, handler_temp, "time", True, True)
        Utils.copy_variable(handler_source, handler_temp, "lev", True, True)
        handler_temp.createDimension("i", 1)
        handler_temp.createDimension("j", gphiv.shape[0])
        handler_temp.createDimension("region", len(result))
        handler_temp.createDimension("region_length", 50)
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        var_region = handler_temp.createVariable(
            "region", "S1", ("region", "region_length")
        )
        lat = handler_temp.createVariable(
            self.data_convention.lat_name, float, ("j", "i"))
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        lat[...] = gphiv[:, max_gphiv]
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        lat.units = "degrees_north"
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        lat.long_name = "Latitude"
        lat.standard_name = "latitude"
        lon = handler_temp.createVariable(
            self.data_convention.lon_name, float, ("j", "i"))
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        lon[...] = 0
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        lon.units = "degrees_east"
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        lon.long_name = "Longitude"
        lon.standard_name = "longitude"
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        var = handler_temp.createVariable(
            "vsftmyz", float, ("time", "lev", "i", "j", "region")
        )
        var.units = "Sverdrup"
        var.coordinates = "lev time latitude longitude"
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        var.long_name = "Ocean meridional overturning volume streamfunction"
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        var.missing_value = 1e20
        var.fill_value = 1e20

        for i, basin in enumerate(result):
            var_region[i, ...] = netCDF4.stringtoarr(str(basin), 50)
            var[..., i] = result[basin]
        handler_temp.close()
        self.results.set_local_file(temp, diagnostic=self)