Source code for openalea.cnwgrass.integration.build_outputs

# -*- coding: latin-1 -*-
from openalea.cnwgrass.cnmetabolism import simulation as cnmetabolism_simulation
from openalea.cnwgrass.senescence import converter as senescence_converter

import numpy as np
import pandas as pd

"""
    integration.build_outputs
    ~~~~~~~~~~~~~~~~~~~~~~~~

    The module :mod:`integration.build_outputs` reads the information stored in the MTG by each model and writes outputs.

"""

#: columns which define the topology in the input/output dataframe
AXES_TOPOLOGY_COLUMNS = ['plant', 'axis']
ELEMENTS_TOPOLOGY_COLUMNS = ['plant', 'axis', 'metamer', 'organ', 'element']  # Mature + emerging elements
HIDDENZONES_TOPOLOGY_COLUMNS = ['plant', 'axis', 'metamer']
ORGANS_TOPOLOGY_COLUMNS = ['plant', 'axis', 'organ']
SOILS_TOPOLOGY_COLUMNS = ['plant', 'axis']

#: variables in each input/output dataframe
AXES_VARIABLES = set(cnmetabolism_simulation.Simulation.AXES_RUN_VARIABLES +
                     senescence_converter.SENESCENCE_AXES_INPUTS_OUTPUTS)
ELEMENTS_VARIABLES = set(cnmetabolism_simulation.Simulation.ELEMENTS_RUN_VARIABLES +
                         senescence_converter.SENESCENCE_ELEMENTS_INPUTS_OUTPUTS)
HIDDENZONES_VARIABLES = set(cnmetabolism_simulation.Simulation.HIDDENZONE_RUN_VARIABLES)
ORGANS_VARIABLES = set(cnmetabolism_simulation.Simulation.ORGANS_RUN_VARIABLES +
                       senescence_converter.SENESCENCE_ROOTS_INPUTS_OUTPUTS)
SOILS_VARIABLES = set(cnmetabolism_simulation.Simulation.SOILS_RUN_VARIABLES)

BOTANICAL_ORGANS_AT_AXIS_SCALE = ['roots', 'phloem', 'grains', 'endosperm', 'xylem']
BOTANICAL_COMPARTMENTS_AT_AXIS_SCALE = BOTANICAL_ORGANS_AT_AXIS_SCALE + ['soil']


[docs] class BuildOutputs(object): """ The BuildOutputs class permits to ... from a :class:`MTG <openalea.mtg.mtg.MTG>`, and update the MTG and the dataframes shared between all models. """ def __init__(self, shared_mtg, morphogenesis_facade, growth_facade, gasexchange_facade, hydraulics_facade=None): """ :param openalea.mtg.mtg.MTG shared_mtg: The MTG shared between all models. :param integration.morphogenesis_facade.MorphogenesisFacade morphogenesis_facade: the facade of Morphogenesis :param integration.morphogenesis_facade.GrowthFacade growth_facade: the facade of Growth :param integration.gasexchange_facade.GasExchangeFacade gasexchange_facade: the facade of Gas-Exchange :param None or integration.hydraulics_facade.hydraulicsFacade hydraulics_facade: the facade of hydraulics """ self._shared_mtg = shared_mtg #: the MTG shared between all models AXES_VARIABLES.update(morphogenesis_facade._simulation.axis_inputs_outputs, growth_facade._simulation.axis_inputs_outputs) ELEMENTS_VARIABLES.update(morphogenesis_facade._simulation.element_inputs_outputs, gasexchange_facade._simulation.elements_inputs_outputs, growth_facade._simulation.element_inputs_outputs) HIDDENZONES_VARIABLES.update(morphogenesis_facade._simulation.hiddenzone_inputs_outputs, growth_facade._simulation.hiddenzone_inputs_outputs) ORGANS_VARIABLES.update(growth_facade._simulation.root_inputs_outputs) if hydraulics_facade is not None: AXES_VARIABLES.update(hydraulics_facade._simulation.AXES_RUN_VARIABLES) ELEMENTS_VARIABLES.update(hydraulics_facade._simulation.ELEMENTS_RUN_VARIABLES) HIDDENZONES_VARIABLES.update(hydraulics_facade._simulation.HIDDENZONE_RUN_VARIABLES) ORGANS_VARIABLES.update(hydraulics_facade._simulation.ORGANS_RUN_VARIABLES) SOILS_VARIABLES.update(hydraulics_facade._simulation.SOILS_RUN_VARIABLES) def _read_outputs_on_MTG(self): """ Extract the outputs of all sub-models from the MTG shared between all models. """ axes_dict = {} elements_dict = {} hiddenzones_dict = {} organs_dict = {} soils_dict = {} for mtg_plant_vid in self._shared_mtg.components_iter(self._shared_mtg.root): mtg_plant_index = int(self._shared_mtg.index(mtg_plant_vid)) # Axis scale for mtg_axis_vid in self._shared_mtg.components_iter(mtg_plant_vid): mtg_axis_label = self._shared_mtg.label(mtg_axis_vid) if isinstance(mtg_axis_label, bytes): mtg_axis_label = mtg_axis_label.decode('utf-8') mtg_axis_properties = self._shared_mtg.get_vertex_property(mtg_axis_vid) axis_id = (mtg_plant_index, mtg_axis_label) axis_dict = {} if '.' in mtg_axis_label: # todo: temporary, used to filter secondary tillers continue for axis_run_variable in AXES_VARIABLES: if axis_run_variable in mtg_axis_properties: # use the input from the MTG axis_dict[axis_run_variable] = mtg_axis_properties[axis_run_variable] axes_dict[axis_id] = axis_dict # Botanical organs at axis scale for botanical_organ_name in BOTANICAL_ORGANS_AT_AXIS_SCALE: if botanical_organ_name in mtg_axis_properties: organ_id = (mtg_plant_index, mtg_axis_label, botanical_organ_name) mtg_organ_properties = mtg_axis_properties[botanical_organ_name] organ_dict = {} for organ_run_variable in ORGANS_VARIABLES: if organ_run_variable in mtg_organ_properties: organ_dict[organ_run_variable] = mtg_organ_properties[organ_run_variable] organs_dict[organ_id] = organ_dict # Soil at axis scale if 'soil' in mtg_axis_properties: mtg_soil_properties = mtg_axis_properties['soil'] soil_dict = {} for soil_run_variable in SOILS_VARIABLES: if soil_run_variable in mtg_soil_properties: soil_dict[soil_run_variable] = mtg_soil_properties[soil_run_variable] soils_dict[axis_id] = soil_dict # Metamer scale for mtg_metamer_vid in self._shared_mtg.components_iter(mtg_axis_vid): mtg_metamer_index = int(self._shared_mtg.index(mtg_metamer_vid)) mtg_metamer_properties = self._shared_mtg.get_vertex_property(mtg_metamer_vid) if 'hiddenzone' in mtg_metamer_properties: hiddenzone_id = (mtg_plant_index, mtg_axis_label, mtg_metamer_index) mtg_hiddenzone_properties = mtg_metamer_properties['hiddenzone'] hiddenzone_dict = {} for hiddenzone_run_variable in HIDDENZONES_VARIABLES: if hiddenzone_run_variable in mtg_hiddenzone_properties: # use the input from the MTG hiddenzone_dict[hiddenzone_run_variable] = mtg_hiddenzone_properties[hiddenzone_run_variable] hiddenzones_dict[hiddenzone_id] = hiddenzone_dict # Photosynthetic organ scale for mtg_organ_vid in self._shared_mtg.components_iter(mtg_metamer_vid): mtg_organ_label = self._shared_mtg.label(mtg_organ_vid) # Element scale for mtg_element_vid in self._shared_mtg.components_iter(mtg_organ_vid): mtg_element_label = self._shared_mtg.label(mtg_element_vid) mtg_element_properties = self._shared_mtg.get_vertex_property(mtg_element_vid) if np.nan_to_num(self._shared_mtg.property('length').get(mtg_element_vid, 0)) == 0: continue element_dict = {} for morphogenesis_element_run_variable in ELEMENTS_VARIABLES: element_dict[morphogenesis_element_run_variable] = mtg_element_properties.get(morphogenesis_element_run_variable, np.nan) element_id = (mtg_plant_index, mtg_axis_label, mtg_metamer_index, mtg_organ_label, mtg_element_label) elements_dict[element_id] = element_dict return {'axes': axes_dict, 'elements': elements_dict, 'hiddenzones': hiddenzones_dict, 'organs': organs_dict, 'soils': soils_dict} @staticmethod def _to_dataframes(data_dict): """ Convert outputs from _read_outputs_on_MTG() which are dictionaries to Pandas dataframes. :param dict data_dict: outputs from _read_outputs_on_MTG() which are dictionaries :return: Five dataframes: axes, elements, hiddenzones, organs, soils :rtype: (pandas.DataFrame, pandas.DataFrame, pandas.DataFrame, pandas.DataFrame, pandas.DataFrame) """ dataframes_dict = {} for (current_key, current_topology_columns, current_outputs_names) in (('soils', SOILS_TOPOLOGY_COLUMNS, SOILS_VARIABLES), ('organs', ORGANS_TOPOLOGY_COLUMNS, ORGANS_VARIABLES), ('hiddenzones', HIDDENZONES_TOPOLOGY_COLUMNS, HIDDENZONES_VARIABLES), ('elements', ELEMENTS_TOPOLOGY_COLUMNS, ELEMENTS_VARIABLES), ('axes', AXES_TOPOLOGY_COLUMNS, AXES_VARIABLES)): current_data_dict = data_dict[current_key] current_ids_df = pd.DataFrame(current_data_dict.keys(), columns=current_topology_columns) current_data_df = pd.DataFrame(current_data_dict.values()) current_df = pd.concat([current_ids_df, current_data_df], axis=1) current_df.sort_values(by=current_topology_columns, inplace=True) current_columns_sorted = current_topology_columns + list(current_outputs_names) current_df = current_df.reindex(current_columns_sorted, axis=1, copy=False) # Reset dtypes current_df = pd.DataFrame(current_df.where(current_df.notnull(), np.nan).values.tolist(), columns=current_df.columns) current_df.reset_index(drop=True, inplace=True) dataframes_dict[current_key] = current_df return dataframes_dict['axes'], dataframes_dict['elements'], dataframes_dict['hiddenzones'], dataframes_dict['organs'], dataframes_dict['soils']
[docs] def build_outputs_df_from_MTG(self): outputs_dict = self._read_outputs_on_MTG() return self._to_dataframes(outputs_dict)