Ejemplo n.º 1
0
    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")
Ejemplo n.º 2
0
    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")
Ejemplo n.º 3
0
    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")
Ejemplo n.º 4
0
    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")
Ejemplo n.º 5
0
    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")
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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")
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
    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")
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
    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)
Ejemplo n.º 14
0
    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
Ejemplo n.º 15
0
 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))
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
    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)
Ejemplo n.º 18
0
    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
Ejemplo n.º 19
0
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
Ejemplo n.º 20
0
 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")
Ejemplo n.º 21
0
    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
Ejemplo n.º 22
0
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
Ejemplo n.º 23
0
    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())
Ejemplo n.º 24
0
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)
Ejemplo n.º 25
0
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
Ejemplo n.º 26
0
    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
Ejemplo n.º 27
0
    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)
Ejemplo n.º 28
0
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
Ejemplo n.º 29
0
        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)
Ejemplo n.º 30
0
    :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)