def test_raise_error_no_time_coordinate(self): """Test that the function raises an error if no time coordinate.""" cube = set_up_wxcube() cube.coord("time").rename("nottime") msg = "cube must have time coordinate" with self.assertRaisesRegex(CoordinateNotFoundError, msg): update_daynight(cube)
def test_wxcode_updated_on_latlon(self): """Test Correct wxcodes returned for lat lon cube.""" cube = set_up_wxcube(lat_lon=True) cube.data = self.cube_data expected_result = np.array([ [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3], [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], [6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6], [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7], [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8], [9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10], [13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14], [15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17], [18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18], [19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20], [22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23], [25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26], [27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27], [28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29], ]) result = update_daynight(cube) self.assertArrayEqual(result.data, expected_result)
def test_wxcode_time_different_seconds(self): """ Test code works if time coordinate has a difference in the number of seconds, which should round to the same time in hours and minutes. This was raised by changes to cftime which altered its precision.""" cube = set_up_wxcube(time=datetime.datetime(2018, 9, 12, 5, 42, 59)) cube.data = self.cube_data expected_result = np.array([ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3], [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], [6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6], [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7], [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8], [9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10], [13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14], [15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17], [18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18], [19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20], [22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23], [25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26], [27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27], [28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29], ]) result = update_daynight(cube) self.assertArrayEqual(result.data, expected_result) self.assertEqual(result.data.shape, (16, 16))
def test_wxcode_updated(self): """Test Correct wxcodes returned for cube.""" cube = set_up_wxcube() cube.data = self.cube_data # Only 1,3,10, 14, 17, 20, 23, 26 and 29 change from day to night expected_result = np.array([ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3], [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], [6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6], [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7], [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8], [9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10], [13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14], [15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17], [18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18], [19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20], [22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23], [25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26], [27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27], [28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29], ]) result = update_daynight(cube) self.assertArrayEqual(result.data, expected_result) self.assertEqual(result.shape, (16, 16))
def test_wxcode_time_different_seconds(self): """ Test code works if time coordinate has a difference in the number of seconds, which should round to the same time in hours and minutes. This was raised by changes to cftime which altered its precision.""" time_origin = "hours since 1970-01-01 00:00:00" calendar = "gregorian" dateval = datetime.datetime(2018, 9, 12, 5, 42, 59) numdateval = date2num(dateval, time_origin, calendar) time_points = [numdateval] cube = set_up_wxcube(time_points=time_points) cube.data = self.cube_data cube = iris.util.squeeze(cube) expected_result = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3], [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], [6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6], [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7], [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8], [9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10], [13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14], [15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17], [18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18], [19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20], [22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23], [25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26], [27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27], [28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29]]) result = update_daynight(cube) self.assertArrayEqual(result.data, expected_result) self.assertEqual(result.data.shape, (16, 16))
def test_wxcode_time_as_attribute(self): """ Test code works if time is an attribute not a dimension """ cube = set_up_wxcube() cube.data = self.cube_data cube = iris.util.squeeze(cube) expected_result = np.array( [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3], [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5], [6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6], [7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7], [8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8], [9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10], [13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14], [15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15], [16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17], [18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18], [19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20], [22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23], [25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26], [27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27], [28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29]]) result = update_daynight(cube) self.assertArrayEqual(result.data, expected_result) self.assertEqual(result.data.shape, (16, 16))
def test_basic_lat_lon(self): """Test that the function returns a weather code lat lon cube..""" cube = set_up_wxcube(lat_lon=True) result = update_daynight(cube) self.assertIsInstance(result, iris.cube.Cube) self.assertEqual(result.name(), "weather_code") self.assertEqual(result.units, "1") self.assertArrayEqual(result.attributes["weather_code"], self.wxcode) self.assertEqual(result.attributes["weather_code_meaning"], self.wxmeaning)
def test_basic_lat_lon(self): """Test that the function returns a weather code lat lon cube..""" cube = set_up_wxcube_lat_lon() result = update_daynight(cube) self.assertIsInstance(result, Cube) self.assertEqual(result.name(), 'weather_code') self.assertEqual(result.units, Unit("1")) self.assertArrayEqual(result.attributes['weather_code'], self.wxcode) self.assertEqual(result.attributes['weather_code_meaning'], self.wxmeaning)
def test_basic(self): """Test that the function returns a weather code cube.""" cube = set_up_wxcube() result = update_daynight(cube) self.assertIsInstance(result, Cube) self.assertEqual(result.name(), "weather_code") self.assertEqual(result.units, Unit("1")) self.assertArrayEqual(result.attributes["weather_code"], self.wxcode) self.assertEqual(result.attributes["weather_code_meaning"], self.wxmeaning)
def test_wxcode_time_as_array(self): """ Test code works if time is an array of dimension > 1 """ cube = set_up_wxcube(time_points=[ datetime.datetime(2018, 9, 12, 5), datetime.datetime(2018, 9, 12, 6), datetime.datetime(2018, 9, 12, 7), ]) expected_result = np.ones((3, 16, 16)) expected_result[0, :, :] = 0 result = update_daynight(cube) self.assertArrayEqual(result.data, expected_result)
def test_wxcode_time_as_array(self): """ Test code works if time is an array of dimension > 1 """ num1 = datetime_to_numdateval(year=2018, month=9, day=12, hour=5, minutes=0) num2 = datetime_to_numdateval(year=2018, month=9, day=12, hour=6, minutes=0) num3 = datetime_to_numdateval(year=2018, month=9, day=12, hour=7, minutes=0) cube = set_up_wxcube(time_points=[num1, num2, num3]) expected_result = np.ones((3, 16, 16)) expected_result[0, :, :] = 0 result = update_daynight(cube) self.assertArrayEqual(result.data, expected_result)
def test_wxcode_time_as_array(self): """ Test code works if time is an array of dimension > 1 """ time_points = [ datetime.datetime(2018, 9, 12, 5), datetime.datetime(2018, 9, 12, 6), datetime.datetime(2018, 9, 12, 7), ] cubes = iris.cube.CubeList() for time in time_points: cubes.append(set_up_wxcube(time=time)) cube = cubes.merge_cube() expected_result = np.ones((3, 16, 16)) expected_result[0, :, :] = 0 result = update_daynight(cube) self.assertArrayEqual(result.data, expected_result)
def process(self, cubes: CubeList) -> Cube: """Apply the decision tree to the input cubes to produce weather symbol output. Args: cubes: A cubelist containing the diagnostics required for the weather symbols decision tree, these at co-incident times. Returns: A cube of weather symbols. """ # Check input cubes contain required data optional_node_data_missing = self.check_input_cubes(cubes) # Construct graph nodes dictionary graph = { key: [self.queries[key]["succeed"], self.queries[key]["fail"]] for key in self.queries } # Search through tree for all leaves (weather code end points) defined_symbols = [] for item in self.queries.values(): for value in item.values(): if isinstance(value, int): defined_symbols.append(value) # Create symbol cube symbols = self.create_symbol_cube(cubes) # Loop over possible symbols for symbol_code in defined_symbols: # In current decision tree # start node is heavy_precipitation routes = self.find_all_routes( graph, self.start_node, symbol_code, omit_nodes=optional_node_data_missing, ) # Loop over possible routes from root to leaf for route in routes: conditions = [] for i_node in range(len(route) - 1): current_node = route[i_node] current = copy.copy(self.queries[current_node]) try: next_node = route[i_node + 1] except KeyError: next_node = symbol_code if current["fail"] == next_node: ( current["threshold_condition"], current["condition_combination"], ) = self.invert_condition(current) conditions.append(self.create_condition_chain(current)) test_chain = [conditions, "AND"] # Set grid locations to suitable weather symbol symbols.data[ np.ma.where(self.evaluate_condition_chain(cubes, test_chain)) ] = symbol_code # Update symbols for day or night. symbols = update_daynight(symbols) return symbols