Source code for mtpy.modeling.modem.control_fwd

"""
==================
ModEM
==================

# Generate files for ModEM

# revised by JP 2017
# revised by AK 2017 to bring across functionality from ak branch
# revised by OA 2024 to update docs

"""

# =============================================================================
# Imports
# =============================================================================
from pathlib import Path

from mtpy.utils import exceptions as mtex

# =============================================================================


[docs] class ControlFwd: """Reads and writes control files for ModEM to control how the forward solver starts and how it is run. ==================== ====================================================== Attributes Description ==================== ====================================================== num_qmr_iter Number of QMR iterations per divergence correction. int, *default* is 40 max_num_div_calls Maximum number of divergence correction calls. int, *default* is 20 max_num_div_iters Maximum number of divergence correction iterations. int, *default* is 100 misfit_tol_fwd Misfit tolerance for EM forward solver. float, *default* is 1e-07 misfit_tol_adj Misfit tolerance for EM adjoint solver. float, *default* is 1e-07 misfit_tol_div Misfit tolerance for divergence correction. float, *default* is 1e-05 save_path Path at which to save the control file. PosixPath, *default* is current working directory. fn_basename Name of the control file. str, *default* is 'control.fwd', """ def __init__(self, **kwargs): self.num_qmr_iter = 40 self.max_num_div_calls = 20 self.max_num_div_iters = 100 self.misfit_tol_fwd = 1.0e-7 self.misfit_tol_adj = 1.0e-7 self.misfit_tol_div = 1.0e-5 self.save_path = Path().cwd() self.fn_basename = "control.fwd" self._control_keys = [ "Number of QMR iters per divergence correction", "Maximum number of divergence correction calls", "Maximum number of divergence correction iters", "Misfit tolerance for EM forward solver", "Misfit tolerance for EM adjoint solver", "Misfit tolerance for divergence correction", ] self._control_dict = dict( [ (key, value) for key, value in zip( self._control_keys, [ self.num_qmr_iter, self.max_num_div_calls, self.max_num_div_iters, self.misfit_tol_fwd, self.misfit_tol_adj, self.misfit_tol_div, ], ) ] ) self._string_fmt_dict = dict( [ (key, value) for key, value in zip( self._control_keys, ["<.0f", "<.0f", "<.0f", "<.1e", "<.1e", "<.1e"], ) ] ) for key, value in kwargs.items(): setattr(self, key, value) @property def control_fn(self): """Control fn.""" return self.save_path.joinpath(self.fn_basename) @control_fn.setter def control_fn(self, value): """Control fn.""" if value is not None: value = Path(value) self.save_path = value.parent self.fn_basename = value.name
[docs] def write_control_file(self, control_fn=None, save_path=None, fn_basename=None): """Write control file. Arguments:: **control_fn** : string full path to save control file to *default* is save_path/fn_basename **save_path** : string directory path to save control file to *default* is cwd **fn_basename** : string basename of control file *default* is control.inv """ if control_fn is not None: self.control_fn = control_fn if save_path is not None: self.save_path = Path(save_path) if fn_basename is not None: self.fn_basename = fn_basename self._control_dict = dict( [ (key, value) for key, value in zip( self._control_keys, [ self.num_qmr_iter, self.max_num_div_calls, self.max_num_div_iters, self.misfit_tol_fwd, self.misfit_tol_adj, self.misfit_tol_div, ], ) ] ) clines = [] for key in self._control_keys: value = self._control_dict[key] str_fmt = self._string_fmt_dict[key] clines.append("{0:<47}: {1:{2}}\n".format(key, value, str_fmt)) with open(self.control_fn, "w") as cfid: cfid.writelines(clines) print("Wrote ModEM control file to {0}".format(self.control_fn))
[docs] def read_control_file(self, control_fn=None): """Read in a control file.""" if control_fn is not None: self.control_fn = control_fn if self.control_fn is None: raise mtex.MTpyError_file_handling( "control_fn is None, input " "control file" ) if not self.control_fn.is_file(): raise mtex.MTpyError_file_handling( "Could not find {0}".format(self.control_fn) ) with open(self.control_fn, "r") as cfid: clines = cfid.readlines() for cline in clines: clist = cline.strip().split(":") if len(clist) == 2: try: self._control_dict[clist[0].strip()] = float(clist[1]) except ValueError: self._control_dict[clist[0].strip()] = clist[1] # set attributes attr_list = [ "num_qmr_iter", "max_num_div_calls", "max_num_div_iters", "misfit_tol_fwd", "misfit_tol_adj", "misfit_tol_div", ] for key, kattr in zip(self._control_keys, attr_list): setattr(self, kattr, self._control_dict[key])