Пример #1
0
    def write_dataset_variable(self: 'ModelOutput', data: np.ndarray,
                               data_type: str) -> None:
        """
        Prepare to write data into a variable by the name of data_type
        in this instance's NetCDF dataset file. Apply this variable's
        dimensions and type, along with several attributes.

        :param data:
            A single-variable grid taken from Arrhenius model output
        :param data_type:
            The name of the variable as it will appear in the dataset
        """
        dims_map = [[], ['latitude'], ['latitude', 'longitude'],
                    ['time', 'latitude', 'longitude'],
                    ['time', 'level', 'latitude', 'longitude']]

        global_output_center().submit_output(
            Debug.PRINT_NOTICES, "Writing {} to dataset".format(data_type))
        variable_type = VARIABLE_METADATA[data_type][VAR_TYPE]
        self._dataset.variable(data_type, variable_type, dims_map[data.ndim])

        for attr, val in VARIABLE_METADATA[data_type][VAR_ATTRS].items():
            self._dataset.variable_attribute(data_type, attr, val)

        self._dataset.data(data_type, data)
Пример #2
0
def print_solo_statistics(data: GriddedData) -> None:
    """
    Display a series of tables and statistics based on model run results.
    Which outputs are displayed is determined by the current output
    controller, and its settings under the SpecialReportDatatype and
    ReportDatatype categories.
    """
    output_center = out_cnf.global_output_center()

    # Prepare data tables.
    temp_name = out_cnf.ReportDatatype.REPORT_TEMP.value
    delta_t_name = out_cnf.ReportDatatype.REPORT_TEMP_CHANGE.value

    temp_data = \
        extract_multidimensional_grid_variable(data, temp_name)
    temp_table = convert_grid_data_to_table(temp_data)

    output_center.submit_output(out_cnf.ReportDatatype.REPORT_TEMP,
                                temp_table)

    delta_temp_data = \
        extract_multidimensional_grid_variable(data, delta_t_name)
    delta_temp_table = convert_grid_data_to_table(delta_temp_data)

    # Print tables of data.
    output_center.submit_output(
        out_cnf.ReportDatatype.REPORT_TEMP_CHANGE,
        delta_temp_table
    )
Пример #3
0
def write_model_output(data: List['LatLongGrid'], output_title: str) -> None:
    """
    Write the results of a model run (data) to disk, in the form of a
    NetCDF dataset and a series of image files arranged into a directory
    with the name given by output_title.

    :param data:
        The output from an Arrhenius model run
    :param output_title:
        A unique name for the output directory
    """
    writer = ModelOutput(data)
    controller = global_output_center()

    # Upload collection handlers for dataset and image file collections.
    controller.register_collection(DATASET_VARS, handler=writer.write_dataset)
    controller.register_collection(IMAGES, handler=writer.write_images)

    # Change several output type handlers within each collection.
    for output_type in ReportDatatype:
        controller.change_handler_if_enabled(output_type, (DATASET_VARS, ),
                                             writer.write_dataset_variable)
        controller.change_handler_if_enabled(output_type, (IMAGES, ),
                                             write_image_type)

    writer.write_output(output_title)
Пример #4
0
    def write_images(self: 'ModelOutput',
                     data: List['LatLongGrid'],
                     output_path: str,
                     run_id: str = "") -> None:
        """
        Produce a series of maps displaying some of the results of an
        Arrhenius model run according to what variable the output controller
        allows. Images are stored in a directory given by output_path.

        One image will be produced per time segment per variable for which
        output is allowed by the output controller, based on which
        ReportDatatype output types are enabled. The optional argument
        img_base_name specifies a prefix that will be added to each of the
        image files to identify which model run they belong to.

        :param data:
            The output from an Arrhenius model run
        :param output_path:
            The directory where image files will be stored
        :param run_id:
            A prefix that will start off the names of all the image files
        """
        output_controller = global_output_center()

        # Attempt to output images for each variable output type.
        for output_type in ReportDatatype:
            variable_name = output_type.value
            variable = extract_multidimensional_grid_variable(
                data, variable_name)
            img_type_path = path.join(output_path, variable_name)

            output_controller.submit_output(output_type, variable,
                                            img_type_path, variable_name,
                                            run_id)
Пример #5
0
def write_model_output(data: List['LatLongGrid']) -> None:
    """
    Write the results of a model run (data) to disk, in the form of a
    NetCDF dataset and a series of image files.

    Location and output specifications are given by thread-specific
    global configurations, which can be accessed using the global_config
    and set_configuration functions in the configuration module, and the
    corresponding functions in output_config.

    :param data:
        The output from an Arrhenius model run
    """
    writer = ModelOutput(data)
    controller = global_output_center()

    # Upload collection handlers for dataset and image file collections.
    controller.register_collection(DATASET_VARS, handler=writer.write_dataset)
    controller.register_collection(IMAGES, handler=writer.write_images)

    # Change several output type handlers within each collection.
    for output_type in ReportDatatype:
        controller.change_handler_if_enabled(output_type,
                                             (DATASET_VARS,),
                                             writer.write_dataset_variable)
        controller.change_handler_if_enabled(output_type,
                                             (IMAGES,),
                                             write_image_type)

    writer.write_output(global_config())
Пример #6
0
    def write_output(self: 'ModelOutput',
                     config: 'ArrheniusConfig') -> None:
        """
        Produce NetCDF data files and image files from the provided data,
        located in a new directory for this output set. The name of the
        directory is based on config.

        One image file is created per time segment in the data. In the
        case of Arrhenius' model, this is one per season. Only one NetCDF data
        file is produced, in which all time segments are present.

        :param config:
            Configuration options for the model run
        """
        run_title = config.run_id()

        # Create a directory for this model output if none exists already.
        out_dir_path = path.join(OUTPUT_FULL_PATH, run_title)
        out_dir = Path(out_dir_path)
        out_dir.mkdir(exist_ok=True)

        output_controller = global_output_center()
        output_controller.submit_collection_output((DATASET_VARS,),
                                                   self._data,
                                                   out_dir_path,
                                                   run_title + ".nc")
        output_controller.submit_collection_output((IMAGES,),
                                                   self._data,
                                                   out_dir_path,
                                                   config)
Пример #7
0
    def write_images(self: 'ModelOutput',
                     data: List['LatLongGrid'],
                     output_path: str,
                     config: 'ArrheniusConfig') -> None:
        """
        Produce a series of maps displaying some of the results of an
        Arrhenius model run according to what variable the output controller
        allows. Images are stored in a directory given by output_path.

        One image will be produced per time segment per variable for which
        output is allowed by the output controller, based on which
        ReportDatatype output types are enabled. Names of these image files
        are based on variable and time unit, as well as config.

        :param data:
            The output from an Arrhenius model run
        :param output_path:
            The directory where image files will be stored
        :param config:
            Configuration options for the model run
        """
        output_controller = global_output_center()

        # Attempt to output images for each variable output type.
        for output_type in ReportDatatype:
            var_name = output_type.value
            variable = extract_multidimensional_grid_variable(data, var_name)

            output_controller.submit_output(output_type, variable,
                                            output_path,
                                            var_name,
                                            config)
Пример #8
0
def print_relation_statistics(data: GriddedData, expected: np.ndarray) -> None:
    """
    Print a series of tables and statistics based on the relation between
    model run results, given by data, and an array of expected results for
    temperature change, given by the parameter expected.

    The expected results must have dimensions appropriate to the model data
    in table format. Table format reduces the number of dimensions of the data
    by one, by aggregating latitude bands. Otherwise, the dimensions of the
    data remain in the same order (time, level, longitude).

    :param data:
        A nested list of model run results
    :param expected:
        An array of expected temperature change values for the model run
    """
    delta_t_name = out_cnf.ReportDatatype.REPORT_TEMP_CHANGE.value
    delta_temp_data = \
        extract_multidimensional_grid_variable(data, delta_t_name)
    delta_temp_table = convert_grid_data_to_table(delta_temp_data)

    output_center = out_cnf.global_output_center()
    diff = expected - delta_temp_table

    output_center.submit_output(
        out_cnf.SpecialReportData.REPORT_DELTA_TEMP_DEVIATIONS, diff)

    output_center.submit_output(
        out_cnf.AccuracyMetrics.TEMP_DELTA_AVG_DEVIATION, mean(diff))

    output_center.submit_output(
        out_cnf.AccuracyMetrics.TEMP_DELTA_STD_DEVIATION, std_dev(diff))

    output_center.submit_output(out_cnf.AccuracyMetrics.TEMP_DELTA_VARIANCE,
                                variance(diff))
Пример #9
0
def write_image_type(data: np.ndarray,
                     parent_path: str,
                     data_type: str,
                     config: 'ArrheniusConfig') -> bool:
    """
    Write out a category of output, given by the parameter data, to a
    directory with the name given by output_path. One image file will
    be produced for every index in the highest-level dimension in the
    data. Returns True iff a new image was produced that was not already
    present on disk.

    The third parameter specifies the name of the variable being
    represented by this set of images. The fourth parameter is a
    configuration set belonging to the model run the images will be
    based on. Configuration will determine the names of the output files.

    :param data:
        A single-variable grid derived from Arrhenius model output
    :param output_path:
        The directory where image files will be stored
    :param data_type:
        The name of the variable on which the data is based
    :param config:
        Configuration options for the previously-run model run
    :return:
        True iff a new image file was produced
    """
    output_center = global_output_center()
    output_center.submit_output(Debug.PRINT_NOTICES,
                                "Preparing to write {} images"
                                .format(data_type))

    output_path = \
        get_image_directory(parent_path, config.run_id(), data_type,
                            config.colorbar(), create=True)
    file_ext = '.png'

    annual_avg = np.array([np.mean(data, axis=0)])
    data = np.concatenate([annual_avg, data], axis=0)

    created = False

    # Write an image file for each time segment.
    for i in range(len(data)):
        base_name = data_type + "_" + str(i)
        img_name = image_file_name(base_name, config) + file_ext
        img_path = path.join(output_path, img_name)

        new_created = not Path(img_path).is_file()

        if new_created:
            # Produce and save the image.
            output_center.submit_output(Debug.PRINT_NOTICES,
                                        "\tSaving image file {}...".format(i))
            g = ModelImageRenderer(data[i])
            g.save_image(img_path, config.colorbar())
            created = True

    return created
Пример #10
0
    def write_dataset(self: 'ModelOutput',
                      data: List['LatLongGrid'],
                      dir_path: str,
                      dataset_name: str) -> None:
        """
        Produce a NetCDF dataset, with the name given by dataset_name.nc,
        containing the variables in the data parameter that the output
        controller allows. The dataset will be written to the specified
        path in the file system.

        The dataset contains all the dimensions that are used in the data
        (e.g. time, latitude, longitude) as well as variables including
        final temperature, temperature change, humidity, etc. according
        to which of the ReportDatatype output types are enabled in the
        current output controller.

        :param data:
            Output from an Arrhenius model run
        :param dir_path:
            The directory where the dataset will be written
        :param dataset_name:
            The name of the dataset
        """
        # Write the data out to a NetCDF file in the output directory.
        grid_by_count = self._grid.dims_by_count()
        output_path = path.join(dir_path, dataset_name)

        global_output_center().submit_output(Debug.PRINT_NOTICES,
                                             "Writing NetCDF dataset...")
        self._dataset.global_attribute("description", "Output for an"
                                                      "Arrhenius model run.")\
            .dimension('time', np.int32, len(data), (0, len(data)))\
            .dimension('latitude', np.int32, grid_by_count[0], (-90, 90)) \
            .dimension('longitude', np.int32, grid_by_count[1], (-180, 180)) \

        for output_type in ReportDatatype:
            variable_data =\
                extract_multidimensional_grid_variable(data,
                                                       output_type.value)
            global_output_center().submit_output(output_type, variable_data,
                                                 output_type.value)

        self._dataset.write(output_path)
Пример #11
0
    def write_output(self: 'ModelOutput', run_title: str) -> None:
        """
        Produce NetCDF data files and image files from the provided data, and
        a directory with the name dir_name to hold them.

        One image file is created per time segment in the data. In the
        case of Arrhenius' model, this is one per season. Only one NetCDF data
        file is produced, in which all time segments are present.
        """
        # Create a directory for this model output if none exists already.
        out_dir_path = path.join(OUTPUT_FULL_PATH, run_title)
        out_dir = Path(out_dir_path)
        out_dir.mkdir(exist_ok=True)

        output_controller = global_output_center()
        output_controller.submit_collection_output(
            (DATASET_VARS, ), self._data, out_dir_path, run_title + ".nc")
        output_controller.submit_collection_output((IMAGES, ), self._data,
                                                   out_dir_path, run_title)
Пример #12
0
def write_image_type(data: np.ndarray, output_path: str, data_type: str,
                     run_id: str) -> None:
    """
    Write out a category of output, given by the parameter data, to a
    directory with the name given by output_path. One image file will
    be produced for every index in the highest-level dimension in the
    data.

    The third ard fourth parameters specify the name of the variable
    being represented by this set of images, and the name of the model
    run respectively. EAch image's name will begin with run_id followed
    by an underscore followed by data_type. These will be followed by a
    number indicating the order in which the images were written.

    :param data:
        A single-variable grid derived from Arrhenius model output
    :param output_path:
        The directory where image files will be stored
    :param data_type:
        The name of the variable on which the data is based
    :param run_id:
        A unique name for the current model run
    """
    output_center = global_output_center()
    output_center.submit_output(
        Debug.PRINT_NOTICES, "Preparing to write {} images".format(data_type))

    img_base_name = "_".join([run_id, data_type])
    file_ext = '.png'

    # Write an image file for each time segment.
    for i in range(len(data)):
        img_name = "_".join([img_base_name, str(i + 1) + file_ext])
        img_path = path.join(output_path, img_name)

        Path(output_path).mkdir(exist_ok=True)

        # Produce and save the image.
        output_center.submit_output(Debug.PRINT_NOTICES,
                                    "\tSaving image file {}...".format(i))
        g = ModelImageRenderer(data[i])
        g.save_image(img_path, (-1, 1))
Пример #13
0
    def print_statistic_tables(self: 'ModelRun') -> None:
        """
        Display a series of tables and statistics based on model run results.
        Which outputs are displayed is determined by the current output
        controller, and its settings under the SpecialReportDatatype and
        ReportDatatype categories.
        """
        output_center = out_cnf.global_output_center()

        # Prepare data tables.
        temp_name = out_cnf.ReportDatatype.REPORT_TEMP.value
        delta_t_name = out_cnf.ReportDatatype.REPORT_TEMP_CHANGE.value

        temp_data = \
            extract_multidimensional_grid_variable(self.grids, temp_name)
        temp_table = convert_grid_data_to_table(temp_data)

        output_center.submit_output(out_cnf.ReportDatatype.REPORT_TEMP,
                                    temp_table)

        delta_temp_data = \
            extract_multidimensional_grid_variable(self.grids, delta_t_name)
        delta_temp_table = convert_grid_data_to_table(delta_temp_data)

        # Print tables of data.
        output_center.submit_output(out_cnf.ReportDatatype.REPORT_TEMP_CHANGE,
                                    delta_temp_table)

        expected = X2_EXPECTED
        diff = expected - delta_temp_table

        output_center.submit_output(
            out_cnf.SpecialReportData.REPORT_DELTA_TEMP_DEVIATIONS, diff)

        output_center.submit_output(
            out_cnf.AccuracyMetrics.TEMP_DELTA_AVG_DEVIATION, mean(diff))

        output_center.submit_output(
            out_cnf.AccuracyMetrics.TEMP_DELTA_STD_DEVIATION, std_dev(diff))
Пример #14
0
    def run_model(self: 'ModelRun',
                  expected: Optional[np.ndarray] = None) -> GriddedData:
        """
        Calculate Earth's surface temperature change due to a change in
        CO2 levels given in the model runner's configuration.

        Returns a list of grids, each of which represents the state of the
        Earth's surface over a range of time. The grids contain data produced
        from the model run.

        :param expected:
            An array of expected temperature change values in table format
        :return:
            The state of the Earth's surface based on the model's calculations
        """
        cnf.set_configuration(self.config)
        out_cnf.set_output_center(self.output_controller)

        year_of_interest = self.config.year()
        self.grids = self.collector.get_gridded_data(year_of_interest)

        init_co2 = self.config.init_co2()
        final_co2 = self.config.final_co2()
        iterations = self.config.iterations()

        # Average values over each latitude band before the model run.
        if self.config.aggregate_latitude() == cnf.AGGREGATE_BEFORE:
            self.grids = multigrid_latitude_bands(self.grids)

        # Run the body of the model, calculating temperature changes for each
        # cell in the grid.
        counter = 1
        for time_seg in self.grids:
            place = "th" if (not 1 <= counter % 10 <= 3) \
                            and (not 10 < counter < 20) \
                else "st" if counter % 10 == 1 \
                else "nd" if counter % 10 == 2 \
                else "rd"
            report = "Preparing model run on {}{} grid".format(counter, place)
            self.output_controller.submit_output(out_cnf.Debug.PRINT_NOTICES, report)

            if self.config.model_mode() == cnf.ABS_SRC_MULTILAYER:
                self.compute_multilayer(time_seg, init_co2,
                                        final_co2, iterations)

            else:
                self.compute_single_layer(time_seg[0], init_co2,
                                          final_co2, iterations)

            counter += 1

        # Average values over each latitude band after the model run.
        if self.config.aggregate_latitude() == cnf.AGGREGATE_AFTER:
            self.grids = multigrid_latitude_bands(self.grids)

        ground_layer = [time_seg[0] for time_seg in self.grids]

        print_solo_statistics(ground_layer)
        if expected is not None:
            print_relation_statistics(ground_layer, expected)

        # Finally, write model output to disk.
        out_cnf.global_output_center().submit_collection_output(
            out_cnf.PRIMARY_OUTPUT_PATH,
            ground_layer
        )

        return self.grids
Пример #15
0
    def run_model(self, init_co2: float,
                  new_co2: float) -> List[List['LatLongGrid']]:
        """
        Calculate Earth's surface temperature change due to a change in
        CO2 levels from init_co2 to new_co2.
        Returns a list of grids, each of which represents the state of the
        Earth's surface over a range of time. The grids contain data produced
        from the model run.
        :param init_co2:
            The initial amount of CO2 in the atmosphere
        :param new_co2:
            The new amount of CO2 in the atmosphere
        :return:
            The state of the Earth's surface based on the model's calculations
        """
        out_cnf.set_output_center(self.output_controller)

        if self.grids is None:
            year_of_interest = self.config[cnf.YEAR]
            self.grids = self.collector.get_gridded_data(year_of_interest)

        # Average values over each latitude band before the model run.
        if self.config[cnf.AGGREGATE_LAT] == cnf.AGGREGATE_BEFORE:
            self.grids = [grid.latitude_bands() for grid in self.grids]

        # Run the body of the model, calculating temperature changes for each
        # cell in the grid.
        if self.config[cnf.ABSORBANCE_SRC] == cnf.ABS_SRC_MULTILAYER:
            for time in self.grids:
                iterators = []
                pressures = []
                for grid in time:
                    iterators.append(grid.__iter__())
                    pressures.append(grid.get_pressure())
                pressures.pop(0)

                # merges terms in each iterator into a Tuple; returns
                # single iterator over Tuples
                cell_iterator = zip(*iterators)

                # replace dummy array below with pressures later!
                layer_dims = pressures_to_layer_dimensions(pressures)

                for layered_cell in cell_iterator:
                    new_temps = self.calculate_layered_cell_temperature(
                        init_co2, new_co2, pressures, layer_dims, layered_cell)
                    for cell_num in range(len(layered_cell)):
                        layered_cell[cell_num].set_temperature(
                            new_temps[cell_num])

                out_cnf.global_output_center().submit_collection_output(
                    out_cnf.PRIMARY_OUTPUT_PATH, self.grids[0],
                    self.config[cnf.RUN_ID])
            return self.grids

        else:
            counter = 1
            for time in self.grids:
                for grid in time:
                    place = "th" if (not 1 <= counter % 10 <= 3) \
                                    and (not 10 < counter < 20) \
                        else "st" if counter % 10 == 1 \
                        else "nd" if counter % 10 == 2 \
                        else "rd"
                    report = "Preparing model run on {}{} grid".format(
                        counter, place)
                    self.output_controller.submit_output(
                        out_cnf.Debug.PRINT_NOTICES, report)

                    if self.config[cnf.ABSORBANCE_SRC] == cnf.ABS_SRC_TABLE:
                        for cell in grid:
                            new_temp = self.calculate_arr_cell_temperature(
                                init_co2, new_co2, cell)
                            cell.set_temperature(new_temp)

                    elif self.config[cnf.ABSORBANCE_SRC] == cnf.ABS_SRC_MODERN:
                        for cell in grid:
                            new_temp = self.calculate_modern_cell_temperature(
                                init_co2, new_co2, cell)
                            cell.set_temperature(new_temp)

                    counter += 1

        # # Average values over each latitude band after the model run.
        # if self.config[cnf.AGGREGATE_LAT] == cnf.AGGREGATE_AFTER:
        #     self.grids = [grid.latitude_bands() for grid in self.grids]
        #
        # self.print_statistic_tables()
        #
        # # Finally, write model output to disk.
        # out_cnf.global_output_center().submit_collection_output(
        #     out_cnf.PRIMARY_OUTPUT_PATH,
        #     self.grids,
        #     self.config[cnf.RUN_ID]
        # )

        return self.grids