def test_hydraulic_prop_attributes_the_right_properties_to_the_different_organs( ): simple_shoot = potted_syrah() simple_shoot.node(simple_shoot.root).vid_base = architecture.mtg_base( simple_shoot, vtx_label='inT') vid_base = simple_shoot.node(simple_shoot.root).vid_base for vtx_id in traversal.post_order2(simple_shoot, vid_base): n = simple_shoot.node(vtx_id) if n.label.startswith('LI'): n.E = 0. n.An = 0. hydraulic.hydraulic_prop(simple_shoot, mass_conv=18.01528, length_conv=1.e-2, a=2.6, b=2.0, min_kmax=0.) for vtx_id in traversal.post_order2(simple_shoot, vid_base): n = simple_shoot.node(vtx_id) assert hasattr(n, 'Flux') assert hasattr(n, 'FluxC') if n.label.startswith(('in', 'cx', 'Pet')): assert hasattr(n, 'Kmax')
def hydraulic_prop(g, mass_conv=18.01528, length_conv=1.e-2, a=2.6, b=2.0, min_kmax=0.): """Computes water flux `Flux` and maximum hydraulic conductivity `Kmax` of each hydraulic segment. Both properties are then attached to the corresponding mtg nodes. Args: g (openalea.mtg.MTG): a multiscale tree graph object mass_conv (float): [gr mol-1] molar mass of H2O length_conv (float): conversion coefficient from the length unit of the mtg to that of [1 m] a (float): [kg s-1 MPa-1] slope of the Kh(D) relationship, see :func:`conductivity_max` for details b (float): [-] exponent of the Kh(D) relationship, see :func:`conductivity_max` for details min_kmax (float): [kg s-1 m MPa-1] minimum value for the maximum conductivity, see :func:`conductivity_max` for details Returns: (openalea.mtg.MTG): the multiscale tree graph object Notes: The units of **Flux** and **Kmax** properties are related: - if `Flux` is given as water flux [kg s-1], then `Kmax` is in [kg m s-1 Pa-1] (or [kg m s-1 MPa-1]) - else if `Flux` is given as water flux density [kg m-2 s-1], then `Kmax` is in [kg m-1 s-1 Pa-1] (or [kg m-1 s-1 MPa-1]) Transpiration flux density per leaf surface area `E` (propery of the :arg:`mtg`) must be in [mol m-2 s-1], otherwise, the :arg:`mass_conv` value must be re-adapted The resulting water potential, calculated in :func:`transient_xylem_water_potential` is then given in [MPa] """ vid_base = g.node(g.root).vid_base for vtx_id in traversal.post_order2(g, vid_base): n = g.node(vtx_id) if n.label.startswith('LI'): try: leaf_area = n.leaf_area * 1. except (AttributeError, TypeError): leaf_area = surf(n.geometry) * length_conv ** 2 # [m2] # Note: The surface of the leaf mesh is overestimated compared to allometry results # leaf_area = (0.0175*(n.Length*10.)**1.9057)*LengthConv**2 #[m2] n.leaf_area = leaf_area n.Flux = (n.E * mass_conv * 1.e-3) * leaf_area # n.FluxC = ((n.An)*44.0095*1.e-9)*leaf_area # [kgCO2 s-1] n.FluxC = n.An * leaf_area # [umol s-1] elif n.label.startswith(('in', 'cx', 'Pet')): n.Flux = sum([vtx.Flux for vtx in n.children()]) diam = 0.5 * (n.TopDiameter + n.BotDiameter) * length_conv n.Kmax = conductivity_max(diam, a, b, min_kmax) n.FluxC = sum([vtx.FluxC for vtx in n.children()]) elif n.label.startswith('rhyzo'): n.Flux = sum([vtx.Flux for vtx in n.children()]) n.FluxC = sum([vtx.FluxC for vtx in n.children()]) n.Kmax = None return g
def hydraulic_prop(mtg, vtx_label='inT', MassConv=18.01528, LengthConv=1.e-2, a=2.6, b=2.0, min_kmax=0.): """ Returns water flux, `F` [kg s-1] and maximum stem conductivity [kg m s-1 Pa-1] of each internode. :Attention: 1. The units of **F** and **K** are related: - if `F` is given as water flux [kg s-1], then `K` must be given as [kg m s-1 Pa-1] (or [kg m s-1 MPa-1]) - else if `F` is given as water flux density [kg m-2 s-1], then `K` must be given as [kg m-1 s-1 Pa-1] (or [kg m-1 s-1 MPa-1]). 2. Transpiration flux density per leaf surface area `E` must be in [mol m-2 s-1], otherwise, the `MassConv` value must be readapted. The resulting water portential, calculated in :func:`transient_xylem_water_potential` is then given in [MPa]. :Parameters: - **mtg**: an MTG object - **vtx_label**: string, the label prefix of the basal vertex at highest scale - **MassConv**: molar mass of H2O [gr mol-1] - **LengthConv**: conversion coefficient from the length unit of the mtg to that of 1 m - **a** and **b**: respectively the slope and power parameters for the Kh(D) relationship - **min_kmax**: float, minimum value for the maximum conductivity [kg s-1 m MPa-1] """ # Getting the basal vertex of the highest scale vertices vid_base = mtg.node(mtg.root).vid_base for vtx_id in traversal.post_order2(mtg,vid_base): n = mtg.node(vtx_id) if n.label.startswith('LI'): try: leaf_area = n.leaf_area*1. except: leaf_area = surf(n.geometry)*LengthConv**2 #[m2] # leaf_area = (0.0175*(n.Length*10.)**1.9057)*LengthConv**2 #[m2] n.leaf_area = leaf_area # Note: The surface of the leaf mesh is overestimated compared to allometry results n.Flux = ((n.E)*MassConv*1.e-3)*leaf_area # n.FluxC = ((n.An)*44.0095*1.e-9)*leaf_area # [kgCO2 s-1] n.FluxC = (n.An)*leaf_area # [umol s-1] elif n.label.startswith(('in','cx','Pet')): n.Flux = sum([vtx.Flux for vtx in n.children()]) Diam = 0.5*(n.TopDiameter + n.BotDiameter)*LengthConv n.Kmax = k_max(Diam,a,b,min_kmax) n.FluxC = sum([vtx.FluxC for vtx in n.children()]) elif n.label.startswith('rhyzo'): n.Flux = sum([vtx.Flux for vtx in n.children()]) n.FluxC = sum([vtx.FluxC for vtx in n.children()]) n.Kmax = None return mtg
def pipemodel(mtg, rootradius, leafradius, root=None): from math import log from openalea.mtg.traversal import post_order2 if root is None: roots = mtg.roots(scale=mtg.max_scale()) assert len(roots) == 1 root = roots[0] vertices = list(post_order2(mtg, root)) leaves = [vid for vid in vertices if len(mtg.children(vid)) == 0] # pipeexponent = log(len(leaves)) / (log(rootradius) - log(leafradius)) # print pipeexponent # invpipeexponent = 1./ pipeexponent radiusprop = dict() for vid in leaves: radiusprop[vid] = leafradius nbelems = dict() for vid in leaves: nbelems[vid] = 1 for vid in vertices: if not vid in nbelems: nbelems[vid] = sum([nbelems[child] for child in mtg.children(vid)]) + 1 print(root, nbelems[root]) # pipeexponent = log(nbelems[root]) / (log(rootradius) - log(leafradius)) pipeexponent = (log(rootradius) - log(leafradius)) / log(nbelems[root]) print(pipeexponent) invpipeexponent = 1. / pipeexponent for vid in vertices: if not vid in radiusprop: radiusprop[vid] = leafradius * (nbelems[vid]**pipeexponent) # for vid in post_order2(mtg, root): # if not vid in radiusprop: # rad = pow(sum([pow(radiusprop[child], pipeexponent) for child in mtg.children(vid)]), invpipeexponent) # radiusprop[vid] = rad return radiusprop
def pipemodel(mtg, rootradius, leafradius, root = None): from math import log from openalea.mtg.traversal import post_order2 if root is None: roots = mtg.roots(scale=mtg.max_scale()) assert len(roots) == 1 root = roots[0] vertices = list(post_order2(mtg, root)) leaves = [vid for vid in vertices if len(mtg.children(vid)) == 0] #pipeexponent = log(len(leaves)) / (log(rootradius) - log(leafradius)) #print pipeexponent #invpipeexponent = 1./ pipeexponent radiusprop = dict() for vid in leaves: radiusprop[vid] = leafradius nbelems = dict() for vid in leaves: nbelems[vid] = 1 for vid in vertices: if not vid in nbelems: nbelems[vid] = sum([nbelems[child] for child in mtg.children(vid)]) + 1 print root, nbelems[root] #pipeexponent = log(nbelems[root]) / (log(rootradius) - log(leafradius)) pipeexponent = (log(rootradius) - log(leafradius))/log(nbelems[root]) print pipeexponent invpipeexponent = 1./ pipeexponent for vid in vertices: if not vid in radiusprop: radiusprop[vid] = leafradius*(nbelems[vid]**pipeexponent) #for vid in post_order2(mtg, root): # if not vid in radiusprop: # rad = pow(sum([pow(radiusprop[child], pipeexponent) for child in mtg.children(vid)]), invpipeexponent) # radiusprop[vid] = rad return radiusprop