Source code for modparams

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
-----------------------------------------
  Modification of contMech params files
-----------------------------------------

A collection of functions allowing to modify a `contMech` params file in-place.

.. warning::
    This module uses system calls to `sed` (on GNU/Linux) or `gsed` (on Mac).
    Note that the Mac version of `sed` is fundamentally different to GNU's. 
    Importing the module raises an error if GNU `sed` is not installed properly.


---------------------
  API documentation
---------------------

"""

DEBUG = False
SED = 'sed'

import os, sys
from cmparams import paramType
from subprocess import run as call



# check the installed version of sed/gsed
testfile = "_modparams_test_"
with open(testfile, "w") as fid: fid.write("original")
try: 
  proc = call(["gsed", "-i", r"/original/c\modified", testfile], capture_output=True)
  returnval = proc.returncode
  if returnval: print(proc.stderr)
except: 
  returnval = 1
if returnval:
  try: 
    proc = call(["sed", "-i", r"/original/c\modified", testfile], capture_output=True)
    returnval = proc.returncode
    if returnval: print(proc.stderr)
  except: 
    returnval = 1
  if returnval:
    os.remove(testfile)
    raise OSError("sed/gsed not working as intended.")
  else: 
    with open(testfile, "r") as fid: content = fid.read()
    if content == "modified\n": SED = "sed"
    else: 
      if DEBUG: print(content)
      os.remove(testfile)
      raise OSError("sed/gsed not working as intended.")
else: 
  with open(testfile, "r") as fid: content = fid.read()
  if content == "modified\n": SED = "gsed"
  else: 
    if DEBUG: print(content)
    os.remove(testfile)
    raise OSError("sed/gsed not working as intended.")
os.remove(testfile)


[docs] def sed(command, file): proc = call([SED, "-i", command, file], capture_output=True) if proc.returncode: print(proc.stderr) raise proc.check_returncode()
[docs] def check(params, values=None): if isinstance(params, str): params = [params] for i in range(len(params)): if params[i][:2] == '# ': params[i] = params[i][2:] if params[i][-2:] == ' #': params[i] = params[i][:-2] if values is not None: if isinstance(values, int) or isinstance(values, float): values = [values] if len(values)==1: values = [values[0]]*len(params) if len(values)!=len(params): raise ValueError(f'parameter names and values must have same length, but have {len(params)} and {len(values)}') return params, values else: return params
[docs] def param_type(param): try: ptype = paramType[param] except: print(f'WARNING: Unknown paramType for _{param}_. Assuming float.') ptype = 'float' return ptype
[docs] def get_values(params, file): # sanity checks if not os.path.isfile(file): raise ValueError('invalid params file: %s' % file) params = check(params) values = [0]*len(params) with open(file,'r') as fid: for line in fid.readlines(): for i,param in enumerate(params): ptype = param_type(param) if f'# {param} #' in line: #print(line)#DEBUG if ptype == 'int': values[i] = int(line.split()[0]) else: values[i] = float(line.split()[0]) return values
[docs] def set(params, values, file='params.in'): # sanity checks if not os.path.isfile(file): raise ValueError('invalid params file: %s' % file) params, values = check(params, values) for param,pval in zip(params,values): ptype = param_type(param) if ptype == 'int': newval = int(round(pval)) command = f"/# {param} #/c\\{newval}\\t\\t# {param} #" else: newval = pval command = f"/# {param} #/c\\{newval:g}\\t\\t# {param} #" if DEBUG: print(f"{SED} -i '{command}' {file}") sed(command, file)
[docs] def add(params, values, after, file='params.in'): # sanity checks if not os.path.isfile(file): raise ValueError('invalid params file: %s' % file) params, values = check(params, values) if after[:2] == '# ': after = after[2:] if after[-2:] == ' #': after = after[:-2] for param,pval in zip(params,values): ptype = param_type(param) if ptype == 'int': newval = int(round(pval)) command = f"/# {after} #/a\\{newval}\\t\\t# {param} #" else: newval = pval command = f"/# {after} #/a\\{newval:g}\\t\\t# {param} #" if DEBUG: print(f"{SED} -i '{command}' {file}") sed(command, file)
[docs] def multiply(params, factors, file='params.in'): # sanity checks params, factors = check(params, factors) old_values = get_values(params, file) new_values = [val*fac for val,fac in zip(old_values, factors)] set(params, new_values, file)
# old functions for compatibility paramNames = ['nTime'] paramFacs = [1]
[docs] def modify(file): multiply(file, paramNames, paramFacs)
[docs] def run(file=None): if len(paramNames) != len(paramFacs): raise ValueError('paramNames, paramFacs and paramTypes must have the same length!') modify(file)