pydfnWorks
python wrapper for dfnWorks
gather_information.py
Go to the documentation of this file.
1 """
2  :filename: gather_information.py
3  :synopsis: gathers information from files output by dfnGen and combines them into lists of dictionaries for each fracture and fracture families. Additional information about the domain and network are put into a general parameter dictionary.
4  :version: 1.0
5  :maintainer: Jeffrey Hyman
6  .. moduleauthor:: Jeffrey Hyman <jhyman@lanl.gov>
7 """
8 
9 import re
10 import sys
11 
12 from pydfnworks.dfnGen.meshing import mesh_dfn_helper as mh
14 
15 
16 def parse_dfn_output(params, families):
17  """ Parses information from the 'DFN_output.txt' report generated by dfnGen into family dictionaries and params dictionary.
18 
19  Parameters
20  ------------
21  params : dictionary
22  Output report dictionary containing general parameters. See output_report for more details
23  families : list
24  list of dictionaries with information about fracture family
25 
26  Returns
27  ---------
28  params : dictionary
29  Output report dictionary containing general parameters. See output_report for more details
30  families : list
31  list of dictionaries with information about fracture family
32 
33  Notes
34  -------
35  Information for user defined fractures are not included into the family dictionaries
36 
37 
38  """
39 
40  bulk_params = [
41  "Total Surface Area", "Total Fractures Volume",
42  "Total Fracture Density (P30)", "Total Fracture Intensity (P32)",
43  "Total Fracture Porosity (P33)", "Total Fractures Rejected"
44  ]
45 
46  final_params = [
47  "Isolated Fractures Removed", "Final Number of Fractures",
48  "Total Fractures Rejected", "Total Fractures Re-translated"
49  ]
50 
51  intersection_params = [
52  " Number of Intersections", " Intersections Shortened",
53  " Original Intersection (Before Intersection Shrinking) Length",
54  " Intersection Length Discarded", " Final Intersection Length"
55  ]
56 
57  family_parms = [
58  " Fractures After Isolated Fracture Removal",
59  " Isolated Fractures Removed", " Accepted", " Rejected",
60  " Surface Area", " Volume", " Fracture Intensity (P32)"
61  ]
62 
63  string_params = ["Time Stamp"]
64 
65  pre_iso_flag = False
66  post_iso_flag = False
67  family_block_flag = False
68  with open('DFN_output.txt', "r") as fp:
69  for line in fp.readlines():
70  if "Statistics Before Isolated Fractures Removed" in line:
71  pre_iso_flag = True
72  #print("Pre ISO")
73  if "Statistics After Isolated Fractures Removed" in line:
74  pre_iso_flag = False
75  post_iso_flag = True
76  #print("Post ISO")
77 
78  if len(line.split()) > 0:
79  parsed_line = line.split(": ")
80  if len(parsed_line) > 1:
81  variable = parsed_line[0]
82  value = parsed_line[1].rstrip()
83  # Bulk Params
84  if variable in string_params:
85  params[variable] = value
86 
87  if variable in bulk_params:
88  if "m" in value:
89  value = value.split()[0]
90  if pre_iso_flag:
91  params["Pre-Iso " + variable] = float(value)
92  elif post_iso_flag:
93  params["Post-Iso " + variable] = float(value)
94 
95  elif variable in final_params:
96  params[variable] = int(value)
97 
98  elif variable in intersection_params:
99  if "m" in value:
100  value = value.split()[0]
101  params[variable.lstrip()] = float(value)
102 
103  # Parse by Family
104  elif variable == "Family":
105  for fam in families:
106  if int(value) == fam["Global Family"]:
107  family_block_flag = True
108  break
109 
110  elif variable in family_parms and family_block_flag:
111  if "m" in value:
112  value = value.split()[0]
113  if pre_iso_flag:
114  fam["Pre-Iso " + variable.lstrip()] = float(value)
115  elif post_iso_flag:
116  fam["Post-Iso " + variable.lstrip()] = float(value)
117  if variable.lstrip() == "Fracture Intensity (P32)":
118  family_block_flag = False
119 
120  return params, families
121 
122 
124  """ Reads in information from families.dat file that lists the data for each fracture family.
125 
126  Parameters
127  -----------
128  None
129 
130  Returns
131  --------
132  families : list
133  List of dictionaries with information about fracture family
134  Notes
135  ------
136  None
137 
138  """
139 
140  int_params = [
141  "Rectangular Family", "Global Family", "Number of Vertices",
142  "Layer Number", "Region Number", "Ellipse Family"
143  ]
144  string_params = [
145  "Distribution", "Region", "Layer",
146  "Beta Distribution (Rotation Around Normal Vector)"
147  ]
148  families = []
149  with open('families.dat', "r") as fp:
150  family = {}
151  for line in fp.readlines():
152  if len(line.split()) > 0:
153  parsed_line = line.split(": ")
154  variable = parsed_line[0]
155  value = parsed_line[1].rstrip()
156  if variable in string_params:
157  family[variable] = str(value)
158  elif variable in int_params:
159  family[variable] = int(value)
160  else:
161  family[variable] = float(value)
162 
163  else:
164  families.append(family)
165  del family
166  family = {}
167 
168  # Add necessary keys for user defined fractures and shapes
169  new_families = []
170  for family in families:
171  keys = family.keys()
172 
173  if "UserDefined Rectangle Family" in keys:
174  family["Global Family"] = -1
175  family["Distribution"] = "user_rectangles"
176  family["Layer"] = False
177  family["Region"] = False
178  family["Shape"] = "Rectangle"
179 
180  elif "UserDefined Ellipse Family" in keys:
181  family["Distribution"] = "user_ellipses"
182  family["Global Family"] = 0
183  family["Layer"] = False
184  family["Region"] = False
185  family["Shape"] = "Ellipse"
186 
187  elif "UserDefined Polygon Family" in keys:
188  family["Distribution"] = "user_polygons"
189  family["Global Family"] = -2
190  family["Layer"] = False
191  family["Region"] = False
192  family["Shape"] = "Polygon"
193 
194  elif "Rectangular Family" in keys:
195  family["Shape"] = "Rectangle"
196  new_families.append(family)
197 
198  elif "Ellipse Family" in keys:
199  family["Shape"] = "Ellipse"
200  new_families.append(family)
201 
202  families = new_families
203  del new_families
204 
205  # Parse Layers and Regions
206  for family in families:
207  if family["Global Family"] > 0:
208  #try:
209  if family["Layer"] != "Entire domain":
210  values = re.sub("{|}", "", family["Layer"]).strip().split(",")
211  family["z_min"] = float(values[0])
212  family["z_max"] = float(values[1])
213  family["Layer"] = True
214  else:
215  family["Layer"] = False
216 
217  if family["Region"] != "Entire domain":
218  values = re.sub("{|}", "", family["Region"]).strip().split(",")
219  family["x_min"] = float(values[0])
220  family["x_max"] = float(values[1])
221  family["y_min"] = float(values[2])
222  family["y_max"] = float(values[3])
223  family["z_min"] = float(values[4])
224  family["z_max"] = float(values[5])
225  family["Region"] = True
226  else:
227  family["Region"] = False
228  # except:
229  # print("ERROR on this family")
230  # print(family)
231  # print("Unexpected error:", sys.exc_info()[0])
232  # pass
233 
234  num_fam = len(families)
235  if num_fam == 1:
236  print(f"--> There is {num_fam} Fracture Family")
237  else:
238  print(f"--> There are {num_fam} Fracture Families")
239 
240  return families
241 
242 
244  fracture = {
245  "frac_id": None,
246  "x-radius": None,
247  "y-radius": None,
248  "normal": [None, None, None],
249  "center": {
250  "x": None,
251  "y": None,
252  "z": None
253  },
254  "family": None,
255  #"connections": None,
256  "surface_area": None,
257  "removed": bool
258  }
259  return fracture
260 
261 
263  """ Reads in information about fractures. Information is taken from radii.dat, translations.dat, normal_vectors.dat, and surface_area_Final.dat files. Information for each fracture is stored in a dictionary created by create_fracture_dictionary() that includes the fracture id, radius, normal vector, center, family number, surface area, and if the fracture was removed due to being isolated
264 
265  Parameters
266  -----------
267  None
268 
269  Returns
270  --------
271  fractuers : list
272  List of fracture dictionaries with information.
273  Notes
274  ------
275  Both fractures in the final network and those removed due to being isolated are included in the list.
276 
277  """
278  fractures = []
279  accepted_fractures = 0
280  # walk through radii file and start parsing fracture information
281  with open('radii.dat', "r") as fp:
282  fp.readline() # header
283  for i, line in enumerate(fp.readlines()):
284  fracture = create_fracture_dictionary()
285 
286  if "R" in line:
287  line = line.split()
288  fracture["frac_id"] = -1
289  fracture["x-radius"] = float(line[0])
290  fracture["y-radius"] = float(line[1])
291  fracture["family"] = float(line[2])
292  fracture["removed"] = True
293  else:
294  line = line.split()
295  fracture["frac_id"] = i + 1
296  fracture["x-radius"] = float(line[0])
297  fracture["y-radius"] = float(line[1])
298  fracture["family"] = int(line[2])
299  fracture["removed"] = False
300  accepted_fractures += 1
301  fractures.append(fracture)
302 
303  # Walk through translation file
304  with open('translations.dat', "r") as fp:
305  fp.readline() # header
306  for i, line in enumerate(fp.readlines()):
307  line = line.split()
308  fractures[i]["center"]["x"] = float(line[0])
309  fractures[i]["center"]["y"] = float(line[1])
310  fractures[i]["center"]["z"] = float(line[2])
311  if not fractures[i]["removed"] and len(line) > 3:
312  error = f"ERROR!!! Unexpected removed fracture in output report.\nCheck fracture number {i+1}\n.Exiting Program.\n"
313  sys.stderr.write(error)
314  sys.exit(1)
315 
316  # Walk through normal vector file
317  with open("normal_vectors.dat", "r") as fp:
318  for i in range(len(fractures)):
319  if not fractures[i]["removed"]:
320  line = fp.readline().split()
321  fractures[i]["normal"][0] = float(line[0])
322  fractures[i]["normal"][1] = float(line[1])
323  fractures[i]["normal"][2] = float(line[2])
324 
325  # Walk through surface_area_file and keep the surface areas in the final network
326  with open("surface_area_Final.dat", "r") as fp:
327  fp.readline() # header
328  for i in range(len(fractures)):
329  if not fractures[i]["removed"]:
330  line = fp.readline().split()
331  fractures[i]["surface_area"] = float(line[0])
332 
333  print(f"--> There are {len(fractures)} fractures in the domain")
334  print(f"--> There are {accepted_fractures} fractures in the final network")
335  # Note could also return list of only accepted fractures
336  return fractures
337 
338 
340  """ Combines information from the fracture families and individual fractures, e.g., list of indicies . Creates the parameter dictionary.
341 
342  Parameters
343  -----------
344  families : list
345  List of dictionaries with information about fracture family
346  fractures : list
347  List of fracture dictionaries
348 
349  Returns
350  --------
351  families : list
352  List of dictionaries with information about fracture family
353  fractures : list
354  List of fracture dictionaries
355  params : dictionary
356  Output report dictionary containing general parameters. See output_report for more details
357 
358  Notes
359  ------
360  None
361 
362  """
363 
364  colors = load_colors()
365  num_fractures, _, _, _, domain = mh.parse_params_file(quiet=True)
366  num_families = len(families)
367 
368  for ifam, family in enumerate(families):
369  family["fracture list - all"] = []
370  family["fracture list - final"] = []
371  for i, fracture in enumerate(fractures):
372  if fracture["family"] == family["Global Family"]:
373  family["fracture list - all"].append(i)
374  if not fracture["removed"]:
375  family["fracture list - final"].append(i)
376  family["total_number_of_fractures"] = len(
377  family["fracture list - all"])
378  family["final_number_of_fractures"] = len(
379  family["fracture list - final"])
380 
381  if num_families < 10:
382  family["color"] = colors[2 * ifam]
383  else:
384  family["color"] = colors[ifam]
385 
386  params = {
387  "num_families": num_families,
388  "num_accepted_fractures": num_fractures,
389  "num_total_fractures": len(fractures),
390  "domain": domain,
391  "final_color": "#4787ff",
392  "all_color": "#ffe940",
393  "analytic_color": "#ff4073"
394  }
395 
396  return families, fractures, params