def spanning_mtg(graph): """ Extract an MTG from the GroIMP graph. Parameters ---------- - graph is a RootedGraph created from the GroIMP Graph TODO: - compress vertices to only usefull vertices (geometry) - compress edges to spanning mtg """ # Manage a mapping between the graph and the mtg graph2mtg = {} g = graph edge_type = g.edge_property('edge_type') mtg = MTG() mtg.root = graph.root # Check if the graph contains decomposition (/) edges if not is_multiscale(graph): pass # Compute the scale from each vertex. # Select one decomposition path if there are several in the GroIMP graph _scales = scales(g) # Set the internal scale information to the MTG mtg._scale = _scales # Set the edge_type for each vertex (<, +) _edge_type = _build_edge_type(g, mtg) # Compute the tree information at all scales _children_and_parent(g, mtg) # Compute the complex (upscale) and components (downscale) for each vertex _complex_and_components(g, mtg) print "scales :", mtg._scale # Extract all the vertex properties. _vertex_properties(g, mtg) # Compute missing links to have constant time access (O(1)) to neighbourhood fat_mtg(mtg) print "scales :", mtg._scale return mtg
def build_mtg(self): """ Build an MTG structure from data. The MTG is composed of 3 scales: Plant, Crown, Phytomer """ self._axis_vid = [] self.g = MTG() g = self.g # build 2 elements: P plante and C crown #self._vid = plant_id = g.add_component(g.root, label='Plant') # add crown #self._vid = g.add_component(self._vid, label='Crown') self._order = 0 self._scale = 3 self._vid = None #self._axis_vid.append(self._vid) nb_lines = len(self.content) - self.prop_no for i in range(nb_lines): #print (self._vid) self.read_line() self.g = fat_mtg(g)
def parse(self, fn): self.trash = [] self._g = MTG() # Current proxy node for managing properties self._node = None doc = xml.parse(fn) root = doc.getroot() self.dispatch(root) self._g = fat_mtg(self._g) return self._g
def parse(self, filename, debug=False): self.debug = debug self.trash = [] self._g = MTG() # Current proxy node for managing properties self._node = None doc = xml.parse(filename) root = doc.getroot() # recursive call of the functions to add neww plants/root axis to the MTG self.dispatch(root) g = fat_mtg(self._g) # Add metadata as property of the graph #g.graph_property() return g
def mtg_factory(parameters, metamer_factory=adel_metamer, leaf_sectors=1, leaves=None, stand=None, axis_dynamics=None, add_elongation=False, topology=['plant', 'axe_id', 'numphy'], split=False, aborting_tiller_reduction=1.0, leaf_db=None): """ Construct a MTG from a dictionary of parameters. The dictionary contains the parameters of all metamers in the stand (topology + properties). metamer_factory is a function that build metamer properties and metamer elements from parameters dict. leaf_sectors is an integer giving the number of LeafElements per Leaf blade leaves is a {species:adel.geometric_elements.Leaves} dict stand is a list of tuple (xy_position_tuple, azimuth) of plant positions axis_dynamics is a 3 levels dict describing axis dynamic. 1st key level is plant number, 2nd key level is axis number, and third ky level are labels of values (n, tip, ssi, disp) topology is the list of key names used in parameters dict for plant number, axe number and metamer number aborting_tiller_reduction is a scaling factor applied to reduce all dimensions of organs of tillers that will abort Axe number 0 is compulsory """ if leaf_db is not None: raise AdelDeprecationError( 'leaf_db argument is deprecated, use leaves argument instead') if leaves is None: dynamic_leaf_db = {0: False} leaves = {0: None} else: dynamic_leaf_db = {k: leaves[k].dynamic for k in leaves} g = MTG() # buffers # for detection of newplant/newaxe prev_plant = 0 prev_axe = -1 # current vid vid_plant = -1 vid_axe = -1 vid_metamer = -1 vid_node = -1 vid_elt = -1 # vid of top of stem nodes and elements vid_topstem_node = -1 vid_topstem_element = -1 # vid of plant main stem (axe0) vid_main_stem = -1 # buffer for the vid of main stem anchor points for the first metamer, node and element of tillers metamers = [] nodes = [] elts = [] dp = parameters nrow = len(dp['plant']) for i in range(nrow): plant, num_metamer = [ int(convert(dp.get(x)[i], undef=None)) for x in [topology[e] for e in [0, 2]] ] axe = dp.get(topology[1])[i] mspos = int(convert(dp.get('ms_insertion')[i], undef=None)) args = properties_from_dict(dp, i, exclude=topology) # Add plant if new if plant != prev_plant: label = 'plant' + str(plant) position = (0, 0, 0) azimuth = 0 species = 0 if 'species' in args: species = args['species'] if stand and len(stand) >= plant: position, azimuth = stand[plant - 1] vid_plant = g.add_component(g.root, label=label, edge_type='/', position=position, azimuth=azimuth, refplant_id=args.get('refplant_id'), species=species) # reset buffers prev_axe = -1 vid_axe = -1 vid_metamer = -1 vid_node = -1 vid_elt = -1 vid_topstem_node = -1 vid_topstem_element = -1 vid_main_stem = -1 metamers = [] nodes = [] elts = [] # Add axis if axe != prev_axe: label = ''.join(axe.split('.')) timetable = None if axis_dynamics: timetable = axis_dynamics[str(plant)][str(axe)] if axe == 'MS': vid_axe = g.add_component(vid_plant, edge_type='/', label=label, timetable=timetable, HS_final=args.get('HS_final'), nff=args.get('nff'), hasEar=args.get('hasEar'), azimuth=args.get('az_insertion')) vid_main_stem = vid_axe else: vid_axe = g.add_child(vid_main_stem, edge_type='+', label=label, timetable=timetable, HS_final=args.get('HS_final'), nff=args.get('nff'), hasEar=args.get('hasEar'), azimuth=args.get('az_insertion')) # Add metamer assert num_metamer > 0 # args are added to metamers only if metamer_factory is none, otherwise compute metamer components components = [] if metamer_factory: xysr_key = None if leaves[ species] is not None and 'LcType' in args and 'LcIndex' in args: lctype = int(args['LcType']) lcindex = int(args['LcIndex']) if lctype != -999 and lcindex != -999: age = None if dynamic_leaf_db[species]: age = float( args['rph'] ) - 0.3 # age_db = HS - rank + 1 = ph - 1.3 - rank +1 = rph - .3 if age != 'NA': age = max(0, int(float(age))) xysr_key = leaves[species].get_leaf_key( lctype, lcindex, age) elongation = None if add_elongation: startleaf = -.4 endleaf = 1.6 stemleaf = 1.2 startE = endleaf endE = startE + (endleaf - startleaf) / stemleaf endBlade = endleaf if args['Gl'] > 0: endBlade = args['Ll'] / args['Gl'] * (endleaf - startleaf) elongation = { 'startleaf': startleaf, 'endBlade': endBlade, 'endleaf': endleaf, 'endE': endE } if not 'ntop' in args: args.update({'ntop': None}) if not 'Gd' in args: args.update({'Gd': 0.19}) args.update({'split': split}) if args.get('HS_final') < args.get('nff'): for what in ('Ll', 'Lv', 'Lr', 'Lsen', 'L_shape', 'Lw_shape', 'Gl', 'Gv', 'Gsen', 'Gd', 'El', 'Ev', 'Esen', 'Ed'): args.update( {what: args.get(what) * aborting_tiller_reduction}) components = metamer_factory(Lsect=leaf_sectors, shape_key=xysr_key, elongation=elongation, leaves=leaves[species], **args) args = {'L_shape': args.get('L_shape')} # label = 'metamer' + str(num_metamer) new_metamer = g.add_component(vid_axe, edge_type='/', label=label, **args) if axe == 'MS' and num_metamer == 1: vid_metamer = new_metamer elif num_metamer == 1: # add the edge with the bearing metamer on main stem vid_metamer = metamers[mspos - 1] vid_metamer = g.add_child(vid_metamer, child=new_metamer, edge_type='+') else: vid_metamer = g.add_child(vid_metamer, child=new_metamer, edge_type='<') # add metamer components, if any if len(components) > 0: # deals with first component (internode) and first element node, elements = get_component(components, 0) element = elements[0] new_node = g.add_component(vid_metamer, edge_type='/', **node) new_elt = g.add_component(new_node, edge_type='/', **element) if axe == 'MS' and num_metamer == 1: # root of main stem vid_node = new_node vid_elt = new_elt elif num_metamer == 1: # root of tiller vid_node = nodes[mspos - 1] vid_node = g.add_child(vid_node, child=new_node, edge_type='+') vid_elt = elts[mspos - 1] vid_elt = g.add_child(vid_elt, child=new_elt, edge_type='+') else: vid_node = g.add_child(vid_topstem_node, child=new_node, edge_type='<') vid_elt = g.add_child(vid_topstem_element, child=new_elt, edge_type='<') # add other elements of first component (the internode) for i in range(1, len(elements)): element = elements[i] vid_elt = g.add_child(vid_elt, edge_type='<', **element) vid_topstem_node = vid_node vid_topstem_element = vid_elt # last element of internode # add other components for i in range(1, len(components)): node, elements = get_component(components, i) if node['label'] == 'sheath': edge_type = '+' else: edge_type = '<' vid_node = g.add_child(vid_node, edge_type=edge_type, **node) element = elements[0] new_elt = g.add_component(vid_node, edge_type='/', **element) vid_elt = g.add_child(vid_elt, child=new_elt, edge_type=edge_type) for j in range(1, len(elements)): element = elements[j] vid_elt = g.add_child(vid_elt, edge_type='<', **element) # update buffers if axe == 'MS': metamers.append(vid_metamer) if len(components) > 0: nodes.append(vid_topstem_node) elts.append(vid_topstem_element) prev_plant = plant prev_axe = axe return fat_mtg(g)
def cereals(json=None, classic=False, unit='cm', seed=None, plant=None): """ Generate a 'geometric-based' MTG representation of cereals Args: json: a dict of parameters with: leaf_order : a list of int defining leaf rank leaf_polylines : [[(x, y, z, r), ..., ], ...] list of list tuple sampling leaf midribs. r is leaf width at position x, y, z along leaf midrib stem : [(x, y, z, r), ..., ] list of tuples sampling stem from its base to its end. r is the stem diameter at x,y,z position along the stem classic: (bool) should stem cylinders be classical pgl cylinders ? unit: (string) desired length unit for the output mtg seed: (int) a seed for the random number generator """ if plant is None: blade_dimensions, stem_dimensions, leaves = as_plant(json) dim = blade_dimensions.merge(stem_dimensions) dim = dim.sort_values('ntop', ascending=False) relative_azimuth = dim.leaf_azimuth.copy() relative_azimuth[1:] = numpy.diff(relative_azimuth) else: dim = plant leaves = { row['ntop']: row['leaf_shape'] for index, row in dim.iterrows() } g = MTG() vid_node = g.add_component(g.root, label='plant', edge_type='/') for i, row in dim.iterrows(): internode = { 'label': 'StemElement', 'length': row['L_internode'], 'is_green': True, 'diameter_base': row['W_internode'], 'diameter_top': row['W_internode'], 'azimuth': row['leaf_azimuth'] } vid_node = g.add_child(vid_node, edge_type='<', **internode) blade = { 'label': 'LeafElement', 'shape': leaves[row['ntop']], 'shape_mature_length': row['L_blade'], 'length': row['L_blade'], 'visible_length': row['L_blade'], 'is_green': True, 'srb': 0, 'srt': 1, 'lrolled': 0, 'd_rolled': 0, 'shape_max_width': row['W_blade'], 'stem_diameter': row['W_internode'] } vid_blade = g.add_child(vid_node, edge_type='+', **blade) g = fat_mtg(g) # Compute geometry g = mtg_interpreter(g, classic=classic) return g
def read_lsystem_string( string, symbol_at_scale, functional_symbol={}, mtg=None ): """Read a string generated by a lsystem. :Parameters: - `string`: The lsystem string representing the axial tree. - `symbol_at_scale`: A dict containing the scale for each symbol name. :Optional parameters: - `functional_symbol`: A dict containing a function for specific symbols. The args of the function have to be coherent with those in the string. The return type of the functions have to be a dictionary of properties: dict(name, value) :Return: MTG object """ import openalea.plantgl.all as pgl s = string def transform(turtle, mesh): x = turtle.getUp() z = turtle.getHeading() bo = pgl.BaseOrientation(x, z^x) matrix = pgl.Transform4(bo.getMatrix()) matrix.translate(turtle.getPosition()) mesh = mesh.transform(matrix) return mesh # 1. Create the mtg structure. if mtg is None: mtg = MTG() # 2. add some properties to the MTG mtg.add_property('index') mtg.add_property('can_label') mtg.add_property('geometry') mtg.add_property('tissue_type') vid = mtg.root # vid of the support tree, i.e. at the finest scale current_vertex = mtg.root branching_stack = [] pending_edge = '' # edge type for the next edge to be created scale = 0 lsys_symbols = ['[', ']', '/', '+', '^', 'f'] modules = symbol_at_scale.keys() symbols = lsys_symbols + modules index = dict(zip(symbol_at_scale.keys(), [0]*len(symbol_at_scale))) is_ramif = False # 2. Create a PlantGL Turtle... turtle = pgl.Turtle() max_scale = max(symbol_at_scale.values()) for edge_type in symbols: if edge_type != 'f': s = s.replace(edge_type, '\n%s'%edge_type) else: s = s.replace('f(', '\nf(') l = s.split() try: plant_name = [s for s in symbol_at_scale.keys() if 'plant' in s.lower()][0] except: ValueError("""Incorrect plant name (should be plant)""") for node in l: # Check if node is a module tag = node[0] if tag == '[': branching_stack.append(vid) turtle.push() is_ramif = True elif tag == ']': vid = branching_stack.pop() current_vertex = vid scale = mtg.scale(vid) turtle.pop() is_ramif = False elif tag == '/': args = get_args(node[1:]) if args: angle = get_float(args[1:-1]) turtle.rollR(angle) else: turtle.rollR() elif tag == '+': args = get_args(node[1:]) if args: angle = get_float(args[1:-1]) turtle.left(angle) else: turtle.left() elif tag == '^': args = get_args(node[1:]) if args: angle = get_float(args[1:-1]) turtle.up(angle) else: turtle.up() elif tag == 'f' and node[1] == '(': args = get_args(node[1:]) if args: length = get_float(args[1:-1]) if length > 0: turtle.f(length) else: turtle.f() else: # add new modules to the mtg (i.e. add nodes) name = get_name(node) if name not in modules: print 'Unknow element %s'% name continue module_scale = symbol_at_scale[name] if is_ramif: edge_type = '+' else: edge_type = '<' log(node, module_scale, edge_type ) if module_scale == scale: if mtg.scale(vid) == scale: vid = mtg.add_child(vid, edge_type=edge_type, label=name) current_vertex = vid pending_edge = '' log('','Cas 1.1', scale, 'mtg.scale(vid)', mtg.scale(vid), 'generated vertex', vid) assert mtg.scale(vid) == module_scale else: # add the edge to the current vertex current_vertex = mtg.add_child(current_vertex, edge_type=edge_type, label=name) log('', 'Cas 1.2', scale, 'mtg.scale(vid)', mtg.scale(vid), 'generated vertex', current_vertex) assert mtg.scale(current_vertex) == module_scale is_ramif = False elif module_scale > scale: log('', 'Cas 2', scale, 'mtg.scale(vid)', mtg.scale(vid)) old_current_vertex = current_vertex while module_scale > scale: if mtg.scale(vid) == scale: assert vid == current_vertex vid = mtg.add_component(vid) current_vertex = vid log('', '', 'Cas 2.1', scale, 'generate new component', current_vertex) scale += 1 if module_scale == scale: assert mtg.scale(current_vertex) == module_scale mtg.property('label')[current_vertex] = name break else: scale += 1 current_vertex = mtg.add_component(current_vertex) else: log(node, 'add_child(%d, child=%d)'%(old_current_vertex, current_vertex)) mtg.property('label')[current_vertex] = name if mtg.scale(vid) == scale: vid = mtg.add_child(vid, child=current_vertex, edge_type=edge_type) is_ramif = False else: assert module_scale < scale while module_scale < scale: scale -= 1 current_vertex = mtg.complex(current_vertex) else: current_vertex = mtg.add_child(current_vertex, edge_type=edge_type, label=name) assert mtg.scale(current_vertex) == module_scale # MANAGE the properties, the geometry and the indices!!! index[name] += 1 if name == plant_name: for k in index.keys(): if k != name: index[k] = 0 mtg.property('index')[current_vertex] = index[name] if name in functional_symbol: features = eval(node, functional_symbol) geom = features.get('geometry') canlabel = features.get('label') ttype = features.get('tissue_type') if geom: # get the transformation from the turtle geom = transform(turtle, geom) mtg.property('geometry')[current_vertex] = geom if name == 'StemElement': # parse args to know how the turtle has to move . args = get_args(node)[1:-1] list_args= args.split(',') length = float(list_args[1]) # 2nd arg if length > 0: turtle.f(length) if canlabel: canlabel.elt_id = index[name] plant_id = mtg.complex_at_scale(current_vertex, scale=1) canlabel.plant_id = mtg.property('index')[plant_id] mtg.property('can_label')[current_vertex] = canlabel if ttype: mtg.property('tissue_type')[current_vertex] = ttype mtg = fat_mtg(mtg) return mtg
def mtg_factory(params, sectors = 1): """ Construct a MTG from a dictionary. The dictionary contains the parameters and a list of elements. Sector is an integer giving the number of LeafElements per Leaf The keys of params are: - plant: indx of plant - axe: - numphy - Lv - L_shape - Lsen - Lw_shape - LcType - LcIndex - Linc - Laz - Lpo - Lpos - Gl - Gv - Gsen - Gpo - Gpos - Gd - Ginc - El - Ev - Esen - Ed - Einc - Epo - Epos :TODO: * add length and final_length (DONE) * fix naming convention for Linc: relative inclination (DONE) * Add a scale to define the tissue types (ear, sheath, laminae, gain) * diam and final_diam (resp. width) * function reset length * function phenology(g, table) -> dynamic parameters (start_thermaltime, end_thermaltime) * function growthThermaltime(g, tt, dtt): tt=thermaltime du couvert * function growthThermaltime(g, tt, dtt, stress factor) * stress factor: offre/demande - demand = :math:`D=\int_{tt}^{tt+dtt}{S(x)dx}*\rho_s+\int_{tt}^{tt+dtt}{V(x)dx}*\rho_v` - offre : :math:`sum{E_abs}*\eps_b` => ds = ds_predit* stress_factor * give the area to the leaf model * update properties """ if not _check_adel_parameters(params): raise ValueError('Adel parameters are invalid') g = MTG() topology = ['plant', 'axe', 'numphy'] # buffers prev_plant = 0 prev_axe = -1 prev_metamer = -1 vid_plant = -1 vid_axe = -1 vid_metamer = -1 vid_node = -1 # store the metamer vids of the axis 0 metamers = [] nodes = [] edge_type = '<' dp = params nrow = len(params['plant']) for i in range(nrow): #plant, axe, num_metamer = [int(convert(d.get(x),undef=None)) for x in topology] plant = int(dp['plant'][i]) try: axe = int(dp['axe'][i]) except: axe = int(dp['ms_insertion'][i]) num_metamer = int(dp['numphy'][i]) #plant, axe, num_metamer = [int(convert(d.get(x),undef=None)) for x in topology] #print 'plant: %d, axe:%d, nb_metamers: %d'%(plant, axe, num_metamer) # Add new plant if plant != prev_plant: label = 'plant'+str(plant) vid_plant = g.add_component(g.root, label=label, edge_type='/') vid_axe = -1 vid_metamer = -1 vid_node = -1 prev_axe = -1 if num_metamer < prev_metamer: prev_axe = -1 prev_metamer = -1 # Add an axis if axe != prev_axe: label = 'axe'+str(axe) if axe == 0: vid_axe = g.add_component(vid_plant,edge_type='/',label=label) vid_node = -1 else: #args['edge_type'] = '+' edge_type = '+' assert g.parent(vid_plant) is None new_axe = g.add_child(vid_axe,edge_type=edge_type,label=label) print vid_axe, new_axe, vid_plant assert g.parent(vid_plant) is None #vid, vid_axe = g.add_child_and_complex(metamers[axe], complex=vid_axe, **args) # Add metamers args = properties_from_dict(dp,i,exclude=topology) assert num_metamer > 0 label = 'metamer'+str(num_metamer) if axe==0 and num_metamer==1: metamers=[] edge_type = '/' vid_metamer = g.add_component(vid_axe, edge_type='/', label = label, **args) elif num_metamer == 1: # Add the first element connected to previous metamer on the previous axis edge_type = '+' vid_metamer = g.add_component(vid_axe, label=label, **args) vid_metamer = g.add_child(metamers[axe-1], child=vid_metamer, edge_type='+') vid_node = nodes[axe-1] else: edge_type = '<' vid_metamer = g.add_child(vid_metamer, label=label, edge_type='<',**args) if axe == 0: metamers.append(vid_metamer) # Add internode, sheath, and lamina # Visible Internode #if args['Ev'] > 0.: tissue = 'internode' # Several cases: Egreen = args['Ev']-args['Esen'] if args['Ev']-args['Esen'] >0. else 0. Esen = args['Ev'] if Egreen == 0. else args['Esen'] # - Green element and perhaps a senescent one if vid_node == -1: # first metamer on the axis vid_node= g.add_component(vid_metamer, label='StemElement', edge_type='/', length=Egreen,final_length=args['El'],po=args['Epo'], diam=args['Ed'], tissue=tissue, inclination=args['Einc'] ) assert edge_type == '/' else: # first element on the metamer which has a parent metamer on the axis new_node = g.add_component(vid_metamer) vid_node= g.add_child(vid_node,child=new_node, label='StemElement', edge_type=edge_type, length=Egreen,final_length=args['El'],po=args['Epo'], diam=args['Ed'], tissue=tissue, inclination=args['Einc'] ) # Add a senescent element #if args['Esen'] > 0.: vid_node = g.add_child(vid_node, label='StemElement', edge_type='<', length=Esen,final_length=args['El'],po=args['Epos'], diam=args['Ed'], tissue=tissue, sen=True, inclination=0.) # Sheath # Same logic that described previously. Ggreen = args['Gv']-args['Gsen'] if args['Gv']-args['Gsen'] >0. else 0. Gsen = args['Gv'] if Ggreen == 0. else args['Gsen'] vid_node= g.add_child(vid_node, label='StemElement', edge_type='<', length=Ggreen,final_length=args['Gl'],po=args['Gpo'], diam=args['Gd'], tissue=tissue, inclination=args['Ginc'] ) #if args['Gsen'] > 0.: vid_node= g.add_child(vid_node, label='StemElement', edge_type='<', length=Gsen,final_length=args['Gl'],po=args['Gpos'], diam=args['Gd'], sen=True, tissue=tissue, inclination=0.) if axe == 0: nodes.append(vid_node) # Lamina #if args['Lv'] > 0.: l_node = vid_node tissue='lamina' ds = 1. / sectors srlim = 1.-(args['Lsen']/args['Lv']) st = ds edge_type = '+' Laz = args['Laz'] Lgreen = args['Lv']-args['Lsen'] if args['Lv']-args['Lsen'] >0. else 0. Lsen = args['Lv'] if Lgreen == 0. else args['Lsen'] for isect in range(sectors): # create one green and/or one senescent sector srb_green = st-ds srt_green = min(st, max(srb_green,srlim)) srb_sen = srt_green srt_sen= st l_node = g.add_child(l_node, label='LeafElement', edge_type=edge_type, length=args['Lv'],final_length=args['L_shape'],po=args['Lpo'], Ll=args['Ll'], Lw= args['Lw_shape'], LcType=args['LcType'], LcIndex=args['LcIndex'], Laz=Laz,Linc=args['Linc'], srb=srb_green, srt=srt_green, tissue=tissue) l_node = g.add_child(l_node, label='LeafElement', edge_type='<', length=args['Lv'],final_length=args['L_shape'],po=args['Lpos'], Ll=args['Ll'], Lw= args['Lw_shape'], LcType=args['LcType'], LcIndex=args['LcIndex'], Laz=Laz,Linc=args['Linc'], srb=srb_sen, srt=srt_sen, sen=True, tissue=tissue) st += ds edge_type = '<' prev_plant = plant prev_axe = axe prev_metamer = num_metamer return fat_mtg(g)
def topological_table_to_mtg(csv_file, epsilon=1e-6): f = open(csv_file) l=f.readline() sniffer = csv.Sniffer() dialect = sniffer.sniff(l) # Go from start of file f.seek(0) reader = csv.DictReader(f, dialect=dialect) # Build the MTG g = MTG() topology = ['plant', 'axe', 'numphy'] # buffers prev_plant = 0 prev_axe = -1 prev_metamer = -1 vid_plant = -1 vid_axe = -1 vid_metamer = -1 vid_node = -1 # store the metamer vids of the axis 0 metamers = [] nodes = [] edge_type = '<' for d in reader: plant, axe, num_metamer = [int(convert(d.get(x),undef=None)) for x in topology] #print 'adding vertices for plant: %d, axe:%d, metamer: %d'%(plant, axe, num_metamer) # Add new plant if plant != prev_plant: label = 'plant'+str(plant) vid_plant = g.add_component(g.root, edge_type='/',label=label) vid_axe = -1 vid_metamer = -1 vid_node = -1 prev_axe = -1 #?? if num_metamer < prev_metamer: prev_axe = -1 prev_metamer = -1 # Add an axis if axe != prev_axe: label = 'axe'+str(axe) if axe == 0: vid_axe = g.add_component(vid_plant,edge_type='/',label=label) vid_node = -1 else: #args['edge_type'] = '+' edge_type = '+' vid_axe = g.add_child(vid_axe, edge_type=edge_type, label=label) #vid, vid_axe = g.add_child_and_complex(metamers[axe], complex=vid_axe, **args) # Add metamers args = properties(d, exclude=topology) assert num_metamer > 0 label = 'metamer'+str(num_metamer) new_axe = True if axe==0 and num_metamer==1: metamers=[] edge_type = '/' vid_metamer = g.add_component(vid_axe, edge_type='/', label = label, **args) elif num_metamer == 1: # Add the first element connected to previous metamer on the previous axis edge_type = '+' vid_metamer, vid_axe = g.add_child_and_complex(metamers[axe-1], complex=vid_axe, edge_type='+',label=label, **args) vid_node = nodes[axe-1] else: edge_type = '<' vid_metamer = g.add_child(vid_metamer, label=label, edge_type='<',**args) new_axe = False if axe == 0: metamers.append(vid_metamer) # Add internode, sheath, and lamina nb_internodes = 0 nb_sheath = 0 nb_leaf = 0 # Internode if args['Ev'] > 0.: if args['Esen'] > args['Ev']: if vid_node == -1: vid_node= g.add_component(vid_metamer, label='Esen', edge_type='/',length=args['Ev'],po=args['Epos'], diam=args['Ed'] ) assert edge_type == '/' else: vid_node, vid_metamer= g.add_child_and_complex(vid_node, complex=vid_metamer, label='Esen', edge_type=edge_type,length=args['Ev'],po=args['Epos'], diam=args['Ed'] ) else: if vid_node == -1: vid_node= g.add_component(vid_metamer, label='Egreen', edge_type='/',length=args['Ev']-args['Esen'],po=args['Epo'], diam=args['Ed'] ) assert edge_type == '/' else: vid_node, vid_metamer= g.add_child_and_complex(vid_node, complex=vid_metamer, label='Egreen', edge_type=edge_type,length=args['Ev']-args['Esen'],po=args['Epo'], diam=args['Ed'] ) vid_node = g.add_child(vid_node, label='Esen', edge_type='<',length=args['Esen'],po=args['Epos'], diam=args['Ed']) else: if new_axe and args['Gv'] == 0.: if vid_node == -1: vid_node= g.add_component(vid_metamer, label='Egreen', edge_type='/',length=0.,po=args['Epo'], diam=args['Ed'] ) else: vid_node, vid_metamer= g.add_child_and_complex(vid_node, complex=vid_metamer, label='Egreen', edge_type=edge_type,length=0.,po=args['Epo'], diam=args['Ed'] ) # Sheath if args['Gv'] > 0.: if args['Gsen'] > args['Gv']: vid_node= g.add_child(vid_node, label='Gsen', edge_type='<',length=args['Gv'],po=args['Gpos'], diam=args['Gd'] ) else: vid_node = g.add_child(vid_node, label='Ggreen', edge_type='<',length=args['Gv']-args['Gsen'],po=args['Gpo'], diam=args['Gd'] ) vid_node = g.add_child(vid_node, label='Gsen', edge_type='<',length=args['Gsen'],po=args['Gpos'], diam=args['Gd']) if axe == 0: nodes.append(vid_node) # Laminae if args['Lv'] > 0.: if args['Lsen'] > args['Lv']: l_node= g.add_child(vid_node, label='Lsen', edge_type='+',length=args['Lv'],po=args['Lpos'], Ll=args['Ll'], Lw= args['Lw'], LcType=args['LcType'], LcIndex=args['LcIndex'], Linc=args['Linc'], Laz=args['Laz'], srb=0, srt=1) else: l_node = g.add_child(vid_node, label='Lgreen', edge_type='+',length=args['Lv']-args['Lsen'],po=args['Lpo'], Ll=args['Ll'], Lw= args['Lw'], LcType=args['LcType'], LcIndex=args['LcIndex'], Linc=args['Linc'], Laz=args['Laz'], srb=0, srt=1-(args['Lsen']/args['Lv'])) l_node = g.add_child(l_node, label='Lsen', edge_type='<',length=args['Lsen'],po=args['Lpos'], Ll=args['Ll'], Lw= args['Lw'], LcType=args['LcType'], LcIndex=args['LcIndex'], Linc=args['Linc'], Laz=args['Laz'], srt=1, srb=1-(args['Lsen']/args['Lv'])) prev_plant = plant prev_axe = axe prev_metamer = num_metamer f.close() return fat_mtg(g)
def new_mtg_factory(parameters, metamer_factory=adel_metamer, leaf_sectors=1, leaves=None, stand=None, axis_dynamics=None, add_elongation=False, topology=('plant', 'axe_id', 'numphy'), split=False, aborting_tiller_reduction=1.0, leaf_db=None): """A 'clone' of mtg_factory that uses mtg_edition functions """ if leaf_db is not None: raise AdelDeprecationError( 'leaf_db argument is deprecated, use leaves argument instead') if leaves is None: dynamic_leaf_db = {0: False} leaves = {0: None} else: dynamic_leaf_db = {k: leaves[k].dynamic for k in leaves} g = MTG() # buffers # for detection of newplant/newaxe prev_plant = 0 prev_axe = -1 dp = parameters nrow = len(dp['plant']) species = 0 for i in range(nrow): plant, num_metamer = [int(convert(dp.get(x)[i], undef=None)) for x in [topology[e] for e in [0, 2]]] axe = dp.get(topology[1])[i] args = properties_from_dict(dp, i, exclude=topology) # Add plant if new if plant != prev_plant: if axe != 'MS': raise ValueError('Main stem is expected first when a new plant ' 'is declared') position, azimuth = (0, 0, 0), 0 if stand and len(stand) >= plant: position, azimuth = stand[plant - 1] plant_properties = {'position': position, 'azimuth': azimuth, 'refplant_id': args.get('refplant_id'), 'species': species} timetable = None if axis_dynamics: timetable = axis_dynamics[str(plant)][str(axe)] mainstem_properties = dict(timetable=timetable, HS_final=args.get('HS_final'), nff=args.get('nff'), hasEar=args.get('hasEar'), azimuth=args.get('az_insertion')) add_plant(g, plant_number=plant, plant_properties=plant_properties, axis_properties=mainstem_properties) prev_plant = plant # Add axis if axe != prev_axe and axe != 'MS': timetable = None if axis_dynamics: timetable = axis_dynamics[str(plant)][str(axe)] axe_properties = dict(timetable=timetable, HS_final=args.get('HS_final'), nff=args.get('nff'), hasEar=args.get('hasEar'), azimuth=args.get('az_insertion')) add_axe(g, axe, plant, axis_properties=axe_properties) prev_axe = axe # Add metamer assert num_metamer > 0 # args are added to metamers only if metamer_factory is none, # otherwise compute metamer components components = [] if metamer_factory: xysr_key = None if leaves[species] is not None and 'LcType' in args and 'LcIndex' in args: lctype = int(args['LcType']) lcindex = int(args['LcIndex']) if lctype != -999 and lcindex != -999: age = None if dynamic_leaf_db[species]: age = float(args[ 'rph']) - 0.3 # age_db = HS - rank + 1 = ph - 1.3 - rank +1 = rph - .3 if age != 'NA': age = max(0, int(float(age))) xysr_key = leaves[species].get_leaf_key(lctype, lcindex, age) elongation = None if add_elongation: startleaf = -.4 endleaf = 1.6 stemleaf = 1.2 startE = endleaf endE = startE + (endleaf - startleaf) / stemleaf endBlade = endleaf if args['Gl'] > 0: endBlade = args['Ll'] / args['Gl'] * (endleaf - startleaf) elongation = {'startleaf': startleaf, 'endBlade': endBlade, 'endleaf': endleaf, 'endE': endE} if not 'ntop' in args: args.update({'ntop': None}) if not 'Gd' in args: args.update({'Gd': 0.19}) args.update({'split': split}) if args.get('HS_final') < args.get('nff'): for what in ( 'Ll', 'Lv', 'Lr', 'Lsen', 'L_shape', 'Lw_shape', 'Gl', 'Gv', 'Gsen', 'Gd', 'El', 'Ev', 'Esen', 'Ed'): args.update( {what: args.get(what) * aborting_tiller_reduction}) components = metamer_factory(Lsect=leaf_sectors, shape_key=xysr_key, elongation=elongation, leaves=leaves[species], **args) args = {'L_shape': args.get('L_shape')} # metamer_properties = args internode, sheath, blade = None, None, None elts = {k: [] for k in ('internode', 'sheath', 'blade')} if len(components) > 0: internode, sheath, blade = components internode.pop('label') sheath.pop('label') blade.pop('label') elts['internode'] = internode.pop('elements') elts['sheath'] = sheath.pop('elements') elts['blade'] = blade.pop('elements') vid_metamer = add_vegetative_metamer(g, plant, axe, metamer_properties=metamer_properties, internode_properties=internode, sheath_properties=sheath, blade_properties=blade) for organ in g.components(vid_metamer): label = g.property('label')[organ] if label in elts and len(elts[label]) > 0: insert_elements(g, organ, elts[label]) return fat_mtg(g)
def mtg_factory(parameters, metamer_factory=None, leaf_sectors=1, leaves = None, stand = None, axis_dynamics = None, add_elongation = False, topology = ['plant','axe_id','numphy'], split=False, aborting_tiller_reduction = 1.0, leaf_db =None): """ Construct a MTG from a dictionary of parameters. The dictionary contains the parameters of all metamers in the stand (topology + properties). metamer_factory is a function that build metamer properties and metamer elements from parameters dict. leaf_sectors is an integer giving the number of LeafElements per Leaf blade leaves is an instance of adel.geometric_elements.Leaves class stand is a list of tuple (xy_position_tuple, azimuth) of plant positions axis_dynamics is a 3 levels dict describing axis dynamic. 1st key level is plant number, 2nd key level is axis number, and third ky level are labels of values (n, tip, ssi, disp) topology is the list of key names used in parameters dict for plant number, axe number and metamer number aborting_tiller_reduction is a scaling factor applied to reduce all dimensions of organs of tillers that will abort Axe number 0 is compulsory """ if leaf_db is not None: raise AdelDeprecationError('leaf_db argument is deprecated, use leaves argument instead') if leaves is None: dynamic_leaf_db = False else: dynamic_leaf_db = leaves.dynamic g = MTG() # buffers # for detection of newplant/newaxe prev_plant = 0 prev_axe = -1 # current vid vid_plant = -1 vid_axe = -1 vid_metamer = -1 vid_node = -1 vid_elt = -1 # vid of top of stem nodes and elements vid_topstem_node = -1 vid_topstem_element = -1 #vid of plant main stem (axe0) vid_main_stem = -1 # buffer for the vid of main stem anchor points for the first metamer, node and element of tillers metamers = [] nodes = [] elts = [] dp = parameters nrow = len(dp['plant']) for i in range(nrow): plant, num_metamer = [int(convert(dp.get(x)[i],undef=None)) for x in [topology[e] for e in [0,2]]] axe = dp.get(topology[1])[i] mspos = int(convert(dp.get('ms_insertion')[i],undef=None)) args = properties_from_dict(dp,i,exclude=topology) # Add plant if new if plant != prev_plant: label = 'plant' + str(plant) position = (0,0,0) azimuth = 0 if stand and len(stand) >= plant: position,azimuth = stand[plant-1] vid_plant = g.add_component(g.root, label=label, edge_type='/', position = position, azimuth = azimuth, refplant_id = args.get('refplant_id')) #reset buffers prev_axe = -1 vid_axe = -1 vid_metamer = -1 vid_node = -1 vid_elt = -1 vid_topstem_node = -1 vid_topstem_element = -1 vid_main_stem = -1 metamers = [] nodes = [] elts = [] # Add axis if axe != prev_axe: label = ''.join(axe.split('.')) timetable = None if axis_dynamics: timetable = axis_dynamics[str(plant)][str(axe)] if axe == 'MS': vid_axe = g.add_component(vid_plant,edge_type='/',label=label, timetable=timetable, HS_final=args.get('HS_final'), nff=args.get('nff'), hasEar=args.get('hasEar'), azimuth=args.get('az_insertion')) vid_main_stem = vid_axe else: vid_axe = g.add_child(vid_main_stem, edge_type='+',label=label, timetable=timetable, HS_final=args.get('HS_final'), nff=args.get('nff'), hasEar=args.get('hasEar'), azimuth=args.get('az_insertion')) # Add metamer assert num_metamer > 0 # args are added to metamers only if metamer_factory is none, otherwise compute metamer components components = [] if metamer_factory: xysr_key = None if leaves is not None and 'LcType' in args and 'LcIndex' in args: lctype = int(args['LcType']) lcindex = int(args['LcIndex']) if lctype != -999 and lcindex != -999: age = None if dynamic_leaf_db: age = float(args['rph']) - 0.3 # age_db = HS - rank + 1 = ph - 1.3 - rank +1 = rph - .3 if age != 'NA': age = max(0,int(float(age))) xysr_key = leaves.get_leaf_key(lctype, lcindex, age) elongation = None if add_elongation: startleaf = -.4 endleaf = 1.6 stemleaf = 1.2 startE = endleaf endE = startE + (endleaf - startleaf) / stemleaf endBlade = endleaf if args['Gl'] > 0: endBlade = args['Ll'] / args['Gl'] * (endleaf - startleaf) elongation = {'startleaf' : startleaf , 'endBlade':endBlade, 'endleaf': endleaf, 'endE': endE} if not 'ntop' in args: args.update({'ntop':None}) if not 'Gd' in args: args.update({'Gd':0.19}) args.update({'split':split}) if args.get('HS_final') < args.get('nff'): for what in ('Ll', 'Lv', 'Lr', 'Lsen', 'L_shape', 'Lw_shape', 'Gl', 'Gv', 'Gsen', 'Gd', 'El', 'Ev', 'Esen', 'Ed'): args.update({what:args.get(what) * aborting_tiller_reduction}) components = metamer_factory(Lsect = leaf_sectors, shape_key = xysr_key, elongation = elongation, leaves = leaves, **args) args={'L_shape':args.get('L_shape')} # label = 'metamer'+str(num_metamer) new_metamer = g.add_component(vid_axe, edge_type='/', label = label, **args) if axe=='MS' and num_metamer==1: vid_metamer = new_metamer elif num_metamer == 1: # add the edge with the bearing metamer on main stem vid_metamer = metamers[mspos-1] vid_metamer = g.add_child(vid_metamer, child=new_metamer, edge_type='+') else: vid_metamer = g.add_child(vid_metamer, child=new_metamer, edge_type='<') # add metamer components, if any if len(components) > 0: # deals with first component (internode) and first element node, elements = get_component(components,0) element = elements[0] new_node = g.add_component(vid_metamer, edge_type='/', **node) new_elt = g.add_component(new_node, edge_type='/', **element) if axe=='MS' and num_metamer==1: #root of main stem vid_node = new_node vid_elt = new_elt elif num_metamer == 1: # root of tiller vid_node = nodes[mspos - 1] vid_node = g.add_child(vid_node, child = new_node, edge_type='+') vid_elt = elts[mspos - 1] vid_elt = g.add_child(vid_elt, child = new_elt, edge_type='+') else: vid_node = g.add_child(vid_topstem_node, child=new_node, edge_type='<') vid_elt = g.add_child(vid_topstem_element, child=new_elt, edge_type='<') #add other elements of first component (the internode) for i in range(1,len(elements)): element = elements[i] vid_elt = g.add_child(vid_elt, edge_type='<',**element) vid_topstem_node = vid_node vid_topstem_element = vid_elt #last element of internode # add other components for i in range(1,len(components)): node, elements = get_component(components,i) if node['label'] == 'sheath': edge_type = '+' else: edge_type = '<' vid_node = g.add_child(vid_node, edge_type=edge_type, **node) element = elements[0] new_elt = g.add_component(vid_node, edge_type='/', **element) vid_elt = g.add_child(vid_elt, child=new_elt, edge_type=edge_type) for j in range(1,len(elements)): element = elements[j] vid_elt = g.add_child(vid_elt, edge_type='<',**element) #update buffers if axe == 'MS' : metamers.append(vid_metamer) if len(components) > 0: nodes.append(vid_topstem_node) elts.append(vid_topstem_element) prev_plant = plant prev_axe = axe return fat_mtg(g)