def extend_from_db(G, attachmentVertices, dbDirectory): """Extends a VascularGraph at given attachment vertices with vascular trees chosen randomly from a tree database. INPUT: G: VascularGraph attachmentVertices: Vertices at which the vascular trees are to be attached. dbDirectory: The directory of the database as string. OUTPUT: None (G is modified in-place.) """ # Get names of database files: dbFiles = glob.glob1(dbDirectory, '*.pkl') # Determine number of vascular trees present in the database: dbCount = len(dbFiles) # At each attachment vertex, extend the VascularGraph with a vascular tree # from the database: Gtrees = vgm.VascularGraph(0) treeno = 1 G.vs['degree']=G.degree() for vertex in attachmentVertices: #print('Tree %i of %i' % (treeno, len(attachmentVertices))); treeno += 1 i = np.random.random_integers(0,dbCount-1,1)[0] vascularTree = vgm.read_pkl(os.path.join(dbDirectory, dbFiles[i])) offset = G.vs[vertex]['r'] - \ vascularTree.vs[vascularTree['attachmentVertex']]['r'] vgm.shift(vascularTree, offset) Gtrees.disjoint_union_attribute_preserving(vascularTree, 'omit') #G.union_attribute_preserving(vascularTree) if G.vs['apv'][vertex] == 1: kindAttr='pa' elif G.vs['vpv'][vertex] == 1: kindAttr='pv' else: kindAttr='n' stdout.flush() G.union_attribute_preserving(Gtrees, 'omit',kind=kindAttr)
def construct_cortical_network(G, gXtm, zLim=None, originXtm=None, insertXtm=False, invivo=True,BC=[60,10,0.2]): """Builds a VascularGraph that includes the pial vessels, penetrating arterioles and draining veins, as well as the capillary bed. INPUT: G: VascularGraph of the pial network. This should be created using the function construct_pial_network(). gXTM: VascularGraph of srXTM data. This is implanted at location originXtm of the cortical network. zLim: Limits of capillary grid in z-direction as tuple (zMin, zMax). If not supplied, it will be determined from the artificial network consisting of pial and penetrating vessels, as well as the SRXTM sample. originXtm: The origin (x,y) of the cylindrical srXTM in the cortical network, i.e. the location of its rotational axis. This will be the network's center of mass, if not provided. sf: Scaling Factor by which to multiply vertex positions and diameters (e.g. to convert units of pixels to microns). epperc: Percentage of offshoots that should be en-passent. These are chosen randomly. BC: list with pBC at inlet, pBC at outlet, inflow tube hematocrit OUTPUT: G: VascularGraph. Note that this function relies on input from control.py """ # Get settings from control file: basedir = control.basedir treeDB = control.treeDB eps = finfo(float).eps * 1e4 # Add offshoots and remove parts with z<0: print('Adding offshoots (%i arterial and %i venous)...' % (len(G['apv']), len(G['vpv']))) t0 = time.time() vcount = G.vcount() G.vs['apv']=[0]*G.vcount() G.vs['vpv']=[0]*G.vcount() for i in G['apv']: G.vs[i]['apv']=1 for i in G['vpv']: G.vs[i]['vpv']=1 x=[] y=[] for i in G.vs['r']: x.append(i[0]) y.append(i[1]) xMin=np.min(x) xMax=np.max(x) yMin=np.min(y) yMax=np.max(y) stdout.flush() print('CHECK DEGREE 1') print(max(G.degree())) #All deg1 vertices are in apv or vpv or they are in/outlets #add arterial penetratiing trees G.vs['degree'] = G.degree() print('Number of Components: Only pial') print(len(G.components())) print('Should be KEPT!') components=len(G.components()) #extend_from_db(G, G['apv'], os.path.join(treeDB, 'arteryDB')) extend_from_db(G, G['apv'], os.path.join(treeDB, 'arteryDBmouse')) print('Number of Components: Artery trees added') print(len(G.components())) print('CHECK DEGREE 2') print(max(G.degree())) if len(G.components()) > components: print('ERROR') print('More components than expected') #Assign kind G.vs[range(vcount, G.vcount())]['kind'] = ['a' for v in xrange(vcount, G.vcount())] G.vs['degree']=G.degree() vcount = G.vcount() #add venous penetrating trees #extend_from_db(G, G['vpv'], os.path.join(treeDB, 'veinDB')) extend_from_db(G, G['vpv'], os.path.join(treeDB, 'veinDBmouse')) print('Number of Components: Vein trees added') print(len(G.components())) print('CHECK DEGREE 3') print(max(G.degree())) if len(G.components()) > components: print('ERROR') print('More components than expected') #Assign kind G.vs[range(vcount, G.vcount())]['kind'] = ['v' for v in xrange(vcount, G.vcount())] G.vs['degree']=G.degree() #adding trees lead to some new dead ends at the z=0 level, in contrast to the penetrating vessels their kind #is either 'a' or 'v' but not 'pa' and not 'pv' #Remove capillaries (d < 7 mum) in pial vessels and penetrating vessels print(str(len(G.es(diameter_le=7)))+' Edges have a diameter which is smaller than 7mum and are therefor removed') G.delete_edges(G.es(diameter_le=7)) G.vs['degree']=G.degree() print('Number of Components: Capillaries deleted') print(len(G.components())) if len(G.components()) > components: print('ERROR') print('More components than expected') print(components) print(len(G.components())) for i in len(G.components()): print(len(G.components()[i])) #Remove vertices where z < 0 (would be abolve pial surface) G.vs['z'] = [r[2] for r in G.vs['r']] deleteList=G.vs(z_lt=0).indices print('Number of vertices where z<0') print(len(deleteList)) deleteList.sort(reverse=True) for i in range(len(deleteList)): G.delete_vertices(deleteList[i]) print('Number of components: z lt 0 deleted') print(len(G.components())) if len(G.components()) > components: print('ERROR') print('More components than expected') G.vs['degree']=G.degree() G.delete_vertices(G.vs(degree_eq=0)) print('Number of components: degree 0 deleted') print(len(G.components())) if len(G.components()) > components: print('ERROR') print('More components than expected') #Delete len=0 edges G.es['length'] = [np.linalg.norm(G.vs[e.source]['r'] - G.vs[e.target]['r']) for e in G.es] G.delete_edges(G.es(length_eq=0).indices) print('...done. Time taken: %.1f min' % ((time.time()-t0)/60.)) G.vs['degree']=G.degree() #Delete double Edges doubleVertices=[] print('CHECK for doule Edges (Edges connecting two similar vertices)') #TODO could be changed that only really similiar edges are deleted (see preprocessing SRCTM) for i in range(G.vcount()): if len(G.neighbors(i)) != len(np.unique(G.neighbors(i))): print('') print(G.neighbors(i)) print(np.unique(G.neighbors(i))) doubleVertices.append(i) print('Number of possible double Edges') print(len(doubleVertices)) while len(doubleVertices) > 0: for i in doubleVertices: neighbors=[] print('') print(G.neighbors(i)) print(G.adjacent(i)) adjacents=G.adjacent(i) for k,j in enumerate(G.neighbors(i)): print('') print(k) if j in neighbors: G.delete_edges(adjacents[k]) else: neighbors.append(j) doubleVertices=[] print('len double vertices') for i in range(G.vcount()): if len(G.neighbors(i)) != len(np.unique(G.neighbors(i))): doubleVertices.append(i) print(len(doubleVertices)) #Assign nkind to vertex for i in range(G.vcount()): if G.vs['kind'][i]=='pa': G.vs[i]['nkind']=0 elif G.vs['kind'][i]=='a': G.vs[i]['nkind']=2 elif G.vs['kind'][i]=='pv': G.vs[i]['nkind']=1 elif G.vs['kind'][i]=='v': G.vs[i]['nkind']=3 vgm.write_pkl(G, 'stage1.pkl') vgm.write_pkl(G, 'stage1.vtp') print('number of capillaries') print(len(G.vs(kind_eq='c'))) if not zLim is None: if max(G.vs['z']) > zLim[1]: print('Deleting all vessels below z=%.1f' % (zLim[1])) t0 = time.time() G.delete_vertices(G.vs(z_gt=zLim[1])) print('...done. Time taken: %.1f min' % ((time.time()-t0)/60.)) vgm.write_pkl(G, 'stage1b.pkl') stdout.flush() # Add capillary bed as honeycomb network: # Add volume and conductance before adding capillary grid print('Adding capillary grid...') #all vertices of the network containing the pial vessels and the numNCVertices = G.vcount() vcount=G.vcount() ecount=G.ecount() t0 = time.time() rMin = np.min(G.vs['r'], axis=0) rMax = np.max((np.max(G.vs['r'], axis=0), (np.max(gXtm.vs['r'], axis=0)-np.min(gXtm.vs['r'], axis=0))), axis=0) if not zLim is None: rMin[2] = zLim[0] rMax[2] = zLim[1] print(rMin) print(rMax) #honeycomb = capillary_bed.randomized_honeycomb(gXtm, (rMin[0], rMax[0]), (rMin[1], rMax[1]), (rMin[2], rMax[2])) honeycomb = capillary_bed.honeycomb((rMin[0], rMax[0]), (rMin[1], rMax[1]), (rMin[2], rMax[2]),60) print('CHECK DEGREE HONEYCOMB') print(max(honeycomb.degree())) print(honeycomb.es.attributes()) print('Edges with 0 length in honeycomb') print(len(honeycomb.es(length_eq=0))) honeycomb.vs['degree']=honeycomb.degree() print('Degree 1 vertices in honeycomb') print(len(honeycomb.vs(degree_eq=1))) #Honeycomb network is moved such that it finishes at the same level as the pial+penetrating-network rMinHC= np.min(honeycomb.vs['r'], axis=0) offset=np.array([0.,0.,rMinHC[2]*(-1)]) print('') print('Honeycomb Network is shifted in z-direction by') print(offset) print('such that zmin of Honeycomb Network = 0') vgm.shift(honeycomb,offset) print('number of capillaries') print(len(G.vs(kind_eq='c'))) #honeycomb network and pial+penetrating network are put together G.disjoint_union_attribute_preserving(honeycomb, 'omit', False) print('number of capillaries') print(len(G.vs(kind_eq='c'))) print(len(xrange(vcount, G.vcount()))) G.vs[range(vcount, G.vcount())]['kind'] = ['c' for v in xrange(vcount, G.vcount())] G.vs[range(vcount, G.vcount())]['nkind'] = [5 for v in xrange(vcount, G.vcount())] G.vs['capGrid']=np.zeros(G.vcount()) G.vs[range(vcount,G.vcount())]['capGrid'] = [1]*(G.vcount()-vcount) G.es['capGrid']=np.zeros(G.ecount()) G.es[range(ecount,G.ecount())]['capGrid'] = [1]*(G.ecount()-ecount) print('number of capillaries') print(len(G.vs(kind_eq='c'))) print('number of honeycomb vertices') print(honeycomb.vcount()) vcount = G.vcount() print(G.es.attributes()) print('Edges with length 0') print(len(G.es(length_eq=0))) #print('...done. Time taken: %.1f min' % ((time.time()-t0)/60.)) vgm.write_pkl(G, 'stage2.pkl') stdout.flush() # Connect offshoots to capillary grid to penetrating vessels: print('Connecting offshoots to capillary grid...') print('number of edges where lenght = 0') print(len(G.es(length_eq=0))) t0 = time.time() G.vs['degree'] = G.degree() G.vs['z'] = [r[2] for r in G.vs['r']] #vertices with only one adjacent edge #cv edges of penetrating trees with dead end --> to be connected to capillary bed cv = G.vs(z_ge=0.0, degree_eq=1,capGrid_eq=0).indices print('Number of pials and trees') print(numNCVertices) print('in cv vertices') print(max(cv)) #In and outlet of pial vessels should be preserved for i in G['vv']: if i in cv: cv.remove(i) else: print(G.vs[i]['r']) for i in G['av']: if i in cv: cv.remove(i) else: print(G.vs[i]['r']) print(len(G.es(length_eq=0))) #Capillary bed should not be attached to pial vessels for i in cv: if G.vs[i]['kind'] == 'pa': print('ERROR') if G.vs[i]['kind'] == 'pv': print('ERROR') Kdt = kdtree.KDTree(honeycomb.vs['r'], leafsize=10) print('Dead Ends to connect') print(len(cv)) stdout.flush() posConnections=[] G.vs['degree']=G.degree() print('Are there degree=0 vertices') print(len(G.vs(degree_eq=0))) #Compute possible Connections for vertices. Maximum degree = 4 G.vs['posConnections']=[3]*G.vcount() deg4=G.vs(degree_ge=4).indices G.vs[deg4]['posConnections']=[0]*len(deg4) deg3=G.vs(degree_eq=3).indices G.vs[deg3]['posConnections']=[1]*len(deg3) deg2=G.vs(degree_eq=2).indices G.vs[deg2]['posConnections']=[2]*len(deg2) print('posConnections assigned') stdout.flush() print('Possible number of connections') posConnections=np.sum(G.vs[numNCVertices:G.vcount()-1]['posConnections']) print(posConnections) stdout.flush() #Start connection process for v in cv: diameter = G.es[G.adjacent(v)[0]]['diameter'] newVertexFound=0 count= 1 while newVertexFound != 1: #start with 5 possible nearest neighbors nearestN=Kdt.query(G.vs[v]['r'],k=10*count) for i in range((count-1)*10,count*10): newVertex=int(nearestN[1][i]) if G.vs['posConnections'][newVertex+numNCVertices] == 0: print('No connection possible') else: G.vs[newVertex+numNCVertices]['posConnections'] = int(np.round(G.vs[newVertex+numNCVertices]['posConnections'] - 1)) newVertexFound = 1 break count += 1 print('CONNECTION FOUND') print(v) stdout.flush() nn = newVertex #Distance between analyzed endppoint and closest point in honeycomb network #Maximum length is set to 5 mum, TODO why is this done? why is not the acrual length used? #length = min(5., np.linalg.norm(G.vs[v]['r'] - G.vs[numNCVertices + nn]['r'])) length = np.linalg.norm(G.vs[v]['r'] - G.vs[numNCVertices + nn]['r']) #inewEdges.append((v, numNCVertices+nn)) #add edge between the points G.add_edges((v, numNCVertices + nn)) G.es[G.ecount()-1]['diameter'] = diameter G.es[G.ecount()-1]['length'] = length print('...done. Time taken: %.1f min' % ((time.time()-t0)/60.)) G.vs['degree'] = G.degree() print('CHECK DEGREE 4') print(max(G.degree())) # Remove edges with length 0 and with degree 1: # Deg1 vertices of artificial capillary bed, should be located at the borders of the artificial capillary bed print('Number of edges where length is equal to 0') print(len(G.es(length_eq=0))) G.delete_edges(G.es(length_eq=0).indices) print('Number of degree 1 vertices') G.vs['degree']=G.degree() print(len(G.vs(degree_eq=1))) deg1=G.vs(degree_eq=1).indices G.vs['av']=[0]*G.vcount() G.vs['vv']=[0]*G.vcount() for i in G['av']: deg1.remove(i) G.vs[i]['av']=1 for i in G['vv']: deg1.remove(i) G.vs[i]['vv']=1 G.delete_vertices(deg1) G['av']=G.vs(av_eq=1).indices G['vv']=G.vs(vv_eq=1).indices print('Number of degree 1 vertices') G.vs['degree']=G.degree() print(len(G.vs(degree_eq=1))) deg1=G.vs(degree_eq=1).indices for i in G['av']: deg1.remove(i) for i in G['vv']: deg1.remove(i) G.delete_vertices(deg1) print('Number of degree 1 vertices') G.vs['degree']=G.degree() G['av']=G.vs(av_eq=1).indices G['vv']=G.vs(vv_eq=1).indices print('Number of degree 1 vertices') deg1=G.vs(degree_eq=1).indices print(len(G.vs(degree_eq=1))) for i in G['av']: deg1.remove(i) for i in G['vv']: deg1.remove(i) G.delete_vertices(deg1) print('Number of degree 1 vertices') G.vs['degree']=G.degree() G['av']=G.vs(av_eq=1).indices G['vv']=G.vs(vv_eq=1).indices print('Number of degree 1 vertices') deg1=G.vs(degree_eq=1).indices print(len(G.vs(degree_eq=1))) vgm.write_vtp(G, 'stage3.vtp', False) vgm.write_pkl(G, 'stage3.pkl') stdout.flush() # Set conductance of all vessels: print('Adding conductance...') t0 = time.time() aindices = G.vs(kind='pa').indices aindices.extend(G.vs(kind='a').indices) vindices = G.vs(kind='pv').indices vindices.extend(G.vs(kind='v').indices) cindices = G.vs(kind='c').indices vgm.add_conductance(G, 'a', invivo,edges=G.get_vertex_edges(aindices)) vgm.add_conductance(G, 'v', invivo,edges=G.get_vertex_edges(vindices)) vgm.add_conductance(G, 'a', invivo,edges=G.get_vertex_edges(cindices)) print('...done. Time taken: %.1f min' % ((time.time()-t0)/60.)) stdout.flush() # Insert srXTM sample at originXtm: print('Embedding SRXTM...') t0 = time.time() if insertXtm: G = implant_srxtm.implant_srxtm(G, gXtm, originXtm) print('...done. Time taken: %.1f min' % ((time.time()-t0)/60.)) G['av']=G.vs(av_eq=1).indices G['vv']=G.vs(vv_eq=1).indices vgm.write_vtp(G, 'stage4.vtp', False) vgm.write_pkl(G, 'stage4.pkl') print('stage4 written') stdout.flush() # Delete obsolete graph properties: for vProperty in ['z', 'degree', 'nkind', 'epID', 'maxD']: if vProperty in G.vs.attribute_names(): del G.vs[vProperty] for eProperty in ['diameter_orig', 'diameter_change', 'cost','depth']: if eProperty in G.es.attribute_names(): del G.es[eProperty] for gPropery in ['attachmentVertex', 'sampleName', 'distanceToBorder', 'avZOffset']: if gPropery in G.attributes(): del G[gPropery] # Add a numerical version of vessel kind to facilitate paraview display: nkind = {'pa':0, 'pv':1, 'a':2, 'v':3, 'c':4, 'n':5} for v in G.vs: v['nkind'] = nkind[v['kind']] G.vs['degree']=G.degree() print('CHECK DEGREE 7') print(max(G.vs['degree'])) #1. If effective Diameter exists it is assigned as diameter if 'effDiam' in G.es.attribute_names(): diamEff=G.es(effDiam_ne=None).indices print('effective diameter available') print(len(diamEff)) for i in diamEff: G.es[i]['diameter']=G.es[i]['effDiam'] #2. check if there are degree 0 vertices G.vs['degree']=G.degree() deg0=G.vs(degree_eq=0).indices print('Degree 0 vertices?') print(len(deg0)) G.delete_vertices(deg0) G.vs['degree']=G.degree() #Reassign av and vv and apv and vpv G['av']=G.vs(av_eq=1).indices G['vv']=G.vs(vv_eq=1).indices G['apv']=G.vs(apv_eq=1).indices G['vpv']=G.vs(vpv_eq=1).indices #Eliminate small diameters in capGrid diam0capGrid=G.es(diameter_lt=1.0,capGrid_eq=1.).indices G.es[diam0capGrid]['diameter']=[1]*len(diam0capGrid) #Recheck smalles diameter diam0=G.es(diameter_lt=1.0).indices if len(diam0) > 0: print('ERROR no small diameters should exist') #Recheck for loops at deadEnd vertices print('check for loops') G.es['length2'] = [np.linalg.norm(G.vs[e.source]['r'] -G.vs[e.target]['r']) for e in G.es] len0=G.es(length2_eq=0).indices print('Len0 Edges are deleted') print(len(len0)) G['infoDeadEndLoops']=len(len0) for i in len0: e=G.es[i] if e.tuple[0] != e.tuple[1]: print('WARNING') G.delete_edges(len0) G.vs['degree']=G.degree() del(G.es['length2']) #Delete new deg1s print('Deleting the loops can lead to more degree 1 vertices') G.vs['degree']=G.degree() deg1=G.vs(degree_eq=1).indices print(len(deg1)) while len(deg1) > len(G['av'])+len(G['vv']): print('') print(len(deg1)) av=G.vs(av_eq=1).indices vv=G.vs(vv_eq=1).indices for i in av: if i in deg1: deg1.remove(i) print(len(deg1)) for i in vv: if i in deg1: deg1.remove(i) print(len(deg1)) G.delete_vertices(deg1) G.vs['degree']=G.degree() deg1=G.vs(degree_eq=1).indices stdout.flush() print('All newly created Dead Ends have ben elimanted') G.vs['degree']=G.degree() print(len(G.vs(degree_eq=1))) #Recheck the degrees of the graph G.vs['degree']=G.degree() deg1=G.vs(degree_eq=1).indices print('Degree 1 vertices') print(len(deg1)) for i in deg1: if i not in G['av'] and i not in G['vv']: print('ERROR deg1 vertex not in av and neither in vv') #Recheck max and min degree print('min degree') print(min(G.degree())) if min(G.degree()) < 1: print('ERROR in min degree') if np.max(G.vs['degree']) > 4: print('ERROR in Maximum degree') print(np.max(G.vs['degree'])) #Reassign av and vv and apv and vpv G['av']=G.vs(av_eq=1).indices G['vv']=G.vs(vv_eq=1).indices G['apv']=G.vs(apv_eq=1).indices G['vpv']=G.vs(vpv_eq=1).indices # 6. Diameter Srxtm vessels is adjusted such, that at least one RBC fits in # every vessel if 'isSrxtm' in G.es.attribute_names(): P=vgm.Physiology() vrbc=P.rbc_volume('mouse') G.es['minDist'] = [vrbc / (np.pi * e['diameter']**2 / 4) for e in G.es] maxMinDist=max(G.es['minDist']) countDiamChanged=0 diamNew=[] edge=[] probEdges=G.es(length_lt=1*maxMinDist,isSrxtm_eq=1).indices count=0 for i in probEdges: if 1*G.es['minDist'][i] > G.es['length'][i]: G.es[i]['diameter']=np.ceil(100*np.sqrt(4*2*vrbc/(np.pi*G.es['length'][i])))/100. countDiamChanged += 1 diamNew.append(np.ceil(100*np.sqrt(4*2*vrbc/(np.pi*G.es['length'][i])))/100.) edge.append(i) count += 1 print('vessel volume has been increased in') print(countDiamChanged) G.es['minDist'] = [vrbc / (np.pi * e['diameter']**2 / 4) for e in G.es] stdout.flush() # 7. Length is added to edges which do not have a length yet noLength=G.es(length_eq=None).indices print('Edges with no length') print(len(noLength)) for i in noLength: e=G.es[i] G.es[i]['length']=np.linalg.norm(G.vs[e.source]['r']-G.vs[e.target]['r']) noLength=G.es(length_eq=None).indices print('Edges with no length') print(len(noLength)) # 3. Assign pressure BCs print('Assign pressure BCs') for i in G['av']: G.vs[i]['pBC']=BC[0] print(G.vs[i]['pBC']) for i in G['vv']: G.vs[i]['pBC']=BC[1] print(G.vs[i]['pBC']) print('Pressure BCs assigned') # 4. Assign tube hematocrit boundary conditions print('assign inlet tube hematocrits') for i in G['av']: G.es[G.adjacent(i)[0]]['httBC']=BC[2] #Recheck BCs (pBC,rBC, httBC) for i in G['av']: print('') print(G.vs['pBC'][i]) print(G.vs['rBC'][i]) print(G.es[G.adjacent(i)]['httBC']) if G.vs['pBC'][i] == None and G.vs['rBC'][i] == None: print('ERROR in av boundary condition') if G.es[G.adjacent(i)]['httBC'] == None: print('ERROR in av boundary condition: httBC') for i in G['vv']: print('') print(G.vs['pBC'][i]) print(G.vs['rBC'][i]) if G.vs['pBC'][i] == None and G.vs['rBC'][i] == None: print('ERROR in vv boundary condition') stdout.flush() vgm.write_pkl(G, 'stage5.pkl') stdout.flush() return G
def prepare_for_concatenating_the_compound_NW(Ga,Gd): """ 1. The edge attribute 'eBlock' labels all non-capillary vessels. Hence, all vessels with eBlock=1 should be either arterioles (medianLabelAV=3) or venules (medianLabelAV=4). The medianLabelAV label is adjusted based on neighboring edges. 2. There might also be As and Vs which do not have an eBlock Label. Their medianLabelAV will be changed to 1 (=capillaries) INPUT: G: Vascular graph in iGraph format. OUTPUT: updatedProperties eBlock and medianLabelAV """ #1.Shift the realistic network, such that the centers of the NW overlap #2.Delete all capillaries of the artificial network which are found in the implantation region #3. xMinCut=Gd['xMinCut'] xMaxCut=Gd['xMaxCut'] yMinCut=Gd['yMinCut'] yMaxCut=Gd['yMaxCut'] zMaxCut=Gd['zMaxCut'] centerGd=Gd['center'] print('shift realistic network by') origin = np.mean(Ga.vs['r'], axis=0)[:2] shift = (np.append(origin,0.)-np.append(centerGd,Gd['zMeanPial'])).tolist() print(shift) vgm.shift(Gd, shift) Ga.vs['z'] = [r[2] for r in Ga.vs['r']] Ga.vs['x'] = [r[0] for r in Ga.vs['r']] Ga.vs['y'] = [r[1] for r in Ga.vs['r']] xMinCutGa=xMinCut + shift[0] xMaxCutGa=xMaxCut + shift[0] yMinCutGa=yMinCut + shift[1] yMaxCutGa=yMaxCut + shift[1] zMaxCutGa=zMaxCut + shift[2] centerGa=[centerGd[0]+shift[0],centerGd[1]+shift[1]] Ga['xMinCut']=xMinCutGa Ga['xMaxCut']=xMaxCutGa Ga['yMinCut']=yMinCutGa Ga['yMaxCut']=yMaxCutGa Ga['zMaxCut']=zMaxCutGa Ga['center']=centerGa #First all capillary vertices lying in the center of ther artificial network ar deleted delVerts=Ga.vs(x_gt=xMinCutGa,x_lt=xMaxCutGa,y_gt=yMinCutGa,y_lt=yMaxCutGa,z_lt=zMaxCutGa,nkind_eq=4).indices Ga.delete_vertices(delVerts) #Now all artificial penetrating trees and artificial venules are deleted if their root point is lying #in the area of the implantation including points of the penetrting trees #lying outside the implantation regio #Arteriol roots delVertsPA=Ga.vs(x_gt=xMinCutGa,x_lt=xMaxCutGa,y_gt=yMinCutGa,y_lt=yMaxCutGa,z_lt=zMaxCutGa,av_eq=1).indices delVertsWholeTree=[] doneVerts=[] for i in delVertsPA: treeVertices2=[i] while treeVertices2 != []: treeVertices=[] for j in treeVertices2: neighbors=Ga.neighbors(j) for k in neighbors: if Ga.vs[k]['nkind'] == 2 and k not in doneVerts: treeVertices.append(k) delVertsWholeTree.append(k) doneVerts.append(j) treeVertices2=deepcopy(treeVertices) delVertsWholeTree.append(i) #Venule roots delVertsPA=Ga.vs(x_gt=xMinCutGa,x_lt=xMaxCutGa,y_gt=yMinCutGa,y_lt=yMaxCutGa,z_lt=zMaxCutGa,vv_eq=1).indices delVertsWholeTree=[] doneVerts=[] for i in delVertsPA: treeVertices2=[i] while treeVertices2 != []: treeVertices=[] for j in treeVertices2: neighbors=Ga.neighbors(j) for k in neighbors: if Ga.vs[k]['nkind'] == 3 and k not in doneVerts: treeVertices.append(k) delVertsWholeTree.append(k) doneVerts.append(j) treeVertices2=deepcopy(treeVertices) delVertsWholeTree.append(i) #Eliminate remaining a and v vessels at implant location delVertsPA=Ga.vs(x_gt=xMinCutGa,x_lt=xMaxCutGa,y_gt=yMinCutGa,y_lt=yMaxCutGa,z_lt=zMaxCutGa,nkind_eq=2).indices Ga.delete_vertices(delVertsPA) delVertsPV=Ga.vs(x_gt=xMinCutGa,x_lt=xMaxCutGa,y_gt=yMinCutGa,y_lt=yMaxCutGa,z_lt=zMaxCutGa,nkind_eq=3).indices Ga.delete_vertices(delVertsPV) #delete unconnected components while (len(Ga.components())) > 1: delVerts=Ga.components()[len(Ga.components())-1] Ga.delete_vertices(delVerts) return Ga,Gd
def implant_srxtm(Ga, Gd, origin=None, crWidth=150): """Implants a cylindrical srXTM sample in an artificial vascular network consisting of pial vessels, arterioles, venoles and capillaries. At the site of insertion, artificial vessels are removed to make space for the srXTM sample. At the border between artificial and data networks, connections are made between the respective loose ends. INPUT: Ga: VascularGraph of the artificial vasculature. Gd: VascularGraph of the srXTM data. The graph is expected to have the attributes 'av' and 'vv' that denote the indices of endpoints of the large penetrating arteries and veins respectively. origin: The two-dimensional origin in the xy plane, where the srXTM sample should be inserted. This will be the network's center of mass, if not provided. crWidth: Width of connection region. After computing the center and radius of the SRXTM sample, loose ends of the SRXTM at radius - 2*crWidth are connected to loose ends of the artificial network at radius + 2*crWidth. OUTPUT: Ga: Modified input Ga, with Gd inserted at origin. """ # Create Physiology object with appropriate default units: P = vgm.Physiology(Ga['defaultUnits']) eps = finfo(float).eps * 1e4 # Define exceptions: class ShapeException(Exception): def __init__(self): return def __str__(self): return 'The shape of the srXTM sample must be cylindrical!' # Assert that the srXTM sample is cylindrical: if Gd.shape() != 'cylinder': raise ShapeException # Compute the network's center of mass as origin, if origin is not provided: if origin is None: origin = np.mean(Ga.vs['r'], axis=0)[:2] print('origin') print(origin) print('Original number of components') print(len(Ga.components())) stdout.flush() print('Kind Check') print(np.unique(Ga.vs['kind'])) # Remove all vertices of Ga which are within Gd's radius of 'origin' and # at a depth less than the maximum depth of Gd. Leave the pial vessels # of Ga untouched: Ga.vs['distanceFromOrigin'] = [np.linalg.norm(r[:2] - origin) for r in Ga.vs['r']] Ga.vs['isPial'] = [0 if k not in ['pa', 'pv'] else 1 for k in Ga.vs['kind']] Ga.vs['z'] = [r[2] for r in Ga.vs['r']] radius, center = Gd.radius_and_center() area, length = Gd.cross_sectional_area_and_length(shape='cylinder') Ga.delete_vertices(Ga.vs(distanceFromOrigin_le=radius, z_le=length, isPial_eq=0)) print('Kind Check 1 1') print(np.unique(Ga.vs['kind'])) print('Center deleted') # Remove all non-capillaries that have lost their root: Ga.vs['degree'] = Ga.degree() #pial endpoints are located at the pial level in the area, where the realistic network is implanted pialEndpoints = [v.index for v in Ga.vs(degree_eq=1) if v['kind'] in ['pa', 'pv']] if len(pialEndpoints) > 0: print('pialEndpoints') print(pialEndpoints) print(len(pialEndpoints)) Gc = copy.deepcopy(Ga) Gc.vs['index'] = xrange(Gc.vcount()) del(Gc.vs['degree']) del(Gc.vs['distanceFromOrigin']) del(Gc.vs['nkind']) del(Gc.vs['pBC']) del(Gc.vs['z']) del(Gc.vs['isPial']) del(Gc.es['diameter']) del(Gc.es['diameter_orig']) del(Gc.es['diameters']) del(Gc.es['lengths']) del(Gc.es['diameter_change']) del(Gc.es['conductance']) del(Gc.es['length']) del(Gc.es['cost']) del(Gc.es['points']) #Gc consists of pial vessels and penetrating trees Gc.delete_vertices(Gc.vs(kind_eq='c').indices) print('Capillaries deleted') print('Number of components') print(len(Gc.components())) del(Gc.vs['kind']) #add random vertex Gc.add_vertices(1) Gc.vs[Gc.vcount()-1]['index']=100000000000000 Gc.vs[Gc.vcount()-1]['r']=[-500.,-500.,0.] pialEndpoints2 = [] #pialEndpoints2 = pialEndpoints in Gc graph for i in pialEndpoints: pialEndpoints2.append(Gc.vs(index_eq=i).indices[0]) #connect all pial endpoints (=in and outflows at pial level and deg1 pial vertices resulting from hole at implant position) to that random vertices Gc.add_edges([(v, Gc.vcount()-1) for v in pialEndpoints2]) print('Number of components 2 --> unconnected penetrating trees') print(len(Gc.components())) #deletes connected component print('Kind Check 1 2') print(np.unique(Ga.vs['kind'])) Gc.delete_vertices(Gc.subcomponent(Gc.vcount()-1)) Ga.delete_vertices(Gc.vs['index']) #unconnected capillaries still present, but no more unconnected penetrating trees else: print('Reduce components') print(len(Ga.components())) while len(Ga.components()) > 1: delVertices=Ga.components()[len(Ga.components())-1] print(len(delVertices)) Ga.delete_vertices(Ga.components()[len(Ga.components())-1]) print('number of components') print(len(Ga.components())) print('Kind Check 1 3') print(np.unique(Ga.vs['kind'])) #Delete unconnected capillaries print('Number of components 3') print(len(Ga.components())) components=Ga.components() delVertices=[] stdout.flush() for i in range(1,len(components)): delVertices = delVertices + components[i] if len(delVertices) > len(components[0]): print('ERROR --> main component deleted') Ga.delete_vertices(delVertices) print('Number of components 4') print(len(Ga.components())) # Insert Gd into Ga (insert realistic network into artificial network): print('CHECK DEGREE SRXTM') print(max(Gd.degree())) origin = np.append(origin, 0.) center = np.append(center, min([r[2] for r in Gd.vs['r']])) shift = (origin-center).tolist() print('shift realistic networ by') print(shift) vgm.shift(Gd, shift) print('Components gXTM') print(len(Gd.components())) print('Components trees and capillaries') print(len(Ga.components())) initialVcount = Ga.vcount() initialEcount = Ga.ecount() Ga.union_attribute_preserving(Gd) print('Put together') print(len(Ga.components())) Ga.vs['isSrxtm'] = [0 if x < initialVcount else 1 for x in xrange(Ga.vcount())] # artificial network: 0, srXTM: 1 Ga.es['isSrxtm'] = [0 if x < initialEcount else 1 for x in xrange(Ga.ecount())] # artificial network: 0, srXTM: 1 stdout.flush() # Connect loose ends of Gd (srXTM to artificial capillary bed): # only dead ends in a given radius are connected origin = origin[:2] Ga.vs(isSrxtm_eq=1)['distanceFromOrigin'] = [np.linalg.norm(r[:2] - origin) for r in Ga.vs(isSrxtm_eq=1)['r']] #All capillary vertices which are at max 2.0*radius away from the center of the srXTM #possible capillary attachment vertices capillaryVertices = Ga.vs(isSrxtm_eq=0, distanceFromOrigin_le=radius*2.0, kind_eq='c', degree_le=3) Kdt = kdtree.KDTree(capillaryVertices['r'], leafsize=10) #all srxtm vertices in radius print('Connect Implant to capillary bed') looseEndsI = Ga.vs(distanceFromOrigin_le=radius+2*crWidth, distanceFromOrigin_ge=radius-2*crWidth, degree_eq=1, isSrxtm_eq=1).indices # srxtm capillaries and non-capillaries print('Remove av and vv of Srxtm from the looseEndsI list') print(len(looseEndsI)) for i in Gd['av']: vIndex = int(np.nonzero(np.all(Gd.vs[i]['r'] == Ga.vs['r'], axis=1))[0][0]) if vIndex in looseEndsI: looseEndsI.remove(vIndex) print(len(looseEndsI)) for i in Gd['vv']: vIndex = int(np.nonzero(np.all(Gd.vs[i]['r'] == Ga.vs['r'], axis=1))[0][0]) if vIndex in looseEndsI: looseEndsI.remove(vIndex) print(len(looseEndsI)) print('Non capillaries artificial network') looseEndsI_2=Ga.vs(distanceFromOrigin_le=radius+2*crWidth, distanceFromOrigin_ge=radius-2*crWidth, degree_eq=1, isSrxtm_eq=0, kind_ne='c').indices # artificial network non-capillaries print(len(looseEndsI_2)) dummy1=Ga.vs(distanceFromOrigin_le=radius+2*crWidth, distanceFromOrigin_ge=radius-2*crWidth, degree_eq=1, isSrxtm_eq=0, kind_eq='pa').indices dummy2=Ga.vs(distanceFromOrigin_le=radius+2*crWidth, distanceFromOrigin_ge=radius-2*crWidth, degree_eq=1, isSrxtm_eq=0, kind_eq='pv').indices print('Remove dummy1 (pa) from loosEndsI_2') print(len(looseEndsI_2)) print(len(dummy1)) print('Kind Check 3') print(np.unique(Ga.vs['kind'])) for i in dummy1: if i in looseEndsI_2: looseEndsI_2.remove(i) print(len(looseEndsI_2)) print('Remove dummy2 (pv) from loosEndsI_2') for i in dummy2: if i in looseEndsI_2: looseEndsI_2.remove(i) print(len(dummy2)) print(len(looseEndsI_2)) print('Exten looseEndsI') print(len(looseEndsI)) looseEndsI.extend(looseEndsI_2) print(len(looseEndsI)) print('Check loosEnds 2') looseEndesII=Ga.vs(distanceFromOrigin_le=radius+2*crWidth, distanceFromOrigin_ge=radius-2*crWidth, degree_eq=1, isSrxtm_eq=0, kind_ne='c').indices for i in looseEndesII: print(Ga.vs[i]['kind']) print('len(looseEndsI)') print(len(looseEndsI)) print('Degree one artificial') Ga.vs['degree']=Ga.degree() print(len(Ga.vs(isSrxtm_eq=0, distanceFromOrigin_le=radius*2.0, kind_eq='c',degree_le=3))) posConnections=[] for i in Ga.vs['degree']: if i >= 3: posConnections.append(0) elif i == 3: posConnections.append(1) elif i == 2: posConnections.append(2) else: posConnections.append(3) Ga.vs['posConnections']=posConnections posConnections=np.sum(Ga.vs[Ga.vs(isSrxtm_eq=0, distanceFromOrigin_le=radius*2.0, kind_eq='c', degree_le=3).indices]['posConnections']) print('Possible Connections') print(posConnections) looseEnds = Ga.vs(looseEndsI) newEdges = [] vertex_withSrxtm=[] stdout.flush() print('Kind Check 4') print(np.unique(Ga.vs['kind'])) for le in looseEnds: print('') print(le.index) stdout.flush() newVertexFound=0 count= 1 while newVertexFound != 1: #start with 5 possible nearest neighbors if count*5 > len(capillaryVertices): print('WARNING last chance to find a connecting vertex') print(count*5) nearestN=Kdt.query(le['r'],k=5*count) for i in range((count-1)*5,count*5): newVertex=capillaryVertices[int(nearestN[1][i])].index #newVertex=capillaryVertices[int(Kdt.query(le['r'])[1])].index if Ga.vs['posConnections'][newVertex] == 0: print('No connection possible') else: Ga.vs[newVertex]['posConnections'] = Ga.vs[newVertex]['posConnections'] - 1 newVertexFound = 1 break count += 1 print('CONNECTION FOUND') print(le.index) newEdges.append((le.index, newVertex)) vertex_withSrxtm.append(le.index) Ga.add_edges(newEdges) Ga.vs['degree']=Ga.degree() print('CHECK DEGREE 5') print(max(Ga.degree())) #TODO think of fixed diameter and fixed length diameter = 7. length = 50. conductance = P.conductance(diameter, length, P.dynamic_blood_viscosity(diameter, 'a')) Ga.es[-len(newEdges):]['diameter'] = [diameter for e in newEdges] Ga.es[-len(newEdges):]['conductance'] = [conductance for e in newEdges] Ga.es['newEdge'] = [0 if x < Ga.ecount()-len(newEdges) else 1 for x in xrange(Ga.ecount())] print('Kind Check 4') print(np.unique(Ga.vs['kind'])) # Connect endpoints of large penetrating vessels to pial vessels: #'av' - arterial inflows, 'pv' -venule outflow print('Standard Network av') print(Ga['av']) print(len(Ga['av'])) print('Standard Network vv') print(Ga['vv']) print(len(Ga['vv'])) print('Implant Network av') print(Gd['av']) print(len(Gd['av'])) print('Implant Network vv') print(Gd['vv']) print(len(Gd['av'])) print(zip((Gd['av'], Gd['vv']), ('pa', 'pv'))) Ga['vWithSRXTM']=vertex_withSrxtm posConnections=[] stdout.flush() for i in Ga.vs['degree']: if i > 2: posConnections.append(0) elif i == 2: posConnections.append(1) else: posConnections.append(2) Ga.vs['posConnections']=posConnections print(np.unique(Ga.vs['kind'])) for avv, pk in zip((Gd['av'], Gd['vv']), ('pa', 'pv')): print('CHECK') print(len(avv)) print(pk) #alle pial vessels (either arteries or venules) pialIndices = Ga.vs(kind_eq=pk).indices print(pialIndices) #KDTree of all pial vessels (either arteries or venules) of main graph Kdt = kdtree.KDTree(Ga.vs(pialIndices)['r'], leafsize=10) newEdges = [] length = [] diameter = [] conductance = [] srxtmAV = [] vs=[] degree0=[] for v in avv: #to find the vertex number in the new graph vIndex = int(np.nonzero(np.all(Gd.vs[v]['r'] == Ga.vs['r'], axis=1))[0][0]) #corresponding vertexNumber of Inflow/Outflow vertices of srxtm srxtmAV.append(vIndex) degree0.append(Ga.vs[vIndex]['degree']) vs.append(v) #Closes vertex of pial vertices newVertexFound = 0 count = 1 while newVertexFound != 1: #pIndex = pialIndices[int(Kdt.query(Ga.vs[vIndex]['r'])[1])] nearestN = Kdt.query(Ga.vs[vIndex]['r'],k=5*count) for i in range((count-1)*5,count*5): pIndex=pialIndices[int(nearestN[1][i])] if Ga.vs['posConnections'][pIndex] == 0 or pIndex in vertex_withSrxtm: print('No connection possible') else: print('posConnections') print(Ga.vs['posConnections'][pIndex]) Ga.vs[pIndex]['posConnections'] = Ga.vs[pIndex]['posConnections'] - 1 newVertexFound = 1 print(Ga.vs['posConnections'][pIndex]) break count += 1 print('CONNECTION FOUND') print(v) newEdges.append((vIndex, pIndex)) length.append(np.linalg.norm(Ga.vs[vIndex]['r'] - Ga.vs[pIndex]['r'])) #diameter is set to the maximum diameter of the adjacent edges of the pial vertex diameter.append(max(Ga.es[Ga.adjacent(pIndex)]['diameter'])) conductance.append(P.conductance(diameter[-1], length[-1], P.dynamic_blood_viscosity(diameter[-1], pk[1]))) #inflow/outflow vertices of srxtm Ga['srxtm_' + pk[1]] = srxtmAV Ga.add_edges(newEdges) Ga.vs['degree']=Ga.degree() Ga.es[-len(newEdges):]['diameter'] = diameter Ga.es[-len(newEdges):]['conductance'] = conductance #newly introduced edges a/v Ga.es['newEdge_'+pk] = [0 if x < Ga.ecount()-len(newEdges) else 1 for x in xrange(Ga.ecount())] noneEdges=Ga.es(newEdge_pa_eq=None).indices Ga.es[noneEdges]['newEdge_pa']=[0]*len(noneEdges) Ga.vs['srxtm_a']=[0]*Ga.vcount() Ga.vs['srxtm_v']=[0]*Ga.vcount() for i in Ga['srxtm_a']: Ga.vs[i]['srxtm_a']=1 for i in Ga['srxtm_v']: Ga.vs[i]['srxtm_v']=1 del(Ga['srxtm_a']) del(Ga['srxtm_v']) Ga.vs['degree']=Ga.degree() print('CHECK DEGREE 6') print(max(Ga.degree())) # Remove Dead Ends # Dead Ends around the implant print('Delete dead ends around implant') deg1=Ga.vs(degree_eq=1,distanceFromOrigin_gt=radius+2*crWidth,distanceFromOrigin_lt=radius-2*crWidth,isSrxtm_eq=1).indices for i in deg1: if Ga.vs[i]['av'] == 1.0: deg1.remove(i) elif Ga.vs[i]['vv'] == 1.0: deg1.remove(i) print('avs and vvs') print(len(Ga.vs(av_eq=1))) print(len(Ga.vs(vv_eq=1))) while len(deg1) > 0: print('') print(len(deg1)) Ga.delete_vertices(deg1) Ga.vs['degree']=Ga.degree() print('avs and vvs') print(len(Ga.vs(av_eq=1))) print(len(Ga.vs(vv_eq=1))) deg1=Ga.vs(degree_eq=1,distanceFromOrigin_gt=radius+2*crWidth,distanceFromOrigin_lt=radius-2*crWidth,isSrxtm_eq=1).indices for i in deg1: if Ga.vs[i]['av'] == 1.0: deg1.remove(i) elif Ga.vs[i]['vv'] == 1.0: deg1.remove(i) # Delete obsolete vertex properties: del Ga.vs['degree'] stdout.flush() #Delte av and vv of SRXTM av=Ga.vs(av_eq=1).indices print('len av') print(len(av)) for i in av: if Ga.vs['isSrxtm'][i]: Ga.vs[i]['av']=0 av=Ga.vs(av_eq=1).indices print('len av') print(len(av)) Ga['av']=av vv=Ga.vs(vv_eq=1).indices print('len vv') print(len(vv)) for i in vv: if Ga.vs['isSrxtm'][i]: Ga.vs[i]['vv']=0 vv=Ga.vs(vv_eq=1).indices print('len vv') print(len(vv)) Ga['vv']=vv #There might be deadEnd Vertices of the artificial capillary bed where the SRXTM was implemented #Those vertices are delted #First assign capGrid = 0 to SRXTM capGridNone=Ga.vs(capGrid_eq=None).indices Ga.vs[capGridNone]['capGrid']=[0]*len(capGridNone) Ga.vs['degree'] = Ga.degree() print('Check if deg1 are only located at in- and outlet and at borders of capillary grid') deg1=Ga.vs(degree_eq=1).indices print(len(deg1)) for i in deg1: if Ga.vs[i]['capGrid'] == 0: if Ga.vs['av'] == 0 and Ga.vs['vv'] == 0: print('ERROR') print(i) print(Ga.vs[i]['isSrxtm']) print(Ga.vs[i]['capGrid']) while len(deg1) > len(Ga['av'])+len(Ga['vv']): print('') print(len(deg1)) av=Ga.vs(av_eq=1).indices vv=Ga.vs(vv_eq=1).indices for i in av: if i in deg1: deg1.remove(i) print(len(deg1)) for i in vv: if i in deg1: deg1.remove(i) print(len(deg1)) Ga.delete_vertices(deg1) Ga.vs['degree']=Ga.degree() deg1=Ga.vs(degree_eq=1).indices del Ga.vs['distanceFromOrigin'] print('All newly created Dead Ends have ben elimanted') Ga.vs['degree']=Ga.degree() Ga['av']=Ga.vs(av_eq=1).indices Ga['vv']=Ga.vs(vv_eq=1).indices print(len(Ga.vs(degree_eq=1))) print(len(Ga['av'])) print(len(Ga['vv'])) stdout.flush() return Ga