Source code for openalea.cnwheat.model

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

from __future__ import division  # use "//" to do integer division
import numpy as np
from math import exp

from openalea.cnwheat import parameters

"""
    cnwheat.model
    ~~~~~~~~~~~~~

    The module :mod:`cnwheat.model` defines the equations of the CN exchanges in a population of plants.

"""


[docs] class EcophysiologicalConstants: """ Ecophysiological constants. """ def __init__(self): pass C_MOLAR_MASS = 12 #: Molar mass of carbon (g mol-1) NB_C_TRIOSEP = 3 #: Number of C in 1 mol of trioseP NB_C_HEXOSES = 6 #: Number of C in 1 mol of hexoses (glucose, fructose) NB_C_SUCROSE = 12 #: Number of C in 1 mol of sucrose HEXOSE_MOLAR_MASS_C_RATIO = 0.42 #: Contribution of C in hexose mass TRIOSESP_MOLAR_MASS_C_RATIO = 0.21 #: Contribution of C in triosesP mass RATIO_C_mstruct = 0.44 #: Mean contribution of carbon to structural dry mass (g C g-1 mstruct) AMINO_ACIDS_C_RATIO = 4.15 #: Mean number of mol of C in 1 mol of the major amino acids of plants (Glu, Gln, Ser, Asp, Ala, Gly) AMINO_ACIDS_N_RATIO = 1.25 #: Mean number of mol of N in 1 mol of the major amino acids of plants (Glu, Gln, Ser, Asp, Ala, Gly) PROTEINS_MOLAR_MASS_N_RATIO = 0.151 #: Mean contribution of N in protein mass (Penning De Vries 1989) AMINO_ACIDS_MOLAR_MASS_N_RATIO = 0.135 #: Mean contribution of N in amino acids mass of the major amino acids of plants (Glu, Gln, Ser, Asp, Ala, Gly) NITRATES_MOLAR_MASS_N_RATIO = 0.23 #: Contribution of N in amino acids mass N_MOLAR_MASS = 14 #: Molar mass of nitrogen (g mol-1) AMINO_ACIDS_MOLAR_MASS_C_RATIO = 0.38 #: (Penning De Vries 1989) PROTEINS_MOLAR_MASS_C_RATIO = 0.38 #: As for AA
[docs] class Population(object): """ The class :class:`Population` defines the CN exchanges at population scale. A :class:`population <Population>` must have at least one :class:`plant <Plant>`. """ PARAMETERS = parameters.POPULATION_PARAMETERS #: the internal parameters of the population def __init__(self, plants=None): if plants is None: plants = [] self.plants = plants #: the list of plants
[docs] def calculate_aggregated_variables(self): """Calculate the integrative variables of the population recursively. """ for plant in self.plants: plant.calculate_aggregated_variables()
[docs] class Plant(object): """ The class :class:`Plant` defines the CN exchanges at plant scale. A :class:`plant <Plant>` must have at least one :class:`axis <Axis>`. """ PARAMETERS = parameters.PLANT_PARAMETERS #: the internal parameters of the plants def __init__(self, index=None, axes=None): self.index = index #: the index of the plant if axes is None: axes = [] self.axes = axes #: the list of axes self.cohorts = [] #: list of cohort values - Hack to treat tillering cases : TEMPORARY
[docs] def calculate_aggregated_variables(self): """Calculate the integrative variables of the plant recursively. """ for axis in self.axes: axis.calculate_aggregated_variables()
[docs] @staticmethod def calculate_temperature_effect_on_conductivity(Tair): """Effect of the temperature on phloeme translocation conductivity (Farrar 1988) Should multiply the rate at 20°C :param float Tair: Air temperature (°C) :return: Correction to apply to conductivity coefficients. :rtype: float """ Q10 = 1.3 Tref = 20. return Q10 ** ((Tair - Tref) / 10.)
[docs] @staticmethod def calculate_temperature_effect_on_Vmax(Tair): """Effect of the temperature on maximal enzyme activity Should multiply the rate at 20°C :param float Tair: Air temperature (°C) :return: Correction to apply to enzyme activity :rtype: float """ Tref = 20 + 273.15 Tk = Tair + 273.15 R = 8.3144 #: Physical parameter: Gas constant (J mol-1 K-1) deltaHa = 55 #: Enthalpie of activation of parameter pname (kJ mol-1) deltaS = 0.48 #: entropy term of parameter pname (kJ mol-1 K-1) deltaHd = 154 #: Enthalpie of deactivation of parameter pname (kJ mol-1) f_activation = np.exp((deltaHa * (Tk - Tref)) / (R * 1E-3 * Tref * Tk)) #: Energy of activation (normalized to unity) f_deactivation = (1 + np.exp((Tref * deltaS - deltaHd) / (Tref * R * 1E-3))) / (1 + np.exp((Tk * deltaS - deltaHd) / (Tk * R * 1E-3))) #: Energy of deactivation (normalized to unity) return f_activation * f_deactivation
[docs] class Axis(object): """ The class :class:`Axis` defines the CN exchanges at axis scale. An :class:`axis <Axis>` must have: * one :class:`set of roots <Roots>`, * one :class:`phloem <Phloem>`, * zero or one :class:`set of grains <Grains>`, * at least one :class:`phytomer<Phytomer>`. """ PARAMETERS = parameters.AXIS_PARAMETERS #: the internal parameters of the axes INIT_COMPARTMENTS = parameters.AXIS_INIT_COMPARTMENTS #: the initial values of compartments and state parameters def __init__(self, label=None, roots=None, phloem=None, grains=None, phytomers=None, C_exudated=INIT_COMPARTMENTS.C_exudated, sum_respi_shoot=INIT_COMPARTMENTS.sum_respi_shoot, sum_respi_roots=INIT_COMPARTMENTS.sum_respi_roots): self.label = label #: the label of the axis self.roots = roots #: the roots self.phloem = phloem #: the phloem self.grains = grains #: the grains if phytomers is None: phytomers = [] self.phytomers = phytomers #: the list of phytomers # state variables self.C_exudated = C_exudated self.sum_respi_shoot = sum_respi_shoot self.sum_respi_roots = sum_respi_roots # integrative variables self.Total_Transpiration = None #: the total transpiration (mmol s-1) self.mstruct = None #: structural mass of the axis (g) self.senesced_mstruct = None #: senesced structural mass of the axis (g) self.nitrates = None #: nitrates in the axis (µmol N)
[docs] def calculate_aggregated_variables(self): """Calculate the integrative variables of the axis recursively. """ self.mstruct = 0 self.senesced_mstruct = 0 self.nitrates = 0 if self.roots is not None: self.roots.calculate_aggregated_variables() self.mstruct += self.roots.mstruct self.senesced_mstruct += self.roots.senesced_mstruct self.nitrates += self.roots.nitrates if self.phloem is not None: self.phloem.calculate_aggregated_variables() if self.grains is not None: self.grains.calculate_aggregated_variables() self.mstruct += self.grains.structural_dry_mass for phytomer in self.phytomers: phytomer.calculate_aggregated_variables() self.mstruct += phytomer.mstruct * phytomer.nb_replications self.senesced_mstruct += phytomer.senesced_mstruct * phytomer.nb_replications self.nitrates += phytomer.nitrates * phytomer.nb_replications
# COMPARTMENTS
[docs] @staticmethod def calculate_C_exudated(C_exudation, N_exudation, roots_mstruct): """delta sucrose :param float C_exudation: Rates of sucrose exudated (µmol` C g-1 mstruct h-1) :param float N_exudation: Rate of amino acids exudated (µmol` N g-1 mstruct h-1) :param float roots_mstruct: RStructural mass of the roots (g) :return: delta C loss by exudation (µmol` C) :rtype: float """ return (C_exudation + N_exudation * EcophysiologicalConstants.AMINO_ACIDS_C_RATIO / EcophysiologicalConstants.AMINO_ACIDS_N_RATIO) * roots_mstruct
[docs] class Phytomer(object): """ The class :class:`Phytomer` defines the CN exchanges at phytomer scale. A :class:`phytomer <Phytomer>` must have at least: * 1 photosynthetic organ: :class:`chaff <Chaff>`, :class:`peduncle <Peduncle>`, :class:`lamina <Lamina>`, :class:`internode <Internode>`, or :class:`sheath <Sheath>`. * or 1 :class:`hiddenzone <HiddenZone>`. """ PARAMETERS = parameters.PHYTOMER_PARAMETERS #: the internal parameters of the phytomers def __init__(self, index=None, chaff=None, peduncle=None, lamina=None, internode=None, sheath=None, hiddenzone=None, cohorts=None, cohorts_replications=None): self.index = index #: the index of the phytomer self.chaff = chaff #: the chaff self.peduncle = peduncle #: the peduncle self.lamina = lamina #: the lamina self.internode = internode #: the internode self.sheath = sheath #: the sheath self.hiddenzone = hiddenzone #: the hidden zone self.mstruct = None #: the structural mass of the phytomer (g) self.senesced_mstruct = None #: senesced structural mass of the phytomer (g) self.nitrates = None #: nitrates of the phytomer (µmol N) if cohorts is None: cohorts = [] self.cohorts = cohorts #: list of cohort values - Hack to treat tillering cases : TEMPORARY. Devrait être porté à l'échelle de la plante uniquement mais je ne vois pas comment faire mieux self.cohorts_replications = cohorts_replications #: dictionary of number of replications per cohort rank
[docs] def calculate_aggregated_variables(self): """Calculate the integrative variables of the phytomer recursively. """ self.mstruct = 0 self.senesced_mstruct = 0 self.nitrates = 0 for organ_ in (self.chaff, self.peduncle, self.lamina, self.internode, self.sheath, self.hiddenzone): if organ_ is not None: organ_.calculate_aggregated_variables() self.mstruct += organ_.mstruct if hasattr(organ_, 'senesced_mstruct'): self.senesced_mstruct += organ_.senesced_mstruct if hasattr(organ_, 'nitrates'): self.nitrates += organ_.nitrates
@property def nb_replications(self): return sum(int(v <= self.index) * self.cohorts_replications.get(v, 0) for v in self.cohorts) + 1
[docs] class Organ(object): """ The class :class:`Organ` defines the CN exchanges at organ scale. :class:`Organ` is the base class of all organs. DO NOT INSTANTIATE IT. """ def __init__(self, label): self.label = label #: the label of the organ
[docs] def initialize(self): """Initialize the derived attributes of the organ. """ pass
[docs] def calculate_aggregated_variables(self): """Calculate the integrative variables of the organ recursively. """ pass
[docs] class HiddenZone(Organ): """ The class :class:`HiddenZone` defines the CN exchanges in an hidden zone. """ PARAMETERS = parameters.HIDDEN_ZONE_PARAMETERS #: the internal parameters of the hidden zone INIT_COMPARTMENTS = parameters.HIDDEN_ZONE_INIT_COMPARTMENTS #: the initial values of compartments and state parameters def __init__(self, label='hiddenzone', mstruct=INIT_COMPARTMENTS.mstruct, Nstruct=INIT_COMPARTMENTS.Nstruct, sucrose=INIT_COMPARTMENTS.sucrose, fructan=INIT_COMPARTMENTS.fructan, amino_acids=INIT_COMPARTMENTS.amino_acids, proteins=INIT_COMPARTMENTS.proteins, ratio_DZ=INIT_COMPARTMENTS.ratio_DZ, cohorts=None, cohorts_replications=None, index=None): super(HiddenZone, self).__init__(label) if cohorts is None: cohorts = [] self.cohorts = cohorts #: list of cohort values - Hack to treat tillering cases : TEMPORARY. Devrait être porté à l'échelle de la plante uniquement mais je ne vois pas comment faire mieux self.cohorts_replications = cohorts_replications #: dictionary of number of replications per cohort rank self.index = index #: the index of the phytomer TEMPORARY # state parameters self.mstruct = mstruct #: g self.Nstruct = Nstruct #: g self.ratio_DZ = ratio_DZ # state variables self.sucrose = sucrose #: µmol` C self.fructan = fructan #: µmol` C self.amino_acids = amino_acids #: µmol` N self.proteins = proteins #: µmol` N # fluxes from phloem self.Unloading_Sucrose = None #: current Unloading of sucrose from phloem to hiddenzone integrated over delta t (µmol` C) self.Unloading_Amino_Acids = None #: current Unloading of amino acids from phloem to hiddenzone integrated over delta t (µmol` N) # other fluxes self.S_Proteins = None #: protein synthesis (µmol` N g-1 mstruct) self.S_Fructan = None #: fructan synthesis (µmol` C g-1 mstruct) self.D_Fructan = None #: fructan degradation (µmol` C g-1 mstruct) self.D_Proteins = None #: protein degradation (µmol` N g-1 mstruct) # intermediate variables self.R_residual = None #: Residual maintenance respiration (cost from protein turn-over, cell ion gradients, futile cycles...) (µmol` C respired) # Integrated variables self.Total_Organic_Nitrogen = None #: current total nitrogen amount (µmol` N) @property def nb_replications(self): return sum(int(v <= self.index) * self.cohorts_replications.get(v, 0) for v in self.cohorts) + 1
[docs] def calculate_aggregated_variables(self): self.Total_Organic_Nitrogen = self.calculate_Total_Organic_Nitrogen(self.amino_acids, self.proteins, self.Nstruct)
# VARIABLES
[docs] @staticmethod def calculate_Total_Organic_Nitrogen(amino_acids, proteins, Nstruct): """Total amount of organic N (amino acids + proteins + Nstruct). Used to calculate residual respiration. :param float amino_acids: Amount of amino acids (µmol` N) :param float proteins: Amount of proteins (µmol` N) :param float Nstruct: Structural N mass (g) :return: Total amount of organic N (µmol` N) :rtype: float """ return amino_acids + proteins + (Nstruct / EcophysiologicalConstants.N_MOLAR_MASS) * 1E6
# FLUXES
[docs] def calculate_Unloading_Sucrose(self, sucrose, sucrose_phloem, mstruct_axis, T_effect_conductivity): """Rate of sucrose Unloading from phloem to the hidden zone (µmol` C sucrose unloaded h-1). Transport-resistance equation :param float sucrose: Sucrose amount in the hidden zone (µmol` C) :param float sucrose_phloem: Sucrose amount in phloem (µmol` C) :param float mstruct_axis: The structural dry mass of the axis (g) :param float T_effect_conductivity: Effect of the temperature on the conductivity rate at 20°C (AU) :return: Rate of Sucrose Unloading (µmol` C h-1) :rtype: float """ conc_sucrose_phloem = (sucrose_phloem / mstruct_axis) conc_sucrose_HZ = (sucrose / self.mstruct) conductance = HiddenZone.PARAMETERS.SIGMA * HiddenZone.PARAMETERS.BETA * self.mstruct ** (2 / 3) * T_effect_conductivity # TODO: choix valeurs paramq par rapport flux phloem-hgz return (conc_sucrose_phloem - conc_sucrose_HZ) * conductance * parameters.SECOND_TO_HOUR_RATE_CONVERSION
[docs] def calculate_Unloading_Amino_Acids(self, amino_acids, amino_acids_phloem, mstruct_axis, T_effect_conductivity): """Rate of amino acids Unloading from phloem to the hidden zone (µmol` N amino acids unloaded h-1). Transport-resistance equation :param float amino_acids: Amino_acids amount in the hidden zone (µmol` N) :param float amino_acids_phloem: Amino_acids amount in phloem (µmol` N) :param float mstruct_axis: The structural dry mass of the axis (g) :param float T_effect_conductivity: Effect of the temperature on the conductivity rate at 20°C (AU) :return: Rate of Amino_acids Unloading (µmol` N h-1) :rtype: float """ conc_amino_acids_phloem = (amino_acids_phloem / mstruct_axis) conc_amino_acids_HZ = (amino_acids / self.mstruct) conductance = HiddenZone.PARAMETERS.SIGMA * HiddenZone.PARAMETERS.BETA * self.mstruct ** (2 / 3) * T_effect_conductivity return (conc_amino_acids_phloem - conc_amino_acids_HZ) * conductance * parameters.SECOND_TO_HOUR_RATE_CONVERSION
[docs] def calculate_S_proteins(self, amino_acids, T_effect_Vmax): """Rate of protein synthesis (µmol` N proteins h-1 g-1 MS). Michaelis-Menten function of amino acids. :param float amino_acids: Amino acid amount in the hidden zone (µmol` N) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Protein synthesis (µmol` N g-1 mstruct h-1) :rtype: float """ vmax = HiddenZone.PARAMETERS.VMAX_SPROTEINS_EMZ * (1 - self.ratio_DZ) + HiddenZone.PARAMETERS.VMAX_SPROTEINS_DZ * self.ratio_DZ #: 'Mean' Vmax for the whole hidden zone return ((vmax * max(0, (amino_acids / self.mstruct))) / (HiddenZone.PARAMETERS.K_SPROTEINS + max(0, (amino_acids / self.mstruct)))) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax
[docs] def calculate_D_Proteins(self, proteins, T_effect_Vmax): """Rate of protein degradation (µmol` N proteins h-1 g-1 MS). First order kinetic :param float proteins: Protein amount in the hidden zone (µmol` N) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Protein degradation (µmol` N g-1 mstruct h-1) :rtype: float """ return max(0, (HiddenZone.PARAMETERS.delta_Dproteins * (proteins / self.mstruct))) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax
[docs] def calculate_Regul_S_Fructan(self, Unloading_Sucrose): """Regulating function for fructan maximal rate of synthesis. Negative regulation by the loading of sucrose from the phloem ("swith-off" sigmoïdal kinetic). :param float Unloading_Sucrose: Sucrose unloading (µmol` C) :return: Maximal rate of fructan synthesis (µmol` C g-1 mstruct) :rtype: float """ if Unloading_Sucrose >= 0: Vmax_Sfructans = HiddenZone.PARAMETERS.VMAX_SFRUCTAN_POT else: # Regulation by sucrose unloading if hidden zone is a source for C rate_Loading_Sucrose_massic = -Unloading_Sucrose / self.mstruct / parameters.SECOND_TO_HOUR_RATE_CONVERSION Vmax_Sfructans = HiddenZone.PARAMETERS.VMAX_SFRUCTAN_POT * (HiddenZone.PARAMETERS.K_REGUL_SFRUCTAN ** HiddenZone.PARAMETERS.N_REGUL_SFRUCTAN / (max(0., rate_Loading_Sucrose_massic ** HiddenZone.PARAMETERS.N_REGUL_SFRUCTAN) + HiddenZone.PARAMETERS.K_REGUL_SFRUCTAN ** HiddenZone.PARAMETERS.N_REGUL_SFRUCTAN)) return Vmax_Sfructans
[docs] def calculate_S_Fructan(self, sucrose, Regul_S_Fructan, T_effect_Vmax): """Rate of fructan synthesis (µmol` C fructan g-1 mstruct h-1). Sigmoïdal function of sucrose. :param float sucrose: Amount of sucrose (µmol` C) :param float Regul_S_Fructan: Maximal rate of fructan synthesis regulated by sucrose loading (µmol` C g-1 mstruct) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Fructan synthesis (µmol` C g-1 mstruct) :rtype: float """ return ((max(0., sucrose) / self.mstruct) * HiddenZone.PARAMETERS.VMAX_SFRUCTAN_RELATIVE * Regul_S_Fructan) / \ ((max(0., sucrose) / self.mstruct) + HiddenZone.PARAMETERS.K_SFRUCTAN) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax
[docs] def calculate_D_Fructan(self, sucrose, fructan, T_effect_Vmax): """Rate of fructan degradation (µmol` C fructan g-1 mstruct h-1). Inhibition function by the end product i.e. sucrose (Bancal et al., 2012). :param float sucrose: Amount of sucrose (µmol` C) :param float fructan: Amount of fructan (µmol` C) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Fructan degradation (µmol` C g-1 mstruct) :rtype: float """ d_potential = ((HiddenZone.PARAMETERS.K_DFRUCTAN * HiddenZone.PARAMETERS.VMAX_DFRUCTAN * T_effect_Vmax) / ((max(0., sucrose) / self.mstruct) + HiddenZone.PARAMETERS.K_DFRUCTAN)) * parameters.SECOND_TO_HOUR_RATE_CONVERSION d_actual = min(d_potential, max(0., fructan)) return d_actual
# COMPARTMENTS
[docs] def calculate_sucrose_derivative(self, Unloading_Sucrose, S_Fructan, D_Fructan, hiddenzone_Loading_Sucrose_contribution, R_residual): """delta sucrose of hidden zone. :param float Unloading_Sucrose: Sucrose unloaded (µmol` C) :param float S_Fructan: Fructan synthesis (µmol` C g-1 mstruct) :param float D_Fructan: Fructan degradation (µmol` C g-1 mstruct) :param float hiddenzone_Loading_Sucrose_contribution: Sucrose imported from the emerged tissues (µmol` C) :param float R_residual: Residual respiration (µmol` C) :return: delta sucrose (µmol` C sucrose) :rtype: float """ return Unloading_Sucrose + (D_Fructan - S_Fructan) * self.mstruct + hiddenzone_Loading_Sucrose_contribution - R_residual
[docs] def calculate_amino_acids_derivative(self, Unloading_Amino_Acids, S_Proteins, D_Proteins, hiddenzone_Loading_Amino_Acids_contribution): """delta amino acids of hidden zone. :param float Unloading_Amino_Acids: Amino acids unloaded (µmol` N) :param float S_Proteins: Protein synthesis (µmol` N g-1 mstruct) :param float D_Proteins: Protein degradation (µmol` N g-1 mstruct) :param float hiddenzone_Loading_Amino_Acids_contribution: Amino acids imported from the emerged tissues (µmol` N) :return: delta amino acids (µmol` N amino acids) :rtype: float """ return Unloading_Amino_Acids + (D_Proteins - S_Proteins) * self.mstruct + hiddenzone_Loading_Amino_Acids_contribution
[docs] def calculate_fructan_derivative(self, S_Fructan, D_Fructan): """delta fructans of hidden zone. :param float S_Fructan: Fructans synthesis (µmol` C g-1 mstruct) :param float D_Fructan: Fructans degradation (µmol` C g-1 mstruct) :return: delta fructans (µmol` C fructans) :rtype: float """ return (S_Fructan - D_Fructan) * self.mstruct
[docs] def calculate_proteins_derivative(self, S_Proteins, D_Proteins): """delta proteins of hidden zone. :param float S_Proteins: Protein synthesis (µmol` N g-1 mstruct) :param float D_Proteins: Protein degradation (µmol` N g-1 mstruct) :return: delta proteins (µmol` N proteins) :rtype: float """ return (S_Proteins - D_Proteins) * self.mstruct
[docs] class Phloem(Organ): """ The class :class:`Phloem` defines the CN exchanges in a phloem. """ PARAMETERS = parameters.PHLOEM_PARAMETERS #: the internal parameters of the phloem INIT_COMPARTMENTS = parameters.PHLOEM_INIT_COMPARTMENTS #: the initial values of compartments and state parameters def __init__(self, label='phloem', sucrose=INIT_COMPARTMENTS.sucrose, amino_acids=INIT_COMPARTMENTS.amino_acids): super(Phloem, self).__init__(label) # state variables self.sucrose = sucrose #: µmol` C sucrose self.amino_acids = amino_acids #: µmol` N amino acids # COMPARTMENTS
[docs] @staticmethod def calculate_sucrose_derivative(contributors): """delta sucrose :param list [PhotosyntheticOrganElement, Grains, Roots, HiddenZone] contributors: Organs exchanging C with the phloem :return: delta sucrose (µmol` C sucrose) :rtype: float """ sucrose_derivative = 0 for contributor in contributors: if isinstance(contributor, PhotosyntheticOrganElement): sucrose_derivative += contributor.Loading_Sucrose * contributor.nb_replications elif isinstance(contributor, Grains): sucrose_derivative -= contributor.S_grain_structure + (contributor.S_grain_starch * contributor.structural_dry_mass) elif isinstance(contributor, Roots): sucrose_derivative -= contributor.Unloading_Sucrose * contributor.mstruct * contributor.__class__.PARAMETERS.ALPHA elif isinstance(contributor, HiddenZone): sucrose_derivative -= contributor.Unloading_Sucrose * contributor.nb_replications return sucrose_derivative
[docs] @staticmethod def calculate_amino_acids_derivative(contributors): """delta amino acids :param list [PhotosyntheticOrganElement, Grains, Roots, HiddenZone] contributors: Organs exchanging N with the phloem :return: delta amino acids (µmol` N amino acids) :rtype: float """ amino_acids_derivative = 0 for contributor in contributors: if isinstance(contributor, PhotosyntheticOrganElement): amino_acids_derivative += contributor.Loading_Amino_Acids * contributor.nb_replications elif isinstance(contributor, Grains): amino_acids_derivative -= contributor.S_Proteins elif isinstance(contributor, Roots): amino_acids_derivative -= contributor.Unloading_Amino_Acids * contributor.mstruct * contributor.__class__.PARAMETERS.ALPHA elif isinstance(contributor, HiddenZone): amino_acids_derivative -= contributor.Unloading_Amino_Acids * contributor.nb_replications return amino_acids_derivative
[docs] class Grains(Organ): """ The class :class:`Grains` defines the CN exchanges in a set of grains. """ AMINO_ACIDS_MOLAR_MASS_N_RATIO = 0.136 #: Mean contribution of N in amino acids mass contained in gluten (Glu, Gln and Pro) PARAMETERS = parameters.GRAINS_PARAMETERS #: the internal parameters of the grains INIT_COMPARTMENTS = parameters.GRAINS_INIT_COMPARTMENTS #: the initial values of compartments and state parameters def __init__(self, label='grains', age_from_flowering=INIT_COMPARTMENTS.age_from_flowering, starch=INIT_COMPARTMENTS.starch, structure=INIT_COMPARTMENTS.structure, proteins=INIT_COMPARTMENTS.proteins): super(Grains, self).__init__(label) # state variables self.age_from_flowering = age_from_flowering #: seconds self.starch = starch #: µmol` of C starch self.structure = structure #: µmol` of C sucrose self.proteins = proteins #: µmol` of N proteins # derived attributes self.structural_dry_mass = None #: g of MS # fluxes from phloem self.S_grain_structure = None #: current synthesis of grain structure integrated over a delta t (µmol` C) self.S_grain_starch = None #: current synthesis of grain starch integrated over a delta t (µmol` C g-1 mstruct) self.S_Proteins = None #: current synthesis of grain proteins integrated over a delta t (µmol` N) # intermediate variables self.RGR_Structure = None #: RGR of grain structure (dimensionless?) self.R_grain_growth_struct = None #: grain struct respiration (µmol` C respired) self.R_grain_growth_starch = None #: grain starch growth respiration (µmol` C respired)
[docs] def initialize(self): """Initialize the derived attributes of the organ. """ self.structural_dry_mass = self.calculate_structural_dry_mass(self.structure)
# VARIABLES
[docs] @staticmethod def calculate_structural_dry_mass(structure): """Grain structural dry mass. :param float structure: Grain structural C mass (µmol` C) :return: Grain structural dry mass (g) :rtype: float """ return (structure * 1E-6 * EcophysiologicalConstants.C_MOLAR_MASS) / EcophysiologicalConstants.RATIO_C_mstruct
[docs] @staticmethod def modified_Arrhenius_equation(temperature): # TODO: move in a seperate model """ Return value of equation from Johnson and Lewin (1946) for temperature. The equation is modified to return zero below zero degree. :param float temperature: organ temperature (degree Celsius) :return: Return value of Eyring equation from Johnson and Lewin (1946) for temperature (dimensionless). The equation is modified to return zero below zero degree. :rtype: float """ # Parameters for temperature responses Temp_Ea_R = 8900 # Parameter Ea/R in Eyring equation from Johnson and Lewin (1946) - Parameter value fitted from Kemp and Blacklow (1982) (K) Temp_DS_R = 68.432 # Parameter deltaS/R in Eyring equation from Johnson and Lewin (1946) - Parameter value fitted from Kemp and Blacklow (1982) (dimensionless) Temp_DH_R = 20735.5 # Parameter deltaH/R in Eyring equation from Johnson and Lewin (1946) - Parameter value fitted from Kemp and Blacklow (1982) (K) Temp_Ttransition = 9 # Below this temperature f = linear function of temperature instead of Arrhenius-like(°C) def Arrhenius_equation(T): return T * exp(-Temp_Ea_R / T) / (1 + exp(Temp_DS_R - Temp_DH_R / T)) temperature_K = temperature + 273.15 #: Kelvins if temperature < 0: res = 0 elif temperature < Temp_Ttransition: res = temperature * Arrhenius_equation(Temp_Ttransition + 273.15) / Temp_Ttransition else: res = Arrhenius_equation(temperature_K) return res
[docs] def calculate_temperature_effect_on_growth(self, Tair): """Effect of the temperature on elongation. Return value of equation from Johnson and Lewin (1946) for temperature. The equation is modified to return zero below zero degree. Identical to modified_Arrhenius_equation in ElongWheat. Should multiply the rate at 20°C :param float Tair: Air temperature(°C) :return: Correction to apply to RGR Structure of the grains (dimensionless) :rtype: float """ return self.modified_Arrhenius_equation(Tair) / Grains.PARAMETERS.Arrhenius_ref
[docs] @staticmethod def calculate_RGR_Structure(sucrose_phloem, mstruct_axis, T_effect_growth): """Relative Growth Rate of grain structure, regulated by sucrose concentration in phloem. :param float sucrose_phloem: Sucrose amount in phloem (µmol` C) :param float mstruct_axis: The structural dry mass of the axis (g) :param float T_effect_growth: Effect of the temperature on the growth rate at 20°C (AU) :return: RGR of grain structure at 20°C (s-1) :rtype: float """ return ((max(0., sucrose_phloem) / (mstruct_axis * Axis.PARAMETERS.ALPHA)) * Grains.PARAMETERS.VMAX_RGR) / ((max(0., sucrose_phloem) / (mstruct_axis * Axis.PARAMETERS.ALPHA)) + Grains.PARAMETERS.K_RGR) * T_effect_growth
# FLUXES
[docs] def calculate_S_grain_structure(self, prec_structure, RGR_Structure): """Rate of grain structure synthesis (µmol` C structure h-1). Exponential function, RGR regulated by sucrose concentration in the phloem. :param float prec_structure: Grain structure at t-1 (µmol` C) :param float RGR_Structure: Relative Growth Rate of grain structure (dimensionless?) :return: Rate of Synthesis of grain structure (µmol` C h-1) :rtype: float """ if self.age_from_flowering <= Grains.PARAMETERS.FILLING_INIT: #: Grain enlargment S_grain_structure = prec_structure * RGR_Structure * parameters.SECOND_TO_HOUR_RATE_CONVERSION else: #: Grain filling S_grain_structure = 0 return S_grain_structure
[docs] def calculate_S_grain_starch(self, sucrose_phloem, mstruct_axis, T_effect_Vmax): """Rate of starch synthesis in grains (i.e. grain filling) (µmol` C starch g-1 mstruct h-1). Michaelis-Menten function of sucrose concentration in the phloem. :param float sucrose_phloem: Sucrose concentration in phloem (µmol` C g-1 mstruct) :param float mstruct_axis: The structural dry mass of the axis (g) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Synthesis of grain starch (µmol` C g-1 mstruct h-1) :rtype: float """ if self.age_from_flowering <= Grains.PARAMETERS.FILLING_INIT: #: Grain enlargment S_grain_starch = 0 elif self.age_from_flowering > Grains.PARAMETERS.FILLING_END: #: Grain maturity S_grain_starch = 0 else: #: Grain filling S_grain_starch = (((max(0., sucrose_phloem) / (mstruct_axis * Axis.PARAMETERS.ALPHA)) * Grains.PARAMETERS.VMAX_STARCH) / ((max(0., sucrose_phloem) / (mstruct_axis * Axis.PARAMETERS.ALPHA)) + Grains.PARAMETERS.K_STARCH)) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax return S_grain_starch
[docs] @staticmethod def calculate_S_proteins(S_grain_structure, S_grain_starch, amino_acids_phloem, sucrose_phloem, structural_dry_mass): """Protein synthesis in grains. N is assumed to be co-transported along with the unloaded sucrose from phloem (using the ratio amino acids:sucrose of phloem). :param float S_grain_structure: Synthesis of grain structure (µmol` C) :param float S_grain_starch: Synthesis of grain starch (µmol` C g-1 mstruct) :param float amino_acids_phloem: Amino acids concentration in phloem (µmol` N g-1 mstruct) :param float sucrose_phloem: Sucrose concentration in phloem (µmol` C g-1 mstruct) :param float structural_dry_mass: Grain structural dry mass (g) :return: Synthesis of grain proteins (µmol` N) :rtype: float """ if sucrose_phloem > 0: S_Proteins = (S_grain_structure + S_grain_starch * structural_dry_mass) * (amino_acids_phloem / sucrose_phloem) else: S_Proteins = 0 return S_Proteins
# COMPARTMENTS
[docs] @staticmethod def calculate_structure_derivative(S_grain_structure, R_growth): """delta grain structure. :param float S_grain_structure: Synthesis of grain structure (µmol` C) :param float R_growth: Grain growth respiration (µmol` C respired) :return: delta grain structure (µmol` C structure) :rtype: float """ return S_grain_structure - R_growth
[docs] @staticmethod def calculate_starch_derivative(S_grain_starch, structural_dry_mass, R_growth): """delta grain starch. :param float S_grain_starch: Synthesis of grain starch (µmol` C g-1 mstruct) :param float structural_dry_mass: Grain structural dry mass (g) :param float R_growth: Grain growth respiration (µmol` C respired) :return: delta grain starch (µmol` C starch) :rtype: float """ return (S_grain_starch * structural_dry_mass) - R_growth
[docs] @staticmethod def calculate_proteins_derivative(S_Proteins): """delta grain proteins. :param float S_Proteins: Synthesis of grain proteins (µmol` N) :return: delta grain proteins (µmol` N proteins) :rtype: float """ return S_Proteins
[docs] class Roots(Organ): """ The class :class:`Roots` defines the CN exchanges in a set of roots. """ PARAMETERS = parameters.ROOTS_PARAMETERS #: the internal parameters of the roots INIT_COMPARTMENTS = parameters.ROOTS_INIT_COMPARTMENTS #: the initial values of compartments and state parameters def __init__(self, label='roots', mstruct=INIT_COMPARTMENTS.mstruct, senesced_mstruct=INIT_COMPARTMENTS.senesced_mstruct, Nstruct=INIT_COMPARTMENTS.Nstruct, sucrose=INIT_COMPARTMENTS.sucrose, nitrates=INIT_COMPARTMENTS.nitrates, amino_acids=INIT_COMPARTMENTS.amino_acids, cytokinins=INIT_COMPARTMENTS.cytokinins): super(Roots, self).__init__(label) # state parameters self.mstruct = mstruct #: Structural mass (g) self.senesced_mstruct = senesced_mstruct #: Senesced structural mass (g) self.Nstruct = Nstruct #: Structural N mass (g) # state variables self.sucrose = sucrose #: µmol` C sucrose self.nitrates = nitrates #: µmol` N nitrates self.amino_acids = amino_acids #: µmol` N amino acids self.cytokinins = cytokinins #: AU cytokinins # fluxes from phloem self.Unloading_Sucrose = None #: current Unloading of sucrose from phloem to roots self.Unloading_Amino_Acids = None #: current Unloading of amino acids from phloem to roots # other fluxes self.Export_Nitrates = None #: Total export of nitrates from roots to shoot organs integrated over a delta t (µmol` N) self.Export_Amino_Acids = None #: Total export of amino acids from roots to shoot organs integrated over a delta t (µmol` N) self.S_Amino_Acids = None #: Rate of amino acid synthesis in roots integrated over a delta t (µmol` N g-1 mstruct) self.Uptake_Nitrates = None #: Rate of nitrate uptake by roots integrated over a delta t (µmol` N nitrates) self.S_cytokinins = None #: Rate of cytokinin synthesis integrated over a delta t (AU g-1 mstruct) self.Export_cytokinins = None #: Total export of cytokinin from roots to shoot organs integrated over a delta t (AU) # Integrated variables self.Total_Organic_Nitrogen = None #: current amount of organic N (µmol` N) # intermediate variables self.R_Nnit_upt = None #: Nitrate uptake respiration (µmol` C respired) self.R_Nnit_red = None #: Nitrate reduction-linked respiration (µmol` C respired) self.R_residual = None #: Residual maintenance respiration (cost from protein turn-over, cell ion gradients, futile cycles...) (µmol` C respired) self.C_exudation = None #: C sucrose lost by root exudation integrated over a delta t (µmol` C g-1 mstruct) self.N_exudation = None #: N amino acids lost by root exudation integrated over a delta t (µmol` N g-1 mstruct) self.regul_transpiration = None #: Dimensionless regulating factor of metabolite exports from roots by shoot transpiration self.HATS_LATS = None #: Nitrate influx (µmol` N) self.sum_respi = None #: Sum of respirations for roots i.e. related to N uptake, amino acids synthesis and residual (µmol` C)
[docs] def calculate_aggregated_variables(self): self.Total_Organic_Nitrogen = self.calculate_Total_Organic_Nitrogen(self.amino_acids, self.Nstruct)
# VARIABLES
[docs] @staticmethod def calculate_Total_Organic_Nitrogen(amino_acids, Nstruct): """Total amount of organic N (amino acids + Nstruct). Used to calculate residual respiration. :param float amino_acids: Amount of amino acids (µmol` N) :param float Nstruct: Structural N mass (g) :return: Total amount of organic N (µmol` N) :rtype: float """ return amino_acids + (Nstruct / EcophysiologicalConstants.N_MOLAR_MASS) * 1E6
[docs] @staticmethod def calculate_regul_transpiration(total_transpiration): """A function to regulate metabolite exports from roots by shoot transpiration :param float total_transpiration: Total transpiration (mmol s-1) :return: Dimensionless regulating factor :rtype: float """ return total_transpiration
# FLUXES
[docs] def calculate_Unloading_Sucrose(self, sucrose_roots, sucrose_phloem, mstruct_axis, T_effect_conductivity): """Rate of sucrose Unloading from phloem to roots (µmol` C sucrose unloaded g-1 mstruct h-1). :param float sucrose_roots: Amount of sucrose in roots (µmol` C) :param float sucrose_phloem: Sucrose concentration in phloem (µmol` C g-1 mstruct) :param float mstruct_axis: The structural dry mass of the axis (g) :param float T_effect_conductivity: Effect of the temperature on the conductivity rate at 20°C (AU) :return: Rate of Sucrose Unloading (µmol` C g-1 mstruct h-1) :rtype: float """ conc_sucrose_roots = sucrose_roots / (self.mstruct * self.__class__.PARAMETERS.ALPHA) conc_sucrose_phloem = sucrose_phloem / (mstruct_axis * parameters.AXIS_PARAMETERS.ALPHA) #: Driving compartment (µmol` C g-1 mstruct) driving_sucrose_compartment = max(conc_sucrose_roots, conc_sucrose_phloem) #: Gradient of sucrose between the roots and the phloem (µmol` C g-1 mstruct) diff_sucrose = conc_sucrose_phloem - conc_sucrose_roots #: Conductance depending on mstruct (g2 µmol`-1 s-1) conductance = Roots.PARAMETERS.SIGMA_SUCROSE * Roots.PARAMETERS.BETA * self.mstruct ** (2 / 3) * T_effect_conductivity return driving_sucrose_compartment * diff_sucrose * conductance * parameters.SECOND_TO_HOUR_RATE_CONVERSION
[docs] @staticmethod def calculate_Unloading_Amino_Acids(Unloading_Sucrose, sucrose_phloem, amino_acids_phloem): """Unloading of amino_acids from phloem to roots. Amino acids are assumed to be co-transported along with the unloaded sucrose from phloem (using the ratio amino acids:sucrose of phloem). :param float Unloading_Sucrose: Sucrose Unloading (µmol` C g-1 mstruct) :param float sucrose_phloem: Sucrose concentration in phloem (µmol` C g-1 mstruct) :param float amino_acids_phloem: Amino acids concentration in phloem (µmol` N g-1 mstruct) :return: Amino acids Unloading (µmol` N g-1 mstruct) :rtype: float """ if amino_acids_phloem <= 0 or sucrose_phloem <= 0 or Unloading_Sucrose <= 0: Unloading_Amino_Acids = 0 else: Unloading_Amino_Acids = Unloading_Sucrose * (amino_acids_phloem / sucrose_phloem) return Unloading_Amino_Acids
[docs] def calculate_Uptake_Nitrates(self, Conc_Nitrates_Soil, nitrates_roots, sucrose_roots, T_effect_Vmax): """Rate of nitrate uptake by roots - Nitrate uptake is calculated as the sum of the 2 transport systems: HATS and LATS - HATS and LATS parameters are calculated as a function of root nitrate concentration (negative regulation) - Nitrate uptake is finally regulated by the total culm transpiration and sucrose concentration (positive regulation) :param float Conc_Nitrates_Soil: Soil nitrate concentration Unloading (µmol` N m-3 soil) :param float nitrates_roots: Amount of nitrates in roots (µmol` N) :param float sucrose_roots: Amount of sucrose in roots (µmol` C) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Nitrate uptake (µmol` N nitrates) and nitrate influxes HATS and LATS (µmol` N h-1) :rtype: (float, float) """ conc_nitrates_roots = nitrates_roots / self.mstruct #: High Affinity Transport System (HATS) VMAX_HATS_MAX = max(0., Roots.PARAMETERS.A_VMAX_HATS * conc_nitrates_roots + Roots.PARAMETERS.B_VMAX_HATS) #: Maximal rate of nitrates influx at saturating soil N concentration;HATS (µ mol` N nitrates g-1 mstruct s-1) K_HATS = max(0., Roots.PARAMETERS.A_K_HATS * conc_nitrates_roots + Roots.PARAMETERS.B_K_HATS) #: Affinity coefficient of nitrates influx at saturating soil N concentration;HATS (µmol` m-3) HATS = (VMAX_HATS_MAX * Conc_Nitrates_Soil) / (K_HATS + Conc_Nitrates_Soil) #: Rate of nitrate influx by HATS (µmol` N nitrates uptaked s-1 g-1 mstruct) #: Low Affinity Transport System (LATS) K_LATS = max(0., Roots.PARAMETERS.A_LATS * conc_nitrates_roots + Roots.PARAMETERS.B_LATS) #: Rate constant for nitrates influx at low soil N concentration; LATS (m3 g-1 mstruct s-1) LATS = (K_LATS * Conc_Nitrates_Soil) #: Rate of nitrate influx by LATS (µmol` N nitrates g-1 mstruct) #: Nitrate influx (µmol` N) HATS_LATS = (HATS + LATS) nitrate_influx = HATS_LATS * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax * self.mstruct # Regulations regul_C = (sucrose_roots / self.mstruct) * Roots.PARAMETERS.RELATIVE_VMAX_N_UPTAKE / ((sucrose_roots / self.mstruct) + Roots.PARAMETERS.K_C) #: Nitrate uptake regulation by root C if HATS_LATS < Roots.PARAMETERS.MIN_INFLUX_FOR_UPTAKE: net_nitrate_uptake = 0 else: net_nitrate_uptake = nitrate_influx * Roots.PARAMETERS.NET_INFLUX_UPTAKE_RATIO * regul_C #: Net nitrate uptake (µmol` N nitrates uptaked by roots) return net_nitrate_uptake, nitrate_influx
[docs] def calculate_S_amino_acids(self, nitrates, sucrose, T_effect_Vmax): """Rate of amino acid synthesis in roots (µmol` N amino acids g-1 mstruct h-1). Bi-substrate Michaelis-Menten function of nitrates and sucrose. :param float nitrates: Amount of nitrates in roots (µmol` N) :param float sucrose: Amount of sucrose in roots (µmol` C) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Amino acids synthesis (µmol` N g-1 mstruct h-1) :rtype: float """ return T_effect_Vmax * Roots.PARAMETERS.VMAX_AMINO_ACIDS / ((1 + Roots.PARAMETERS.K_AMINO_ACIDS_NITRATES / (nitrates / (self.mstruct * Roots.PARAMETERS.ALPHA))) * (1 + Roots.PARAMETERS.K_AMINO_ACIDS_SUCROSE / (sucrose / (self.mstruct * Roots.PARAMETERS.ALPHA))) ) * parameters.SECOND_TO_HOUR_RATE_CONVERSION
[docs] def calculate_Export_Nitrates(self, nitrates, regul_transpiration): """Total export of nitrates from roots to shoot organs Export is calculated as a function on nitrate concentration and culm transpiration. :param float nitrates: Amount of nitrates in roots (µmol` N) :param float regul_transpiration: Regulating factor by transpiration (mmol H2O m-2 s-1) :return: Rate of Export of nitrates (µmol` N h-1) :rtype: float """ f_nitrates = (nitrates / (self.mstruct * Roots.PARAMETERS.ALPHA)) * Roots.PARAMETERS.K_NITRATE_EXPORT #: µmol` g-1 s-1 Export_Nitrates = f_nitrates * self.mstruct * regul_transpiration * parameters.SECOND_TO_HOUR_RATE_CONVERSION #: Nitrate export regulation by transpiration (µmol` N) return max(min(Export_Nitrates, nitrates), 0.)
[docs] def calculate_Export_Amino_Acids(self, amino_acids, regul_transpiration): """Total export of amino acids from roots to shoot organs Amino acids export is calculated as a function of nitrate export using the ratio amino acids:nitrates in roots. :param float amino_acids: Amount of amino acids in roots (µmol` N) :param float regul_transpiration: Regulating factor by transpiration (mmol H2O m-2 s-1) :Returns: Rate of Export of amino acids (µmol` N h-1) :Returns Type: :class:`float` """ f_amino_acids = (amino_acids / (self.mstruct * Roots.PARAMETERS.ALPHA)) * Roots.PARAMETERS.K_AMINO_ACIDS_EXPORT #: µmol` g-1 s-1 Export_Amino_Acids = f_amino_acids * self.mstruct * regul_transpiration * parameters.SECOND_TO_HOUR_RATE_CONVERSION #: Amino acids export regulation by plant transpiration (µmol` N) return max(min(Export_Amino_Acids, amino_acids), 0.)
[docs] @staticmethod def calculate_exudation(Unloading_Sucrose, sucrose_roots, amino_acids_roots, amino_acids_phloem): """C sucrose and N amino acids lost by root exudation (µmol` C or N g-1 mstruct). - C exudation is calculated as a fraction of C Unloading from phloem - N exudation is calculated from C exudation using the ratio amino acids:sucrose of the phloem :param float Unloading_Sucrose: Sucrose Unloading (µmol` C g-1 mstruct h-1) :param float sucrose_roots: Amount of sucrose in roots (µmol` C) :param float amino_acids_roots: Amount of amino acids in roots (µmol` N) :param float amino_acids_phloem: Amount of amino acids in phloem (µmol` N) :return: Rates of C exudated (µmol` C g-1 mstruct h-1) and N_exudation (µmol` N g-1 mstruct h-1) :rtype: (float, float) """ if sucrose_roots <= 0 or Unloading_Sucrose <= 0: C_exudation = 0 else: C_exudation = min(sucrose_roots, Unloading_Sucrose * Roots.PARAMETERS.C_EXUDATION) #: C exudated (µmol` g-1 mstruct) if amino_acids_phloem <= 0 or amino_acids_roots <= 0 or sucrose_roots <= 0: N_exudation = 0 else: N_exudation = min((amino_acids_roots / sucrose_roots), Roots.PARAMETERS.N_EXUDATION_MAX) * C_exudation return C_exudation, N_exudation # TODO: C_exudation and N_exudation should be renamed as the exudation of AA result in a loss of both C and N
[docs] def calculate_S_cytokinins(self, sucrose_roots, nitrates_roots, T_effect_Vmax): """ Rate of cytokinin synthesis (AU cytokinins g-1 mstruct h-1). Cytokinin synthesis regulated by both root sucrose and nitrates. As a signal molecule, cytokinins are assumed have a neglected effect on sucrose. Thus, no cost in C is applied to the sucrose pool. :param float sucrose_roots: Amount of sucrose in roots (µmol` C) :param float nitrates_roots: Amount of nitrates in roots (µmol` N) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Cytokinin synthesis (AU g-1 mstruct h-1) :rtype: float """ conc_sucrose = max(0, (sucrose_roots / self.mstruct)) conc_Nitrates = max(0, (nitrates_roots / self.mstruct)) f_sucrose = conc_sucrose ** Roots.PARAMETERS.N_SUC_CYTOKININS / (conc_sucrose ** Roots.PARAMETERS.N_SUC_CYTOKININS + Roots.PARAMETERS.K_SUCROSE_CYTOKININS ** Roots.PARAMETERS.N_SUC_CYTOKININS) f_nitrates = conc_Nitrates ** Roots.PARAMETERS.N_NIT_CYTOKININS / ( conc_Nitrates ** Roots.PARAMETERS.N_NIT_CYTOKININS + Roots.PARAMETERS.K_NITRATES_CYTOKININS ** Roots.PARAMETERS.N_NIT_CYTOKININS) S_cytokinins = Roots.PARAMETERS.VMAX_S_CYTOKININS * f_sucrose * f_nitrates * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax return S_cytokinins
[docs] def calculate_Export_cytokinins(self, cytokinins, regul_transpiration): """Total export of cytokinin from roots to shoot organs Cytokinin export is calculated as a function of cytokinin concentration and culm transpiration. :param float cytokinins: Amount of cytokinins in roots (AU) :param float regul_transpiration: Regulating factor by transpiration (mmol H2O m-2 s-1) :return: Rate of Cytokinin export (AU h-1) :rtype: float """ f_cytokinins = (cytokinins / (self.mstruct * Roots.PARAMETERS.ALPHA)) * Roots.PARAMETERS.K_CYTOKININS_EXPORT #: AU g-1 s-1 Export_cytokinins = f_cytokinins * self.mstruct * regul_transpiration * parameters.SECOND_TO_HOUR_RATE_CONVERSION #: Cytokinin export regulation by plant transpiration (AU) return max(min(Export_cytokinins, cytokinins), 0.)
# COMPARTMENTS
[docs] def calculate_sucrose_derivative(self, Unloading_Sucrose, S_Amino_Acids, C_exudation, sum_respi): """delta root sucrose. :param float Unloading_Sucrose: Sucrose Unloading (µmol` C g-1 mstruct) :param float S_Amino_Acids: Amino acids synthesis (µmol` N g-1 mstruct) :param float C_exudation: C exudation (µmol` C g-1 mstruct) :param float sum_respi: Sum of respirations for roots i.e. related to N uptake, amino acids synthesis and residual (µmol` C) :return: delta root sucrose (µmol` C sucrose) :rtype: float """ #: Contribution of sucrose to the synthesis of amino_acids sucrose_consumption_AA = (S_Amino_Acids / EcophysiologicalConstants.AMINO_ACIDS_N_RATIO) * EcophysiologicalConstants.AMINO_ACIDS_C_RATIO return (Unloading_Sucrose - sucrose_consumption_AA - C_exudation) * self.mstruct - sum_respi
[docs] def calculate_nitrates_derivative(self, Uptake_Nitrates, Export_Nitrates, S_Amino_Acids): """delta root nitrates. :param float Uptake_Nitrates: Nitrate uptake (µmol` N nitrates) :param float Export_Nitrates: Export of nitrates (µmol` N) :param float S_Amino_Acids: Amino acids synthesis (µmol` N g-1 mstruct) :return: delta root nitrates (µmol` N nitrates) :rtype: float """ import_nitrates_roots = Uptake_Nitrates nitrate_reduction_AA = S_Amino_Acids #: Contribution of nitrates to the synthesis of amino_acids return import_nitrates_roots - Export_Nitrates - nitrate_reduction_AA * self.mstruct
[docs] def calculate_amino_acids_derivative(self, Unloading_Amino_Acids, S_Amino_Acids, Export_Amino_Acids, N_exudation): """delta root amino acids. :param float Unloading_Amino_Acids: Amino acids Unloading (µmol` N g-1 mstruct) :param float S_Amino_Acids: Amino acids synthesis (µmol` N g-1 mstruct) :param float Export_Amino_Acids: Export of amino acids (µmol` N) :param float N_exudation: N exudated (µmol` g-1 mstruct) :return: delta root amino acids (µmol` N amino acids) :rtype: float """ return (Unloading_Amino_Acids + S_Amino_Acids - N_exudation) * self.mstruct - Export_Amino_Acids
[docs] def calculate_cytokinins_derivative(self, S_cytokinins, Export_cytokinins): """delta root cytokinins. :param float S_cytokinins: Cytokinin synthesis (AU g-1 mstruct) :param float Export_cytokinins: Cytokinin export (AU) :return: delta root cytokinins (AU cytokinins) :rtype: float """ return S_cytokinins * self.mstruct - Export_cytokinins
[docs] class PhotosyntheticOrgan(Organ): """ The class :class:`PhotosyntheticOrgan` defines the CN exchanges in a photosynthetic organ. A :class:`photosynthetic organ <PhotosyntheticOrgan>` must have at least 1 :class:`photosynthetic organ element <PhotosyntheticOrganElement>`: :class:`chaff element <ChaffElement>`, :class:`lamina element <LaminaElement>`, :class:`internode element <InternodeElement>`, :class:`peduncle element <PeduncleElement>`, or :class:`sheath element <SheathElement>`. :class:`PhotosyntheticOrgan` is the base class of all photosynthetic organs. DO NOT INSTANTIATE IT. """ PARAMETERS = parameters.PHOTOSYNTHETIC_ORGAN_PARAMETERS #: the internal parameters of the photosynthetic organs def __init__(self, label, exposed_element, enclosed_element): super(PhotosyntheticOrgan, self).__init__(label) self.exposed_element = exposed_element #: the exposed element self.enclosed_element = enclosed_element #: the enclosed element self.mstruct = None #: the structural dry mass self.senesced_mstruct = None #: senesced structural dry mass self.nitrates = None #: nitrates (µmol N)
[docs] def calculate_aggregated_variables(self): self.mstruct = 0 self.senesced_mstruct = 0 self.nitrates = 0 for element in (self.exposed_element, self.enclosed_element): if element is not None: element.calculate_aggregated_variables() self.mstruct += element.mstruct self.senesced_mstruct += element.senesced_mstruct self.nitrates += element.nitrates
[docs] class Chaff(PhotosyntheticOrgan): """ The class :class:`Chaff` defines the CN exchanges in a chaff. """ PARAMETERS = parameters.CHAFF_PARAMETERS #: the internal parameters of the chaffs def __init__(self, label=None, exposed_element=None, enclosed_element=None): super(Chaff, self).__init__(label, exposed_element, enclosed_element)
[docs] class Lamina(PhotosyntheticOrgan): """ The class :class:`Lamina` defines the CN exchanges in a lamina. """ PARAMETERS = parameters.LAMINA_PARAMETERS #: the internal parameters of the laminae def __init__(self, label=None, exposed_element=None, enclosed_element=None): super(Lamina, self).__init__(label, exposed_element, enclosed_element)
[docs] class Internode(PhotosyntheticOrgan): """ The class :class:`Internode` defines the CN exchanges in an internode. """ PARAMETERS = parameters.INTERNODE_PARAMETERS #: the internal parameters of the internodes def __init__(self, label=None, exposed_element=None, enclosed_element=None): super(Internode, self).__init__(label, exposed_element, enclosed_element)
[docs] class Peduncle(PhotosyntheticOrgan): """ The class :class:`Peduncle` defines the CN exchanges in a peduncle. """ PARAMETERS = parameters.PEDUNCLE_PARAMETERS #: the internal parameters of the peduncles def __init__(self, label=None, exposed_element=None, enclosed_element=None): super(Peduncle, self).__init__(label, exposed_element, enclosed_element)
[docs] class Sheath(PhotosyntheticOrgan): """ The class :class:`Sheath` defines the CN exchanges in a sheath. """ PARAMETERS = parameters.SHEATH_PARAMETERS #: the internal parameters of the sheaths def __init__(self, label=None, exposed_element=None, enclosed_element=None): super(Sheath, self).__init__(label, exposed_element, enclosed_element)
[docs] class PhotosyntheticOrganElement(object): """ The class :class:`PhotosyntheticOrganElement` defines the CN exchanges in a photosynthetic organ element. An element must belong to an organ of the same type (e.g. a class:`LaminaElement` must belong to a class:`Lamina`). :class:`PhotosyntheticOrganElement` is the base class of all photosynthetic organs elements. DO NOT INSTANTIATE IT. """ PARAMETERS = parameters.PHOTOSYNTHETIC_ORGAN_ELEMENT_PARAMETERS #: the internal parameters of the photosynthetic organs elements INIT_COMPARTMENTS = parameters.PHOTOSYNTHETIC_ORGAN_ELEMENT_INIT_COMPARTMENTS #: the initial values of compartments and state parameters def __init__(self, label=None, green_area=INIT_COMPARTMENTS.green_area, mstruct=INIT_COMPARTMENTS.mstruct, senesced_mstruct=INIT_COMPARTMENTS.senesced_mstruct, Nstruct=INIT_COMPARTMENTS.Nstruct, triosesP=INIT_COMPARTMENTS.triosesP, starch=INIT_COMPARTMENTS.starch, sucrose=INIT_COMPARTMENTS.sucrose, fructan=INIT_COMPARTMENTS.fructan, nitrates=INIT_COMPARTMENTS.nitrates, amino_acids=INIT_COMPARTMENTS.amino_acids, proteins=INIT_COMPARTMENTS.proteins, cytokinins=INIT_COMPARTMENTS.cytokinins, Tr=INIT_COMPARTMENTS.Tr, Ag=INIT_COMPARTMENTS.Ag, Ts=INIT_COMPARTMENTS.Ts, is_growing=INIT_COMPARTMENTS.is_growing, cohorts=None, cohorts_replications=None, index=None): self.label = label #: the label of the element if cohorts is None: #: list of cohort values - Hack to treat tillering cases : TEMPORARY. Devrait être porté à l'échelle de la plante uniquement mais je ne vois pas comment faire mieux cohorts = [] self.cohorts = cohorts #: list of cohort values - Hack to treat tillering cases : TEMPORARY. Devrait être porté à l'échelle de la plante uniquement mais je ne vois pas comment faire mieux self.cohorts_replications = cohorts_replications #: dictionary of number of replications per cohort rank self.index = index #: the index of the phytomer TEMPORARY if cohorts is None: cohorts = [] self.cohorts = cohorts #: list of cohort values - Hack to treat tillering cases : TEMPORARY. Devrait être porté à l'échelle de la plante uniquement mais je ne vois pas comment faire mieux self.cohorts_replications = cohorts_replications #: dictionary of number of replications per cohort rank self.index = index #: the index of the phytomer TEMPORARY # state parameters self.mstruct = mstruct #: Structural dry mass (g) self.senesced_mstruct = senesced_mstruct #: Senesced structural dry mass (g) self.Nstruct = Nstruct #: Structural N mass (g) self.is_growing = is_growing #: Flag indicating if the element is growing or not (:class:`bool`) self.green_area = green_area #: green area (m-2) self.Tr = Tr #: Transpiration rate (mmol m-2 s-1) self.Ag = Ag #: Gross assimilation (µmol` m-2 s-1) self.Ts = Ts #: Organ temperature (°C) # state variables self.triosesP = triosesP #: µmol` C self.starch = starch #: µmol` C self.sucrose = sucrose #: µmol` C self.fructan = fructan #: µmol` C self.nitrates = nitrates #: µmol` N self.amino_acids = amino_acids #: µmol` N self.proteins = proteins #: µmol` N self.cytokinins = cytokinins #: AU # fluxes to phloem self.Loading_Sucrose = None #: Rate of sucrose loading to phloem (µmol` C) self.Loading_Amino_Acids = None #: Rate of amino acids loading to phloem (µmol` N) # other fluxes self.S_Proteins = None #: Rate of protein synthesis (µmol` N g-1 mstruct) self.S_Amino_Acids = None #: Rate of amino acids synthesis (µmol` N g-1 mstruct) self.Regul_S_Fructan = None #: Maximal rate of fructan synthesis (µmol` C g-1 mstruct) self.S_Starch = None #: Rate of starch synthesis (µmol` C g-1 mstruct) self.D_Starch = None #: Rate of starch degradation (µmol` C g-1 mstruct) self.S_Sucrose = None #: Rate of sucrose synthesis (µmol` C g-1 mstruct) self.S_Fructan = None #: Rate of fructan synthesis (µmol` C g-1 mstruct) self.D_Fructan = None #: Rate of fructan degradation ((µmol` C g-1 mstruct) self.Nitrates_import = None #: Total nitrates imported from roots (µmol` N nitrates) self.Amino_Acids_import = None #: Total amino acids imported from roots (µmol` N amino acids) self.D_Proteins = None #: Rate of protein degradation (µmol` N g-1 mstruct) self.cytokinins_import = None #: Import of cytokinins (AU) self.D_cytokinins = None #: Rate of cytokinins degradation (AU g-1 mstruct) # Integrated variables self.Total_Organic_Nitrogen = None #: current total nitrogen amount (µmol` N) # intermediate variables self.R_Nnit_red = None #: Nitrate reduction-linked respiration (µmol` C respired) self.R_residual = None #: Residual maintenance respiration (cost from protein turn-over, cell ion gradients, futile cycles...) (µmol` C respired) self.Transpiration = None #: Surfacic transpiration rate of an element (mmol H2O s-1) self.R_phloem_loading = None #: Phloem loading respiration (µmol` C respired) self.Photosynthesis = None #: Total Photosynthesis of an element integrated over a delta t (µmol` C) self.sum_respi = None #: Sum of respirations for the element i.e. related to C loading to phloem, amino acids synthesis and residual (µmol` C) @property def nb_replications(self): return sum(int(v <= self.index) * self.cohorts_replications.get(v, 0) for v in self.cohorts) + 1
[docs] def calculate_aggregated_variables(self): """Calculate the integrative variables of the element. """ self.Total_Organic_Nitrogen = self.calculate_Total_Organic_Nitrogen(self.amino_acids, self.proteins, self.Nstruct)
# VARIABLES
[docs] @staticmethod def calculate_total_Photosynthesis(Ag, green_area): """Total Photosynthesis of an element (µmol` C m-2 h-1 * m2). :param float Ag: Gross Photosynthesis rate (µmol` C m-2 s-1) :param float green_area: Green area (m2) :return: Rate of Total Photosynthesis (µmol` C h-1) :rtype: float """ return Ag * green_area * parameters.SECOND_TO_HOUR_RATE_CONVERSION
[docs] @staticmethod def calculate_Total_Transpiration(Tr, green_area): """Surfacic transpiration rate of an element :param float Tr: Transpiration rate (mmol H2O m-2 s-1) :param float green_area: Green area (m2) :return: Total transpiration (mmol H2O s-1) :rtype: float """ return Tr * green_area
[docs] def calculate_Regul_S_Fructan(self, Loading_Sucrose): """Regulating function for fructan maximal rate of synthesis. Negative regulation by the loading of sucrose from the phloem ("swith-off" sigmoïdal kinetic). :param float Loading_Sucrose: Sucrose loading (µmol` C) :return: Maximal rate of fructan synthesis (µmol` C g-1 mstruct h-1) :rtype: float """ if Loading_Sucrose <= 0: Vmax_Sfructans = self.__class__.PARAMETERS.VMAX_SFRUCTAN_POT else: # Regulation by sucrose loading rate_Loading_Sucrose_massic = Loading_Sucrose / self.mstruct / parameters.SECOND_TO_HOUR_RATE_CONVERSION Vmax_Sfructans = ((self.__class__.PARAMETERS.VMAX_SFRUCTAN_POT * self.__class__.PARAMETERS.K_REGUL_SFRUCTAN ** self.__class__.PARAMETERS.N_REGUL_SFRUCTAN) / (max(0, rate_Loading_Sucrose_massic ** self.__class__.PARAMETERS.N_REGUL_SFRUCTAN) + self.__class__.PARAMETERS.K_REGUL_SFRUCTAN ** self.__class__.PARAMETERS.N_REGUL_SFRUCTAN)) return Vmax_Sfructans
[docs] @staticmethod def calculate_Total_Organic_Nitrogen(amino_acids, proteins, Nstruct): """Total amount of organic N (amino acids + proteins + Nstruct). Used to calculate residual respiration. :param float amino_acids: Amount of amino acids (µmol` N) :param float proteins: Amount of proteins (µmol` N) :param float Nstruct: Structural N mass (g) :return: Total amount of organic N (µmol` N) :rtype: float """ return amino_acids + proteins + (Nstruct / EcophysiologicalConstants.N_MOLAR_MASS) * 1E6
# FLUXES
[docs] def calculate_S_Starch(self, triosesP, T_effect_Vmax): """Rate of starch synthesis (µmol` C starch g-1 mstruct h-1). Michaelis-Menten function of triose phosphates. :param float triosesP: Amount of triose phosphates (µmol` C) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Starch synthesis (µmol` C g-1 mstruct h-1) :rtype: float """ if triosesP <= 0: S_Starch = 0 else: S_Starch = (((triosesP / (self.mstruct * self.__class__.PARAMETERS.ALPHA)) * self.__class__.PARAMETERS.VMAX_STARCH) / ((triosesP / (self.mstruct * self.__class__.PARAMETERS.ALPHA)) + self.__class__.PARAMETERS.K_STARCH)) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax return S_Starch
[docs] def calculate_D_Starch(self, starch, T_effect_Vmax): """Rate of starch degradation (µmol` C starch g-1 mstruct h-1). First order kinetic. :param float starch: Amount of starch (µmol` C) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Starch degradation (µmol` C g-1 mstruct h-1) :rtype: float """ return max(0, self.__class__.PARAMETERS.DELTA_DSTARCH * (starch / (self.mstruct * self.__class__.PARAMETERS.ALPHA))) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax
[docs] def calculate_S_Sucrose(self, triosesP, T_effect_Vmax): """Rate of sucrose synthesis (µmol` C sucrose g-1 mstruct h-1). Michaelis-Menten function of triose phosphates. :param float triosesP: Amount of triose phosphates (µmol` C) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Sucrose synthesis (µmol` C g-1 mstruct h-1) :rtype: float """ if triosesP <= 0: S_Sucrose = 0 else: S_Sucrose = (((triosesP / (self.mstruct * self.__class__.PARAMETERS.ALPHA)) * self.__class__.PARAMETERS.VMAX_SUCROSE) / ((triosesP / (self.mstruct * self.__class__.PARAMETERS.ALPHA)) + self.__class__.PARAMETERS.K_SUCROSE)) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax return S_Sucrose
[docs] def calculate_Loading_Sucrose(self, sucrose, sucrose_phloem, mstruct_axis, T_effect_conductivity): """Rate of sucrose loading to phloem (µmol` C sucrose h-1). Transport-resistance model. :param float sucrose: Amount of sucrose in the element (µmol` C) :param float sucrose_phloem: Amount of sucrose in the phloem (µmol` C) :param float mstruct_axis: Structural dry mass of the axis (g) :param float T_effect_conductivity: Effect of the temperature on the conductivity rate at 20°C (AU) :return: Rate of Sucrose loading (µmol` C h-1) :rtype: float """ conc_sucrose_element = sucrose / (self.mstruct * self.__class__.PARAMETERS.ALPHA) conc_sucrose_phloem = sucrose_phloem / (mstruct_axis * parameters.AXIS_PARAMETERS.ALPHA) #: Driving compartment (µmol` C g-1 mstruct) driving_sucrose_compartment = max(conc_sucrose_element, conc_sucrose_phloem) #: Gradient of sucrose between the element and the phloem (µmol` C g-1 mstruct) diff_sucrose = conc_sucrose_element - conc_sucrose_phloem #: Conductance depending on mstruct (g2 µmol`-1 s-1) conductance = self.__class__.PARAMETERS.SIGMA_SUCROSE * self.__class__.PARAMETERS.BETA * self.mstruct ** (2 / 3) * T_effect_conductivity return driving_sucrose_compartment * diff_sucrose * conductance * parameters.SECOND_TO_HOUR_RATE_CONVERSION
[docs] def calculate_export_sucrose(self, sucrose, sucrose_hiddenzone, mstruct_hiddenzone, T_effect_conductivity): """Rate of sucrose exportation to hidden zone (µmol` C sucrose h-1). Transport-resistance model. :param float sucrose: Amount of sucrose in the element (µmol` C) :param float sucrose_hiddenzone: Sucrose amount in the hidden zone (µmol` C) :param float mstruct_hiddenzone: mstruct of the hidden zone (g) :param float T_effect_conductivity: Effect of the temperature on the conductivity rate at 20°C (AU) :return: Rate of Sucrose export (µmol` C h-1) :rtype: float """ conc_sucrose_element = sucrose / (self.mstruct * self.__class__.PARAMETERS.ALPHA) conc_sucrose_hiddenzone = sucrose_hiddenzone / mstruct_hiddenzone #: Gradient of sucrose between the element and the hidden zone (µmol` C g-1 mstruct) diff_sucrose = conc_sucrose_element - conc_sucrose_hiddenzone #: Conductance depending on mstruct conductance = HiddenZone.PARAMETERS.SIGMA * self.__class__.PARAMETERS.BETA * mstruct_hiddenzone ** (2 / 3) * T_effect_conductivity return diff_sucrose * conductance * parameters.SECOND_TO_HOUR_RATE_CONVERSION
[docs] def calculate_S_Fructan(self, sucrose, Regul_S_Fructan, T_effect_Vmax): """Rate of fructan synthesis (µmol` C fructan g-1 mstruct h-1). Sigmoïdal function of sucrose. :param float sucrose: Amount of sucrose (µmol` C) :param float Regul_S_Fructan: Maximal rate of fructan synthesis regulated by sucrose loading (µmol` C g-1 mstruct) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Fructan synthesis (µmol` C g-1 mstruct h-1) :rtype: float """ return ((max(0., sucrose) / (self.mstruct * self.__class__.PARAMETERS.ALPHA)) * Regul_S_Fructan) / \ ((max(0., sucrose) / (self.mstruct * self.__class__.PARAMETERS.ALPHA)) + self.__class__.PARAMETERS.K_SFRUCTAN) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax
[docs] def calculate_D_Fructan(self, sucrose, fructan, T_effect_Vmax): """Rate of fructan degradation (µmol` C fructan g-1 mstruct h-1). Inhibition function by the end product i.e. sucrose (Bancal et al., 2012). :param float sucrose: Amount of sucrose (µmol` C) :param float fructan: Amount of fructan (µmol` C) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Fructan degradation (µmol` C g-1 mstruct h-1) :rtype: float """ d_potential = ((self.__class__.PARAMETERS.K_DFRUCTAN * self.__class__.PARAMETERS.VMAX_DFRUCTAN) / ((max(0., sucrose) / (self.mstruct * self.__class__.PARAMETERS.ALPHA)) + self.__class__.PARAMETERS.K_DFRUCTAN)) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax d_actual = min(d_potential, max(0., fructan)) return d_actual
[docs] @staticmethod def calculate_Nitrates_import(Export_Nitrates, element_transpiration, Total_Transpiration): """Total nitrates imported from roots (µmol` N nitrates). Nitrates coming from roots (fraction of uptake + direct export) are distributed according to the contribution of the element to culm transpiration. :param float Export_Nitrates: Exported nitrates by roots (µmol` N) :param float element_transpiration: Element transpiration (mmol H2O s-1) :param float Total_Transpiration: Culm transpiration (mmol H2O s-1) :return: Total nitrates import (µmol` N nitrates) :rtype: float """ if Total_Transpiration > 0: Nitrates_import = Export_Nitrates * (element_transpiration / Total_Transpiration) #: Proportion of exported nitrates from roots to element else: # Avoids further float division by zero error Nitrates_import = 0 return Nitrates_import
[docs] @staticmethod def calculate_Amino_Acids_import(roots_exported_amino_acids, element_transpiration, Total_Transpiration): """Total amino acids imported from roots (µmol` N amino acids). Amino acids exported by roots are distributed according to the contribution of the element to culm transpiration. :param float roots_exported_amino_acids: Exported amino acids by roots (µmol` N) :param float element_transpiration: Element transpiration (mmol H2O s-1) :param float Total_Transpiration: Culm transpiration (mmol H2O s-1) :return: Total amino acids import (µmol` N amino acids) :rtype: float """ if Total_Transpiration > 0: Amino_Acids_import = roots_exported_amino_acids * (element_transpiration / Total_Transpiration) #: Proportion of exported amino acids from roots to organ else: Amino_Acids_import = 0 return Amino_Acids_import
[docs] def calculate_S_amino_acids(self, nitrates, triosesP, T_effect_Vmax): """Rate of amino acids synthesis (µmol` N amino acids h-1 g-1 MS). Bi-substrate Michaelis-Menten function of nitrates and triose phosphates. :param float nitrates: Amount of nitrates (µmol` N) :param float triosesP: Amount of triosesP (µmol` C) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Amino acids synthesis (µmol` N h-1 g-1 mstruct) :rtype: float """ if nitrates <= 0 or triosesP <= 0: calculate_S_amino_acids = 0 else: calculate_S_amino_acids = self.__class__.PARAMETERS.VMAX_AMINO_ACIDS / \ ((1 + self.__class__.PARAMETERS.K_AMINO_ACIDS_NITRATES / (nitrates / (self.mstruct * self.__class__.PARAMETERS.ALPHA))) * (1 + self.__class__.PARAMETERS.K_AMINO_ACIDS_TRIOSESP / (triosesP / (self.mstruct * self.__class__.PARAMETERS.ALPHA)))) * \ parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax return calculate_S_amino_acids
[docs] def calculate_S_proteins(self, amino_acids, T_effect_Vmax): """Rate of protein synthesis (µmol` N proteins h-1 g-1 MS). Michaelis-Menten function of amino acids. :param float amino_acids: Amount of amino acids (µmol` N) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Protein synthesis (µmol` N h-1 g-1 mstruct) :rtype: float """ calculate_S_proteins = (((max(0., amino_acids) / (self.mstruct * self.__class__.PARAMETERS.ALPHA)) * self.__class__.PARAMETERS.VMAX_SPROTEINS) / ((max(0., amino_acids) / (self.mstruct * self.__class__.PARAMETERS.ALPHA)) + self.__class__.PARAMETERS.K_SPROTEINS) ) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax return calculate_S_proteins
[docs] def calculate_D_Proteins(self, proteins, cytokinins, T_effect_Vmax): """Rate of protein degradation (µmol` N proteins s-1 g-1 MS h-1). First order kinetic regulated by cytokinins concentration. :param float proteins: Amount of proteins (µmol` N) :param float cytokinins: Amount of cytokinins (AU) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of protein degradation (µmol` N g-1 mstruct) :rtype: float """ conc_proteins = proteins / (self.mstruct * self.__class__.PARAMETERS.ALPHA) conc_cytokinins = max(0, cytokinins / self.mstruct) regul_cytokinins = (self.__class__.PARAMETERS.VMAX_DPROTEINS_CYTOK * self.__class__.PARAMETERS.K_DPROTEINS_CYTOK ** self.__class__.PARAMETERS.N_DPROTEINS) / \ (conc_cytokinins ** self.__class__.PARAMETERS.N_DPROTEINS + self.__class__.PARAMETERS.K_DPROTEINS_CYTOK ** self.__class__.PARAMETERS.N_DPROTEINS) return max(0, (conc_proteins * self.__class__.PARAMETERS.VMAX_DPROTEINS / (conc_proteins + self.__class__.PARAMETERS.K_DPROTEINS)) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * regul_cytokinins * T_effect_Vmax)
[docs] def calculate_Loading_Amino_Acids(self, amino_acids, amino_acids_phloem, mstruct_axis, T_effect_conductivity): """Rate of amino acids loading to phloem (µmol` N amino acids h-1). Transport-resistance model. :param float amino_acids: Amount of amino acids in the element (µmol` N) :param float amino_acids_phloem: Amount of amino acids in the phloem (µmol` N) :param float mstruct_axis: Structural dry mass of the axis (g) :param float T_effect_conductivity: Effect of the temperature on the conductivity rate at 20°C (AU) :return: Amino acids loading (µmol` N h-1) :rtype: float """ Conc_Amino_Acids_element = amino_acids / (self.mstruct * self.__class__.PARAMETERS.ALPHA) Conc_Amino_Acids_phloem = amino_acids_phloem / (mstruct_axis * parameters.AXIS_PARAMETERS.ALPHA) #: Driving compartment (µmol` N g-1 mstruct) driving_amino_acids_compartment = max(Conc_Amino_Acids_element, Conc_Amino_Acids_phloem) #: Gradient of amino acids between the element and the phloem (µmol` N g-1 mstruct) diff_amino_acids = Conc_Amino_Acids_element - Conc_Amino_Acids_phloem #: Conductance depending on mstruct (g2 µmol`-1 s-1) conductance = self.__class__.PARAMETERS.SIGMA_AMINO_ACIDS * self.__class__.PARAMETERS.BETA * self.mstruct ** (2 / 3) * T_effect_conductivity return driving_amino_acids_compartment * diff_amino_acids * conductance * parameters.SECOND_TO_HOUR_RATE_CONVERSION
[docs] def calculate_Export_Amino_Acids(self, amino_acids, amino_acids_hiddenzone, mstruct_hiddenzone, T_effect_conductivity): """Rate of amino acids exportation to hidden zone (µmol` N amino acids h-1). Transport-resistance model. :param float amino_acids: Amount of amino acids in the element (µmol` N) :param float amino_acids_hiddenzone: Amino acids amount in the hidden zone (µmol` N) :param float mstruct_hiddenzone: mstruct of the hidden zone (g) :param float T_effect_conductivity: Effect of the temperature on the conductivity rate at 20°C (AU) :return: Rate of Amino acids export (µmol` N h-1) :rtype: float """ Conc_Amino_Acids_element = amino_acids / (self.mstruct * self.__class__.PARAMETERS.ALPHA) Conc_Amino_Acids_hiddenzone = amino_acids_hiddenzone / mstruct_hiddenzone #: Gradient of amino acids between the element and the hidden zone (µmol` N g-1 mstruct) diff_amino_acids = Conc_Amino_Acids_element - Conc_Amino_Acids_hiddenzone #: Conductance depending on mstruct conductance = HiddenZone.PARAMETERS.SIGMA * self.__class__.PARAMETERS.BETA * mstruct_hiddenzone ** (2 / 3) * T_effect_conductivity return diff_amino_acids * conductance * parameters.SECOND_TO_HOUR_RATE_CONVERSION
[docs] @staticmethod def calculate_cytokinins_import(roots_exporteD_cytokinins, element_transpiration, Total_Transpiration): """Import of cytokinins (AU). Cytokinin exported by roots are distributed according to the contribution of the element to culm transpiration. :param float roots_exporteD_cytokinins: Exported cytokinins from roots (AU) :param float element_transpiration: Element transpiration (mmol H2O s-1) :param float Total_Transpiration: Culm transpiration (mmol H2O s-1) :return: Cytokinin import (AU) :rtype: float """ if Total_Transpiration > 0: cytokinins_import = roots_exporteD_cytokinins * (element_transpiration / Total_Transpiration) else: cytokinins_import = 0 return cytokinins_import
[docs] def calculate_D_cytokinins(self, cytokinins, T_effect_Vmax): """Rate of cytokinins degradation (AU g-1 mstruct h-1). First order kinetic. Vary with organ temperature. :param float cytokinins: Amount of cytokinins (AU) :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Cytokinin degradation (AU g-1 mstruct h-1) :rtype: float """ return max(0, self.__class__.PARAMETERS.DELTA_D_CYTOKININS * (cytokinins / (self.mstruct * self.__class__.PARAMETERS.ALPHA))) * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax
# COMPARTMENTS
[docs] def calculate_triosesP_derivative(self, Photosynthesis, S_Sucrose, S_Starch, S_Amino_Acids): """ delta triose phosphates of element. :param float Photosynthesis: Total gross Photosynthesis (µmol` C) :param float S_Sucrose: Sucrose synthesis (µmol` C g-1 mstruct) :param float S_Starch: Starch synthesis (µmol` C g-1 mstruct) :param float S_Amino_Acids: Amino acids synthesis (µmol` N g-1 mstruct) :return: delta triose phosphates (µmol` C triose phosphates) :rtype: float """ #: Contribution of triosesP to the synthesis of amino_acids triosesP_consumption_AA = (S_Amino_Acids / EcophysiologicalConstants.AMINO_ACIDS_N_RATIO) * EcophysiologicalConstants.AMINO_ACIDS_C_RATIO return Photosynthesis - (S_Sucrose + S_Starch + triosesP_consumption_AA) * (self.mstruct * self.__class__.PARAMETERS.ALPHA)
[docs] def calculate_starch_derivative(self, S_Starch, D_Starch): """delta starch of element. :param float S_Starch: Starch synthesis (µmol` C g-1 mstruct) :param float D_Starch: Starch degradation (µmol` C g-1 mstruct) :return: delta starch (µmol` C starch) :rtype: float """ return (S_Starch - D_Starch) * (self.mstruct * self.__class__.PARAMETERS.ALPHA)
[docs] def calculate_sucrose_derivative(self, S_Sucrose, D_Starch, Loading_Sucrose, S_Fructan, D_Fructan, sum_respi): """delta sucrose of element. :param float S_Sucrose: Sucrose synthesis (µmol` C g-1 mstruct) :param float D_Starch: Starch degradation (µmol` C g-1 mstruct) :param float Loading_Sucrose: Sucrose loading (µmol` C) :param float S_Fructan: Fructan synthesis (µmol` C g-1 mstruct) :param float D_Fructan: Fructan degradation (µmol` C g-1 mstruct) :param float sum_respi: Sum of respirations for the element i.e. related to C loading to phloem, amino acids synthesis and residual (µmol` C) :return: delta sucrose (µmol` C sucrose) :rtype: float """ return (S_Sucrose + D_Starch + D_Fructan - S_Fructan) * self.mstruct - sum_respi - Loading_Sucrose
[docs] def calculate_fructan_derivative(self, S_Fructan, D_Fructan): """delta fructan of element. :param float S_Fructan: Fructan synthesis (µmol` C g-1 mstruct) :param float D_Fructan: Fructan degradation (µmol` C g-1 mstruct) :return: delta fructan (µmol` C fructan) :rtype: float """ return (S_Fructan - D_Fructan) * (self.mstruct * self.__class__.PARAMETERS.ALPHA)
[docs] def calculate_nitrates_derivative(self, Nitrates_import, S_Amino_Acids): """delta nitrates of element. :param float Nitrates_import: Nitrate import from roots (µmol` N) :param float S_Amino_Acids: Amino acids synthesis (µmol` N g-1 mstruct) :return: delta nitrates (µmol` N nitrates) :rtype: float """ nitrate_reduction_AA = S_Amino_Acids #: Contribution of nitrates to the synthesis of amino_acids return Nitrates_import - (nitrate_reduction_AA * self.mstruct * self.__class__.PARAMETERS.ALPHA)
[docs] def calculate_amino_acids_derivative(self, Amino_Acids_import, S_Amino_Acids, S_Proteins, D_Proteins, Loading_Amino_Acids): """delta amino acids of element. :param float Amino_Acids_import: Amino acids import from roots (µmol` N) :param float S_Amino_Acids: Amino acids synthesis (µmol` N g-1 mstruct) :param float S_Proteins: Protein synthesis (µmol` N g-1 mstruct) :param float D_Proteins: Protein degradation (µmol` N g-1 mstruct) :param float Loading_Amino_Acids: Amino acids loading (µmol` N) :return: delta amino acids (µmol` N amino acids) :rtype: float """ return Amino_Acids_import - Loading_Amino_Acids + (S_Amino_Acids + D_Proteins - S_Proteins) * (self.mstruct * self.__class__.PARAMETERS.ALPHA)
[docs] def calculate_proteins_derivative(self, S_Proteins, D_Proteins): """delta proteins of element. :param float S_Proteins: Protein synthesis (µmol` N g-1 mstruct) :param float D_Proteins: Protein degradation (µmol` N g-1 mstruct) :return: delta proteins (µmol` N proteins) :rtype: float """ return (S_Proteins - D_Proteins) * (self.mstruct * self.__class__.PARAMETERS.ALPHA)
[docs] def calculate_cytokinins_derivative(self, import_cytokinins, D_cytokinins): """delta cytokinins of element. :param float import_cytokinins: Cytokinin import (AU) :param float D_cytokinins: Cytokinin degradation (AU g-1 mstruct) :return: delta cytokinins (AU cytokinins) :rtype: float """ return import_cytokinins - D_cytokinins * (self.mstruct * self.__class__.PARAMETERS.ALPHA)
[docs] class ChaffElement(PhotosyntheticOrganElement): """ The class :class:`ChaffElement` defines the CN exchanges in a chaff element. """ PARAMETERS = parameters.CHAFF_ELEMENT_PARAMETERS #: the internal parameters of the chaffs elements
[docs] class LaminaElement(PhotosyntheticOrganElement): """ The class :class:`LaminaElement` defines the CN exchanges in a lamina element. """ PARAMETERS = parameters.LAMINA_ELEMENT_PARAMETERS #: the internal parameters of the laminae elements
[docs] class InternodeElement(PhotosyntheticOrganElement): """ The class :class:`InternodeElement` defines the CN exchanges in an internode element. """ PARAMETERS = parameters.INTERNODE_ELEMENT_PARAMETERS #: the internal parameters of the internodes elements
[docs] class PeduncleElement(PhotosyntheticOrganElement): """ The class :class:`PeduncleElement` defines the CN exchanges in a peduncle element. """ PARAMETERS = parameters.PEDUNCLE_ELEMENT_PARAMETERS #: the internal parameters of the peduncles elements
[docs] class SheathElement(PhotosyntheticOrganElement): """ The class :class:`SheathElement` defines the CN exchanges in a sheath element. """ PARAMETERS = parameters.SHEATH_ELEMENT_PARAMETERS #: the internal parameters of the sheaths elements
[docs] class Soil(object): """ The class :class:`Soil` defines the amount of nitrogen in the volume of soil explored by roots. """ PARAMETERS = parameters.SOIL_PARAMETERS #: the internal parameters of the soil def __init__(self, volume=None, nitrates=None, Tsoil=None): # state parameters self.volume = volume #: volume of soil explored by roots (m3) self.Tsoil = Tsoil #: soil temperature (°C) self.constant_Conc_Nitrates = False #: If True, the model run with a constant soil nitrate concentration (bool) # state variables self.nitrates = nitrates #: µmol` N nitrates # intermediate variables self.Conc_Nitrates_Soil = None #: soil nitrate concentration Unloading (µmol` N m-3 soil) self.mineralisation = None #: mineralisation on organic N into nitrates in soil (µmol`)
[docs] @staticmethod def calculate_temperature_effect_on_Vmax(Tsoil): """Effect of the temperature on maximal enzyme activity Should multiply the rate at 20°C :param float Tsoil: Soil temperature (°C) :return: Correction to apply to enzyme activity :rtype: float """ Tref = 20 + 273.15 Tk = Tsoil + 273.15 R = 8.3144 #: Physical parameter: Gas constant (J mol-1 K-1) deltaHa = 55 # 89.7 #: Enthalpie of activation of parameter pname (kJ mol-1) deltaS = 0.48 # 0.486 #: entropy term of parameter pname (kJ mol-1 K-1) deltaHd = 154 # 149.3 #: Enthalpie of deactivation of parameter pname (kJ mol-1) f_activation = np.exp((deltaHa * (Tk - Tref)) / (R * 1E-3 * Tref * Tk)) #: Energy of activation (normalized to unity) f_deactivation = (1 + np.exp((Tref * deltaS - deltaHd) / (Tref * R * 1E-3))) / (1 + np.exp((Tk * deltaS - deltaHd) / (Tk * R * 1E-3))) #: Energy of deactivation (normalized to unity) return f_activation * f_deactivation
[docs] @staticmethod def calculate_temperature_effect_on_conductivity(Tsoil): """Effect of the temperature on phloeme translocation conductivity (Farrar 1988) Should multiply the rate at 20°C :param float Tsoil: Soil temperature (°C) :return: Correction to apply to conductivity coefficients. :rtype: float """ Q10 = 1.3 Tref = 20. return Q10 ** ((Tsoil - Tref) / 10.)
# VARIABLES
[docs] def calculate_Conc_Nitrates(self, nitrates): """Nitrate concentration in soil. :param float nitrates: Amount of nitrates (µmol` N) :return: Nitrate concentration (µmol` nitrates m-3) :rtype: float """ return max(0, (nitrates / self.volume))
# FLUX
[docs] @staticmethod def calculate_mineralisation(T_effect_Vmax): """Mineralisation on organic N into nitrates in soil. :param float T_effect_Vmax: Correction to apply to enzyme activity :return: Rate of Nitrate mineralisation (µmol` h-1) :rtype: float """ return parameters.SOIL_PARAMETERS.MINERALISATION_RATE * parameters.SECOND_TO_HOUR_RATE_CONVERSION * T_effect_Vmax
# COMPARTMENTS
[docs] @staticmethod def calculate_nitrates_derivative(mineralisation, soil_contributors, culm_density, constant_Conc_Nitrates): """delta soil nitrates. :param float mineralisation: N mineralisation in soil (µmol` m-2 N nitrates) :param (float, int) soil_contributors: A tuple with (Nitrate uptake per axis (µmol` N nitrates), the plant id) :param dict [plant_id, culm_density] culm_density: A dictionary of culm density (culm_density = {plant_id: culm_density, ...}) :param bool constant_Conc_Nitrates: If True, the model run with a constant soil nitrate concentration. :return: delta nitrates (µmol` N nitrates) :rtype: float """ delta_Nitrates = 0 if not constant_Conc_Nitrates: Uptake_Nitrates = 0 for root_uptake, plant_id in soil_contributors: Uptake_Nitrates += root_uptake * culm_density[plant_id] # TODO: temporary, will be removed in next version delta_Nitrates = mineralisation - Uptake_Nitrates return delta_Nitrates