datamanager.py 54.2 KB
Newer Older
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        :rtype: str
        """
        if frequency == 'mon':
            if domain == 'seaIce':
                domain_abreviattion = 'OImon'
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            elif domain == 'landIce':
                domain_abreviattion = 'LImon'
            else:
                domain_abreviattion = domain[0].upper() + 'mon'
        elif frequency == '6hr':
            domain_abreviattion = '6hrPlev'
        else:
            domain_abreviattion = 'day'
        return domain_abreviattion

    def get_year(self, domain, var, startdate, member, year, grid=None, box=None):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """
        Gets all the data corresponding to a given year from the CMOR repository to the scratch folder as one file and
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        returns the path to the scratch's copy.

        :param year: year to retrieve
        :type year: int
        :param domain: CMOR domain
        :type domain: str
        :param var: variable name
        :type var: str
        :param startdate: file's startdate
        :type startdate: str
        :param member: file's member
        :type member: int
        :param grid: file's grid (only needed if it is not the original)
        :type grid: str
        :param box: file's box (only needed to retrieve sections or averages)
        :type box: Box
        :return: path to the copy created on the scratch folder
        :rtype: str
        """
        for chunk in self.exp_manager.get_year_chunks(startdate, year):
            chunk_files.append(self.get_file(domain, var, startdate, member, chunk, grid=grid, box=box))

        if len(chunk_files) > 1:
            temp = TempFile.get()
            Utils.nco.ncrcat(input=' '.join(chunk_files), output=temp)
            for chunk_file in chunk_files:
                os.remove(chunk_file)
        else:
            temp = chunk_files[0]
        temp2 = TempFile.get()
        handler = Utils.openCdf(temp)
        time = Utils.get_datetime_from_netcdf(handler)
        handler.close()
        start = None
        end = None
        for x in range(0, len(time)):
            date = time[x]
            if date.year == year:
                if date.month == 1:
                    start = x
                elif date.month == 12:
                    end = x

        Utils.nco.ncks(input=temp, output=temp2, options='-O -d time,{0},{1}'.format(start, end))
        os.remove(temp)
        return temp2

    def _is_cmorized(self, startdate, member):
        if not os.path.exists(self.get_startdate_path(startdate)):
            return False
        startdate_path = self.get_startdate_path(startdate)
        for freq in os.listdir(startdate_path):
            freq_path = os.path.join(startdate_path, freq)
            for domain in os.listdir(freq_path):
                domain_path = os.path.join(freq_path, domain)
                for var in os.listdir(domain_path):
                    member_path = os.path.join(domain_path, var, 'r{0}i1p1'.format(member+1))
                    if os.path.exists(member_path):
                        return True
        return False
class Variable(object):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    """
    Class to characterize a CMOR variable. It also contains the static method to make the match between thje original
    name and the standard name. Requires cmor_table.csv to work.
    """
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    _dict_variables = None
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

    def __init__(self, line):
        self.short_name = line[1].strip()
        self.standard_name = line[2].strip()
        self.long_name = line[3].strip()
        self.domain = line[4].strip()
        self.basin = Basins.parse(line[5])
        self.units = line[6].strip()
        self.valid_min = line[7].strip()
        self.valid_max = line[8].strip()

    @classmethod
    def get_variable(cls, original_name):
        Returns the cmor variable instance given a variable name
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

        :param original_name: original variable's name
        :type original_name: str
        :return: CMOR variable
        :rtype: Variable
        """
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
            return cls._dict_variables[original_name.lower()]
        except KeyError:
            Log.warning('Variable {0} is not defined in the CMOR table. Please add it'.format(original_name))
            return None
    @classmethod
    def load_variables(cls):
        """
        Loads the cmor_table.csv and creates the variables dictionary
        """
        Variable._dict_variables = dict()
        with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'cmor_table.csv'), 'rb') as csvfile:
            reader = csv.reader(csvfile, dialect='excel')
            for line in reader:
                if line[0] == 'variable':
                    continue

                var = Variable(line)
                if not var.short_name:
                    continue
                for old_name in line[0].split(':'):
                    Variable._dict_variables[old_name] = var
                Variable._dict_variables[var.short_name] = var

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

class UnitConversion(object):
    """
    Class to manage unit conversions
    """
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
    _dict_conversions = None

    @classmethod
    def load_conversions(cls):
        """
        Load conversions from the configuration file
        """
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        cls._dict_conversions = dict()
        with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'conversions.csv'), 'rb') as csvfile:
            reader = csv.reader(csvfile, dialect='excel')
            for line in reader:
                if line[0] == 'original':
                    continue
                cls.add_conversion(UnitConversion(line[0], line[1], line[2], line[3]))
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed

    @classmethod
    def add_conversion(cls, conversion):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """
        Adds a conversion to the dictionary

        :param conversion: conversion to add
        :type conversion: UnitConversion
        """
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        cls._dict_conversions[(conversion.source, conversion.destiny)] = conversion

    def __init__(self, source, destiny, factor, offset):
        self.source = source
        self.destiny = destiny
        self.factor = float(factor)
        self.offset = float(offset)

    @classmethod
    def get_conversion_factor_offset(cls, input_units, output_units):
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        """
        Gets the conversion factor and offset for two units . The conversion has to be done in the following way:
        converted = original * factor + offset

        :param input_units: original units
        :type input_units: str
        :param output_units: destiny units
        :type output_units: str
        :return: factor and offset
        :rtype: [float, float]
        """
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        units = input_units.split()
        if len(units) == 1:
            scale_unit = 1
            unit = units[0]
        else:
            if '^' in units[0]:
                values = units[0].split('^')
                scale_unit = pow(int(values[0]), int(values[1]))
            else:
                scale_unit = float(units[0])
            unit = units[1]

        units = output_units.split()
        if len(units) == 1:
            scale_new_unit = 1
            new_unit = units[0]
        else:
            if '^' in units[0]:
                values = units[0].split('^')
                scale_new_unit = pow(int(values[0]), int(values[1]))
            else:
                scale_new_unit = float(units[0])
            new_unit = units[1]

        factor, offset = UnitConversion._get_factor(new_unit, unit)
        if factor is None:
            return None, None
Javier Vegas-Regidor's avatar
Javier Vegas-Regidor committed
        factor = factor * scale_unit / float(scale_new_unit)
        offset /= float(scale_new_unit)

        return factor, offset

    @classmethod
    def _get_factor(cls, new_unit, unit):
        # Add  only the conversions with a factor greater than 1
        if unit == new_unit:
            return 1, 0
        elif (unit, new_unit) in cls._dict_conversions:
            conversion = cls._dict_conversions[(unit, new_unit)]
            return conversion.factor, conversion.offset
        elif (new_unit, unit) in cls._dict_conversions:
            conversion = cls._dict_conversions[(unit, new_unit)]
            return 1/conversion.factor, -conversion.offset
        else:
            return None, None