def test_negative_lat_error(self): """ Test that an error is returned when grid dimensions are created with a cell latitude width/count below zero. """ with self.assertRaises(ValueError): grid = GridDimensions((-1, 6), "width") with self.assertRaises(ValueError): grid = GridDimensions((-2.5, 180), "count")
def test_negative_lon_error(self): """ Test that an error is returned when grid dimensions are created with a cell longitude width/count below zero. """ with self.assertRaises(ValueError): grid = GridDimensions((4.5, -125), "width") with self.assertRaises(ValueError): grid = GridDimensions((90, -4.5), "count")
def test_floating_point_count_error(self): """ Test that an error is returned when grid dimensions are created based on non-integer cell counts. """ with self.assertRaises(ValueError): grid = GridDimensions((1.1, 1), "count") with self.assertRaises(ValueError): grid = GridDimensions((1, 12.5), "count")
def test_zero_lon_error(self): """ Test that an error is returned when grid dimensions are created with a cell longitude width/count equal to zero. """ with self.assertRaises(ValueError): grid = GridDimensions((9, 0), "width") with self.assertRaises(ValueError): grid = GridDimensions((2, 0), "count")
def test_invalid_grid_form_error(self): """ Test that an error is returned when grid dimensions are created with a grid format that is not recognized. """ with self.assertRaises(ValueError): grid = GridDimensions((1, 2), "") with self.assertRaises(ValueError): grid = GridDimensions((1, 2), "no-op")
def test_grid_by_width(self): """ Test error-free creation and return of a valid grid, with dimensions provided as cell widths. """ grid = GridDimensions((180, 360), "width") dims_by_width = grid.dims_by_width() dims_by_width_expected = (180, 360) self.assertEqual(dims_by_width, dims_by_width_expected)
def test_short_tuple_error(self): """ Test that an error is returned when grid dimensions are created with fewer than two elements in its dimension tuple. """ with self.assertRaises(ValueError): grid = GridDimensions((), "width") with self.assertRaises(ValueError): grid = GridDimensions((1, ), "width")
def test_grid_by_count(self): """ Test error-free creation and return of a valid grid, with dimensions provided as cell counts. """ grid = GridDimensions((2, 2), "count") dims_by_count = grid.dims_by_count() dims_by_count_expected = (2, 2) self.assertEqual(dims_by_count, dims_by_count_expected)
def test_grid_count_to_width(self): """ Test error-free creation and return of a valid grid with dimensions provided as cell counts, and the correct conversion of the grid to a representation in cell widths. """ grid = GridDimensions((45, 180), "count") dims_by_width = grid.dims_by_width() dims_by_width_expected = (4, 2) self.assertEqual(dims_by_width, dims_by_width_expected)
def test_grid_width_to_count(self): """ Test error-free creation and return of a valid grid with dimensions provided as cell widths, and the correct conversion of the grid to a representation in cell counts. """ grid = GridDimensions((90, 90), "width") dims_by_count = grid.dims_by_count() dims_by_count_expected = (2, 4) self.assertEqual(dims_by_count, dims_by_count_expected)
def test_out_of_bounds_lon_error(self): """ Test that an error is returned when grid dimensions are created with longitude cell width greater than the number of degrees of longitude around the Earth. """ with self.assertRaises(ValueError): grid = GridDimensions((60, 480), "width") with self.assertRaises(ValueError): grid = GridDimensions((18, 360.1), "width")
def test_max_grid_dimensions(self): """ Test that a grid is successfully created when the maximum valid cell widths are provided. """ grid = GridDimensions((180, 360), "width") dims_by_width = grid.dims_by_width() dims_by_width_expected = (180, 360) dims_by_count = grid.dims_by_count() dims_by_count_expected = (1, 1) self.assertEqual(dims_by_width, dims_by_width_expected) self.assertEqual(dims_by_count, dims_by_count_expected)
def test_tiny_grid_cells(self): """ Test correct conversion between grid representations when grid cell widths are very small. """ grid = GridDimensions((2880, 2880), "count") dims_by_width = grid.dims_by_width() dims_by_width_expected = (0.0625, 0.125) dims_by_count = grid.dims_by_count() dims_by_count_expected = (2880, 2880) self.assertEqual(dims_by_width, dims_by_width_expected) self.assertEqual(dims_by_count, dims_by_count_expected)
def set_grid(self: 'ArrheniusConfig', grid: Dict[str, Union[str, Dict[str, int]]]) -> None: """ Sets the global grid that surface and atmospheric data will be represented on. Settings of these variables should be stored in a dictionary, mapping "repr" to the grid's representation type, and "dims" to a nested dictionary storing lat and lon values under those keys. If any of this structure is violated, or the values are invalid for constructing a grid, then an InvalidConfigError will be raised. :param grid: A dictionary giving grid dimension specifications """ if "dims" not in grid: raise InvalidConfigError("\"dims\" is a required" " field for grid specification") dims = grid["dims"] for param in ["lat", "lon"]: if param not in dims: raise InvalidConfigError("\"" + param + "\" is a required" " field for grid dimensions") dims_tuple = (dims["lat"], dims["lon"]) self._settings[GRID] = GridDimensions(dims_tuple, grid.get("repr", "width")) self._basis["grid"] = grid
def test_invalid_lon_dimensions_error(self): """ Test that an error is returned when grid dimensions are used that produce a non-integral number of cells in the longitude dimension. """ with self.assertRaises(ValueError): grid = GridDimensions((10, 0.74))
def arrhenius_temperature_data(grid: 'GridDimensions' = GridDimensions((10, 20)), year: int = None) -> np.ndarray: """ A data provider returning temperature data from Arrhenius' original 1895 dataset. Data is gridded on a 10x20 degree latitude-longitude grid, and so any attempts to regrid to a finer grid will produce grainy results. Data is divided into four time segments of each a season long, for a total of one year of data coverage. Not all grid cells have values, especially in the Arctic and Antarctic circles. These missing values are present as NaN in the array returned. The data will default to a 10x20 degree grid, but can be converted to other grid dimensions through the function parameter grid. Only grids containing integer multiples of the original grid are supported. :param grid: The dimensions of the grid onto which the data is to be converted :return: Temperature data from Arrhenius' original dataset """ dataset = custom_readers.ArrheniusDataReader() data = dataset.collect_untimed_data("temperature")[:] # Regrid the humidity variable to the specified grid, if necessary. regridded_data = _regrid_netcdf_variable(data, grid, 3) return regridded_data
def test_float_grid_dims(self): """ Test the error-free creation of a valid grid with floating point grid cell widths, and sensible conversion to a representation in cell counts. """ grid = GridDimensions((0.5, 1.5), "width") dims_by_width = grid.dims_by_width() dims_by_width_expected = (0.5, 1.5) dims_by_count = grid.dims_by_count() dims_by_count_expected = (360, 240) self.assertEqual(dims_by_width, dims_by_width_expected) self.assertEqual(dims_by_count, dims_by_count_expected)
def __init__( self: 'ClimateDataCollector', grid: 'GridDimensions' = GridDimensions((10, 20)) ) -> None: """ Instantiate a new ClimateDataCollector instance. Takes an optional parameter grid, which is a set of grid dimensions. If no value is provided, a default grid will be used with 18 cells in each of the latitude and longitude dimensions. :param grid: An optional set of grid dimensions """ # Provider functions that produce various types of data. self._temp_source = None self._humidity_source = None self._albedo_source = None self._absorbance_source = None self._pressure_source = None # Cached data from the above sources. self._grid_data = None self._pressure_data = None self._absorbance_data = None self._grid = grid
def ncar_humidity_data(grid: 'GridDimensions' = GridDimensions((10, 20)), year: int = None) -> np.array: """ A data provider returning (by default) 1-degree gridded relative humidity data at surface level. The data will be adjusted to a new grid if one is provided. Data is returned as a nested list structure. The outermost list has 12 indices, and represents months of the year. For instance, index 0 represents January, and index 9 is October. The second index is latitude, and the third is longitude. The data will default to a 1-by-1-degree grid, but can be converted to other grid dimensions through the two function parameters. Only grids containing integer multiples of the original grid are supported. :param grid: The dimensions of the grid onto which the data will be converted :return: NCEP/NCAR surface relative humidity data """ dataset = custom_readers.NCEPReader('water') humidity = dataset.collect_timed_layered_data('rhum', year) # Regrid the humidity variable to the specified grid, if necessary. regridded_humidity = _regrid_netcdf_variable(humidity, grid, 4) grid_by_count = grid.dims_by_count() top_atm_shape = (humidity.shape[0], 5, grid_by_count[0], grid_by_count[1]) high_layer_humidity = np.zeros(top_atm_shape) regridded_humidity = np.hstack((regridded_humidity, high_layer_humidity)) return regridded_humidity
def test_long_tuple_error(self): """ Test that an error is returned when grid dimensions are created with more than two elements in its dimension tuple. :return: """ with self.assertRaises(ValueError): grid = GridDimensions((1, 2, 3), "width")
def __init__(self: 'ModelImageRenderer', data: np.ndarray) -> None: """ Instantiate a new ModelImageReader. Data to display is provided through the data parameter. This parameter may either by an array, or an array-like structure such as a nested list. the There must be three dimensions to the data: time first, followed by latitude and longitude. :param data: An array-like structure of numeric values, representing temperature over a globe """ self._data = data self._grid = GridDimensions((len(data), len(data[0])), "count") # Some parameters for the visualization are also left as attributes. self._continent_linewidth = 0.5 self._lat_long_linewidth = 0.1
def berkeley_temperature_data(grid: 'GridDimensions' = GridDimensions((10, 20)), year: int = None) -> np.array: """ A data provider returning temperature data from the Berkeley Earth temperature dataset. Includes 100% surface and ocean coverage in 1-degree gridded format. Data is reported for the last full year, in monthly sections. Returned in a numpy array. First index corresponds to month, with 0 being January and 11 being December; the second index is latitude, with 0 being 90 and 179 being 90; the third index is longitude, specifications unknown. The data will default to a 1-by-1-degree grid, but can be converted to other grid dimensions through the function parameter grid. Only grids containing integer multiples of the original grid are supported. :param grid: The dimensions of the grid onto which the data is to be converted :return: Berkeley Earth surface temperature data on the selected grid """ dataset = custom_readers.BerkeleyEarthTemperatureReader() if year is None: data = dataset.read_newest('temperature')[:] else: data = dataset.collect_timed_data('temperature', year) clmt = dataset.collect_untimed_data('climatology')[:] # Translate data from the default, 1 by 1 grid to any specified grid. regridded_data = _regrid_netcdf_variable(data, grid, 3) regridded_clmt = _regrid_netcdf_variable(clmt, grid, 3) grid_dims = grid.dims_by_count() for i in range(0, 12): # Store arrays locally to avoid repeatedly indexing dataset. data_by_month = regridded_data[i] clmt_by_month = regridded_clmt[i] for j in range(0, grid_dims[0]): data_by_lat = data_by_month[j] clmt_by_lat = clmt_by_month[j] for k in range(0, grid_dims[1]): # Only one array index required per addition instead # of three gives significant performance increases. data_by_lat[k] += clmt_by_lat[k] return regridded_data
def test_correct_sign(self): """Test that all temp changes are positive values when co2 increases, all temp changes are negative when co2 decreases, and all temp changes are 0 when co2 doesn't change. """ grid_dims = GridDimensions((10, 20)) grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) original_model.run_model(1, 2) grid_cells = h.convert_grids_to_table(original_model.grids) self.assertTrue((grid_cells > 0).all()) grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) original_model.run_model(1, .3) grid_cells = h.convert_grids_to_table(original_model.grids) self.assertTrue((grid_cells < 0).all()) grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) original_model.run_model(1, 1) grid_cells = h.convert_grids_to_table(original_model.grids) self.assertTrue((grid_cells == 0).all())
def constant_albedo_data( temp_data: np.ndarray, grid: 'GridDimensions' = GridDimensions((10, 20)) ) -> np.ndarray: """ Returns an array of absorption values for grid cells under the specified grid, and with the same number of time units as temp_data. Assumes that all grid cells have a constant absorption of 1.0, that is, that the whole Earth is a black body. This assumption may have been made by Arrhenius for simplicity in the original model. :param temp_data: Temperature data for the run, straight from the dataset :param grid: The dimensions of the grid onto which the data will be converted :return: A grid of 1's satisfying the shape of the existing data. """ grid_count = grid.dims_by_count() grid_shape = (len(temp_data), grid_count[0], grid_count[1]) return np.ones(grid_shape)
def ncar_temperature_data(grid: 'GridDimensions' = GridDimensions((10, 20)), year: int = None) -> np.array: """ :param grid: :type grid: :param year: :type year: :return: :rtype: """ dataset = custom_readers.NCEPReader('temperature') temp = dataset.collect_timed_layered_data('air', year) # Regrid the humidity variable to the specified grid, if necessary. regridded_temp = _regrid_netcdf_variable(temp, grid, 4) ground_temp = regridded_temp[:, 0, ...] ground_temp = ground_temp[:, np.newaxis, ...] regridded_temp = np.hstack((ground_temp, regridded_temp)) return regridded_temp
def test_versus_original_results(self): grid_dims = GridDimensions((10, 20)) grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) original_model.run_model(1, .67) averages = h.convert_grids_to_table(original_model.grids) differences = abs(averages - X067_EXPECTED) assert abs(differences.mean) < MEAN_ERROR assert differences.std < STD_ERROR grid_dims = GridDimensions((10, 20)) grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) original_model.run_model(1, 1) averages = h.convert_grids_to_table(original_model.grids) differences = abs(averages - X1_EXPECTED) assert abs(differences.mean) < MEAN_ERROR assert differences.std < STD_ERROR grid_dims = GridDimensions((10, 20)) grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) original_model.run_model(1, 1.5) averages = h.convert_grids_to_table(original_model.grids) differences = abs(averages - X15_EXPECTED) assert abs(differences.mean) < MEAN_ERROR assert differences.std < STD_ERROR grid_dims = GridDimensions((10, 20)) grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) original_model.run_model(1, 2) averages = h.convert_grids_to_table(original_model.grids) differences = abs(averages - X2_EXPECTED) assert abs(differences.mean) < MEAN_ERROR assert differences.std < STD_ERROR grid_dims = GridDimensions((10, 20)) grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) run_model(1, 2.5) averages = h.convert_grids_to_table(original_model.grids) differences = abs(averages - X25_EXPECTED) assert abs(differences.mean) < MEAN_ERROR assert differences.std < STD_ERROR grid_dims = GridDimensions((10, 20)) grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) original_model.run_model(1, 3) averages = h.convert_grids_to_table(original_model.grids) differences = abs(averages - X3_EXPECTED) assert abs(differences.mean) < MEAN_ERROR assert differences.std < STD_ERROR
def test_same_output_input(self): """ Test that running the model with the same inputs yields the same outputs. """ # test co2 increase grid_dims = GridDimensions((10, 20)) grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) original_model.run_model(1, 2) grid_cells_2 = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model_2 = ModelRunner(conf, conf, grid_cells_2) original_model_2.run_model(1, 2) self.assertEqual(original_model.grids, original_model_2.grids) # test co2 decrease grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) original_model.run_model(1, .5) grid_cells_2 = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model_2 = ModelRunner(conf, conf, grid_cells_2) original_model_2.run_model(1, .5) self.assertEqual(original_model.grids, original_model_2.grids) # test no co2 change grid_cells = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model = ModelRunner(conf, conf, grid_cells) original_model.run_model(2, 2) grid_cells_2 = ClimateDataCollector(grid_dims) \ .use_temperature_source(pr.arrhenius_temperature_data) \ .use_humidity_source(pr.arrhenius_humidity_data) \ .use_albedo_source(pr.landmask_albedo_data) \ .get_gridded_data() conf = cnf.DEFAULT_CONFIG conf[cnf.CO2_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY conf[cnf.H2O_WEIGHT] = cnf.WEIGHT_BY_PROXIMITY original_model_2 = ModelRunner(conf, conf, grid_cells_2) original_model_2.run_model(2, 2) self.assertEqual(original_model.grids, original_model_2.grids)
def landmask_albedo_data( temp_data: np.ndarray, grid: 'GridDimensions' = GridDimensions((10, 20)) ) -> np.ndarray: """ A data provider returning 1-degree gridded surface albedo data for land and ocean. Uses Arrhenius' albedo scheme, in which all land has a constant albedo, and all water likewise has a constant albedo. In this case clouds are ignored, although they would contribute to lower global average albedo. Data is returned in a numpy array. The first index represents latitude, and the second index is longitude. Gridded temperature data is required in the first parameter in order to identify which cells are covered in snow. This data should come from a temperature provider function that has been passed the same grid as this function. That is, the temperature data should be on the same grid as the albedo data will be converted to. The returned albedo data will have the same time granularity as the temperature data it is based on (i.e. monthly value if the temperature is reported in monthly values). :param temp_data: Gridded surface temperature data, on the same grid as the data will be converted to :param grid: The dimensions of the grid onto which the data will be converted :return: Surface albedo data by Arrhenius' scheme """ dataset = custom_readers.BerkeleyEarthTemperatureReader() # Berkeley Earth dataset includes variables indicating which 1-degree # latitude-longitude cells are primarily land. land_coords = dataset.collect_untimed_data('land_mask')[:] # Regrid the land/ocean variable to the specified grid, if necessary. regridded_land_coords = _naive_regrid(land_coords, grid) grid_dims = grid.dims_by_count() # Create an array of the same size as the grid, in which to store # grid cell albedo values. albedo_mask = np.ones((len(temp_data), grid_dims[0], grid_dims[1]), dtype=float) # (Inverse) albedo values used by Arrhenius in his model calculations. ocean_albedo_inverse = 0.925 land_albedo_inverse = 1.0 snow_albedo_inverse = 0.5 ocean_albedo = 1 - ocean_albedo_inverse land_albedo = 1 - land_albedo_inverse snow_albedo = 1 - snow_albedo_inverse # Intermediate array slices are cached at each for loop iteration # to prevent excess array indexing. for i in range(len(temp_data)): if len(temp_data.shape) == 3: temp_time_segment = temp_data[i] else: temp_time_segment = temp_data[i, ..., 0, :, :] for j in range(grid_dims[0]): landmask_row = regridded_land_coords[j] temp_row = temp_time_segment[j] for k in range(grid_dims[1]): land_percent = landmask_row[k] ocean_percent = 1 - land_percent # Grid cells are identified as containing snow based on having # land at a temperature below 0 degrees celsius. if temp_row[k] < -15: # Any land in this cell is interpreted as being covered in # snow. albedo_mask[i][j][k] = land_percent * snow_albedo\ + ocean_percent * ocean_albedo else: # Any land in this cell is interpreted as being uncovered. albedo_mask[i][j][k] = land_percent * land_albedo\ + ocean_percent * ocean_albedo return albedo_mask
The albedo of the grid cell :param new_transparency: The new value of the transparency for the grid cell :param k: A constant used in Arrhenius' temperature change equation :return: The change in temperature for a grid cell with the given change in B """ denominator = 1 + albedo * new_transparency return pow((k / denominator), 1 / 4) if __name__ == '__main__': title = "multilayer_1" grid = GridDimensions((4, 4), "count") conf = cnf.default_config() conf[cnf.RUN_ID] = title conf[cnf.AGGREGATE_LAT] = cnf.AGGREGATE_NONE conf[cnf.CO2_WEIGHT] = cnf.weight_by_mean conf[cnf.H2O_WEIGHT] = cnf.weight_by_mean out_cont = out_cnf.development_output_config() out_cont.enable_output_type(out_cnf.ReportDatatype.REPORT_TEMP_CHANGE, handler=print_tables) out_cont.enable_output_type( out_cnf.AccuracyMetrics.TEMP_DELTA_AVG_DEVIATION) out_cont.enable_output_type( out_cnf.AccuracyMetrics.TEMP_DELTA_STD_DEVIATION)
:return: Arrhenius' atmospheric absorbance coefficient """ return STATIC_ATM_ABSORBANCE REQUIRE_TEMP_DATA_INPUT = [landmask_albedo_data, constant_albedo_data] PROVIDERS = { "temperature": { "arrhenius": arrhenius_temperature_data, "berkeley": berkeley_temperature_data, "ncar": ncar_temperature_data, }, "humidity": { "arrhenius": arrhenius_humidity_data, "ncar": ncar_humidity_data, }, "albedo": { "landmask": landmask_albedo_data, "flat": constant_albedo_data, }, "pressure": { "ncar": ncar_pressure_levels, }, } if __name__ == '__main__': grid = GridDimensions((10, 20), "width") g = ncar_humidity_data(grid, 1950)