Source code for openalea.fspmwheat.growthwheat_facade

# -*- coding: latin-1 -*-

from openalea.growthwheat import converter, simulation, parameters
from openalea.fspmwheat import tools

"""
    fspmwheat.growthwheat_facade
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    The module :mod:`fspmwheat.growthwheat_facade` is a facade of the model GrowthWheat.

    This module permits to initialize and run the model GrowthWheat from a :class:`MTG <openalea.mtg.mtg.MTG>`
    in a convenient and transparent way, wrapping all the internal complexity of the model, and dealing
    with all the tedious initialization and conversion processes.

"""

LEAF_LABELS = ['blade', 'sheath']

EMERGED_GROWING_ORGAN_LABELS = ['StemElement', 'LeafElement1']
ELEMENT_LABELS = ['StemElement', 'LeafElement1', 'HiddenElement']

SHARED_AXES_INPUTS_OUTPUTS_INDEXES = ['plant', 'axis']

SHARED_ORGANS_INPUTS_OUTPUTS_INDEXES = ['plant', 'axis', 'organ']

SHARED_HIDDENZONES_INPUTS_OUTPUTS_INDEXES = ['plant', 'axis', 'metamer']

SHARED_ELEMENTS_INPUTS_OUTPUTS_INDEXES = ['plant', 'axis', 'metamer', 'organ', 'element']


[docs] class GrowthWheatFacade(object): """ The GrowthWheatFacade class permits to initialize, run the model GrowthWheat from a :class:`MTG <openalea.mtg.mtg.MTG>`, and update the MTG and the dataframes shared between all models. Use :meth:`run` to run the model. :Parameters: """ def __init__(self, shared_mtg, delta_t, model_hiddenzones_inputs_df, model_elements_inputs_df, model_roots_inputs_df, model_axes_inputs_df, shared_organs_inputs_outputs_df, shared_hiddenzones_inputs_outputs_df, shared_elements_inputs_outputs_df, shared_axes_inputs_outputs_df, update_parameters=None, update_shared_df=True): """ :param openalea.mtg.mtg.MTG shared_mtg: The MTG shared between all models. :param int delta_t: The delta between two runs, in seconds. :param pandas.DataFrame model_hiddenzones_inputs_df: the inputs of the model at hiddenzones scale. :param pandas.DataFrame model_elements_inputs_df: the inputs of the model at elements scale. :param pandas.DataFrame model_roots_inputs_df: the inputs of the model at roots scale. :param pandas.DataFrame model_axes_inputs_df: the inputs of the model at axes scale. :param pandas.DataFrame shared_organs_inputs_outputs_df: the dataframe of inputs and outputs at organs scale shared between all models. :param pandas.DataFrame shared_hiddenzones_inputs_outputs_df: the dataframe of inputs and outputs at hiddenzones scale shared between all models. :param pandas.DataFrame shared_elements_inputs_outputs_df: the dataframe of inputs and outputs at elements scale shared between all models. :param pandas.DataFrame shared_axes_inputs_outputs_df: the dataframe of inputs and outputs at axis scale shared between all models. :param dict update_parameters: A dictionary with the parameters to update, should have the form {'param1': value1, 'param2': value2, ...}. :param bool update_shared_df: If `True` update the shared dataframes at init and at each run (unless stated otherwise) """ if update_parameters is None: update_parameters = {} self._shared_mtg = shared_mtg #: the MTG shared between all models self._simulation = simulation.Simulation(delta_t=delta_t, update_parameters=update_parameters) #: the simulator to use to run the model all_growthwheat_inputs_dict = converter.from_dataframes(model_hiddenzones_inputs_df, model_elements_inputs_df, model_roots_inputs_df, model_axes_inputs_df) self._update_shared_MTG(all_growthwheat_inputs_dict['hiddenzone'], all_growthwheat_inputs_dict['elements'], all_growthwheat_inputs_dict['roots'], all_growthwheat_inputs_dict['axes']) self._shared_organs_inputs_outputs_df = shared_organs_inputs_outputs_df #: the dataframe at organs scale shared between all models self._shared_hiddenzones_inputs_outputs_df = shared_hiddenzones_inputs_outputs_df #: the dataframe at hiddenzones scale shared between all models self._shared_elements_inputs_outputs_df = shared_elements_inputs_outputs_df #: the dataframe at elements scale shared between all models self._shared_axes_inputs_outputs_df = shared_axes_inputs_outputs_df #: the dataframe at axis scale shared between all models self._update_shared_df = update_shared_df if self._update_shared_df: self._update_shared_dataframes(model_hiddenzones_inputs_df, model_elements_inputs_df, model_roots_inputs_df, model_axes_inputs_df)
[docs] def run(self, postflowering_stages=False, update_shared_df=None): """ Run the model and update the MTG and the dataframes shared between all models. :param bool postflowering_stages: if True the model will calculate root growth with the parameters calibrated for post flowering stages :param bool update_shared_df: if 'True', update the shared dataframes at this time step. """ self._initialize_model() self._simulation.run(postflowering_stages) self._update_shared_MTG(self._simulation.outputs['hiddenzone'], self._simulation.outputs['elements'], self._simulation.outputs['roots'], self._simulation.outputs['axes']) if update_shared_df or (update_shared_df is None and self._update_shared_df): growthwheat_hiddenzones_outputs_df, growthwheat_elements_outputs_df, growthwheat_roots_outputs_df, growthwheat_axes_outputs_df = converter.to_dataframes(self._simulation.outputs) self._update_shared_dataframes(growthwheat_hiddenzones_outputs_df, growthwheat_elements_outputs_df, growthwheat_roots_outputs_df, growthwheat_axes_outputs_df)
def _initialize_model(self): """ Initialize the inputs of the model from the MTG shared between all models. """ all_growthwheat_hiddenzones_inputs_dict = {} all_growthwheat_elements_inputs_dict = {} all_growthwheat_roots_inputs_dict = {} all_growthwheat_axes_inputs_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)) for mtg_axis_vid in self._shared_mtg.components_iter(mtg_plant_vid): mtg_axis_label = self._shared_mtg.label(mtg_axis_vid) if mtg_axis_label != 'MS': continue mtg_axis_properties = self._shared_mtg.get_vertex_property(mtg_axis_vid) axis_id = (mtg_plant_index, mtg_axis_label) if set(mtg_axis_properties).issuperset(simulation.AXIS_INPUTS): growthwheat_axis_inputs_dict = {} for growthwheat_axis_input_name in simulation.AXIS_INPUTS: growthwheat_axis_inputs_dict[growthwheat_axis_input_name] = mtg_axis_properties[growthwheat_axis_input_name] all_growthwheat_axes_inputs_dict[axis_id] = growthwheat_axis_inputs_dict # Roots if 'roots' in mtg_axis_properties: roots_id = (mtg_plant_index, mtg_axis_label, 'roots') mtg_roots_properties = mtg_axis_properties['roots'] if set(mtg_roots_properties).issuperset(simulation.ROOT_INPUTS): growthwheat_roots_inputs_dict = {} for growthwheat_roots_input_name in simulation.ROOT_INPUTS: growthwheat_roots_inputs_dict[growthwheat_roots_input_name] = mtg_roots_properties[growthwheat_roots_input_name] all_growthwheat_roots_inputs_dict[roots_id] = growthwheat_roots_inputs_dict 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'] if set(mtg_hiddenzone_properties).issuperset(simulation.HIDDENZONE_INPUTS): # Initial values are set by elongwheat growthwheat_hiddenzone_inputs_dict = {} for growthwheat_hiddenzone_input_name in simulation.HIDDENZONE_INPUTS: growthwheat_hiddenzone_inputs_dict[growthwheat_hiddenzone_input_name] = mtg_hiddenzone_properties[growthwheat_hiddenzone_input_name] all_growthwheat_hiddenzones_inputs_dict[hiddenzone_id] = growthwheat_hiddenzone_inputs_dict # We take only the elements of growing metamers ie. the ones with hiddenzones for mtg_organ_vid in self._shared_mtg.components_iter(mtg_metamer_vid): mtg_organ_label = self._shared_mtg.label(mtg_organ_vid) for mtg_element_vid in self._shared_mtg.components_iter(mtg_organ_vid): mtg_element_label = self._shared_mtg.label(mtg_element_vid) element_id = (mtg_plant_index, mtg_axis_label, mtg_metamer_index, mtg_organ_label, mtg_element_label) mtg_element_properties = self._shared_mtg.get_vertex_property(mtg_element_vid) if mtg_element_label in ELEMENT_LABELS and \ mtg_element_properties.get('length', 0) > 0: # Note : ADEL puts length to positive value after updates even for HiddenElement. growthwheat_element_inputs_dict = {} # Exclude the HiddenElement appart from remobilization cases remobilisation = False if mtg_element_label == 'HiddenElement': if growthwheat_hiddenzone_inputs_dict['leaf_is_remobilizing'] or growthwheat_hiddenzone_inputs_dict['internode_is_remobilizing']: remobilisation = True else: continue for growthwheat_element_input_name in simulation.ELEMENT_INPUTS: mtg_element_input = mtg_element_properties.get(growthwheat_element_input_name) if mtg_element_input is None: mtg_element_input = parameters.OrganInit().__dict__[growthwheat_element_input_name] growthwheat_element_inputs_dict[growthwheat_element_input_name] = mtg_element_input if remobilisation: # Needed later on for CN Wheat calculation. TODO: Should it be in elongwheat_facade instead ? (MG) growthwheat_element_inputs_dict['green_area'] = mtg_element_properties.get('area') all_growthwheat_elements_inputs_dict[element_id] = growthwheat_element_inputs_dict self._simulation.initialize({'hiddenzone': all_growthwheat_hiddenzones_inputs_dict, 'elements': all_growthwheat_elements_inputs_dict, 'roots': all_growthwheat_roots_inputs_dict, 'axes': all_growthwheat_axes_inputs_dict}) def _update_shared_MTG(self, all_growthwheat_hiddenzones_data_dict, all_growthwheat_elements_data_dict, all_growthwheat_roots_data_dict, all_growthwheat_axes_data_dict): """ Update the MTG shared between all models from the inputs or the outputs of the model. :param dict all_growthwheat_hiddenzones_data_dict: Growth-Wheat outputs at hidden zone scale :param dict all_growthwheat_elements_data_dict: Growth-Wheat outputs at element scale :param dict all_growthwheat_roots_data_dict: Growth-Wheat outputs at root scale :param dict all_growthwheat_axes_data_dict: Growth-Wheat outputs at axis scale """ # add the properties if needed mtg_property_names = self._shared_mtg.property_names() if 'roots' not in mtg_property_names: self._shared_mtg.add_property('roots') for growthwheat_data_name in set(simulation.HIDDENZONE_INPUTS_OUTPUTS + simulation.ELEMENT_INPUTS_OUTPUTS): if growthwheat_data_name not in mtg_property_names: self._shared_mtg.add_property(growthwheat_data_name) # update the properties of the MTG 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)) for mtg_axis_vid in self._shared_mtg.components_iter(mtg_plant_vid): mtg_axis_label = self._shared_mtg.label(mtg_axis_vid) axis_id = (mtg_plant_index, mtg_axis_label) if mtg_axis_label != 'MS': continue growthwheat_axis_data_dict = all_growthwheat_axes_data_dict[axis_id] for axis_data_name, axis_data_value in growthwheat_axis_data_dict.items(): self._shared_mtg.property(axis_data_name)[mtg_axis_vid] = axis_data_value roots_id = (mtg_plant_index, mtg_axis_label, 'roots') if roots_id in all_growthwheat_roots_data_dict: growthwheat_roots_data_dict = all_growthwheat_roots_data_dict[roots_id] mtg_axis_properties = self._shared_mtg.get_vertex_property(mtg_axis_vid) if 'roots' not in mtg_axis_properties: self._shared_mtg.property('roots')[mtg_axis_vid] = {} for roots_data_name, roots_data_value in growthwheat_roots_data_dict.items(): self._shared_mtg.property('roots')[mtg_axis_vid][roots_data_name] = roots_data_value #: 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)) hiddenzone_id = (mtg_plant_index, mtg_axis_label, mtg_metamer_index) if hiddenzone_id in all_growthwheat_hiddenzones_data_dict: growthwheat_hiddenzone_data_dict = all_growthwheat_hiddenzones_data_dict[hiddenzone_id] mtg_metamer_properties = self._shared_mtg.get_vertex_property(mtg_metamer_vid) if 'hiddenzone' not in mtg_metamer_properties: # MG : when is it used ? self._shared_mtg.property('hiddenzone')[mtg_metamer_vid] = {} for hiddenzone_data_name, hiddenzone_data_value in growthwheat_hiddenzone_data_dict.items(): self._shared_mtg.property('hiddenzone')[mtg_metamer_vid][hiddenzone_data_name] = hiddenzone_data_value elif 'hiddenzone' in self._shared_mtg.get_vertex_property(mtg_metamer_vid): # remove the 'hiddenzone' property from this metamer del self._shared_mtg.property('hiddenzone')[mtg_metamer_vid] #: 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) element_id = (mtg_plant_index, mtg_axis_label, mtg_metamer_index, mtg_organ_label, mtg_element_label) if element_id in all_growthwheat_elements_data_dict: growthwheat_element_data_dict = all_growthwheat_elements_data_dict[element_id] for element_data_name, element_data_value in growthwheat_element_data_dict.items(): self._shared_mtg.property(element_data_name)[mtg_element_vid] = element_data_value def _update_shared_dataframes(self, growthwheat_hiddenzones_data_df, growthwheat_elements_data_df, growthwheat_roots_data_df, growthwheat_axes_data_df): """ Update the dataframes shared between all models from the inputs dataframes or the outputs dataframes of the model. :param pandas.DataFrame growthwheat_hiddenzones_data_df: Growth-Wheat shared dataframe at hidden zone scale :param pandas.DataFrame growthwheat_elements_data_df: Growth-Wheat shared dataframe at element scale :param pandas.DataFrame growthwheat_roots_data_df: Growth-Wheat shared dataframe at roots scale :param pandas.DataFrame growthwheat_axes_data_df: Growth-Wheat shared dataframe at axis scale """ for growthwheat_data_df, \ shared_inputs_outputs_indexes, \ shared_inputs_outputs_df in ((growthwheat_hiddenzones_data_df, SHARED_HIDDENZONES_INPUTS_OUTPUTS_INDEXES, self._shared_hiddenzones_inputs_outputs_df), (growthwheat_elements_data_df, SHARED_ELEMENTS_INPUTS_OUTPUTS_INDEXES, self._shared_elements_inputs_outputs_df), (growthwheat_roots_data_df, SHARED_ORGANS_INPUTS_OUTPUTS_INDEXES, self._shared_organs_inputs_outputs_df), (growthwheat_axes_data_df, SHARED_AXES_INPUTS_OUTPUTS_INDEXES, self._shared_axes_inputs_outputs_df)): if growthwheat_data_df is growthwheat_roots_data_df: growthwheat_data_df = growthwheat_data_df.copy() growthwheat_data_df.loc[:, 'organ'] = 'roots' tools.combine_dataframes_inplace(growthwheat_data_df, shared_inputs_outputs_indexes, shared_inputs_outputs_df)