Source code for pybert.data.datascheme

# -*- coding: utf-8 -*-

import pygimli as pg
import pybert as pb

# import matplotlib.pyplot as plt
import numpy as np
# from numpy import ma


[docs]def createData(elecs, schemeName='none', **kwargs): """ Utility one-liner to create a BERT datafile Parameters ---------- elecs : int | list[pos] | array(x) Number of electrodes or electrode positions or x-positions schemeName : str ['none'] Name of the configuration. If you provide an unknown scheme name, all known schemes ['wa', 'wb', 'pp', 'pd', 'dd', 'slm', 'hw', 'gr'] listed. **kwargs : Arguments that will be forwarded to the scheme generator. * inverse : bool interchange AB MN with MN AB * reciprocity : bool interchange AB MN with BA NM * addInverse : bool add aditional inverse measurements * spacing : float [1] electrode spacing in meters * closed : bool Close the chain. Measure from the end of the array to the first electrode. Returns ------- data : DataContainerERT Examples -------- >>> import matplotlib.pyplot as plt >>> import pybert as pb >>> >>> schms = ['wa', 'wb', 'pp', 'pd', 'dd', 'slm', 'hw', 'gr'] >>> fig, ax = plt.subplots(3,3) >>> >>> for i, schemeName in enumerate(schms): ... s = pb.createData(elecs=21, schemeName=schemeName) ... k = pb.geometricFactor(s) ... mg = pb.data.DataSchemeManager() ... longname = mg.scheme(schemeName).name ... pb.showData(s, vals=k, ax=ax[i/3, i%3], ... label='k ' + longname + ')-' + schemeName) >>> >>> plt.show() """ mg = pb.data.DataSchemeManager() if schemeName is "none": for i in mg.schemes(): print(i, "scheme: " + mg.scheme(i).prefix) scheme = mg.scheme(schemeName) scheme.setInverse(kwargs.pop('inverse', False)) scheme.addInverse(kwargs.pop('addInverse', False)) scheme._closed = kwargs.pop('closed', False) # scheme.setReciprocity(kwargs.pop('reciprocity', False)) if type(elecs) == int: data = scheme.create(nElectrodes=elecs, electrodeSpacing=kwargs.pop('spacing', 1), **kwargs) elif hasattr(elecs, '__iter__'): if type(elecs[0]) == np.float64: data = scheme.create(nElectrodes=len(elecs), **kwargs) for i, p in enumerate(data.sensorPositions()): p[0] = elecs[i] data.setSensorPosition(i, p) else: data = scheme.create(sensorList=elecs, **kwargs) else: print(elecs) raise Exception("cannot interprete elecs") return data
[docs]def createDataVES(ab2, mn2): """ Utility one-liner to create a BERT datafile for Schlumberger 1D VES Parameters ---------- ab2: array Half distance between current electrodes mn2: float Half distance between measurement electrodes Returns ------- data : DataContainerERT """ data = pb.DataContainerERT() if type(mn2) is float or type(mn2) is int: mn2 = [mn2] count = 0 for mn in mn2: emID = data.createSensor([-mn, 0.0, 0.0]) enID = data.createSensor([mn, 0.0, 0.0]) for x in ab2: eaID = data.createSensor([-x, 0.0, 0.0]) ebID = data.createSensor([x, 0.0, 0.0]) data.createFourPointData(count, eaID, ebID, emID, enID) count += 1 data.fitFillSize() return data
[docs]class Pseudotype: unknown = 0 A_M = 1 AB_MN = 2 AB_M = 3 AB_N = 4 DipoleDipole = 5 Schlumberger = 6 WennerAlpha = 7 WennerBeta = 8 Gradient = 9 PoleDipole = 10 HalfWenner = 11 PolePole = 12 Test = 99
[docs]class DataSchemeManager(object): """ """ def __init__(self): """ """ self.schemes_ = dict() self.addScheme(DataSchemeBase()) self.addScheme(DataSchemeWennerAlpha()) self.addScheme(DataSchemeWennerBeta()) self.addScheme(DataSchemeDipoleDipole()) self.addScheme(DataSchemeSchlumberger()) self.addScheme(DataSchemePolePole()) self.addScheme(DataSchemePoleDipole()) self.addScheme(DataSchemeHalfWenner()) self.addScheme(DataSchemeMultipleGradient()) self.addScheme(DataSchemeBase(typ=Pseudotype.A_M, name='A_M')) self.addScheme(DataSchemeBase(typ=Pseudotype.AB_MN, name='AB_MN')) self.addScheme(DataSchemeBase(typ=Pseudotype.AB_M, name='AB_M')) self.addScheme(DataSchemeBase(typ=Pseudotype.AB_N, name='AB_N'))
[docs] def addScheme(self, scheme): """ """ self.schemes_[scheme.name] = scheme
[docs] def scheme(self, name): """ Return DataScheme for a given name if registered. Parameters ---------- name : str | int Name or prefix name of a known data scheme. If the name is unknown all known data schemes are listed. Name can be a integer number that represents the internal Pseudotype. Return ------ scheme : DataScheme """ if type(name) == int: s = self.schemeFromTyp(name) if s: return s elif type(name) == str: # or type(name) == unicode: (always in Py3) s = self.schemeFromPrefix(name) if s: return s if name in self.schemes_.keys(): return self.schemes_[name] print('Unknown scheme name:', name) print('-----------------------') print('Valid names or prefixes') print('-----------------------') for s in self.schemes_.values(): print(s.name, ': ', s.prefix) raise Exception("No scheme known for name: ", name) return DataSchemeBase()
# name = 'unknown' # return self.schemes_[name]
[docs] def schemeFromPrefix(self, prefix): """ Return DataScheme for a given prefix name. """ for s in list(self.schemes_.values()): if s.prefix == prefix: return s return None
[docs] def schemeFromTyp(self, typ): for s in list(self.schemes_.values()): if s.typ == typ: return s return None
[docs] def schemes(self): ''' ''' return list(self.schemes_.keys())
[docs]class DataSchemeBase(object): """ Attributes ---------- closed : bool Close the chain. Measure from the end of the array to the first electrode. """ def __init__(self, typ=Pseudotype.unknown, name="unknown", prefix='uk'): self.name = name self.prefix = prefix self.typ = typ self.data_ = None self.inverse_ = False self.addInverse_ = False self.reciprocity = False self.nElectrodes_ = 0 self.maxSeparation = 1e99 self._closed = False @property def closed(self): return self._closed
[docs] def create(self, nElectrodes=24, electrodeSpacing=1, sensorList=None, **kwargs): """ """ self.createElectrodes(nElectrodes, electrodeSpacing, sensorList) self.createData(kwargs) if self.addInverse_: out = pb.DataContainerERT(self.data_) self.setInverse(not self.inverse_) self.createData(kwargs) self.data_.add(out) self.data_.removeInvalid() self.data_.sortSensorsIndex() if kwargs.values(): print("Warning! DataSchemeBase::create has unhandled arguments") print(kwargs) return self.data_
[docs] def createElectrodes(self, nElectrodes=24, electrodeSpacing=1, sensorList=None): self.data_ = pb.DataContainerERT() if sensorList is not None: for p in sensorList: if isinstance(p, float): self.data_.createSensor((p, 0.)) else: self.data_.createSensor(p) else: for i in range(nElectrodes): self.data_.createSensor(pg.RVector3(float(i) * electrodeSpacing, 0.0)) self.nElectrodes_ = self.data_.sensorCount()
[docs] def createData(self, kwargs): print('*'*100)
# raise (abstract)
[docs] def setInverse(self, inverse=False): self.inverse_ = inverse
[docs] def addInverse(self, addInverse=False): """ Add inverse value to create a full dataset. """ self.addInverse_ = addInverse
[docs] def setMaxSeparation(self, maxSep): if maxSep > 0.0: self.maxSeparation = maxSep else: self.maxSeparation = 1e99
[docs] def createDatum_(self, a, b, m, n, count): if a < self.nElectrodes_ and b < self.nElectrodes_ and \ m < self.nElectrodes_ and n < self.nElectrodes_: if self.inverse_: self.data_.createFourPointData(count, m, n, a, b) else: self.data_.createFourPointData(count, a, b, m, n) count += 1 return count
[docs]class DataSchemePolePole(DataSchemeBase): ''' ''' def __init__(self): DataSchemeBase.__init__(self) self.name = "Pole Pole (C-P)" self.prefix = "pp" self.typ = Pseudotype.PolePole
[docs] def createData(self, kwargs): ''' ''' nElectrodes = self.nElectrodes_ # reserve a couple more than nesseccary ### self.data_.resize((nElectrodes) * (nElectrodes)) count = 0 # enlargeEverySep = 0 # not used b = -1 n = -1 for a in range(0, nElectrodes): for m in range(a + 1, nElectrodes): if m - a > self.maxSeparation: break count = self.createDatum_(a, b, m, n, count) self.data_.removeInvalid() return self.data_
[docs]class DataSchemeDipoleDipole(DataSchemeBase): """Dipole-dipole data scheme. """ def __init__(self): DataSchemeBase.__init__(self) self.name = "Dipole Dipole (CC-PP)" self.prefix = "dd" self.typ = Pseudotype.DipoleDipole self.enlargeEverySep = 0 self.spacings = [1]
[docs] def createData(self, kwargs): """ Create a Dipole-Dipole dataset. Don't use direct .. call create from DataSchemeManager or pybert.createData(**kwargs) instead. Parameters ---------- **kwargs: * complete : bool Add reciprocity measurements. """ nElectrodes = self.nElectrodes_ complete = kwargs.pop('complete', False) if complete: self._closed = True self.enlargeEverySep = kwargs.pop('enlarge', 0) self.spacings = kwargs.pop('spacings', self.spacings) # self.createElectrodes(nElectrodes, electrodeSpacing) # reserve a couple more than necessary ### nElectrodes = self.nElectrodes_ self.data_.resize(nElectrodes * nElectrodes) count = 0 if self.closed: space = 1 for i in range(nElectrodes): a = i b = (a + space) % nElectrodes for j in range(nElectrodes): m = (j) % nElectrodes n = (m + space) % nElectrodes if not complete: if j <= i: continue if a != m and a != n and b != m and b != n: count = self.createDatum_(a, b, m, n, count) else: for space in self.spacings: maxSep = nElectrodes - space maxInj = nElectrodes - space if self.maxSeparation < maxSep: maxSep = self.maxSeparation for sep in range(1, maxSep + 1): if self.enlargeEverySep > 0: if (sep-1) % self.enlargeEverySep == 0: space += 1 for i in range(maxInj - sep): a = i b = (a + space) % nElectrodes m = (b + sep) % nElectrodes n = (m + space) % nElectrodes if m + space < nElectrodes: count = self.createDatum_(a, b, m, n, count) self.data_.removeInvalid() return self.data_
[docs]class DataSchemePoleDipole(DataSchemeBase): """Pole-dipole data scheme""" def __init__(self): DataSchemeBase.__init__(self) self.name = "Pole Dipole (C-PP)" self.prefix = "pd" self.typ = Pseudotype.PoleDipole
[docs] def createData(self, kwargs): ''' ''' nElectrodes = self.nElectrodes_ # self.createElectrodes(nElectrodes, electrodeSpacing) # reserve a couple more than nesseccary !!! self.data_.resize((nElectrodes) * (nElectrodes)) count = 0 # enlargeEverySep = 0 # not yet used b = -1 for a in range(0, nElectrodes): for m in range(a + 1, nElectrodes - 1): n = m + 1 if m - a > self.maxSeparation: break count = self.createDatum_(a, b, m, n, count) self.data_.removeInvalid() return self.data_
[docs]class DataSchemeHalfWenner(DataSchemeBase): """Pole-Dipole like Wenner Beta with increasing dipole distance""" def __init__(self): DataSchemeBase.__init__(self) self.name = "Half Wenner (C-P-P)" self.prefix = "hw" self.typ = Pseudotype.HalfWenner
[docs] def createData(self, kwargs): ''' ''' nElectrodes = self.nElectrodes_ # reserve a couple more than nesseccary !!! self.data_.resize((nElectrodes) * (nElectrodes)) print("create", self.maxSeparation) count = 0 # space = 0 # not yet used # enlargeEverySep = 0 # not yet used b = -1 for a in range(0, nElectrodes): inc = 1 while True: m = a - inc n = m - inc if m < 0 or n < 0 or inc > self.maxSeparation: break count = self.createDatum_(a, b, m, n, count) inc = inc + 1 inc = 1 while True: m = a + inc n = m + inc if m > nElectrodes or n > nElectrodes or \ inc > self.maxSeparation: break count = self.createDatum_(a, b, m, n, count) inc = inc + 1 self.data_.removeInvalid() self.data_.sortSensorsIndex() return self.data_
[docs]class DataSchemeWennerAlpha(DataSchemeBase): """Wenner alpha (C--P--P--C) data scheme with equal distances. """ def __init__(self): DataSchemeBase.__init__(self) self.name = "Wenner Alpha (C-P-P-C)" self.prefix = "wa" self.typ = Pseudotype.WennerAlpha
[docs] def createData(self, kwargs): ''' ''' nElectrodes = self.nElectrodes_ maxSep = nElectrodes - 2 if self.maxSeparation < maxSep: maxSep = self.maxSeparation # reserve a couple more than nesseccary !!! self.data_.resize(nElectrodes * nElectrodes) count = 0 for sep in range(1, maxSep + 1): for i in range((nElectrodes - 2) - sep): a = i m = a + sep n = m + sep b = n + sep count = self.createDatum_(a, b, m, n, count) self.data_.removeInvalid() return self.data_
[docs]class DataSchemeWennerBeta(DataSchemeBase): """Wenner-beta (C--C--P--P) data scheme with equal distance.""" def __init__(self): DataSchemeBase.__init__(self) self.name = "Wenner Beta(C-C-P-P)" self.prefix = "wb" self.typ = Pseudotype.WennerBeta
[docs] def createData(self, kwargs): ''' ''' nElectrodes = self.nElectrodes_ maxSep = nElectrodes - 2 if self.maxSeparation < maxSep: maxSep = self.maxSeparation # reserve a couple more than nesseccary ### self.data_.resize((nElectrodes * nElectrodes)) count = 0 for sep in range(1, maxSep + 1): for i in range((nElectrodes - 2) - sep): a = i b = a + sep m = b + sep n = m + sep count = self.createDatum_(a, b, m, n, count) self.data_.removeInvalid() return self.data_
# class DataSchemeSchlumberger(...)
[docs]class DataSchemeSchlumberger(DataSchemeBase): """Wenner-Schlumberger (C--P-P--C) data scheme. """ def __init__(self): DataSchemeBase.__init__(self) self.name = "Schlumberger(C-PP-C)" self.prefix = "slm" self.typ = Pseudotype.Schlumberger
[docs] def createData(self, kwargs): ''' ''' nElectrodes = self.nElectrodes_ maxSep = nElectrodes - 2 if self.maxSeparation < maxSep: maxSep = self.maxSeparation self.data_.resize(nElectrodes * nElectrodes) count = 0 for sep in range(1, maxSep + 1): for i in range((nElectrodes - 2) - sep): a = i m = a + sep n = m + 1 b = n + sep count = self.createDatum_(a, b, m, n, count) self.data_.removeInvalid() return self.data_
[docs]class DataSchemeMultipleGradient(DataSchemeBase): """MultipleGradient (C---P-P--C) data scheme. """ def __init__(self): DataSchemeBase.__init__(self) self.name = "MultipleGradient(C--P-P--C)" self.prefix = "gr" self.typ = Pseudotype.Gradient
[docs] def createData(self, kwargs): ''' ''' nElectrodes = self.nElectrodes_ ab_sep_base = 9 # number of channels + 2 ev = 2 takeevery = 2 max_fak = int(np.ceil(nElectrodes / ab_sep_base)) ab_space = [ii*ab_sep_base for ii in range(max_fak) if ii % ev == 1] mn_space = [ii for ii in range(max_fak) if ii % takeevery == 1] count = 0 a, b, m, n = [], [], [], [] for ab in range(len(ab_space)): # ab spacings for aa in np.arange(1, nElectrodes-ab_space[ab]+1, 1): # a index mn = mn_space[ab] for mm in np.arange(aa+mn, aa+ab_space[ab]-mn, mn): count += 1 a.append(int(aa)) b.append(int(aa+ab_space[ab])) m.append(int(mm)) n.append(int(mm+mn)) self.data_.resize(count) self.data_.set('a', pg.RVector(a) - 1) self.data_.set('b', pg.RVector(b) - 1) self.data_.set('m', pg.RVector(m) - 1) self.data_.set('n', pg.RVector(n) - 1) self.data_.set('valid', pg.RVector(count, 1)) if 0: print(self.data_) self.data_.checkDataValidity() self.data_.removeInvalid() print(self.data_) return self.data_
if __name__ == '__main__': import matplotlib.pyplot as plt schms = ['wa', 'wb', 'pp', 'pd', 'dd', 'slm', 'gr', 'hw'] fig, ax = plt.subplots(3, 3) for i, schemeName in enumerate(schms): s = createData(elecs=21, schemeName=schemeName) k = pb.geometricFactor(s) mg = pb.data.DataSchemeManager() longname = mg.scheme(schemeName).name pb.showData(s, vals=k, ax=ax[i/3, i % 3], label='k ' + longname + ')-' + schemeName) plt.show()