pydfnWorks
python wrapper for dfnWorks
graph_flow.py
Go to the documentation of this file.
1 import networkx as nx
2 import numpy as np
3 import sys
4 import scipy.sparse
5 
6 # pydfnworks modules
7 from pydfnworks.dfnGraph import dfn2graph as d2g
8 
9 
11  nodelist=None,
12  weight=None,
13  dtype=None,
14  format='lil'):
15  """ Get the matrices D, A that make up the Laplacian sparse matrix in desired sparsity format. Used to enforce boundary conditions by modifying rows of L = D - A
16 
17  Parameters
18  ----------
19  G : object
20  NetworkX graph equipped with weight attribute
21 
22  nodelist : list
23  list of nodes of G for which laplacian is desired. Default is None in which case, all the nodes
24 
25  weight : string
26  For weighted Laplacian, else all weights assumed unity
27 
28  dtype : default is None, cooresponds to float
29 
30  format: string
31  sparse matrix format, csr, csc, coo, lil_matrix with default being lil
32 
33  Returns
34  -------
35  D : sparse 2d float array
36  Diagonal part of Laplacian
37 
38  A : sparse 2d float array
39  Adjacency matrix of graph
40  """
41 
42  A = nx.to_scipy_sparse_matrix(G,
43  nodelist=nodelist,
44  weight=weight,
45  dtype=dtype,
46  format=format)
47 
48  (n, n) = A.shape
49  data = np.asarray(A.sum(axis=1).T)
50  D = scipy.sparse.spdiags(data, 0, n, n, format=format)
51  return D, A
52 
53 
54 def prepare_graph_with_attributes(inflow, outflow,G=None):
55  """ Create a NetworkX graph, prepare it for flow solve by equipping edges with attributes, renumber vertices, and tag vertices which are on inlet or outlet
56 
57  Parameters
58  ----------
59  inflow : string
60  name of file containing list of DFN fractures on inflow boundary
61 
62  outflow: string
63  name of file containing list of DFN fractures on outflow boundary
64 
65  Returns
66  -------
67  Gtilde : NetworkX graph
68  """
69 
70  if G == None:
71  G = d2g.create_intersection_graph(
72  inflow, outflow, intersection_file="intersection_list.dat")
73 
74  Gtilde = G.copy()
75  d2g.add_perm(Gtilde)
76  d2g.add_area(Gtilde)
77  d2g.add_weight(Gtilde)
78 
79  else:
80  Gtilde = G
81 
82 
83  for v in nx.nodes(Gtilde):
84  Gtilde.nodes[v]['inletflag'] = False
85  Gtilde.nodes[v]['outletflag'] = False
86 
87  for v in nx.neighbors(Gtilde, 's'):
88  Gtilde.nodes[v]['inletflag'] = True
89 
90  for v in nx.neighbors(Gtilde, 't'):
91  Gtilde.nodes[v]['outletflag'] = True
92 
93  Gtilde.remove_node('s')
94  Gtilde.remove_node('t')
95 
96  Gtilde = nx.convert_node_labels_to_integers(Gtilde,
97  first_label=0,
98  ordering="sorted",
99  label_attribute="old_label")
100 
101  return Gtilde
102 
103 
104 def solve_flow_on_graph(Gtilde, Pin, Pout, fluid_viscosity=8.9e-4):
105  """ Given a NetworkX graph prepared for flow solve, solve for vertex pressures, and equip edges with attributes (Darcy) flux and time of travel
106 
107  Parameters
108  ----------
109  Gtilde : NetworkX graph
110 
111  Pin : double
112  Value of pressure (in Pa) at inlet
113 
114  Pout : double
115  Value of pressure (in Pa) at outlet
116 
117  fluid_viscosity : double
118  optional, in Pa-s, default is for water
119 
120  Returns
121  -------
122  Gtilde : NetworkX graph
123  Gtilde is updated with vertex pressures, edge fluxes and travel times
124  """
125 
126  Inlet = [v for v in nx.nodes(Gtilde) if Gtilde.nodes[v]['inletflag']]
127  Outlet = [v for v in nx.nodes(Gtilde) if Gtilde.nodes[v]['outletflag']]
128 
129  if not set(Inlet).isdisjoint(set(Outlet)):
130  error = "Incompatible graph: Vertex connected to both source and target\n"
131  sys.stderr.write(error)
132  sys.exit(1)
133 
134  D, A = get_laplacian_sparse_mat(Gtilde, weight='weight', format='lil')
135 
136  rhs = np.zeros(Gtilde.number_of_nodes())
137 
138  for v in Inlet:
139  rhs[v] = Pin
140  A[v, :] = 0
141  D[v, v] = 1.0
142  for v in Outlet:
143  rhs[v] = Pout
144  A[v, :] = 0
145  D[v, v] = 1.0
146  L = D - A # automatically converts to csr when returning L
147 
148  print("Solving sparse system")
149  Phat = scipy.sparse.linalg.spsolve(L, rhs)
150  print("Updating graph edges with flow solution")
151 
152  for v in nx.nodes(Gtilde):
153  Gtilde.nodes[v]['pressure'] = Phat[v]
154 
155  for u, v in nx.edges(Gtilde):
156  delta_p = abs(Gtilde.nodes[u]['pressure'] -
157  Gtilde.nodes[v]['pressure'])
158  if delta_p > np.spacing(Gtilde.nodes[u]['pressure']):
159  Gtilde.edges[u, v]['flux'] = (
160  Gtilde.edges[u, v]['perm'] / fluid_viscosity
161  ) * abs(Gtilde.nodes[u]['pressure'] -
162  Gtilde.nodes[v]['pressure']) / Gtilde.edges[u, v]['length']
163  Gtilde.edges[u, v]['time'] = Gtilde.edges[
164  u, v]['length'] / Gtilde.edges[u, v]['flux']
165  else:
166  Gtilde.edges[u, v]['flux'] = 0
167 
168  print("Graph flow complete")
169  return Gtilde
170 
171 
172 def run_graph_flow(self, inflow, outflow, Pin, Pout, fluid_viscosity=8.9e-4, G = None):
173  """ Run the graph flow portion of the workflow
174 
175  Parameters
176  ----------
177  self : object
178  DFN Class
179 
180 
181  inflow : string
182  name of file containing list of DFN fractures on inflow boundary
183 
184  outflow: string
185  name of file containing list of DFN fractures on outflow boundary
186 
187  Pin : double
188  Value of pressure (in Pa) at inlet
189 
190  Pout : double
191  Value of pressure (in Pa) at outlet
192 
193  fluid_viscosity : double
194  optional, in Pa-s, default is for water
195 
196  Returns
197  -------
198  Gtilde : NetworkX graph
199  Grtilde is updated with vertex pressures, edge fluxes and travel times
200 
201  Notes
202  -----
203  Information on individual functions in found therein
204  """
205  Gtilde = prepare_graph_with_attributes(inflow, outflow, G)
206  Gtilde = solve_flow_on_graph(Gtilde, Pin, Pout, fluid_viscosity)
207  return Gtilde
def solve_flow_on_graph(Gtilde, Pin, Pout, fluid_viscosity=8.9e-4)
Definition: graph_flow.py:104
def run_graph_flow(self, inflow, outflow, Pin, Pout, fluid_viscosity=8.9e-4, G=None)
Definition: graph_flow.py:172
def get_laplacian_sparse_mat(G, nodelist=None, weight=None, dtype=None, format='lil')
Definition: graph_flow.py:14
def prepare_graph_with_attributes(inflow, outflow, G=None)
Definition: graph_flow.py:54