pydfnWorks
python wrapper for dfnWorks
lagrit_scripts_poisson_disc.py
Go to the documentation of this file.
1 """
2 .. module:: lagrit_scripts.py
3  :synopsis: create lagrit scripts for meshing dfn using LaGriT
4 .. moduleauthor:: Jeffrey Hyman <jhyman@lanl.gov>
5 
6 """
7 import os
8 import sys
9 import glob
10 from shutil import copy, rmtree, move
11 from numpy import genfromtxt, sqrt, cos, arcsin
12 import subprocess
13 
14 from pydfnworks.dfnGen.meshing import mesh_dfn_helper as mh
15 
16 
17 def edit_intersection_files(num_poly, fracture_list, path):
18  """ If pruning a DFN, this function walks through the intersection files
19  and removes references to files that are not included in the
20  fractures that will remain in the network.
21 
22  Parameters
23  ---------
24  num_poly : int
25  Number of Fractures in the original DFN
26  fracture_list :list of int
27  List of fractures to keep in the DFN
28 
29  Returns
30  -------
31  None
32 
33  Notes
34  -----
35  1. Currently running in serial, but it could be parallelized
36  2. Assumes the pruning directory is not the original directory
37 
38  """
39  # Make list of connectivity.dat
40  connectivity = []
41  fp = open("connectivity.dat", "r")
42  for i in range(num_poly):
43  tmp = []
44  line = fp.readline()
45  line = line.split()
46  for frac in line:
47  tmp.append(int(frac))
48  connectivity.append(tmp)
49  fp.close()
50 
51  fractures_to_remove = list(
52  set(range(1, num_poly + 1)) - set(fracture_list))
53  cwd = os.getcwd()
54  os.chdir('intersections')
55  # clean up directory
56  #fl_list = glob.glob("*prune.inp")
57  #for fl in fl_list:
58  # os.remove(fl)
59 
60  print("--> Editing Intersection Files")
61 
62  for i in fracture_list:
63  filename = f'intersections_{i}.inp'
64  print(f'--> Working on: {filename}')
65  intersecting_fractures = connectivity[i - 1]
66  pull_list = list(
67  set(intersecting_fractures).intersection(set(fractures_to_remove)))
68  if len(pull_list) > 0:
69  # Create Symlink to original intersection file
70  os.symlink(path + 'intersections/' + filename, filename)
71  # Create LaGriT script to remove intersections with fractures not in prune_file
72  lagrit_script = f"""
73 read / {filename} / mo1
74 pset / pset2remove / attribute / b_a / 1,0,0 / eq / {pull_list[0]}
75 """
76  for j in pull_list[1:]:
77  lagrit_script += f'''
78 pset / prune / attribute / b_a / 1,0,0 / eq / {j}
79 pset / pset2remove / union / pset2remove, prune
80 rmpoint / pset, get, prune
81 pset / prune / delete
82  '''
83  lagrit_script += f'''
84 rmpoint / pset, get, pset2remove
85 rmpoint / compress
86 
87 cmo / modatt / mo1 / imt / ioflag / l
88 cmo / modatt / mo1 / itp / ioflag / l
89 cmo / modatt / mo1 / isn / ioflag / l
90 cmo / modatt / mo1 / icr / ioflag / l
91 
92 cmo / status / brief
93 dump / intersections_{i}_prune.inp / mo1
94 finish
95 
96 '''
97 
98  lagrit_filename = 'prune_intersection.lgi'
99  f = open(lagrit_filename, 'w')
100  f.write(lagrit_script)
101  f.flush()
102  f.close()
103  mh.run_lagrit_script("prune_intersection.lgi",
104  f"out_{i}.txt",
105  quiet=True)
106  os.remove(filename)
107  move(f"intersections_{i}_prune.inp", f"intersections_{i}.inp")
108  else:
109  try:
110  copy(path + 'intersections/' + filename, filename)
111  except:
112  pass
113  os.chdir(cwd)
114 
115 
116 def create_parameter_mlgi_file(fracture_list, h, slope=2.0, refine_dist=0.5):
117  """Create parameteri.mlgi files used in running LaGriT Scripts
118 
119  Parameters
120  ----------
121  num_poly : int
122  Number of polygons
123  h : float
124  Meshing length scale
125  slope : float
126  Slope of coarsening function, default = 2
127  refine_dist : float
128  Distance used in coarsening function, default = 0.5
129 
130  Returns
131  -------
132  None
133 
134  Notes
135  -----
136  Set slope = 0 for uniform mesh
137  """
138 
139  print("\n--> Creating parameter*.mlgi files")
140  try:
141  os.mkdir('parameters')
142  except OSError:
143  rmtree('parameters')
144  os.mkdir('parameters')
145 
146  # Extrude and Translate computation
147  # Parameters, delta: buffer zone, amount of h/2 we remove from around line
148  # h_extrude height of rectangle extruded from line of intersection
149  # r_radius: Upper bound on radius of circumscribed circle around rectangle
150  # h_trans : amount needed to translate to create delta buffer
151  # It's just a little trig!
152  delta = 0.75
153  h_extrude = 0.5 * h # upper limit on spacing of points on intersection line
154  h_radius = sqrt((0.5 * h_extrude)**2 + (0.5 * h_extrude)**2)
155  h_trans = -0.5 * h_extrude + h_radius * cos(arcsin(delta))
156 
157  #Go through the list and write out parameter file for each polygon
158  #to be an input file for LaGriT
159  data = genfromtxt('poly_info.dat')
160 
161  for index, i in enumerate(fracture_list):
162  # using i - 1 do to python indexing from 0
163  # fracture index starts at 1
164  frac_id = str(int(data[i - 1, 0]))
165  long_name = str(int(data[i - 1, 0]))
166 
167  theta = data[i - 1, 2]
168  x1 = data[i - 1, 3]
169  y1 = data[i - 1, 4]
170  z1 = data[i - 1, 5]
171  x2 = data[i - 1, 6]
172  y2 = data[i - 1, 7]
173  z2 = data[i - 1, 8]
174  family = data[i - 1, 1]
175 
176  fparameter_name = 'parameters/parameters_' + long_name + '.mlgi'
177  f = open(fparameter_name, 'w')
178  f.write('define / ID / ' + str(index + 1) + '\n')
179  f.write('define / OUTFILE_GMV / mesh_' + long_name + '.gmv\n')
180  f.write('define / OUTFILE_AVS / mesh_' + long_name + '.inp\n')
181  f.write('define / OUTFILE_LG / mesh_' + long_name + '.lg\n')
182  f.write('define / POLY_FILE / poly_' + long_name + '.inp\n')
183  f.write('define / QUAD_FILE / tmp_quad_' + frac_id + '.inp\n')
184  f.write('define / EXCAVATE_FILE / tmp_excavate_' + frac_id + '.inp\n')
185  f.write('define / PRE_FINAL_FILE / tmp_pre_final_' + frac_id +
186  '.inp\n')
187  f.write('define / PRE_FINAL_MASSAGE / tmp_pre_final_massage_' +
188  frac_id + '.gmv\n')
189 
190  f.write('define / H_SCALE / %e \n' % h)
191  f.write('define / H_EPS / %e \n' % (h * 10**-7))
192  f.write('define / H_SCALE2 / %e \n' % (1.5 * h))
193 
194  f.write('define / H_EXTRUDE / %e \n' % (h_extrude))
195  f.write('define / H_TRANS / %f \n' % (h_trans))
196 
197  f.write('define / H_PRIME / %e \n' % (0.4 * h))
198 
199  # f.write('define / H_SCALE3 / %e \n' % (3.0 * h))
200  # f.write('define / H_SCALE8 / %e \n' % (8.0 * h))
201  # f.write('define / H_SCALE16 / %e \n' % (16.0 * h))
202  # f.write('define / H_SCALE32 / %e \n' % (32.0 * h))
203  # f.write('define / H_SCALE64 / %e \n' % (64.0 * h))
204 
205  # f.write('define / PERTURB8 / %e \n' % (8 * 0.05 * h))
206  # f.write('define / PERTURB16 / %e \n' % (16 * 0.05 * h))
207  # f.write('define / PERTURB32 / %e \n' % (32 * 0.05 * h))
208  # f.write('define / PERTURB64 / %e \n' % (64 * 0.05 * h))
209 
210  # f.write('define / PARAM_A / %f \n' % slope)
211  # f.write('define / PARAM_B / %f \n' % (h * (1 - slope * refine_dist)))
212 
213  # f.write('define / PARAM_A2 / %f \n' % (0.5 * slope))
214  # f.write('define / PARAM_B2 / %f \n' %
215  # (h * (1 - 0.5 * slope * refine_dist)))
216 
217  f.write('define / THETA / %0.12f \n' % theta)
218  f.write('define / X1 / %0.12f \n' % x1)
219  f.write('define / Y1 / %0.12f \n' % y1)
220  f.write('define / Z1 / %0.12f \n' % z1)
221  f.write('define / X2 / %0.12f \n' % x2)
222  f.write('define / Y2 / %0.12f \n' % y2)
223  f.write('define / Z2 / %0.12f \n' % z2)
224  f.write('define / FAMILY / %d \n' % family)
225  f.write('finish \n')
226  f.flush()
227  f.close()
228 
229 
230 # lagrit_input = f"""
231 # define / ID / {index + 1}
232 # define / OUTFILE_AVS / mesh_{long_name}.inp
233 # define / OUTFILE_LG / mesh_{long_name}.lg
234 # define / POLY_FILE / poly_{long_name}.inp
235 
236 # define / H_SCALE / {h:e}
237 # define / H_EPS / {h*10**-7:0.12e}
238 # define / H_SCALE2 / {h*1.5:0.12e}
239 # define / H_EXTRUDE / {h_extrude:0.12e}
240 # define / H_TRANS / {h_trans:0.12e}
241 # define / H_PRIME / {0.8*h:0.12e}
242 
243 # define / THETA / {theta:0.12f}
244 # define / X1 / {x1:0.12f}
245 # define / Y1 / {y1:0.12f}
246 # define / Z1 / {z1:0.12f}
247 
248 # define / X2 / {x2:0.12f}
249 # define / Y2 / {y2:0.12f}
250 # define / Z2 / {z2:0.12f}
251 # define / FAMILY / {family}
252 
253 # finish
254 
255 # # """
256 # with open(f'parameters/parameters_{long_name}.mlgi', 'w') as fp:
257 # fp.write(lagrit_input)
258 # fp.flush()
259 # fp.close()
260 
261  print("--> Creating parameter*.mlgi files: Complete\n")
262 
263 
264 def create_lagrit_scripts_poisson(fracture_list):
265  """ Creates LaGriT script to be mesh each polygon using Poisson-Disc
266  sampling method
267 
268  Parameters
269  ----------
270  fracture_list : list
271  list of fracture numbers to be meshed
272 
273  Returns
274  -------
275  None
276 
277  Notes
278  -----
279 
280  """
281 
282  #Section 2 : Creates LaGriT script to be run for each polygon
283  #Switches to control the LaGriT output
284  #Network visualization mode True ouputs the triangulated mesh
285  #for each fracture without any refinement. The goal is to visualize
286  #the network structure instead of outputing the appropriate values
287  #for computation
288 
289  print("--> Writing LaGriT Control Files")
290  #Go through the list and write out parameter file for each polygon
291  #to be an input file for LaGriT
292 
293  lagrit_input = """
294 # This LaGriT Scripts reads in the points generated by the Poisson-Disc
295 # sampling method. Then it reads in the intersection points generated
296 # in dfnGEn. All points in the Poisson-Disc set that are too close to
297 # the line of intersection are removed. Then the mesh is written out
298 # in binary LaGriT and AVS UCD format.
299 
300 # LaGriT Parameter file
301 infile parameters_{0}.mlgi
302 
303 # Name of input files that contains the lines of intersection
304 # and Poisson Points
305 
306 define / POINT_FILE / points_{0}.xyz
307 define / LINE_FILE / intersections_{0}.inp
308 
309 # connectivity file used in mesh checking
310 define / OUTPUT_INTER_ID_SSINT / id_tri_node_{0}.list
311 
312 #### READ IN POISSON DISC POINTS
313 
314 # Create a mesh object named mo_pts
315 cmo / create / mo_pts / / / triplane
316 
317 # Read in the three column x,y,z vertex data
318 cmo / readatt / mo_pts / xic,yic,zic / 1,0,0 / POINT_FILE
319 
320 # Send some diagnostic output to the screen
321 cmo / status / brief
322 cmo / printatt / mo_pts / -xyz- / minmax
323 
324 # Set imt (integer material type) of all vertices to ID
325 cmo / setatt / mo_pts / imt / 1 0 0 / ID
326 # Set itp of all vertices to 0
327 cmo / setatt / mo_pts / itp / 1 0 0 / 0
328 
329 # This should not do anything. If there were 2 or more vertices within distance
330 # epsilon of one another, this would remove all but one. Since the distributions
331 # should be well behaved, it should not filter/delete any vertices.
332 
333 filter / 1 0 0
334 rmpoint / compress
335 #
336 # Connect the 2D planar (XY-plane) vertices to create a Delaunay triangular mesh
337 # with an exterior boundary that is the convex hull of the vertices in mo_pts.
338 connect
339 resetpts / itp
340 
341 # Diagnostic output to the screen on triangle aspect ratio and volume (area)
342 quality
343 
344 # Add cell attribute for area and aspect ratio
345 cmo / addatt / mo_pts / area / tri_area
346 quality / aspect / y
347 
348 # Apply two iterations of Laplace smoothing and Lawson flipping to smooth the mesh
349 # and recover the Delaunay triangulation.
350 assign///maxiter_sm/ 1
351 smooth;recon 0
352 smooth;recon 1
353 
354 ##### DEBUG #####
355 # comments out to dump poisson initial triangulation
356 # dump / avs2 / output_{0}.inp / mo_pts
357 ##### DEBUG #####
358 
359 ## Read the lines of intersections into mesh object mo_line_work
360 read / LINE_FILE / mo_line_work
361 
362 # Extrude the line mesh a distance H_EXTRUDE in the Z direction (vector 0.,0.,1.) to create a quad mesh.
363 extrude / mo_quad / mo_line_work / const / H_EXTRUDE / volume / 0. 0. 1.
364 
365 
366 # Translate extruded lines of intersection down slightly to excavate
367 # nearby points from the mesh
368 
369 trans / 1 0 0 / 0. 0. 0. / 0. 0. H_TRANS
370 hextotet / 2 / mo_tri / mo_quad
371 cmo / delete / mo_quad
372 # Remove (excavate) vertices from mo_pts that fall within the circumscribed sphere of any triangle in mo_tri.
373 # Place the result in mo_excavate.
374 addmesh / excavate / mo_excavate / mo_pts / mo_tri
375 
376 ##### DEBUG #####
377 # If meshing fails, uncomment and rerun the script to get tmp meshes,
378 # which are otherwise not output
379 #dump / avs2 / tmp_tri.inp / mo_tri / 1 1 1 0
380 #dump / avs2 / tmp_pts.inp / mo_pts / 1 1 1 0
381 #dump / avs2 / tmp_excavate.inp / mo_excavate / 1 1 1 0
382 ##### DEBUG #####
383 
384 cmo / delete / mo_tri
385 cmo / delete / mo_pts
386 
387 # recompute dfield
388 cmo / create / mo_final / / / triplane
389 copypts / mo_final / mo_excavate
390 # Compute the distance field between the vertices in mo_line_work (fracture intersections)
391 # and the vertices in mo_final (fracture mesh vertices).
392 compute / distance_field / mo_final / mo_line_work / dfield
393 # Output min/max values of distance field (dfield)
394 cmo / printatt / mo_final / dfield / minmax
395 pset / pdel / attribute dfield / 1,0,0 / lt H_PRIME
396 # Delete any vertices with distance field less than H_PRIME
397 rmpoint / pset,get,pdel / inclusive
398 rmpoint / compress
399 # Copy the intersection vertices into the fracture mesh mo_final
400 copypts / mo_final / mo_line_work
401 
402 cmo / select / mo_final
403 cmo / setatt / mo_final / imt / 1 0 0 / ID
404 cmo / setatt / mo_final / itp / 1 0 0 / 0
405 # cmo / printatt / mo_final / -xyz- / minmax
406 # Translate the vertices so the bounding box is centered on 0,0,0.
407 trans/ 1 0 0 / zero / xyz
408 # Due to slight numerical jitter, all Z values may not be 0. Set them to 0.
409 cmo / setatt / mo_final / zic / 1 0 0 / 0.0
410 cmo / printatt / mo_final / -xyz- / minmax
411 # Connect the 2D planar (XY-plane) vertices to create a Delaunay triangular mesh
412 # with an exterior boundary that is the convex hull of the vertices in mo_final.
413 connect
414 cmo / setatt / mo_final / itetclr / 1 0 0 / ID
415 resetpts / itp
416 # Translate back to the original coordinates.
417 trans / 1 0 0 / original / xyz
418 cmo / printatt / mo_final / -xyz- / minmax
419 
420 #cmo / delete / mo_line_work
421 cmo / delete / mo_excavate
422 cmo / select / mo_final
423 
424 ## Massage the mesh where vertices are are not on the boundary and
425 # not within a distance H_EPS of the intersection vertices.
426 pset / pref / attribute / dfield / 1,0,0 / lt / H_EPS
427 pset / pregion / attribute / dfield / 1,0,0 / gt / H_SCALE2
428 pset / pboundary / attribute / itp / 1,0,0 / eq / 10
429 pset / psmooth / not / pregion pref pboundary
430 
431 assign///maxiter_sm/1
432 smooth / position / esug / pset get psmooth
433 recon 0
434 smooth / position / esug / pset get psmooth
435 recon 0
436 smooth / position / esug / pset get psmooth
437 recon 1
438 assign///maxiter_sm/10
439 
440 
441 ###########################################
442 # nodes for Intersection / Mesh Connectivity Check dump
443 cmo / copy / mo_final_check / mo_final
444 #
445 # Define variables that are hard wired for this part of the workflow
446 define / MO_TRI_MESH_SSINT / mo_tri_tmp_subset
447 define / MO_LINE_MESH_SSINT / mo_line_tmp_subset
448 define / ATT_ID_INTERSECTION_SSINT / b_a
449 define / ATT_ID_SOURCE_SSINT / id_node_global
450 define / ATT_ID_SINK_SSINT / id_node_tri
451 #
452 # Before subsetting the mesh reate a node attribute containing the integer global node number
453 cmo / set_id / mo_final_check / node / ATT_ID_SOURCE_SSINT
454 #
455 # Subset the triangle mesh based on b_a node attribute ne 0
456 #
457 cmo / select / mo_final_check
458 pset / pkeep / attribute / ATT_ID_INTERSECTION_SSINT / 1 0 0 / ne / 0
459 pset / pall / seq / 1 0 0
460 pset / pdel / not pall pkeep
461 rmpoint / pset get pdel / exclusive
462 rmpoint / compress
463 #
464 # Create an integer node attribute in the line mesh to interpolate the triangle node number onto
465 #
466 cmo / addatt / mo_line_work / ATT_ID_SINK_SSINT / vint / scalar / nnodes
467 interpolate / voronoi / mo_line_work ATT_ID_SINK_SSINT / 1 0 0 / &
468  mo_final_check ATT_ID_SOURCE_SSINT
469 #
470 # Supress AVS output of a bunch of node attributes
471 #
472 cmo / modatt / mo_line_work / imt / ioflag / l
473 cmo / modatt / mo_line_work / itp / ioflag / l
474 cmo / modatt / mo_line_work / isn / ioflag / l
475 cmo / modatt / mo_line_work / icr / ioflag / l
476 cmo / modatt / mo_line_work / a_b / ioflag / l
477 cmo / modatt / mo_line_work / b_a / ioflag / l
478 #
479 # Output list of intersection nodes with the corresponding node id number from the triangle mesh
480 
481 dump / avs2 / OUTPUT_INTER_ID_SSINT / mo_line_work / 0 0 2 0
482 cmo / delete / mo_line_work
483 
484 cmo / delete / mo_final_check
485 # nodes for intersection check over
486 
487 cmo / select / mo_final
488 
489 ##### DEBUG ######
490 # Write out mesh before it is rotate back into its final location
491 # Useful to compare with meshing work-flow if something crashes
492 #dump / avs2 / tmp_mesh_2D.inp / mo_final / 1 1 1 0
493 ##### DEBUG #####
494 
495 # Rotate fracture back into original plane
496 rotateln / 1 0 0 / nocopy / X1, Y1, Z1 / X2, Y2, Z2 / THETA / 0.,0.,0.,/
497 cmo / printatt / mo_final / -xyz- / minmax
498 
499 # Create cell attributes, xnorm, ynorm, znorm, and fill them with the unit normal vector.
500 cmo / addatt / mo_final / unit_area_normal / xyz / vnorm
501 cmo / addatt / mo_final / scalar / xnorm ynorm znorm / vnorm
502 cmo / DELATT / mo_final / vnorm
503 
504 # Create Family element set
505 cmo / addatt / mo_final / family_id / vint / scalar / nelements
506 cmo / setatt / mo_final / family_id / 1 0 0 / FAMILY
507 
508 # Output mesh in AVS UCD format - required for connectivity checking, is promptly deleted
509 dump / OUTFILE_AVS / mo_final
510 # Output mesh in LaGriT binary format.
511 dump / lagrit / OUTFILE_LG / mo_final
512 
513 quality
514 cmo / delete / mo_final
515 cmo / status / brief
516 finish
517 
518 """
519 
520  if os.path.isdir('lagrit_scripts'):
521  rmtree("lagrit_scripts")
522  os.mkdir("lagrit_scripts")
523  else:
524  os.mkdir("lagrit_scripts")
525 
526  # Create a different run file for each fracture
527  for i in fracture_list:
528  file_name = 'lagrit_scripts/mesh_poly_{0}.lgi'.format(i)
529  with open(file_name, 'w') as f:
530  f.write(lagrit_input.format(i))
531  f.flush()
532  print('--> Writing LaGriT Control Files: Complete')
533 
534 
536  """ Creates LaGriT scripts to create a coarse (non-conforming)
537  mesh of each fracture.
538 
539  Parameters
540  ----------
541  fracture_list : list
542  list of fracture numbers to be meshed
543 
544  Returns
545  -------
546  None
547 
548  Notes
549  -----
550  """
551 
552  #Section 2 : Creates LaGriT script to be run for each polygon
553  #Switches to control the LaGriT output
554  #Network visualization mode True ouputs the triangulated mesh
555  #for each fracture without any refinement. The goal is to visualize
556  #the network structure instead of outputing the appropriate values
557  #for computation
558 
559  print("--> Writing LaGriT Control Files")
560 
561  lagrit_input = """
562 
563 # LaGriT Parameter file
564 infile parameters_{0}.mlgi
565 
566 # Name of input files that contains the boundary of the polygon/fracture
567 
568 define / POLY_FILE / poly_{0}.inp
569 
570 ## Triangulate Fracture perimeter without point addition
571 read / POLY_FILE / mo_poly_work
572 cmo / create / mo_pts / / / triplane
573 copypts / mo_pts / mo_poly_work
574 cmo / select / mo_pts
575 triangulate / counterclockwise
576 
577 cmo / setatt / mo_pts / imt / 1 0 0 / ID
578 cmo / setatt / mo_pts / itetclr / 1 0 0 / ID
579 resetpts / itp
580 cmo / delete / mo_poly_work
581 cmo / select / mo_pts
582 
583 # Create Family element set
584 cmo / addatt / mo_pts / family_id / vint / scalar / nelements
585 cmo / setatt / mo_pts / family_id / 1 0 0 / FAMILY
586 
587 # Rotate
588 rotateln / 1 0 0 / nocopy / X1, Y1, Z1 / X2, Y2, Z2 / THETA / 0.,0.,0.,/
589 # Supress AVS output of a icr and isn node attributes
590 cmo / modatt / mo_pts / icr1 / ioflag / l
591 cmo / modatt / mo_pts / isn1 / ioflag / l
592 cmo / copy/ mo_final /mo_pts
593 # Output mesh in AVS UCD format and LaGriT binary format.
594 dump / lagrit / OUTFILE_LG / mo_final
595 dump / OUTFILE_AVS / mo_final
596 finish
597 
598 """
599 
600  if os.path.isdir('lagrit_scripts'):
601  rmtree("lagrit_scripts")
602  os.mkdir("lagrit_scripts")
603  else:
604  os.mkdir("lagrit_scripts")
605 
606  # Create a different run file for each fracture
607  for i in fracture_list:
608  file_name = f'lagrit_scripts/mesh_poly_{i}.lgi'
609  with open(file_name, 'w') as f:
610  f.write(lagrit_input.format(i))
611  f.flush()
612  print('--> Writing LaGriT Control Files: Complete')
613 
614  print('--> Writing LaGriT Control Files: Complete')
615 
616 
617 def create_merge_poly_files(ncpu, num_poly, fracture_list, h, visual_mode,
618  domain, flow_solver):
619  """ Creates a LaGriT script that reads in each fracture mesh, appends it to the main mesh, and then deletes that mesh object. Then duplicate points are removed from the main mesh using EPS_FILTER. The points are compressed, and then written to file.
620 
621  Parameters
622  ----------
623  ncpu : int
624  Number of Processors used for meshing
625  fracture_list : list of int
626  List of fracture numbers in the DFN
627  h : float
628  Meshing length scale
629  visual_mode : bool
630  If True, reduced_mesh.inp will be output. If False, full_mesh.inp is output
631  domain : dict
632  Dictionary of x,y,z domain size
633  flow_solver : string
634  Name of target flow solver (Changes output files)
635 
636  Returns
637  -------
638  n_jobs : int
639  number of merge jobs
640 
641  Notes
642  -----
643  1. Fracture mesh objects are read into different part_*.lg files. This allows for merging of the mesh to be performed in batches.
644  """
645 
646  print("--> Writing : merge_poly.lgi")
647  part_size = int(num_poly / ncpu) + 1
648  endis = []
649  ii = 0
650  for i in fracture_list[:-1]:
651  ii += 1
652  if ii == part_size:
653  endis.append(i)
654  ii = 0
655  endis.append(fracture_list[-1])
656  n_jobs = len(endis)
657 
658  lagrit_input = """
659 # Change to read LaGriT
660 read / lagrit / %s / mo_%d / binary
661 cmo / move / mo_%d / mo_final
662 define / MO_NAME_FRAC / mo_%d
663 """
664  if not visual_mode:
665  lagrit_input += """
666 cmo / addatt / MO_NAME_FRAC / volume / evol_one
667 math / sum / MO_NAME_FRAC / evol_sum / 1 0 0 / MO_NAME_FRAC / evol_one
668 """
669  lagrit_input += """
670 addmesh / merge / cmo_tmp / cmo_tmp / mo_%d
671 cmo / delete / mo_%d
672 """
673  lagrit_input_2 = '#Writing out merged fractures\n'
674  if not visual_mode:
675  lagrit_input_2 += """
676 mo / addatt/ cmo_tmp / volume / evol_all
677 math / sum / cmo_tmp / evol_sum / 1 0 0 / cmo_tmp / evol_all """
678  lagrit_input_2 += """
679 cmo select cmo_tmp
680 dump lagrit part%d.lg cmo_tmp
681 finish \n
682 """
683 
684  j = 0 # Counter for cpus
685  fout = 'lagrit_scripts/merge_poly_part_1.lgi'
686  f = open(fout, 'w')
687  for i in fracture_list:
688  tmp = 'mesh_' + str(i) + '.lg'
689  f.write(lagrit_input % (tmp, i, i, i, i, i))
690  # if i is the last fracture in the cpu set
691  # move to the next cpu set
692  if i == endis[j]:
693  f.write(lagrit_input_2 % (j + 1))
694  f.flush()
695  f.close()
696  j += 1
697  fout = 'lagrit_scripts/merge_poly_part_' + str(j + 1) + '.lgi'
698  f = open(fout, 'w')
699 
700  f.flush()
701  f.close()
702  os.remove(fout)
703 
704 
705 
706  lagrit_input = """
707 read / lagrit / part%d.lg / junk / binary
708 addmesh / merge / mo_all / mo_all / cmo_tmp
709 cmo / delete / cmo_tmp
710  """
711  f = open('lagrit_scripts/merge_rmpts.lgi', 'w')
712  for j in range(1, n_jobs + 1):
713  f.write(lagrit_input % (j))
714 
715  # Append meshes complete
716  if not visual_mode:
717  lagrit_input = """
718 # Appending the meshes complete
719 # LaGriT Code to remove duplicates and output the mesh
720 cmo / select / mo_all
721 #recon 1
722 define / EPS / %e
723 define / EPS_FILTER / %e
724 pset / pinter / attribute / dfield / 1,0,0 / lt / EPS
725 #cmo / addatt / mo_all / inter / vint / scalar / nnodes
726 #cmo / setatt / mo_all / inter / 1 0 0 / 0
727 #cmo / setatt / mo_all / inter / pset, get, pinter / 1
728 
729 filterkd / pset get pinter / EPS_FILTER / nocheck
730 pset / pinter / delete
731 
732 rmpoint / compress
733 # SORT can affect a_b attribute
734 sort / mo_all / index / ascending / ikey / imt xic yic zic
735 reorder / mo_all / ikey
736 cmo / DELATT / mo_all / ikey
737 """ % (h * 10**-5, h * 10**-3)
738  lagrit_input += """
739 resetpts / itp
740 boundary_components
741 #dump / full_mesh.gmv / mo_all
742 dump / full_mesh.inp / mo_all
743 dump / lagrit / full_mesh.lg / mo_all
744 """
745  if flow_solver == "PFLOTRAN":
746  print("\n--> Dumping output for %s" % flow_solver)
747  lagrit_input += """
748 dump / pflotran / full_mesh / mo_all / nofilter_zero
749 dump / stor / full_mesh / mo_all / ascii
750  """
751  elif flow_solver == "FEHM":
752  print("\n--> Dumping output for %s" % flow_solver)
753  lagrit_input += """
754 dump / stor / full_mesh / mo_all / ascii
755 dump / coord / full_mesh / mo_all
756 # matid start at 1, but we need them to start at 7 for FEHM due to zone files
757 # So we do a little addition
758 math / add / mo_all / imt1 / 1,0,0 / mo_all / imt1 / 6
759 dump / zone_imt / full_mesh / mo_all
760 # and then we subtract 6 back
761 math / subtract / mo_all / imt1 / 1,0,0 / mo_all / imt1 / 6
762 """
763  else:
764  print("WARNING!!!!!!!\nUnknown flow solver selection: %s" %
765  flow_solver)
766  lagrit_input += """
767 # Dump out Material ID Dat file
768 cmo / modatt / mo_all / isn / ioflag / l
769 cmo / modatt / mo_all / x_four / ioflag / l
770 cmo / modatt / mo_all / fac_n / ioflag / l
771 cmo / modatt / mo_all / dfield / ioflag / l
772 cmo / modatt / mo_all / rf_field / ioflag / l
773 cmo / modatt / mo_all / a_b / ioflag / l
774 cmo / modatt / mo_all / b_a / ioflag / l
775 cmo / modatt / mo_all / xnorm / ioflag / l
776 cmo / modatt / mo_all / ynorm / ioflag / l
777 cmo / modatt / mo_all / znorm / ioflag / l
778 cmo / modatt / mo_all / evol_one / ioflag / l
779 cmo / modatt / mo_all / evol_all / ioflag / l
780 cmo / modatt / mo_all / numbnd / ioflag / l
781 cmo / modatt / mo_all / id_numb / ioflag / l
782 cmo / modatt / mo_all / evol_all / ioflag / l
783 cmo / modatt / mo_all / itp / ioflag / l
784 cmo / modatt / mo_all / icr / ioflag / l
785 cmo / modatt / mo_all / meshid / ioflag / l
786 cmo / modatt / mo_all / id_n_1 / ioflag / l
787 cmo / modatt / mo_all / id_n_2 / ioflag / l
788 cmo / modatt / mo_all / pt_gtg / ioflag / l
789 cmo / modatt / mo_all / pt_gtg / ioflag / l
790 # Dump out Material ID Dat file
791 dump / avs2 / materialid.dat / mo_all / 0 0 2 0
792 
793 cmo / modatt / mo_all / imt1 / ioflag / l
794 #cmo / modatt / mo_all / family_id / ioflag / l
795 cmo / modatt / mo_all / evol_onen / ioflag / l
796 # Dump mesh with no attributes for viz
797 dump / full_mesh_viz.inp / mo_all
798 
799 # Dump out zone files
800 define / XMAX / %e
801 define / XMIN / %e
802 define / YMAX / %e
803 define / YMIN / %e
804 define / ZMAX / %e
805 define / ZMIN / %e
806 
807 define / ZONE / 1
808 define / FOUT / boundary_top
809 pset / top / attribute / zic / 1,0,0/ gt / ZMAX
810 pset / top / zone / FOUT/ ascii / ZONE
811 
812 define / ZONE / 2
813 define / FOUT / boundary_bottom
814 pset / bottom / attribute / zic / 1,0,0/ lt / ZMIN
815 pset / bottom / zone / FOUT/ ascii / ZONE
816 
817 define / ZONE / 3
818 define / FOUT / boundary_left_w
819 pset / left_w / attribute/ xic/ 1,0,0 /lt / XMIN
820 pset / left_w / zone / FOUT/ ascii / ZONE
821 
822 define / ZONE / 4
823 define / FOUT / boundary_front_n
824 pset / front_n / attribute/ yic / 1,0,0 / gt / YMAX
825 pset / front_n / zone / FOUT/ ascii / ZONE
826 
827 define / ZONE / 5
828 define / FOUT / boundary_right_e
829 pset / right_e / attribute/ xic / 1,0,0/ gt / XMAX
830 pset / right_e / zone / FOUT/ ascii / ZONE
831 
832 define / ZONE / 6
833 define / FOUT / boundary_back_s
834 pset / back_s / attribute/ yic/ 1,0,0 / lt / YMIN
835 pset / back_s / zone / FOUT/ ascii / ZONE
836 
837 """
838  eps = h * 10**-3
839  parameters = (0.5*domain['x'] - eps, -0.5*domain['x'] + eps, \
840  0.5*domain['y'] - eps, -0.5*domain['y'] + eps, \
841  0.5*domain['z'] - eps, -0.5*domain['z'] + eps)
842 
843  lagrit_input = lagrit_input % parameters
844 
845  else:
846  lagrit_input = """
847 cmo / modatt / mo_all / icr1 / ioflag / l
848 cmo / modatt / mo_all / isn1 / ioflag / l
849 cmo / modatt / mo_all / itp1 / ioflag / l
850 #dump / reduced_mesh.gmv / mo_all
851 dump / reduced_mesh.inp / mo_all
852 """
853  lagrit_input += """
854 quality
855 finish
856 """
857  f.write(lagrit_input)
858  f.flush()
859  f.close()
860 
861  return n_jobs
862 
863 
865  """Processes zone files for particle tracking. All zone files are combined into allboundaries.zone
866 
867  Parameters
868  ----------
869  None
870 
871  Returns
872  -------
873  None
874 
875  Notes
876  -----
877  None
878  """
879 
880  fall = open("allboundaries.zone", "w")
881  #copy all but last 2 lines of boundary_top.zone in allboundaries.zone
882  fzone = open("boundary_top.zone", "r")
883  lines = fzone.readlines()
884  lines = lines[:-2]
885  fzone.close()
886  fall.writelines(lines)
887  #copy all but frist and last 2 lines of boundary_bottom.zone in allboundaries.zone
888  files = ['bottom', 'left_w', 'front_n', 'right_e']
889  for f in files:
890  fzone = open("boundary_%s.zone" % f, "r")
891  lines = fzone.readlines()
892  lines = lines[1:-2]
893  fzone.close()
894  fall.writelines(lines)
895  fzone = open("boundary_back_s.zone", "r")
896  lines = fzone.readlines()
897  lines = lines[1:]
898  fzone.close()
899  fall.writelines(lines)
900  fall.close()
901  # copies boundary zone files for PFLOTRAN
902  # This can be deleted once we clean up the flow
903  move('boundary_bottom.zone', 'pboundary_bottom.zone')
904  move('boundary_left_w.zone', 'pboundary_left_w.zone')
905  move('boundary_front_n.zone', 'pboundary_front_n.zone')
906  move('boundary_right_e.zone', 'pboundary_right_e.zone')
907  move('boundary_back_s.zone', 'pboundary_back_s.zone')
908  move('boundary_top.zone', 'pboundary_top.zone')
909 
910 
def create_merge_poly_files(ncpu, num_poly, fracture_list, h, visual_mode, domain, flow_solver)
def create_parameter_mlgi_file(fracture_list, h, slope=2.0, refine_dist=0.5)