def construct_condition(extract_constraint, condition, probability_threshold): """ Create a string representing a comparison condition. Args: extract_constraint (str or list of str): A string, or list of strings, encoding iris constraints that will be used to extract the correct diagnostic cube (by name) from the input cube list and the correct threshold from that cube. A list should contain only cube names, operators and numbers, e.g. ["probability_of_lwe_snowfall_rate_above_threshold", "-", "probability_of_rainfall_rate_above_threshold", "*", "0.7"] condition (str): The condition statement (e.g. greater than, >). probability_threshold (float): The probability value to use in the comparison. Returns: string: The formatted condition statement, e.g.:: cubes.extract(Constraint( name='probability_of_rainfall_rate_above_threshold', coord_values={'threshold': 0.03}) )[0].data < 0.5) """ if isinstance(extract_constraint, list): formatted_str = "" for item in extract_constraint: if is_variable(item): formatted_str += f" cubes.extract({item})[0].data" else: formatted_str += " " + item return f"({formatted_str}) {condition} {probability_threshold}" return "cubes.extract({})[0].data {} {}".format( extract_constraint, condition, probability_threshold)
def create_condition_chain(self, test_conditions: Dict) -> List: """ Construct a list of all the conditions specified in a single query. Args: test_conditions: A query from the decision tree. Returns: A valid condition chain is defined recursively: (1) If each a_1, ..., a_n is an extract expression (i.e. a constraint, or a list of constraints, operator strings and floats), and b is either "AND", "OR" or "", then [[a1, ..., an], b] is a valid condition chain. (2) If a1, ..., an are each valid conditions chain, and b is either "AND" or "OR", then [[a1, ..., an], b] is a valid condition chain. """ conditions = [] loop = 0 for diagnostic, p_threshold, d_threshold in zip( test_conditions["diagnostic_fields"], test_conditions["probability_thresholds"], test_conditions["diagnostic_thresholds"], ): loop += 1 if isinstance(diagnostic, list): # We have a list which could contain variable names, operators and # numbers. The variable names need converting into Iris Constraint # syntax while operators and numbers remain unchanged. # We expect an entry in p_threshold for each variable name, so # d_threshold_index is used to track these. d_threshold_index = -1 extract_constraint = [] for item in diagnostic: if is_variable(item): # Add a constraint from the variable name and threshold value d_threshold_index += 1 extract_constraint.append( self.construct_extract_constraint( item, d_threshold[d_threshold_index], self.coord_named_threshold, ) ) else: # Add this operator or variable as-is extract_constraint.append(item) else: # Non-lists are assumed to be constraints on a single variable. extract_constraint = self.construct_extract_constraint( diagnostic, d_threshold, self.coord_named_threshold ) conditions.append( [ extract_constraint, test_conditions["threshold_condition"], p_threshold, ] ) condition_chain = [conditions, test_conditions["condition_combination"]] return condition_chain
def create_condition_chain(self, test_conditions): """ A wrapper to call the construct_condition function for all the conditions specified in a single query. Args: test_conditions (dict): A query from the decision tree. Returns: list of str: A list of strings that describe the conditions comprising the query. e.g.:: [ "(cubes.extract(Constraint( name='probability_of_rainfall_rate_above_threshold', coord_values={'threshold': 0.03}) )[0].data < 0.5) | (cubes.extract(Constraint( name= 'probability_of_lwe_snowfall_rate_above_threshold', coord_values={'threshold': 0.03}) )[0].data < 0.5)" ] """ conditions = [] loop = 0 for diagnostic, p_threshold, d_threshold in zip( test_conditions["diagnostic_fields"], test_conditions["probability_thresholds"], test_conditions["diagnostic_thresholds"], ): loop += 1 if isinstance(diagnostic, list): # We have a list which could contain variable names, operators and # numbers. The variable names need converting into Iris Constraint # syntax while operators and numbers remain unchanged. # We expect an entry in p_threshold for each variable name, so # d_threshold_index is used to track these. d_threshold_index = -1 extract_constraint = [] for item in diagnostic: if is_variable(item): # Add a constraint from the variable name and threshold value d_threshold_index += 1 extract_constraint.append( self.construct_extract_constraint( item, d_threshold[d_threshold_index], self.coord_named_threshold, )) else: # Add this operator or variable as-is extract_constraint.append(item) else: # Non-lists are assumed to be strings containing one variable name. extract_constraint = self.construct_extract_constraint( diagnostic, d_threshold, self.coord_named_threshold) conditions.append( self.construct_condition( extract_constraint, test_conditions["threshold_condition"], p_threshold, )) condition_chain = WeatherSymbols.format_condition_chain( conditions, condition_combination=test_conditions["condition_combination"]) return [condition_chain]