Source code for earthdiagnostics.general.scale

# coding=utf-8
"""Scales a variable by with value and offset"""
import math

import numpy as np

from earthdiagnostics.constants import Basins
from earthdiagnostics.general.fix_file import FixFile
from earthdiagnostics.diagnostic import DiagnosticDomainOption, DiagnosticVariableOption, \
    DiagnosticFloatOption, DiagnosticBoolOption, DiagnosticListFrequenciesOption, DiagnosticOption
from earthdiagnostics.utils import Utils


[docs]class Scale(FixFile): """ Scales a variable by the given value also adding at offset Can be useful to correct units or other known errors (think of a tas file declaring K as units but with the data stored as Celsius) :original author: Javier Vegas-Regidor<javier.vegas@bsc.es> :created: July 2016 :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 : :param variable: variable's name :type variable: str :param domain: variable's domain :type domain: ModelingRealm """ alias = 'scale' "Diagnostic alias for the configuration file" def __init__(self, data_manager, startdate, member, chunk, value, offset, domain, variable, grid, min_limit, max_limit, frequency, apply_mask): FixFile.__init__(self, data_manager, startdate, member, chunk, domain, variable, grid) self.value = value self.offset = offset self.min_limit = min_limit self.max_limit = max_limit self.frequency = frequency self.apply_mask = apply_mask self.original_values = None def __str__(self): return 'Scale output Startdate: {0.startdate} Member: {0.member} Chunk: {0.chunk} ' \ 'Scale value: {0.value} Offset: {0.offset} Variable: {0.domain}:{0.variable} ' \ 'Frequency: {0.frequency} Apply mask: {0.apply_mask}'.format(self) def __eq__(self, other): if self._different_type(other): return False return self.startdate == other.startdate and self.member == other.member and self.chunk == other.chunk and \ self.domain == other.domain and self.variable == other.variable and self.frequency == other.frequency and \ self.apply_mask == other.apply_mask and self.value == other.value and self.offset == other.offset
[docs] @classmethod def generate_jobs(cls, diags, options): """ Create a job for each chunk to compute the diagnostic :param diags: Diagnostics manager class :type diags: Diags :param options: variable, domain, grid :type options: list[str] :return: """ options_available = (DiagnosticDomainOption(), DiagnosticVariableOption(diags.data_manager.config.var_manager), DiagnosticFloatOption('value'), DiagnosticFloatOption('offset'), DiagnosticOption('grid', ''), DiagnosticFloatOption('min_limit', float('nan')), DiagnosticFloatOption('max_limit', float('nan')), DiagnosticListFrequenciesOption('frequencies', [diags.config.frequency]), DiagnosticBoolOption('apply_mask', False)) options = cls.process_options(options, options_available) job_list = list() for frequency in options['frequencies']: for startdate, member, chunk in diags.config.experiment.get_chunk_list(): job_list.append(Scale(diags.data_manager, startdate, member, chunk, options['value'], options['offset'], options['domain'], options['variable'], options['grid'], options['min_limit'], options['max_limit'], frequency, options['apply_mask'])) return job_list
[docs] def compute(self): """Run the diagnostic""" variable_file = self.variable_file.local_file handler = Utils.open_cdf(variable_file) var = handler.variables[self.variable] self.original_values = var[:] if self.apply_mask: mask = Utils.get_mask(Basins().Global).astype(float) mask[mask == 0] = np.nan var[:] = mask * var[:] if self._check_limits(): values = self.original_values * self.value + self.offset if self.apply_mask: values[np.isnan(values)] = 0 var[:] = values handler.close() self.corrected.set_local_file(self.variable_file.local_file, self)
def _check_limits(self): if not math.isnan(self.min_limit) and (self.original_values.min() < self.min_limit): return False if not math.isnan(self.max_limit) and (self.original_values.max() > self.max_limit): return False return True