Esempio n. 1
0
def grange(start, end, dx=0, n=0, log=False):
    """Create array with possible increasing spacing.

    Create either array from start step-wise filled with dx until end reached
    [start, end] (like np.array with defined end).
    Fill the array from start to end with n steps.
    [start, end] (like np.linespace)
    Fill the array from start to end with n steps but logarithmic increasing,
    dx will be ignored.

    Parameters
    ----------
    start: float
        First value of the resulting array
    end: float
        Last value of the resulting array
    dx: float
        Linear step length, n will be ignored
    n: int
        Amount of steps
    log: bool

    Examples
    --------
    >>> from pygimli.utils import grange
    >>> v1 = grange(start=0, end=10, dx=3)
    >>> v2 = grange(start=0, end=10, n=3)
    >>> print(v1)
    4 [0.0, 3.0, 6.0, 9.0]
    >>> print(v2)
    3 [0.0, 5.0, 10.0]

    Returns
    -------
    ret: :gimliapi:`GIMLI::RVector`
        Return resulting array
    """
    s = float(start)
    e = float(end)
    d = float(dx)

    if dx != 0:
        if end < start and dx > 0:
            # print("grange: decreasing range but increasing dx, swap dx sign")
            d = -d
        if end > start and dx < 0:
            # print("grange: increasing range but decreasing dx, swap dx sign")
            d = -d
        ret = pg.RVector(range(int(floor(abs((e - s) / d)) + 1)))
        ret *= d
        ret += s
        return ret

    elif n > 0:
        if not log:
            return grange(start, end, dx=(e - s) / (n - 1))
        else:
            return pg.increasingRange(start, end, n)
    else:
        raise Exception('Either dx or n have to be given.')
Esempio n. 2
0
def grange(start, end, dx=0, n=0, log=False):
    """Create array with possible increasing spacing.

    Create either array from start step-wise filled with dx until end reached
    [start, end] (like np.array with defined end).
    Fill the array from start to end with n steps.
    [start, end] (like np.linespace)
    Fill the array from start to end with n steps but logarithmic increasing,
    dx will be ignored.

    Parameters
    ----------
    start: float
        First value of the resulting array
    end: float
        Last value of the resulting array
    dx: float
        Linear step length, n will be ignored
    n: int
        Amount of steps
    log: bool

    Examples
    --------
    >>> from pygimli.utils import grange
    >>> v1 = grange(start=0, end=10, dx=3)
    >>> v2 = grange(start=0, end=10, n=3)
    >>> print(v1)
    4 [0.0, 3.0, 6.0, 9.0]
    >>> print(v2)
    3 [0.0, 5.0, 10.0]

    Returns
    -------
    ret: :gimliapi:`GIMLI::RVector`
        Return resulting array
    """
    s = float(start)
    e = float(end)
    d = float(dx)

    if dx != 0:
        if end < start and dx > 0:
            # print("grange: decreasing range but increasing dx, swap dx sign")
            d = -d
        if end > start and dx < 0:
            # print("grange: increasing range but decreasing dx, swap dx sign")
            d = -d
        ret = pg.RVector(range(int(floor(abs((e - s) / d)) + 1)))
        ret *= d
        ret += s
        return ret

    elif n > 0:
        if not log:
            return grange(start, end, dx=(e - s) / (n - 1))
        else:
            return pg.increasingRange(start, end, n)
    else:
        raise Exception('Either dx or n have to be given.')
Esempio n. 3
0
def createParaMesh2DGrid(sensors,
                         paraDX=1,
                         paraDZ=1,
                         paraDepth=0,
                         nLayers=11,
                         boundary=-1,
                         paraBoundary=2,
                         **kwargs):
    """Create a grid style mesh for an inversion parameter mesh.

    Create a grid style mesh for an inversion parameter mesh.
    Return parameter grid for a given list of sensor positions.
    Uses and forwards arguments to
    :py:mod:`pygimli.meshtools.appendTriangleBoundary`.

    Parameters
    ----------
    sensors : list of RVector3 objects or data container with sensorPositions
        Sensor positions. Must be sorted in positive x direction
    paraDX : float, optional
        Horizontal distance between sensors, relative regarding sensor
        distance. Value must be greater than 0 otherwise 1 is assumed.
    paraDZ : float, optional
        Vertical distance to the first depth layer, relative regarding sensor
        distance. Value must be greater than 0 otherwise 1 is assumed.
    paraDepth : float, optional
        Maximum depth for parametric domain, 0 (default) means 0.4 * maximum
        sensor range.
    nLayers : int, optional [11]
        Number of depth layers.
    boundary : int, optional [-1]
        Boundary width to be appended for domain prolongation in absolute
        para domain width.
        Values lower than 0 force the boundary to be 4 times para domain width.
    paraBoundary : int, optional [2]
        Offset to the parameter domain boundary in absolute sensor spacing.

    Returns
    -------
    mesh: :gimliapi:`GIMLI::Mesh`

    Examples
    --------
    >>> import pygimli as pg
    >>> import matplotlib.pyplot as plt
    >>>
    >>> from pygimli.meshtools import createParaMesh2DGrid
    >>> mesh = createParaMesh2DGrid(sensors=pg.RVector(range(10)),
    ...                             boundary=1, paraDX=1,
    ...                             paraDZ=1, paraDepth=5)
    >>> ax, _ = pg.show(mesh, mesh.cellMarkers(), alpha=0.3, cmap="summer",
    ...                 hold=True)
    >>> ax, _ = pg.show(mesh, ax=ax)
    """
    mesh = pg.Mesh(2)

    # maybe separate x y z and sort
    if isinstance(sensors, np.ndarray) or isinstance(sensors, pg.RVector):
        sensors = [pg.RVector3(s, 0) for s in sensors]

    sensorX = pg.x(sensors)

    eSpacing = abs(sensorX[1] - sensorX[0])

    xmin = min(sensorX) - paraBoundary * eSpacing
    xmax = max(sensorX) + paraBoundary * eSpacing

    if paraDX == 0:
        paraDX = 1.
    if paraDZ == 0:
        paraDZ = 1.

    dx = eSpacing * paraDX
    dz = eSpacing * paraDZ

    if paraDepth == 0:
        paraDepth = 0.4 * (xmax - xmin)

    x = pg.utils.grange(xmin, xmax, dx=dx)

    y = -pg.increasingRange(dz, paraDepth, nLayers)

    mesh.createGrid(x, y)
    mesh.setCellMarkers([2] * mesh.cellCount())

    paraXLimits = [xmin, xmax]
    #    paraYLimits = [min(y), max(y)]  # not used

    if boundary < 0:
        boundary = abs((paraXLimits[1] - paraXLimits[0]) * 4.0)

    mesh = pg.meshtools.appendTriangleBoundary(mesh,
                                               xbound=boundary,
                                               ybound=boundary,
                                               marker=1,
                                               **kwargs)

    return mesh
Esempio n. 4
0
def appendTriangleBoundary(mesh, xbound=10, ybound=10, marker=1, quality=34.0,
                           area=0.0, smooth=False, markerBoundary=1,
                           isSubSurface=False, verbose=False):
    """Add a triangle mesh boundary to a given mesh.

    Returns a new mesh that contains a triangulated box around a given mesh
    suitable for geo-simulation (surface boundary at top).

    Parameters
    ----------
    mesh : mesh object
        Mesh to which the triangle boundary should be appended.
    xbound : float, optional
        Horizontal prolongation distance. Minimal mesh 0.5 x extension.
    ybound : float, optional
        Vertical prolongation distance. Minimal mesh 0.5 y extension.
    marker : int, optional
        Marker of new cells.
    markerBoundary : int, optional
        Marker of the inner boundary edges between mesh and new boundary.
    quality : float, optional
        Triangle quality.
    area: float, optional
        Triangle max size within the boundary.
    smooth : boolean, optional
        Apply mesh smoothing.
    isSubSurface : boolean, optional
        Apply boundary conditions suitable for geo-simulation and prolongate
        mesh to the surface if necessary.
    verbose : boolean, optional
        Be verbose.

    Examples
    --------
    >>> import matplotlib.pyplot as plt
    >>> import pygimli as pg
    >>> from pygimli.mplviewer import drawMesh, drawModel
    >>> from pygimli.meshtools import appendTriangleBoundary
    >>> inner = pg.createGrid(range(5), range(5), marker=1)
    >>> mesh = appendTriangleBoundary(inner, xbound=3, ybound=6, marker=2)

    >>> fig, (ax1, ax2) = plt.subplots(1,2)
    >>> p1 = drawMesh(ax1, inner)
    >>> p2 = drawModel(ax2, mesh, mesh.cellMarkers(), label='marker')
    >>> p3 = drawMesh(ax2, mesh)
    >>> txt1 = ax1.set_title("a) Input grid")
    >>> txt2 = ax2.set_title("b) With triangle boundary")

    See Also
    --------
    appendTetrahedronBoundary
    """
    surface = 0.0

    # find boundaries on left/right/bottom/top side
    le = [b for b in mesh.boundaries() if b.center().x() == mesh.xmin()]
    bo = [b for b in mesh.boundaries() if b.center().y() == mesh.ymin()]
    ri = [b for b in mesh.boundaries() if b.center().x() == mesh.xmax()]
    top = [b for b in mesh.boundaries() if b.center().y() == mesh.ymax()]

    # gather all right boundary nodes after sorting in boundaryNodes
    tmp = []
    for b in ri:
        if b.node(0) not in tmp:
            tmp.append(b.node(0))
        if b.node(1) not in tmp:
            tmp.append(b.node(1))

    tmp.sort(key=lambda n: n.pos().y())
    tmp.reverse()
    boundaryNodes = tmp

    # gather all bottom boundary nodes and add them to boundaryNodes
    boNode = []
    for b in bo:
        if b.node(0) not in boNode + boundaryNodes:
            boNode.append(b.node(0))
        if b.node(1) not in boNode + boundaryNodes:
            boNode.append(b.node(1))

    boNode.sort(key=lambda n: n.pos().x())
    boNode.reverse()
    boundaryNodes = boundaryNodes + boNode

    # gather all left boundary nodes and add them to boundaryNodes
    tmp = []
    for b in le:
        if b.node(0) not in tmp + boundaryNodes:
            tmp.append(b.node(0))
        if b.node(1) not in tmp + boundaryNodes:
            tmp.append(b.node(1))

    tmp.sort(key=lambda n: n.pos().y())
    boundaryNodes = boundaryNodes + tmp

    if isSubSurface:
        # gather all top boundary nodes and add them to boundaryNodes
        topNodes = []
        for boundary in top:
            if boundary.node(0) not in topNodes + boundaryNodes:
                topNodes.append(boundary.node(0))
            if boundary.node(1) not in topNodes + boundaryNodes:
                topNodes.append(boundary.node(1))
        topNodes.sort(key=lambda n: n.pos().x())
        boundaryNodes = boundaryNodes + topNodes

    poly = pg.Mesh()

    preserveSwitch = ''

    if isSubSurface:
        # add all boundary nodes
        for n in boundaryNodes:
            poly.createNode(n.pos())

        # and connect them by a closed polygon
        for i in range(0, poly.nodeCount()):
            poly.createEdge(
                poly.node(i), poly.node((i + 1) % poly.nodeCount()),
                markerBoundary)

        # add four corners of the world box
        xtLen = 12
        # x bottom boundary sampling points
        # xBottom = pg.asvector(np.linspace(mesh.xmin() - xbound,
        #                                   mesh.xmax() + xbound, xtLen))

        n1 = poly.createNode(pg.RVector3(mesh.xmax() + xbound, surface, 0.0))
        n2 = poly.createNode(pg.RVector3(mesh.xmin() - xbound, surface, 0.0))
        n3 = poly.createNode(pg.RVector3(mesh.xmin() - xbound, mesh.ymin() -
                                         ybound, 0.0))
        n4 = poly.createNode(pg.RVector3(mesh.xmax() + xbound, mesh.ymin() -
                                         ybound, 0.0))

        # and connect them by a closed polygon
        poly.createEdge(n1, n2, pg.MARKER_BOUND_HOMOGEN_NEUMANN)
        poly.createEdge(n2, n3, pg.MARKER_BOUND_MIXED)
        poly.createEdge(n3, n4, pg.MARKER_BOUND_MIXED)
        poly.createEdge(n4, n1, pg.MARKER_BOUND_MIXED)

    else:  # no isSubSurface
        xbound = max(xbound, 0.5 * (mesh.xmax() - mesh.xmin()))
        ybound = max(ybound, 0.5 * (mesh.ymax() - mesh.ymin()))
        # add top right node and boundary nodes

        dxMin = boNode[0].pos().distance(boNode[1].pos()) * 1.1
        xtLen = max(5, int(xbound / dxMin / 2.))

        # x top boundary sampling points
        xTop = pg.increasingRange(dxMin, xbound, xtLen)
        # y boundary sampling points
        yLeft = pg.increasingRange(xTop[len(xTop) - 1] - xTop[len(xTop) - 2],
                                   abs(mesh.ymin() - ybound), xtLen)

        xtLen = max(5, int((mesh.xmax() - mesh.xmin()) / dxMin / 2.))

        # x bottom boundary sampling points
        xBottom = pg.RVector(np.linspace(mesh.xmin() - xbound, mesh.xmax() +
                                         xbound, 2 * xtLen))

        for i, val in enumerate(pg.fliplr(xTop)(0, len(xTop) - 1)):
            poly.createNode([mesh.xmax() + val, mesh.ymax(), 0.0])

        for n in boundaryNodes:
            poly.createNode(n.pos())

        # add top left, bottom left and bottom right node

        for t in xTop(1, len(xTop)):
            poly.createNode([mesh.xmin() - t, mesh.ymax(), 0.0])

        for t in yLeft(1, len(yLeft)):
            poly.createNode([mesh.xmin() - xbound, mesh.ymax() - t, 0.0])

        for t in xBottom(1, len(xBottom) - 1):
            poly.createNode([t, mesh.ymin() - ybound, 0.0])

        for t in pg.fliplr(yLeft)(0, len(yLeft) - 1):
            poly.createNode([mesh.xmax() + xbound, mesh.ymax() - t, 0.0])

        # create a closed polygon through all new nodes
        for i in range(0, poly.nodeCount()):
            poly.createEdge(
                poly.node(i), poly.node((i + 1) % poly.nodeCount()),
                markerBoundary)

        preserveSwitch = 'Y'
    # poly.exportVTK('out.poly')

    mesh2 = pg.Mesh(2)

    # call triangle mesh generation
    triswitches = '-pzeAfa' + preserveSwitch + 'q' + str(quality)

    if area > 0:
        triswitches += 'a' + str(area)

    if not verbose:
        triswitches += 'Q'

    if isSubSurface:
        margin = 0.0001
        poly.addHoleMarker(pg.RVector3(mesh.xmin() + margin, mesh.ymax() -
                                       margin))
        tri = pg.TriangleWrapper(poly)
        tri.setSwitches(triswitches)
        tri.generate(mesh2)
    else:
        pg.TriangleWrapper(poly, mesh2, triswitches)

    if smooth:
        mesh2.smooth(nodeMoving=True, edgeSwapping=True, smoothFunction=1,
                     smoothIteration=2)

    mesh2.setCellMarkers([marker] * mesh2.cellCount())

    # map copy the cell not the reference, this should not happen
    # map( lambda cell: mesh2.copyCell( cell ), mesh2.cells() )
    for cell in mesh.cells():
        mesh2.copyCell(cell)

    # old neighbor infos need to be cleaned since the new cells are added
    mesh2.createNeighbourInfos(force=True)

    for b in mesh2.boundaries():
        if b.leftCell() is None or b.rightCell() is None:
            if b.center().y() == mesh2.ymax():
                b.setMarker(pg.MARKER_BOUND_HOMOGEN_NEUMANN)
            else:
                b.setMarker(pg.MARKER_BOUND_MIXED)

    return mesh2
                      start=math.pi,
                      end=2 * math.pi,
                      isClosed=False)

left = plc.createLine(start=(-20, 0.0), end=(-5.1, 0.0), segments=10)
left.node(8).setMarker(1)
mid = plc.createLine(start=(-4.9, 0.0), end=(4.9, 0.0), segments=20)
right = plc.createLine(start=(5.1, 0.0), end=(20, 0.0), segments=10)
left.node(2).setMarker(1)

border = plc.mergePLC([left, c1, mid, c2, right])

depth = 20
nz = 15
newNodes = []
y = pg.increasingRange(0.2, depth, nz)
surface = pg.createMesh2D(border, y, 0, 0, False)

#for n in surface.nodes():
#yNodes = pg.increasingRange(yDefault[1], depth+n.y(), nz)
#for y in yNodes[0:]:
#newNodes.append([n.x(), n.y() -y])

#surface = pg.createGrid(x=yDefault, y=pg.sort(pg.x(surface.positions())))

#for i, n in enumerate(surface.nodes()):
#n.setPos(newNodes[i])

#surface.smooth(1, 1, 1, 10)

ax, _ = pg.show(surface)
                      start=math.pi, end=2*math.pi, isClosed=False)
c2 = plc.createCircle(pos=( 5.0, 0.0), radius=0.1, segments=5,
                      start=math.pi, end=2*math.pi, isClosed=False)

left = plc.createLine(start=(-20, 0.0), end=(-5.1, 0.0), segments=10)
left.node(8).setMarker(1)
mid = plc.createLine(start=(-4.9, 0.0), end=(4.9, 0.0), segments=20)
right= plc.createLine(start=(5.1, 0.0), end=(20, 0.0), segments=10)
left.node(2).setMarker(1)

border = mergePLC([left, c1, mid, c2, right])

depth = 20
nz = 15
newNodes = []
y = pg.increasingRange(0.2, depth, nz)
surface = pg.createMesh2D(border, y, 0, 0, False)

#for n in surface.nodes():
    #yNodes = pg.increasingRange(yDefault[1], depth+n.y(), nz)
    #for y in yNodes[0:]:
        #newNodes.append([n.x(), n.y() -y])    

#surface = pg.createGrid(x=yDefault, y=pg.sort(pg.x(surface.positions())))

#for i, n in enumerate(surface.nodes()):
    #n.setPos(newNodes[i])
    
#surface.smooth(1, 1, 1, 10)    

ax, _ = pg.show(surface)
Esempio n. 7
0
def createParaMesh2DGrid(sensors, paraDX=1, paraDZ=1, paraDepth=0, nLayers=11,
                         boundary=-1, paraBoundary=2, verbose=False, *args,
                         **kwargs):
    """
    Create a grid style mesh for an inversion parameter mesh.

    Return parameter grid for a given list of sensor positions.

    Parameters
    ----------
    sensors : list of RVector3 objects
        Sensor positions. Must be sorted in positive x direction
    paraDX : float, optional
        Horizontal distance between sensors, relative regarding sensor
        distance. Value must be greater than 0 otherwise 1 is assumed.
    paraDZ : float, optional
        Vertical distance to the first depth layer, relative regarding sensor
        distance. Value must be greater than 0 otherwise 1 is assumed.
    paraDepth : float, optional
        Maximum depth for parametric domain, 0 (default) means 0.4 * maxmimum
        sensor range.
    nLayers : int, optional
        Number of depth layers.
    boundary : int, optional
        Boundary width to be appended for domain prolongation in absolute
        para domain width.
        Values lover 0 force the boundary to be 4 times para domain width.
    paraBoundary : int, optional
        Offset for parameter domain boundary in absolute sensor distance.
        2 (default).
    verbose : boolean, optional
        Be verbose.

    Returns
    -------
    mesh: :gimliapi:`GIMLI::Mesh`

    Examples
    --------
    >>> import pygimli as pg
    >>> import matplotlib.pyplot as plt
    >>>
    >>> from pygimli.meshtools import createParaMesh2DGrid
    >>> from pygimli.mplviewer import drawMesh
    >>> x = pg.RVector(range(10))
    >>> mesh = createParaMesh2DGrid(x, boundary=1, paraDX=1,
    ...                             paraDZ=1, paraDepth=5)
    >>> fig, ax = plt.subplots()
    >>> drawMesh(ax, mesh)
    >>> plt.show()
    """

    mesh = pg.Mesh(2)

    # maybe separate x y z and sort
    if isinstance(sensors, np.ndarray) or isinstance(sensors, pg.RVector):
        sensors = [pg.RVector3(s, 0) for s in sensors]

    sensorX = pg.x(sensors)

    eSpacing = abs(sensorX[1] - sensorX[0])

    xmin = min(sensorX) - paraBoundary * eSpacing
    xmax = max(sensorX) + paraBoundary * eSpacing

    if paraDX == 0:
        paraDX = 1.
    if paraDZ == 0:
        paraDZ = 1.

    dx = eSpacing * paraDX
    dz = eSpacing * paraDZ

    if paraDepth == 0:
        paraDepth = 0.4 * (xmax - xmin)

    x = pg.utils.grange(xmin, xmax, dx=dx)

    y = -pg.increasingRange(dz, paraDepth, nLayers)

    mesh.createGrid(x, y)

    list(map(lambda cell: cell.setMarker(2), mesh.cells()))

    paraXLimits = [xmin, xmax]
#    paraYLimits = [min(y), max(y)]  # not used

    if boundary < 0:
        boundary = abs((paraXLimits[1] - paraXLimits[0]) * 4.0)

    mesh = pg.meshtools.appendTriangleBoundary(mesh,
                                               xbound=boundary,
                                               ybound=boundary,
                                               marker=1, *args, **kwargs)

    return mesh
Esempio n. 8
0
def appendTriangleBoundary(
    mesh,
    xbound=10,
    ybound=10,
    marker=1,
    quality=34.0,
    area=0.0,
    smooth=False,
    markerBoundary=1,
    isSubSurface=False,
    verbose=False,
):
    """
    Add a triangle mesh boundary to a given mesh.

    Returns a new mesh that contains a triangulated box around a given mesh
    suitable for geo-simulation (surface boundary at top).

    Parameters
    ----------
    mesh : mesh object
        Mesh to which the triangle boundary should be appended.
    xbound : float, optional
        Horizontal prolongation distance. Minimal mesh 0.5 x extension.
    ybound : float, optional
        Vertical prolongation distance. Minimal mesh 0.5 y extension.
    marker : int, optional
        Marker of new cells.
    markerBoundary : int, optional
        Marker of the inner boundary edges between mesh and new boundary.
    quality : float, optional
        Triangle quality.
    area: float, optional
        Triangle max size within the boundary.
    smooth : boolean, optional
        Apply mesh smoothing.
    isSubSurface : boolean, optional
        Apply boundary conditions suitable for geo-simulation and prolongate
        mesh to the surface if necessary.
    verbose : boolean, optional
        Be verbose.

    Examples
    --------
    >>> from pygimli.meshtools import appendTriangleBoundary
    >>> from matplotlib import pyplot as plt
    >>> import pygimli as pg
    >>> from pygimli.mplviewer import drawMesh, drawModel
    >>> inner = pg.createGrid(range(5), range(5))
    >>> mesh = appendTriangleBoundary(inner, xbound=3, ybound=6, marker=1)
    >>> fig, (ax1, ax2) = plt.subplots(1,2)
    >>> p1 = drawMesh(ax1, inner)
    >>> p2 = drawModel(ax2, mesh, mesh.cellMarker())
    >>> p3 = drawMesh(ax2, mesh)
    >>> txt1 = ax1.set_title("a) Input grid")
    >>> txt2 = ax2.set_title("b) With triangle boundary")
    >>> plt.show()

    See Also
    --------
    appendTetrahedronBoundary
    """

    def sortNodeY(n1, n2):
        """function comparing x for using sort."""
        return cmp(n1.pos().y(), n2.pos().y())

    def sortNodeX(n1, n2):
        """function comparing y for using sort."""
        return cmp(n1.pos().x(), n2.pos().x())

    surface = 0.0

    # find boundaries on left/right/bottom/top side
    le = [b for b in mesh.boundaries() if b.center().x() == mesh.xmin()]
    bo = [b for b in mesh.boundaries() if b.center().y() == mesh.ymin()]
    ri = [b for b in mesh.boundaries() if b.center().x() == mesh.xmax()]
    top = [b for b in mesh.boundaries() if b.center().y() == mesh.ymax()]

    # gather all right boundary nodes after sorting in boundaryNodes
    tmp = []
    for b in ri:
        if b.node(0) not in tmp:
            tmp.append(b.node(0))
        if b.node(1) not in tmp:
            tmp.append(b.node(1))

    tmp.sort(key=lambda n: n.pos().y())
    tmp.reverse()
    boundaryNodes = tmp

    # gather all bottom boundary nodes and add them to boundaryNodes
    boNode = []
    for b in bo:
        if b.node(0) not in boNode + boundaryNodes:
            boNode.append(b.node(0))
        if b.node(1) not in boNode + boundaryNodes:
            boNode.append(b.node(1))

    boNode.sort(key=lambda n: n.pos().x())
    boNode.reverse()
    boundaryNodes = boundaryNodes + boNode

    # gather all left boundary nodes and add them to boundaryNodes
    tmp = []
    for b in le:
        if b.node(0) not in tmp + boundaryNodes:
            tmp.append(b.node(0))
        if b.node(1) not in tmp + boundaryNodes:
            tmp.append(b.node(1))

    tmp.sort(key=lambda n: n.pos().y())
    boundaryNodes = boundaryNodes + tmp

    if isSubSurface:
        # gather all top boundary nodes and add them to boundaryNodes
        topNodes = []
        for boundary in top:
            if boundary.node(0) not in topNodes + boundaryNodes:
                topNodes.append(boundary.node(0))
            if boundary.node(1) not in topNodes + boundaryNodes:
                topNodes.append(boundary.node(1))
        topNodes.sort(key=lambda n: n.pos().x())
        boundaryNodes = boundaryNodes + topNodes

    poly = pg.Mesh()

    preserveSwitch = ""

    if isSubSurface:
        # add all boundary nodes
        for n in boundaryNodes:
            poly.createNode(n.pos())

        # and connect them by a closed polygon
        for i in range(0, poly.nodeCount()):
            poly.createEdge(poly.node(i), poly.node((i + 1) % poly.nodeCount()), markerBoundary)

        # add four corners of the world box
        xtLen = 12
        # x bottom boundary sampling points
        # xBottom = pg.asvector(np.linspace(mesh.xmin() - xbound,
        #                                   mesh.xmax() + xbound, xtLen))

        n1 = poly.createNode(pg.RVector3(mesh.xmax() + xbound, surface, 0.0))
        n2 = poly.createNode(pg.RVector3(mesh.xmin() - xbound, surface, 0.0))
        n3 = poly.createNode(pg.RVector3(mesh.xmin() - xbound, mesh.ymin() - ybound, 0.0))
        n4 = poly.createNode(pg.RVector3(mesh.xmax() + xbound, mesh.ymin() - ybound, 0.0))

        # and connect them by a closed polygon
        poly.createEdge(n1, n2, pg.MARKER_BOUND_HOMOGEN_NEUMANN)
        poly.createEdge(n2, n3, pg.MARKER_BOUND_MIXED)
        poly.createEdge(n3, n4, pg.MARKER_BOUND_MIXED)
        poly.createEdge(n4, n1, pg.MARKER_BOUND_MIXED)

    else:  # no isSubSurface
        xbound = max(xbound, 0.5 * (mesh.xmax() - mesh.xmin()))
        ybound = max(ybound, 0.5 * (mesh.ymax() - mesh.ymin()))
        # add top right node and boundary nodes

        dxMin = boNode[0].pos().distance(boNode[1].pos()) * 1.1
        xtLen = max(5, int(xbound / dxMin / 2.0))

        # x top boundary sampling points
        xTop = pg.increasingRange(dxMin, xbound, xtLen)
        # y boundary sampling points
        yLeft = pg.increasingRange(xTop[len(xTop) - 1] - xTop[len(xTop) - 2], abs(mesh.ymin() - ybound), xtLen)

        xtLen = max(5, int((mesh.xmax() - mesh.xmin()) / dxMin / 2.0))

        # x bottom boundary sampling points
        xBottom = pg.RVector(np.linspace(mesh.xmin() - xbound, mesh.xmax() + xbound, 2 * xtLen))

        for i, val in enumerate(pg.fliplr(xTop)(0, len(xTop) - 1)):
            poly.createNode([mesh.xmax() + val, mesh.ymax(), 0.0])

        for n in boundaryNodes:
            poly.createNode(n.pos())

        # add top left, bottom left and bottom right node

        for t in xTop(1, len(xTop)):
            poly.createNode([mesh.xmin() - t, mesh.ymax(), 0.0])

        for t in yLeft(1, len(yLeft)):
            poly.createNode([mesh.xmin() - xbound, mesh.ymax() - t, 0.0])

        for t in xBottom(1, len(xBottom) - 1):
            poly.createNode([t, mesh.ymin() - ybound, 0.0])

        for t in pg.fliplr(yLeft)(0, len(yLeft) - 1):
            poly.createNode([mesh.xmax() + xbound, mesh.ymax() - t, 0.0])

        # create a closed polygon through all new nodes
        for i in range(0, poly.nodeCount()):
            poly.createEdge(poly.node(i), poly.node((i + 1) % poly.nodeCount()), markerBoundary)

        preserveSwitch = "Y"
    # poly.exportVTK('out.poly')

    mesh2 = pg.Mesh(2)

    # call triangle mesh generation
    triswitches = "-pzeAfa" + preserveSwitch + "q" + str(quality)

    if area > 0:
        triswitches += "a" + str(area)

    if not verbose:
        triswitches += "Q"

    if isSubSurface:
        margin = 0.0001
        poly.addHoleMarker(pg.RVector3(mesh.xmin() + margin, mesh.ymax() - margin))
        tri = pg.TriangleWrapper(poly)
        tri.setSwitches(triswitches)
        tri.generate(mesh2)
    else:
        pg.TriangleWrapper(poly, mesh2, triswitches)

    if smooth:
        mesh2.smooth(nodeMoving=True, edgeSwapping=True, smoothFunction=1, smoothIteration=2)

    list(map(lambda cell: cell.setMarker(marker), mesh2.cells()))

    # map copy the cell not the reference, this should not happen
    # map( lambda cell: mesh2.copyCell( cell ), mesh2.cells() )
    for cell in mesh.cells():
        mesh2.copyCell(cell)

    # old neighbor infos need to be cleaned since the new cells are added
    mesh2.createNeighbourInfos(force=True)

    for b in mesh2.boundaries():
        if b.leftCell() is None or b.rightCell() is None:
            if b.center().y() == mesh2.ymax():
                b.setMarker(pg.MARKER_BOUND_HOMOGEN_NEUMANN)
            else:
                b.setMarker(pg.MARKER_BOUND_MIXED)

    return mesh2
Esempio n. 9
0
def createParaMesh2DGrid(sensors, paraDX=1, paraDZ=1, paraDepth=0, nLayers=11,
                         boundary=-1, paraBoundary=2, **kwargs):
    """Create a grid style mesh for an inversion parameter mesh.

    Create a grid style mesh for an inversion parameter mesh.
    Return parameter grid for a given list of sensor positions.
    Uses and forwards arguments to
    :py:mod:`pygimli.meshtools.appendTriangleBoundary`.

    Parameters
    ----------
    sensors : list of RVector3 objects or data container with sensorPositions
        Sensor positions. Must be sorted in positive x direction
    paraDX : float, optional
        Horizontal distance between sensors, relative regarding sensor
        distance. Value must be greater than 0 otherwise 1 is assumed.
    paraDZ : float, optional
        Vertical distance to the first depth layer, relative regarding sensor
        distance. Value must be greater than 0 otherwise 1 is assumed.
    paraDepth : float, optional
        Maximum depth for parametric domain, 0 (default) means 0.4 * maximum
        sensor range.
    nLayers : int, optional [11]
        Number of depth layers.
    boundary : int, optional [-1]
        Boundary width to be appended for domain prolongation in absolute
        para domain width.
        Values lower than 0 force the boundary to be 4 times para domain width.
    paraBoundary : int, optional [2]
        Offset to the parameter domain boundary in absolute sensor spacing.

    Returns
    -------
    mesh: :gimliapi:`GIMLI::Mesh`

    Examples
    --------
    >>> import pygimli as pg
    >>> import matplotlib.pyplot as plt
    >>>
    >>> from pygimli.meshtools import createParaMesh2DGrid
    >>> mesh = createParaMesh2DGrid(sensors=pg.RVector(range(10)),
    ...                             boundary=1, paraDX=1,
    ...                             paraDZ=1, paraDepth=5)
    >>> ax, _ = pg.show(mesh, markers=True, showMesh=True)
    """
    mesh = pg.Mesh(2)

    # maybe separate x y z and sort
    if isinstance(sensors, np.ndarray) or isinstance(sensors, pg.RVector):
        sensors = [pg.RVector3(s, 0) for s in sensors]

    if isinstance(sensors, pg.DataContainer):
        sensors = sensors.sensorPositions()

    sensorX = pg.x(sensors)

    eSpacing = abs(sensorX[1] - sensorX[0])

    xmin = min(sensorX) - paraBoundary * eSpacing
    xmax = max(sensorX) + paraBoundary * eSpacing

    if paraDX == 0:
        paraDX = 1.
    if paraDZ == 0:
        paraDZ = 1.

    dx = paraDX
    dz = paraDZ
    if eSpacing > 0:
        dx = eSpacing * paraDX
        # dz = eSpacing * paraDZ  # not really making sense

    if paraDepth == 0:
        paraDepth = 0.4 * (xmax - xmin)

    # print(xmin, xmax, dx)
    x = pg.utils.grange(xmin, xmax, dx=dx)

    y = -pg.increasingRange(dz, paraDepth, nLayers)

    mesh.createGrid(x, y)
    mesh.setCellMarkers([2] * mesh.cellCount())

    paraXLimits = [xmin, xmax]
    #    paraYLimits = [min(y), max(y)]  # not used

    if boundary < 0:
        boundary = abs((paraXLimits[1] - paraXLimits[0]) * 4.0)

    mesh = pg.meshtools.appendTriangleBoundary(
        mesh, xbound=boundary, ybound=boundary, marker=1, **kwargs)

    return mesh
Esempio n. 10
0
File: grid.py Progetto: wk1984/gimli
def appendTriangleBoundary(mesh, xbound=10, ybound=10, marker=1, quality=34.0,
                           smooth=False, markerBoundary=1,
                           isSubSurface=False, verbose=False):
    """
    Returns a new mesh that contains a triangulated box around a given mesh
    suitable for geo-simulation (surface boundary at top).

    Parameters
    ----------
    mesh : mesh object
        Mesh to which the triangle boundary should be appended.
    xbound : float, optional
        Horizontal prolongation distance.
    ybound : float, optional
        Vertical prolongation distance.
    marker : int, optional
        Marker of new cells.
    markerBoundary : int, optional
        Marker of the inner boundary edges between mesh and new boundary.
    quality : float, optional
        Triangle quality.
    smooth : boolean, optional
        Apply mesh smoothing.
    isSubSurface : boolean, optional
        Apply boundary conditions suitable for geo-simulation and prolongate
        mesh to the surface if necessary.
    verbose : boolean, optional
        Be verbose.

    See Also
    --------
    appendTetrahedronBoundary
    """

    def sortNodeY(n1, n2):
        """function comparing x for using sort."""
        return cmp(n1.pos().y(), n2.pos().y())

    def sortNodeX(n1, n2):
        """function comparing y for using sort."""
        return cmp(n1.pos().x(), n2.pos().x())

    surface = 0.0

    # find boundaries on left/right/bottom/top side
    le = [b for b in mesh.boundaries() if b.center().x() == mesh.xmin()]
    bo = [b for b in mesh.boundaries() if b.center().y() == mesh.ymin()]
    ri = [b for b in mesh.boundaries() if b.center().x() == mesh.xmax()]
    top = [b for b in mesh.boundaries() if b.center().y() == mesh.ymax()]

    # gather all right boundary nodes after sorting in boundaryNodes
    tmp = []
    for b in ri:
        if b.node(0) not in tmp:
            tmp.append(b.node(0))
        if b.node(1) not in tmp:
            tmp.append(b.node(1))

    tmp.sort(key=lambda n: n.pos().y())
    tmp.reverse()
    boundaryNodes = tmp

    # gather all bottom boundary nodes and add them to boundaryNodes
    boNode = []
    for b in bo:
        if b.node(0) not in boNode + boundaryNodes:
            boNode.append(b.node(0))
        if b.node(1) not in boNode + boundaryNodes:
            boNode.append(b.node(1))

    boNode.sort(key=lambda n: n.pos().x())
    boNode.reverse()
    boundaryNodes = boundaryNodes + boNode

    # gather all left boundary nodes and add them to boundaryNodes
    tmp = []
    for b in le:
        if b.node(0) not in tmp + boundaryNodes:
            tmp.append(b.node(0))
        if b.node(1) not in tmp + boundaryNodes:
            tmp.append(b.node(1))

    tmp.sort(key=lambda n: n.pos().y())
    boundaryNodes = boundaryNodes + tmp

    if isSubSurface:
        # gather all top boundary nodes and add them to boundaryNodes
        topNodes = []
        for boundary in top:
            if boundary.node(0) not in topNodes + boundaryNodes:
                topNodes.append(boundary.node(0))
            if boundary.node(1) not in topNodes + boundaryNodes:
                topNodes.append(boundary.node(1))
        topNodes.sort(key=lambda n: n.pos().x())
        boundaryNodes = boundaryNodes + topNodes

    poly = pg.Mesh()

    preserveSwitch = ''

    if isSubSurface:
        # add all boundary nodes
        for n in boundaryNodes:
            poly.createNode(n.pos())

        # and connect them by a closed polygon
        for i in range(0, poly.nodeCount()):
            poly.createEdge(
                poly.node(i), poly.node((i + 1) %
                                        poly.nodeCount()), markerBoundary)

        # add four corners of the world box
        xtLen = 12
        # x bottom boundary sampling points
        #xBottom = pg.asvector( np.linspace( mesh.xmin() - xbound, mesh.xmax() + xbound, xtLen ) )

        n1 = poly.createNode(pg.RVector3(mesh.xmax() + xbound, surface, 0.0))
        n2 = poly.createNode(pg.RVector3(mesh.xmin() - xbound, surface, 0.0))
        n3 = poly.createNode(pg.RVector3(mesh.xmin() - xbound,
                                        mesh.ymin() - ybound,
                                        0.0))
        n4 = poly.createNode(pg.RVector3(mesh.xmax() + xbound,
                                        mesh.ymin() - ybound,
                                        0.0))
        
        # and connect them by a closed polygon
        poly.createEdge(n1, n2, pg.MARKER_BOUND_HOMOGEN_NEUMANN)
        poly.createEdge(n2, n3, pg.MARKER_BOUND_MIXED)
        poly.createEdge(n3, n4, pg.MARKER_BOUND_MIXED)
        poly.createEdge(n4, n1, pg.MARKER_BOUND_MIXED)

    else:
        # add top right node and boundary nodes
        xtLen = 12

        dxMin = boNode[0].pos().distance(boNode[1].pos()) * 1.5
        # x top boundary sampling points
        xTop = pg.increasingRange(dxMin, xbound, xtLen)
        # y boundary sampling points
        yLeft = pg.increasingRange(
            xTop[xtLen - 1] - xTop[xtLen - 2],
            abs(mesh.ymin() - ybound),
            xtLen)

        # x bottom boundary sampling points
        xBottom = pg.asvector(
            np.linspace(mesh.xmin() - xbound,
                        mesh.xmax() + xbound,
                        xtLen))

        for t in pg.fliplr(xTop)(0, len(xTop) - 1):
            poly.createNode(pg.RVector3(mesh.xmax() + t, mesh.ymax(), 0.0))

        for n in boundaryNodes:
            poly.createNode(n.pos())

        # add top left, bottom left and bottom right node

        for t in xTop(1, len(xTop)):
            poly.createNode(pg.RVector3(mesh.xmin() - t, mesh.ymax(), 0.0))

        for t in yLeft(1, len(yLeft)):
            poly.createNode(
                pg.RVector3(mesh.xmin() - xbound,
                           mesh.ymax() - t,
                           0.0))

        for t in xBottom(1, len(xBottom) - 1):
            poly.createNode(pg.RVector3(t, mesh.ymin() - ybound, 0.0))

        for t in pg.fliplr(yLeft)(0, len(yLeft) - 1):
            poly.createNode(
                pg.RVector3(mesh.xmax() + xbound,
                           mesh.ymax() - t,
                           0.0))

        # create a closed polygon through all new nodes
        for i in range(0, poly.nodeCount()):
            poly.createEdge(
                poly.node(i), poly.node((i + 1) %
                                        poly.nodeCount()), markerBoundary)

        preserveSwitch = 'Y'
    # poly.exportVTK('out.poly')

    mesh2 = pg.Mesh()

    # call triangle mesh generation
    triswitches = '-pzeAfa' + preserveSwitch + 'q' + str(quality)

    if not verbose:
        triswitches += 'Q'

    if isSubSurface:
        tri = pg.TriangleWrapper(poly)
        # area -1.0 means this is a hole
        tri.addRegionMarkerTmp(0,
                               pg.RVector3(mesh.xmin() + 0.0001,
                                          mesh.ymax() - 0.0001),
                               -1.0)
        tri.setSwitches(triswitches)
        tri.generate(mesh2)
    else:
        pg.TriangleWrapper(poly, mesh2, triswitches)

    if smooth:
        mesh2.smooth(nodeMoving=True,
                     edgeSwapping=True,
                     smoothFunction=1,
                     smoothIteration=2)

    list(map(lambda cell: cell.setMarker(marker), mesh2.cells()))

    #! map copy the cell not the reference, this should not happen
    #! map( lambda cell: mesh2.copyCell( cell ), mesh2.cells() )
    for cell in mesh.cells():
        mesh2.copyCell(cell)

    #! old neighbor infos need to be cleaned since the new cells are added
    mesh2.createNeighbourInfos(force=True)

    for b in mesh2.boundaries():
        if b.leftCell() is None or b.rightCell() is None:
            if b.center().y() == mesh2.ymax():
                b.setMarker(pg.MARKER_BOUND_HOMOGEN_NEUMANN)
            else:
                b.setMarker(pg.MARKER_BOUND_MIXED)

    return mesh2