def read_rsml(file_name:str, verbose=True): """ reads an RSML file and converts to MappedSegments with units [cm] @file_name the file name of the rsml, including file extension (e.g. "test.rsml" ) @return a CPlantBox MappedSegments object """ polylines, props, funcs = rsml.read_rsml(file_name) bn = 0 # count base roots for i, _ in enumerate(polylines): if props["parent-poly"][i] < 0: bn += 1 if bn > 1: polylines, props, funcs = rsml.artificial_shoot(polylines, props, funcs) if verbose: print("XylemFluxPython.read_rsml: added an artificial shoot") nodes, segs = rsml.get_segments(polylines, props) radii, seg_ct, types = rsml.get_parameter(polylines, funcs, props) if verbose: print("XylemFluxPython.read_rsml: read rsml with", len(nodes), "nodes and", len(segs), "segments") nodes = np.array(nodes) # for slicing in the plots nodes2 = [] # Conversions... for n in nodes: nodes2.append(pb.Vector3d(n[0] , n[1] , n[2])) segs2 = [] nodeCTs = np.zeros((len(nodes), 1)) # we need node creation times for i, s in enumerate(segs): nodeCTs[s[1]] = seg_ct[i] segs2.append(pb.Vector2i(int(s[0]), int(s[1]))) radii = np.array(radii) types = np.array(types, dtype=np.int64) - 1 # index must start with 0 if verbose: print(" nodeCTs [{:g}, {:g}] days".format(np.min(nodeCTs), np.max(nodeCTs))) print(" raddii [{:g}, {:g}] cm".format(np.min(radii), np.max(radii))) print(" subTypes [{:g}, {:g}] ".format(np.min(types), np.max(types))) return pb.MappedSegments(nodes2, nodeCTs, segs2, radii, types) # root system grid
def convert_to_xylem_flux_(self): """ converts the polylines to a SegmentAnalyser and a MappedSegments object, and stores max_ct uses: properties["parent-poly"], properties["parent-nodes"] radii, cts, types """ nodes, segs = rsml_reader.get_segments(self.polylines, self.properties) # fetch nodes and segments segRadii = np.zeros((segs.shape[0], 1)) # convert to paramter per segment segCTs = np.zeros((segs.shape[0], 1)) subTypes = np.zeros((segs.shape[0], 1)) for i, s in enumerate(segs): segRadii[i] = self.radii[s[1]] # seg to node index segCTs[i] = self.cts[s[1]] subTypes[i] = self.types[s[1]] if np.isnan(subTypes[0]): subTypes = np.ones((len(segs),), dtype=np.int64) segs_ = [pb.Vector2i(s[0], s[1]) for s in segs] # convert to CPlantBox types nodes_ = [pb.Vector3d(n[0], n[1], n[2]) for n in nodes] self.analyser = pb.SegmentAnalyser(nodes_, segs_, segCTs, segRadii) self.analyser.addData("subType", subTypes) ms = pb.MappedSegments(self.analyser.nodes, np.array(self.cts), segs_, np.array(segRadii), np.array(subTypes)) self.xylem_flux = xylem_flux.XylemFluxPython(ms) self.base_nodes = self.get_base_node_indices_() self.xylem_flux.neumann_ind = self.base_nodes # needed for suf self.xylem_flux.dirichlet_ind = self.base_nodes # needed for krs self.base_segs = self.xylem_flux.find_base_segments()
def read_rsml(file_name: str): """ Reads an RSML file and converts to MappedSegments with units [cm] """ polylines, props, funcs = rsml.read_rsml(file_name) assert len(polylines) == len( props['parent-poly'] ), "XylemFluxPython.read_rsml: wrong number of parent-poly tags" if not 'parent-node' in props: # reconstruct... print("parse_rsml: no parent-node tag found, reconstructing...") props['parent-node'] = [] for i in range(0, len(polylines)): if props['parent-poly'][i] >= 0: pni = XylemFluxPython.connect( np.array(polylines[i][0]), polylines[props['parent-poly'][i]]) else: pni = -1 # print("parent", props['parent-poly'][i], "pni", pni) props['parent-node'].append(pni) assert len(polylines) == len( props['parent-node'] ), "XylemFluxPython.read_rsml: wrong number of parent-node tags" nodes, segs = rsml.get_segments(polylines, props) print("Read rsml:", len(nodes), "segs", len(segs), "segs") nodes2 = [pb.Vector3d(n[0], n[1], n[2]) for n in nodes] # convert to plantbox types segs2 = [pb.Vector2i(int(s[0]), int(s[1])) for s in segs] radii_, nodeCTs_, types_ = [], [], [] for i, p in enumerate(polylines): for j in range(0, len(p)): if 'diameter' in funcs: radii_.append(funcs['diameter'][i][j] / 2) else: print("XylemFluxPython.read_rsml: no diameter tag found") radii_.append(0.) if 'emergence_time' in funcs: nodeCTs_.append(funcs['emergence_time'][i][j]) else: print( "XylemFluxPython.read_rsml: no emergence_time tag found" ) nodeCTs_.append(0.) if 'type' in funcs: types_.append(funcs["type"][i][j]) elif 'type' in props: types_.append(props["type"][i]) else: print("XylemFluxPython.read_rsml: no type tag found") types_.append(0) nodeCTs = np.array(nodeCTs_) # creation times per node radii = np.zeros((len(segs), 1)) # radii per segment types = np.ones((len(segs), 1), dtype=np.int64) # types per semgent for i, s in enumerate(segs): radii[i] = radii_[s[1]] types[i] = types_[s[1]] - 1 # index must start with 0 return pb.MappedSegments(nodes2, nodeCTs, segs2, radii, types) # root system grid
def read_rsml(file_name: str, verbose=True): """ reads an RSML file and converts to MappedSegments with units [cm] @file_name the file name of the rsml, including file extension (e.g. "test.rsml" ) @return a CPlantBox MappedSegments object """ polylines, props, funcs, _ = rsml.read_rsml(file_name) bn = 0 # count base roots for i, _ in enumerate(polylines): if props["parent-poly"][i] < 0: bn += 1 if bn > 1: rsml.artificial_shoot(polylines, props, funcs) if verbose: print("XylemFluxPython.read_rsml: added an artificial shoot") nodes, segs = rsml.get_segments(polylines, props) if verbose: print("XylemFluxPython.read_rsml: read rsml with", len(nodes), "nodes and", len(segs), "segments") nodes2 = [pb.Vector3d(n[0], n[1], n[2]) for n in nodes] # Conversions to PlantBox types segs2 = [pb.Vector2i(int(s[0]), int(s[1])) for s in segs] radii, cts, types, tag_names = rsml.get_parameter( polylines, funcs, props) segRadii = np.zeros( (segs.shape[0], 1)) # convert to paramter per segment segTypes = np.zeros((segs.shape[0], 1)) for i, s in enumerate(segs): segRadii[i] = radii[s[1]] # seg to node index segTypes[i] = types[s[1]] if verbose: print(" cts [{:g}, {:g}] days".format( np.min(cts), np.max(cts))) print(" raddii [{:g}, {:g}] cm".format( np.min(radii), np.max(radii))) print(" subTypes [{:g}, {:g}] ".format( np.min(types), np.max(types))) print() return pb.MappedSegments(nodes2, cts, segs2, segRadii, segTypes) # root system grid
def read_rsml(file_name: str): """ Reads an RSML file and converts to MappedSegments with units [cm] """ polylines, props, funcs = rsml.read_rsml(file_name) nodes, segs = rsml.get_segments(polylines, props) radii, seg_ct, types = rsml.get_parameter(polylines, funcs, props) print("Read rsml:", len(nodes), "nodes", len(radii), "radii") nodes = np.array(nodes) # for slicing in the plots nodes2 = [] # Conversions... for n in nodes: nodes2.append(pb.Vector3d(n[0], n[1], n[2])) segs2 = [] nodeCTs = np.zeros((len(nodes), 1)) # we need node creation times for i, s in enumerate(segs): nodeCTs[s[1]] = seg_ct[i] segs2.append(pb.Vector2i(int(s[0]), int(s[1]))) radii = np.array(radii) types = np.array(types, dtype=np.int64) - 1 # index must start with 0 return pb.MappedSegments(nodes2, nodeCTs, segs2, radii, types) # root system grid
def check_polylines_2d_(self, shift_z=False): """ converts 2d image coordinates to 3d coordinates shift_z determines if the roots system seed is shifted to -3 cm """ nodes, segs = rsml_reader.get_segments(self.polylines, self.properties) # fetch nodes and segments maxz = np.max(nodes[:, 2]) minz = np.min(nodes[:, 2]) if maxz >= 0 and minz >= 0: # image coordinates in px often start in lower left corner print("DataModel.check_polylines_2d_(): assuming image coordinates, y-centered and z-flipped ") miny = np.min(nodes[:, 1]) yy = np.max(nodes[:, 1]) - miny for pl in self.polylines: # both (pl and node) are references for node in pl: node[2] = -node[2] node[1] = node[1] - miny - yy / 2 if shift_z: print("DataModel.check_polylines_2d_(): root system seed is shifted to (x,y,-3) ") z = self.polylines[0][0][2] print("z", z) for pl in self.polylines: # both (pl and node) are references for node in pl: node[2] = node[2] - z + (-3)