2 .. module:: mesh_dfn_helper.py
3 :synopsis: helper functions for meshing DFN using LaGriT
4 .. moduleauthor:: Jeffrey Hyman <jhyman@lanl.gov>
9 from numpy
import genfromtxt, sort, zeros
14 """ Reads params.txt file from DFNGen and parses information
19 If True details are not printed to screen, if False they area
26 Meshing length scale h
28 Expected number of dudded points in Filter (LaGriT)
30 If True, reduced_mesh.inp is created (not suitable for flow and transport), if False, full_mesh.inp is created
39 print(
"\n--> Parsing params.txt")
40 fparams = open(
'params.txt',
'r')
42 num_poly = int(fparams.readline())
44 h = float(fparams.readline())
46 visual_mode = int(fparams.readline())
48 dudded_points = int(fparams.readline())
51 domain = {
'x': 0,
'y': 0,
'z': 0}
53 domain[
'x'] = (float(fparams.readline()))
56 domain[
'y'] = (float(fparams.readline()))
59 domain[
'z'] = (float(fparams.readline()))
63 print(
"--> Number of Polygons: %d" % num_poly)
64 print(
"--> H_SCALE %f" % h)
67 print(
"--> Visual mode is on")
70 print(
"--> Visual mode is off")
71 print(f
"--> Expected Number of dudded points: {dudded_points}")
72 print(f
"--> X Domain Size {domain['x']} m")
73 print(f
"--> Y Domain Size {domain['y']} m")
74 print(f
"--> Z Domain Size {domain['z']} m")
75 print(
"--> Parsing params.txt complete\n")
77 return (num_poly, h, visual_mode, dudded_points, domain)
81 """Parses LaGrit log_merge_all.out and checks if number of dudded points is the expected number
86 Expected number of dudded points from params.txt
88 If hard is false, up to 1% of nodes in the mesh can be missed. If hard is True, no points can be missed.
92 True if the number of dudded points is correct and False if the number of dudded points is incorrect
96 If number of dudded points is incorrect by over 1%, program will exit.
99 print(
"--> Checking that number of dudded points is correct\n")
100 with open(
"lagrit_logs/log_merge_all.out",
"r")
as fp:
101 for line
in fp.readlines():
102 if 'Dudding' in line:
103 print(f
'--> From LaGriT: {line}')
105 pts = int(line.split()[1])
107 pts = int(line.split()[-1])
108 if 'RMPOINT:' in line:
109 print(f
'--> From LaGriT: {line}')
110 total_points = int(line.split()[-1])
113 diff = abs(dudded - pts)
114 print(f
"--> Expected Number of dudded points: {dudded}")
115 print(f
"--> Actual Number of dudded points: {pts}")
116 print(f
"--> Difference between expected and actual dudded points: {diff}")
118 print(
'--> The correct number of points were removed. Onward!\n')
123 '--> WARNING!!! Number of points removed does not match the expected value'
125 diff_ratio = 100 * (float(diff) / float(total_points))
126 if diff_ratio < 0.01
and hard ==
False:
127 print(f
"--> However value is small: {diff}")
128 print(
"--> Proceeding\n")
131 print(
'ERROR! Incorrect Number of points removed')
132 print(f
"Over 0.01% of nodes removed. Value is {diff_ratio:.2f}")
137 """ Removes meshing files
149 Only runs if production_mode is True
153 'part*',
'log_merge*',
'merge*',
'mesh_poly_CPU*',
'mesh*inp',
156 for name
in files_to_remove:
157 for fl
in glob.glob(name):
162 """ Prints information about the final mesh to file
166 local_jobname : string
167 Name of current DFN job (not path)
169 Determines is reduced_mesh or full_mesh is dumped
180 f = open(local_jobname +
'_mesh_information.txt',
'w')
181 f.write(
'The final mesh of DFN consists of: \n')
184 "--> Output files for flow calculations are written in : full_mesh.*"
187 finp = open(
'full_mesh.inp',
'r')
190 NumElems = int(g.pop(1))
191 NumIntNodes = int(g.pop(0))
192 f.write(str(NumElems) +
' triangular elements; \n')
193 f.write(str(NumIntNodes) +
' nodes / control volume cells; \n')
196 fstor = open(
'full_mesh.stor',
'r')
199 gs = fstor.readline()
201 NumCoeff = int(gs.pop(0))
204 ' geometrical coefficients / control volume faces. \n')
208 "--> Output files for visualization are written in : reduced_mesh.inp"
210 print(
"--> Warning!!! Mesh is not suitable for flow and transport.")
212 finp = open(
'reduced_mesh.inp',
'r')
215 NumElems = int(g.pop(1))
216 NumIntNodes = int(g.pop(0))
217 f.write(str(NumElems) +
' triangular elements; \n')
218 f.write(str(NumIntNodes) +
' nodes / control volume cells. \n')
224 ''' After pruning a DFN to only include the fractures in prune_file this function removes references to those fractures from params.txt, perm.dat, aperature.dat, and poly_info.dat
236 This function should always be run after pruning if flow solution is going to be run
240 print(
"--> Editing DFN file based on fractures in %s" % self.prune_file)
241 keep_list = sort(genfromtxt(self.prune_file).astype(int))
242 num_frac = len(keep_list)
244 print(
"--> Editing params.txt file")
245 fin = open(self.path +
'/params.txt')
247 os.unlink(
'params.txt')
250 fout = open(
'params.txt',
'w')
251 line = fin.readline()
252 fout.write(
'%d\n' % num_frac)
254 line = fin.readline()
258 print(
"--> Complete")
260 print(
"--> Editing poly_info.dat file")
261 poly_info = genfromtxt(self.path +
'poly_info.dat')[keep_list - 1, :]
263 os.unlink(
'poly_info.dat')
266 f = open(
'poly_info.dat',
'w')
267 for i
in range(num_frac):
268 f.write(
'%d %d %f %f %f %d %f %f %d\n' %
269 (i + 1, poly_info[i, 1], poly_info[i, 2], poly_info[i, 3],
270 poly_info[i, 4], poly_info[i, 5], poly_info[i, 6],
271 poly_info[i, 7], poly_info[i, 8]))
273 print(
"--> Complete")
275 print(
"--> Editing perm.dat file")
276 perm = genfromtxt(self.path +
'perm.dat', skip_header=1)[keep_list - 1, -1]
277 f = open(
'perm.dat',
'w+')
278 f.write(
'permeability\n')
279 for i
in range(num_frac):
280 f.write(
'-%d 0 0 %e %e %e\n' % (7 + i, perm[i], perm[i], perm[i]))
282 print(
"--> Complete")
284 print(
"--> Editing aperture.dat file")
285 aperture = genfromtxt(self.path +
'aperture.dat',
286 skip_header=1)[keep_list - 1, -1]
287 f = open(
'aperture.dat',
'w+')
288 f.write(
'aperture\n')
289 for i
in range(num_frac):
290 f.write(
'-%d 0 0 %e \n' % (7 + i, aperture[i]))
292 print(
"--> Complete")
294 print(
"--> Editing radii_Final.dat file")
295 fin = open(self.path +
'radii_Final.dat')
296 fout = open(
'radii_Final.dat',
'w')
298 line = fin.readline()
300 line = fin.readline()
304 radii = genfromtxt(self.path +
'radii_Final.dat',
305 skip_header=2)[keep_list - 1, :]
306 for i
in range(num_frac):
307 fout.write(
'%f %f %d\n' % (radii[i, 0], radii[i, 1], radii[i, 2]))
309 print(
"--> Complete")
311 print(
"--> Editing normal_vectors.dat file")
312 fin = open(self.path +
'normal_vectors.dat')
313 fout = open(
'normal_vectors.dat',
'w')
315 normal_vect = genfromtxt(self.path +
'normal_vectors.dat')[keep_list -
317 for i
in range(num_frac):
318 fout.write(
'%f %f %f\n' %
319 (normal_vect[i, 0], normal_vect[i, 1], normal_vect[i, 2]))
321 print(
"--> Complete")
323 print(
"--> Editing translations.dat file")
324 fin = open(self.path +
'translations.dat')
325 fout = open(
'translations.dat',
'w')
327 line = fin.readline()
330 for line
in fin.readlines():
331 tmp = line.split(
' ')
333 points.append((float(tmp[0]), float(tmp[1]), float(tmp[2])))
334 from numpy
import asarray
335 points = asarray(points)
336 points = points[keep_list - 1, :]
337 for i
in range(num_frac):
338 fout.write(
'%f %f %f\n' % (points[i, 0], points[i, 1], points[i, 2]))
340 print(
"--> Complete")
342 print(
"--> Editing Fracture Files Complete")
346 ''' Makes symlinks for files in path required for meshing
352 Path to where meshing files are located
364 from shutil
import rmtree
365 print(
"--> Creating links for meshing from %s" % path)
367 'params.txt',
'poly_info.dat',
'connectivity.dat',
'left.dat',
368 'right.dat',
'front.dat',
'back.dat',
'top.dat',
'bottom.dat',
'polys',
369 'intersections',
'aperture.dat',
'perm.dat'
372 if os.path.isfile(f)
or os.path.isdir(f):
373 print(
"Removing %s" % f)
377 print(
"Unable to remove %s" % f)
379 os.symlink(path + f, f)
381 print(
"Unable to make link for %s" % f)
383 print(
"--> Complete")
387 """ Convert inp file to gmv file, for general mesh viewer. Name of output file for base.inp is base.gmv
394 Name of inp file if not an attribure of self
405 self.inp_file = inp_file
407 inp_file = self.inp_file
410 error =
'ERROR: inp file must be specified in inp2gmv!\n'
411 sys.stderr.write(error)
414 gmv_file = inp_file[:-4] +
'.gmv'
416 with open(
'inp2gmv.lgi',
'w')
as fid:
417 fid.write(f
'read / avs / {inp_file} / mo\n')
418 fid.write(f
'dump / gmv / {gmv_file} / mo\n')
419 fid.write(
'finish \n\n')
424 error =
'ERROR: Failed to run LaGrit to get gmv from inp file!\n'
425 sys.stderr.write(error)
427 print(
"--> Finished writing gmv format from avs format")
431 """ Using Python VTK library, convert inp file to VTK file.
444 For a mesh base.inp, this dumps a VTK file named base.vtk
447 if self.flow_solver !=
"PFLOTRAN":
448 error =
"ERROR! Wrong flow solver requested\n"
449 sys.stderr.write(error)
452 print(
"--> Using Python to convert inp files to VTK files")
454 inp_file = self.inp_file
457 error =
'ERROR: Please provide inp filename!\n'
458 sys.stderr.write(error)
462 vtk_file = self.vtk_file
464 vtk_file = inp_file[:-4]
465 self.vtk_file = vtk_file +
'.vtk'
467 print(
"--> Reading inp data")
469 with open(inp_file,
'r')
as f:
471 num_nodes = int(line.strip(
' ').split()[0])
472 num_elems = int(line.strip(
' ').split()[1])
474 coord = zeros((num_nodes, 3),
'float')
478 for i
in range(num_nodes):
480 coord[i, 0] = float(line.strip(
' ').split()[1])
481 coord[i, 1] = float(line.strip(
' ').split()[2])
482 coord[i, 2] = float(line.strip(
' ').split()[3])
484 for i
in range(num_elems):
485 line = f.readline().strip(
' ').split()
488 elem_type = line.pop(0)
489 if elem_type ==
'tri':
490 elem_list_tri.append([int(i) - 1
for i
in line])
491 if elem_type ==
'tet':
492 elem_list_tetra.append([int(i) - 1
for i
in line])
494 print(
'--> Writing inp data to vtk format')
496 pv.UnstructuredGrid(coord,
497 tetra=elem_list_tetra,
498 triangle=elem_list_tri),
499 'Unstructured pflotran grid')
512 Name of LaGriT script to run
514 Name of file to dump LaGriT output
516 If false, information will be printed to screen.
521 If the run was successful, then 0 is returned.
524 if output_file ==
None:
525 cmd = f
"{os.environ['LAGRIT_EXE']} < {lagrit_file}"
527 cmd = f
"{os.environ['LAGRIT_EXE']} < {lagrit_file} > {output_file}"
529 print(f
"--> Running: {cmd}")
531 failure = subprocess.call(cmd, shell=
True)
533 error = f
"ERROR running LaGriT on script {lagrit_file}. Exiting Program.\n"
def parse_params_file(quiet=False)
def run_lagrit_script(lagrit_file, output_file=None, quiet=False)
def output_meshing_report(local_jobname, visual_mode)
def inp2gmv(self, inp_file='')
def create_mesh_links(self, path)
def check_dudded_points(dudded, hard=False)
def clean_up_files_after_prune(self)