Exemple #1
0
    def restore(self):
        """Read data from json infos"""
        if os.path.exists(self._name + '.json'):

            # Fricking mpl kills locale setting to system default .. this went
            # horrible wrong for german 'decimal_point': ','
            pg.checkAndFixLocaleDecimal_point(verbose=False)

            try:
                with open(self._name + '.json') as file:
                    self.info = json.load(file)

                # if len(self.info['type']) != 1:
                #     pg.error('only single return caches supported for now.')

                #pg._y(pg.pf(self.info))
                
                if self.info['type'] == 'DataContainerERT':
                    self._value = pg.DataContainerERT(self.info['file'],
                                                      removeInvalid=False)
                    # print(self._value)
                elif self.info['type'] == 'RVector':
                    self._value = pg.Vector()
                    self._value.load(self.info['file'], format=pg.core.Binary)
                elif self.info['type'] == 'Mesh':
                    pg.tic()
                    self._value = pg.Mesh()
                    self._value.loadBinaryV2(self.info['file'] + '.bms')
                    pg.debug("Restoring cache took:", pg.dur(), "s")
                elif self.info['type'] == 'ndarray':
                    self._value = np.load(self.info['file'] + '.npy',
                                          allow_pickle=True)
                elif self.info['type'] == 'Cm05Matrix':
                    self._value = pg.matrix.Cm05Matrix(self.info['file'])
                elif self.info['type'] == 'GeostatisticConstraintsMatrix':
                    self._value = pg.matrix.GeostatisticConstraintsMatrix(
                                                            self.info['file'])
                else:
                    self._value = np.load(self.info['file'] + '.npy',
                                          allow_pickle=True)

                if self.value is not None:
                    self.info['restored'] = self.info['restored'] + 1
                    self.updateCacheInfo()
                    pg.info('Cache {3} restored ({1}s x {0}): {2}'.\
                        format(self.info['restored'],
                               round(self.info['dur'], 1),
                               self._name, self.info['codeinfo']))
                else:
                    # default try numpy
                    pg.warn('Could not restore cache of type {0}.'.format(self.info['type']))

                pg.debug("Restoring cache took:", pg.dur(), "s")
            except Exception as e:
                import traceback
                traceback.print_exc(file=sys.stdout)
                print(self.info)
                pg.error('Cache restoring failed.')
Exemple #2
0
    def hash(self, funct, *args, **kwargs):
        """"Create a hash value"""
        pg.tic()
        functInfo = self.functInfo(funct)
        funcHash = strHash(functInfo)
        versionHash = strHash(pg.versionStr())
        codeHash = strHash(inspect.getsource(funct))

        argHash = 0
        for a in args:
            if isinstance(a, str):
                argHash = argHash ^ strHash(a)
            elif isinstance(a, list):
                for item in a:
                    if isinstance(item, str):
                        argHash = argHash ^ strHash(item)
                    else:
                        argHash = argHash ^ hash(item)
            else:
                argHash = argHash ^ hash(a)

        for k, v in kwargs.items():
            if isinstance(v, str):
                argHash = argHash ^ strHash(v)
            else:
                argHash = argHash ^ hash(v)

        pg.debug("Hashing took:", pg.dur(), "s")
        return funcHash ^ versionHash ^ codeHash ^ argHash
Exemple #3
0
    def __init__(self, A, verbose=False):
        """Constructor saving matrix and vector.

        Parameters
        ----------
        A : ndarray
            numpy type (full) matrix
        """
        super().__init__(verbose)  # only in Python 3
        self._mul = None

        if isinstance(A, str):
            self.load(A)
        else:
            from scipy.linalg import eigh  # , get_blas_funcs

            if A.shape[0] != A.shape[1]:  # rows/cols for pgcore matrix
                raise Exception("Matrix must by square (and symmetric)!")

            if verbose:
                t = pg.tic(key='init cm05')
            self.ew, self.EV = eigh(A)

            if verbose:
                pg.info(
                    '(C) Time for eigenvalue decomposition: {:.1f}s'.format(
                        pg.dur(key='init cm05')))
Exemple #4
0
    def hash(self, funct, *args, **kwargs):
        """"Create a hash value"""
        pg.tic()
        functInfo = self.functInfo(funct)
        funcHash = strHash(functInfo)
        versionHash = strHash(pg.versionStr())
        codeHash = strHash(inspect.getsource(funct))

        argHash = 0
        for a in args:
            argHash = argHash ^ valHash(a)

        for k, v in kwargs.items():
            argHash = argHash ^ valHash(k) ^ valHash(v)
            
        pg.debug("Hashing took:", pg.dur(), "s")
        return funcHash ^ versionHash ^ codeHash ^ argHash
Exemple #5
0
    def simulate(self, mesh, scheme, res, **kwargs):
        """Simulate an ERT measurement.

        Perform the forward task for a given mesh, a resistivity distribution
        (per cell), a measurement
        scheme and will return data (apparent resistivity) or potential fields.

        This function can also operate on complex resistivity models, thereby
        computing complex apparent resistivities.

        The forward operator itself only calculate potential values
        for the given scheme file.
        To calculate apparent resistivities, geometric factors (k) are needed.
        If there are no values k in the DataContainerERT scheme, then we will
        try to calculate them, either analytic or by using a p2-refined
        version of the given mesh.

        TODO
        ----
        * 2D + Complex + SR

        Args
        ----
        mesh : :gimliapi:`GIMLI::Mesh`
            2D or 3D Mesh to calculate for.

        res : float, array(mesh.cellCount()) | array(N, mesh.cellCount()) | list
            Resistivity distribution for the given mesh cells can be:
            . float for homogeneous resistivity
            . single array of length mesh.cellCount()
            . matrix of N resistivity distributions of length mesh.cellCount()
            . resistivity map as [[regionMarker0, res0],
                                  [regionMarker0, res1], ...]

        scheme : :gimliapi:`GIMLI::DataContainerERT`
            Data measurement scheme.

        Keyword Args
        ------------
        verbose: bool[False]
            Be verbose. Will override class settings.
        calcOnly: bool [False]
            Use fop.calculate instead of fop.response. Useful if you want
            to force the calculation of impedances for homogeneous models.
            No noise handling. Solution is put as token 'u' in the returned
            DataContainerERT.
        noiseLevel: float [0.0]
            add normally distributed noise based on
            scheme('err') or on noiseLevel if scheme did not contain 'err'
        noiseAbs: float [0.0]
            Absolute voltage error in V
        returnArray: bool [False]
            Returns an array of apparent resistivities instead of
            a DataContainerERT
        returnFields: bool [False]
            Returns a matrix of all potential values (per mesh nodes)
            for each injection electrodes.

        Returns
        -------
        DataContainerERT | array(N, data.size()) | array(N, data.size()) |
        array(N, data.size()):
            Data container with resulting apparent resistivity data and
            errors (if noiseLevel or noiseAbs is set).
            Optional returns a Matrix of rhoa values
            (for returnArray==True forces noiseLevel=0).
            In case of a complex valued resistivity model, phase values will be
            returned in the DataContainerERT (see example below), or as an
            additional returned array.

        Examples
        --------
        # TODO: Remove pybert dependencies
        # >>> import pybert as pb
        # >>> import pygimli as pg
        # >>> import pygimli.meshtools as mt
        # >>> world = mt.createWorld(start=[-50, 0], end=[50, -50],
        # ...                        layers=[-1, -5], worldMarker=True)
        # >>> scheme = pb.createData(
        # ...                     elecs=pg.utils.grange(start=-10, end=10, n=21),
        # ...                     schemeName='dd')
        # >>> for pos in scheme.sensorPositions():
        # ...     _= world.createNode(pos)
        # ...     _= world.createNode(pos + [0.0, -0.1])
        # >>> mesh = mt.createMesh(world, quality=34)
        # >>> rhomap = [
        # ...    [1, 100. + 0j],
        # ...    [2, 50. + 0j],
        # ...    [3, 10.+ 0j],
        # ... ]
        # >>> ert = pb.ERTManager()
        # >>> data = ert.simulate(mesh, res=rhomap, scheme=scheme, verbose=True)
        # >>> rhoa = data.get('rhoa').array()
        # >>> phia = data.get('phia').array()
        """
        verbose = kwargs.pop('verbose', self.verbose)
        calcOnly = kwargs.pop('calcOnly', False)
        returnFields = kwargs.pop("returnFields", False)
        returnArray = kwargs.pop('returnArray', False)
        noiseLevel = kwargs.pop('noiseLevel', 0.0)
        noiseAbs = kwargs.pop('noiseAbs', 1e-4)
        seed = kwargs.pop('seed', None)

        #segfaults with self.fop (test & fix)
        fop = self.createForwardOperator(useBert=self.useBert, sr=self.sr)
        fop.data = scheme
        fop.setMesh(mesh, ignoreRegionManager=True)
        fop.verbose = verbose

        rhoa = None
        phia = None

        isArrayData = False
        # parse the given res into mesh-cell-sized array
        if isinstance(res, int) or isinstance(res, float):
            res = np.ones(mesh.cellCount()) * float(res)
        elif isinstance(res, complex):
            res = np.ones(mesh.cellCount()) * res
        elif hasattr(res[0], '__iter__'):  # ndim == 2
            if len(res[0]) == 2:  # res seems to be a res map
                # check if there are markers in the mesh that are not defined in
                # the rhomap. better signal here before it results in some error
                meshMarkers = list(set(mesh.cellMarkers()))
                mapMarkers = [m[0] for m in res]
                if any([mark not in mapMarkers for mark in meshMarkers]):
                    left = [m for m in meshMarkers if m not in mapMarkers]
                    pg.critical(
                        "Mesh contains markers without assigned resistivities {}. Please fix given rhomap."
                        .format(left))
                res = pg.solver.parseArgToArray(res, mesh.cellCount(), mesh)
            else:  # probably nData x nCells array
                # better check for array data here
                isArrayData = True

        if isinstance(res[0], np.complex) or isinstance(res, pg.CVector):
            pg.info("Complex resistivity values found.")
            fop.setComplex(True)
        else:
            fop.setComplex(False)

        if not scheme.allNonZero('k') and not calcOnly:
            if verbose:
                pg.info('Calculate geometric factors.')
            scheme.set('k', fop.calcGeometricFactor(scheme))

        ret = pg.DataContainerERT(scheme)
        ## just be sure that we don't work with artifacts
        ret['u'] *= 0.0
        ret['i'] *= 0.0
        ret['r'] *= 0.0

        if isArrayData:
            rhoa = np.zeros((len(res), scheme.size()))
            for i, r in enumerate(res):
                rhoa[i] = fop.response(r)
                if verbose:
                    print(i, "/", len(res), " : ", pg.dur(), "s", "min r:",
                          min(r), "max r:", max(r), "min r_a:", min(rhoa[i]),
                          "max r_a:", max(rhoa[i]))
        else:  # res is single resistivity array
            if len(res) == mesh.cellCount():

                if calcOnly:
                    fop.mapERTModel(res, 0)

                    dMap = pg.core.DataMap()
                    fop.calculate(dMap)
                    if fop.complex():
                        pg.critical('Implement me')
                    else:
                        ret["u"] = dMap.data(scheme)
                        ret["i"] = np.ones(ret.size())

                    if returnFields:
                        return pg.Matrix(fop.solution())
                    return ret
                else:
                    if fop.complex():
                        res = pg.utils.squeezeComplex(res)

                    resp = fop.response(res)

                    if fop.complex():
                        rhoa, phia = pg.utils.toPolar(resp)
                    else:
                        rhoa = resp
            else:
                print(mesh)
                print("res: ", res)
                raise BaseException(
                    "Simulate called with wrong resistivity array.")

        if not isArrayData:
            ret['rhoa'] = rhoa

            if phia is not None:
                ret.set('phia', phia)
        else:
            ret.set('rhoa', rhoa[0])
            if phia is not None:
                ret.set('phia', phia[0])

        if returnFields:
            return pg.Matrix(fop.solution())

        if noiseLevel > 0:  # if errors in data noiseLevel=1 just triggers
            if not ret.allNonZero('err'):
                # 1A  and #100µV
                ret.set(
                    'err',
                    self.estimateError(ret,
                                       relativeError=noiseLevel,
                                       absoluteUError=noiseAbs,
                                       absoluteCurrent=1))
                print("Data error estimate (min:max) ", min(ret('err')), ":",
                      max(ret('err')))

            rhoa *= 1. + pg.randn(ret.size(), seed=seed) * ret('err')
            ret.set('rhoa', rhoa)

            ipError = None
            if phia is not None:
                if scheme.allNonZero('iperr'):
                    ipError = scheme('iperr')
                else:
                    # np.abs(self.data("phia") +TOLERANCE) * 1e-4absoluteError
                    if noiseLevel > 0.5:
                        noiseLevel /= 100.

                    if 'phiErr' in kwargs:
                        ipError = np.ones(
                            ret.size()) * kwargs.pop('phiErr') / 1000
                    else:
                        ipError = abs(ret["phia"]) * noiseLevel

                    if verbose:
                        print("Data IP abs error estimate (min:max) ",
                              min(ipError), ":", max(ipError))

                phia += np.randn(ret.size(), seed=seed) * ipError
                ret['iperr'] = ipError
                ret['phia'] = phia

        # check what needs to be setup and returned

        if returnArray:
            if phia is not None:
                return rhoa, phia
            else:
                return rhoa

        return ret
Exemple #6
0
    def response(self, model):
        """Solve forward task.

        Create apparent resistivity values for a given resistivity distribution
        for self.mesh.
        """
        ### NOTE TODO can't be MT until mixed boundary condition depends on
        ### self.resistivity
        pg.tic()
        if not self.data.allNonZero('k'):
            pg.error('Need valid geometric factors: "k".')
            pg.warn('Fallback "k" values to -sign("rhoa")')
            self.data.set('k', -pg.math.sign(self.data('rhoa')))

        mesh = self.mesh()

        nDof = mesh.nodeCount()
        elecs = self.data.sensorPositions()

        nEle = len(elecs)
        nData = self.data.size()

        self.resistivity = res = self.createMappedModel(model, -1.0)

        if self.verbose:
            print("Calculate response for model:", min(res), max(res))

        rMin = elecs[0].dist(elecs[1]) / 2.0
        rMax = elecs[0].dist(elecs[-1]) * 2.0

        k, w = self.getIntegrationWeights(rMin, rMax)

        self.k = k
        self.w = w

        # pg.show(mesh, res, label='res')
        # pg.wait()

        rhs = self.createRHS(mesh, elecs)

        # store all potential fields
        u = np.zeros((nEle, nDof))
        self.subPotentials = [pg.Matrix(nEle, nDof) for i in range(len(k))]

        for i, ki in enumerate(k):
            ws = dict()
            uE = pg.solve(mesh,
                          a=1. / res,
                          b=-(ki * ki) / res,
                          f=rhs,
                          bc={'Robin': ['*', self.mixedBC]},
                          userData={
                              'sourcePos': elecs,
                              'k': ki
                          },
                          verbose=False,
                          stats=0,
                          debug=False)
            self.subPotentials[i] = uE
            u += w[i] * uE

        # collect potential matrix,
        # i.e., potential for all electrodes and all injections
        pM = np.zeros((nEle, nEle))

        for i in range(nEle):
            pM[i] = pg.interpolate(mesh, u[i, :], destPos=elecs)

        # collect resistivity values for all 4 pole measurements
        r = np.zeros(nData)

        for i in range(nData):
            iA = int(self.data('a')[i])
            iB = int(self.data('b')[i])
            iM = int(self.data('m')[i])
            iN = int(self.data('n')[i])

            uAB = pM[iA] - pM[iB]
            r[i] = uAB[iM] - uAB[iN]

        self.lastResponse = r * self.data('k')

        if self.verbose:
            print("Resp min/max: {0} {1} {2}s".format(min(self.lastResponse),
                                                      max(self.lastResponse),
                                                      pg.dur()))

        return self.lastResponse
    mgr = TravelTimeManager()

    cols = ["orangered", "blue", "black"]
    recs = [1, 3, 8, 13]

    for i, n in enumerate(sec_nodes):

        # Perform traveltime calculations and log time with pg.tic() & pg.toc()
        pg.tic()
        res = mgr.simulate(vel=vel, scheme=data, mesh=mesh, secNodes=n)
        # We need to copy res['t'] here because res['t'] is a reference to
        # an array in res, and res will be removed in the next iteration.
        # Unfortunately, we don't have any reverence counting for core objects yet.
        t_all.append(res['t'].array())
        durations.append(pg.dur())
        pg.toc("Raytracing with %d secondary nodes:" % n)

        for r, p in enumerate(recs):
            if r == 0:
                lab = "Raypath with %d sec nodes" % n
            else:
                lab = None

            recNode = mgr.fop.mesh().findNearestNode([sensors[p], 0.0])
            sourceNode = mgr.fop.mesh().findNearestNode([0.0, 0.0])

            path = mgr.fop.dijkstra.shortestPath(sourceNode, recNode)
            points = mgr.fop.mesh().positions(withSecNodes=True)[path]
            ax[0, j].plot(pg.x(points), pg.y(points), cols[i], label=lab)
Exemple #8
0
def crankNicolson(times, theta, S, I, f, u0=None, verbose=0):
    """
        S = const over time
        f = const over time

    """

    if len(times) < 2:
        raise BaseException("We need at least 2 times for Crank "
                            "Nicolsen time discretization." + str(len(times)))
    sw = pg.Stopwatch(True)

    if u0 is None:
        u0 = np.zeros(len(f))

    u = np.zeros((len(times), len(f)))
    u[0, :] = u0
    dt = (times[1] - times[0])

    rhs = np.zeros((len(times), len(f)))

    rhs[:] = f

    A = (I + dt * theta * S)

    solver = pg.LinSolver(A, verbose=verbose)

    timeAssemble = []
    timeSolve = []
    # print('0', min(u[0]), max(u[0]), min(f), max(f))
    for n in range(1, len(times)):

        if verbose:
            pg.tic()

#        pg.tic()
#        bRef = (I + (dt * (theta - 1.)) * S) * u[n - 1] + \
#            dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])
#        pg.toc()
#
#        pg.tic()
#        b = u[n - 1] + ((dt * (theta - 1.)) * S) * u[n - 1] + \
#            dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])
#        pg.toc()
#
#        pg.tic()
        b = u[n - 1] + S.mult(dt * (theta - 1.) * u[n - 1]) + \
            dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])
        #        pg.toc()
        #
        #        print(np.linalg.norm(b-b1))
        #        np.testing.assert_allclose(bRef, b)

        if verbose:
            timeAssemble.append(pg.dur())

        if verbose:
            pg.tic()

        u[n, :] = solver.solve(b)

        if verbose:
            timeSolve.append(pg.dur())

        # A = (I + dt * theta * S)
        # u[n, : ] = linsolve(A, b)

        if verbose and (n % verbose == 0):
            # print(min(u[n]), max(u[n]))
            print("timesteps:", n, "/", len(times), 'runtime:', sw.duration(),
                  "s", 'assemble:', np.mean(timeAssemble), 'solve:',
                  np.mean(timeSolve))


#    import matplotlib.pyplot as plt
#    plt.figure()
#    plt.plot(timeAssemble)
#    plt.figure()
#    plt.plot(timeSolve)
#    plt.show()

    return u
    durations = []
    paths = []

    for n in sec_nodes:
        if n > 0:
            pg.tic()
            mesh2 = mesh.createMeshWithSecondaryNodes(n)
            pg.toc("Mesh generation with %d secondary nodes:" % n)
        else:
            mesh2 = mesh

        # Perform traveltime calculations and log time with pg.tic() & pg.toc()
        pg.tic()
        fop = pg.TravelTimeDijkstraModelling(mesh2, data)
        t_all.append(fop.response(1 / vel))
        durations.append(pg.dur())
        pg.toc("Raytracing with %d secondary nodes:" % n)

        # This is to show single raypaths.
        dij = pg.Dijkstra(fop.createGraph(1 / vel))
        dij.setStartNode(mesh2.findNearestNode([0, 0]))
        paths_per_receiver = []
        for receiver in sensors:
            ni = dij.shortestPathTo(mesh2.findNearestNode([receiver, 0]))
            pos = mesh2.positions(withSecNodes=True)[ni]
            paths_per_receiver.append([pg.x(pos), pg.y(pos)])

        paths.append(paths_per_receiver)

    t_ana = ana(px[1:])
Exemple #10
0
def crankNicolson(times, theta, S, I, f, u0=None, progress=None, debug=None):
    """
        S = constant over time
        f = constant over time
    """

    if len(times) < 2:
        raise BaseException("We need at least 2 times for Crank "
                            "Nicolsen time discretization." + str(len(times)))
    sw = pg.Stopwatch(True)

    if u0 is None:
        u0 = np.zeros(len(f))

    u = np.zeros((len(times), len(f)))
    u[0, :] = u0
    dt = times[1] - times[0]

    rhs = np.zeros((len(times), len(f)))

    rhs[:] = f

    A = I + S * dt * theta

    solver = pg.LinSolver(A, verbose=False)

    timeAssemble = []
    timeSolve = []
    # print('0', min(u[0]), max(u[0]), min(f), max(f))

    timeMeasure = False
    if progress:
        timeMeasure = True

    for n in range(1, len(times)):

        if timeMeasure:
            pg.tic()


#        pg.tic()
#bRef = (I + (dt * (theta - 1.)) * S) * u[n - 1] + \
#dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])
#        pg.toc()
#
#        pg.tic()
#b = I * u[n - 1] + ((dt * (theta - 1.)) * S) * u[n - 1] + \
#dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])
#        pg.toc()
#
#        pg.tic()
        b = I * u[n - 1] + S.mult(dt * (theta - 1.) * u[n - 1]) + \
            dt * ((1.0 - theta) * rhs[n - 1] + theta * rhs[n])
        #        pg.toc()
        #
        #        print(np.linalg.norm(b-b1))
        #np.testing.assert_allclose(bRef, b)

        if timeMeasure:
            timeAssemble.append(pg.dur())

        if timeMeasure:
            pg.tic()

        u[n, :] = solver.solve(b)

        if timeMeasure:
            timeSolve.append(pg.dur())

        # A = (I + dt * theta * S)
        # u[n, : ] = linsolve(A, b)

        if progress:
            progress.update(n,
                            ' t_prep: ' + str(round(timeAssemble[-1], 5)) + 's' + \
                            ' t_step: ' + str(round(timeSolve[-1], 5)) + 's')

        #if verbose and (n % verbose == 0):
        ## print(min(u[n]), max(u[n]))
        #print("timesteps:", n, "/", len(times),
        #'runtime:', sw.duration(), "s",
        #'assemble:', np.mean(timeAssemble),
        #'solve:', np.mean(timeSolve))
    return u