Source code for openalea.cnwgrass.integration.morphogenesis_facade

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

import numpy as np

from openalea.cnwgrass.morphogenesis import converter
from openalea.cnwgrass.morphogenesis import simulation
from openalea.cnwgrass.integration import tools

"""
    integration.morphogenesis_facade
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~

    The module :mod:`integration.morphogenesis_facade` is a facade of the model Morphogenesis.

    This module permits to initialize and run the model Morphogenesis 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.

"""

SHARED_AXES_INPUTS_OUTPUTS_INDEXES = ['plant', 'axis']

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

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

ELEMENT_TYPES = ('HiddenElement', 'StemElement', 'LeafElement1')

ELEMENTS_DATA_FROM_ORGAN_DATA = {'width', 'diameter'}


[docs] class MorphogenesisFacade(object): """ The MorphogenesisFacade class permits to initialize, run the model Morphogenesis 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. """ def __init__(self, shared_mtg, delta_t, model_axes_inputs_df, model_hiddenzones_inputs_df, model_elements_inputs_df, shared_axes_inputs_outputs_df, shared_hiddenzones_inputs_outputs_df, shared_elements_inputs_outputs_df, geometrical_model, phytoT=None, hydraulics=False, optimal_growth_option=False, option_static=False, 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_axes_inputs_df: the inputs of the model at axes scale. :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 shared_axes_inputs_outputs_df: the dataframe of inputs and outputs at axes 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 alinea.adel.adel_dynamic.AdelWheatDyn geometrical_model: The model which deals with geometry. This model must implement a method `add_metamer(mtg, phytoT, plant_index, axis_label)` to add a metamer to a specific axis of a plant in an MTG. :param pandas.DataFrame phytoT: a dataframe generated by adel model :param pandas.DataFrame phytoT: a csv file generated by adel model :param bool hydraulics: if True the model will assume the coupling to the turgor-driven growth model :param bool optimal_growth_option: if True the model will assume optimal growth conditions :param bool option_static: Whether the model should be run for a static plant architecture :param None or 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) """ self._shared_mtg = shared_mtg #: the MTG shared between all models self._simulation = simulation.Simulation(delta_t=delta_t, hydraulics=hydraulics, optimal_growth_option=optimal_growth_option, update_parameters=update_parameters) #: the simulator to use to run the model self.geometrical_model = geometrical_model #: the model which deals with geometry self._phytoT = phytoT #: dataframe generated by Adel and needed by the method add_metamer() self.option_static = option_static model_hiddenzones_inputs_df = model_hiddenzones_inputs_df[converter.HIDDENZONE_TOPOLOGY_COLUMNS + [i for i in self._simulation.hiddenzone_inputs if i in model_hiddenzones_inputs_df.columns]].copy() model_elements_inputs_df = model_elements_inputs_df[converter.ELEMENT_TOPOLOGY_COLUMNS + [i for i in self._simulation.element_inputs if i in model_elements_inputs_df.columns]].copy() model_axes_inputs_df = model_axes_inputs_df[converter.AXIS_TOPOLOGY_COLUMNS + [i for i in self._simulation.axis_inputs if i in model_axes_inputs_df.columns]].copy() all_morphogenesis_inputs_dict = converter.from_dataframes(model_hiddenzones_inputs_df, model_elements_inputs_df, model_axes_inputs_df) self._update_shared_MTG(all_morphogenesis_inputs_dict['hiddenzone'], all_morphogenesis_inputs_dict['elements'], all_morphogenesis_inputs_dict['axes'], option_static) self._shared_axes_inputs_outputs_df = shared_axes_inputs_outputs_df #: the dataframe at axes 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._update_shared_df = update_shared_df if self._update_shared_df: self._update_shared_dataframes(model_hiddenzones_inputs_df, model_elements_inputs_df, model_axes_inputs_df) self.seed_is_moistened = True
[docs] def run(self, Tair, Tsoil, Zsowing=0.025, update_shared_df=None): """ Run the model and update the MTG and the dataframes shared between all models. :param float Tair: Air temperature at t (degree Celsius) :param float Tsoil: Soil temperature at t (degree Celsius) :param float Zsowing: Sowing depth (m) :param bool update_shared_df: if 'True', update the shared dataframes at this time step. """ self._initialize_model() if self.seed_is_moistened: self._simulation.run(Tair, Tsoil, Zsowing) self._update_shared_MTG(self._simulation.outputs['hiddenzone'], self._simulation.outputs['elements'], self._simulation.outputs['axes'], self.option_static) if update_shared_df or (update_shared_df is None and self._update_shared_df): morphogenesis_hiddenzones_outputs_df, morphogenesis_elements_outputs_df, morphogenesis_SAM_temperature_outputs_df = converter.to_dataframes(self._simulation.outputs, self._simulation.axis_outputs, self._simulation.hiddenzone_outputs, self._simulation.element_outputs) self._update_shared_dataframes(morphogenesis_hiddenzones_outputs_df, morphogenesis_elements_outputs_df, morphogenesis_SAM_temperature_outputs_df)
def _initialize_model(self): """ Initialize the inputs of the model from the MTG shared between all models. """ all_morphogenesis_hiddenzones_dict = {} all_morphogenesis_elements_dict = {} all_morphogenesis_SAM_temperature_dict = {} all_morphogenesis_length_dict = {} morphogenesis_cumulated_internode_length = {} 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): if isinstance(self._shared_mtg.label(mtg_axis_vid), str): mtg_axis_label = self._shared_mtg.label(mtg_axis_vid) elif isinstance(self._shared_mtg.label(mtg_axis_vid), bytes): mtg_axis_label = self._shared_mtg.label(mtg_axis_vid).decode('UTF-8') else: raise TypeError('Axis label type not recognized') mtg_axis_properties = self._shared_mtg.get_vertex_property(mtg_axis_vid) if 'endosperm' in mtg_axis_properties and mtg_axis_properties['endosperm']['moistening'] < 1: self.seed_is_moistened = False continue elif mtg_axis_label =='MS': self.seed_is_moistened = True axis_id = (mtg_plant_index, mtg_axis_label) morphogenesis_SAM_temperature_inputs_dict = {} is_valid_axis = True for axis_input_name in self._simulation.axis_inputs: if axis_input_name in mtg_axis_properties: # use the input from the MTG morphogenesis_SAM_temperature_inputs_dict[axis_input_name] = mtg_axis_properties[axis_input_name] else: is_valid_axis = False break if is_valid_axis: all_morphogenesis_SAM_temperature_dict[axis_id] = morphogenesis_SAM_temperature_inputs_dict # Complete dict of lengths all_morphogenesis_length_dict[axis_id] = {} for i in range(mtg_axis_properties['nb_leaves']): all_morphogenesis_length_dict[axis_id][i + 1] = {'sheath': [], 'cumulated_internode': []} # For coleoptile phyto0_id = self._shared_mtg.components_at_scale(mtg_axis_vid, scale=3)[0] if self._shared_mtg.label(phyto0_id) == 'metamer0': all_morphogenesis_length_dict[axis_id][0] = {'sheath': [], 'cumulated_internode': []} morphogenesis_cumulated_internode_length[axis_id] = [] # 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)) morphogenesis_hiddenzone_data_from_mtg_organs_data = {} # TODO: still useful? 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'] morphogenesis_hiddenzone_inputs_dict = {} is_valid_hiddenzone = True for hiddenzone_input_name in self._simulation.hiddenzone_inputs: if hiddenzone_input_name in mtg_hiddenzone_properties: # use the input from the MTG morphogenesis_hiddenzone_inputs_dict[hiddenzone_input_name] = mtg_hiddenzone_properties[hiddenzone_input_name] elif hiddenzone_input_name in morphogenesis_hiddenzone_data_from_mtg_organs_data: morphogenesis_hiddenzone_inputs_dict[hiddenzone_input_name] = morphogenesis_hiddenzone_data_from_mtg_organs_data[hiddenzone_input_name] else: print('Invalid hiddenzone {}: input {} is missing'.format(hiddenzone_id, hiddenzone_input_name)) is_valid_hiddenzone = False break if is_valid_hiddenzone: all_morphogenesis_hiddenzones_dict[hiddenzone_id] = morphogenesis_hiddenzone_inputs_dict # Complete dict of lengths if mtg_metamer_index == 0: # Not emerged coleoptile all_morphogenesis_length_dict[axis_id][mtg_metamer_index]['sheath'].append(mtg_hiddenzone_properties['leaf_L']) if mtg_hiddenzone_properties['leaf_is_emerged'] and mtg_hiddenzone_properties['leaf_is_growing']: growing_sheath_length = max(0, mtg_hiddenzone_properties['leaf_L'] - mtg_hiddenzone_properties['lamina_Lmax']) # TODO: should be moved elsewhere all_morphogenesis_length_dict[axis_id][mtg_metamer_index]['sheath'].append(growing_sheath_length) if mtg_hiddenzone_properties['internode_is_growing']: morphogenesis_cumulated_internode_length[axis_id].append(mtg_hiddenzone_properties['internode_L']) all_morphogenesis_length_dict[axis_id][mtg_metamer_index]['cumulated_internode'].extend(morphogenesis_cumulated_internode_length[axis_id]) else: internode_organ_vid = self._shared_mtg.components_at_scale(mtg_metamer_vid, 4)[0] # assert self._shared_mtg.label(internode_organ_vid) == 'internode' internode_element_labels = [self._shared_mtg.label(internode_element) for internode_element in self._shared_mtg.components_at_scale(internode_organ_vid, 5)] if internode_element_labels == ['baseElement', 'topElement']: all_morphogenesis_length_dict[axis_id][mtg_metamer_index]['cumulated_internode'].extend(morphogenesis_cumulated_internode_length[axis_id]) # 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) mtg_organ_properties = self._shared_mtg.get_vertex_property(mtg_organ_vid) if np.nan_to_num(self._shared_mtg.property('length').get(mtg_organ_vid, 0)) == 0: continue if mtg_organ_label == 'blade': morphogenesis_hiddenzone_data_from_mtg_organs_data['lamina_Lmax'] = mtg_organ_properties['shape_mature_length'] if not self._simulation.hydraulics: morphogenesis_hiddenzone_data_from_mtg_organs_data['leaf_Wmax'] = mtg_organ_properties['shape_max_width'] # 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 if np.isnan(mtg_element_properties.get('age', 0)): mtg_element_properties['age'] = 0. if set(mtg_element_properties).issuperset(self._simulation.element_inputs): morphogenesis_element_inputs_dict = {} for morphogenesis_element_input_name in self._simulation.element_inputs: morphogenesis_element_inputs_dict[morphogenesis_element_input_name] = mtg_element_properties[morphogenesis_element_input_name] element_id = (mtg_plant_index, mtg_axis_label, mtg_metamer_index, mtg_organ_label, mtg_element_label) all_morphogenesis_elements_dict[element_id] = morphogenesis_element_inputs_dict # Complete dict of lengths if mtg_organ_label == 'sheath' and not mtg_element_properties['is_growing']: all_morphogenesis_length_dict[axis_id][mtg_metamer_index]['sheath'].append(mtg_element_properties['length']) elif mtg_organ_label == 'internode' and not mtg_element_properties['is_growing']: # This algo won't copy previous internode length for a phytomer without internode morphogenesis_cumulated_internode_length[axis_id].append(mtg_element_properties['length']) if all_morphogenesis_length_dict[axis_id][mtg_metamer_index]['cumulated_internode'] is None: # if empty for that phytomer, the list of all phytomer lengths is all_morphogenesis_length_dict[axis_id][mtg_metamer_index]['cumulated_internode'].extend(morphogenesis_cumulated_internode_length[axis_id]) else: # only the last internode length is written (case of organs with hidden and visible part) all_morphogenesis_length_dict[axis_id][mtg_metamer_index]['cumulated_internode'].append(mtg_element_properties['length']) self._simulation.initialize({'hiddenzone': all_morphogenesis_hiddenzones_dict, 'elements': all_morphogenesis_elements_dict, 'axes': all_morphogenesis_SAM_temperature_dict, 'sheath_internode_lengths': all_morphogenesis_length_dict}) def _update_shared_MTG(self, all_morphogenesis_hiddenzones_data_dict, all_morphogenesis_elements_data_dict, all_morphogenesis_axes_data_dict, option_static=False): """ Update the MTG shared between all models from the inputs or the outputs of the model. :param dict all_morphogenesis_hiddenzones_data_dict: Morphogenesis outputs at hidden zone scale :param dict all_morphogenesis_elements_data_dict: Morphogenesis outputs at element scale :param dict all_morphogenesis_axes_data_dict: Morphogenesis outputs at axes scale :param bool option_static: Whether the model should be run for a static plant architecture """ # add the properties if needed mtg_property_names = self._shared_mtg.property_names() for morphogenesis_data_name in set(self._simulation.hiddenzone_inputs_outputs + self._simulation.element_inputs_outputs + self._simulation.axis_inputs_outputs): if morphogenesis_data_name not in mtg_property_names: self._shared_mtg.add_property(morphogenesis_data_name) if 'hiddenzone' not in mtg_property_names: self._shared_mtg.add_property('hiddenzone') # add new metamer(s) if not option_static: axis_to_metamers_mapping = {} for metamer_id in sorted(all_morphogenesis_elements_data_dict.keys()): axis_id = (metamer_id[0], metamer_id[1]) if axis_id not in axis_to_metamers_mapping: axis_to_metamers_mapping[axis_id] = [] axis_to_metamers_mapping[axis_id].append(metamer_id[:3]) for metamer_id in sorted(all_morphogenesis_hiddenzones_data_dict.keys()): axis_id = (metamer_id[0], metamer_id[1]) if axis_id not in axis_to_metamers_mapping: axis_to_metamers_mapping[axis_id] = [] axis_to_metamers_mapping[axis_id].append(metamer_id) 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) mtg_metamer_ids = set([(mtg_plant_index, mtg_axis_label, int(self._shared_mtg.index(mtg_metamer_vid))) for mtg_metamer_vid in self._shared_mtg.components_iter(mtg_axis_vid)]) if (mtg_plant_index, mtg_axis_label) not in axis_to_metamers_mapping: continue new_metamer_ids = set(axis_to_metamers_mapping[(mtg_plant_index, mtg_axis_label)]).difference(mtg_metamer_ids) for _ in new_metamer_ids: self.geometrical_model.add_metamer(self._shared_mtg, self._phytoT, plant=mtg_plant_index, axe=mtg_axis_label) # Add new metamer with only top and base element # default value to age property in order to run update_geometry() for mtg_organ_vid in self._shared_mtg.components_at_scale(mtg_axis_vid, 4): if self._shared_mtg.property('label')[mtg_organ_vid] == 'blade': self._shared_mtg.property('age')[mtg_organ_vid] = self._shared_mtg.property('age').get(mtg_organ_vid, 0) self.geometrical_model.update_geometry(self._shared_mtg) # Add HiddenElement and Stem/Leaf Element # 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)) # Axis scale for mtg_axis_vid in self._shared_mtg.components_iter(mtg_plant_vid): if isinstance(self._shared_mtg.label(mtg_axis_vid), str): mtg_axis_label = self._shared_mtg.label(mtg_axis_vid) elif isinstance(self._shared_mtg.label(mtg_axis_vid), bytes): mtg_axis_label = self._shared_mtg.label(mtg_axis_vid).decode('UTF-8') else: raise TypeError('Axis label type not recognized') axis_id = (mtg_plant_index, mtg_axis_label) if axis_id in all_morphogenesis_axes_data_dict: morphogenesis_axis_data_dict = all_morphogenesis_axes_data_dict[axis_id] for axis_data_name, axis_data_value in morphogenesis_axis_data_dict.items(): self._shared_mtg.property(axis_data_name)[mtg_axis_vid] = axis_data_value if option_static: continue # 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) mtg_organs_data_from_morphogenesis_hiddenzone_data = {} if hiddenzone_id in all_morphogenesis_hiddenzones_data_dict: morphogenesis_hiddenzone_data_dict = all_morphogenesis_hiddenzones_data_dict[hiddenzone_id] mtg_metamer_properties = self._shared_mtg.get_vertex_property(mtg_metamer_vid) if 'hiddenzone' not in mtg_metamer_properties: self._shared_mtg.property('hiddenzone')[mtg_metamer_vid] = {} for hiddenzone_data_name, hiddenzone_data_value in morphogenesis_hiddenzone_data_dict.items(): self._shared_mtg.property('hiddenzone')[mtg_metamer_vid][hiddenzone_data_name] = hiddenzone_data_value if hiddenzone_data_name in ('lamina_Lmax', 'leaf_Wmax'): mtg_organs_data_from_morphogenesis_hiddenzone_data[hiddenzone_data_name] = hiddenzone_data_value # To be stored at organ scale (see below) 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) if mtg_organ_label not in ('blade', 'sheath', 'internode'): continue organ_id = (mtg_plant_index, mtg_axis_label, mtg_metamer_index, mtg_organ_label) mtg_organ_properties = self._shared_mtg.get_vertex_property(mtg_organ_vid) mtg_elements_data_from_organ_data = {} # Extract data from organs to be stored at element scale (see below) for organ_data_name in ELEMENTS_DATA_FROM_ORGAN_DATA: if organ_data_name in mtg_organ_properties.keys(): mtg_elements_data_from_organ_data[organ_data_name] = mtg_organ_properties[organ_data_name] # Data from hidden zones to be stored at organ scale if mtg_organ_label == 'blade': if len(mtg_organs_data_from_morphogenesis_hiddenzone_data) != 0: self._shared_mtg.property('shape_mature_length')[mtg_organ_vid] = mtg_organs_data_from_morphogenesis_hiddenzone_data['lamina_Lmax'] if not self._simulation.hydraulics: self._shared_mtg.property('shape_max_width')[mtg_organ_vid] = mtg_organs_data_from_morphogenesis_hiddenzone_data['leaf_Wmax'] else: blade_id = organ_id + ('LeafElement1',) if blade_id in all_morphogenesis_elements_data_dict.keys(): self._shared_mtg.property('shape_mature_length')[mtg_organ_vid] = all_morphogenesis_elements_data_dict[organ_id + ('LeafElement1',)]['length'] if not self._simulation.hydraulics: self._shared_mtg.property('shape_max_width')[mtg_organ_vid] = all_morphogenesis_elements_data_dict[organ_id + ('LeafElement1',)]['Wmax'] # Update of organ scale from elements dataframe # Organ length should be correct in order to get correct lengths at both organ and element scales after performing the update_geometry() organ_visible_length = all_morphogenesis_elements_data_dict.get(organ_id + ('LeafElement1',), {}).get('length', 0.) + \ all_morphogenesis_elements_data_dict.get(organ_id + ('StemElement',), {}).get('length', 0.) self._shared_mtg.property('visible_length')[mtg_organ_vid] = organ_visible_length self._shared_mtg.property('age')[mtg_organ_vid] = all_morphogenesis_elements_data_dict.get(organ_id + ('LeafElement1',), {}).get('age', 0.) organ_hidden_length = all_morphogenesis_elements_data_dict.get(organ_id + ('HiddenElement',), {}).get('length', 0.) total_organ_length = organ_visible_length + organ_hidden_length self._shared_mtg.property('length')[mtg_organ_vid] = total_organ_length # Element scale. Most of the code is temporary, waiting for an update of adel in order that the model could update organ properties from elements. mtg_element_labels = {} for actual_element_vid in self._shared_mtg.components_iter(mtg_organ_vid): actual_element_label = self._shared_mtg.label(actual_element_vid) mtg_element_labels[actual_element_label] = actual_element_vid potential_element_ids = [organ_id + (element_type,) for element_type in ELEMENT_TYPES] for element_id in potential_element_ids: element_label = element_id[-1] if element_id in all_morphogenesis_elements_data_dict: morphogenesis_element_data_dict = all_morphogenesis_elements_data_dict[element_id] # Element just created by morphogenesis but not yet in MTG if element_label not in mtg_element_labels.keys(): # MG : This case does not seem to be usefull if element_label in ('StemElement', 'LeafElement1'): self._shared_mtg.property('visible_length')[mtg_organ_vid] = morphogenesis_element_data_dict['length'] self.geometrical_model.update_geometry(self._shared_mtg) # Update element scale based on organ infos mtg_element_vid = [vid for vid in self._shared_mtg.components_iter(mtg_organ_vid) if self._shared_mtg.label(vid) == element_label][0] # if self._shared_mtg.label(vid) in ('StemElement', 'LeafElement1') for element_data_name, element_data_value in morphogenesis_element_data_dict.items(): self._shared_mtg.property(element_data_name)[mtg_element_vid] = element_data_value # Already existent element else: mtg_element_vid = mtg_element_labels[element_label] for element_data_name, element_data_value in morphogenesis_element_data_dict.items(): self._shared_mtg.property(element_data_name)[mtg_element_vid] = element_data_value # Put some properties from organ scale at element scale for organ_data_name in mtg_elements_data_from_organ_data: self._shared_mtg.property(organ_data_name)[mtg_element_vid] = mtg_elements_data_from_organ_data[organ_data_name] def _update_shared_dataframes(self, morphogenesis_hiddenzones_data_df, morphogenesis_elements_data_df, morphogenesis_axes_data_df): """ Update the dataframes shared between all models from the inputs dataframes or the outputs dataframes of the model. :param pandas.DataFrame morphogenesis_hiddenzones_data_df: Morphogenesis shared dataframe at hidden zone scale :param pandas.DataFrame morphogenesis_elements_data_df: Morphogenesis shared dataframe at element scale :param pandas.DataFrame morphogenesis_axes_data_df: Morphogenesis shared dataframe at axes scale """ for morphogenesis_data_df, \ shared_inputs_outputs_indexes, \ shared_inputs_outputs_df in ((morphogenesis_hiddenzones_data_df, SHARED_HIDDENZONES_INPUTS_OUTPUTS_INDEXES, self._shared_hiddenzones_inputs_outputs_df), (morphogenesis_elements_data_df, SHARED_ELEMENTS_INPUTS_OUTPUTS_INDEXES, self._shared_elements_inputs_outputs_df), (morphogenesis_axes_data_df, SHARED_AXES_INPUTS_OUTPUTS_INDEXES, self._shared_axes_inputs_outputs_df)): tools.combine_dataframes_inplace(morphogenesis_data_df, shared_inputs_outputs_indexes, shared_inputs_outputs_df)