[docs]defnetwork_from_networkx(G):r""" Creates an OpenPNM Network from a undirected NetworkX graph object Parameters ---------- G : networkx.classes.graph.Graph Object The NetworkX graph. G should be undirected. The numbering of nodes should be numeric (int's), zero-based and should not contain any gaps, i.e. ``G.nodes() = [0,1,3,4,5]`` is not allowed and should be mapped to ``G.nodes() = [0,1,2,3,4]``. Returns ------- network : dict An OpenPNM network dictionary Notes ----- 1. Each node in a NetworkX object (i.e. ``G``) can be assigned properties using syntax like ``G.node[n]['diameter'] = 0.5`` where ``n`` is the node number. There is no need to precede the property name with any indication that it is pore data such as \'pore\_\'. OpenPNM will prepend \'pore.\' to each property name. 2. Since \'pore.coords\' is so central to OpenPNM it should be specified in the NetworkX object as \'coords\', and the [X, Y, Z] coordinates of each node should be a 1x3 list. 3. Edges in a NetworkX object are accessed using the index numbers of the two nodes it connects, such as ``G.adj[2][3]['length'] = 0.1`` indicating the edge that connects nodes 2 and 3. There is no need to precede the property name with any indication that it is throat data such as \'throat\_\'. OpenPNM will prepend \'throat.\' to each property name. 4. The \'throat.conns\' property is essential to OpenPNM, but this does NOT need to be specified explicitly as a property in NetworkX. The connectivity is embedded into the network representation and is extracted by OpenPNM. """importnetworkxasnxfromopenpnm.networkimportNetworknet={}# Ensure G is an undirected networkX graph with numerically numbered# nodes for which numbering starts at 0 and does not contain any gapsifnotisinstance(G,nx.Graph):# pragma: no coverraiseException('Provided object is not a NetworkX graph.')ifnx.is_directed(G):# pragma: no coverraiseException('Provided graph is directed. Convert to undirected graph.')ifnotall(isinstance(n,int)forninG.nodes()):# pragma: no coverraiseException('Node numbering is not numeric. Convert to int.')ifmin(G.nodes())!=0:# pragma: no coverraiseException('Node numbering does not start at zero.')ifmax(G.nodes())+1!=len(G.nodes()):# pragma: no coverraiseException('Node numbering contains gaps. Map nodes to remove gaps.')# Parsing node dataNp=len(G)net.update({'pore.all':np.ones((Np,),dtype=bool)})forn,propsinG.nodes(data=True):foriteminprops.keys():val=props[item]dtype=type(val)# Remove prepended pore. and pore_ if presentforbin['pore.','pore_']:item=item.replace(b,'')# Create arrays for subsequent indexing, if not present alreadyif'pore.'+itemnotinnet.keys():ifdtype==str:# handle strings of arbitrary lengthnet['pore.'+item]=np.ndarray((Np,),dtype='object')elifdtypeislist:dtype=type(val[0])ifdtype==str:dtype='object'cols=len(val)net['pore.'+item]=np.ndarray((Np,cols),dtype=dtype)else:net['pore.'+item]=np.ndarray((Np,),dtype=dtype)net['pore.'+item][n]=val# Parsing edge data# Deal with conns explicitlytry:conns=list(G.edges)# NetworkX V2exceptException:# pragma: no coverconns=G.edges()# NetworkX V1conns.sort()# Add conns to NetworkNt=len(conns)net.update({'throat.all':np.ones(Nt,dtype=bool)})net.update({'throat.conns':np.array(conns)})# Scan through each edge and extract all its propertiesi=0fortinconns:props=G[t[0]][t[1]]foriteminprops:val=props[item]dtype=type(val)# Remove prepended throat. and throat_ if presentforbin['throat.','throat_']:item=item.replace(b,'')# Create arrays for subsequent indexing, if not present alreadyif'throat.'+itemnotinnet.keys():ifdtype==str:net['throat.'+item]=np.ndarray((Nt,),dtype='object')ifdtypeislist:dtype=type(val[0])ifdtype==str:dtype='object'cols=len(val)net['throat.'+item]=np.ndarray((Nt,cols),dtype=dtype)else:net['throat.'+item]=np.ndarray((Nt,),dtype=dtype)net['throat.'+item][i]=vali+=1network=Network()network.update(net)returnnetwork
[docs]defnetwork_to_networkx(network):r""" Write OpenPNM Network to a NetworkX object. Parameters ---------- network : dict The OpenPNM Network to be converted to a NetworkX object Returns ------- G : undirected graph object A NetworkX object with all pore/throat properties attached to it """importnetworkxasnxfromopenpnm.networkimportNetwork# Ensure network is an Network.ifnotisinstance(network,Network):# pragma: no coverraiseException('Provided network is not an OpenPNM Network.')G=nx.Graph()# Extracting node list and connectivity matrix from Networknodes=map(int,network.Ps)conns=network['throat.conns']# Explicitly add nodes and connectivity matrixG.add_nodes_from(nodes)G.add_edges_from(conns)# Attach Network properties to Gforpropinnetwork.props()+network.labels():if'pore.'inprop:iflen(network[prop].shape)>1:val={i:list(network[prop][i])foriinnetwork.Ps}else:val={i:network[prop][i]foriinnetwork.Ps}nx.set_node_attributes(G,name=prop[5:],values=val)if'throat.'inprop:val={tuple(conn):network[prop][i]fori,conninenumerate(conns)}nx.set_edge_attributes(G,name=prop[7:],values=val)returnG