2 .. module:: run_meshing.py
3 :synopsis: functions to mesh fracture network in parallel
4 .. moduleauthor:: Jeffrey Hyman <jhyman@lanl.gov>
14 import multiprocessing
as mp
15 from shutil
import copy, rmtree
16 from numpy
import genfromtxt
22 """ If meshing fails, this function moves all relavent files
23 to a folder for debugging
28 Current Fracture ID number
30 Number of digits in total number of fractures
38 This will throw warnings depending on when in the work-flow it is called. Some files
39 might not be created at those times. It's okay.
44 print(f
"--> Cleaning up meshing run for fracture {fracture_id}")
46 if not os.path.isfile(
"failure.txt"):
47 with open(
'failure.txt',
"w+")
as failure_file:
48 failure_file.write(f
"{fracture_id}\n")
50 with open(
'failure.txt',
"a")
as failure_file:
51 failure_file.write(f
"{fracture_id}\n")
53 folder = f
"failure_{fracture_id}/"
58 print(f
"Warning! Unable to make new folder: {folder}")
62 f
"mesh_{fracture_id}.inp", f
"{fracture_id}_mesh_errors.txt",
63 f
"id_tri_node_{fracture_id}.list",
64 f
"lagrit_logs/log_lagrit_{fracture_id:0{digits}d}.out"
72 print(f
'--> Warning: Could copy {f} to failure folder')
76 f
"poly_{fracture_id}.inp", f
"intersections_{fracture_id}.inp",
77 f
"parameters_{fracture_id}.mlgi", f
"mesh_poly_{fracture_id}.lgi",
78 f
'points_{fracture_id}.xyz'
86 print(f
'--> Warning: Could not unlink {f}')
90 print(f
"--> Cleanup for Fracture {fracture_id} complete")
94 """Child function for parallelized meshing of fractures
99 Current Fracture ID number
101 True/False for reduced meshing
103 Total Number of Fractures in the DFN
108 0 - run was successful
109 -1 - error making symbolic link
110 -2 - run failed in Poisson Sampling
111 -3 - run failed to produce mesh files
112 -4 - line of intersection not preserved
116 If meshing run fails, information about that fracture will be put into a directory failure_(fracture_id)
121 p = mp.current_process()
122 _, cpu_id = p.name.split(
"-")
125 digits = len(str(num_poly))
128 f
"--> Fracture {fracture_id:0{digits}d} out of {num_poly} is starting on worker {cpu_id}"
131 tic = timeit.default_timer()
134 os.symlink(f
"polys/poly_{fracture_id}.inp", f
"poly_{fracture_id}.inp")
136 print(f
"-->\n\n\nError creating link for poly_{fracture_id}.inp\n\n\n")
137 return (fracture_id, -1)
140 os.symlink(f
"parameters/parameters_{fracture_id}.mlgi",\
141 f
"parameters_{fracture_id}.mlgi")
144 f
"-->\n\n\nError creating link for/parameters_{fracture_id}.mlgi\n\n\n"
146 return (fracture_id, -1)
149 os.symlink(f
"lagrit_scripts/mesh_poly_{fracture_id}.lgi",\
150 f
"mesh_poly_{fracture_id}.lgi")
153 f
"-->\n\n\nError creating link for/parameters_{fracture_id}.mlgi\n\n\n"
155 return (fracture_id, -1)
159 os.symlink(f
"intersections/intersections_{fracture_id}.inp",\
160 f
"intersections_{fracture_id}.inp")
163 f
"\n\n\n--> Error creating link for intersections_{fracture_id}.inp\n\n\n"
165 return (fracture_id, -1)
169 single_fracture_poisson(fracture_id)
171 print(
" Error:", sys.exc_info()[0])
173 f
"-->\n\n\nERROR occurred generating points for fracture {fracture_id}\n\n\n"
176 return (fracture_id, -2)
180 if not os.path.isfile(f
'points/points_{fracture_id}.xyz'):
182 f
"-->\n\n\nERROR occurred generating points for fracture {fracture_id}\n\n\n"
185 return (fracture_id, -2)
187 os.symlink(f
"points/points_{fracture_id}.xyz",
188 f
"points_{fracture_id}.xyz")
191 f
"-->\n\n\nError creating link for points_{fracture_id}.xyz\n\n\n"
193 return (fracture_id, -1)
197 mh.run_lagrit_script(
198 f
"mesh_poly_{fracture_id}.lgi",
199 output_file=f
"lagrit_logs/log_lagrit_{fracture_id:0{digits}d}.out",
203 f
"\n\n\n--> ERROR occurred during meshing fracture {fracture_id}\n\n\n"
206 return (fracture_id, -3)
209 if not os.path.isfile(f
'mesh_{fracture_id}.lg')
or os.stat(
210 f
'mesh_{fracture_id}.lg') == 0:
212 f
"\n\n\n--> ERROR occurred during meshing fracture {fracture_id}\n\n\n"
215 return (fracture_id, -3)
220 cmd_check = f
"{os.environ['CONNECT_TEST_EXE']} \
221 intersections_{fracture_id}.inp \
222 id_tri_node_{fracture_id}.list \
223 mesh_{fracture_id}.inp \
229 if subprocess.call(cmd_check, shell=
True):
231 f
"\n\n\n--> ERROR: MESH CHECKING FAILED on {fracture_id}!!!\n\nEXITING PROGRAM\n\n\n"
234 return (fracture_id, -4)
237 f
"\n\n\n--> ERROR: MESH CHECKING FAILED on {fracture_id}!!!\n\nEXITING PROGRAM\n\n\n"
240 return (fracture_id, -4)
243 files = [f
"id_tri_node_{fracture_id}.list", f
"mesh_{fracture_id}.inp"]
248 print(f
"--> Could not remove {f}\n")
254 f
'poly_{fracture_id}.inp', f
'parameters_{fracture_id}.mlgi',
255 f
"mesh_poly_{fracture_id}.lgi"
259 f
'poly_{fracture_id}.inp', f
'intersections_{fracture_id}.inp',
260 f
'points_{fracture_id}.xyz', f
'parameters_{fracture_id}.mlgi',
261 f
"mesh_poly_{fracture_id}.lgi"
267 print(f
'--> Warning: Could unlink {f}')
270 elapsed = timeit.default_timer() - tic
272 f
"--> Fracture {fracture_id:0{digits}d} out of {num_poly} is complete on worker {cpu_id}. Time required: {elapsed:.2f} seconds\n"
274 return (fracture_id, 0)
278 """ Header function for Parallel meshing of fractures
280 Creates a queue of fracture numbers ranging from 1, num_poly
282 Each fractures is meshed using mesh_fracture called within the
285 If any fracture fails to mesh properly, then a folder is created with
286 that fracture information and the fracture number is written into
292 Fractures to be meshed
294 True/False for reduced meshing
296 Total Number of Fractures
301 True - If failure.txt is empty then all fractures have been meshed correctly
302 False - If failure.txt is not empty, then at least one fracture failed.
306 If one fracture fails meshing, program will exit.
309 t_all = timeit.default_timer()
313 f
"\n--> Triangulating {len(fracture_list)} fractures using {ncpu} processors\n\n"
315 dirs = [
"points",
"lagrit_logs"]
326 def log_result(result):
329 result_list.append(result)
334 "poly_*.inp",
"mesh_poly_*.lgi",
"parameters_*.mlgi",
335 "intersections_*.inp",
"points_*.xzy"
338 files_to_remove = glob.glob(name)
339 for f
in files_to_remove:
342 for i
in fracture_list:
343 pool.apply_async(mesh_fracture,
344 args=(i, visual_mode, len(fracture_list)),
350 for result
in result_list:
353 f
"\n\n--> Fracture number {result[0]} failed with error {result[1]}\n"
357 -1 - error making symbolic link
358 -2 - run failed in Poisson Sampling
359 -3 - run failed to produce mesh files
360 -4 - line of intersection not preserved
365 elapsed = timeit.default_timer() - t_all
367 if os.path.isfile(
"failure.txt"):
368 failure_list = genfromtxt(
"failure.txt")
370 if type(failure_list)
is list:
371 failure_list = sort(failure_list)
373 print(
'--> Fractures:', failure_list,
'Failed')
374 print(
'--> Main process exiting.')
378 print(
'--> Triangulating Polygons: Complete')
380 time_min = elapsed / 60
381 time_hrs = elapsed / 3600
383 print(
"--> Total Time to Mesh Network:")
385 f
"--> {time_sec:.2e} seconds\t{time_min:.2e} minutes\t{time_hrs:.2e} hours"
393 """Parallel worker for merge meshes into final mesh
402 bool : True if failed / False if successful
408 print(f
"--> Starting merge: {job}")
409 tic = timeit.default_timer()
411 if mh.run_lagrit_script(f
"lagrit_scripts/merge_poly_part_{job}.lgi",
412 f
"lagrit_logs/log_merge_poly_part{job}.out",
414 print(f
"Error {job} failed")
417 elapsed = timeit.default_timer() - tic
419 f
"--> Merge Number {job} Complete. Time elapsed: {elapsed:.2f} seconds."
425 """Runs the LaGrit Scripts to merge meshes into final mesh
434 Number of mesh pieces
436 True/False for reduced meshing
444 Meshes are merged in batches for efficiency
449 f
"--> Merging triangulated fracture meshes using {n_jobs} processor."
453 f
"--> Merging triangulated fracture meshes using {n_jobs} processors."
456 jobs = range(1, n_jobs + 1)
457 tic = timeit.default_timer()
459 pool = mp.Pool(num_cpu)
460 outputs = pool.map(merge_worker, jobs)
464 elapsed = timeit.default_timer() - tic
466 f
"\n--> Initial merging complete. Time elapsed: {elapsed:.2f} seconds.\n"
468 for output
in outputs:
470 error =
"ERROR!!! One of the merges failed\nExiting\n"
471 sys.stderr.write(error)
475 print(
"--> Starting Final Merge")
476 tic = timeit.default_timer()
478 mh.run_lagrit_script(
'lagrit_scripts/merge_rmpts.lgi',
479 'lagrit_logs/log_merge_all.out',
482 elapsed = timeit.default_timer() - tic
483 print(f
"--> Final merge took {elapsed:.2f} seconds")
486 if (os.stat(
"full_mesh.lg").st_size > 0):
487 print(
"--> Final merge successful")
490 error =
"ERROR: Final merge Failed\n"
491 sys.stderr.write(error)
495 if os.stat(
"reduced_mesh.inp").st_size > 0:
496 print(
"--> Final merge successful")
498 error =
"ERROR: Final merge Failed\n"
499 sys.stderr.write(error)
def mesh_fracture(fracture_id, visual_mode, num_poly)
def mesh_fractures_header(fracture_list, ncpu, visual_mode, h)
def cleanup_failed_run(fracture_id, digits, quiet=True)
def merge_the_meshes(num_poly, ncpu, n_jobs, visual_mode)