pydfnWorks
python wrapper for dfnWorks
gen_input.py
Go to the documentation of this file.
1 import os
2 import sys
3 import shutil
4 import numpy as np
5 import scipy.integrate
6 import re
7 
8 #pydfnworks modules
9 from pydfnworks.dfnGen.generation import gen_distributions as distr_module
10 
11 
12 class input_helper():
13  """ Functions to help parse the input file and check input parameters.
14 
15  Attributes:
16  * params (list): list of parameters specified in the input file.
17  * minFracSize (float): the minimum fracture size.
18  """
19  def __init__(self, params, minFracSize):
20  self.paramsparams = params
21  self.minFracSizeminFracSize = minFracSize
22 
23 
26 
27  def curly_to_list(self, curlyList):
28  """ '{1,2,3}' --> [1,2,3]
29  """
30  return re.sub("{|}", "", curlyList).strip().split(",")
31 
32  def list_to_curly(self, strList):
33  """ [1,2,3] --> '{1,2,3}' for writing output
34  """
35  curl = re.sub(r'\[', '{', strList)
36  curl = re.sub(r'\]', '}', curl)
37  curl = re.sub(r"\'", '', curl)
38  return curl
39 
40  def has_curlys(self, line, key):
41  """ Checks to see that every { has a matching }.
42  """
43  if '{' in line and '}' in line: return True
44  elif '{' in line or '}' in line:
45  self.errorerror(
46  "Line defining \"{}\" contains a single curly brace.".format(
47  key))
48  return False
49 
50  def value_of(self, key, writing=False):
51  """ Use to get key's value in params. writing always false
52  """
53  if (not writing) and (len(self.paramsparams[key]) > 1):
54  self.errorerror(
55  "\"{}\" can only correspond to 1 list. {} lists have been defined."
56  .format(key, len(self.paramsparams[key])))
57  try:
58  val = self.paramsparams[key][0]
59  if val == '' or val == []:
60  self.errorerror("\"{}\" does not have a value.".format(key))
61  return val
62  except IndexError:
63  self.errorerror("\"{}\" has not been defined.".format(
64  key))
65 
66  def get_groups(self, line, valList, key):
67  """ extract values between { and }
68  """
69  curlyGroup = re.compile('({.*?})')
70  groups = re.findall(curlyGroup, line)
71  for group in groups:
72  line = line.replace(group, '', 1)
73  valList.append(self.curly_to_listcurly_to_list(group))
74 
75  if line.strip() != "":
76  self.errorerror(
77  "Unexpected character found while parsing \"{}\".".format(key))
78 
79  def val_helper(self, line, valList, key):
80  """ pulls values from culry brackets
81  """
82  if self.has_curlyshas_curlys(line, key):
83  self.get_groupsget_groups(line, valList, key)
84  else:
85  valList.append(line)
86 
87  def error(self, errString):
88  """ print an error
89 
90  Args:
91  errString (str): a string describing the error
92  """
93  error = "\nERROR --- " + errString + "\n----Program terminated while parsing input----\n"
94  sys.stderr.write(error)
95  sys.exit(1)
96 
97  def warning(self, warnString):
98  """ print warning
99 
100  Args:
101  warnStinrg (str): a string with the warning
102  """
103  print("WARNING --- " + warnString)
104 
105  def warning(self, warnString, warningFile=''):
106  """ print a warning to a file (currently does not work)"""
107  #global warningFile
108  print("WARNING --- " + warnString)
109  #warningFile.write("WARNING --- " + warnString + "\n")
110 
111  def is_negative(self, num):
112  """"returns True if num is negative, false otherwise
113  """
114  return True if num < 0 else False
115 
116  def check_fam_count(self):
117  """Makes sure at least one polygon family has been defined in nFamRect or nFamEll
118  OR that there is a user input file for polygons.
119  """
120  userDefExists = (self.value_ofvalue_of('userEllipsesOnOff') == '1') |\
121  (self.value_ofvalue_of('userRectanglesOnOff') == '1') |\
122  (self.value_ofvalue_of('userRecByCoord') == '1') |\
123  (self.value_ofvalue_of('userEllByCoord') == '1')
124 
125  ellipseFams = len(self.value_ofvalue_of('nFamRect'))
126  rectFams = len(self.value_ofvalue_of('nFamEll'))
127 
128  if ellipseFams + rectFams <= 0 and not userDefExists:
129  self.errorerror("Zero polygon families have been defined. Please create at least one family "\
130  "of ellipses/rectagnles, or provide a user-defined-polygon input file path in "\
131  "\"UserEll_Input_File_Path\", \"UserRect_Input_File_Path\", \"UserEll_Input_File_Path\", or "\
132  "\"RectByCoord_Input_File_Path\" and set the corresponding flag to '1'.")
133 
134  def scale(self, probList, warningFile):
135  """ scales list of probabilities (famProb) that doesn't add up to 1
136  ie [.2, .2, .4] --> [0.25, 0.25, 0.5]
137  """
138  total = sum(probList)
139  scaled = [float("{:.6}".format(x / total)) for x in probList]
140  self.warningwarningwarning("'famProb' probabilities did not add to 1 and have been scaled accordingly "\
141  "for their current sum, {:.6}. Scaled {} to {}".format(total, probList, scaled), warningFile)
142  return [x / total for x in probList]
143 
144  def zero_in_std_devs(self, valList):
145  """ returns True is there is a zero in valList of standard deviations
146  """
147  for val in valList:
148  if float(val) == 0: return True
149 
150  def check_min_max(self, minParam, maxParam, shape):
151  """ Checks that the minimum parameter for a family is not greater or equal to the maximum parameter.
152  """
153  for minV, maxV in zip(self.value_ofvalue_of(minParam),
154  self.value_ofvalue_of(maxParam)):
155  if minV == maxV:
156  self.errorerror("\"{}\" and \"{}\" contain equal values for the same {} family. "\
157  "If {} and {} were intended to be the same, use the constant distribution "\
158  "(4) instead.".format(minParam, maxParam, shape, minParam, maxParam))
159  if minV > maxV:
160  self.errorerror(
161  "\"{}\" is greater than \"{}\" in a(n) {} family.".format(
162  minParam, maxParam, shape))
163  sys.exit(1)
164 
165  def check_mean(self, minParam, maxParam, meanParam, warningFile=''):
166  """ Warns the user if the minimum value of a parameter is greater than the family's mean value, or if the
167  maximum value of the parameter is less than the family's mean value.
168  """
169  for minV, meanV in zip(self.value_ofvalue_of(minParam),
170  self.value_ofvalue_of(meanParam)):
171  if minV > meanV:
172  self.warningwarningwarning("\"{}\" contains a min value greater than its family's mean value in "\
173  "\"{}\". This could drastically increase computation time due to increased "\
174  "rejection rate of the most common fracture sizes.".format(minParam, meanParam), warningFile)
175  for maxV, meanV in zip(self.value_ofvalue_of(maxParam),
176  self.value_ofvalue_of(meanParam)):
177  if maxV < meanV:
178  self.warningwarningwarning("\"{}\" contains a max value less than its family's mean value in "\
179  "\"{}\". This could drastically increase computation time due to increased "\
180  "rejection rate of the most common fracture sizes.".format(maxParam, meanParam), warningFile)
181 
182  def check_min_frac_size(self, valList):
183  """ Corrects the minimum fracture size if necessary, by looking at the values in valList.
184  """
185  global minFracSize
186  for val in valList:
187  if minFracSize == None:
188  minFracSize = val
189  elif val < minFracSize:
190  minFracSize = val
191 
192 
195  def extract_parameters(self, line, inputIterator):
196  """Returns line without comments or white space.
197  """
198  if "/*" in line:
199  comment = line
200  line = line[:line.index(
201  "/*")]
202  while "*/" not in comment:
203  comment = next(
204  inputIterator)
205 
206  elif "//" in line:
207  line = line[:line.index(
208  "//")]
209 
210  return line.strip()
211 
212  def find_val(self, line, key, inputIterator, unfoundKeys, warningFile):
213  """ Extract the value for key from line.
214  """
215  valList = []
216  line = line[line.index(":") + 1:].strip()
217  if line != "": self.val_helperval_helper(line, valList, key)
218 
219  line = self.extract_parametersextract_parameters(next(inputIterator), inputIterator)
220  while ':' not in line:
221  line = line.strip()
222  if line != "":
223  self.val_helperval_helper(line, valList, key)
224  try:
225  line = self.extract_parametersextract_parameters(next(inputIterator),
226  inputIterator)
227  except StopIteration:
228  break
229 
230  if valList == [] and key in mandatory:
231  self.errorerror(
232  "\"{}\" is a mandatory parameter and must be defined.".format(
233  key))
234  if key is not None:
235  self.paramsparams[key] = valList if valList != [] else [
236  ""
237  ]
238  if line != "":
239  self.process_lineprocess_line(line, unfoundKeys, inputIterator, warningFile)
240 
241  def find_key(self, line, unfoundKeys, warningFile):
242  """ Input: line containing a parameter (key) preceding a ":"
243 
244  Returns:
245  * key -- if it has not been defined yet and is valid
246  * None -- if key does not exist
247  * exits -- if the key has already been defined to prevent duplicate confusion
248  """
249  key = line[:line.index(":")].strip()
250  if key in unfoundKeys:
251  unfoundKeys.remove(key)
252  return key
253  try:
254  self.paramsparams[key]
255  self.errorerror("\"{}\" has been defined more than once.".format(key))
256  except KeyError:
257  self.warningwarningwarning(
258  "\"" + key + "\" is not one of the valid parameter names.",
259  warningFile)
260 
261  def process_line(self, line, unfoundKeys, inputIterator, warningFile):
262  """ Find the key in a line, and the value for that key.
263  """
264  if line.strip != "":
265  key = self.find_keyfind_key(line, unfoundKeys, warningFile)
266  if key != None:
267  self.find_valfind_val(line, key, inputIterator, unfoundKeys,
268  warningFile)
269 
270 
275 
276 
279  def verify_flag(self, value, key="", inList=False):
280  """ Verify that value is either a 0 or a 1.
281  """
282  if value is '0' or value is '1':
283  return int(value)
284  elif inList:
285  return None
286  else:
287  self.errorerror("\"{}\" must be either '0' or '1'".format(key))
288 
289  def verify_float(self, value, key="", inList=False, noNeg=False):
290  """ Verify that value is a positive float.
291  """
292  if type(value) is list:
293  self.errorerror(
294  "\"{}\" contains curly braces {{}} but should not be a list value."
295  .format(key))
296  try:
297  if noNeg and float(value) < 0:
298  self.errorerror("\"{}\" cannot be a negative number.".format(key))
299  return float(value)
300  except ValueError:
301  if inList: return None
302  else:
303  self.errorerror("\"{}\" contains an unexpected character. Must be a single "\
304  "floating point value (0.5, 1.6, 4.0, etc.)".format(key))
305 
306  def verify_int(self, value, key="", inList=False, noNeg=False):
307  """ Verify that value is a positive integer.
308  """
309  if type(value) is list:
310  self.errorerror(
311  "\"{}\" contains curly braces {{}} but should not be a list value."
312  .format(key))
313  try:
314  if noNeg and int(re.sub(r'\.0*$', '', value)) < 0:
315  self.errorerror("\"{}\" cannot be a negative number.".format(key))
316  return int(re.sub(r'\.0*$', '',
317  value))
318  except ValueError:
319  if inList: return None
320  else:
321  self.errorerror("\"{}\" contains an unexpected character. Must be a single "\
322  "integer value (0,1,2,3,etc.)".format(key))
323 
324  def verify_list(self,
325  valList,
326  key,
327  verificationFn,
328  desiredLength,
329  noZeros=False,
330  noNegs=False):
331  """verifies input list that come in format {0, 1, 2, 3}
332 
333  Input:
334  * valList - list of values (flags, floats, or ints) corresponding to a parameter
335  * key - the name of the parameter whose list is being verified
336  * verificationFn - (either verifyflag, verifyfloat or verifyint) checks each list element
337  * desiredLength - how many elements are supposed to be in the list
338  * noZeros - (optional) True for lists than cannot contain 0's, false if 0's are ok
339  * noNegs - (optional) True for lists than cannot contain negative numbers, false otherwise
340  Output:
341  * returns negative value of list length to indicate incorrect length and provide meaningful error message
342  * prints error and exits if a value of the wrong type is found in the list
343  * returns None if successful"""
344 
345  if valList == ['']: return 0
346  if type(valList) is not list:
347  self.errorerror(
348  "\"{}\"'s value must be a list enclosed in curly brackets {{}}."
349  .format(key))
350  if desiredLength != 0 and int(len(valList)) != int(desiredLength):
351  print('list desired length is ', desiredLength, 'but valList is ',
352  valList, 'with length ', len(valList))
353  return -len(valList)
354  for i, value in enumerate(valList):
355  value = value.strip()
356  verifiedVal = verificationFn(value, inList=True)
357  if verifiedVal == None:
358  listType = re.sub(
359  'integer', 'int',
360  re.sub(
361  r'verify', '',
362  verificationFn.__name__))
363  self.errorerror("\"{}\" must be a list of {}s {}. non-{} found in "\
364  "list".format(key, listType, examples[listType], listType))
365  if noZeros and verifiedVal == 0:
366  self.errorerror("\"{}\" list cannot contain any zeros.".format(key))
367  if noNegs and self.is_negativeis_negative(float(verifiedVal)):
368  self.errorerror(
369  "\"{}\" list cannot contain negative values.".format(key))
370  valList[i] = verifiedVal
371 
372 
376 
377 
378 def check_input(self, input_file='', output_file=''):
379  """Check input file for DFNGen to make sure all necessary parameters are defined
380 
381  Input Format Requirements:
382  * Each parameter must be defined on its own line (separate by newline)
383  * A parameter (key) MUST be separated from its value by a colon ':' (ie. --> key: value)
384  * Values may also be placed on lines after the 'key'
385  * Comment Format: On a line containing // or / ``*``, nothing after ``*`` / or // will be processed but text before a comment will be processed
386 
387  Parameters
388  ----------
389  input_file : string
390  name of dfnGen input file
391  output_file : string
392  Name of stripped down input file for DFNGen (input_file_clean.dat)
393 
394  Returns
395  -------
396  None
397 
398  Notes
399  -----
400  There are warnings and errors raised in this function. Warning will let you continue while errors will stop the run. Continue past warnings are your own risk.
401  """
402  global params
403 
407  params = {
408  'esd': [],
409  'insertUserRectanglesFirst': [],
410  'keepOnlyLargestCluster': [],
411  'keepIsolatedFractures': [],
412  'rmin': [],
413  'rAngleOption': [],
414  'boundaryFaces': [],
415  'userRectanglesOnOff': [],
416  'printRejectReasons': [],
417  'numOfLayers': [],
418  'numOfRegions': [],
419  'RectByCoord_Input_File_Path': [],
420  'eLogMean': [],
421  'rExpMin': [],
422  'lengthCorrelatedAperture': [],
423  'ebetaDistribution': [],
424  'tripleIntersections': [],
425  'layers': [],
426  'regions': [],
427  'stdAperture': [],
428  'ealpha': [],
429  'constantPermeability': [],
430  'rLogMax': [],
431  'rLogMean': [],
432  'nFamRect': [],
433  'etheta': [],
434  'eLogMax': [],
435  'rphi': [],
436  'outputAllRadii': [],
437  'r_p32Targets': [],
438  'permOption': [],
439  'userRecByCoord': [],
440  'RectByCoord_Input_File_Path': [],
441  'userRectanglesOnOff': [],
442  'UserRect_Input_File_Path': [],
443  'userEllByCoord': [],
444  'EllByCoord_Input_File_Path': [],
445  'userEllipsesOnOff': [],
446  'UserEll_Input_File_Path': [],
447  'userPolygonByCoord': [],
448  'PolygonByCoord_Input_File_Path': [],
449  'rExpMean': [],
450  'rbetaDistribution': [],
451  'aperture': [],
452  'emax': [],
453  'eExpMean': [],
454  'e_p32Targets': [],
455  'eLayer': [],
456  'eRegion': [],
457  'domainSizeIncrease': [],
458  'h': [],
459  'outputFinalRadiiPerFamily': [],
460  'rbeta': [],
461  'rLogMin': [],
462  'edistr': [],
463  'domainSize': [],
464  'eExpMin': [],
465  'ekappa': [],
466  'rLayer': [],
467  'rRegion': [],
468  'seed': [],
469  'constantAperture': [],
470  'stopCondition': [],
471  'enumPoints': [],
472  'meanAperture': [],
473  'eLogMin': [],
474  'easpect': [],
475  'rtheta': [],
476  'rdistr': [],
477  'rconst': [],
478  'rExpMax': [],
479  'ignoreBoundaryFaces': [],
480  'visualizationMode': [],
481  'outputAcceptedRadiiPerFamily': [],
482  'apertureFromTransmissivity': [],
483  'rsd': [],
484  'ebeta': [],
485  'nFamEll': [],
486  'econst': [],
487  'raspect': [],
488  'eAngleOption': [],
489  'emin': [],
490  'ephi': [],
491  'rmax': [],
492  'famProb': [],
493  'disableFram': [],
494  'ralpha': [],
495  'nPoly': [],
496  'rejectsPerFracture': [],
497  'rkappa': [],
498  'eExpMax': [],
499  'forceLargeFractures': [],
500  'radiiListIncrease': [],
501  'removeFracturesLessThan': []
502  }
503  global unfoundKeys
504 
505  unfoundKeys = {
506  'stopCondition', 'nPoly', 'outputAllRadii', 'outputAllRadii',
507  'outputFinalRadiiPerFamily', 'outputAcceptedRadiiPerFamily',
508  'domainSize', 'numOfLayers', 'layers', 'numOfRegions', 'regions', 'h',
509  'tripleIntersections', 'printRejectReasons', 'disableFram',
510  'visualizationMode', 'seed', 'domainSizeIncrease',
511  'keepOnlyLargestCluster', 'keepIsolatedFractures',
512  'ignoreBoundaryFaces', 'boundaryFaces', 'rejectsPerFracture',
513  'famProb', 'insertUserRectanglesFirst', 'nFamEll', 'eLayer', 'eRegion',
514  'edistr', 'ebetaDistribution', 'e_p32Targets', 'easpect', 'enumPoints',
515  'eAngleOption', 'etheta', 'ephi', 'ebeta', 'ekappa', 'eLogMean', 'esd',
516  'eLogMin', 'eLogMax', 'eExpMean', 'eExpMin', 'eExpMax', 'econst',
517  'emin', 'emax', 'ealpha', 'nFamRect', 'rLayer', 'rRegion', 'rdistr',
518  'rbetaDistribution', 'r_p32Targets', 'raspect', 'rAngleOption',
519  'rtheta', 'rphi', 'rbeta', 'rkappa', 'rLogMean', 'rsd', 'rLogMin',
520  'rLogMax', 'rmin', 'rmax', 'ralpha', 'rExpMean', 'rExpMin', 'rExpMax',
521  'rconst', 'userEllipsesOnOff', 'UserEll_Input_File_Path',
522  'userRectanglesOnOff', 'UserRect_Input_File_Path',
523  'EllByCoord_Input_File_Path', 'userEllByCoord', 'userRecByCoord',
524  'userPolygonByCoord', 'RectByCoord_Input_File_Path',
525  'PolygonByCoord_Input_File_Path', 'aperture', 'meanAperture',
526  'stdAperture', 'apertureFromTransmissivity', 'constantAperture',
527  'lengthCorrelatedAperture', 'permOption', 'constantPermeability',
528  'forceLargeFractures', 'radiiListIncrease', 'removeFracturesLessThan'
529  }
530 
531  global mandatory
532  mandatory = {
533  'stopCondition', 'domainSize', 'numOfLayers', 'numOfRegions',
534  'outputAllRadii', 'outputFinalRadiiPerFamily',
535  'outputAcceptedRadiiPerFamily', 'tripleIntersections',
536  'printRejectReasons', 'disableFram', 'visualizationMode', 'seed',
537  'domainSizeIncrease', 'keepOnlyLargestCluster',
538  'keepIsolatedFractures', 'ignoreBoundaryFaces', 'rejectsPerFracture',
539  'famProb', 'insertUserRectanglesFirst', 'nFamEll', 'nFamRect',
540  'userEllipsesOnOff', 'userRectanglesOnOff', 'userEllByCoord',
541  'userRecByCoord', 'userPolygonByCoord', 'aperture', 'permOption',
542  'forceLargeFractures', 'radiiListIncrease', 'removeFracturesLessThan'
543  }
544 
545  global noDependancyFlags
546  noDependancyFlags = [
547  'outputAllRadii', 'outputFinalRadiiPerFamily',
548  'outputAcceptedRadiiPerFamily', 'tripleIntersections',
549  'printRejectReasons', 'visualizationMode', 'keepOnlyLargestCluster',
550  'keepIsolatedFractures', 'insertUserRectanglesFirst',
551  'forceLargeFractures'
552  ]
553  global examples
554  examples = {
555  "Flag": "(0 or 1)",
556  "Float": "(0.5, 1.6, 4.0, etc.)",
557  "Int": "(0,1,2,3,etc.)"
558  }
559 
560  global ellipseFams
561  ellipseFams = 0
562  global rectFams
563  rectFams = 0
564  global numLayers
565  numLayers = 0
566  global numRegions
567  numRegions = 0
568  global minFracSize
569  minFracSize = None
570 
571 
572  global numEdistribs
573  numEdistribs = [
574  -1, 0, 0, 0, 0
575  ]
576  global numRdistribs
577  numRdistribs = [
578  -1, 0, 0, 0, 0
579  ]
580  global warningFile
581  warningFile = open("warningFileDFNGen.txt", 'w')
582  global jobname
583  jobname = self.jobname
584 
585  input_helper_methods = input_helper(params, minFracSize)
586 
587 
590 
591 
592  def n_fam_ell():
593  """ Check the number of families of ellipses."""
594  global ellipseFams
595 
596  ellipseFams = input_helper_methods.verify_int(
597  input_helper_methods.value_of('nFamEll', params),
598  'nFamEll',
599  noNeg=True)
600  if ellipseFams == 0:
601  input_helper_methods.warning(
602  "You have set the number of ellipse families to 0, outside user-defined ellipses, no ellipses will be generated.",
603  params)
604 
605  def n_fam_rect():
606  """ Check the number of families of rectangles."""
607  global rectFams
608 
609  rectFams = input_helper_methods.verify_int(
610  input_helper_methods.value_of('nFamRect', params),
611  'nFamRect',
612  noNeg=True)
613  if rectFams == 0:
614  input_helper_methods.warning(
615  "You have set the number of rectangle families to 0, outside user-defined rectangles, no rectangles will be generated.",
616  params)
617 
618  def stop_condition():
619  """ Check the number of polygons if stopCondition is set to 1, else check the p32 target parameters."""
620 
621  if input_helper_methods.verify_flag(
622  input_helper_methods.value_of('stopCondition', params),
623  'stopCondition') == 0:
624  n_poly()
625  else:
626  p32_targets()
627 
628  def check_no_dep_flags():
629  """ Check for dependency flags."""
630  for flagName in noDependancyFlags:
631  input_helper_methods.verify_flag(
632  input_helper_methods.value_of(flagName, params), flagName)
633 
634  def domain_size():
635  """ Check that domainSize has 3 non-zero values to define the
636  size of each dimension (x,y,z) of the domain.
637  """
638  errResult = input_helper_methods.verify_list(
639  input_helper_methods.value_of('domainSize', params),
640  'domainSize',
641  input_helper_methods.verify_float,
642  desiredLength=3,
643  noZeros=True,
644  noNegs=True)
645  if errResult != None:
646  input_helper_methods.error("\"domainSize\" has defined {} value(s) but there must be 3 non-zero "\
647  "values to represent x, y, and z dimensions".format(-errResult))
648 
649  def domain_size_increase():
650  """ Check the domain size increase parameters.
651  """
652  errResult = input_helper_methods.verify_list(
653  input_helper_methods.value_of('domainSizeIncrease', params),
654  domain_size_increase,
655  input_helper_methods.verify_float,
656  desiredLength=3)
657  if errResult != None:
658  input_helper_methods.error("\"domainSizeIncrease\" has defined {} value(s) but there must be 3 non-zero "\
659  "values to represent extensions in the x, y, and z dimensions".format(-errResult))
660 
661  for i, val in enumerate(
662  input_helper_methods.value_of('domainSizeIncrease', params)):
663  if val >= input_helper_methods.value_of('domainSize',
664  params)[i] / 2:
665  input_helper_methods.error(
666  "\"domainSizeIncrease\" contains {} which is more than half of the domain's "
667  "range in that dimension. Cannot change the domain's size by more than half of "
668  "that dimension's value defined in \"domainSize\". This risks collapsing or "
669  "doubling the domain.".format(val))
670 
671  def num_of_layers():
672  """ Check the number of layers parameter."""
673  global numLayers
674  numLayers = input_helper_methods.verify_int(
675  input_helper_methods.value_of('numOfLayers', params),
676  'numOfLayers',
677  noNeg=True)
678  if numLayers > 0:
679  if numLayers != len(params['layers']):
680  input_helper_methods.error("\"layers\" has defined {} layers but \"numLayers\" was defined to "\
681  "be {}.".format(len(params['layers']), numLayers))
682  else:
683  layers()
684 
685  def layers():
686  """ Check the layer parameters provided. """
687  halfZdomain = params['domainSize'][0][
688  2] / 2.0
691  for i, layer in enumerate(params['layers']):
692  errResult = input_helper_methods.verify_list(
693  layer,
694  "layer #{}".format(i + 1),
695  input_helper_methods.verify_float,
696  desiredLength=2)
697  if errResult != None:
698  input_helper_methods.error("\"layers\" has defined layer #{} to have {} element(s) but each layer must "\
699  "have 2 elements, which define its upper and lower bounds".format(i+1, -errResult))
700  if params['layers'].count(layer) > 1:
701  input_helper_methods.error(
702  "\"layers\" has defined the same layer more than once.")
703  minZ = layer[0]
704  maxZ = layer[1]
705  if maxZ <= minZ:
706  input_helper_methods.error("\"layers\" has defined layer #{0} where zmin: {1} is "\
707  "greater than zmax {2}".format(i+1,minZ, maxZ))
708  if minZ <= -halfZdomain and maxZ <= -halfZdomain:
709  input_helper_methods.error("\"layers\" has defined layer #{} to have both upper and lower bounds completely "\
710  "below the domain's z-dimensional range ({} to {}). At least one boundary must be within "\
711  "the domain's range. The domain's range is half of 3rd value in \"domainSize\" "\
712  "(z-dimension) in both positive and negative directions.".format(i+1, -halfZdomain, halfZdomain))
713  if minZ >= halfZdomain and maxZ >= halfZdomain:
714  input_helper_methods.error("\"layers\" has defined layer #{} to have both upper and lower bounds completely "\
715  "above the domain's z-dimensional range ({} to {}). At least one boundary must be within "\
716  "the domain's range. The domain's range is half of 3rd value in \"domainSize\" "\
717  "(z-dimension) in both positive and negative directions.".format(i+1, -halfZdomain, halfZdomain))
718 
719  def num_of_regions():
720  """ Check the number of regions parameter."""
721  global numRegions
722  numRegions = input_helper_methods.verify_int(
723  input_helper_methods.value_of('numOfRegions', params),
724  'numOfRegions',
725  noNeg=True)
726  if numRegions > 0:
727  print("Number of Regions {0}".format(numRegions))
728  if numRegions != len(params['regions']):
729  input_helper_methods.error("\"regions\" has defined {} regions but \"numOfRegions\" was defined to "\
730  "be {}.".format(len(params['regions']), numRegions))
731  else:
732  regions()
733 
734  def regions():
735  """ Check the regions parameters provided. """
736  half_x_domain = params['domainSize'][0][
737  0] / 2.0
738  half_y_domain = params['domainSize'][0][
739  1] / 2.0
740  half_z_domain = params['domainSize'][0][
741  2] / 2.0
744  for i, region in enumerate(params['regions']):
745  errResult = input_helper_methods.verify_list(
746  region,
747  "regions #{}".format(i + 1),
748  input_helper_methods.verify_float,
749  desiredLength=6)
750  if errResult != None:
751  input_helper_methods.error("\"regions\" has defined layer #{} to have {} element(s) but each region must "\
752  "have 6 elements, which define its upper and lower bounds".format(i+1, -errResult))
753  if params['regions'].count(regions) > 1:
754  input_helper_methods.error(
755  "\"regions\" has defined the same region more than once.")
756  # min_x = regions[0]
757  # max_x = regions[1]
758  # min_y = regions[2]
759  # max_y = regions[3]
760  # min_z = regions[4]
761  # max_z = regions[5]
762 
763  # X direction
764  if region[1] <= region[0]:
765  input_helper_methods.error("\"regions\" has defined region #{0} where xmin: {1} is "\
766  "greater than xmax {2}".format(i+1,region[0], region[1]))
767  if region[0] <= -half_x_domain and region[1] <= -half_x_domain:
768  input_helper_methods.error("\"regions\" has defined layer #{} to have both upper and lower bounds completely "\
769  "below the domain's x-dimensional range ({} to {}). At least one boundary must be within "\
770  "the domain's range. The domain's range is half of 1st value in \"domainSize\" "\
771  "(x-dimension) in both positive and negative directions.".format(i+1, -half_x_domain, half_x_domain))
772  if region[0] >= half_x_domain and region[1] >= half_x_domain:
773  input_helper_methods.error("\"regions\" has defined layer #{} to have both upper and lower bounds completely "\
774  "above the domain's x-dimensional range ({} to {}). At least one boundary must be within "\
775  "the domain's range. The domain's range is half of 1st value in \"domainSize\" "\
776  "(x-dimension) in both positive and negative directions.".format(i+1, -half_x_domain, half_x_domain))
777  # Y direction
778  if region[3] <= region[2]:
779  input_helper_methods.error("\"regions\" has defined region #{0} where ymin: {1} is "\
780  "greater than ymax {2}".format(i+1,region[3], region[2]))
781  if region[2] <= -half_y_domain and region[3] <= -half_y_domain:
782  input_helper_methods.error("\"regions\" has defined layer #{} to have both upper and lower bounds completely "\
783  "below the domain's y-dimensional range ({} to {}). At least one boundary must be within "\
784  "the domain's range. The domain's range is half of 2nd value in \"domainSize\" "\
785  "(y-dimension) in both positive and negative directions.".format(i+1, -half_x_domain, half_x_domain))
786  if region[2] >= half_y_domain and region[3] >= half_y_domain:
787  input_helper_methods.error("\"regions\" has defined layer #{} to have both upper and lower bounds completely "\
788  "above the domain's y-dimensional range ({} to {}). At least one boundary must be within "\
789  "the domain's range. The domain's range is half of 2nd value in \"domainSize\" "\
790  "(y-dimension) in both positive and negative directions.".format(i+1, -half_y_domain, half_y_domain))
791 
792  # Z direction
793  if region[5] <= region[4]:
794  input_helper_methods.error("\"regions\" has defined region #{0} where zmin: {1} is "\
795  "greater than zmax {2}".format(i+1,region[5], region[4]))
796  if region[4] <= -half_z_domain and region[5] <= -half_z_domain:
797  input_helper_methods.error("\"regions\" has defined layer #{} to have both upper and lower bounds completely "\
798  "below the domain's z-dimensional range ({} to {}). At least one boundary must be within "\
799  "the domain's range. The domain's range is half of 3rd value in \"domainSize\" "\
800  "(z-dimension) in both positive and negative directions.".format(i+1, -half_z_domain, half_z_domain))
801  if region[4] >= half_z_domain and region[5] >= half_z_domain:
802  input_helper_methods.error("\"regions\" has defined layer #{} to have both upper and lower bounds completely "\
803  "above the domain's z-dimensional range ({} to {}). At least one boundary must be within "\
804  "the domain's range. The domain's range is half of 3rd value in \"domainSize\" "\
805  "(z-dimension) in both positive and negative directions.".format(i+1, -half_z_domain, half_z_domain))
806 
807  def disable_fram():
808  """ Verify the flag that indicates whether if FRAM is disabled.
809  If FRAM is enabled, verify the value of h is valid.
810  """
811  if input_helper_methods.verify_flag(
812  input_helper_methods.value_of('disableFram', params),
813  'disableFram') == 0:
814  h()
815  else:
816  input_helper_methods.warning("FRAM (feature rejection algorithm for meshing) is disabled. This means that"\
817  "dfnWorks will only run through fracture network generation (the code will stop before meshing)."\
818  "To run the full code change the disableFram option to 1")
819 
820  def seed():
821  """ Check the value of the seed used for pseudorandom number generation.
822  """
823  val = input_helper_methods.verify_int(input_helper_methods.value_of(
824  'seed', params),
825  'seed',
826  noNeg=True)
827  if val == 0:
828  input_helper_methods.warning("\"seed\" has been set to 0. Random generator will use current wall "\
829  "time so distribution's random selection will not be as repeatable. "\
830  "Use an integer greater than 0 for better repeatability.", params)
831  params['seed'][0] = val
832 
833  def ignore_boundary_faces():
834  """ Check the value fo the ignoreBoundaryFaces flag.
835  """
836  if input_helper_methods.verify_flag(
837  input_helper_methods.value_of('ignoreBoundaryFaces', params),
838  'ignoreBoundaryFaces') == 0:
839  boundary_faces()
840 
841  def rejects_per_fracture():
842  """ Check the value of the rejectsPerFracture int.
843  """
844  val = input_helper_methods.verify_int(input_helper_methods.value_of(
845  'rejectsPerFracture', params),
846  'rejectsPerFracture',
847  noNeg=True)
848  if val == 0:
849  val = 1
850  input_helper_methods.warning(
851  "changing \"rejectsPerFracture\" from 0 to 1. Can't ensure 0 rejections.",
852  params)
853 
854  params['rejectsPerFracture'][0] = val
855 
856  def fam_prob():
857  """ Check the list of family probabilites (the list of probabilities that a fracture is in each family).
858  """
859 
860  errResult = input_helper_methods.verify_list(
861  input_helper_methods.value_of('famProb', params),
862  'famProb',
863  input_helper_methods.verify_float,
864  desiredLength=ellipseFams + rectFams,
865  noZeros=True,
866  noNegs=True)
867 
868  if errResult != None:
869  print(errResult)
870  input_helper_methods.error("\"famProb\" must have {} (nFamEll + nFamRect) non-zero elements,"\
871  "one for each family of ellipses and rectangles. {} probabiliies have "\
872  "been defined.".format(ellipseFams + rectFams, -errResult))
873 
874  probList = [
875  float(x) for x in input_helper_methods.value_of('famProb', params)
876  ]
877  if sum(probList) != 1:
878  input_helper_methods.scale(probList, warningFile)
879 
880  def user_defined():
881  """ Check the parameters for user-defined rectangles and ellipses.
882  """
883  userEs = "userEllipsesOnOff"
884  userRs = "userRectanglesOnOff"
885  recByCoord = "userRecByCoord"
886  ellByCoord = "userEllByCoord"
887  polygonByCoord = "userPolygonByCoord"
888  ePath = "UserEll_Input_File_Path"
889  rPath = "UserRect_Input_File_Path"
890  coordPath = "RectByCoord_Input_File_Path"
891  ecoordPath = "EllByCoord_Input_File_Path"
892  polycoordPath = "PolygonByCoord_Input_File_Path"
893  invalid = "\"{}\" is not a valid path."
894 
895  if input_helper_methods.verify_flag(
896  input_helper_methods.value_of(ellByCoord, params),
897  ellByCoord) == 1:
898  if not os.path.isfile(
899  input_helper_methods.value_of(ecoordPath, params)):
900  print('THIS PATH IS NOT A VALID FILE PATH: ',
901  input_helper_methods.value_of(ecoordPath, params))
902  input_helper_methods.error(invalid.format(ecoordPath))
903  else:
904  shutil.copy(input_helper_methods.value_of(ecoordPath, params),
905  self.jobname)
906 
907  if input_helper_methods.verify_flag(
908  input_helper_methods.value_of(userEs, params), userEs) == 1:
909  if not os.path.isfile(input_helper_methods.value_of(ePath,
910  params)):
911  print('THIS PATH IS NOT A VALID FILE PATH: ',
912  input_helper_methods.value_of(ePath, params))
913  input_helper_methods.error(invalid.format(ePath))
914  else:
915  shutil.copy(input_helper_methods.value_of(ePath, params),
916  self.jobname)
917 
918  if input_helper_methods.verify_flag(
919  input_helper_methods.value_of(userRs, params), userRs) == 1:
920  if not os.path.isfile(input_helper_methods.value_of(rPath,
921  params)):
922  print('THIS PATH IS NOT A VALID FILE PATH: ',
923  input_helper_methods.value_of(rPath, params))
924  input_helper_methods.error(invalid.format(rPath))
925  else:
926  shutil.copy(input_helper_methods.value_of(rPath, params),
927  self.jobname)
928 
929  if input_helper_methods.verify_flag(
930  input_helper_methods.value_of(recByCoord, params),
931  recByCoord) == 1:
932  if not os.path.isfile(
933  input_helper_methods.value_of(coordPath, params)):
934  print('THIS PATH IS NOT A VALID FILE PATH: ',
935  input_helper_methods.value_of(coordPath, params))
936  input_helper_methods.error(invalid.format(coordPath))
937  else:
938  shutil.copy(input_helper_methods.value_of(coordPath, params),
939  self.jobname)
940 
941  def aperture():
942  """ Verify the int value used for aperture.
943  """
944  apOption = input_helper_methods.verify_int(
945  input_helper_methods.value_of('aperture', params), 'aperture')
946 
947  if apOption == 1:
948  if input_helper_methods.verify_float(input_helper_methods.value_of(
949  'meanAperture', params),
950  'meanAperture',
951  noNeg=True) == 0:
952  input_helper_methods.error("\"meanAperture\" cannot be 0.")
953  if input_helper_methods.verify_float(input_helper_methods.value_of(
954  'stdAperture', params),
955  'stdAperture',
956  noNeg=True) == 0:
957  input_helper_methods.error("\"stdAperture\" cannot be 0. If you wish to have a standard deviation "\
958  "of 0, use a constant aperture instead.")
959 
960  elif apOption == 2:
961  input_helper_methods.verify_list(input_helper_methods.value_of(
962  'apertureFromTransmissivity', params),
963  'apertureFromTransmissivity',
964  input_helper_methods.verify_float,
965  desiredLength=2,
966  noNegs=True)
967  if input_helper_methods.value_of('apertureFromTransmissivity',
968  params)[0] == 0:
969  input_helper_methods.error(
970  "\"apertureFromTransmissivity\"'s first value cannot be 0."
971  )
972  if input_helper_methods.value_of('apertureFromTransmissivity',
973  params)[1] == 0:
974  input_helper_methods.warning(
975  "\"apertureFromTransmissivity\"'s second value is 0, which will result in a constant aperature.",
976  params)
977 
978  elif apOption == 3:
979  if input_helper_methods.verify_float(input_helper_methods.value_of(
980  'constantAperture', params),
981  'constantAperture',
982  noNeg=True) == 0:
983 
984  params['constantAperture'][0] = 1e-25
985  input_helper_methods.warning("\"constantAperture\" was set to 0 and has been changed "\
986  "to 1e-25 so fractures have non-zero thickness.", params)
987 
988  elif apOption == 4:
989  input_helper_methods.verify_list(input_helper_methods.value_of(
990  'lengthCorrelatedAperture', params),
991  'lengthCorrelatedAperture',
992  input_helper_methods.verify_float,
993  desiredLength=2,
994  noNegs=True)
995  if input_helper_methods.value_of('lengthCorrelatedAperture',
996  params)[0] == 0:
997  input_helper_methods.error(
998  "\"lengthCorrelatedAperture\"'s first value cannot be 0.")
999  if input_helper_methods.value_of('lengthCorrelatedAperture',
1000  params)[1] == 0:
1001  input_helper_methods.warning(
1002  "\"lengthCorrelatedAperture\"'s second value is 0, which will result in a constant aperature.",
1003  params)
1004 
1005  else:
1006  input_helper_methods.error("\"aperture\" must only be option 1 (log-normal), 2 (from transmissivity), "\
1007  "3 (constant), or 4 (length correlated).")
1008 
1009  def permeability():
1010  """Verify the float used for permeability, if permOption is set to 1"""
1011  if input_helper_methods.verify_flag(
1012  input_helper_methods.value_of('permOption'),
1013  'permOption') == 1:
1014  if input_helper_methods.verify_float(
1015  input_helper_methods.value_of('constantPermeability',
1016  params),
1017  'constantPermeability') == 0:
1018  params['constantPermeability'][0] = 1e-25
1019  input_helper_methods.warning("\"constantPermeability\" was set to 0 and has been changed "\
1020  "to 1e-25 so fractures have non-zero permeability.", params)
1021 
1022 
1025 
1026  def n_poly():
1027  """Verify the number of polygons integer."""
1028  val = input_helper_methods.verify_int(input_helper_methods.value_of(
1029  'nPoly', params),
1030  'nPoly',
1031  noNeg=True)
1032  if val == 0: input_helper_methods.error("\"nPoly\" cannot be zero.")
1033  params['nPoly'][0] = val
1034 
1035  def p32_targets():
1036  """Verify the p32 target parameters for ellipses and parameters."""
1037  global ellipseFams, rectFams
1038  errResult = None if (ellipseFams == 0) else input_helper_methods.verify_list(input_helper_methods.value_of('e_p32Targets', params), 'e_p32Targets', \
1039  input_helper_methods.verify_float, desiredLength = ellipseFams, noNegs=True, noZeros=True)
1040  if errResult != None:
1041  input_helper_methods.error("\"e_p32Targets\" has defined {} p32 values but there is(are) {} ellipse family(ies). "\
1042  "Need one p32 value per ellipse family.".format(-errResult, ellipseFams))
1043 
1044  errResult = None if (rectFams == 0) else input_helper_methods.verify_list(input_helper_methods.value_of('r_p32Targets', params), "r_p32Targets", \
1045  input_helper_methods.verify_float, desiredLength = rectFams, noNegs=True, noZeros=True)
1046  if errResult != None:
1047  input_helper_methods.error("\"r_p32Targets\" has defined {} p32 value(s) but there is(are) {} rectangle "\
1048  "family(ies). Need one p32 value per rectangle family)".format(-errResult, rectFams))
1049 
1050  def f(theta, t, a, b):
1051  """Differential Equation Angle Theta as a function of arc length, see Hyman et al. 2014, SIAM J. Sci. Compu
1052  Equation 3.3"""
1053  return 1.0 / np.sqrt((a * np.sin(theta))**2 + (b * np.cos(theta)**2))
1054 
1055  def h_shape_check(aspect, minRadius, num_points=4):
1056  """ Check that the arc length discretized ellipse is greater than 3*h """
1057  # Major and Minor Axis of Ellipse
1058 
1059  r = minRadius
1060 
1061 
1062  a = aspect
1063  b = 1.0
1064 
1065  # approximation of total arclength
1066  c = np.pi * (a + b) * (1.0 + (3.0 * ((a - b) / (a + b))**2) /
1067  (10. + np.sqrt(4. - 3. * ((a - b) /
1068  (a + b))**2)))
1069 
1070  #number of points
1071  n = num_points
1072  # expected arclength
1073  ds = c / n
1074 
1075  # array of steps
1076  steps = np.linspace(0, c, n + 1)
1077  # Numerically integrate arclength ODE
1078  theta = scipy.integrate.odeint(f, 0, steps, args=(a, b), rtol=10**-10)
1079 
1080  # Convert theta to x and y
1081  x = a * r * np.cos(theta)
1082  y = b * r * np.sin(theta)
1083 
1084  # Check Euclidean Distance between consecutive points
1085  h_min = 99999999999
1086  for i in range(1, n):
1087  for j in range(i, n):
1088  if (i != j):
1089  h_current = np.sqrt((x[i] - x[j])**2 + (y[i] - y[j])**2)
1090  if (h_current < h_min):
1091  h_min = h_current
1092 
1093  return h_min
1094 
1095  def compare_pts_v_sh(prefix, hval):
1096  """ Check that the rectangles and ellipses generated will not involve features with length less than 3*h value used in FRAM.
1097  """
1098  shape = "ellipse" if prefix == 'e' else "rectangle"
1099  aspectList = params[prefix + "aspect"][0]
1100  numPointsList = None
1101 
1102  if shape == "ellipse":
1103  numPointsList = params['enumPoints'][0]
1104 
1105 
1106  numLog = 0
1107  numTPL = 0
1108  numEXP = 0
1109  numConst = 0
1110  numAspect = 0
1111 
1112  for distrib in params[prefix + 'distr'][0]:
1113  if distrib in [1, 2, 3, 4]:
1114  if distrib == 1:
1115  minRad = params[prefix + 'LogMin'][0][numLog]
1116  numLog += 1
1117  elif distrib == 2:
1118  minRad = params[prefix + 'min'][0][numTPL]
1119  numTPL += 1
1120  elif distrib == 3:
1121  minRad = params[prefix + 'ExpMin'][0][numEXP]
1122  numEXP += 1
1123  elif distrib == 4:
1124  minRad = params[prefix + 'const'][0][numConst]
1125  numConst += 1
1126  if shape == "ellipse":
1127  hmin = h_shape_check(float(aspectList[numAspect]),
1128  float(minRad),
1129  int(numPointsList[numAspect]))
1130  else:
1131  hmin = h_shape_check(
1132  float(aspectList[numAspect]), float(minRad)
1133  )
1134 
1135  if hmin < (3 * hval):
1136  input_helper_methods.error(shape + " family #{} has defined a shape with features too small for meshing. Increase the aspect "\
1137  "ratio or minimum radius so that no 2 points of the polygon create a line of length less "\
1138  "than 3h".format(numAspect+1))
1139 
1140  numAspect += 1
1141 
1142  def h():
1143  """ Check the float value provided for h to be used in FRAM (the feautre rejection algorithm for meshing.
1144  """
1145  global minFracSize
1146 
1147  val = input_helper_methods.verify_float(input_helper_methods.value_of(
1148  'h', params),
1149  'h',
1150  noNeg=True)
1151 
1152  if val == 0: input_helper_methods.error("\"h\" cannot be 0.")
1153  if minFracSize is None:
1154  minFracSize = 1
1155  if val < minFracSize / 1000.0 and ellipseFams + rectFams > 0:
1162  input_helper_methods.warning("\"h\" (length scale) is smaller than one 1000th of the minimum "\
1163  "fracture size ({}). The generated mesh will be extremely fine and will likely be "\
1164  "computationally exhausting to create. Computation may take longer than usual.".format(minFracSize))
1165  if val > minFracSize / 10.0:
1166  input_helper_methods.warning("\"h\" (length scale) is greater than one 10th of the minimum "\
1167  "fracture size ({}). The generated mesh will be very coarse and there will likely "\
1168  "be a high rate of fracture rejection.".format(minFracSize))
1169 
1170  if val > minFracSize:
1171  input_helper_methods.error("\"h\" (length scale) is greater than the minimum fracture size ({}). "\
1172  "Choose a smaller value for h or a greater minimum fracure size."\
1173  " ".format(minFracSize))
1174  compare_pts_v_sh('e', val)
1175  compare_pts_v_sh('r', val)
1176 
1177  params['h'][0] = val
1178 
1179  def boundary_faces():
1180  """Check that the boundaryFaceis list is a list of flags of length 6, one for each side of the domain
1181  ie {1, 1, 1, 0, 0, 1} represents --> {+x, -x, +y, -y, +z, -z}
1182  DFN only keeps clusters with connections to domain boundaries set to 1.
1183  """
1184  errResult = input_helper_methods.verify_list(
1185  input_helper_methods.value_of('boundaryFaces', params),
1186  'boundaryFaces', input_helper_methods.verify_flag, 6)
1187  if errResult != None:
1188  input_helper_methods.error("\"boundaryFaces\" must be a list of 6 flags (0 or 1), {} have(has) been defined. Each flag "\
1189  "represents a side of the domain, {{+x, -x, +y, -y, +z, -z}}.".format(-errResult))
1190 
1191  def enum_points():
1192  """ Check the integer value of enumPoints for each ellipse family."""
1193  errResult = input_helper_methods.verify_list(
1194  input_helper_methods.value_of('enumPoints', params),
1195  'enumPoints',
1196  input_helper_methods.verify_int,
1197  desiredLength=ellipseFams,
1198  noZeros=True,
1199  noNegs=True)
1200  if errResult != None:
1201  input_helper_methods.error("\"enumPoints\" has defined {} value(s) but there is(are) {} families of ellipses. Please "\
1202  "define one enumPoints value greater than 4 for each ellipse family.".format(-errResult, ellipseFams))
1203  for val in input_helper_methods.value_of("enumPoints"):
1204  if val <= 4:
1205  input_helper_methods.error("\"enumPoints\" contains a value less than or equal to 4. If 4 points were intended, "\
1206  "define this family as a rectangle family. No polygons with less than 4 verticies are acceptable.")
1207 
1208 
1215 
1216  def aspect(prefix):
1217  """ Check the aspect of the the rectangle or ellipse families. """
1218  shape = "ellipse" if prefix == 'e' else "rectangle"
1219  numFamilies = ellipseFams if prefix == 'e' else rectFams
1220  paramName = prefix + "aspect"
1221 
1222  errResult = input_helper_methods.verify_list(
1223  input_helper_methods.value_of(paramName),
1224  paramName,
1225  input_helper_methods.verify_float,
1226  desiredLength=numFamilies,
1227  noZeros=True,
1228  noNegs=True)
1229  if errResult != None:
1230  input_helper_methods.error("\"{}\" has defined {} value(s) but there is(are) {} {} families. Please define one "\
1231  "aspect ratio for each family.".format(paramName, -errResult, numFamilies, shape))
1232 
1233  def angle_option(prefix):
1234  """ Check the angle option flag. """
1235  paramName = prefix + "AngleOption"
1236  input_helper_methods.verify_flag(
1237  input_helper_methods.value_of(paramName), paramName)
1238 
1239  def layer(prefix):
1240  """ Check the number of layers. """
1241  shape = "ellipse" if prefix == 'e' else "rectangle"
1242  numFamilies = ellipseFams if prefix == 'e' else rectFams
1243  paramName = prefix + "Layer"
1244 
1245  errResult = input_helper_methods.verify_list(
1246  input_helper_methods.value_of(paramName),
1247  paramName,
1248  input_helper_methods.verify_int,
1249  desiredLength=numFamilies)
1250  if errResult != None:
1251  input_helper_methods.error("\"{}\" has defined {} layer(s) but there is(are) {} {} families. "\
1252  "Need one layer per {} family. Layers are numbered by the order they "\
1253  "are defined in 'layers' parameter. Layer 0 is the whole domain."\
1254  .format(paramName, -errResult, numFamilies, shape, shape))
1255 
1256  for layer in input_helper_methods.value_of(paramName):
1257  if input_helper_methods.is_negative(int(layer)):
1258  input_helper_methods.error("\"{}\" contains a negative layer number. Only values from 0 to "\
1259  "{} (numOfLayers) are accepted. Layer 0 corresponds to the entire"\
1260  "domain.".format(paramName, numLayers))
1261  if int(layer) > numLayers:
1262  input_helper_methods.error("\"{}\" contains value '{}' but only {} layer(s) is(are) defined. Make sure the "\
1263  "layer numbers referenced here are found in that same position in \"layers\" "\
1264  "parameter.".format(paramName, layer, numLayers))
1265 
1266  def region(prefix):
1267  """ Check the number of region. """
1268  shape = "ellipse" if prefix == 'e' else "rectangle"
1269  numFamilies = ellipseFams if prefix == 'e' else rectFams
1270  paramName = prefix + "Region"
1271 
1272  errResult = input_helper_methods.verify_list(
1273  input_helper_methods.value_of(paramName),
1274  paramName,
1275  input_helper_methods.verify_int,
1276  desiredLength=numFamilies)
1277  if errResult != None:
1278  input_helper_methods.error("\"{}\" has defined {} layer(s) but there is(are) {} {} families. "\
1279  "Need one layer per {} family. Regions are numbered by the order they "\
1280  "are defined in 'region' parameter. Layer 0 is the whole domain."\
1281  .format(paramName, -errResult, numFamilies, shape, shape))
1282 
1283  for region in input_helper_methods.value_of(paramName):
1284  if input_helper_methods.is_negative(int(region)):
1285  input_helper_methods.error("\"{}\" contains a negative layer number. Only values from 0 to "\
1286  "{} (numOfRegions) are accepted. Layer 0 corresponds to the entire"\
1287  "domain.".format(paramName, numRegions))
1288  if int(region) > numRegions:
1289  input_helper_methods.error("\"{}\" contains value '{}' but only {} region(s) is(are) defined. Make sure the "\
1290  "region numbers referenced here are found in that same position in \"region\" "\
1291  "parameter.".format(paramName, region, numRegions))
1292 
1293  def theta_phi_kappa(prefix):
1294  """ Check the angle parameters used for Fisher distributions
1295  """
1296  shape = "ellipse" if prefix == 'e' else "rectangle"
1297  numFamilies = ellipseFams if prefix == 'e' else rectFams
1298  paramNames = [prefix + name for name in ["theta", "phi", "kappa"]]
1299  errString = "\"{}\" has defined {} angle(s) but there is(are) {} {} family(ies)."\
1300  "Please defined one angle for each {} family."
1301 
1302  for param in paramNames:
1303  errResult = input_helper_methods.verify_list(
1304  input_helper_methods.value_of(param),
1305  param,
1306  input_helper_methods.verify_float,
1307  desiredLength=numFamilies)
1308  if errResult != None:
1309  input_helper_methods.error(
1310  errString.format(param, -errResult, numFamilies, shape,
1311  shape))
1312 
1313  #
1314 
1317 
1318 
1319 
1334 
1336  """ Parse each line of the input file.
1337  """
1338  for line in inputIterator:
1339  line = input_helper_methods.extract_parameters(
1340  line, inputIterator)
1341  if (line != "" and ":" in line):
1342  input_helper_methods.process_line(line, unfoundKeys,
1343  inputIterator, warningFile)
1344  needed = [unfound for unfound in unfoundKeys if unfound in mandatory]
1345  if needed != []:
1346  errString = ""
1347  for key in needed:
1348  errString += "\t\"" + key + "\"\n"
1349  input_helper_methods.error(
1350  "Missing the following mandatory parameters: \n{}".format(
1351  errString))
1352 
1354  """ Verify all of the parameters in the input file.
1355  """
1356  distributions = distr_module.distr(params, numEdistribs, numRdistribs,
1357  minFracSize)
1358  firstPriority = [
1359  n_fam_ell, n_fam_rect, stop_condition, domain_size, num_of_layers,
1360  num_of_regions, seed, domain_size_increase, ignore_boundary_faces,
1361  rejects_per_fracture, user_defined,
1362  input_helper_methods.check_fam_count, check_no_dep_flags, fam_prob
1363  ]
1364 
1365  generalized = [
1366  layer, region, aspect, angle_option, theta_phi_kappa,
1367  distributions.beta_distribution, distributions.distr
1368  ]
1369 
1370  distribs = [
1371  distributions.lognormal_dist, distributions.tpl_dist,
1372  distributions.exponential_dist, distributions.constant_dist
1373  ]
1374 
1375  checkLast = [disable_fram, aperture, permeability]
1376 
1377  for paramFunc in firstPriority:
1378  paramFunc()
1379 
1380  if rectFams > 0:
1381  for paramFunc in generalized:
1382  paramFunc('r')
1383 
1384  if ellipseFams > 0:
1385  enum_points()
1386  for paramFunc in generalized:
1387  paramFunc('e')
1388 
1389  for i, paramFunc in enumerate(distribs):
1390  if numEdistribs[i + 1] > 0:
1391  paramFunc(
1392  'e'
1393  )
1394  if numRdistribs[i + 1] > 0:
1395  paramFunc(
1396  'r')
1397 
1398  for paramFunc in checkLast:
1399  paramFunc()
1400 
1401  def write_back():
1402  """ Write the parameters from the verbose input file back to a simplified input file.
1403  """
1404  for param in params:
1405  if param == 'layers':
1406  writer.write(param + ': ')
1407  for layer in params['layers']:
1408  writer.write(
1409  input_helper_methods.list_to_curly(str(layer)) + " ")
1410  writer.write('\n')
1411 
1412  elif param == 'regions':
1413  writer.write(param + ': ')
1414  for region in params['regions']:
1415  writer.write(
1416  input_helper_methods.list_to_curly(str(region)) + " ")
1417  writer.write('\n')
1418 
1419  elif type(input_helper_methods.value_of(param,
1420  writing=True)) is list:
1421  curl = input_helper_methods.list_to_curly(
1422  str(input_helper_methods.value_of(param, writing=True)))
1423  writer.write(param + ': ' + curl + '\n')
1424  else:
1425  writer.write(
1426  param + ': ' +
1427  str(input_helper_methods.value_of(param, writing=True)) +
1428  '\n')
1429 
1430  #print "--> Checking input files"
1431  try:
1432  if not os.path.exists(os.getcwd()):
1433  print("ERROR: cwd: ", os.getcwd(), " does not exist")
1434  if not os.path.exists(os.path.abspath(self.dfnGen_file)):
1435  print("ERROR: dfnGen input file path: ",
1436  os.path.abspath(self.dfnGen_file), " does not exist")
1437  print(os.path.abspath(self.dfnGen_file))
1438  shutil.copy(os.path.abspath(self.dfnGen_file), os.getcwd())
1439  except:
1440  sys.exit("Unable to copy dfnGen input file\n%s\nExiting" %
1441  self.dfnGen_file)
1442 
1443  ioPaths = {"input": "", "output": ""}
1444  try:
1445  ioPaths["input"] = self.dfnGen_file
1446  except IndexError:
1447  input_helper_methods.error("Please provide an input file path as the first command line argument.\n"\
1448  " $ python3 inputParser.py [inputPath] [outputPath (Optional)]")
1449  try:
1450  ioPaths["output"] = self.jobname + '/' + self.dfnGen_file.split(
1451  '/')[-1][:-4] + '_clean.dat'
1452  ioPaths["output"] = os.path.abspath(ioPaths["output"])
1453  print(ioPaths["output"])
1454  except IndexError:
1455  ioPaths["output"] = "polishedOutput.txt"
1456  input_helper_methods.warning("No output path has been provided so output will be written to "\
1457  "\"polishedOutput.txt\" in your current working directory.", params)
1458  try:
1459  reader = open(ioPaths["input"], 'r')
1460  except:
1461  input_helper_methods.error(
1462  "Check that the path of your input file is valid")
1463  try:
1464  writer = open(ioPaths["output"], 'w')
1465  except:
1466  input_helper_methods.error(
1467  "Check that the path of your output file is valid.")
1468 
1469  inputIterator = iter(reader)
1470  print('--> Checking input data')
1471  print('--> Input Data: ', ioPaths["input"])
1472  print('--> Output File: ', ioPaths["output"])
1473 
1474  parse_input()
1475  verify_params()
1476  write_back()
1477  print('--> Checking Input Data Complete')
def extract_parameters(self, line, inputIterator)
====================================================================== ## Parsing Functions ## ======...
Definition: gen_input.py:195
def process_line(self, line, unfoundKeys, inputIterator, warningFile)
Definition: gen_input.py:261
def val_helper(self, line, valList, key)
Definition: gen_input.py:79
def check_min_max(self, minParam, maxParam, shape)
Definition: gen_input.py:150
def curly_to_list(self, curlyList)
====================================================================== ## Helper Functions ## =======...
Definition: gen_input.py:27
def warning(self, warnString, warningFile='')
Definition: gen_input.py:105
def verify_list(self, valList, key, verificationFn, desiredLength, noZeros=False, noNegs=False)
Definition: gen_input.py:330
def scale(self, probList, warningFile)
Definition: gen_input.py:134
def value_of(self, key, writing=False)
Definition: gen_input.py:50
def find_val(self, line, key, inputIterator, unfoundKeys, warningFile)
Definition: gen_input.py:212
def verify_int(self, value, key="", inList=False, noNeg=False)
Definition: gen_input.py:306
def find_key(self, line, unfoundKeys, warningFile)
Definition: gen_input.py:241
def verify_flag(self, value, key="", inList=False)
====================================================================== ## Verification ## ===========...
Definition: gen_input.py:279
def get_groups(self, line, valList, key)
Definition: gen_input.py:66
def __init__(self, params, minFracSize)
Definition: gen_input.py:19
def verify_float(self, value, key="", inList=False, noNeg=False)
Definition: gen_input.py:289
def check_mean(self, minParam, maxParam, meanParam, warningFile='')
Definition: gen_input.py:165
def check_input(self, input_file='', output_file='')
Definition: gen_input.py:378
def parse_input()
def check_i_oargs(ioPaths): try: ioPaths["input"] = sys.argv[1] except IndexError: input_helper_metho...
Definition: gen_input.py:1335