# -*- coding: latin-1 -*-
from __future__ import division # use "//" to do integer division
import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from openalea.cnwgrass.cnmetabolism import simulation as cnmetabolism_simulation, model as cnmetabolism_model
from openalea.cnwgrass.cnmetabolism import parameters as cnmetabolism_parameters
from openalea.cnwgrass.respiration import model as respiration_model
from openalea.cnwgrass.integration import tools as integration_tools
"""
cnmetabolism.postprocessing
~~~~~~~~~~~~~~~~~~~~~~
The module :mod:`cnmetabolism.postprocessing` defines post-processing to apply
on CN-Metabolism outputs, and provides a front-end to automatize the generation of graphs
for validation of the outputs.
Please use front-ends :func:`postprocessing` and :func:`generate_graphs`.
"""
#: the time index
T_INDEX = cnmetabolism_simulation.Simulation.T_INDEX
#: the index to locate the plants in the modelled system
PLANTS_INDEXES = cnmetabolism_simulation.Simulation.PLANTS_INDEXES
#: concatenation of :attr:`T_INDEX` and :attr:`PLANTS_INDEXES`
PLANTS_T_INDEXES = cnmetabolism_simulation.Simulation.PLANTS_T_INDEXES
#: plants post-processing variables
PLANTS_POSTPROCESSING_VARIABLES = []
#: concatenation of :attr:`PLANTS_T_INDEXES`, :attr:`PLANTS_RUN_VARIABLES <cnmetabolism.simulation.Simulation.PLANTS_RUN_VARIABLES>` and :attr:`PLANTS_POSTPROCESSING_VARIABLES`
PLANTS_RUN_POSTPROCESSING_VARIABLES = set(PLANTS_T_INDEXES + cnmetabolism_simulation.Simulation.PLANTS_RUN_VARIABLES + PLANTS_POSTPROCESSING_VARIABLES)
#: the indexes to locate the axes in the modelled system
AXES_INDEXES = cnmetabolism_simulation.Simulation.AXES_INDEXES
#: concatenation of :attr:`T_INDEX` and :attr:`AXES_INDEXES`
AXES_T_INDEXES = cnmetabolism_simulation.Simulation.AXES_T_INDEXES
#: axes post-processing variables
AXES_POSTPROCESSING_VARIABLES = ['C_N_ratio', 'C_N_ratio_shoot', 'N_content', 'N_content_shoot', 'N_content_roots', 'N_content_mstruct', 'N_content_mstruct_shoot', 'N_content_total_DM_shoot',
'N_content_mstruct_roots', 'sum_N_g', 'sum_N_g_shoot',
'sum_dry_mass', 'sum_dry_mass_shoot', 'sum_dry_mass_laminae', 'sum_dry_mass_stem', 'sum_dry_mass_roots', 'dry_mass_phloem', 'shoot_roots_ratio',
'shoot_roots_mstruct_ratio', 'Total_Photosynthesis', 'Tillers_Photosynthesis', 'Tillers_Photosynthesis_An', 'NNI',
'NS', 'NS_shoot', 'NS_stem', 'NS_laminae', 'NS_roots', 'mstruct_shoot', 'mstruct_laminae', 'mstruct_stem',
'C_respired_shoot', 'C_respired_roots', 'Cont_WSC_DM', 'Cont_WSC_DM_shoot', 'Cont_WSC_DM_roots', 'Cont_WSC_DM_laminae', 'Cont_WSC_DM_stem',
'sum_C_g', 'sum_NSC_g', 'C_exuded']
#: concatenation of :attr:`AXES_T_INDEXES`, :attr:`AXES_RUN_VARIABLES <cnmetabolism.simulation.Simulation.AXES_RUN_VARIABLES>` and :attr:`AXES_POSTPROCESSING_VARIABLES`
AXES_RUN_POSTPROCESSING_VARIABLES = set(AXES_T_INDEXES + cnmetabolism_simulation.Simulation.AXES_RUN_VARIABLES + AXES_POSTPROCESSING_VARIABLES)
#: the indexes to locate the phytomers in the modelled system
PHYTOMERS_INDEXES = cnmetabolism_simulation.Simulation.PHYTOMERS_INDEXES
#: concatenation of :attr:`T_INDEX` and :attr:`PHYTOMERS_INDEXES`
PHYTOMERS_T_INDEXES = cnmetabolism_simulation.Simulation.PHYTOMERS_T_INDEXES
#: phytomers post-processing variables
PHYTOMERS_POSTPROCESSING_VARIABLES = []
#: concatenation of :attr:`PHYTOMERS_T_INDEXES`, :attr:`PHYTOMERS_RUN_VARIABLES <cnmetabolism.simulation.Simulation.PHYTOMERS_RUN_VARIABLES>` and :attr:`PHYTOMERS_POSTPROCESSING_VARIABLES`
PHYTOMERS_RUN_POSTPROCESSING_VARIABLES = set(PHYTOMERS_T_INDEXES + cnmetabolism_simulation.Simulation.PHYTOMERS_RUN_VARIABLES + PHYTOMERS_POSTPROCESSING_VARIABLES)
#: the indexes to locate the organs in the modelled system
ORGANS_INDEXES = cnmetabolism_simulation.Simulation.ORGANS_INDEXES
#: concatenation of :attr:`T_INDEX` and :attr:`ORGANS_INDEXES`
ORGANS_T_INDEXES = cnmetabolism_simulation.Simulation.ORGANS_T_INDEXES
#: organs post-processing variables
ORGANS_POSTPROCESSING_VARIABLES = ['Conc_Amino_Acids', 'Conc_Nitrates', 'Conc_Sucrose', 'Conc_cytokinins', 'Dry_Mass', 'Starch_g', 'Proteins_N_Mass', 'N_tot', 'WSC_g']
ORGANS_RUN_VARIABLES_ADDITIONAL = ['sucrose_consumption_mstruct', 'AA_consumption_mstruct', 'synthetized_mstruct']
#: concatenation of :attr:`ORGANS_T_INDEXES`, :attr:`ORGANS_RUN_VARIABLES <cnmetabolism.simulation.Simulation.ORGANS_RUN_VARIABLES>` and :attr:`ORGANS_POSTPROCESSING_VARIABLES`
ORGANS_RUN_POSTPROCESSING_VARIABLES = set(ORGANS_T_INDEXES + cnmetabolism_simulation.Simulation.ORGANS_RUN_VARIABLES + ORGANS_POSTPROCESSING_VARIABLES + ORGANS_RUN_VARIABLES_ADDITIONAL)
#: the indexes to locate the hidden zones in the modelled system
HIDDENZONE_INDEXES = cnmetabolism_simulation.Simulation.HIDDENZONE_INDEXES
#: concatenation of :attr:`T_INDEX` and :attr:`HIDDENZONE_INDEXES`
HIDDENZONE_T_INDEXES = cnmetabolism_simulation.Simulation.HIDDENZONE_T_INDEXES
#: hidden zones post-processing variables
HIDDENZONE_POSTPROCESSING_VARIABLES = ['Conc_Amino_Acids', 'Conc_Fructan', 'Conc_Proteins', 'Conc_Sucrose', 'RER', 'nb_replications', 'Cont_Fructan_DM', 'Cont_Proteins_DM', 'sum_dry_mass',
'N_content', 'Cont_WSC_DM']
HIDDENZONE_RUN_VARIABLES_ADDITIONAL = ['leaf_L', 'delta_leaf_L', 'internode_L', 'leaf_pseudostem_length', 'leaf_is_emerged', 'Respi_growth', 'sucrose_consumption_mstruct', 'AA_consumption_mstruct']
#: concatenation of :attr:`HIDDENZONE_T_INDEXES`, :attr:`HIDDENZONE_RUN_VARIABLES <cnmetabolism.simulation.Simulation.HIDDENZONE_RUN_VARIABLES>` and :attr:`HIDDENZONE_POSTPROCESSING_VARIABLES`
HIDDENZONE_RUN_POSTPROCESSING_VARIABLES = set(HIDDENZONE_T_INDEXES + cnmetabolism_simulation.Simulation.HIDDENZONE_RUN_VARIABLES + HIDDENZONE_RUN_VARIABLES_ADDITIONAL + HIDDENZONE_POSTPROCESSING_VARIABLES)
#: the indexes to locate the elements in the modelled system
ELEMENTS_INDEXES = cnmetabolism_simulation.Simulation.ELEMENTS_INDEXES
#: concatenation of :attr:`T_INDEX` and :attr:`ELEMENTS_INDEXES`
ELEMENTS_T_INDEXES = cnmetabolism_simulation.Simulation.ELEMENTS_T_INDEXES
#: elements post-processing variables
ELEMENTS_POSTPROCESSING_VARIABLES = ['Conc_Amino_Acids', 'Conc_Fructan', 'Conc_Nitrates', 'Conc_Proteins', 'Conc_Starch', 'Conc_Sucrose', 'Conc_TriosesP', 'Cont_Fructan_DM',
'Conc_cytokinins', 'Surfacic_NS', 'NS', 'N_content', 'N_content_total_DM', 'N_tot', 'nb_replications', 'SLA', 'SLN',
'SLN_nonstruct', 'sum_dry_mass', 'Photosynthetic_efficiency', 'Cont_WSC_DM']
ELEMENTS_RUN_VARIABLES_ADDITIONAL = ['length', 'PARa']
#: concatenation of :attr:`ELEMENTS_T_INDEXES`, :attr:`ELEMENTS_RUN_VARIABLES <cnmetabolism.simulation.Simulation.ELEMENTS_RUN_VARIABLES>` and :attr:`ELEMENTS_POSTPROCESSING_VARIABLES`
ELEMENTS_RUN_POSTPROCESSING_VARIABLES = set(ELEMENTS_T_INDEXES + cnmetabolism_simulation.Simulation.ELEMENTS_RUN_VARIABLES + ELEMENTS_RUN_VARIABLES_ADDITIONAL + ELEMENTS_POSTPROCESSING_VARIABLES)
#: the indexes to locate the soils in the modelled system
SOILS_INDEXES = cnmetabolism_simulation.Simulation.SOILS_INDEXES
#: concatenation of :attr:`T_INDEX` and :attr:`SOILS_INDEXES`
SOILS_T_INDEXES = cnmetabolism_simulation.Simulation.SOILS_T_INDEXES
#: soils post-processing variables
SOILS_POSTPROCESSING_VARIABLES = []
#: concatenation of :attr:`SOILS_T_INDEXES`, :attr:`SOILS_RUN_VARIABLES <cnmetabolism.simulation.Simulation.SOILS_RUN_VARIABLES>` and :attr:`SOILS_POSTPROCESSING_VARIABLES`
SOILS_RUN_POSTPROCESSING_VARIABLES = SOILS_T_INDEXES + cnmetabolism_simulation.Simulation.SOILS_RUN_VARIABLES + SOILS_POSTPROCESSING_VARIABLES
# -------------------------------------------------
# ----------- POST-PROCESSING FUNCTIONS -----------
# ----------- DO NOT USE THEM DIRECTLY ------------
# -------------------------------------------------
[docs]
class Roots:
"""
Post-processing to apply on Roots outputs.
"""
def __init__(self):
pass
[docs]
@staticmethod
def calculate_WSC_g(sucrose):
"""Mass of Water Soluble Carbohydrates
:param float or pandas.Series sucrose: Amount of sucrose (µmol` C)
:return: Water Soluble Carbohydrates (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
WSC_g = (sucrose * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO
return WSC_g
[docs]
@staticmethod
def calculate_Conc_Nitrates(nitrates, mstruct):
"""Nitrate concentration.
:param float or pandas.Series nitrates: Amount of nitrates (µmol` N)
:param float or pandas.Series mstruct: Structural mass (g)
:return: Nitrate concentration (µmol` nitrates g-1 mstruct)
:rtype: float
"""
return nitrates / mstruct
[docs]
@staticmethod
def calculate_Conc_Amino_Acids(amino_acids, mstruct):
"""Amino_acid concentration.
:param float or pandas.Series amino_acids: Amount of amino acids (µmol` N)
:param float or pandas.Series mstruct: Structural mass (g)
:return: Amino_acid concentration (µmol` amino_acids g-1 mstruct)
:rtype: float
"""
return (amino_acids / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_N_RATIO) / mstruct
[docs]
@staticmethod
def calculate_conc_sucrose(sucrose, mstruct):
"""Sucrose concentration.
:param float or pandas.Series sucrose: Amount of sucrose (µmol` C)
:param float or pandas.Series mstruct: Structural mass (g)
:return: Sucrose concentration (µmol` sucrose g-1 mstruct)
:rtype: float
"""
return (sucrose / mstruct) / cnmetabolism_model.EcophysiologicalConstants.NB_C_SUCROSE
[docs]
@staticmethod
def calculate_conc_cytokinins(cytokinins, mstruct):
"""Cytokinin concentration.
:param float or pandas.Series cytokinins: Amount of cytokinins (AU)
:param float or pandas.Series mstruct: Structural mass (g)
:return: cytokinins concentration (AU cytokinins g-1 mstruct)
:rtype: float
"""
return cytokinins / mstruct
[docs]
class Phloem:
"""
Post-processing to apply on Phloem outputs.
"""
def __init__(self):
pass
[docs]
@staticmethod
def calculate_WSC_g(sucrose):
"""Mass of Water Soluble Carbohydrates
:param float or pandas.Series sucrose: Amount of sucrose (µmol` C)
:return: Water Soluble Carbohydrates (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
WSC_g = (sucrose * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO
return WSC_g
[docs]
@staticmethod
def calculate_conc_amino_acids(amino_acids, mstruct_axis):
"""Amino_acids concentration. Related to the structural dry mass of the culm.
:param float or pandas.Series amino_acids: Amount of amino_acids in phloem (µmol` N)
:param float or pandas.Series mstruct_axis: The structural dry mass of the axis (g)
:return: Amino_acids concentration (µmol` amino_acids g-1 mstruct)
:rtype: float
"""
return (amino_acids / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_N_RATIO) / mstruct_axis
[docs]
@staticmethod
def calculate_conc_sucrose(sucrose, mstruct_axis):
"""Sucrose concentration. Related to the structural dry mass of the culm
:param float or pandas.Series sucrose: Amount of sucrose in phloem (µmol` C)
:param float or pandas.Series mstruct_axis: The structural dry mass of the axis (g)
:return: Sucrose concentration (µmol` sucrose g-1 mstruct)
:rtype: float
"""
return (sucrose / cnmetabolism_model.EcophysiologicalConstants.NB_C_SUCROSE) / mstruct_axis
[docs]
class Grains:
"""
Post-processing to apply on Grains outputs.
"""
def __init__(self):
pass
[docs]
@staticmethod
def calculate_dry_mass(structure, starch, proteins):
"""Grain total dry mass.
:param float or pandas.Series structure: Grain structural C mass (µmol` C)
:param float or pandas.Series starch: Grain starch content (µmol` C)
:param float or pandas.Series proteins: Grain protein content (µmol` N)
:return: Grain total dry mass (g)
:rtype: float
"""
#: Carbohydrates mass, grain carbohydrates supposed to be mainly starch i.e. glucose polymers (C6 H12 O6)
C_mass = ((structure + starch) * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO
#: N mass, grain proteins were supposed to be gluten mainly composed of Glu, Gln and Pro
N_mass = (proteins * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS) / cnmetabolism_model.Grains.AMINO_ACIDS_MOLAR_MASS_N_RATIO
return C_mass + N_mass
[docs]
@staticmethod
def calculate_WSC_g(sucrose, starch):
""" Mass of Water Soluble Carbohydrates
:param float or pandas.Series sucrose: Amount of sucrose (µmol` C)
:param float or pandas.Series starch: Amount of sucrose (µmol` C)
:return: Water Soluble Carbohydrates (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
WSC_g = ((sucrose * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO +
(starch * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO)
return WSC_g
[docs]
@staticmethod
def calculate_protein_N_mass(proteins):
"""Grain total protein mass.
:param float or pandas.Series proteins: Grain protein content (µmol` N)
:return: Grain total protein mass (g)
:rtype: float
"""
mass_N_proteins = proteins * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS #: Mass of nitrogen in proteins (g)
# masS_proteins = mass_N_proteins / EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO #: Total mass of proteins (g)
return mass_N_proteins
[docs]
class Endosperm:
"""
Post-processing to apply on Endosperm outputs.
"""
def __init__(self):
pass
[docs]
@staticmethod
def calculate_dry_mass(starch, proteins, mstruct):
"""Endosperm total dry mass.
:param float or pandas.Series starch: Endosperm starch content (µmol` C)
:param float or pandas.Series proteins: Endosperm protein content (µmol` N)
:param float or pandas.Series mstruct: structural mass (g)
:return: Endosperm total dry mass (g)
:rtype: float
"""
#: Carbohydrates mass, grain carbohydrates supposed to be mainly starch i.e. glucose polymers (C6 H12 O6)
C_mass = (starch * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO
#: N mass, grain proteins were supposed to be gluten mainly composed of Glu, Gln and Pro
N_mass = (proteins * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS) / cnmetabolism_model.Grains.AMINO_ACIDS_MOLAR_MASS_N_RATIO
return C_mass + N_mass + mstruct
[docs]
@staticmethod
def calculate_starch_g(starch):
""" Endosperm starch mass
:param float or pandas.Series starch: Endosperm starch content (µmol` C)
:return: starch (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
starch_g = (starch * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO
return starch_g
[docs]
@staticmethod
def calculate_protein_N_mass(proteins):
"""Endosperm protein mass.
:param float or pandas.Series proteins: Endosperm protein content (µmol` N)
:return: Endosperm protein N mass (g)
:rtype: float
"""
mass_N_proteins = proteins * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS #: Mass of nitrogen in proteins (g)
return mass_N_proteins
[docs]
class HiddenZone:
"""
Post-processing to apply on HiddenZone outputs.
"""
def __init__(self):
pass
[docs]
@staticmethod
def calculate_dry_mass(sucrose, fructan, amino_acids, proteins, mstruct):
"""Dry mass
:param float or pandas.Series sucrose: Amount of sucrose (µmol` C)
:param float or pandas.Series fructan: Amount of fructan (µmol` C)
:param float or pandas.Series amino_acids: Amount of amino acids (µmol` N)
:param float or pandas.Series proteins: Amount of proteins (µmol` N)
:param float or pandas.Series mstruct: structural mass (g)
:return: Dry mass (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
N_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS
dry_mass = ((sucrose * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO +
(fructan * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO +
(amino_acids * 1E-6 * N_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO +
(proteins * 1E-6 * N_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO +
mstruct)
return dry_mass
[docs]
@staticmethod
def calculate_WSC_g(sucrose, fructan):
"""Mass of Water Soluble Carbohydrates
:param float or pandas.Series sucrose: Amount of sucrose (µmol` C)
:param float or pandas.Series fructan: Amount of fructan (µmol` C)
:return: Water Soluble Carbohydrates (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
WSC_g = ((sucrose * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO +
(fructan * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO
)
return WSC_g
[docs]
@staticmethod
def calculate_C_g(sucrose, starch, fructan, amino_acids, proteins, mstruct):
"""Mass of carbon metabolites
:param float or pandas.Series sucrose: Amount of sucrose (µmol` C)
:param float or pandas.Series starch: Amount of starch (µmol` C)
:param float or pandas.Series fructan: Amount of fructan (µmol` C)
:param float or pandas.Series amino_acids: Amount of amino acids (µmol` N)
:param float or pandas.Series proteins: Amount of proteins (µmol` N)
:param float or pandas.Series mstruct: structural mass (g)
:return: Dry mass (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
N_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS
C_mass = ((sucrose * 1E-6 * C_MOLAR_MASS) +
(starch * 1E-6 * C_MOLAR_MASS) +
(fructan * 1E-6 * C_MOLAR_MASS) +
(amino_acids * 1E-6 * N_MOLAR_MASS) *
cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_C_RATIO / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO +
(proteins * 1E-6 * N_MOLAR_MASS) * cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_C_RATIO / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO +
mstruct * cnmetabolism_model.EcophysiologicalConstants.RATIO_C_mstruct)
return C_mass
[docs]
@staticmethod
def calculate_N_g(amino_acids, proteins, Nstruct):
"""Mass of N metabolites
:param float or pandas.Series amino_acids: Amount of amino acids (µmol` N)
:param float or pandas.Series proteins: Amount of proteins (µmol` N)
:param float or pandas.Series Nstruct: N structural mass(g)
:return: Dry mass (g)
:rtype: float
"""
N_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS
N_mass = ((amino_acids * 1E-6 * N_MOLAR_MASS) +
(proteins * 1E-6 * N_MOLAR_MASS) +
Nstruct)
return N_mass
[docs]
@staticmethod
def calculate_fructan_g(fructan):
"""Mass of fructans
:param float or pandas.Series fructan: Amount of fructans (µmol` C)
:return: Dry mass (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
return (fructan * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO
[docs]
@staticmethod
def calculate_proteins_g(proteins):
"""Mass of proteins
:param float or pandas.Series proteins: Amount of proteins (µmol` N)
:return: Dry mass (g)
:rtype: float
"""
N_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS
return (proteins * 1E-6 * N_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.PROTEINS_MOLAR_MASS_N_RATIO
[docs]
@staticmethod
def calculate_Conc_Amino_Acids(amino_acids, mstruct):
"""Amino acid concentration.
:param float or pandas.Series amino_acids: N amino acids (µmol` N)
:param float or pandas.Series mstruct: Structural mass
:return: Amino_acid concentration (µmol` amino acids g-1 mstruct)
:rtype: float
"""
return (amino_acids / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_N_RATIO) / mstruct
[docs]
@staticmethod
def calculate_conc_sucrose(sucrose, mstruct):
"""Sucrose concentration.
:param float or pandas.Series sucrose: C sucrose (µmol` C)
:param float or pandas.Series mstruct: Structural mass
:return: Sucrose concentration (µmol` sucrose g-1 mstruct)
:rtype: float
"""
return (sucrose / mstruct) / cnmetabolism_model.EcophysiologicalConstants.NB_C_SUCROSE
[docs]
@staticmethod
def calculate_conc_fructan(fructan, mstruct):
"""Fructan concentration.
:param float or pandas.Series fructan: C fructan (µmol` C)
:param float or pandas.Series mstruct: Structural mass
:return: Fructan concentration (µmol` fructan g-1 mstruct, eq. glucose).
:rtype: float
"""
return (fructan / mstruct) / cnmetabolism_model.EcophysiologicalConstants.NB_C_HEXOSES
[docs]
@staticmethod
def calculate_conc_protein(proteins, mstruct):
"""Proteins concentration.
:param float or pandas.Series proteins: N proteins (µmol` N)
:param float or pandas.Series mstruct: Structural mass
:return: Protein concentration (g proteins g-1 mstruct)
:rtype: float
"""
mass_N_proteins = proteins * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS #: Mass of N in proteins (g)
masS_proteins = mass_N_proteins / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO #: Total mass of proteins (g)
return masS_proteins / mstruct
[docs]
@staticmethod
def calculate_RER(delta_leaf_L, leaf_L, delta_t):
"""Relative Extension Rate.
:param float or pandas.Series delta_leaf_L: delta of leaf length between t and t-1 (m)
:param float or pandas.Series leaf_L: leaf length (m)
:param float or pandas.Series delta_t: delta_t (s)
:return: Relative Extension Rate (s-1)
:rtype: float
"""
return (delta_leaf_L / delta_t) / leaf_L
[docs]
class Element:
"""
Post-processing to apply on Element outputs.
"""
def __init__(self):
pass
[docs]
@staticmethod
def calculate_dry_mass(triosesP, sucrose, starch, fructan, nitrates, amino_acids, proteins, mstruct):
"""Dry mass
:param triosesP: Amount of triose phosphates (µmol` C)
:param float or pandas.Series sucrose: Amount of sucrose (µmol` C)
:param float or pandas.Series starch: Amount of sucrose (µmol` C)
:param float or pandas.Series fructan: Amount of sucrose (µmol` C)
:param float or pandas.Series nitrates: Amount of nitrates (µmol` N)
:param float or pandas.Series amino_acids: Amount of sucrose (µmol` N)
:param float or pandas.Series proteins: Amount of sucrose (µmol` N)
:param float or pandas.Series mstruct: structural mass (g)
:return: Dry mass (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
N_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS
dry_mass = ((triosesP * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.TRIOSESP_MOLAR_MASS_C_RATIO +
(sucrose * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO +
(starch * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO +
(fructan * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO +
(nitrates * 1E-6 * N_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.NITRATES_MOLAR_MASS_N_RATIO +
(amino_acids * 1E-6 * N_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO +
(proteins * 1E-6 * N_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO +
mstruct)
return dry_mass
[docs]
@staticmethod
def calculate_WSC_g(triosesP, sucrose, starch, fructan):
""" Mass of Water Soluble Carbohydrates
:param float or pandas.Series triosesP: Amount of triose phosphates (µmol` C)
:param float or pandas.Series sucrose: Amount of sucrose (µmol` C)
:param float or pandas.Series starch: Amount of sucrose (µmol` C)
:param float or pandas.Series fructan: Amount of sucrose (µmol` C)
:return: Water Soluble Carbohydrates (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
WSC_g = ((triosesP * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.TRIOSESP_MOLAR_MASS_C_RATIO +
(sucrose * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO +
(starch * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO +
(fructan * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO
)
return WSC_g
[docs]
@staticmethod
def calculate_fructan_g(fructan):
"""Mass of fructans
:param float or pandas.Series fructan: Amount of fructans (µmol` C)
:return: Dry mass (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
return (fructan * 1E-6 * C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO
[docs]
@staticmethod
def calculate_C_g(triosesP, sucrose, starch, fructan, amino_acids, proteins, mstruct):
"""Mass of carbon metabolites
:param float or pandas.Series triosesP: Amount of triose phosphates (µmol` C)
:param float or pandas.Series sucrose: Amount of sucrose (µmol` C)
:param float or pandas.Series starch: Amount of starch (µmol` C)
:param float or pandas.Series fructan: Amount of fructan (µmol` C)
:param float or pandas.Series amino_acids: Amount of amino acids (µmol` N)
:param float or pandas.Series proteins: Amount of proteins (µmol` N)
:param float or pandas.Series mstruct: structural mass (g)
:return: Dry mass (g)
:rtype: float
"""
C_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS
N_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS
C_mass = ((triosesP * 1E-6 * C_MOLAR_MASS) +
(sucrose * 1E-6 * C_MOLAR_MASS) +
(starch * 1E-6 * C_MOLAR_MASS) +
(fructan * 1E-6 * C_MOLAR_MASS) +
(amino_acids * 1E-6 * N_MOLAR_MASS) *
cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_C_RATIO / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO +
(proteins * 1E-6 * N_MOLAR_MASS) * cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_C_RATIO / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO +
mstruct * cnmetabolism_model.EcophysiologicalConstants.RATIO_C_mstruct)
return C_mass
[docs]
@staticmethod
def calculate_N_g(nitrates, amino_acids, proteins, Nstruct):
"""Mass of N metabolites
:param float or pandas.Series nitrates: Amount of nitrates (µmol` N)
:param float or pandas.Series amino_acids: Amount of amino acids (µmol` N)
:param float or pandas.Series proteins: Amount of proteins (µmol` N)
:param float or pandas.Series Nstruct: N structural mass(g)
:return: Dry mass (g)
:rtype: float
"""
N_MOLAR_MASS = cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS
N_mass = ((nitrates * 1E-6 * N_MOLAR_MASS) +
(amino_acids * 1E-6 * N_MOLAR_MASS) +
(proteins * 1E-6 * N_MOLAR_MASS) +
Nstruct)
return N_mass
[docs]
@staticmethod
def calculate_conc_triosesP(triosesP, mstruct):
"""Triose Phosphates concentration.
:param float or pandas.Series triosesP: Amount of triose phosphates (µmol` C)
:param float or pandas.Series mstruct: Structural mass
:return: Triose phosphates concentration (µmol` triosesP g-1 mstruct)
:rtype: float
"""
return (triosesP / mstruct) / cnmetabolism_model.EcophysiologicalConstants.NB_C_TRIOSEP
[docs]
@staticmethod
def calculate_conc_sucrose(sucrose, mstruct):
"""Sucrose concentration.
:param float or pandas.Series sucrose: Amount of sucrose (µmol` C)
:param float or pandas.Series mstruct: Structural mass
:return: Sucrose concentration (µmol` sucrose g-1 mstruct)
:rtype: float
"""
return (sucrose / mstruct) / cnmetabolism_model.EcophysiologicalConstants.NB_C_SUCROSE
[docs]
@staticmethod
def calculate_conc_starch(starch, mstruct):
"""Starch concentration.
:param float or pandas.Series starch: Amount of sucrose (µmol` C)
:param float or pandas.Series mstruct: Structural mass
:return: Starch concentration (µmol` starch g-1 mstruct)
:rtype: float
"""
return (starch / mstruct) / cnmetabolism_model.EcophysiologicalConstants.NB_C_HEXOSES
[docs]
@staticmethod
def calculate_conc_fructan(fructan, mstruct):
"""Fructan concentration.
:param float or pandas.Series fructan: Amount of fructan (µmol` C)
:param float or pandas.Series mstruct: Structural mass
:return: Fructan concentration (µmol` fructan g-1 mstruct, eq. glucose).
:rtype: float
"""
return (fructan / mstruct) / cnmetabolism_model.EcophysiologicalConstants.NB_C_HEXOSES
[docs]
@staticmethod
def calculate_Conc_Nitrates(nitrates, mstruct):
"""Nitrate concentration.
:param float or pandas.Series nitrates: Amount of nitrates (µmol` N)
:param float or pandas.Series mstruct: Structural mass
:return: Nitrate concentration (µmol` nitrates g-1 mstruct)
:rtype: float
"""
return nitrates / mstruct
[docs]
@staticmethod
def calculate_Conc_Amino_Acids(amino_acids, mstruct):
"""Amino_acid concentration.
:param float or pandas.Series amino_acids: Amount of amino acids (µmol` N)
:param float or pandas.Series mstruct: Structural mass
:return: Amino_acid concentration (µmol` amino acids g-1 mstruct)
:rtype: float
"""
return (amino_acids / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_N_RATIO) / mstruct
[docs]
@staticmethod
def calculate_conc_proteins(proteins, mstruct):
"""Protein concentration.
:param float or pandas.Series proteins: Amount of proteins (µmol` N)
:param float or pandas.Series mstruct: Structural mass
:return: Protein concentration (g proteins g-1 mstruct)
:rtype: float
"""
mass_N_proteins = proteins * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS #: Mass of N in proteins (g)
mass_proteins = mass_N_proteins / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO #: Total mass of proteins (g)
return mass_proteins / mstruct
[docs]
@staticmethod
def calculate_conc_cytokinins(cytokinins, mstruct):
"""Cytokinin concentration.
:param float or pandas.Series cytokinins: Amount of cytokinins (AU)
:param float or pandas.Series mstruct: Structural mass
:return: Cytokinin concentration (AU g-1 mstruct)
:rtype: float
"""
return cytokinins / mstruct
[docs]
@staticmethod
def calculate_SLN(nitrates, amino_acids, proteins, Nstruct, green_area):
""" Surfacic Leaf Nitrogen (SLN, g.m-2)
:param float or pandas.Series nitrates: Amount of nitrates (µmol` N)
:param float or pandas.Series amino_acids: Amount of amino_acids (µmol` N)
:param float or pandas.Series proteins: Amount of proteins (µmol` N)
:param float or pandas.Series Nstruct: Structural N (g)
:param float or pandas.Series green_area: Green area (m-2)
:return: Surfacic Leaf Nitrogen (SLN, g.m-2)
:rtype: float
"""
mass_N_tot = (nitrates + amino_acids + proteins) * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS + Nstruct
return mass_N_tot / green_area
[docs]
@staticmethod
def calculate_SLN_nonstruct(nitrates, amino_acids, proteins, green_area):
""" Surfacic Leaf Nitrogen (SLN, g.m-2)
:param float or pandas.Series nitrates: Amount of nitrates (µmol` N)
:param float or pandas.Series amino_acids: Amount of amino_acids (µmol` N)
:param float or pandas.Series proteins: Amount of proteins (µmol` N)
:param float or pandas.Series green_area: Green area (m-2)
:return: Surfacic Leaf Nitrogen (SLN, g.m-2)
:rtype: float
"""
mass_N_tot = (nitrates + amino_acids + proteins) * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS
return mass_N_tot / green_area
[docs]
@staticmethod
def calculate_SLA(dry_mass, green_area):
"""Specific Leaf Area (SLA, m2.kg-1)
:param float or pandas.Series dry_mass: Dry mass (g)
:param float or pandas.Series green_area: Green area (m-2)
:return: Specific Leaf Area (SLA, m2 kg-1)
:rtype: float
"""
return green_area / (dry_mass * 10 ** -3)
[docs]
@staticmethod
def calculate_surfacic_non_structural(dry_mass, mstruct, green_area):
"""Surfacic content of non-structural mass
:param float or pandas.Series dry_mass: Dry mass (g)
:param float or pandas.Series mstruct: Structural mass (g)
:param float or pandas.Series green_area: Green area (m-2)
:return: Surfacic non-structural mass (g m-2)
:rtype: float
"""
return (dry_mass - mstruct) / green_area
[docs]
@staticmethod
def calculate_ratio_non_structural(dry_mass, mstruct):
"""Surfacic content of nitrogen
:param float or pandas.Series dry_mass: Dry mass (g)
:param float or pandas.Series mstruct: Structural mass (g)
:return: Surfacic non-structural mass (g m-2)
:rtype: float
"""
return (1 - mstruct / dry_mass) * 100
# -----------------------------------------------------------------------------
# --------------------- POST-PROCESSING FRONT-END -----------------------------
# PLEASE USE THIS FUNCTION TO APPLY POST-PROCESSING ON THE OUTPUT OF CN-METABOLISM -
# -----------------------------------------------------------------------------
[docs]
def postprocessing(plants_df=None, axes_df=None, metamers_df=None, hiddenzones_df=None, organs_df=None, elements_df=None, soils_df=None, delta_t=1):
"""
Compute post-processing from CN-Metabolism outputs, and format the post-processing to :class:`dataframes <pandas.DataFrame>`.
For each post-processing output dataframe:
* compute post-processing from CN-Metabolism outputs,
* concatenate CN-Metabolism outputs and post-processing and place the results in a jointed dataframe,
* reorder the columns of the dataframes according to :attr:`PLANTS_RUN_POSTPROCESSING_VARIABLES`,
:attr:`AXES_RUN_POSTPROCESSING_VARIABLES`, :attr:`PHYTOMERS_RUN_POSTPROCESSING_VARIABLES`,
:attr:`ORGANS_RUN_POSTPROCESSING_VARIABLES`, :attr:`HIDDENZONE_RUN_POSTPROCESSING_VARIABLES`,
:attr:`ELEMENTS_RUN_POSTPROCESSING_VARIABLES` and :attr:`SOILS_RUN_POSTPROCESSING_VARIABLES`,
* and convert the indexes of plants and metamers to integers (if relevant).
:param pandas.DataFrame plants_df: CN-Metabolism outputs at plant scale (see :attr:`simulation.Simulation.PLANTS_RUN_VARIABLES`)
:param pandas.DataFrame axes_df: CN-Metabolism outputs at axis scale (see :attr:`simulation.Simulation.AXES_RUN_VARIABLES`)
:param pandas.DataFrame metamers_df: CN-Metabolism outputs at phytomer scale (see :attr:`simulation.Simulation.PHYTOMERS_RUN_VARIABLES`)
:param pandas.DataFrame hiddenzones_df: CN-Metabolism outputs at hidden zone scale (see :attr:`simulation.Simulation.HIDDENZONE_RUN_VARIABLES`)
:param pandas.DataFrame organs_df: CN-Metabolism outputs at organ scale (see :attr:`simulation.Simulation.ORGANS_RUN_VARIABLES`)
:param pandas.DataFrame elements_df: CN-Metabolism outputs at element scale (see :attr:`simulation.Simulation.ELEMENTS_RUN_VARIABLES`)
:param pandas.DataFrame soils_df: CN-Metabolism outputs at soil scale (see :attr:`simulation.Simulation.SOILS_RUN_VARIABLES`)
:param float delta_t: Delta t between 2 outputs (in seconds).
:return: post-processing for each scale:
* plant (see :attr:`PLANTS_RUN_POSTPROCESSING_VARIABLES`)
* axis (see :attr:`AXES_RUN_POSTPROCESSING_VARIABLES`)
* metamer (see :attr:`PHYTOMERS_RUN_POSTPROCESSING_VARIABLES`)
* organ (see :attr:`ORGANS_RUN_POSTPROCESSING_VARIABLES`)
* hidden zone (see :attr:`HIDDENZONE_RUN_POSTPROCESSING_VARIABLES`)
* element (see :attr:`ELEMENTS_RUN_POSTPROCESSING_VARIABLES`)
* and soil (see :attr:`SOILS_RUN_POSTPROCESSING_VARIABLES`)
depending on the dataframes given as argument.
For example, if user passes only dataframes `plants_df`, `axes_df` and `metamers_df`,
then only post-processing dataframes of plants, axes and metamers are returned.
:rtype: tuple [pandas.DataFrame]
"""
returned_dataframes = []
# plants
if plants_df is not None:
pp_plants_df = pd.concat([plants_df, pd.DataFrame(columns=PLANTS_POSTPROCESSING_VARIABLES)], sort=False)
pp_plants_df = pp_plants_df.reindex(list(PLANTS_RUN_POSTPROCESSING_VARIABLES), axis=1, copy=False)
pp_plants_df['plant'] = pp_plants_df['plant'].astype(int)
returned_dataframes.append(pp_plants_df)
else:
returned_dataframes.append(pd.DataFrame({'A': []}))
# metamers
if metamers_df is not None:
pp_metamers_df = pd.concat([metamers_df, pd.DataFrame(columns=PHYTOMERS_POSTPROCESSING_VARIABLES)], sort=False)
pp_metamers_df = pp_metamers_df.reindex(list(PHYTOMERS_RUN_POSTPROCESSING_VARIABLES), axis=1, copy=False)
pp_metamers_df[['plant', 'metamer']] = pp_metamers_df[['plant', 'metamer']].astype(int)
returned_dataframes.append(pp_metamers_df)
else:
returned_dataframes.append(pd.DataFrame({'A': []}))
# organs
if organs_df is not None and axes_df is not None:
axes_df = axes_df[axes_df['axis'] == 'MS'].copy() # TODO : Temporary !
pp_organs_df = pd.concat([organs_df, pd.DataFrame(columns=ORGANS_POSTPROCESSING_VARIABLES)], sort=False)
organs_df['sum_dry_mass'] = (((organs_df.fillna(0)['structure'] + organs_df.fillna(0)[
'starch']) * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO) +
(organs_df.fillna(0)[
'sucrose'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO +
(organs_df.fillna(0)['starch'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.HEXOSE_MOLAR_MASS_C_RATIO +
(organs_df.fillna(0)[
'nitrates'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.NITRATES_MOLAR_MASS_N_RATIO +
(organs_df.fillna(0)[
'amino_acids'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO +
(organs_df.fillna(0)[
'proteins'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS) / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO +
organs_df.fillna(0)['mstruct'])
organs_df['C_g'] = ((organs_df.fillna(0)['sucrose'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS) +
(organs_df.fillna(0)['starch'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.C_MOLAR_MASS) +
(organs_df.fillna(0)[
'amino_acids'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS) * cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_C_RATIO /
cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO + (organs_df.fillna(0)['proteins'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS) *
cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_C_RATIO / cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_MOLAR_MASS_N_RATIO +
organs_df.fillna(0)['mstruct'] * cnmetabolism_model.EcophysiologicalConstants.RATIO_C_mstruct)
organs_df['N_g'] = ((organs_df.fillna(0)['nitrates'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS) +
(organs_df.fillna(0)['amino_acids'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS) +
(organs_df.fillna(0)['proteins'] * 1E-6 * cnmetabolism_model.EcophysiologicalConstants.N_MOLAR_MASS) +
organs_df.fillna(0)['Nstruct'])
pp_organs_df['N_tot'] = organs_df['N_g']
# roots
roots_df = organs_df.loc[organs_df.organ == 'roots']
pp_organs_df.loc[pp_organs_df.organ == 'roots', 'WSC_g'] = Roots.calculate_WSC_g(roots_df['sucrose'])
pp_organs_df.loc[pp_organs_df.organ == 'roots', 'Conc_Nitrates'] = Roots.calculate_Conc_Nitrates(roots_df['nitrates'], roots_df['mstruct'])
pp_organs_df.loc[pp_organs_df.organ == 'roots', 'Conc_Amino_Acids'] = Roots.calculate_Conc_Amino_Acids(roots_df['amino_acids'], roots_df['mstruct'])
pp_organs_df.loc[pp_organs_df.organ == 'roots', 'Conc_Sucrose'] = Roots.calculate_conc_sucrose(roots_df['sucrose'], roots_df['mstruct'])
pp_organs_df.loc[pp_organs_df.organ == 'roots', 'Conc_cytokinins'] = Roots.calculate_conc_cytokinins(roots_df['cytokinins'], roots_df['mstruct'])
pp_organs_df.loc[pp_organs_df.organ == 'roots', 'Conc_cytokinins'] = Roots.calculate_conc_cytokinins(roots_df['cytokinins'], roots_df['mstruct'])
R_residual = np.array(
list(map(respiration_model.RespirationModel.R_residual, roots_df['sucrose'], roots_df['mstruct'] * cnmetabolism_model.Roots.PARAMETERS.ALPHA, roots_df['Total_Organic_Nitrogen'],
soils_df['Tsoil'])))
pp_organs_df.loc[pp_organs_df.organ == 'roots', 'R_residual'] = R_residual
# phloem
phloems_df = organs_df.loc[organs_df.organ == 'phloem']
pp_organs_df.loc[pp_organs_df.organ == 'phloem', 'WSC_g'] = Phloem.calculate_WSC_g(phloems_df['sucrose'])
pp_organs_df.loc[pp_organs_df.organ == 'phloem', 'Conc_Amino_Acids'] = Phloem.calculate_conc_amino_acids(phloems_df['amino_acids'], axes_df.set_index(phloems_df.index)['mstruct'])
pp_organs_df.loc[pp_organs_df.organ == 'phloem', 'Conc_Sucrose'] = Phloem.calculate_conc_sucrose(phloems_df['sucrose'], axes_df.set_index(phloems_df.index)['mstruct'])
# grains
grains_df = organs_df.loc[organs_df.organ == 'grains']
pp_organs_df.loc[pp_organs_df.organ == 'grains', 'Dry_Mass'] = Grains.calculate_dry_mass(grains_df['structure'], grains_df['starch'], grains_df['proteins'])
pp_organs_df.loc[pp_organs_df.organ == 'grains', 'WSC_g'] = Grains.calculate_WSC_g(grains_df['sucrose'], grains_df['starch'])
pp_organs_df.loc[pp_organs_df.organ == 'grains', 'Proteins_N_Mass'] = Grains.calculate_protein_N_mass(grains_df['proteins'])
# endosperm
endosperms_df = organs_df.loc[organs_df.organ == 'endosperm']
pp_organs_df.loc[pp_organs_df.organ == 'endosperm', 'Dry_Mass'] = Endosperm.calculate_dry_mass(endosperms_df['starch'], endosperms_df['proteins'], endosperms_df['mstruct'])
pp_organs_df.loc[pp_organs_df.organ == 'endosperm', 'Starch_g'] = Endosperm.calculate_starch_g(endosperms_df['starch'])
pp_organs_df.loc[pp_organs_df.organ == 'endosperm', 'Proteins_N_Mass'] = Endosperm.calculate_protein_N_mass(endosperms_df['proteins'])
pp_organs_df = pp_organs_df.reindex(columns=list(ORGANS_RUN_POSTPROCESSING_VARIABLES), copy=False)
pp_organs_df['plant'] = pp_organs_df['plant'].astype(int)
returned_dataframes.append(pp_organs_df)
else:
returned_dataframes.append(pd.DataFrame({'A': []}))
# elements
if elements_df is not None:
elements_df['sum_dry_mass'] = Element.calculate_dry_mass(elements_df.fillna(0)['triosesP'],
elements_df.fillna(0)['sucrose'],
elements_df.fillna(0)['starch'],
elements_df.fillna(0)['fructan'],
elements_df.fillna(0)['nitrates'],
elements_df.fillna(0)['amino_acids'],
elements_df.fillna(0)['proteins'],
elements_df['mstruct'])
elements_df['sum_dry_mass_total'] = Element.calculate_dry_mass(elements_df.fillna(0)['triosesP'],
elements_df.fillna(0)['sucrose'],
elements_df.fillna(0)['starch'],
elements_df.fillna(0)['fructan'],
elements_df.fillna(0)['nitrates'],
elements_df.fillna(0)['amino_acids'],
elements_df.fillna(0)['proteins'],
elements_df['max_mstruct'] + elements_df['Nresidual'])
elements_df['C_g'] = Element.calculate_C_g(elements_df.fillna(0)['triosesP'],
elements_df.fillna(0)['sucrose'],
elements_df.fillna(0)['starch'],
elements_df.fillna(0)['fructan'],
elements_df.fillna(0)['amino_acids'],
elements_df.fillna(0)['proteins'],
elements_df['mstruct'])
elements_df['N_g'] = Element.calculate_N_g(elements_df.fillna(0)['nitrates'],
elements_df.fillna(0)['amino_acids'],
elements_df.fillna(0)['proteins'],
elements_df['Nstruct'])
elements_df['N_g_total'] = Element.calculate_N_g(elements_df.fillna(0)['nitrates'],
elements_df.fillna(0)['amino_acids'],
elements_df.fillna(0)['proteins'],
elements_df['Nstruct'] + elements_df['Nresidual'])
elements_df['WSC_g'] = Element.calculate_WSC_g(elements_df.fillna(0)['triosesP'],
elements_df.fillna(0)['sucrose'],
elements_df.fillna(0)['starch'],
elements_df.fillna(0)['fructan'], )
pp_elements_df = pd.concat([elements_df, pd.DataFrame(columns=ELEMENTS_POSTPROCESSING_VARIABLES, dtype='float64')], sort=False)
# pp_elements_df.loc[:, 'Conc_TriosesP'] = Element.calculate_conc_triosesP(elements_df['triosesP'], elements_df['mstruct'])
pp_elements_df.loc[:, 'Conc_Starch'] = Element.calculate_conc_starch(elements_df['starch'], elements_df['mstruct'])
pp_elements_df.loc[:, 'Conc_Sucrose'] = Element.calculate_conc_sucrose(elements_df['sucrose'], elements_df['mstruct'])
pp_elements_df.loc[:, 'Conc_Fructan'] = Element.calculate_conc_fructan(elements_df['fructan'], elements_df['mstruct'])
pp_elements_df.loc[:, 'Conc_Nitrates'] = Element.calculate_Conc_Nitrates(elements_df['nitrates'], elements_df['mstruct'])
pp_elements_df.loc[:, 'Conc_Amino_Acids'] = Element.calculate_Conc_Amino_Acids(elements_df['amino_acids'], elements_df['mstruct'])
pp_elements_df.loc[:, 'Conc_Proteins'] = Element.calculate_conc_proteins(elements_df['proteins'], elements_df['mstruct'])
pp_elements_df.loc[:, 'Conc_cytokinins'] = Element.calculate_conc_cytokinins(elements_df['cytokinins'], elements_df['mstruct'])
pp_elements_df.loc[:, 'Cont_Fructan_DM'] = Element.calculate_fructan_g(elements_df['fructan']) / elements_df['sum_dry_mass'] * 100
pp_elements_df.loc[:, 'Cont_WSC_DM'] = elements_df['WSC_g'] / elements_df['sum_dry_mass'] * 100
pp_elements_df.loc[:, 'Surfacic_NS'] = Element.calculate_surfacic_non_structural(elements_df['sum_dry_mass'],
elements_df['mstruct'], elements_df['green_area'])
pp_elements_df.loc[:, 'NS'] = Element.calculate_ratio_non_structural(elements_df['sum_dry_mass'],
elements_df['mstruct'])
pp_elements_df.loc[:, 'N_content'] = elements_df['N_g'] / elements_df['sum_dry_mass'] * 100
pp_elements_df.loc[:, 'N_content_total_DM'] = elements_df['N_g_total'] / elements_df['sum_dry_mass_total'] * 100
pp_elements_df.loc[:, 'N_tot'] = elements_df['N_g_total']
pp_elements_df.loc[:, 'SLN'] = Element.calculate_SLN(elements_df['nitrates'], elements_df['amino_acids'], elements_df['proteins'],
elements_df['Nstruct'], elements_df['green_area'])
pp_elements_df.loc[pp_elements_df['is_growing'] == 1., 'SLN'] = np.nan
pp_elements_df.loc[:, 'SLN_nonstruct'] = Element.calculate_SLN_nonstruct(elements_df['nitrates'], elements_df['amino_acids'], elements_df['proteins'],
elements_df['green_area'])
pp_elements_df.loc[pp_elements_df['is_growing'] == 1., 'SLN_nonstruct'] = np.nan
pp_elements_df.loc[:, 'SLA'] = Element.calculate_SLA(elements_df['sum_dry_mass'], elements_df['green_area'])
pp_elements_df.loc[pp_elements_df['is_growing'] == 1., 'SLA'] = np.nan
pp_elements_df.loc[:, 'Photosynthetic_efficiency'] = elements_df['Ag'] / elements_df['PARa']
grouped = elements_df.groupby('organ')
for organ_type, parameters_class in \
(('ear', cnmetabolism_parameters.CHAFF_ELEMENT_PARAMETERS),
('blade', cnmetabolism_parameters.LAMINA_ELEMENT_PARAMETERS),
('internode', cnmetabolism_parameters.INTERNODE_ELEMENT_PARAMETERS),
('peduncle', cnmetabolism_parameters.PEDUNCLE_ELEMENT_PARAMETERS),
('sheath', cnmetabolism_parameters.SHEATH_ELEMENT_PARAMETERS)):
if organ_type not in grouped.groups:
continue
group = grouped.get_group(organ_type)
if len(group) == 0: # TODO: faire mm tri que dans simulation de cnmetabolism (surface nulle)
continue
curr_organ_elements_df = elements_df.loc[group.index]
pp_curr_organ_elements_df = pp_elements_df.loc[group.index]
R_residual = np.vectorize(respiration_model.RespirationModel.R_residual)(curr_organ_elements_df['sucrose'].fillna(0), curr_organ_elements_df['mstruct'].fillna(0) * parameters_class.ALPHA,
curr_organ_elements_df['Total_Organic_Nitrogen'].fillna(0), curr_organ_elements_df['Ts'].fillna(0))
pp_curr_organ_elements_df.loc[:, 'R_residual'] = R_residual
pp_elements_df = pp_elements_df.reindex(columns=list(ELEMENTS_RUN_POSTPROCESSING_VARIABLES))
pp_elements_df[['plant', 'metamer']] = pp_elements_df[['plant', 'metamer']].astype(int)
returned_dataframes.append(pp_elements_df)
else:
returned_dataframes.append(pd.DataFrame({'A': []}))
# hidden zones
if hiddenzones_df is not None:
# hiddenzones_df = hiddenzones_df.merge(nb_replications_df, on='metamer')
hiddenzones_df['sum_dry_mass'] = HiddenZone.calculate_dry_mass(hiddenzones_df.fillna(0)['sucrose'],
hiddenzones_df.fillna(0)['fructan'],
hiddenzones_df.fillna(0)['amino_acids'],
hiddenzones_df.fillna(0)['proteins'],
hiddenzones_df['mstruct'])
hiddenzones_df['C_g'] = HiddenZone.calculate_C_g(hiddenzones_df.fillna(0)['sucrose'],
0, # hiddenzones_df.fillna(0)['starch'],
hiddenzones_df.fillna(0)['fructan'],
hiddenzones_df.fillna(0)['amino_acids'],
hiddenzones_df.fillna(0)['proteins'],
hiddenzones_df['mstruct'])
hiddenzones_df['N_g'] = HiddenZone.calculate_N_g(hiddenzones_df.fillna(0)['amino_acids'],
hiddenzones_df.fillna(0)['proteins'],
hiddenzones_df['leaf_enclosed_Nstruct'] + hiddenzones_df['internode_enclosed_Nstruct'])
hiddenzones_df['WSC_g'] = HiddenZone.calculate_WSC_g(hiddenzones_df.fillna(0)['sucrose'],
hiddenzones_df.fillna(0)['fructan'])
pp_hiddenzones_df = pd.concat([hiddenzones_df, pd.DataFrame(columns=HIDDENZONE_POSTPROCESSING_VARIABLES, dtype='float64')], sort=False)
pp_hiddenzones_df.loc[:, 'Conc_Amino_Acids'] = HiddenZone.calculate_Conc_Amino_Acids(hiddenzones_df['amino_acids'], hiddenzones_df['mstruct'])
pp_hiddenzones_df.loc[:, 'Conc_Fructan'] = HiddenZone.calculate_conc_fructan(hiddenzones_df['fructan'], hiddenzones_df['mstruct'])
pp_hiddenzones_df.loc[:, 'Conc_Proteins'] = HiddenZone.calculate_conc_protein(hiddenzones_df['proteins'], hiddenzones_df['mstruct'])
pp_hiddenzones_df.loc[:, 'Conc_Sucrose'] = HiddenZone.calculate_conc_sucrose(hiddenzones_df['sucrose'], hiddenzones_df['mstruct'])
pp_hiddenzones_df.loc[:, 'Cont_Fructan_DM'] = HiddenZone.calculate_fructan_g(hiddenzones_df['fructan']) / hiddenzones_df['sum_dry_mass'] * 100
pp_hiddenzones_df.loc[:, 'Cont_Proteins_DM'] = HiddenZone.calculate_proteins_g(hiddenzones_df['proteins']) / hiddenzones_df['sum_dry_mass'] * 100
pp_hiddenzones_df.loc[:, 'Cont_WSC_DM'] = hiddenzones_df['WSC_g'] / hiddenzones_df['sum_dry_mass'] * 100
pp_hiddenzones_df.loc[:, 'N_content'] = pp_hiddenzones_df['N_g'] / pp_hiddenzones_df['sum_dry_mass'] * 100
if set(hiddenzones_df.columns).issuperset(['delta_leaf_L', 'leaf_L']):
# this is temporary: those post-processing should be done in model "morphogenesis"
pp_hiddenzones_df.loc[:, 'RER'] = HiddenZone.calculate_RER(hiddenzones_df['delta_leaf_L'], hiddenzones_df['leaf_L'], delta_t)
pp_hiddenzones_df = pp_hiddenzones_df.reindex(columns=list(HIDDENZONE_RUN_POSTPROCESSING_VARIABLES), copy=False)
pp_hiddenzones_df[['plant', 'metamer']] = pp_hiddenzones_df[['plant', 'metamer']].astype(int)
returned_dataframes.append(pp_hiddenzones_df)
else:
returned_dataframes.append(pd.DataFrame({'A': []}))
# axes
if axes_df is not None:
axes_df = axes_df[axes_df['axis'] == 'MS'].copy() # TODO : Temporary !
pp_axes_df = pd.concat([axes_df, pd.DataFrame(columns=AXES_POSTPROCESSING_VARIABLES)], sort=False)
# Integrated variables TODO : Homogeneiser la structure de ce bout de code
if (hiddenzones_df is not None) and (organs_df is not None) and (elements_df is not None):
# Add missing row if any
axes_row_keys = organs_df[AXES_T_INDEXES].drop_duplicates()
pp_axes_df = pp_axes_df.merge(axes_row_keys, how='outer', on=AXES_T_INDEXES)
pp_axes_df.sort_values(AXES_T_INDEXES, inplace=True) # Make sure axes_df is sorted
pp_axes_df.reset_index(drop=True, inplace=True)
# Roots
dry_mass_roots = organs_df[(organs_df['organ'] == 'roots')].groupby(['t', 'plant', 'axis'])['sum_dry_mass'].agg('sum')
# Total mstruct shoot and root
hz_df_MS = hiddenzones_df[hiddenzones_df['axis'] == 'MS'].copy()
elt_df_MS = elements_df[elements_df['axis'] == 'MS'].copy()
hz_df_MS['mstruct_tillers'] = hz_df_MS['mstruct'] * hz_df_MS['nb_replications']
elt_df_MS['mstruct_tillers'] = elt_df_MS['mstruct'] * elt_df_MS['nb_replications']
sum_mstruct_shoot = hz_df_MS.groupby(['t', 'plant', 'axis'])['mstruct_tillers'].agg('sum') + elt_df_MS.groupby(['t', 'plant', 'axis'])['mstruct_tillers'].agg('sum')
sum_mstruct_shoot.fillna(0, inplace=True)
if not elements_df.empty:
sum_mstruct_laminae = elt_df_MS[elt_df_MS.element == 'LeafElement1'].groupby(['t', 'plant', 'axis'])['mstruct_tillers'].agg('sum')
if sum_mstruct_laminae.empty:
sum_mstruct_laminae = pd.Series([0] * len(axes_df.index), index=sum_mstruct_shoot.index)
sum_mstruct_stem = sum_mstruct_shoot
else:
mux = (pd.MultiIndex.from_product((range(sum_mstruct_shoot.index.get_level_values(0).min(), sum_mstruct_laminae.index.get_level_values(0).max() + 1),
sum_mstruct_laminae.index.get_level_values(1).unique(), sum_mstruct_laminae.index.get_level_values(2).unique())))
sum_mstruct_laminae = sum_mstruct_laminae.reindex(mux, fill_value=0)
sum_mstruct_stem = sum_mstruct_shoot - sum_mstruct_laminae
else:
sum_mstruct_laminae = pd.Series([0] * len(axes_df.index))
sum_mstruct_stem = sum_mstruct_shoot
sum_mstruct_roots = organs_df[(organs_df['organ'] == 'roots')].groupby(['t', 'plant', 'axis'])['mstruct'].agg('sum')
shoot_roots_mstruct_ratio = sum_mstruct_shoot / sum_mstruct_roots
# Phloem
phloem_shoot_root = 1 / (1 + 1 / shoot_roots_mstruct_ratio)
phloem_stem = sum_mstruct_stem / (sum_mstruct_shoot + sum_mstruct_roots)
sum_dry_mass_phloem = organs_df[(organs_df['organ'] == 'phloem')].groupby(['t', 'plant', 'axis'])['sum_dry_mass'].agg('sum')
sum_dry_mass_phloem_shoot = sum_dry_mass_phloem * phloem_shoot_root
sum_dry_mass_phloem_roots = sum_dry_mass_phloem * (1 - phloem_shoot_root)
sum_N_g_phloem_shoot = organs_df[(organs_df['organ'] == 'phloem')].groupby(['t', 'plant', 'axis'])['N_g'].agg('sum') * phloem_shoot_root
sum_C_g_phloem_shoot = organs_df[(organs_df['organ'] == 'phloem')].groupby(['t', 'plant', 'axis'])['C_g'].agg('sum') * phloem_shoot_root
sum_WSC_g_phloem_shoot = pp_organs_df[(organs_df['organ'] == 'phloem')].groupby(['t', 'plant', 'axis'])['WSC_g'].agg('sum') * phloem_shoot_root
sum_WSC_g_phloem_stem = pp_organs_df[(organs_df['organ'] == 'phloem')].groupby(['t', 'plant', 'axis'])['WSC_g'].agg('sum') * phloem_stem
sum_WSC_g_phloem_roots = pp_organs_df[(organs_df['organ'] == 'phloem')].groupby(['t', 'plant', 'axis'])['WSC_g'].agg('sum') * (1 - phloem_shoot_root)
if not elements_df.empty:
phloem_laminae = sum_mstruct_laminae / (sum_mstruct_shoot + sum_mstruct_roots)
sum_dry_mass_phloem_laminae = sum_dry_mass_phloem * phloem_laminae
sum_WSC_g_phloem_laminae = pp_organs_df[(organs_df['organ'] == 'phloem')].groupby(['t', 'plant', 'axis'])['WSC_g'].agg('sum') * phloem_laminae
# Total shoot
hz_df_MS['sum_dry_mass_tillers'] = hz_df_MS['sum_dry_mass'] * hz_df_MS['nb_replications']
elt_df_MS['sum_dry_mass_tillers'] = elt_df_MS['sum_dry_mass'] * elt_df_MS['nb_replications']
elt_df_MS['sum_dry_mass_total_tillers'] = elt_df_MS['sum_dry_mass_total'] * elt_df_MS['nb_replications']
sum_dry_mass_shoot = sum_dry_mass_phloem_shoot + \
hz_df_MS.groupby(['t', 'plant', 'axis'])['sum_dry_mass_tillers'].agg('sum') + \
elt_df_MS.groupby(['t', 'plant', 'axis'])['sum_dry_mass_tillers'].agg('sum')
if not elements_df.empty:
sum_dry_mass_laminae = sum_dry_mass_phloem_laminae + \
elt_df_MS[elt_df_MS.element == 'LeafElement1'].groupby(['t', 'plant', 'axis'])['sum_dry_mass_tillers'].agg('sum')
sum_dry_mass_laminae.fillna(0, inplace=True)
sum_dry_mass_stem = sum_dry_mass_shoot - sum_dry_mass_laminae
else:
sum_dry_mass_laminae = pd.Series([0] * len(axes_df.index))
sum_dry_mass_stem = sum_dry_mass_shoot
sum_dry_mass_total_shoot = sum_dry_mass_phloem_shoot + \
hz_df_MS.groupby(['t', 'plant', 'axis'])['sum_dry_mass_tillers'].agg('sum') + \
elt_df_MS.groupby(['t', 'plant', 'axis'])['sum_dry_mass_total_tillers'].agg('sum')
# Total root
sum_dry_mass_roots = sum_dry_mass_phloem_roots + dry_mass_roots
# Total shoot + roots
sum_dry_mass = sum_dry_mass_shoot + sum_dry_mass_roots
sum_mstruct = sum_mstruct_roots + sum_mstruct_shoot
# N content
hz_df_MS['N_g_tillers'] = hz_df_MS['N_g'] * hz_df_MS['nb_replications']
elt_df_MS['N_g_tillers'] = elt_df_MS['N_g'] * elt_df_MS['nb_replications']
elt_df_MS['N_g_total_tillers'] = elt_df_MS['N_g_total'] * elt_df_MS['nb_replications']
sum_N_g = (organs_df[organs_df['axis'] == 'MS'].groupby(['t', 'plant', 'axis'])['N_g'].agg('sum') +
hz_df_MS.groupby(['t', 'plant', 'axis'])['N_g_tillers'].agg('sum') +
elt_df_MS.groupby(['t', 'plant', 'axis'])['N_g_tillers'].agg('sum'))
N_content = sum_N_g / sum_dry_mass * 100
N_content_mstruct = sum_N_g / sum_mstruct * 100
sum_N_g_shoot = (sum_N_g_phloem_shoot +
hz_df_MS.groupby(['t', 'plant', 'axis'])['N_g_tillers'].agg('sum') +
elt_df_MS.groupby(['t', 'plant', 'axis'])['N_g_tillers'].agg('sum')).fillna(0)
sum_N_g_total_shoot = (sum_N_g_phloem_shoot +
hz_df_MS.groupby(['t', 'plant', 'axis'])['N_g_tillers'].agg('sum') +
elt_df_MS.groupby(['t', 'plant', 'axis'])['N_g_total_tillers'].agg('sum'))
N_content_shoot = sum_N_g_shoot / sum_dry_mass_shoot * 100
N_content_total_DM_shoot = sum_N_g_total_shoot / sum_dry_mass_total_shoot * 100
N_content_mstruct_shoot = sum_N_g_shoot / sum_mstruct_shoot * 100
N_content_roots = (N_content * sum_dry_mass - N_content_shoot * sum_dry_mass_shoot) / sum_dry_mass_roots
N_content_mstruct_roots = (N_content_mstruct * sum_mstruct - N_content_mstruct_shoot * sum_mstruct_shoot) / sum_mstruct_roots
# WSC
hz_df_MS['WSC_g_tillers'] = hz_df_MS['WSC_g'] * hz_df_MS['nb_replications']
elt_df_MS['WSC_g_tillers'] = elt_df_MS['WSC_g'] * elt_df_MS['nb_replications']
WSC_g_plant = hz_df_MS.groupby(['t', 'plant', 'axis'])['WSC_g_tillers'].agg('sum') + elt_df_MS.groupby(['t', 'plant', 'axis'])['WSC_g_tillers'].agg('sum') + \
pp_organs_df.groupby(['t', 'plant', 'axis'])['WSC_g'].agg('sum')
sum_WSC_g_shoot = (sum_WSC_g_phloem_shoot +
hz_df_MS.groupby(['t', 'plant', 'axis'])['WSC_g_tillers'].agg('sum') +
elt_df_MS.groupby(['t', 'plant', 'axis'])['WSC_g_tillers'].agg('sum'))
if not elements_df.empty:
sum_WSC_g_laminae = (sum_WSC_g_phloem_laminae +
elt_df_MS[elt_df_MS.element == 'LeafElement1'].groupby(['t', 'plant', 'axis'])['WSC_g_tillers'].agg('sum')).fillna(0)
else:
sum_WSC_g_laminae = pd.Series([0] * len(axes_df.index))
sum_WSC_g_stem = (sum_WSC_g_phloem_stem +
hz_df_MS.groupby(['t', 'plant', 'axis'])['WSC_g_tillers'].agg('sum') +
elt_df_MS[~(elt_df_MS.element == 'LeafElement1')].groupby(['t', 'plant', 'axis'])['WSC_g_tillers'].agg('sum'))
sum_WSC_g_roots = (sum_WSC_g_phloem_roots + pp_organs_df[(organs_df['organ'] == 'roots')].groupby(['t', 'plant', 'axis'])['WSC_g'].agg('sum'))
# C/N ratio
hz_df_MS['C_g_tillers'] = hz_df_MS['C_g'] * hz_df_MS['nb_replications']
elt_df_MS['C_g_tillers'] = elt_df_MS['C_g'] * elt_df_MS['nb_replications']
sum_C_g = (organs_df[organs_df['axis'] == 'MS'].groupby(['t', 'plant', 'axis'])['C_g'].agg('sum') +
hz_df_MS.groupby(['t', 'plant', 'axis'])['C_g_tillers'].agg('sum') +
elt_df_MS.groupby(['t', 'plant', 'axis'])['C_g_tillers'].agg('sum'))
sum_C_g_shoot = (sum_C_g_phloem_shoot +
hz_df_MS.groupby(['t', 'plant', 'axis'])['C_g_tillers'].agg('sum') +
elt_df_MS.groupby(['t', 'plant', 'axis'])['C_g_tillers'].agg('sum')).fillna(0)
C_N_ratio = sum_C_g / sum_N_g
C_N_ratio_shoot = sum_C_g_shoot / sum_N_g_shoot
# C non structural
sum_NSC_g = sum_C_g.values - (axes_df['mstruct'] * cnmetabolism_model.EcophysiologicalConstants.RATIO_C_mstruct)
# Photosynthesis
if not elements_df.empty:
elements_df['Tillers_Photosynthesis'] = elements_df['Photosynthesis'] * elements_df['nb_replications']
elements_df['Tillers_Photosynthesis_An'] = elements_df['An'] * elements_df['green_area'] * 3600 * elements_df['nb_replications']
tillers_photosynthesis = elements_df[elements_df['axis'] == 'MS'].groupby(['t', 'plant', 'axis'])['Tillers_Photosynthesis'].agg('sum') # TEMPORARY : porter au niveau de la plante
mux = (pd.MultiIndex.from_product((range(pp_axes_df.index.get_level_values(0).min(), tillers_photosynthesis.index.get_level_values(0).max() + 1),
tillers_photosynthesis.index.get_level_values(1).unique(), tillers_photosynthesis.index.get_level_values(2).unique())))
tillers_photosynthesis = tillers_photosynthesis.reindex(mux, fill_value=0)
tillers_photosynthesis_An = elements_df[elements_df['axis'] == 'MS'].groupby(['t', 'plant', 'axis'])['Tillers_Photosynthesis_An'].agg('sum')
tillers_photosynthesis_An = tillers_photosynthesis_An.reindex(mux, fill_value=0)
tot_photosynthesis = elements_df[elements_df['axis'] == 'MS'].groupby(['t', 'plant', 'axis'])['Photosynthesis'].agg('sum')
tot_photosynthesis = tot_photosynthesis.reindex(mux, fill_value=0)
else:
tillers_photosynthesis = pd.Series([0] * len(axes_df.index))
tillers_photosynthesis_An = pd.Series([0] * len(axes_df.index))
tot_photosynthesis = pd.Series([0] * len(axes_df.index))
# INN
DM_t_ha = sum_dry_mass_shoot * 250 * 10 ** -2 # convert from g.plant-1 to t.ha-1
N_content_critical = np.where(DM_t_ha < 1.55, 4.4, 5.35 * DM_t_ha ** -0.442) # from Justes 1994 : valid at field scale from Feekes 3 i.e. mid tillering
NNI = N_content_shoot / N_content_critical
# Ratio Non-Structural Mass
NS_shoot = (1 - sum_mstruct_shoot / sum_dry_mass_shoot) * 100
NS_stem = (1 - sum_mstruct_stem / sum_dry_mass_stem) * 100
if not elements_df.empty:
NS_laminae = (1 - sum_mstruct_laminae / sum_dry_mass_laminae) * 100
else:
NS_laminae = pd.Series([0] * len(axes_df.index))
NS_roots = (1 - sum_mstruct_roots / sum_dry_mass_roots) * 100
NS = (1 - sum_mstruct / sum_dry_mass) * 100
# C_respired_shoot
hiddenzones_df['sum_respi'] = (hiddenzones_df.Respi_growth.fillna(0) + hiddenzones_df.R_residual.fillna(0)) * hiddenzones_df.nb_replications
hz_respi = hiddenzones_df.groupby('t')['sum_respi'].sum()
elements_df['sum_respi'] = (elements_df.R_phloem_loading + elements_df.R_Nnit_red + elements_df.R_residual) * elements_df.nb_replications
elements_respi = elements_df.groupby('t')['sum_respi'].sum()
grains_df['sum_respi'] = (grains_df.R_grain_growth_struct + grains_df.R_grain_growth_starch).fillna(0)
grains_respi = grains_df.groupby('t')['sum_respi'].sum()
C_respired_shoot = hz_respi.add(elements_respi, fill_value=0).add(grains_respi, fill_value=0)
# C_respired_roots
roots_df['sum_respi_roots'] = roots_df['Respi_growth'] + roots_df['sum_respi']
C_respired_roots = roots_df['sum_respi_roots'].reset_index(drop=True)
# C exuded
roots_df['sum_C_exuded'] = (roots_df.C_exudation + roots_df.N_exudation * cnmetabolism_model.EcophysiologicalConstants.AMINO_ACIDS_C_RATIO / cnmetabolism_model.
EcophysiologicalConstants.AMINO_ACIDS_N_RATIO) * roots_df.mstruct
C_exuded_roots = roots_df['sum_C_exuded'].reset_index(drop=True)
# Add to axes df
pp_axes_df.sort_values(AXES_T_INDEXES, inplace=True) # Make sure axes_df is sorted
pp_axes_df.loc[:, 'C_N_ratio'] = C_N_ratio.values
pp_axes_df.loc[:, 'C_N_ratio_shoot'] = C_N_ratio_shoot.values
pp_axes_df.loc[:, 'N_content'] = N_content.values
pp_axes_df.loc[:, 'N_content_shoot'] = N_content_shoot.values
pp_axes_df.loc[:, 'N_content_roots'] = N_content_roots.values
pp_axes_df.loc[:, 'N_content_mstruct'] = N_content_mstruct.values
pp_axes_df.loc[:, 'N_content_mstruct_shoot'] = N_content_mstruct_shoot.values
pp_axes_df.loc[:, 'N_content_total_DM_shoot'] = N_content_total_DM_shoot.values
pp_axes_df.loc[:, 'N_content_mstruct_roots'] = N_content_mstruct_roots.values
pp_axes_df.loc[:, 'sum_N_g'] = sum_N_g.values
pp_axes_df.loc[:, 'sum_N_g_shoot'] = sum_N_g_shoot.values
pp_axes_df.loc[:, 'sum_dry_mass'] = sum_dry_mass.values
pp_axes_df.loc[:, 'sum_dry_mass_shoot'] = sum_dry_mass_shoot.values
pp_axes_df.loc[:, 'sum_dry_mass_laminae'] = sum_dry_mass_laminae.values
pp_axes_df.loc[:, 'sum_dry_mass_stem'] = sum_dry_mass_stem.values
pp_axes_df.loc[:, 'sum_dry_mass_roots'] = sum_dry_mass_roots.values
pp_axes_df.loc[:, 'sum_C_g'] = sum_C_g.values
pp_axes_df.loc[:, 'sum_NSC_g'] = sum_NSC_g.values
pp_axes_df.loc[:, 'dry_mass_phloem'] = sum_dry_mass_phloem.values
pp_axes_df.loc[:, 'shoot_roots_ratio'] = pp_axes_df['sum_dry_mass_shoot'] / pp_axes_df['sum_dry_mass_roots']
pp_axes_df.loc[:, 'shoot_roots_mstruct_ratio'] = shoot_roots_mstruct_ratio.values
pp_axes_df.loc[:, 'Total_Photosynthesis'] = tot_photosynthesis.values
pp_axes_df.loc[:, 'Tillers_Photosynthesis'] = tillers_photosynthesis.values
pp_axes_df.loc[:, 'Tillers_Photosynthesis_An'] = tillers_photosynthesis_An.values
pp_axes_df.loc[:, 'NNI'] = NNI.values
pp_axes_df.loc[:, 'NS_roots'] = NS_roots.values
pp_axes_df.loc[:, 'NS_shoot'] = NS_shoot.values
pp_axes_df.loc[:, 'NS_stem'] = NS_stem.values
pp_axes_df.loc[:, 'NS_laminae'] = NS_laminae.values
pp_axes_df.loc[:, 'NS'] = NS.values
pp_axes_df.loc[:, 'mstruct_shoot'] = sum_mstruct_shoot.values
pp_axes_df.loc[:, 'mstruct_laminae'] = sum_mstruct_laminae.values
pp_axes_df.loc[:, 'mstruct_stem'] = sum_mstruct_stem.values
pp_axes_df.loc[:, 'C_respired_shoot'] = C_respired_shoot
pp_axes_df.loc[:, 'C_respired_roots'] = C_respired_roots
pp_axes_df.loc[:, 'WSC_g'] = WSC_g_plant.values
pp_axes_df.loc[:, 'Cont_WSC_DM'] = pp_axes_df['WSC_g'] / pp_axes_df['sum_dry_mass'] * 100
pp_axes_df.loc[:, 'Cont_WSC_DM_shoot'] = sum_WSC_g_shoot.values / sum_dry_mass_shoot.values * 100
if sum_dry_mass_laminae.sum() != 0:
pp_axes_df.loc[:, 'Cont_WSC_DM_laminae'] = sum_WSC_g_laminae.to_numpy() / sum_dry_mass_laminae.replace(0, np.nan).to_numpy() * 100
else:
pp_axes_df.loc[:, 'Cont_WSC_DM_laminae'] = [0] * len(pp_axes_df.index)
pp_axes_df.loc[:, 'Cont_WSC_DM_stem'] = sum_WSC_g_stem.values / sum_dry_mass_stem.values * 100
pp_axes_df.loc[:, 'Cont_WSC_DM_roots'] = sum_WSC_g_roots.values / sum_dry_mass_roots.values * 100
pp_axes_df.loc[:, 'C_exuded'] = C_exuded_roots.values
pp_axes_df = pp_axes_df.reindex(list(AXES_RUN_POSTPROCESSING_VARIABLES), axis=1)
pp_axes_df['plant'] = pp_axes_df['plant'].astype(int)
returned_dataframes.append(pp_axes_df)
else:
returned_dataframes.append(pd.DataFrame({'A': []}))
# soils
if soils_df is not None:
pp_soils_df = pd.concat([soils_df, pd.DataFrame(columns=SOILS_POSTPROCESSING_VARIABLES)])
pp_soils_df = pp_soils_df.reindex(columns=SOILS_RUN_POSTPROCESSING_VARIABLES, copy=False)
pp_soils_df[['plant']] = pp_soils_df[['plant']].astype(int)
returned_dataframes.append(pp_soils_df)
else:
returned_dataframes.append(pd.DataFrame({'A': []}))
return tuple(returned_dataframes)
# -----------------------------------------------------------
# --------------- GRAPHS GENERATION FRONT-END ---------------
# -- PLEASE USE THIS FUNCTION FOR THE GENERATION OF GRAPHS --
# -----------------------------------------------------------
[docs]
def generate_graphs(axes_df=None, hiddenzones_df=None, organs_df=None, elements_df=None, soils_df=None, meteo_data=None, graphs_dirpath='.'):
"""
Generate graphs to validate the outputs of CN-Metabolism, and save them in directory `graphs_dirpath`.
:param pandas.DataFrame axes_df: CN-Metabolism outputs and post-processing at axis scale (see :attr:`PLANTS_RUN_POSTPROCESSING_VARIABLES`)
:param pandas.DataFrame hiddenzones_df: CN-Metabolism outputs at hidden zone scale (see :attr:`HIDDENZONE_RUN_POSTPROCESSING_VARIABLES`)
:param pandas.DataFrame organs_df: CN-Metabolism outputs at organ scale (see :attr:`ORGANS_RUN_POSTPROCESSING_VARIABLES`)
:param pandas.DataFrame elements_df: CN-Metabolism outputs at element scale (see :attr:`ELEMENTS_RUN_POSTPROCESSING_VARIABLES`)
:param pandas.DataFrame soils_df: CN-Metabolism outputs at soil scale (see :attr:`SOILS_RUN_POSTPROCESSING_VARIABLES`)
:param pandas.DataFrame meteo_data: the meteo dataframe having the mapping between t (hours) and calendar dates
:param str graphs_dirpath: the path of the directory to save the generated graphs in
"""
x_name = 't'
x_label = 'Time (Hour)'
colors = ['blue', 'darkorange', 'green', 'red', 'darkviolet', 'gold', 'magenta', 'brown', 'darkcyan', 'grey', 'lime']
colors = colors + colors + colors + colors + colors
# 1) Photosynthetic organs
if elements_df is not None:
elements_df = elements_df.loc[elements_df['mstruct'] != 0]
graph_variables_ph_elements = {'Ag': u'Gross photosynthesis (µmol m$^{-2}$ s$^{-1}$)', 'Tr': u'Organ surfacic transpiration rate (mmol H$_{2}$0 m$^{-2}$ s$^{-1}$)',
'Transpiration': u'Organ transpiration rate (mmol H$_{2}$0 s$^{-1}$)', 'Ts': u'Temperature surface (°C)', 'Conc_TriosesP': u'[TriosesP] (µmol g$^{-1}$ mstruct)',
'Conc_Starch': u'[Starch] (µmol g$^{-1}$ mstruct)', 'Conc_Sucrose': u'[Sucrose] (µmol g$^{-1}$ mstruct)', 'Conc_Fructan': u'[Fructan] (µmol g$^{-1}$ mstruct)',
'Conc_Nitrates': u'[Nitrates] (µmol g$^{-1}$ mstruct)', 'Conc_Amino_Acids': u'[Amino_Acids] (µmol g$^{-1}$ mstruct)',
'Conc_Proteins': u'[Proteins] (g g$^{-1}$ mstruct)', 'Cont_Fructan_DM': u'Fructan content (% DM)', 'Cont_WSC_DM': u'WSC content (% DM)',
'Nitrates_import': u'Total nitrates imported (µmol h$^{-1}$)',
'Amino_Acids_import': u'Total amino acids imported (µmol N h$^{-1}$)', 'S_Amino_Acids': u'[Rate of amino acids synthesis] (µmol N g$^{-1}$ mstruct h$^{-1}$)',
'S_Proteins': u'Rate of protein synthesis (µmol N g$^{-1}$ mstruct h$^{-1}$)', 'D_Proteins': u'Rate of protein degradation (µmol N g$^{-1}$ mstruct h$^{-1}$)',
'Loading_Sucrose': u'Loading Sucrose (µmol C sucrose h$^{-1}$)', 'Loading_Amino_Acids': u'Loading Amino acids (µmol N amino acids h$^{-1}$)',
'green_area': u'Green area (m$^{2}$)', 'R_phloem_loading': u'Respiration phloem loading (µmol C h$^{-1}$)',
'R_Nnit_red': u'Respiration nitrate reduction (µmol C h$^{-1}$)', 'R_residual': u'Respiration residual (µmol C h$^{-1}$)', 'mstruct': u'Structural mass (g)',
'Nstruct': u'Structural N mass (g)', 'Conc_cytokinins': u'[cytokinins] (UA g$^{-1}$ mstruct)', 'D_cytokinins': u'Cytokinin degradation (UA g$^{-1}$ mstruct)',
'cytokinins_import': u'Cytokinin import (UA)', 'Surfacic_NS': u'Surfacic Non Structural mass (g m$^{-2}$)',
'NS': u'Ratio of Non Structural mass', 'N_content': u'N content in the green tissues (% DM)',
'N_content_total_DM': u'N content in the green + senesced tissues (% DM)', 'N_tot': u'N mass (g)',
'SLA': u'Specific Leaf Area (m$^{2}$.kg$^{-1}$)',
'SLN': u'Surfacic Leaf Nitrogen (g.m$^{-2}$)',
'SLN_nonstruct': u'Surfacic Leaf Non-structural Nitrogen (g.m$^{-2}$)', 'length': u'Length (m)',
'Photosynthetic_efficiency': u'Photosynthetic yield (µmol C/µmol PARa)'}
for org_ph in (['blade'], ['sheath'], ['internode'], ['peduncle', 'ear']):
for variable_name, variable_label in graph_variables_ph_elements.items():
graph_name = variable_name + '_' + '_'.join(org_ph) + '.PNG'
integration_tools.plot_outputs(elements_df,
x_name=x_name,
y_name=variable_name,
x_label=x_label,
y_label=variable_label,
colors=[colors[i - 1] for i in elements_df.metamer.unique().tolist()],
filters={'axis': 'MS', 'organ': org_ph},
plot_filepath=os.path.join(graphs_dirpath, graph_name),
meteo_data=meteo_data,
explicit_label=False)
# 2) Roots, grains, endosperm and phloem
if organs_df is not None:
graph_variables_organs = {'Conc_Sucrose': u'[Sucrose] (µmol g$^{-1}$ mstruct)', 'Dry_Mass': 'Dry mass (g)', 'Conc_Nitrates': u'[Nitrates] (µmol g$^{-1}$ mstruct)',
'Conc_Amino_Acids': u'[Amino Acids] (µmol g$^{-1}$ mstruct)', 'Proteins_N_Mass': 'N Proteins (g)', 'Starch_g': 'Endosperm starch (g)',
'Uptake_Nitrates': u'Nitrates uptake (µmol h$^{-1}$)',
'sucrose': u'Sucrose (µmol)', 'amino_acids': u'Amino Acids (µmol)', 'Unloading_Sucrose': u'Unloaded sucrose (µmol C g$^{-1}$ mstruct h$^{-1}$)',
'Unloading_Amino_Acids': u'Unloaded Amino Acids (µmol N AA g$^{-1}$ mstruct h$^{-1}$)',
'S_Amino_Acids': u'Rate of amino acids synthesis (µmol N g$^{-1}$ mstruct h$^{-1}$)', 'S_Proteins': u'Rate of protein synthesis (µmol N h$^{-1}$)',
'Export_Nitrates': u'Total export of nitrates (µmol N h$^{-1}$)', 'Export_Amino_Acids': u'Total export of Amino acids (µmol N h$^{-1}$)',
'R_Nnit_upt': u'Respiration nitrates uptake (µmol C h$^{-1}$)', 'R_Nnit_red': u'Respiration nitrate reduction (µmol C h$^{-1}$)',
'R_residual': u'Respiration residual (µmol C h$^{-1}$)',
'R_grain_growth_struct': u'Respiration grain structural growth (µmol C h$^{-1}$)', 'R_grain_growth_starch': u'Respiration grain starch growth (µmol C h$^{-1}$)',
'mstruct': u'Structural mass (g)', 'C_exudation': u'Carbon lost by root exudation (µmol C g$^{-1}$ mstruct h$^{-1}$',
'N_exudation': u'Nitrogen lost by root exudation (µmol N g$^{-1}$ mstruct h$^{-1}$', 'Conc_cytokinins': u'[cytokinins] (UA g$^{-1}$ mstruct)',
'S_cytokinins': u'Rate of cytokinins synthesis (UA g$^{-1}$ mstruct)', 'Export_cytokinins': 'Export of cytokinins from roots (UA h$^{-1}$)',
'HATS_LATS': u'Potential uptake (µmol h$^{-1}$)', 'regul_transpiration': u'Regulating transpiration function',
'senesced_mstruct': u'Cumulated senesced mstruct (g)', 'synthetized_mstruct': u'Cumulated synthetized mstruct (g)', }
for org in (['roots'], ['grains'], ['phloem'], ['endosperm']):
for variable_name, variable_label in graph_variables_organs.items():
graph_name = variable_name + '_' + '_'.join(org) + '.PNG'
integration_tools.plot_outputs(organs_df,
x_name=x_name,
y_name=variable_name,
x_label=x_label,
y_label=variable_label,
colors=['blue'],
filters={'organ': org},
plot_filepath=os.path.join(graphs_dirpath, graph_name),
meteo_data=meteo_data,
explicit_label=False)
# 3) Soil
if soils_df is not None:
_, (ax1) = plt.subplots(1)
Conc_Nitrates_soil = soils_df['Conc_Nitrates_Soil'] * 14E-6
ax1.plot(soils_df['t'], Conc_Nitrates_soil)
ax1.set_ylabel(u'[Nitrates] (g m$^{-3}$)')
ax1.set_xlabel('Time (hour)')
ax1.set_title = 'Conc Nitrates Soil'
ax1.set_ylim(bottom=0)
plt.savefig(os.path.join(graphs_dirpath, 'Conc_Nitrates_Soil.PNG'), format='PNG', bbox_inches='tight')
plt.close()
# 4) Hidden zones
if hiddenzones_df is not None:
graph_variables_hiddenzones = {'Conc_Sucrose': u'[Sucrose] (µmol g$^{-1}$ mstruct)', 'Conc_Amino_Acids': u'[Amino Acids] (µmol g$^{-1}$ mstruct)',
'Conc_Proteins': u'[Proteins] (g g$^{-1}$ mstruct)', 'Conc_Fructan': u'[Fructan] (µmol g$^{-1}$ mstruct)', 'Cont_Fructan_DM': u'Fructan content (% DM)',
'Cont_Proteins_DM': u'Protein content (% DM)', 'Cont_WSC_DM': u'WSC content (% DM)', 'Unloading_Sucrose': u'Rate of Sucrose unloading (µmol C h${-1}$)',
'Unloading_Amino_Acids': u'Rate of Amino_acids unloading (µmol N h${-1}$)', 'mstruct': u'Structural mass (g)', 'Nstruct': u'Structural N mass (g)',
'leaf_L': u'Leaf length in hz (m)', 'delta_leaf_L': u'delta of leaf length (m)', 'internode_L': u'Internode length in hz (m)',
'leaf_pseudostem_length': u'leaf pseudostem length (m)'}
for variable_name, variable_label in graph_variables_hiddenzones.items():
graph_name = variable_name + '_hz' + '.PNG'
integration_tools.plot_outputs(hiddenzones_df,
x_name=x_name,
y_name=variable_name,
x_label=x_label,
y_label=variable_label,
colors=[colors[i - 1] for i in hiddenzones_df.metamer.unique().tolist()],
filters={'plant': 1, 'axis': 'MS'},
plot_filepath=os.path.join(graphs_dirpath, graph_name),
meteo_data=meteo_data,
explicit_label=False)
# 4) Axes
graph_variables_axes = {'mstruct': 'Axis mstruct (g)',
'C_N_ratio': u'C/N mass ratio', 'C_N_ratio_shoot': u'C/N mass ratio of the shoot',
'N_content': u'N content in the axis (% DM)', 'N_content_shoot': u'N content in the shoot (% DM)',
'N_content_total_DM_shoot': u'N content in the shoot accounting for partly senesced leaves (% DM)',
'N_content_roots': u'N content in the roots (% DM)',
'N_content_mstruct': u'N content in the axis (% mstruct)', 'N_content_mstruct_shoot': u'N content in the shoot (% mstruct)',
'N_content_mstruct_roots': u'N content in the roots (% mstruct)',
'sum_N_g': u'N mass (g)', 'sum_N_g_shoot': u'N mass in the shoot (g)',
'shoot_roots_ratio': u'Shoot/Roots dry mass ratio',
'shoot_roots_mstruct_ratio': u'Shoot/Roots mstruct ratio',
'sum_dry_mass': u'Total dry mass (g)', 'sum_dry_mass_shoot': u'Dry mass of the shoot (g)',
'sum_dry_mass_roots': u'Dry mass of the roots (g)', 'dry_mass_phloem': u'Dry mass of the phloem (g)',
'NNI': u'Nitrogen Nutrition Index',
'NS_shoot': u'Ratio of Non Structural Mass in the shoot', 'NS_roots': u'Ratio of Non Structural Mass in the roots',
'NS': u'Ratio of Non Structural Mass for the plant',
'mstruct_shoot': u'Structural Mass of the shoot (g)',
'Cont_WSC_DM': u'WSC content (% DM)'}
for variable_name, variable_label in graph_variables_axes.items():
graph_name = variable_name + '_axis' + '.PNG'
integration_tools.plot_outputs(axes_df,
x_name=x_name,
y_name=variable_name,
x_label=x_label,
y_label=variable_label,
colors=['blue'],
filters={'plant': 1, 'axis': 'MS'},
plot_filepath=os.path.join(graphs_dirpath, graph_name),
meteo_data=meteo_data,
explicit_label=False)