# Source code for pygimli.utils.base

```# -*- coding: utf-8 -*-
"""Pygimli base functions.

Some needs to be sorted. Need to fit nameing conventions!
"""
import os.path
import time

import numpy as np
import pygimli as pg

[docs]
def rms(v, axis=None):
"""Compute the root mean square."""
# abs for complex values
return np.sqrt(np.mean(np.abs(v)**2, axis))

[docs]
def rrms(a, b, axis=None):
"""Compute the relative (regarding a) root mean square."""
# abs for complex values
return rms(np.abs(a-b)/np.abs(a), axis)

[docs]
def nanrms(v, axis=None):
"""Compute the root mean square excluding nan values."""
# abs for complex values
return np.sqrt(np.nanmean(np.abs(v)**2, axis))

[docs]
def rmsWithErr(a, b, err, errtol=1):
"""Compute (abs-)root-mean-square of values with error above threshold."""
fi = pg.find(err < errtol)
return rms(a[fi] - b[fi])

[docs]
def chi2(a, b, err, trans=None):
"""Return chi square value."""
if trans is None:
trans = pg.trans.Trans()

d = (trans(a) - trans(b)) / trans.error(a, err)
return pg.math.dot(d, d) / len(d)

# fc_cleaning compatibilty to bert
rmswitherr = rmsWithErr

def rrmsWithErr(a, b, err, errtol=1):
"""Compute root mean square of values with error above a threshold."""
fi = pg.find(err < errtol)
return rms((a[fi]-b[fi])/a[fi])

[docs]
def gmat2numpy(mat):
"""Convert pygimli matrix into numpy.array.

TODO implement correct rval
"""
nmat = np.zeros((len(mat), len(mat[0])))
for i, row in enumerate(mat):
nmat[i] = row
return nmat

[docs]
def numpy2gmat(nmat):
"""Convert numpy.array into pygimli RMatrix.

TODO implement correct rval
"""
gmat = pg.Matrix()
for arr in nmat:
gmat.push_back(arr)  # pg.asvector(arr))
return gmat

[docs]
def rndig(a, ndig=3):
"""Round float using a number of counting digits."""
if np.abs(a) < 1e-4:
return a
else:
return np.around(a, ndig - int(np.ceil(np.log10(np.abs(a) + 1e-4))))

[docs]
def num2str(a, fmtstr='%g'):
"""List of strings (deprecated, for backward-compatibility)."""
return [fmtstr % rndig(ai) for ai in a]

[docs]
def inthist(a, vals, bins=None, islog=False):
"""Return point of integral (cumulative) histogram.

E.g. inthist(a, [25, 50, 75]) provides quartiles and median of an array"""
if bins is None:
bins = int(np.min((np.round(len(a) / 20), 10)))

if islog:
hists, edges = np.histogram(np.log(a), bins=bins)
else:
hists, edges = np.histogram(a, bins=bins)

cums = np.cumsum(np.hstack((0., hists))) / np.sum(hists) * 100.
out = np.interp(vals, cums, edges)
if islog:
return np.exp(out)
else:
return out

[docs]
def interperc(a, trimval=3.0, islog=False, bins=None):
"""Return symmetric interpercentiles for alpha-trim outliers.

E.g. interperc(a, 3) returns range of inner 94% (3 to 97%)
which is particularly useful for colorscales)."""
return inthist(a, np.array([trimval, 100. - trimval]),
bins=bins, islog=islog)

[docs]
def interpExtrap(x, xp, yp):
"""numpy.interp interpolation function extended by linear extrapolation."""
y = np.interp(x, xp, yp)
y = np.where(x < xp[0], yp[0]+(x-xp[0])*(yp[0]-yp[1])/(xp[0]-xp[1]), y)
return np.where(x > xp[-1], yp[-1]+(x-xp[-1])*(yp[-1]-yp[-2]) /
(xp[-1]-xp[-2]), y)

[docs]
def saveResult(fname, data, rrms=None, chi2=None, mode='w'):
"""Save rms/chi2 results into filename."""
pg.warn("utils.saveResult .. in use? (debug)")
with open(fname, mode) as f:
np.savetxt(f, data)
if rrms is not None:
f.write('\nrrms:{}\n'.format(rrms))
if chi2 is not None:
f.write('\nchi2:{}\n'.format(chi2))

[docs]
def createDateTimeString(now=None):
"""Return datetime as string (e.g. for saving results)."""
if now is None:
now = time.localtime()
return str(now.tm_year) + str(now.tm_mon).zfill(2) + \
str(now.tm_mday).zfill(2) + '-' + \
str(now.tm_hour).zfill(2) + '.' + \
str(now.tm_min).zfill(2)

[docs]
def getSavePath(folder=None, subfolder='', now=None):
"""TODO."""
if folder is None:
path = createResultPath(subfolder, now=now)
else:
path = createPath([folder, subfolder])
return path

[docs]
def createResultPath(subfolder, now=None):
"""Create a result Folder."""
result = createDateTimeString(now)
return createPath(['.', result, subfolder])

[docs]
def createPath(pathList):
"""Create the path structure specified by list.

Parameters
----------
pathList: str | list(str)
Create Path with option subpaths
"""
if hasattr(pathList, '__iter__'):
path = os.path.join('', *pathList)
else:
path = os.path.join('', pathList)

try:
os.makedirs(path)
except FileExistsError:
except OSError as e:
pg.error(f'Unable to create path "{path}".')
raise e
return path

@pg.renamed(createResultPath, '1.2')  # 20200515
def createResultFolder(subfolder, now=None):
pass

@pg.renamed(createPath, '1.2')  # 20200515
def createfolders(foldername_list):
pass

@pg.renamed(createPath, '1.2')  # 20200515
def createFolders(pathList):
pass
```