def honeycomb_2d(sideLength=10, size=20): """Creates a 2D honeycomb capillary network. INPUT: sideLength: The side length of a hexagon of the honeycomb network. size: The size of the network as multiples of hexagons OUTPUT: Honeycomb network as VascularGraph """ ff = np.cos(np.deg2rad(30.)) G = honeycomb((0, size*2*ff*sideLength), (0, size*2*ff*sideLength), (0,0), sideLength) maxima = np.max(G.vs['r'], axis=0) G.delete_vertices([v.index for v in G.vs if v['r'][1] == maxima[1]]) minima = np.min(G.vs['r'], axis=0) maxima = np.max(G.vs['r'], axis=0) blacklist = [v.index for v in G.vs if np.allclose(v['r'][1], minima[1])] blacklist.extend([v.index for v in G.vs if np.allclose(v['r'][1], maxima[1])]) tmplist = sorted([(v['r'][1], v.index) for v in G.vs if np.allclose(v['r'][0], minima[0])]) tmplist = [x[1] for x in tmplist] blacklist.extend(np.setdiff1d(tmplist, tmplist[2::3]).tolist()) tmplist = sorted([(v['r'][1], v.index) for v in G.vs if np.allclose(v['r'][0], maxima[0])]) tmplist = [x[1] for x in tmplist] blacklist.extend(np.setdiff1d(tmplist, tmplist[2::3]).tolist()) G.delete_order_two_vertices(blacklist=blacklist) vgm.write_vtp(G, 'G1.vtp', False) return G
def solve(self, method, **kwargs): """Solves the linear system A x = b for the vector of unknown pressures x, either using a direct solver or an iterative AMG solver. From the pressures, the flow field is computed. INPUT: method: This can be either 'direct' or 'iterative' **kwargs precision: The accuracy to which the ls is to be solved. If not supplied, machine accuracy will be used. maxiter: The maximum number of iterations. The default value for the iterative solver is 250. OUTPUT: None - G is modified in place. """ b = self._b G = self._G htt2htd = self._P.tube_to_discharge_hematocrit A = self._A.tocsr() if method == 'direct': linalg.use_solver(useUmfpack=True) x = linalg.spsolve(A, b) elif method == 'iterative': if kwargs.has_key('precision'): eps = kwargs['precision'] else: eps = self._eps if kwargs.has_key('maxiter'): maxiter = kwargs['maxiter'] else: maxiter = 250 AA = pyamg.smoothed_aggregation_solver(A, max_levels=10, max_coarse=500) x = abs(AA.solve(self._b, x0=None, tol=eps, accel='cg', cycle='V', maxiter=maxiter)) # abs required, as (small) negative pressures may arise elif method == 'iterative2': # Set linear solver ml = rootnode_solver(A, smooth=('energy', {'degree':2}), strength='evolution' ) M = ml.aspreconditioner(cycle='V') # Solve pressure system x,info = gmres(A, self._b, tol=self._eps, maxiter=50, M=M) if info != 0: print('ERROR in Solving the Matrix') G.vs['pressure'] = x self._x = x conductance = self._conductance G.es['flow'] = [abs(G.vs[edge.source]['pressure'] - \ G.vs[edge.target]['pressure']) * \ conductance[i] for i, edge in enumerate(G.es)] for v in G.vs: v['pressure']=v['pressure']/vgm.units.scaling_factor_du('mmHg',G['defaultUnits']) if self._withRBC: for e in G.es: dischargeHt = min(htt2htd(e['htt'], e['diameter'], self._invivo), 1.0) e['v']=dischargeHt/e['htt']*e['flow']/(0.25*np.pi*e['diameter']**2) else: for e in G.es: e['v']=e['flow']/(0.25*np.pi*e['diameter']**2) #Convert 'pBC' from default Units to mmHg pBCneNone=G.vs(pBC_ne=None).indices if 'diamCalcEff' in G.es.attribute_names(): del(G.es['diamCalcEff']) if 'effResistance' in G.es.attribute_names(): del(G.es['effResistance']) if 'conductance' in G.es.attribute_names(): del(G.es['conductance']) if 'resistance' in G.es.attribute_names(): del(G.es['resistance']) G.vs[pBCneNone]['pBC']=np.array(G.vs[pBCneNone]['pBC'])*(1/vgm.units.scaling_factor_du('mmHg',G['defaultUnits'])) vgm.write_pkl(G, 'G_final.pkl') vgm.write_vtp(G, 'G_final.vtp',False) #Write Output sampledict={} for eprop in ['flow', 'v']: if not eprop in sampledict.keys(): sampledict[eprop] = [] sampledict[eprop].append(G.es[eprop]) for vprop in ['pressure']: if not vprop in sampledict.keys(): sampledict[vprop] = [] sampledict[vprop].append(G.vs[vprop]) g_output.write_pkl(sampledict, 'sampledict.pkl')
if case == 1: r.append(np.array([x[0], coord1, coord2])) elif case == 2: r.append(np.array([coord1, y[0], coord2])) elif case == 3: r.append(np.array([coord1, coord2, z[0]])) valuesGridList = [] for j in valuesGrid: for k in j: valuesGridList.append(k) planeG = vgm.VascularGraph(len(r)) planeG.vs['r'] = r planeG.vs[attribute] = valuesGridList vgm.write_vtp(planeG, filename + '.vtp', False) vgm.write_pkl(planeG, filename + '.pkl') return grid_d1, grid_d2, valuesGrid, case #------------------------------------------------------------------------------ def make_axis_labels(minVal, maxVal, factor=1, considerLimits=1): """ Creates the labels for an axis. based on the min and max value provided. INPUT: minVal: minimum Value of the data maxVal: maximum Value of the date factor: factor between the actual values and the strings provided (e.g factor = 0.001 --> value 1000 --> string '1.0') considerLimits: bool if the labels should be trimmed at the lower/upper bound OUTPUT: labels,labelsString: list with the location of the labels and the according strings limits: lower and upper limit for the axis
def transient_dilation(G='G_standard',edges=[240, 243, 246, 249], fdilation=[1.1, 1.1, 0.9, 0.9], ttotal=900,ht0=0.4, ttransient=[400, 100, 10], plotstep=2, samplestep=2,**kwargs): """Load VascularGraph from disk. Run RBC-transport simulation, where a vessel is dilated at some point during the simulation. The dilation occurs in several steps. Note that there are some hard-coded variables which need to be adjusted if use-case changes! INPUT: G: Input Graph as pkl-file (name without the ending .pkl) edges: List of edges to dilate fdilation: List of dilation-factors ttotal: total time ht0: initial tube hematocrit value throughout the VascularGraph ttransient: [tinitial, tduration, steps]= [start of the dilation, time period till dilation is finished, number of steps for dilation] plotstep: timestep for plotting samplestep: timestep for sampling **kwargs: httBC: tube hematocrit boundary condition at inflow bigger: 0 = 2 Vessel network, 1= 2in2 Vessel network 2=Honeycomb wholeBr: Boolean whether the whole Branch is dilated (TRUE) or only center of the Branch is dilated (FALSE) OUTPUT: None, pre- and post-dilation VascularGraph, sample-dictionary, and RBC-plots are written to disk. """ filename=G+'.pkl' G = vgm.read_pkl(filename) if kwargs.has_key('httBC'): for vi in G['av']: for ei in G.adjacent(vi): G.es[ei]['httBC']=kwargs['httBC'] if kwargs.has_key('bigger'): NW=kwargs['bigger'] else: NW=0 if kwargs.has_key('wholeBr'): wholeBr=kwargs['wholeBr'] else: wholeBr=False G.add_points(1.) dilatedList=[] G.es['dfactor'] = [None for e in G.es] G.es[edges]['dfactor'] = 1.0 if wholeBr: dilatedList=edges else: while len(G.es(dfactor_ne=None)) > 0: eindex = G.es(dfactor_ne=None).indices[0] dfactor = G.es[eindex]['dfactor'] vi, ei, dilated_ei = G.central_dilation(eindex, dfactor, 4/5.) G.es[ei]['dfactor'] = [None for e in ei] dilatedList.append(dilated_ei) for i in range(len(dilatedList)): dilatedList[i]=dilatedList[i]-(len(dilatedList)-i-1) Gd = copy.deepcopy(G) LSd = vgm.LinearSystemHtdWCyth(Gd, dThreshold=10.0, ht0=ht0) #Run simulation without dilation till tinitial is reached LSd.evolve(time=ttransient[0], method='direct', plotPrms=[0, ttransient[0], plotstep], samplePrms=[0, ttransient[0], samplestep]) #LSd._plot_sample_average('G_pre_dilation.vtp') #vgm.write_pkl(Gd, 'G_pre_dilation.pkl') tstep = ttransient[1] / ttransient[2] Gd.es['dfactor'] = [None for e in G.es] Gd.es[dilatedList]['dfactor'] = fdilation fsteps = [Gd.es[edge]['diameter'] * (fdil - 1) / ttransient[2] for edge, fdil in zip(dilatedList, fdilation)] for step in xrange(ttransient[2]): for edge, fstep in zip(dilatedList, fsteps): Gd.es[edge]['diameter'] += fstep stdout.write("\rEdge = %g \n" %edge) stdout.write("\rDiameter = %f \n" %Gd.es[edge]['diameter']) #START: Consider Change of minDist during dilation of vessel LSd._update_minDist_and_nMax(esequence=dilatedList) LSd._update_tube_hematocrit(esequence=dilatedList) #END: Consider Change of minDist during dilation of vessel LSd._update_nominal_and_specific_resistance(esequence=dilatedList) LSd._update_eff_resistance_and_LS() LSd.evolve(time=tstep, method='direct', plotPrms=(0.0, tstep, plotstep), samplePrms=(0.0, tstep, samplestep),init=False) filename2='G_transient_dilation_'+str(step)+'.vtp' LSd._plot_sample_average(filename2) vgm.write_pkl(Gd, 'G_transient_dilation_'+str(step)+'.pkl') stdout.write("\rDilation Step = %g \n" %step) #stdout.write("\rDiameter = %f \n" %Gd.es[342]['diameter']) tstep = ttotal - ttransient[0] - ttransient[1] LSd.evolve(time=tstep, method='direct', plotPrms=(0.0, tstep, plotstep), samplePrms=(0.0, tstep, samplestep),init=False) vgm.write_pkl(Gd, 'G_post_dilation.pkl') vgm.write_vtp(Gd, 'G_post_dilation.vtp', False)
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 construct_pial_network(sf=5, epperc=15, epmode='distributed'): """Builds a VascularGraph representing the pial network. INPUT: 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 either chosen randomly or such, that the penetrating vessels are distributed as homogeneously as possible. epmode: Mode by which en-passent vessels are chosen. This can be either 'random' or 'distributed' OUTPUT: G: VascularGraph. Note that this function is specifically tuned to the csv files and would need to change if the csv files change. Moreover, it relies on input from control.py """ # Get settings from control file: basedir = control.basedir pialDB = control.pialDB av = control.av vv = control.vv # Read csv files and scale from mm to micron: G = vgm.read_csv(os.path.join(pialDB, 'vertices.csv'), os.path.join(pialDB, 'edges.csv')) del G.vs['nkind'] G.vs['r'] = [r * sf for r in G.vs['r']] G.es['diameter'] = [d * sf for d in G.es['diameter']] G.es['length'] = [np.linalg.norm(G.vs[e.source]['r'] - G.vs[e.target]['r']) for e in G.es] G.vs['isAv'] = [0] * G.vcount() G.vs['isVv'] = [0] * G.vcount() # add 'av' and 'vv' from control dict G.vs(av)['isAv'] = [1] * len(av) G.vs(vv)['isVv'] = [1] * len(vv) G.delete_selfloops() G.add_points(100) G.delete_order_two_vertices() minnp = 3 if epmode == 'distributed': # Find arterial and venous components: #Find clusters = group of connected nodes co = G.components(mode='weak') #all vertices belonging to arterlial network and venous network, respectively aComponent = [] vComponent = [] for c in co: #everything which is not in av => vComponent if any(map(lambda x: x in c, av)): aComponent.extend(c) else: vComponent.extend(c) G.vs['degree'] = G.degree() G.es['nPoints'] = [len(x) for x in G.es['points']] G.es['midpoint'] = [np.mean(G.vs[e.tuple]['r'], axis=0) for e in G.es] epVertices = [] for component, avvv in zip((aComponent, vComponent), (av, vv)): #All edges belong to the component edges = G.get_vertex_edges(G.vs(component).indices, 'all', True) #edges where nPoints >= minnp edges = G.es(edges, nPoints_ge=minnp).indices #vertices of the component with only one adjacent edge dovertices = G.vs(component, degree_eq=1).indices # Compute number of en-passent offshoots: nep = int(epperc / (100 - epperc) * (len(dovertices) - len(avvv))) rlist = G.vs(dovertices)['r'] epEdges = [] for i in xrange(nep): Kdt = kdtree.KDTree(rlist, leafsize=10) distances = [(Kdt.query(G.es[e]['midpoint'])[0], e) for e in edges] #edge which is farest away epEdge = sorted(distances, reverse=True)[0][1] edges.remove(epEdge) epEdges.append(epEdge) rlist.append(G.es[epEdge]['midpoint']) newVertices = range(G.vcount(), G.vcount()+len(epEdges)) component.extend(newVertices) epVertices.extend(newVertices) for edge in epEdges: G.split_edge(edge, int(G.es[edge]['nPoints']/2.), False) G.delete_edges(epEdges) #Prevent new vertices from belonging to in and outlet vertices G.vs(newVertices)['isVv']=[0]*len(newVertices) G.vs(newVertices)['isAv']=[0]*len(newVertices) del G.es['midpoint'] elif epmode == 'random': # Compute number of en-passent offshoots: nep = epperc / (1 - epperc) * \ (len(np.nonzero(np.array(G.degree()) == 1)[0]) - len(av) - len(vv)) G.es['nPoints'] = [len(x) for x in G.es['points']] epEdges = np.random.permutation(G.es(nPoints_gt=minnp).indices)[:nep].tolist() epVertices = range(G.vcount(), G.vcount()+len(epEdges)) for edge in epEdges: G.split_edge(edge, int(G.es[edge]['nPoints']/2.), False) G.delete_edges(epEdges) # Find arterial and venous components: co = G.components(mode='weak') aComponent = [] vComponent = [] for c in co: if any(map(lambda x: x in c, av)): aComponent.extend(c) else: vComponent.extend(c) G['av'] = G.vs(isAv_eq=1).indices G['vv'] = G.vs(isVv_eq=1).indices del G.vs['isAv'] del G.vs['isVv'] del G.es['nPoints'] #all penetrating vessels pv = G.vs(_degree_eq=1).indices #if in or outflow -> remove from penetrating vessels for prop in ['av', 'vv']: for x in G[prop]: try: pv.remove(x) except: pass #add en passent penetrating vessels pv.extend(epVertices) G.vs['degree']=G.degree() remove=[] for i in pv: if G.vs['degree'][i] > 2: remove.append(i) print('Need to be removed') print(remove) for i in remove: pv.remove(i) #List of penetratiting arteries (apv) and venules (vpv) G['apv'] = [v for v in pv if v in aComponent] G['vpv'] = [v for v in pv if v not in aComponent] G.vs['degree'] = G.degree() #vertex characteristic pial arterty or pial venule G.vs[aComponent]['kind'] = ['pa' for v in aComponent] G.vs[vComponent]['kind'] = ['pv' for v in vComponent] G.vs['nkind'] = [0] * G.vcount() #0 = pial artery, 1 = pial venule, 2 = en passent penetrating G.vs[aComponent]['nkind'] = [0 for v in aComponent] G.vs[vComponent]['nkind'] = [1 for v in vComponent] G.vs[epVertices]['nkind'] = [2 for v in epVertices] # Set in- and outflow pressure boundary conditions. # Arterial pressure 60 mmHg, venous pressure 10 mmHg, according to a # Hypertesion paper by Harper and Bohlen 1984. G.vs[G['av'][0]]['pBC'] = 60 * vgm.scaling_factor_du('mmHg', G['defaultUnits']) for v in G['vv']: G.vs[v]['pBC'] = 10 * vgm.scaling_factor_du('mmHg', G['defaultUnits']) vgm.write_pkl(G,'pial.pkl') vgm.write_vtp(G,'pial.vtp',False) return G
def planePlots_paraview(G,edges,intersectionCoords,attribute,filename,interpMethod='linear',gridpoints=100): """ Interpolates values on a grid based on the intersection of edges with a plane. It outputs a .vtp and a .pkl file to be read into paraview. It returns the grid and the interpolated values at those locations (those can be processed to produce a contour plot in matplotlib) INPUT: G: main Graph edges: edges which intersect with the plane of interst intersectionCoords: coordinates intersection points attribute: that should be plotted filename: filename (including path) of the .vtp and .pkl file which will be saved (without file type extension) interpMethod: the interpolation method of scipy.interpolate.griddata common choices: 'nearest','linear' (default),'cubic' gridpoints: number of gridpoints (default = 100) OUTPUT: .pkl and .vtp file is written grid_d1,grid_d2: grid values valuesGrid: interpolated attribute values for the grid case: integer to define if the normal vector is in x- (case=1), y- (case=2) or in z-direction (case=3) """ values=G.es[edges][attribute] x=[] y=[] z=[] for coord in coords: x.append(coord[0]) y.append(coord[1]) z.append(coord[2]) if len(np.unique(x)) < len(np.unique(y)) and len(np.unique(x)) < len(np.unique(z)): case=1 d1Min=np.min(y) d1Max=np.max(y) d2Min=np.min(z) d2Max=np.max(z) d1=y d2=z elif len(np.unique(y)) < len(np.unique(x)) and len(np.unique(y)) < len(np.unique(z)): case=2 d1Min=np.min(x) d1Max=np.max(x) d2Min=np.min(z) d2Max=np.max(z) d1=x d2=z elif len(np.unique(z)) < len(np.unique(y)) and len(np.unique(z)) < len(np.unique(x)): case=3 d1Min=np.min(x) d1Max=np.max(x) d2Min=np.min(y) d2Max=np.max(y) d1=x d2=y grid_d1,grid_d2=np.mgrid[d1Min:d1Max:(d1Max-d1Min)/100,d2Min:d2Max:(d2Max-d2Min)/100] valuesGrid=griddata(zip(d1,d2),values,(grid_d1,grid_d2),method=interpMethod) r=[] for coord1 in np.arange(d1Min,d1Max,(d1Max-d1Min)/100): for coord2 in np.arange(d2Min,d2Max,(d2Max-d2Min)/100): if case == 1: r.append(np.array([x[0],coord1,coord2])) elif case == 2: r.append(np.array([coord1,y[0],coord2])) elif case == 3: r.append(np.array([coord1,coord2,z[0]])) valuesGridList=[] for j in valuesGrid: for k in j: valuesGridList.append(k) planeG=vgm.VascularGraph(len(r)) planeG.vs['r']=r planeG.vs[attribute]=valuesGridList vgm.write_vtp(planeG,filename+'.vtp',False) vgm.write_pkl(planeG,filename+'.pkl') return grid_d1,grid_d2,valuesGrid,case
def solve(self, method, **kwargs): """Solves the linear system A x = b for the vector of unknown pressures x, either using a direct solver (obsolete) or an iterative GMRES solver. From the pressures, the flow field is computed. INPUT: method: This can be either 'direct' or 'iterative2' OUTPUT: None - G is modified in place. G_final.pkl & G_final.vtp: are save as output sampledict.pkl: is saved as output """ b = self._b G = self._G htt2htd = self._P.tube_to_discharge_hematocrit A = self._A.tocsr() if method == 'direct': linalg.use_solver(useUmfpack=True) x = linalg.spsolve(A, b) elif method == 'iterative2': ml = rootnode_solver(A, smooth=('energy', { 'degree': 2 }), strength='evolution') M = ml.aspreconditioner(cycle='V') # Solve pressure system #x,info = gmres(A, self._b, tol=self._eps, maxiter=1000, M=M) x, info = gmres(A, self._b, tol=10 * self._eps, M=M) if info != 0: print('ERROR in Solving the Matrix') print(info) G.vs['pressure'] = x self._x = x conductance = self._conductance G.es['flow'] = [abs(G.vs[edge.source]['pressure'] - G.vs[edge.target]['pressure']) * \ conductance[i] for i, edge in enumerate(G.es)] #Default Units - mmHg for pressure for v in G.vs: v['pressure'] = v['pressure'] / vgm.units.scaling_factor_du( 'mmHg', G['defaultUnits']) if self._withRBC: G.es['v'] = [ e['htd'] / e['htt'] * e['flow'] / (0.25 * np.pi * e['diameter']**2) for e in G.es ] else: G.es['v'] = [ e['flow'] / (0.25 * np.pi * e['diameter']**2) for e in G.es ] #Convert 'pBC' from default Units to mmHg pBCneNone = G.vs(pBC_ne=None).indices G.vs[pBCneNone]['pBC'] = np.array(G.vs[pBCneNone]['pBC']) * ( 1 / vgm.units.scaling_factor_du('mmHg', G['defaultUnits'])) vgm.write_pkl(G, 'G_final.pkl') vgm.write_vtp(G, 'G_final.vtp', False) #Write Output sampledict = {} for eprop in ['flow', 'v']: if not eprop in sampledict.keys(): sampledict[eprop] = [] sampledict[eprop].append(G.es[eprop]) for vprop in ['pressure']: if not vprop in sampledict.keys(): sampledict[vprop] = [] sampledict[vprop].append(G.vs[vprop]) g_output.write_pkl(sampledict, 'sampledict.pkl')