2 .. module:: map2continuum.py
3 :synopsis: Produce octree-refined continuum mesh replacing dfn
4 .. moduleauthor:: Matthew Sweeney <msweeney2796@lanl.gov>
15 import multiprocessing
as mp
20 """ This function generates an octree-refined continuum mesh using the
21 reduced_mesh.inp as input. To generate the reduced_mesh.inp, one must
22 turn visualization mode on in the DFN input card.
29 Size (m) of level-0 mesh element in the continuum mesh
31 Number of total refinement levels in the octree
33 path to primary DFN directory
35 name of directory where the octree mesh is created
43 octree_dfn.inp : Mesh file
44 Octree-refined continuum mesh
45 fracX.inp : Mesh files
46 Octree-refined continuum meshes, which contain intersection areas
50 print(
"Meshing Continuum Using LaGrit : Starting")
53 if type(orl)
is not int
or orl < 1:
54 error =
"ERROR: orl must be positive integer. Exiting"
55 sys.stderr.write(error)
59 normal_vectors = np.genfromtxt(path +
'normal_vectors.dat', delimiter=
' ')
61 with open(path +
'translations.dat')
as old, open(
'points.dat',
67 points = np.genfromtxt(
'points.dat', skip_header=0, delimiter=
' ')
70 os.symlink(path +
'params.txt',
'params.txt')
73 num_poly, h, _, _, domain = mh.parse_params_file()
76 x0 = 0 - (domain[
'x'] / 2.0)
77 x1 = 0 + (domain[
'x'] / 2.0)
78 y0 = 0 - (domain[
'y'] / 2.0)
79 y1 = 0 + (domain[
'y'] / 2.0)
80 z0 = 0 - (domain[
'z'] / 2.0)
81 z1 = 0 + (domain[
'z'] / 2.0)
84 nx = domain[
'x'] / l + 1
85 ny = domain[
'y'] / l + 1
86 nz = domain[
'z'] / l + 1
88 if nx * ny * nz > 1e8:
89 error =
"ERROR: Number of elements > 1e8. Exiting"
90 sys.stderr.write(error)
93 print(
"\nCreating *.lgi files for octree mesh\n")
97 shutil.rmtree(dir_name)
100 lagrit_driver(dir_name, nx, ny, nz, num_poly, normal_vectors, points)
101 lagrit_parameters(dir_name, orl, x0, x1, y0, y1, z0, z1, nx, ny, nz, h)
112 """ This function creates the main lagrit driver script, which calls all
118 Name of working directory
120 Number of cells in each direction
123 normal_vectors : array
124 Array containing normal vectors of each fracture
126 Array containing a point on each fracture
137 xn, yn, zn, xp, yp, zp = 0, 0, 0, 0, 0, 0
140 for i
in range(1, int(num_poly + 2)):
141 if j != num_poly + 1:
142 xn = normal_vectors[j - 1][0]
143 yn = normal_vectors[j - 1][1]
144 zn = normal_vectors[j - 1][2]
145 xp = points[j - 1][0]
146 yp = points[j - 1][1]
147 zp = points[j - 1][2]
148 floop +=
"""cmo / create / FRACTURE{0}
149 cmo / copy / FRACTURE{0} / MODFN
150 cmo / select / FRACTURE{0}
151 pset / pdel / attribute imt / 1 0 0 / ne / {0}
152 rmpoint pset, get, pdel
156 eltset / edel / itetclr / ne / {0}
157 rmpoint element eltset, get, edel
160 eltset / edel / delete
162 intersect_elements / mohex2 / FRACTURE{0} / if_int
163 eltset / erefine / if_int / ne / 0
164 pset / pinter / eltset erefine
166 cmo / create / temp{0}
167 cmo / copy / temp{0} / mohex2
168 cmo / select / temp{0}
169 pset / pdel / if_int / 1 0 0 / eq / 0
170 rmpoint, pset, get, pdel
174 eltset / edel / if_int / eq / 0
175 rmpoint element eltset, get, edel
178 eltset / edel / delete
179 cmo / setatt / temp{0} / itetclr / 1 0 0 / {0}
180 cmo / setatt / temp{0} / imt / 1 0 0 / {0}
182 cmo / create / TETCOPY
183 cmo / copy / TETCOPY / MOTET
184 cmo / select / TETCOPY
185 interpolate / map / TETCOPY / itetclr / 1 0 0 / temp{0} / itetclr
186 compute / distance_field / TETCOPY / temp{0} /dfield
187 cmo / select / TETCOPY
188 pset / pfrac / attribute / dfield / 1 0 0 / le / 1.e-8
189 cmo / setatt / TETCOPY / imt / 1 0 0 / {1}
190 cmo / setatt / TETCOPY / imt / pset get pfrac / {0}
191 eltset / etemp / itetclr / ne / {0}
192 cmo / setatt / TETCOPY / itetclr / eltset get etemp / {1}
193 eltset / etemp / delete
194 pset / pfrac / delete
196 cmo / set_id / MOTET_np1 / element / id_cell
197 cmo / set_id / MOTET_np1 / node / id_vertex
199 extract / plane / ptnorm / &
202 1 0 0 / moext / MOTET_np1
206 cmo / DELATT / moext / id_cell
207 cmo / DELATT / moext / id_parent
208 dump / avs2 / ex_xyz{0}.table / moext 0 0 0 1
210 cmo / addatt / moext / volume / area_tri
211 cmo / DELATT / moext / xmed
212 cmo / DELATT / moext / ymed
213 cmo / DELATT / moext / zmed
214 dump / avs2 / ex_area{0}.table / moext 0 0 0 1
217 cmo / select / TETCOPY
218 cmo / DELATT / TETCOPY / icr1
219 cmo / DELATT / TETCOPY / itp1
220 cmo / DELATT / TETCOPY / isn1
222 dump / avs2 / frac{0}.inp / TETCOPY
223 cmo / delete / temp{0}
224 cmo / delete / TETCOPY
226 cmo / select / mohex2
227 cmo / setatt / mohex2 / itetclr / eltset get erefine / {0}
228 cmo / setatt / mohex2 / imt / pset get pinter / {0}
229 eltset / erefine / delete
230 pset / pinter / delete
231 cmo / DELATT / mohex2 / if_int
232 cmo / delete / FRACTURE{0}
233 """.format(j, num_poly + 1, xp, yp, zp, xn, yn, zn)
236 f_name = f
'{dir_name}/driver_octree.lgi'
237 f = open(f_name,
'w')
239 # LaGriT control files to build an octree refined hex mesh with refinement
240 # based on intersection of hex mesh with a DFN triangulation mesh
243 # parameters_octree_dfn.mlgi
245 # intersect_refine.mlgi
249 # Define some parameters
251 infile parameters_octree_dfn.mlgi
255 read / FTYPE / FNAME / MODFN
256 cmo / printatt / MODFN / -xyz- / minmax
258 # Octree refined orthogonal mesh based on intersection with DFN mesh
260 infile build_octree.mlgi
262 # Identify cells in hex mesh that are intersected by DFN mesh
264 # This is the last pass through intersect_elements in order to figure out
265 # which cells in the fully refined hex mesh are intersected by the dfn mesh
267 intersect_elements / MOHEX / MODFN / if_int
268 eltset / einter / if_int / ne / 0
269 pset / pinter / eltset einter
271 # Use the itetclr(cell) and imt(vertex) attribute to hold the information
273 cmo / setatt / MOHEX / itetclr / 1 0 0 / 1
274 cmo / setatt / MOHEX / itetclr / eltset get einter / 2
275 cmo / setatt / MOHEX / imt / 1 0 0 / 1
276 cmo / setatt / MOHEX / imt / pset get pinter / 2
278 # Output final hex mesh
280 #dump / avs2 / tmp_hex_refine.inp / MOHEX
282 # Same as above but for np1 hex mesh
284 intersect_elements / MOHEX_np1 / MODFN / if_int
285 eltset / einter / if_int / ne / 0
286 pset / pinter / eltset einter
290 cmo / setatt / MOHEX_np1 / itetclr / 1 0 0 / 1
291 cmo / setatt / MOHEX_np1 / itetclr / eltset get einter / 2
292 cmo / setatt / MOHEX_np1 / imt / 1 0 0 / 1
293 cmo / setatt / MOHEX_np1 / imt / pset get pinter / 2
294 #dump / avs2 / tmp_hex_np1_refine.inp / MOHEX_np1
296 # Convert the hex mesh to a tet mesh
298 infile hex_to_tet.mlgi
300 # Modify the hex data structure from a full octree data structure
301 # to one in which only the highest level of refined hex is maintained
302 # and all parent cells are stripped out of the data structure
304 grid2grid / tree_to_fe / mohex2 / MOHEX
305 #dump / avs / octree_hex_mesh.inp / MOHEX
308 cmo / select / mohex2
310 # Remove all but the most refined hex cells
312 loop / do / NTIMES / 0 N_OCTREE_REFINE_M1 1 / loop_end &
313 infile remove_cells.mlgi
315 cmo / select / mohex2
316 cmo / DELATT / mohex2 / if_int
317 intersect_elements / mohex2 / MODFN / if_int
318 cmo / select / mohex2
319 eltset / edelete / if_int / eq / 0
320 rmpoint / element / eltset get edelete
321 eltset / edelete / release
324 # NOTE: I commented out the following lines for unknown but seemingly
327 #cmo / setatt / mohex2 / itetclr / 1 0 0 / 1
328 #cmo / setatt / mohex2 / imt / 1 0 0 / 1
331 #dump / avs / tmp_remove_cells.inp / mohex2
332 #dump / avs / tmp_tet.inp / MOTET
334 interpolate / map / MOTET / itetclr / 1 0 0 / mohex2 / itetclr
335 compute / distance_field / MOTET / mohex2 / dfield
338 # This use of 1.e-8 is fine for now but might cause problems if the
339 # bounding box of the problem was very small (<1.e-7)
341 pset / pfrac / attribute / dfield / 1 0 0 / le / 1.e-8
342 cmo / setatt / MOTET / imt / 1 0 0 / 2
343 cmo / setatt / MOTET / imt / pset get pfrac / 1
345 cmo / modatt / MOTET / itp / ioflag / l
346 cmo / modatt / MOTET / isn / ioflag / l
347 cmo / modatt / MOTET / icr / ioflag / l
349 dump / pflotran / full_mesh / MOTET / nofilter_zero
350 dump / avs2 / octree_dfn.inp / MOTET
351 dump / coord / octree_dfn / MOTET
352 dump / stor / octree_dfn / MOTET
353 dump / zone_imt / octree_dfn / MOTET
354 dump / zone_outside / octree_dfn / MOTET
357 define / FOUT / pboundary_top
358 pset / top / attribute / zic / 1 0 0 / gt / ZMAX
359 pset / top / zone / FOUT / ascii / ZONE
362 define / FOUT / pboundary_bottom
363 pset / bottom / attribute / zic / 1 0 0 / lt / ZMIN
364 pset / bottom / zone / FOUT / ascii / ZONE
367 define / FOUT / pboundary_left_w
368 pset / left_w / attribute / xic / 1 0 0 / lt / XMIN
369 pset / left_w / zone / FOUT / ascii / ZONE
372 define / FOUT / pboundary_front_n
373 pset / front_n / attribute / yic / 1 0 0 / gt / YMAX
374 pset / front_n / zone / FOUT / ascii / ZONE
377 define / FOUT / pboundary_right_e
378 pset / right_e / attribute / xic / 1 0 0 / gt / XMAX
379 pset / right_e / zone / FOUT / ascii / ZONE
382 define / FOUT / pboundary_back_s
383 pset / back_s / attribute / yic / 1 0 0 / lt / YMIN
384 pset / back_s / zone / FOUT / ascii / ZONE
387 # Work around for getting *.fehnm file
390 cmo / setatt / MOTET / itetclr / 1 0 0 / 1
391 cmo / setatt / MOTET / imt / 1 0 0 / 1
393 dump / fehm / tmp_tmp_ / MOTET
400 print(
"Creating driver_octree.lgi file: Complete\n")
403 def lagrit_parameters(dir_name, orl, x0, x1, y0, y1, z0, z1, nx, ny, nz, h):
404 """ This function creates the parameters_octree_dfn.mlgi lagrit script.
409 Name of working directory
411 Number of total refinement levels in the octree
413 Extent of domain in x, y, z directions
415 Number of cells in each direction
425 f_name = f
'{dir_name}/parameters_octree_dfn.mlgi'
426 f = open(f_name,
'w')
428 # Define some parameters
433 define / FNAME / reduced_mesh.inp
435 define / MOHEX / mohex
436 define / MOTET / motet
438 # Set AMR refinement. 123 means refine in x,y,z directions
439 # See LaGriT refine command for more options
441 define / REFINE_AMR / 123
446 f.write(
'define / N_OCTREE_REFINE / %d \n' % orl)
447 f.write(
'define / N_OCTREE_REFINE_M1 / %d \n' % (orl - 1))
448 f.write(
'define / N_OCTREE_np1 / %d \n' % (orl + 1))
449 f.write(
'define / N_OCTREE_np1_M1 / %d \n' % (orl))
450 f.write(
'define / X0 / %0.12f \n' % x0)
451 f.write(
'define / X1 / %0.12f \n' % x1)
452 f.write(
'define / Y0 / %0.12f \n' % y0)
453 f.write(
'define / Y1 / %0.12f \n' % y1)
454 f.write(
'define / Z0 / %0.12f \n' % z0)
455 f.write(
'define / Z1 / %0.12f \n' % z1)
456 f.write(
'define / XMAX / %0.12f \n' % (x1 - eps))
457 f.write(
'define / XMIN / %0.12f \n' % (x0 + eps))
458 f.write(
'define / YMAX / %0.12f \n' % (y1 - eps))
459 f.write(
'define / YMIN / %0.12f \n' % (y0 + eps))
460 f.write(
'define / ZMAX / %0.12f \n' % (z1 - eps))
461 f.write(
'define / ZMIN / %0.12f \n' % (z0 + eps))
462 f.write(
'define / NX / %d \n' % nx)
463 f.write(
'define / NY / %d \n' % ny)
464 f.write(
'define / NZ / %d \n' % nz)
468 print(
"Creating parameters_octree_dfn.mlgi file: Complete\n")
472 """ This function creates the build_octree.mlgi lagrit script.
477 name of working directory
488 f_name = f
'{dir_name}/build_octree.mlgi'
489 f = open(f_name,
'w')
490 fin =
"""cmo / create / MOHEX / / / hex
491 createpts / brick / xyz / NX NY NZ / X0 Y0 Z0 / X1 Y1 Z1 / 1 1 1
492 cmo / setatt / MOHEX / imt / 1 0 0 / 1
493 cmo / setatt / MOHEX / itetclr / 1 0 0 / 1
496 # Print to screen and logfiles the extents of the hex mesh and dfn mesh
498 cmo / printatt / MOHEX / -xyz- / minmax
500 cmo / printatt / MODFN / -xyz- / minmax
502 # Generate copy of hex mesh for upscaling
504 cmo / copy / MOHEX_np1 / MOHEX
506 # Loop through steps to intersect dfn mesh (MODFN) with hex mesh (MOHEX)
507 # and refine hex mesh based on cell intersections. Loop through
508 # N_OCTREE_REFINE times
510 loop / do / NTIMES / 1 N_OCTREE_REFINE 1 / loop_end &
511 infile intersect_refine.mlgi
513 # See above - except do it once additional time ("np1")
515 loop / do / NTIMEs / 1 N_OCTREE_np1 1 / loop_end &
516 infile intersect_refine_np1.mlgi
523 print(
"Creating build_octree.mlgi file: Complete\n")
527 """ This function creates the intersect_refine.mlgi lagrit scripts.
532 name of working directory
543 f_name = f
'{dir_name}/intersect_refine.mlgi'
544 f = open(f_name,
'w')
546 # Compute mesh to mesh intersection and refine hex mesh
548 intersect_elements / MOHEX / MODFN / if_int
549 eltset / erefine / if_int / ne / 0
550 pset / prefine / eltset erefine
552 # If one wants anisotropic mesh refinement, then the
553 # variable REFINE_AMR can be set in parameters_octree_dfn.mlgi
555 refine/constant/imt1/linear/element/pset,get,prefine/ &
556 -1.,0.,0./exclusive/amr REFINE_AMR
558 # Clean up eltset, pset, and if_int attribute
560 eltset / erefine / delete
561 pset / prefine / delete
562 cmo / DELATT / MOHEX / if_int
564 # Print out diagnostics
574 print(
"Creating intersect_refine.mlgi file: Complete\n")
575 f_name = f
'{dir_name}/intersect_refine_np1.mlgi'
576 f = open(f_name,
'w')
578 # For comments see intersect_refine.mlgi
580 intersect_elements / MOHEX_np1 / MODFN / if_int
581 eltset / erefine / if_int / ne / 0
582 pset / prefine / eltset erefine
583 refine/constant/imt1/linear/element/pset,get,prefine/ &
584 -1.,0.,0./exclusive/amr REFINE_AMR
586 eltset / erefine / delete
587 pset / prefine / delete
588 cmo / DELATT / MOHEX_np1 / if_int
598 print(
"Creating intersect_refine_np1.mlgi file: Complete\n")
602 """ This function creates the hex_to_tet.mlgi lagrit script.
607 name of working directory
618 f_name = f
'{dir_name}/hex_to_tet.mlgi'
619 f = open(f_name,
'w')
621 # Convert the octree hex mesh to tet mesh by connecting the
622 # octree vertex collection to a Delaunay mesh
625 copypts / MOTET / MOHEX
629 cmo / setatt / MOTET / imt / 1 0 0 / 1
630 cmo / setatt / MOTET / itp / 1 0 0 / 0
632 # Sort and reorder the nodes based on coordinates
634 sort / MOTET / index / ascending / ikey / xic yic zic
635 reorder / MOTET / ikey
636 cmo / DELATT / MOTET / ikey
641 cmo / setatt / MOTET / itetclr / 1 0 0 / 1
644 # Do the same for np1 mesh
646 cmo / create / MOTET_np1
647 copypts / MOTET_np1 / MOHEX_np1
648 cmo / select / MOTET_np1
651 cmo / setatt / MOTET_np1 / imt / 1 0 0 / 1
652 cmo / setatt / MOTET_np1 / itp / 1 0 0 / 0
656 sort / MOTET_np1 / index / ascending / ikey / xic yic zic
657 reorder / MOTET_np1 / ikey
658 cmo / DELATT / MOTET_np1 / ikey
661 cmo / setatt / MOTET_np1 / itetclr / 1 0 0 / 1
669 print(
"Creating hex_to_tet.mlgi file: Complete\n")
673 """ This function creates the remove_cells.mlgi lagrit script.
678 name of working directory
689 f_name = f
'{dir_name}/remove_cells.mlgi'
690 f = open(f_name,
'w')
692 # Remove cells from hex mesh based on the level of refinement
693 # itetlev is the refinement level. Original mesh itetlev=0
695 eltset / edelete / itetlev / eq / NTIMES
696 rmpoint / element / eltset get edelete
697 eltset / edelete / release
705 print(
"Creating remove_cells.mlgi file: Complete\n")
709 """ This function executes the lagrit scripts.
727 if os.path.isfile(path +
"reduced_mesh.inp"):
728 os.symlink(path +
"reduced_mesh.inp",
"reduced_mesh.inp")
729 elif os.path.isfile(path +
"../" +
"reduced_mesh.inp"):
730 os.symlink(path +
"../" +
"reduced_mesh.inp",
"reduced_mesh.inp")
732 error =
"ERROR!!! Reduced Mesh not found. Please run mesh_dfn with visual_mode=True.\nExiting"
733 sys.stderr.write(error)
736 mh.run_lagrit_script(
"driver_octree.lgi")
742 """ This function strips and replaces the headers of the files, which is
743 needed to assign the fracture areas to a mesh object.
760 for i
in range(1, num_poly + 1):
761 with open(
'ex_xyz{0}.table'.format(i),
'r')
as infile:
762 for k, l
in enumerate(infile):
764 node_dict.setdefault(i, []).append(k - 4)
767 for i
in range(1, num_poly + 1):
768 with open(
'ex_xyz{0}.table'.format(i),
'r')
as infile:
769 with open(
'ex_xyz{0}_2.inp'.format(i),
'w')
as outfile:
770 for j, line
in enumerate(infile):
772 outfile.write(
"{0} 0 0 0 0\n".format(node_dict[i][0]))
777 with open(
'ex_area{0}.table'.format(i),
'r')
as infile:
778 with open(
'ex_area{0}_2.table'.format(i),
'w')
as outfile:
779 for j, line
in enumerate(infile):
781 outfile.write(line.split()[1])
788 """ This function drives the parallelization of the area sums upscaling.
806 frac_index = range(1, int(num_poly + 1))
807 number_of_task = len(frac_index)
808 number_of_processes = self.ncpu
809 tasks_to_accomplish = mp.Queue()
810 tasks_that_are_done = mp.Queue()
813 for i
in range(number_of_task):
814 tasks_to_accomplish.put(i + 1)
817 for w
in range(number_of_processes):
818 p = mp.Process(target=worker,
819 args=(tasks_to_accomplish, tasks_that_are_done))
822 tasks_to_accomplish.put(
'STOP')
827 while not tasks_that_are_done.empty():
828 print(tasks_that_are_done.get())
834 """ Generates lagrit script that makes mesh files with area sums.
850 fname =
'driver{0}.lgi'.format(f_id)
853 fin +=
"""read / avs / ex_xyz{0}_2.inp / mo_vertex
854 cmo / addatt / mo_vertex / area_tri / vdouble / scalar / nnodes
855 cmo / readatt / mo_vertex / area_tri / 1 0 0 / ex_area{0}_2.table
857 read / avs / frac{0}.inp / frac
858 cmo / addatt / frac / area_sum / vdouble / scalar / nnodes
860 upscale / sum / frac, area_sum / 1 0 0 / mo_vertex, area_tri
861 dump / avs / area_sum{0}.inp / frac
863 cmo / delete / mo_vertex
874 mh.run_lagrit_script(
"driver{0}.lgi".format(f_id))
877 def worker(tasks_to_accomplish, tasks_that_are_done):
878 """ Worker function for python parallel. See multiprocessing module
879 documentation for details.
883 tasks_to_accomplish : ?
884 Processes still in queue
885 tasks_that_are_done : ?
894 for f_id
in iter(tasks_to_accomplish.get,
'STOP'):
def lagrit_parameters(dir_name, orl, x0, x1, y0, y1, z0, z1, nx, ny, nz, h)
def driver_parallel(self, num_poly)
def worker(tasks_to_accomplish, tasks_that_are_done)
def lagrit_run(path, dir_name)
def lagrit_hex_to_tet(dir_name)
def upscale_parallel(f_id)
def lagrit_strip(num_poly)
def lagrit_intersect(dir_name)
def lagrit_build(dir_name)
def lagrit_driver(dir_name, nx, ny, nz, num_poly, normal_vectors, points)
def map_to_continuum(self, l, orl, path="./", dir_name="octree")
def lagrit_remove(dir_name)