# (C) Copyright 2021-2022 NOAA/NWS/EMC
#
# (C) Copyright 2021-2022 United States Government as represented by the Administrator of the
# National Aeronautics and Space Administration. All Rights Reserved.
#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
# --------------------------------------------------------------------------------------------------
from math import sqrt
from numpy import log
import re
from statistics import mean
from eva.utilities.config import get
from eva.utilities.logger import Logger
from eva.transforms.transform_utils import parse_for_dict, split_collectiongroupvariable
from eva.transforms.transform_utils import replace_cgv
from eva.utilities.utils import remove_list_duplicates
from eva.utilities.utils import remove_empty_from_list_of_strings
# --------------------------------------------------------------------------------------------------
[docs]def isfloat(a_string):
"""
Checks if a string can be converted to a floating-point number.
Args:
a_string (str): The string to be checked.
Returns:
bool: True if the string can be converted to a float, False otherwise.
This function determines whether a given string can be successfully converted to a
floating-point number.
Example:
::
result = isfloat("3.14")
"""
try:
float(a_string)
return True
except ValueError:
return False
# --------------------------------------------------------------------------------------------------
[docs]def arithmetic(config, data_collections):
"""
Applies arithmetic transformations to data variables using specified expressions.
Args:
config (dict): A configuration dictionary containing transformation parameters.
data_collections (DataCollections): An instance of the DataCollections class containing
input data.
Returns:
None
This function applies arithmetic transformations to data variables within the provided data
collections. It iterates over the specified collections, groups, and variables, and applies
arithmetic expressions as defined in the 'equals' expressions within the configuration. The
resulting variables are added to the data collections.
Example:
::
config = {
'collections': [...],
'groups': [...],
'variables': [...],
'new name': 'result_variable',
'equals': '(${collection}::${group}::${var1} + ${collection}::${group}::${var2})
/ 2'
}
arithmetic(config, data_collections)
"""
# Create a logger
logger = Logger('ArithmeticTransform')
# Parse the for dictionary
[collections, groups, variables] = parse_for_dict(config, logger)
# Parse config for the expression and new collection/group/variable naming
new_name_template = get(config, logger, 'new name')
expression_template = get(config, logger, 'equals')
# Loop over the templates
for collection in collections:
for group in groups:
for variable in variables:
# Replace collection, group, variable in template
[new_name, expression] = replace_cgv(logger, collection, group, variable,
new_name_template, expression_template)
# Remove white space
expression = ''.join(expression.split())
# Split math equation
expression_elements = re.split(r'\(|\)|-|\*|\+|\/|log', expression)
# Remove empty elements and duplicates from expression elements
expression_elements = remove_empty_from_list_of_strings(expression_elements)
expression_variables = remove_list_duplicates(expression_elements)
# Build the expression
vars = []
var_counter = 0
for n in range(len(expression_variables)):
if not isfloat(expression_variables[n]):
# Extract the data from the collections
cgv = split_collectiongroupvariable(logger, expression_variables[n])
exp_var_data = data_collections.get_variable_data_array(cgv[0], cgv[1],
cgv[2])
vars.append(exp_var_data)
# Replace the name in the expression
expression = expression.replace(expression_variables[n],
'vars['+str(var_counter)+']')
var_counter = var_counter + 1
# Evaluate the expression
new_variable = eval(str(expression))
# Add the new field to the data collections
cgv = split_collectiongroupvariable(logger, new_name)
data_collections.add_variable_to_collection(cgv[0], cgv[1], cgv[2], new_variable)
# --------------------------------------------------------------------------------------------------
[docs]def generate_arithmetic_config(new_name, expression, collection, var_list):
"""
Generates a configuration dictionary for the 'arithmetic' transformation.
Args:
new_name (str): The new variable name after the transformation.
expression (str): The arithmetic expression to be applied.
collection (str): The collection name.
var_list (list): A list of variables to apply the transformation to.
Returns:
dict: A configuration dictionary for the 'arithmetic' transformation.
This function generates a configuration dictionary for the 'arithmetic' transformation based
on the provided parameters. It updates the 'new name' field, adjusts the arithmetic expression
based on the provided collection and group names, and specifies the 'for' dictionary to apply
the transformation to the specified variables.
Example:
::
new_name = 'result_variable'
expression = '(${group1} + ${group2}) / 2'
collection = 'my_collection'
var_list = ['variable1', 'variable2']
config = generate_arithmetic_config(new_name, expression, collection, var_list)
"""
# Update new_name
updated_name = collection + '::' + new_name + '::${variable}'
# Fix expression
groups = re.split(r'\(|\)|-|\*|\+|\/', expression)
for group in groups:
expression = expression.replace(group, collection +
'::' + group + '::${variable}')
# Build dictionary
arithmetic_config = {
'new name': updated_name,
'transform': "arithmetic",
'for': {
'variable': var_list
},
'equals': expression
}
return arithmetic_config
# --------------------------------------------------------------------------------------------------