Source code for openalea.hydroroot.radius

# License

"""

functions to compute the vertex radii in different way.
functions to set the vertices length, to compute the total surface and volume of the MTG

"""
from openalea.mtg import *
from openalea.mtg import algo
from math import pi




[docs] def radius(g): """ calculate the radius from the property diameter :param g: :return: """ radius = {} diameters= g.property('diam') for i,j in diameters.items(): radius[i] = j/2 g.properties()['radius'] = radius
[docs] def cont_radius(g, r_base, r_tip): """Compute the radius of each segment of a root system. Set radius for elements of a mtg with an increase rate computed from given base and tip radius in a continuous way. :param g: (MTG) :param r_base: (float) - radius of the base :param r_tip: (float) - radius of the tip :return: - g """ r_base, r_tip = float(r_base), float(r_tip) assert (r_base>r_tip),"Base radius should be greater than tip radius" base = next(g.component_roots_iter(g.root)) base = g.node(base) base.radius = r_base _tips = dict((vid, g.order(vid)) for vid in g.vertices_iter(scale = g.max_scale()) if g.is_leaf(vid)) tips = {} for tip,order in _tips.items(): tips.setdefault(order, []).append(tip) max_order = max(tips) for order in range(max_order+1): for tip in tips[order]: l = [g.node(vid) for vid in algo.axis(g,tip)] n = len(l) if n==1: # only one segment in the lateral root - very young lateral l[0].radius = r_tip else : # more than one segment in the lateral root parent = l[0].parent() r0 = parent.radius if parent else r_base dr = (r0-r_tip)/(n-1) for node in l: if node.radius==r0: # keep the value of the base/junction radius for the first segment of the lateral continue node.radius = node.parent().radius - dr # decrease the radius from base to tip return g
[docs] def discont_radius(g, r_base, r_tip): """Compute the radius of each segment of a root system. Set radius for elements of a mtg with an increase rate computed from the length of the longest axis and its base and tip radius. Radius can be discontinuous e.g. for a young/small lateral on an old root, the young root radius is very small initially compared to the old one. :param g: (MTG) :param r_base: (float) - radius of the base :param r_tip: (float) - radius of the tip :return: - g """ r_base, r_tip = float(r_base), float(r_tip) assert (r_base>r_tip),"Base radius should be greater than tip radius" base = next(g.component_roots_iter(g.root)) base = g.node(base) base.radius = r_base _tips = dict((vid, g.order(vid)) for vid in g.vertices_iter(scale = g.max_scale()) if not algo.sons(g,vid,EdgeType='<')) tips = {} for tip,order in _tips.items(): tips.setdefault(order, []).append(tip) max_order = max(tips) max_len = 0 for order in range(max_order+1): #find the longest axis length among all axis for tip in tips[order]: max_len = max(max_len, len(list(algo.axis(g,tip)))) assert (max_len>1), "MTG too short for analysis" growth_rate = (r_base-r_tip)/(max_len-1) #define growth rate according to radius extremities of the longest axis # radius are computed from tips to bases according to growth rate extrapolated from absolute longest axis of the MTG for order in range(max_order+1): for tip in tips[order]: node = g.node(tip) node.radius = r_tip while node and node.parent() and node.edge_type() != '+': node.parent().radius = node.radius + growth_rate node = node.parent() return g
[docs] def ordered_radius(g, ref_radius=1e-4, order_decrease_factor=0.5): """Compute the radius of each segment of a root system. Set radius for elements of a mtg with fixed decrease between each order. ref_radius: reference radius of the primary root (in m) order_decrease_factor: radius decrease factor applied when increasing order :param g: (MTG) :param ref_radius: the radius of the primary root (Default value = 1e-4) :param order_decrease_factor: then the decrease factor per order (Default value = 0.5) :return: - g if primary root as a radius :math:`r`, the first order lateral has a radius of :math:`r \\beta`, the second order lateral :math:`r \\beta^2`, with :math:`\\beta` the order decrease factor """ #print 'entering MTG radius setting' max_scale = g.max_scale() ref_r, d_factor = float(ref_radius), float(order_decrease_factor) base = next(g.component_roots_iter(g.root)) orders = algo.orders(g,scale=max_scale) max_order = max(orders) radius_order = {} for order in range(max_order+1): radius_order[order] = ref_r*(d_factor**order) g_radius = g.properties()['radius'] = {} for vid, order in orders.items(): g_radius[vid] = radius_order[order] #print 'exiting MTG radius setting' return g
[docs] def compute_length(g, length = 1.e-4): """Set the length of each vertex of the MTG :param g: (MTG) :param length: (float) - vertices length (Default value = 1.e-4) :return: -g """ #print 'entering MTG length setting' length = float(length) for vid in g.vertices_iter(scale=g.max_scale()): g.node(vid).length = length #print 'exiting MTG length setting' return g
[docs] def compute_surface(g): """Compute the total surface of the MTG in hydroroot length unit is the m so the surface is in square meters :param g: (MTG) :return: - g - surface in square length unit of g.property('radius') and g.property('length') """ #print 'entering surface computation' surf = 0 max_scale = g.max_scale() radius = g.property('radius') length = g.property('length') for vid in g.vertices_iter(scale = max_scale): if vid in radius and vid in length: surf += 2 * pi * radius[vid] * length[vid] #print 'surface (sq. meters): ',surf #print 'leaving surface computation' return g, surf
[docs] def compute_volume(g): """Compute the total volume of the MTG in hydroroot length unit is the m so the volume is in cubic meters :param g: (MTG) :return: - g - volume in cubic length unit of g.property('radius') and g.property('length') """ #print 'entering volume computation' volume = 0. max_scale = g.max_scale() radius = g.property('radius') length = g.property('length') for vid in g.vertices_iter(scale = max_scale): if vid in radius and vid in length: volume += pi * (radius[vid]**2) * length[vid] #print 'volume (cube meters): ',volume #print 'leaving volume computation' return g, volume
[docs] def compute_relative_position(g): """Compute the position of each segment relative to the axis bearing it. Add the properties "position" and "relative_position" to the MTG. g.properties()['position'] is in meter the distance from the tip in unit of g.property('length'), in hydroroot must be m g.properties()['relative_position'] is the distance from the tip relative to the axis bearing it (base is 1, tip is 0) :param g: (MTG) return: - g """ #print 'entering MTG node positionning computation' scale = g.max_scale() position = {} position_measure = {} axis_length = {} length = g.property('length') root_id = next(g.component_roots_at_scale_iter(g.root, scale=scale)) for vid in traversal.post_order2(g, root_id): #sons = algo.sons(g,vid,EdgeType='<') sons = [cid for cid in g.children(vid) if g.edge_type(cid) == '<'] position[vid] = position[sons[0]]+1 if sons else 0 position_measure[vid] = position[vid] * length[vid] if g.edge_type(vid) == '+' or g.parent(vid) is None: axis_length[vid] = position[vid] relative_position = {} for axis_id, _length in axis_length.items(): _length = float(max(1, _length)) for v in algo.local_axis(g,axis_id): relative_position[v] = position[v] / _length g.properties()['position'] = position_measure g.properties()['relative_position'] = relative_position #print 'exiting MTG node positionning computation' return g