Пример #1
0
def drawVA(ax, data, vals=None, usePos=True, pseudosection=False, **kwargs):
    """Draw apparent velocities as matrix into an axis.

    Parameters
    ----------
    ax : mpl.Axes

    data : pg.DataContainer()
        Datacontainer with 's' and 'g' Sensorindieces and 't' traveltimes.

    usePos: bool [True]
        Use sensor positions for axes tick labels

    pseudosection : bool [False]
        Show in pseudosection style.

    vals : iterable
        Traveltimes, if None data need to contain 't' values.
    """
    if isinstance(vals, str):
        vals = data(vals)

    if vals is None:
        vals = data('t')

    px = pg.x(data)
    gx = np.asarray([px[g] for g in data.id("g")])
    sx = np.asarray([px[s] for s in data.id("s")])

    offset = shotReceiverDistances(data, full=True)

    if min(vals) < 1e-10:
        print(vals)
        pg.error('zero traveltimes found.')
    va = offset / vals

    if pseudosection:
        midpoint = (gx + sx) / 2
        gci = pg.viewer.mpl.dataview.drawVecMatrix(ax, midpoint, offset, va,
                                                   queeze=True,
                                                   label=pg.unit('as'))
    else:
        gci = pg.viewer.mpl.dataview.drawVecMatrix(ax, gx, sx, va,
                                                   squeeze=True,
                                                   label=pg.unit('as'))

    # A = np.ones((data.sensorCount(), data.sensorCount())) * np.nan
    # for i in range(data.size()):
    #     A[int(data('s')[i]), int(data('g')[i])] = va[i]
    # gci = ax.imshow(A, interpolation='nearest')
    # ax.grid(True)

    if usePos:
        xt = np.arange(0, data.sensorCount(), 50)
        ax.set_xticks(xt)
        ax.set_xticklabels([str(int(px[xti])) for xti in xt])
        ax.set_yticks(xt)
        ax.set_yticklabels([str(int(px[xti])) for xti in xt])

    return gci
Пример #2
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.')
Пример #3
0
def showMatrix(mat, ax=None, **kwargs):
    """Show various pyGIMLi matrices using matplotlib.

    Args
    ----
    mat: matrix

    ax: mpl.axes

    Keyword Args
    ------------
        **kwargs : forwarded to mpl plotting commands

    Returns
    -------
        mpl.axes, Colorbar
    """
    if ax is None:
        print(ax)
        ax = pg.show()[0]

    try:
        from scipy.sparse import spmatrix

        if isinstance(mat, spmatrix):
            gci = drawSparseMatrix(ax, mat, **kwargs)
            return ax, None
    except ImportError:
        pass

    if isinstance(mat, (pg.core.RSparseMapMatrix, pg.core.RSparseMatrix)):
        gci = drawSparseMatrix(ax, mat, **kwargs)
        cBar = None
    elif isinstance(mat, pg.matrix.BlockMatrix):
        gci, cBar = drawBlockMatrix(ax, mat, **kwargs)

        if cBar is None:
            uniqueIDs = pg.unique([e.matrixID for e in mat.entries()])
            cMap = pg.plt.cm.get_cmap("Set3", len(uniqueIDs))
            sm = pg.plt.cm.ScalarMappable(cmap=cMap)

            cBar = createColorBar(sm,
                                  ax=ax,
                                  label="Matrix ID",
                                  cMin=-0.5,
                                  cMax=len(uniqueIDs) - 0.5)
            ticks = np.arange(len(uniqueIDs))
            cBar.set_ticks(ticks)

            labels = []
            for ID in uniqueIDs:
                label = "{:d}".format(ID)
                labels.append(label)
            cBar.set_ticklabels(labels)

    else:
        pg.error("Matrix type not supported yet.")
    return ax, cBar
Пример #4
0
def setCbarLevels(cbar, cMin=None, cMax=None, nLevs=5, levels=None):
    """Set colorbar levels given a number of levels and min/max values."""
    if cMin is None:
        if hasattr(cbar, 'mappable'):
            cMin = cbar.mappable.get_clim()[0]
        else:
            pg.error('no cbar mappable. Cannot find cmin')
    if cMax is None:
        if hasattr(cbar, 'mappable'):
            cMax = cbar.mappable.get_clim()[1]
        else:
            pg.error('no cbar mappable. Cannot find cmax')

    if cMin == cMax:

        cMin *= 0.999
        cMax *= 1.001

    norm = None
    if hasattr(cbar, 'mappable'):
        norm = cbar.mappable.norm
    elif hasattr(cbar, 'norm'):
        norm = cbar.norm

    #norm.clip = True

    if levels is not None:
        cbarLevels = levels
    else:
        if isinstance(norm, mpl.colors.LogNorm):
            cbarLevels = np.logspace(np.log10(cMin), np.log10(cMax), nLevs)
        else:
            #if cMax < cMin:
            cbarLevels = np.linspace(cMin, cMax, nLevs)

    # FIXME: [10.1, 10.2, 10.3] mapped to [10 10 10]

    cbarLevelsString = []
    if np.all(np.array(cbarLevels) < 1e-2):
        pg.debug("All values smaller than 1e-4, avoiding additional rounding.")
        roundValue = False
    else:
        roundValue = True

    for i in cbarLevels:
        cbarLevelsString.append(prettyFloat(i, roundValue))

    if hasattr(cbar, 'mappable'):
        #cbar.set_clim(cMin, cMax)
        cbar.mappable.set_clim(vmin=cMin, vmax=cMax)

    cbar.set_ticks(cbarLevels)
    cbar.set_ticklabels(cbarLevelsString)
    cbar.draw_all()

    # necessary since mpl 3.0
    cbar.ax.minorticks_off()
Пример #5
0
    def checkError(self, err, dataVals):
        """Return relative error."""
        if isinstance(err, pg.DataContainer):
            if not err.haveData('err'):
                pg.error('DataContainer has no "err" values. Fallback to 3%')
                return np.ones(err.size()) * 0.03
            return err['err'] / dataVals

        return err
Пример #6
0
    def regionProperties(self, regionNr=None):
        """Return dictionary of all properties for region number regionNr."""
        if regionNr is None:
            return self._regionProperties

        try:
            return self._regionProperties[regionNr]
        except KeyError:
            print(self._regionProperties)
            pg.error("no region for region #:", regionNr)
Пример #7
0
    def checkError(self, err, dataVals=None):
        """Return relative error. Default we assume 'err' are relative values.
        Overwrite is derived class if needed. """
        if isinstance(err, pg.DataContainer):
            if not err.haveData('err'):
                pg.error('Datacontainer have no "err" values. '
                         'Fallback set to 0.01')
            return err['err']

        return err
Пример #8
0
def showMesh3DVista(mesh, data=None, **kwargs):
    """
    Make use of the actual 3D visualization tool kit

    Parameters
    ----------
    data: pg.Vector or np.ndarray
        Dictionary of cell values, sorted by key. The values need to be
        numpy arrays.

    Returns
    -------
    plotter: pyvista.Plotter
        The plotter from pyvista.
    gui: Show3D [None]
        The small gui based on pyvista. Note that this is returned as 'None'
        if gui is passed as 'False'.

    Note
    ----
    Not having PyQt5 installed results in displaying the first key
    (and values) from the dictionary.
    """
    hold = kwargs.pop('hold', False)
    cmap = kwargs.pop('cmap', 'viridis')
    notebook = kwargs.pop('notebook', _inlineBackend_)
    gui = kwargs.pop('gui', False)

    # add given data from argument
    if gui:
        app = Qt.QApplication(sys.argv)
        s3d = Show3D(app)
        s3d.addMesh(mesh, data, cmap=cmap, **kwargs)
        if not hold:
            s3d.wait()
        return s3d.plotter, s3d  # plotter, gui

    else:
        if notebook:
            pyvista.set_plot_theme('document')

        try:
            plotter = drawModel(None,
                                mesh,
                                data,
                                notebook=notebook,
                                cmap=cmap,
                                **kwargs)
        except Exception as e:
            print(e)
            pg.error("fix pyvista bindings")

        if not hold:
            plotter.show()
        return plotter, None
Пример #9
0
def filterIndex(seq, idx):
    """TODO DOCUMENTME."""
    pg.error('filterIndex in use?')
    if isinstance(seq, pg.Vector):
        # return seq(idx)
        ret = pg.Vector(len(idx))
    else:
        ret = list(range(len(idx)))

    for i, ix in enumerate(idx):
        ret[i] = seq[ix]

    return ret
Пример #10
0
def pgMesh2pvMesh(mesh, data=None, label=None):
    """
    pyGIMLi's mesh format is different from pyvista's needs,
    some preparation is necessary.

    Parameters
    ----------
    mesh: pg.Mesh
        Structure generated by pyGIMLi to display.
    data: iterable
        Parameter to distribute to cells/nodes.
    """
    _, tmp = tempfile.mkstemp(suffix=".vtk")
    # export given mesh temporarily is the easiest and fastest option ATM
    mesh.exportVTK(tmp)
    grid = pv.read(tmp)

    # check for parameters inside the pg.Mesh
    for key, values in mesh.dataMap():
        if len(values) == mesh.cellCount():
            grid.cell_arrays[key] = np.asarray(values)
        elif len(values) == mesh.nodeCount():
            grid.point_arrays[key] = np.asarray(values)

    # check the given data as well
    try:
        if data is not None:
            if len(data) == mesh.cellCount():
                grid.cell_arrays[label] = np.asarray(data)
            elif len(data) == mesh.nodeCount():
                grid.point_arrays[label] = np.asarray(data)
            else:
                pg.warn("Given data fits neither cell count nor node count:")
                pg.warn("{} vs. {} vs. {}".format(len(data), mesh.cellCount(),
                                                  mesh.nodeCount()))
    except Exception as e:
        print(e)
        pg.error("fix pyvista bindings")

    if label is None:
        # last data that was added
        label = grid.array_names[-1]
    elif label not in grid.array_names:
        pg.warn("Given label '{}' was not found.".format(label))
        label = grid.array_names[-1]

    grid.set_active_scalars(label)

    return grid
Пример #11
0
def getIndex(seq, f):
    """TODO DOCUMENTME."""
    pg.error('getIndex in use?')
    # DEPRECATED_SLOW
    idx = []
    if isinstance(seq, pg.Vector):
        for i, _ in enumerate(seq):
            v = seq[i]
            if f(v):
                idx.append(i)
    else:
        for i, d in enumerate(seq):
            if f(d):
                idx.append(i)
    return idx
Пример #12
0
def showmymatrix(mat, x, y, dx=2, dy=1, xlab=None, ylab=None, cbar=None):
    """What is this good for?."""
    pg.error('who use this?')
    plt.imshow(mat, interpolation='nearest')
    plt.xticks(np.arange(0, len(x), dx), ["%g" % rndig(xi, 2) for xi in x])
    plt.yticks(np.arange(0, len(y), dy), ["%g" % rndig(yi, 2) for yi in y])
    plt.ylim((len(y) - 0.5, -0.5))

    if xlab is not None:
        plt.xlabel(xlab)
    if ylab is not None:
        plt.ylabel(ylab)
    plt.axis('auto')
    if cbar is not None:
        plt.colorbar(orientation=cbar)
    return
Пример #13
0
def createMeshPatches(ax, mesh, verbose=True):
    """Utility function to create 2d mesh patches within a given ax."""
    if not mesh:
        pg.error("drawMeshBoundaries(ax, mesh): invalid mesh:", mesh)
        return

    if mesh.nodeCount() < 2:
        pg.error("drawMeshBoundaries(ax, mesh): to few nodes:", mesh)
        return

    pg.tic()
    polys = [_createCellPolygon(c) for c in mesh.cells()]
    patches = mpl.collections.PolyCollection(polys, picker=True)

    if verbose:
        pg.info("Creation of mesh patches took = ", pg.toc())

    return patches
Пример #14
0
 def startModel(self, model):
     """
     model: [float] | float
         Model used as starting model.
         Float value is used as constant model.
     """
     if model is None:
         self._startModel = None
     elif isinstance(model, float) or isinstance(model, int):
         self._startModel = np.ones(self.parameterCount) * float(model)
         pg.info("Startmodel set from given value.", float(model))
     elif hasattr(model, '__iter__'):
         if len(model) == self.parameterCount:
             pg.info("Startmodel set from given array.", model)
             self._startModel = model
         else:
             pg.error("Startmodel size invalid {0} != {0}.".format(
                 len(model), self.parameterCount))
Пример #15
0
def drawSlice(ax, mesh, normal=[1, 0, 0], **kwargs):
    """

    Parameters
    ----------
    ax: pyvista.Plotter
        The Plotter to draw on.
    mesh: pg.Mesh
        The mesh to take the slice out of.
    normal: list [[1, 0, 0]]
        Coordinates to orientate the slice.

    Returns
    -------
    ax: pyvista.Plotter
        The plotter containing the mesh and drawn electrode positions.

    Note
    ----
    Possible kwargs are:
    normal: tuple(float), str
    origin: tuple(float)
    generate_triangles: bool, optional
    contour: bool, optional

    They can be found at https://docs.pyvista.org/core/filters.html#pyvista.CompositeFilters.slice
    """
    label = kwargs.pop('label', None)
    data = kwargs.pop('data', None)
    mesh = pgMesh2pvMesh(mesh, data, label)

    try:
        single_slice = mesh.slice(normal, **kwargs)

    except AssertionError as e:
        # 'contour' kwarg only works with point data and breaks execution
        pg.error(e)
    else:
        # REVIEW: bounds and axes might be confused with the outline..?!
        outline = mesh.outline()
        ax.add_mesh(outline, color="k")
        ax.add_mesh(single_slice)

    return ax
Пример #16
0
def createMeshPatches(ax, mesh, verbose=True, rasterized=False):
    """Utility function to create 2d mesh patches within a given ax."""
    if not mesh:
        pg.error("drawMeshBoundaries(ax, mesh): invalid mesh:", mesh)
        return

    if mesh.nodeCount() < 2:
        pg.error("drawMeshBoundaries(ax, mesh): to few nodes:", mesh)
        return

    pg.tic()
    polys = [_createCellPolygon(c) for c in mesh.cells()]
    patches = mpl.collections.PolyCollection(polys, picker=True,
                                             rasterized=rasterized)

    if verbose:
        pg.info("Creation of mesh patches took = ", pg.toc())

    return patches
Пример #17
0
            def _drawField(ax, mesh, data, kwargs):
                ### kwargs as reference here to set defaults valid outside too
                validData = True
                if len(data) == mesh.cellCount():
                    kwargs['nCols'] = kwargs.pop('nCols', 256)
                    gci = drawModel(ax, mesh, data, **kwargs)

                elif len(data) == mesh.nodeCount():
                    kwargs['nLevs'] = kwargs.pop('nLevs', 5)
                    kwargs['nCols'] = kwargs.pop('nCols', kwargs['nLevs'] - 1)

                    gci = drawField(ax, mesh, data, **kwargs)
                else:
                    pg.error("Data size invalid")
                    print("Data: ", len(data), min(data), max(data),
                          pg.core.haveInfNaN(data))
                    print("Mesh: ", mesh)
                    validData = False
                    drawMesh(ax, mesh)

                return gci, validData
Пример #18
0
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:
        print(f'Path {path} already exists. Skipping')
    except OSError as e:
        pg.error(f'Unable to create path "{path}".')
        raise e
    return path
Пример #19
0
    def fixLayers(self, fixLayers):
        """Fix layer thicknesses.

        Parameters
        ----------
        fixLayers : bool | [float]
            Fix all layers to the last value or set the fix layer
            thickness for all layers
        """
        if fixLayers is False:
            self.fop.setRegionProperties(0, modelControl=1.0)
        elif fixLayers is not None:
            # how do we fix values without modelControl?
            # maybe set the region to be fixed here
            self.fop.setRegionProperties(0, modelControl=1e6)
            if hasattr(fixLayers, '__iter__'):
                if len(fixLayers) != self.fop.nLayers:
                    print("fixLayers:", fixLayers)
                    pg.error("fixlayers needs to have a length of nLayers-1=" +
                             str(self.fop.nLayers - 1))
                self.fop.setRegionProperties(0, startModel=fixLayers)
Пример #20
0
def valHash(a):
    
    if isinstance(a, str):
        return strHash(a)
    elif isinstance(a, int):
        return a
    elif isinstance(a, list):
        hsh = 0
        for item in a:
            hsh = hsh ^ valHash(item)
        return hsh
    elif isinstance(a, np.ndarray):
        if a.ndim == 1:
            return hash(pg.Vector(a))
        elif a.ndim == 2:
            # convert to RVector to use memcopy
            return hash(pg.Vector(a.reshape((1,a.shape[0]*a.shape[1]))[0]))
        else:
            print(a)
            pg.error('no hash for numpy array')

    return hash(a)
Пример #21
0
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 OSError as e:
        if os.path.exists(path):
            print('Path "{}" already exists.'.format(path))
        else:
            pg.error('Unable to create path "{}".'.format(path))
        raise e
    return path
Пример #22
0
    def convertStartModel(self, model):
        """Convert scalar or array into startmodel with valid range or
            self.fop.parameterCount, if possible.

        Attributes
        ----------
        model: float|int|array|None

        """
        if model is None:
            return None
        elif isinstance(model, float) or isinstance(model, int):
            pg.info("Homogeneous starting model set to:", float(model))
            return np.full(self.fop.parameterCount, float(model))
        elif hasattr(model, '__iter__'):
            if len(model) == self.fop.parameterCount:
                pg.info("Starting model set from given array.", model)
                return model
            else:
                pg.error("Starting model size invalid {0} != {1}.".
                         format(len(model), self.fop.parameterCount))
        return None
Пример #23
0
def createCrossholeData(sensors):
    """
    Create crosshole scheme assuming two boreholes with equal sensor numbers.

    Parameters
    ----------
    sensors : array (Nx2)
        Array with position of sensors.

    Returns
    -------
    scheme : DataContainer
        Data container with `sensors` predefined sensor indices 's' and 'g'
        for shot and receiver numbers.
    """
    from itertools import product
    if len(sensors) % 2 > 0:
        pg.error("createCrossholeData is only defined for an equal number of"
                 " sensors in two boreholes.")
    n = len(sensors) // 2
    numbers = np.arange(n)
    rays = np.array(list(product(numbers, numbers + n)))

    # Empty container
    scheme = pg.DataContainer()

    # Add sensors
    for sen in sensors:
        scheme.createSensor(sen)

    # Add measurements
    scheme.resize(len(rays))
    scheme["s"] = rays[:, 0]
    scheme["g"] = rays[:, 1]
    scheme["valid"] = np.ones(len(rays))
    scheme.registerSensorIndex("s")
    scheme.registerSensorIndex("g")
    return scheme
Пример #24
0
def unit(name, unit='auto'):
    """ Return the name of a physical quantity with its unit.

    TODO
    ----
        * example
        * localization

    Parameters
    ----------
    """
    q = quantity(name)

    if unit == 'auto' and q is None:
        ## fall back if the name is given instead of the abbreviation
        print(quants)
        pg.error('Please give abbreviation or full name '
                 'for the quantity name: {0}'.format(name))
    else:
        if rc['lang'] == 'german' or rc['lang'] == 'de' or rc['lang'] == 'ger':
            name = q['ger']
        else:
            name = q['name']

        if unit == 'auto':
            unit = q['unit']

    if unit is None:
        return '{0}'.format(name)

    if rc['unitStyle'] == 1 or \
        rc['lang'] == 'german' or rc['lang'] == 'de' or rc['lang'] == 'ger':
        return '{0} in {1}'.format(name, unit)
    elif rc['unitStyle'] == 2:
        return '{0} ({1})'.format(name, unit)
    elif rc['unitStyle'] == 3:
        return '{0} [{1}]'.format(name, unit)
Пример #25
0
def readGmsh(fname, verbose=False):
    r"""Read :term:`Gmsh` ASCII file and return instance of GIMLI::Mesh class.

    Parameters
    ----------
    fname : string
        Filename of the file to read (\\*.msh). The file must conform
        to the `MSH ASCII file version 2
        <http://gmsh.info/doc/texinfo/gmsh.html#MSH-ASCII-file-format>`_ format
    verbose : boolean, optional
        Be verbose during import.

    Notes
    -----
    Physical groups specified in Gmsh are interpreted as follows:

    - Points with the physical number 99 are interpreted as sensors.
    - Physical Lines and Surfaces define boundaries in 2D and 3D, respectively.
        - Physical Number 1: Homogeneous Neumann condition
        - Physical Number 2: Mixed boundary condition
        - Physical Number 3: Homogeneous Dirichlet condition
        - Physical Number 4: Dirichlet condition
    - Physical Surfaces and Volumes define regions in 2D and 3D, respectively.
        - Physical Number 1: No inversion region
        - Physical Number >= 2: Inversion region

    Examples
    --------
    >>> import tempfile, os
    >>> from pygimli.meshtools import readGmsh
    >>> gmsh = '''
    ... $MeshFormat
    ... 2.2 0 8
    ... $EndMeshFormat
    ... $Nodes
    ... 3
    ... 1 0 0 0
    ... 2 0 1 0
    ... 3 1 1 0
    ... $EndNodes
    ... $Elements
    ... 7
    ... 1 15 2 0 1 1
    ... 2 15 2 0 2 2
    ... 3 15 2 0 3 3
    ... 4 1 2 0 1 2 3
    ... 5 1 2 0 2 3 1
    ... 6 1 2 0 3 1 2
    ... 7 2 2 0 5 1 2 3
    ... $EndElements
    ... '''
    >>> fname = tempfile.mktemp()
    >>> with open(fname, "w") as f:
    ...     f.writelines(gmsh)
    >>> mesh = readGmsh(fname)
    >>> print(mesh)
    Mesh: Nodes: 3 Cells: 1 Boundaries: 3
    >>> os.remove(fname)
    """
    inNodes, inElements, ncount = 0, 0, 0
    fid = open(fname)
    if verbose:
        print('Reading %s... \n' % fname)

    for line in fid:

        if line[0] == '$':
            if line.find('Nodes') > 0:
                inNodes = 1
            if line.find('EndNodes') > 0:
                inNodes = 0
            if line.find('Elements') > 0:
                inElements = 1
            if line.find('EndElements') > 0:
                inElements = 0

        else:
            if inNodes == 1:
                if len(line.split()) == 1:
                    nodes = np.zeros((int(line), 3))
                    if verbose:
                        print('  Nodes: %s' % int(line))
                else:
                    nodes[ncount, :] = np.array(line.split(), 'float')[1:]
                    ncount += 1

            elif inElements == 1:
                if len(line.split()) == 1:
                    if verbose:
                        print('  Entries: %s' % int(line))
                    points, lines, triangles, tets = [], [], [], []

                else:
                    entry = [int(e_) for e_ in line.split()][1:]

                    if entry[0] == 15:
                        points.append((entry[-2], entry[-3]))
                    elif entry[0] == 1:
                        lines.append((entry[-2], entry[-1], entry[2]))
                    elif entry[0] == 2:
                        triangles.append((entry[-3], entry[-2], entry[-1],
                                          entry[2]))
                    elif entry[0] == 4:
                        tets.append((entry[-4], entry[-3], entry[-2],
                                     entry[-1], entry[2]))
                    elif entry[0] in [3, 6]:
                        pg.error("Qudrangles and prisms are not supported yet.")

    fid.close()
    lines = np.asarray(lines)
    triangles = np.asarray(triangles)
    tets = np.asarray(tets)

    if verbose:
        print('    Points: %s' % len(points))
        print('    Lines: %s' % len(lines))
        print('    Triangles: %s' % len(triangles))
        print('    Tetrahedra: %s \n' % len(tets))
        print('Creating mesh object... \n')

    # check dimension
    if len(tets) == 0:
        dim, bounds, cells = 2, lines, triangles
        zero_dim = np.abs(nodes.sum(0)).argmin()  # identify zero dimension
    else:
        dim, bounds, cells = 3, triangles, tets
    if verbose:
        print('  Dimension: %s-D' % dim)

    # creating instance of GIMLI::Mesh class
    mesh = pg.Mesh(dim)

    # replacing boundary markers (gmsh does not allow negative phys. regions)
    bound_marker = (pg.MARKER_BOUND_HOMOGEN_NEUMANN, pg.MARKER_BOUND_MIXED,
                    pg.MARKER_BOUND_HOMOGEN_DIRICHLET,
                    pg.MARKER_BOUND_DIRICHLET)

    if bounds.any():
        for i in range(4):
            bounds[:, dim][bounds[:, dim] == i + 1] = bound_marker[i]

        # account for CEM markers
        bounds[:, dim][bounds[:, dim] >= 10000] *= -1

        if verbose:
            bound_types = np.unique(bounds[:, dim])
            print('  Boundary types: %s ' % len(bound_types) + str(
                tuple(bound_types)))
    else:
        print("WARNING: No boundary conditions found.",
              "Setting Neumann on the outer edges by default.")

    if verbose:
        regions = np.unique(cells[:, dim + 1])
        print('  Regions: %s ' % len(regions) + str(tuple(regions)))

    for node in nodes:
        if dim == 2:
            mesh.createNode(node[0], node[3 - zero_dim], 0)
        else:
            mesh.createNode(node)

    for cell in cells:
        if dim == 2:
            mesh.createTriangle(
                mesh.node(int(cell[0] - 1)), mesh.node(int(cell[1] - 1)),
                mesh.node(int(cell[2] - 1)), marker=int(cell[3]))
        else:
            mesh.createTetrahedron(
                mesh.node(int(cell[0] - 1)), mesh.node(int(cell[1] - 1)),
                mesh.node(int(cell[2] - 1)), mesh.node(int(cell[3] - 1)),
                marker=int(cell[4]))

    mesh.createNeighbourInfos()

    # Set Neumann on outer edges by default (can be overriden by Gmsh info)
    for b in mesh.boundaries():
        if not b.leftCell() or not b.rightCell():
            b.setMarker(pg.MARKER_BOUND_HOMOGEN_NEUMANN)

    for bound in bounds:
        if dim == 2:
            mesh.createEdge(
                mesh.node(int(bound[0] - 1)), mesh.node(int(bound[1] - 1)),
                marker=int(bound[2]))
        else:
            mesh.createTriangleFace(
                mesh.node(int(bound[0] - 1)), mesh.node(int(bound[1] - 1)),
                mesh.node(int(bound[2] - 1)), marker=int(bound[3]))

    # assign marker to corresponding nodes (sensors, reference nodes, etc.)
    if points:
        for point in points:
            mesh.node(point[0] - 1).setMarker(-point[1])

    if verbose:
        if points:
            points = np.asarray(points)
            node_types = np.unique(points[:, 1])
            print('  Marked nodes: %s ' % len(points) + str(tuple(node_types)))
        print('\nDone. \n')
        print('  ' + str(mesh))
    return mesh
Пример #26
0
    def run(self, dataVals, errorVals, **kwargs):
        """Run inversion.

        The inversion will always start from the starting model taken from
        the forward operator.
        If you want to run the inversion from a specified prior model,
        e.g., from a other run, set this model as starting model to the FOP
        (fop.setStartModel).
        Any self.inv.setModel() settings will be overwritten.

        Parameters
        ----------
        dataVals : iterable
            Data values
        errorVals : iterable
            Relative error values. dv / v

        Keyword Arguments
        -----------------
        maxIter : int
            Overwrite class settings for maximal iterations number.
        dPhi : float [1]
            Overwrite class settings for delta data phi aborting criteria.
            Default is 1%
        """
        self.reset()
        if self.isFrameWork:
            pg.critical('in use?')
            return self._inv.run(dataVals, errorVals, **kwargs)

        if self.fop is None:
            raise Exception(
                "Need a valid forward operator for the inversion run.")

        maxIter = kwargs.pop('maxIter', self.maxIter)
        minDPhi = kwargs.pop('dPhi', self.minDPhi)

        self.verbose = kwargs.pop('verbose', self.verbose)
        self.debug = kwargs.pop('debug', self.debug)
        self.robustData = kwargs.pop('robustData', False)

        lam = kwargs.pop('lam', 20)

        progress = kwargs.pop('progress', None)
        showProgress = kwargs.pop('showProgress', False)

        self.inv.setTransModel(self.fop.modelTrans)

        self.dataVals = dataVals
        self.errorVals = errorVals

        sm = kwargs.pop('startModel', None)
        if sm is not None:
            self.startModel = sm

        self.inv.setData(self._dataVals)
        self.inv.setRelativeError(self._errorVals)
        self.inv.setLambda(lam)

        # temporary set max iter to one for the initial run call
        maxIterTmp = self.maxIter
        self.maxIter = 1

        if self.verbose:
            pg.info('Starting inversion.')
            print("fop:", self.inv.fop())
            if isinstance(self.dataTrans, pg.trans.TransCumulative):
                print("Data transformation (cumulative):")
                for i in range(self.dataTrans.size()):
                    print("\t", i, self.dataTrans.at(i))
            else:
                print("Data transformation:", self.dataTrans)
            if isinstance(self.modelTrans, pg.trans.TransCumulative):
                print("Model transformation (cumulative):")
                for i in range(self.modelTrans.size()):
                    if i < 10:
                        print("\t", i, self.modelTrans.at(i))
                    else:
                        print(".", end='')
            else:
                print("Model transformation:", self.modelTrans)

            print("min/max (data): {0}/{1}".format(pf(min(self._dataVals)),
                                                   pf(max(self._dataVals))))
            print("min/max (error): {0}%/{1}%".format(
                pf(100 * min(self._errorVals)),
                pf(100 * max(self._errorVals))))
            print("min/max (start model): {0}/{1}".format(
                pf(min(self.startModel)), pf(max(self.startModel))))

        ### To ensure reproduceability of the run() call inv.start() will
        ### reset self.inv.model() to fop.startModel().
        self.fop.setStartModel(self.startModel)
        self.inv.setReferenceModel(self.startModel)

        if self.verbose:
            print("-" * 80)
        if self._preStep and callable(self._preStep):
            self._preStep(0, self)

        self.inv.start()
        self.maxIter = maxIterTmp

        if self._postStep and callable(self._postStep):
            self._postStep(0, self)

        if showProgress:
            self.showProgress(showProgress)

        lastPhi = self.phi()
        self.chi2History = [self.chi2()]
        self.modelHistory = [self.startModel]

        for i in range(1, maxIter):

            if self._preStep and callable(self._preStep):
                self._preStep(i, self)

            if self.verbose:
                print("-" * 80)
                print("inv.iter", i + 1, "... ", end='')

            try:
                self.inv.oneStep()
            except RuntimeError as e:
                print(e)
                pg.error('One step failed. '
                         'Aborting and going back to last model')

            if np.isnan(self.model).any():
                print(model)
                pg.critical('invalid model')

            resp = self.inv.response()
            chi2 = self.inv.chi2()

            self.chi2History.append(chi2)
            self.modelHistory.append(self.model)

            if showProgress:
                self.showProgress(showProgress)

            if self._postStep and callable(self._postStep):
                self._postStep(i, self)

            ### we need to check  the following before oder after chi2 calc??
            self.inv.setLambda(self.inv.getLambda() * self.inv.lambdaFactor())

            if self.robustData:
                self.inv.robustWeighting()

            if self.inv.blockyModel():
                self.inv.constrainBlocky()

            phi = self.phi()
            dPhi = phi / lastPhi

            if self.verbose:
                print("chi² = {0} (dPhi = {1}%) lam: {2}".format(
                    round(chi2, 2), round((1 - dPhi) * 100, 2),
                    self.inv.getLambda()))

            if chi2 <= 1 and self.stopAtChi1:
                print("\n")
                if self.verbose:
                    pg.boxprint("Abort criterion reached: chi² <= 1 (%.2f)" %
                                chi2)
                break

            if (dPhi > (1.0 - minDPhi / 100.0)) and i > 2:
                # if dPhi < -minDPhi:
                if self.verbose:
                    pg.boxprint(
                        "Abort criteria reached: dPhi = {0} (< {1}%)".format(
                            round((1 - dPhi) * 100, 2), minDPhi))
                break

            lastPhi = phi

        ### will never work as expected until we unpack kwargs .. any idea for
        # better strategy?
        # if len(kwargs.keys()) > 0:
        #     print("Warning! unused keyword arguments", kwargs)

        self.model = self.inv.model()
        return self.model
Пример #27
0
def show(mesh=None, data=None, **kwargs):
    """Mesh and model visualization.

    Syntactic sugar to show a mesh with data. Forwards to
    :py:mod:`pygimli.viewer.showMesh` or
    :py:mod:`pygimli.viewer.mayaview.showMesh3D` to show most of the typical 2D
    and 3D content. See tutorials and examples for usage hints. An empty show
    call create an empty ax window.

    Parameters
    ----------
    mesh : :gimliapi:`GIMLI::Mesh` or list of meshes
        2D or 3D GIMLi mesh

    **kwargs :
        * fitView : bool [True]
            Scale x and y limits to match the view.

        * ax : axe [None]
            Matplotlib axes object. Create a new if necessary.

        * Will be forwarded to the appropriate show functions.

    Returns
    -------
    Return the results from the showMesh* functions.

    See Also
    --------
    showMesh
    """
    if "axes" in kwargs:
        print("Deprecation Warning: Please use keyword `ax` instead of `axes`")
        kwargs['ax'] = kwargs.pop('axes', None)

    if isinstance(mesh, list):
        ax = kwargs.pop('ax', None)
        fitView = kwargs.pop('fitView', True)

        ax, cbar = show(mesh[0],
                        data,
                        hold=1,
                        ax=ax,
                        fitView=fitView,
                        **kwargs)
        xmin = mesh[0].xmin()
        xmax = mesh[0].xmax()
        ymin = mesh[0].ymin()
        ymax = mesh[0].ymax()

        for m in mesh[1:]:
            ax, cbar = show(m, data, ax=ax, hold=1, fitView=False, **kwargs)
            xmin = min(xmin, m.xmin())
            xmax = max(xmax, m.xmax())
            ymin = min(ymin, m.ymin())
            ymax = max(ymax, m.ymax())


#        ax.relim()
#        ax.autoscale_view(tight=True)
        if fitView is not False:
            ax.set_xlim([xmin, xmax])
            ax.set_ylim([ymin, ymax])
        #        print(ax.get_data_interval())
        return ax, cbar

    if isinstance(mesh, pg.Mesh):
        if mesh.dim() == 2:
            if pg.zero(pg.y(mesh)):
                pg.info("swap z<->y coordinates for visualization.")
                meshSwap = pg.Mesh(mesh)
                for n in meshSwap.nodes():
                    n.pos()[1] = n.pos()[2]
                return showMesh(meshSwap, data, **kwargs)

            return showMesh(mesh, data, **kwargs)
        elif mesh.dim() == 3:

            from .mayaview import showMesh3D

            return showMesh3D(mesh, data, **kwargs)
        else:
            pg.error("ERROR: Mesh not valid.", mesh)

    ax = kwargs.pop('ax', None)

    if ax is None:
        ax = plt.subplots()[1]

    return ax, None
Пример #28
0
def drawModel(ax, mesh, data=None, logScale=True, cMin=None, cMax=None,
              xlabel=None, ylabel=None, verbose=False,
              tri=False, rasterized=False, **kwargs):
    """Draw a 2d mesh and color the cell by the data.

    Parameters
    ----------
    mesh : :gimliapi:`GIMLI::Mesh`
        The plotted mesh to browse through.
    ax : mpl axis instance, optional
        Axis instance where the mesh is plotted (default is current axis).
    data : array, optional
        Data to draw. Should either equal numbers of cells or nodes of the
        corresponding `mesh`.
    tri : boolean, optional
        use MPL tripcolor (experimental)
    rasterized : boolean, optional
        Rasterize mesh patches to reduce file size and avoid zooming artifacts
        in some PDF viewers.
    **kwargs : Additional keyword arguments
        Will be forwarded to the draw functions and matplotlib methods,
        respectively.

    Returns
    -------
    gci : matplotlib graphics object

    Examples
    --------
    >>> import numpy as np
    >>> import matplotlib.pyplot as plt
    >>> import pygimli as pg
    >>> from pygimli.mplviewer import drawModel
    >>> n = np.linspace(0, -2, 11)
    >>> mesh = pg.createGrid(x=n, y=n)
    >>> mx = pg.x(mesh.cellCenter())
    >>> my = pg.y(mesh.cellCenter())
    >>> data = np.cos(1.5 * mx) * np.sin(1.5 * my)
    >>> fig, ax = plt.subplots()
    >>> drawModel(ax, mesh, data)
    <matplotlib.collections.PolyCollection object at ...>
    """
    # deprecated .. remove me
    if 'cMap' in kwargs or 'cmap' in kwargs:
        pg.warn('cMap|cmap argument is deprecated for draw functions. ' +
                'Please use show or customize a colorbar.')
    # deprecated .. remove me

    if mesh.nodeCount() == 0:
        pg.error("drawModel: The mesh is empty.", mesh)

    if tri:
        gci = drawMPLTri(ax, mesh, data,
                         cMin=cMin, cMax=cMax, logScale=logScale,
                         **kwargs)
    else:
        gci = pg.mplviewer.createMeshPatches(ax, mesh, verbose=verbose,
                                             rasterized=rasterized)
        ax.add_collection(gci)

        if data is None:
            data = pg.RVector(mesh.cellCount())

        if len(data) != mesh.cellCount():
            print(data, mesh)
            pg.info("drawModel have wrong data length .. " +
                    " indexing data from cellMarkers()")
            viewdata = data[mesh.cellMarkers()]
        else:
            viewdata = data

        if min(data) <= 0:
            logScale = False

        pg.mplviewer.setMappableData(gci, viewdata, cMin=cMin, cMax=cMax,
                                     logScale=logScale)

    gci.set_antialiased(True)
    gci.set_linewidths(0.1)
    gci.set_edgecolors("face")

    if xlabel is not None:
        ax.set_xlabel(xlabel)

    if ylabel is not None:
        ax.set_ylabel(ylabel)

    if kwargs.pop('fitView', True):
        ax.set_xlim(mesh.xmin(), mesh.xmax())
        ax.set_ylim(mesh.ymin(), mesh.ymax())
        ax.set_aspect('equal')

    updateAxes_(ax)
    return gci
Пример #29
0
def show(mesh=None, data=None, **kwargs):
    """Mesh and model visualization.

    Syntactic sugar to show a mesh with data. Forwards to
    :py:mod:`pygimli.viewer.showMesh` or
    :py:mod:`pygimli.viewer.mayaview.showMesh3D` to show most of the typical 2D
    and 3D content. See tutorials and examples for usage hints. An empty show
    call creates an empty ax window.

    Parameters
    ----------
    mesh : :gimliapi:`GIMLI::Mesh` or list of meshes
        2D or 3D GIMLi mesh

    **kwargs :
        * fitView : bool [True]
            Scale x and y limits to match the view.

        * ax : axe [None]
            Matplotlib axes object. Create a new if necessary.

        * Will be forwarded to the appropriate show functions.

    Returns
    -------
    Return the results from the showMesh* functions.

    See Also
    --------
    showMesh
    """
    if "axes" in kwargs:
        print("Deprecation Warning: Please use keyword `ax` instead of `axes`")
        kwargs['ax'] = kwargs.pop('axes', None)

    if isinstance(mesh, list):
        ax = kwargs.pop('ax', None)
        fitView = kwargs.pop('fitView', True)

        ax, cbar = show(mesh[0], data, hold=1, ax=ax, fitView=fitView, **kwargs)
        xmin = mesh[0].xmin()
        xmax = mesh[0].xmax()
        ymin = mesh[0].ymin()
        ymax = mesh[0].ymax()

        for m in mesh[1:]:
            ax, cbar = show(m, data, ax=ax, hold=1, fitView=False, **kwargs)
            xmin = min(xmin, m.xmin())
            xmax = max(xmax, m.xmax())
            ymin = min(ymin, m.ymin())
            ymax = max(ymax, m.ymax())

#        ax.relim()
#        ax.autoscale_view(tight=True)
        if fitView is not False:
            ax.set_xlim([xmin, xmax])
            ax.set_ylim([ymin, ymax])
        #        print(ax.get_data_interval())
        return ax, cbar

    if isinstance(mesh, pg.Mesh):
        if mesh.dim() == 2:
            if pg.zero(pg.y(mesh)):
                pg.info("swap z<->y coordinates for visualization.")
                meshSwap = pg.Mesh(mesh)
                for n in meshSwap.nodes():
                    n.pos()[1] = n.pos()[2]
                return showMesh(meshSwap, data, **kwargs)

            return showMesh(mesh, data, **kwargs)
        elif mesh.dim() == 3:

            from .mayaview import showMesh3D

            return showMesh3D(mesh, data, **kwargs)
        else:
            pg.error("ERROR: Mesh not valid.", mesh)

    ax = kwargs.pop('ax', None)

    if ax is None:
        ax = plt.subplots()[1]

    return ax, None
Пример #30
0
def readGmsh(fname, verbose=False):
    r"""Read :term:`Gmsh` ASCII file and return instance of GIMLI::Mesh class.

    Parameters
    ----------
    fname : string
        Filename of the file to read (\\*.msh). The file must conform
        to the `MSH ASCII file version 2
        <http://gmsh.info/doc/texinfo/gmsh.html#MSH-ASCII-file-format>`_ format
    verbose : boolean, optional
        Be verbose during import.

    Notes
    -----
    Physical groups specified in Gmsh are interpreted as follows:

    - Points with the physical number 99 are interpreted as sensors.
    - Physical Lines and Surfaces define boundaries in 2D and 3D, respectively.
        - Physical Number 1: Homogeneous Neumann condition
        - Physical Number 2: Mixed boundary condition
        - Physical Number 3: Homogeneous Dirichlet condition
        - Physical Number 4: Dirichlet condition
    - Physical Surfaces and Volumes define regions in 2D and 3D, respectively.
        - Physical Number 1: No inversion region
        - Physical Number >= 2: Inversion region

    Examples
    --------
    >>> import tempfile, os
    >>> from pygimli.meshtools import readGmsh
    >>> gmsh = '''
    ... $MeshFormat
    ... 2.2 0 8
    ... $EndMeshFormat
    ... $Nodes
    ... 3
    ... 1 0 0 0
    ... 2 0 1 0
    ... 3 1 1 0
    ... $EndNodes
    ... $Elements
    ... 7
    ... 1 15 2 0 1 1
    ... 2 15 2 0 2 2
    ... 3 15 2 0 3 3
    ... 4 1 2 0 1 2 3
    ... 5 1 2 0 2 3 1
    ... 6 1 2 0 3 1 2
    ... 7 2 2 0 5 1 2 3
    ... $EndElements
    ... '''
    >>> fname = tempfile.mktemp()
    >>> with open(fname, "w") as f:
    ...     f.writelines(gmsh)
    >>> mesh = readGmsh(fname)
    >>> print(mesh)
    Mesh: Nodes: 3 Cells: 1 Boundaries: 3
    >>> os.remove(fname)
    """
    inNodes, inElements, ncount = 0, 0, 0
    fid = open(fname)
    if verbose:
        print('Reading %s... \n' % fname)

    for line in fid:

        if line[0] == '$':
            if line.find('Nodes') > 0:
                inNodes = 1
            if line.find('EndNodes') > 0:
                inNodes = 0
            if line.find('Elements') > 0:
                inElements = 1
            if line.find('EndElements') > 0:
                inElements = 0

        else:
            if inNodes == 1:
                if len(line.split()) == 1:
                    nodes = np.zeros((int(line), 3))
                    if verbose:
                        print('  Nodes: %s' % int(line))
                else:
                    nodes[ncount, :] = np.array(line.split(), 'float')[1:]
                    ncount += 1

            elif inElements == 1:
                if len(line.split()) == 1:
                    if verbose:
                        print('  Entries: %s' % int(line))
                    points, lines, triangles, tets = [], [], [], []

                else:
                    entry = [int(e_) for e_ in line.split()][1:]

                    if entry[0] == 15:
                        points.append((entry[-2], entry[-3]))
                    elif entry[0] == 1:
                        lines.append((entry[-2], entry[-1], entry[2]))
                    elif entry[0] == 2:
                        triangles.append(
                            (entry[-3], entry[-2], entry[-1], entry[2]))
                    elif entry[0] == 4:
                        tets.append((entry[-4], entry[-3], entry[-2],
                                     entry[-1], entry[2]))
                    elif entry[0] in [3, 6]:
                        pg.error(
                            "Qudrangles and prisms are not supported yet.")

    fid.close()
    lines = np.asarray(lines)
    triangles = np.asarray(triangles)
    tets = np.asarray(tets)

    if verbose:
        print('    Points: %s' % len(points))
        print('    Lines: %s' % len(lines))
        print('    Triangles: %s' % len(triangles))
        print('    Tetrahedra: %s \n' % len(tets))
        print('Creating mesh object... \n')

    # check dimension
    if len(tets) == 0:
        dim, bounds, cells = 2, lines, triangles
        zero_dim = np.abs(nodes.sum(0)).argmin()  # identify zero dimension
    else:
        dim, bounds, cells = 3, triangles, tets
    if verbose:
        print('  Dimension: %s-D' % dim)

    # creating instance of GIMLI::Mesh class
    mesh = pg.Mesh(dim)

    # replacing boundary markers (gmsh does not allow negative phys. regions)
    bound_marker = (pg.MARKER_BOUND_HOMOGEN_NEUMANN, pg.MARKER_BOUND_MIXED,
                    pg.MARKER_BOUND_HOMOGEN_DIRICHLET,
                    pg.MARKER_BOUND_DIRICHLET)

    if bounds.any():
        for i in range(4):
            bounds[:, dim][bounds[:, dim] == i + 1] = bound_marker[i]

        # account for CEM markers
        bounds[:, dim][bounds[:, dim] >= 10000] *= -1

        if verbose:
            bound_types = np.unique(bounds[:, dim])
            print('  Boundary types: %s ' % len(bound_types) +
                  str(tuple(bound_types)))
    else:
        print("WARNING: No boundary conditions found.",
              "Setting Neumann on the outer edges by default.")

    if verbose:
        regions = np.unique(cells[:, dim + 1])
        print('  Regions: %s ' % len(regions) + str(tuple(regions)))

    for node in nodes:
        if dim == 2:
            mesh.createNode(node[0], node[3 - zero_dim], 0)
        else:
            mesh.createNode(node)

    for cell in cells:
        if dim == 2:
            mesh.createTriangle(mesh.node(int(cell[0] - 1)),
                                mesh.node(int(cell[1] - 1)),
                                mesh.node(int(cell[2] - 1)),
                                marker=int(cell[3]))
        else:
            mesh.createTetrahedron(mesh.node(int(cell[0] - 1)),
                                   mesh.node(int(cell[1] - 1)),
                                   mesh.node(int(cell[2] - 1)),
                                   mesh.node(int(cell[3] - 1)),
                                   marker=int(cell[4]))

    mesh.createNeighbourInfos()

    # Set Neumann on outer edges by default (can be overriden by Gmsh info)
    for b in mesh.boundaries():
        if not b.leftCell() or not b.rightCell():
            b.setMarker(pg.MARKER_BOUND_HOMOGEN_NEUMANN)

    for bound in bounds:
        if dim == 2:
            mesh.createEdge(mesh.node(int(bound[0] - 1)),
                            mesh.node(int(bound[1] - 1)),
                            marker=int(bound[2]))
        else:
            mesh.createTriangleFace(mesh.node(int(bound[0] - 1)),
                                    mesh.node(int(bound[1] - 1)),
                                    mesh.node(int(bound[2] - 1)),
                                    marker=int(bound[3]))

    # assign marker to corresponding nodes (sensors, reference nodes, etc.)
    if points:
        for point in points:
            mesh.node(point[0] - 1).setMarker(-point[1])

    if verbose:
        if points:
            points = np.asarray(points)
            node_types = np.unique(points[:, 1])
            print('  Marked nodes: %s ' % len(points) + str(tuple(node_types)))
        print('\nDone. \n')
        print('  ' + str(mesh))
    return mesh
Пример #31
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
Пример #32
0
def drawModel(ax, mesh, data=None, logScale=True, cMin=None, cMax=None,
              xlabel=None, ylabel=None, verbose=False,
              tri=False, rasterized=False, **kwargs):
    """Draw a 2d mesh and color the cell by the data.

    Parameters
    ----------
    mesh : :gimliapi:`GIMLI::Mesh`
        The plotted mesh to browse through.
    ax : mpl axis instance, optional
        Axis instance where the mesh is plotted (default is current axis).
    data : array, optional
        Data to draw. Should either equal numbers of cells or nodes of the
        corresponding `mesh`.
    tri : boolean, optional
        use MPL tripcolor (experimental)
    rasterized : boolean, optional
        Rasterize mesh patches to reduce file size and avoid zooming artifacts
        in some PDF viewers.
    **kwargs : Additional keyword arguments
        Will be forwarded to the draw functions and matplotlib methods,
        respectively.

    Returns
    -------
    gci : matplotlib graphics object

    Examples
    --------
    >>> import numpy as np
    >>> import matplotlib.pyplot as plt
    >>> import pygimli as pg
    >>> from pygimli.mplviewer import drawModel
    >>> n = np.linspace(0, -2, 11)
    >>> mesh = pg.createGrid(x=n, y=n)
    >>> mx = pg.x(mesh.cellCenter())
    >>> my = pg.y(mesh.cellCenter())
    >>> data = np.cos(1.5 * mx) * np.sin(1.5 * my)
    >>> fig, ax = plt.subplots()
    >>> drawModel(ax, mesh, data)
    <matplotlib.collections.PolyCollection object at ...>
    """
    # deprecated .. remove me
    if 'cMap' in kwargs or 'cmap' in kwargs:
        pg.warn('cMap|cmap argument is deprecated for draw functions. ' +
                'Please use show or customize a colorbar.')
    # deprecated .. remove me

    if mesh.nodeCount() == 0:
        pg.error("drawModel: The mesh is empty.", mesh)

    if tri:
        gci = drawMPLTri(ax, mesh, data,
                         cMin=cMin, cMax=cMax, logScale=logScale,
                         **kwargs)
    else:
        gci = pg.mplviewer.createMeshPatches(ax, mesh, verbose=verbose,
                                             rasterized=rasterized)
        ax.add_collection(gci)

        if data is None:
            data = pg.RVector(mesh.cellCount())

        if len(data) != mesh.cellCount():
            print(data, mesh)
            pg.info("drawModel have wrong data length .. " +
                    " indexing data from cellMarkers()")
            viewdata = data[mesh.cellMarkers()]
        else:
            viewdata = data

        if min(data) <= 0:
            logScale = False

        pg.mplviewer.setMappableData(gci, viewdata, cMin=cMin, cMax=cMax,
                                     logScale=logScale)

    gci.set_antialiased(True)
    gci.set_linewidths(0.1)
    gci.set_edgecolors("face")

    if xlabel is not None:
        ax.set_xlabel(xlabel)

    if ylabel is not None:
        ax.set_ylabel(ylabel)

    if kwargs.pop('fitView', True):
        ax.set_xlim(mesh.xmin(), mesh.xmax())
        ax.set_ylim(mesh.ymin(), mesh.ymax())
        ax.set_aspect('equal')

    updateAxes_(ax)
    return gci
Пример #33
0
def show(obj=None, data=None, **kwargs):
    """Mesh and model visualization.

    Syntactic sugar to show a obj with data. Forwards to
    a known visualization for obj. Typical is
    :py:mod:`pygimli.viewer.showMesh` or
    :py:mod:`pygimli.viewer.mayaview.showMesh3D` to show most of the typical 2D
    and 3D content.
    See tutorials and examples for usage hints. An empty show
    call creates an empty ax window.

    Parameters
    ----------
    obj: obj
        obj can be so far.
        * :gimliapi:`GIMLI::Mesh` or list of meshes
        * DataContainer
        * pg.core.Sparse[Map]Matrix

    data: iterable
        Optionally data to visualize. See appropriate show function.

    Keyword Arguments
    -----------------
    **kwargs
        Additional kwargs forward to appropriate show functions.

        * ax : axe [None]
            Matplotlib axes object. Create a new if necessary.
        * fitView : bool [True]
            Scale x and y limits to match the view.

    Returns
    -------
    Return the results from the showMesh* functions. Usually the axe object
    and a colorbar.

    See Also
    --------
    showMesh
    """
    if "axes" in kwargs:
        print("Deprecation Warning: Please use keyword `ax` instead of `axes`")
        kwargs['ax'] = kwargs.pop('axes', None)

    if isinstance(obj, pg.DataContainerERT):
        from pygimli.physics.ert import showERTData
        return showERTData(obj, vals=kwargs.pop('vals', data), **kwargs)

    if isinstance(obj, pg.core.MatrixBase):
        ax, _ = pg.show()
        return drawMatrix(ax, obj, **kwargs)

    mesh = kwargs.pop('mesh', obj)

    if isinstance(mesh, list):
        ax = kwargs.pop('ax', None)
        fitView = kwargs.pop('fitView', ax is None)

        ax, cBar = show(mesh[0],
                        data,
                        hold=1,
                        ax=ax,
                        fitView=fitView,
                        **kwargs)
        xMin = mesh[0].xMin()
        xMax = mesh[0].xMax()
        yMin = mesh[0].yMin()
        yMax = mesh[0].yMax()

        for m in mesh[1:]:
            ax, cBar = show(m, data, ax=ax, hold=1, fitView=False, **kwargs)
            xMin = min(xMin, m.xMin())
            xMax = max(xMax, m.xMax())
            yMin = min(yMin, m.yMin())
            yMax = max(yMax, m.yMax())


#        ax.relim()
#        ax.autoscale_view(tight=True)
        if fitView is not False:
            ax.set_xlim([xMin, xMax])
            ax.set_ylim([yMin, yMax])
        #        print(ax.get_data_interval())
        return ax, cBar

    if isinstance(mesh, pg.Mesh):
        if mesh.dim() == 2:
            if pg.zero(pg.y(mesh)):
                pg.info("swap z<->y coordinates for visualization.")
                meshSwap = pg.Mesh(mesh)
                for n in meshSwap.nodes():
                    n.pos()[1] = n.pos()[2]
                return showMesh(meshSwap, data, **kwargs)

            return showMesh(mesh, data, **kwargs)
        elif mesh.dim() == 3:

            from .vistaview import showMesh3D
            return showMesh3D(mesh, data, **kwargs)
        else:
            pg.error("ERROR: Mesh not valid.", mesh)

    ax = kwargs.pop('ax', None)

    if ax is None:
        ax = plt.subplots()[1]

    return ax, None
Пример #34
0
def showMesh(mesh,
             data=None,
             hold=False,
             block=False,
             colorBar=None,
             label=None,
             coverage=None,
             ax=None,
             savefig=None,
             showMesh=False,
             showBoundary=None,
             markers=False,
             **kwargs):
    """2D Mesh visualization.

    Create an axis object and plot a 2D mesh with given node or cell data.
    Returns the axis and the color bar. The type of data determines the
    appropriate draw method.

    Parameters
    ----------
    mesh: :gimliapi:`GIMLI::Mesh`
        2D or 3D GIMLi mesh
    data: iterable [None]
        Optionally data to visualize.

        . None (draw mesh only)
            forward to :py:mod:`pygimli.viewer.mpl.drawMesh`
            or if no cells are given:
            forward to :py:mod:`pygimli.viewer.mpl.drawPLC`

        . [[marker, value], ...]
            List of Cellvalues per cell marker
            forward to :py:mod:`pygimli.viewer.mpl.drawModel`

        . float per cell -- model, patch
            forward to :py:mod:`pygimli.viewer.mpl.drawModel`

        . float per node -- scalar field
            forward to :py:mod:`pygimli.viewer.mpl.drawField`

        . iterable of type [float, float] -- vector field
            forward to :py:mod:`pygimli.viewer.mpl.drawStreams`

        . pg.core.R3Vector -- vector field
            forward to :py:mod:`pygimli.viewer.mpl.drawStreams`

        . pg.core.stdVectorRVector3 -- sensor positions
            forward to :py:mod:`pygimli.viewer.mpl.drawSensors`
    hold: bool [false]
        Set interactive plot mode for matplotlib.
        If this is set to false [default] your script will open
        a window with the figure and draw your content.
        If set to true nothing happens until you either force another show with
        hold=False, you call plt.show() or pg.wait().
        If you want show with stopping your script set block = True.
    block: bool [false]
        Force show drawing your content and block the script until you
        close the current figure.
    colorBar: bool [None], Colorbar
        Create and show a colorbar. If colorBar is a valid colorbar then only
        its values will be updated.
    label: str
        Set colorbar label. If set colorbar is toggled to True. [None]
    coverage: iterable [None]
        Weight data by the given coverage array and fadeout the color.
    ax: matplotlib.Axes [None]
        Instead of creating a new and empty ax, just draw into the given one.
        Useful to combine multiple plots into one figure.
    savefig: string
        Filename for a direct save to disc.
        The matplotlib pdf-output is a little bit big so we try
        an epstopdf if the .eps suffix is found in savefig
    showMesh: bool [False]
        Shows the mesh itself additional.
    showBoundary: bool [None]
        Shows all boundary with marker != 0. A value None means automatic
        True for cell data and False for node data.
    marker: bool [False]
        Show mesh and boundary marker.

    Keyword Arguments
    -----------------
    **kwargs:
        * xlabel: str [None]
            Add label to the x axis
        * ylabel: str [None]
            Add label to the y axis
        fitView: bool
            Fit the axes limits to the view object. Default is True if ax is None else is set to False.
        All remaining will be forwarded to the draw functions
        and matplotlib methods, respectively.

    Examples
    --------
    >>> import pygimli as pg
    >>> import pygimli.meshtools as mt
    >>> world = mt.createWorld(start=[-10, 0], end=[10, -10],
    ...                        layers=[-3, -7], worldMarker=False)
    >>> mesh = mt.createMesh(world, quality=32, area=0.2, smooth=[1, 10])
    >>> _ = pg.viewer.showMesh(mesh, markers=True)

    Returns
    -------
    ax : matplotlib.axes

    colobar : matplotlib.colorbar
    """
    renameKwarg('cmap', 'cMap', kwargs)

    cMap = kwargs.pop('cMap', 'viridis')
    nCols = None
    cBarOrientation = kwargs.pop('orientation', 'horizontal')

    fitViewDefault = False
    if ax is None:
        fitViewDefault = True
        ax = plt.subplots()[1]

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

    if block:
        hold = True

    lastHoldStatus = pg.viewer.mpl.utils.holdAxes__
    if not lastHoldStatus or hold:
        pg.viewer.mpl.hold(val=1)
        hold = True

    gci = None
    validData = False

    if markers:
        kwargs["boundaryMarker"] = True
        if mesh.cellCount() > 0:
            uniquemarkers, uniqueidx = np.unique(np.array(mesh.cellMarkers()),
                                                 return_inverse=True)
            label = "Cell markers"
            cMap = plt.cm.get_cmap("Set3", len(uniquemarkers))
            kwargs["logScale"] = False
            kwargs["cMin"] = -0.5
            kwargs["cMax"] = len(uniquemarkers) - 0.5
            data = np.arange(len(uniquemarkers))[uniqueidx]

    if data is None:
        showMesh = True
        mesh.createNeighborInfos()
        if showBoundary is None:
            showBoundary = True
    elif isinstance(data, pg.core.stdVectorRVector3):
        drawSensors(ax, data, **kwargs)
    elif isinstance(data, pg.core.R3Vector):
        drawStreams(ax, mesh, data, **kwargs)
    else:
        ### data=[[marker, val], ....]
        if isinstance(data, list) and \
            isinstance(data[0], list) and isinstance(data[0][0], int):
            data = pg.solver.parseMapToCellArray(data, mesh)

        if hasattr(data[0], '__len__') and not \
            isinstance(data, np.ma.core.MaskedArray):

            if len(data) == 2:  # [u,v] x N
                data = np.array(data).T

            if data.shape[1] == 2:
                drawStreams(ax, mesh, data, **kwargs)

            elif data.shape[1] == 3:  # probably N x [u,v,w]
                # if sum(data[:, 0]) != sum(data[:, 1]):
                # drawStreams(ax, mesh, data, **kwargs)
                drawStreams(ax, mesh, data[:, 0:2], **kwargs)
            else:
                pg.warn("No valid stream data:", data.shape, data.ndim)
                showMesh = True
        # elif min(data) == max(data):  # or pg.core.haveInfNaN(data):
        #     pg.warn("No valid data: ", min(data), max(data), pg.core.haveInfNaN(data))
        #     showMesh = True
        else:
            validData = True
            if bool(colorBar) is not False:
                colorBar = True

            try:
                if len(data) == mesh.cellCount():
                    kwargs['nCols'] = kwargs.pop('nCols', 256)
                    if label is None:
                        label = ""

                    gci = drawModel(ax, mesh, data, **kwargs)
                    if showBoundary is None:
                        showBoundary = True

                elif len(data) == mesh.nodeCount():
                    kwargs['nLevs'] = kwargs.pop('nLevs', 5)
                    kwargs['nCols'] = kwargs.pop('nCols', kwargs['nLevs'] - 1)
                    if label is None:
                        label = ""

                    gci = drawField(ax, mesh, data, **kwargs)
                else:
                    pg.error("Data size invalid")
                    print("Data: ", len(data), min(data), max(data),
                          pg.core.haveInfNaN(data))
                    print("Mesh: ", mesh)
                    validData = False
                    drawMesh(ax, mesh)

                if cMap is not None and gci is not None:
                    gci.set_cmap(cmapFromName(cMap))
                    #gci.cmap.set_under('k')

            except BaseException as e:
                pg.error("Exception occurred: ", e)

    if mesh.cellCount() == 0:
        showMesh = False
        if mesh.boundaryCount() == 0:
            pg.viewer.mpl.drawPLC(ax,
                                  mesh,
                                  showNodes=True,
                                  fillRegion=False,
                                  showBoundary=False,
                                  **kwargs)
            showBoundary = False
            #ax.plot(pg.x(mesh), pg.y(mesh), '.', color='black')
        else:
            pg.viewer.mpl.drawPLC(ax, mesh, **kwargs)

    if showMesh:
        if gci is not None and hasattr(gci, 'set_antialiased'):
            gci.set_antialiased(True)
            gci.set_linewidth(0.3)
            gci.set_edgecolor("0.1")
        else:
            pg.viewer.mpl.drawSelectedMeshBoundaries(ax,
                                                     mesh.boundaries(),
                                                     color=kwargs.pop(
                                                         'color', "0.1"),
                                                     linewidth=0.3)
            #drawMesh(ax, mesh, **kwargs)

    if showBoundary == True or showBoundary == 1:
        b = mesh.boundaries(mesh.boundaryMarkers() != 0)
        pg.viewer.mpl.drawSelectedMeshBoundaries(ax,
                                                 b,
                                                 color=(0.0, 0.0, 0.0, 1.0),
                                                 linewidth=1.4)

    fitView = kwargs.pop('fitView', fitViewDefault)
    if fitView:
        ax.set_xlim(mesh.xMin(), mesh.xMax())
        ax.set_ylim(mesh.yMin(), mesh.yMax())
        ax.set_aspect('equal')

    cBar = None

    if label is not None and colorBar is None:
        colorBar = True

    if colorBar and validData:
        labels = ['cMin', 'cMax', 'nCols', 'nLevs', 'logScale', 'levels']
        subkwargs = {key: kwargs[key] for key in labels if key in kwargs}

        subkwargs['label'] = label
        subkwargs['cMap'] = cMap
        subkwargs['orientation'] = cBarOrientation

        if bool(colorBar):
            cBar = createColorBar(gci,
                                  size=kwargs.pop('size', 0.2),
                                  pad=kwargs.pop('pad', None),
                                  **subkwargs)
        elif colorBar is not False:
            cBar = updateColorBar(colorBar, **subkwargs)

        if markers:
            ticks = np.arange(len(uniquemarkers))
            cBar.set_ticks(ticks)
            labels = []
            for marker in uniquemarkers:
                labels.append(str((marker)))
            cBar.set_ticklabels(labels)

    if coverage is not None:
        if len(data) == mesh.cellCount():
            addCoverageAlpha(gci,
                             coverage,
                             dropThreshold=kwargs.pop('dropThreshold', 0.4))
        else:
            raise BaseException('toImplement')
            # addCoverageAlpha(gci, pg.core.cellDataToPointData(mesh, coverage))

    if not hold or block is not False and plt.get_backend().lower() != "agg":
        if data is not None:
            if len(data) == mesh.cellCount():
                CellBrowser(mesh, data, ax=ax)

        plt.show(block=block)
        try:
            plt.pause(0.01)
        except BaseException as _:
            pass

    if hold:
        pg.viewer.mpl.hold(val=lastHoldStatus)

    if savefig:
        print('saving: ' + savefig + ' ...')

        if '.' not in savefig:
            savefig += '.pdf'

        ax.figure.savefig(savefig, bbox_inches='tight')
        # rc params savefig.format=pdf

        if '.eps' in savefig:
            try:
                print("trying eps2pdf ... ")
                os.system('epstopdf ' + savefig)
            except BaseException:
                pass
        print('.. done')

    return ax, cBar
Пример #35
0
 def testTraceback2():
     pg.error("Start error test.: int", 1, " vec", pg.RVector(2))