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
Beispiel #2
0
    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')
Beispiel #3
0
            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
Beispiel #4
0
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
Beispiel #7
0
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
Beispiel #8
0
    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')