Source code for openalea.farquharwheat.simulation

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

from __future__ import division  # use "//" to do integer division

from openalea.farquharwheat import model
from openalea.farquharwheat import parameters

"""
    farquharwheat.simulation
    ~~~~~~~~~~~~~~~~~~~~~~~~

    The module :mod:`farquharwheat.simulation` is the front-end to run the Farquhar-Wheat :mod:`model <farquharwheat.model>`.

"""


[docs] class SimulationError(Exception): pass
[docs] class SimulationInputsError(SimulationError): pass
[docs] class Simulation(object): """The Simulation class permits to initialize and run a simulation. """ def __init__(self, update_parameters=None): #: The inputs of Farquhar-Wheat. #: #: `inputs` is a dictionary of dictionaries: #: {(plant_index, axis_label, metamer_index, organ_label, element_label): {element_input_name: element_input_value, ...}, ...} #: See :meth:`Model.run <farquharwheat.model.run>` #: for more information about the inputs. self.inputs = {} #: The outputs of Farquhar-Wheat. #: #: `outputs` is a dictionary of dictionaries: #: {(plant_index, axis_label, metamer_index, organ_label, element_label): {element_output_name: element_output_value, ...}, ...} #: See :meth:`Model.run <farquharwheat.model.run>` #: for more information about the outputs. self.outputs = {} #: Update parameters if specified if update_parameters: parameters.__dict__.update(update_parameters)
[docs] def initialize(self, inputs): """ Initialize :attr:`inputs` from `inputs`. :param dict inputs: Dictionary of two dictionaries : - `elements` : The inputs by element. - `axes` : The inputs by axis. `inputs` must be a dictionary with the same structure as :attr:`inputs`. See :meth:`Model.run <farquharwheat.model.run>` for more information about the inputs. """ self.inputs.clear() self.inputs.update(inputs)
[docs] def run(self, Ta, ambient_CO2, RH, Ur): """ Compute Farquhar variables for each element in :attr:`inputs` and put the results in :attr:`outputs`. :param float Ta: air temperature at t (degree Celsius) :param float ambient_CO2: air CO2 at t (µmol mol-1) :param float RH: relative humidity at t (decimal fraction) :param float Ur: wind speed at the top of the canopy at t (m s-1) """ self.outputs.update({inputs_type: {} for inputs_type in self.inputs['elements'].keys()}) for (element_id, element_inputs) in self.inputs['elements'].items(): axis_id = element_id[:2] organ_label = element_id[3] axe_label = axis_id[1] if axe_label != 'MS': # Calculation only for the main stem continue # In case it is an HiddenElement, we need temperature calculation. Cases of Visible Element without geomtry proprety (because too small) don't have photosynthesis calculation neither. if element_inputs['height'] is None: Ag, An, Rd, Tr, gs = 0., 0., 0., 0., 0. Ts = self.inputs['axes'][axis_id]['SAM_temperature'] else: PARa = element_inputs['PARa'] #: Amount of absorbed PAR per unit area (µmol m-2 s-1) height_canopy = self.inputs['axes'][axis_id]['height_canopy'] if parameters.SurfacicProteins: surfacic_photosynthetic_proteins = model.calculate_surfacic_photosynthetic_proteins(element_inputs['proteins'], element_inputs['green_area']) surfacic_nitrogen = model.calculate_surfacic_nonstructural_nitrogen_Farquhar(surfacic_photosynthetic_proteins) else: surfacic_nitrogen = model.calculate_surfacic_nitrogen(element_inputs['nitrates'], element_inputs['amino_acids'], element_inputs['proteins'], element_inputs['Nstruct'], element_inputs['green_area']) surfacic_NSC = model.calculate_surfacic_WSC(element_inputs['sucrose'], element_inputs['starch'], element_inputs['fructan'], element_inputs['green_area']) if not parameters.prim_scale: #: Computation at organ scale Ag, An, Rd, Tr, Ts, gs = model.run(surfacic_nitrogen, parameters.NSC_Retroinhibition, surfacic_NSC, element_inputs['width'], element_inputs['height'], PARa, Ta, ambient_CO2, RH, Ur, organ_label, height_canopy) else: #: Computation at primitive scale Ag_prim_list = [] for PARa_prim in element_inputs['PARa_prim']: #: Amount of absorbed PAR per unit area (µmol m-2 s-1) Ag_prim, An, Rd, Tr, Ts, gs = model.run(surfacic_nitrogen, parameters.NSC_Retroinhibition, surfacic_NSC, element_inputs['width'], element_inputs['height'], PARa_prim, Ta, ambient_CO2, RH, Ur, organ_label, height_canopy) Ag_prim_list.append(Ag_prim) if not Ag_prim_list: Ag = 0 else: Ag = sum([Ag_prim * area_prim for Ag_prim, area_prim in zip(Ag_prim_list, element_inputs['area_prim'])]) / sum(element_inputs['area_prim']) element_outputs = {'Ag': Ag, 'An': An, 'Rd': Rd, 'Tr': Tr, 'Ts': Ts, 'gs': gs, 'width': element_inputs['width'], 'height': element_inputs['height']} self.outputs[element_id] = element_outputs