Source code for pygimli.physics.traveltime.utils
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Tools for traveltime/refraction tomography."""
import numpy as np
import pygimli as pg
[docs]
def createCrossholeData(sensors=None, x=None, z=None):
"""
Create crosshole scheme assuming two boreholes with equal sensor numbers.
Parameters
----------
sensors : array (Nx2)
Array with position of sensors. Alternatively, specify x and z
x : iterable [M]
horizontal positions of boreholes
z : iterable [M]
vertical positions of sensors in each borehole
Returns
-------
scheme : DataContainer
Data container with `sensors` predefined sensor indices 's' and 'g'
for shot and receiver numbers.
"""
from itertools import product
if sensors is None:
if x is None or z is None:
raise Exception("Both x and z must be given")
sensors = np.array([(xi, zi) for zi in z for xi in x])
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
[docs]
def shotReceiverDistances(data, full=True):
"""Distance vector between shot and for each 's' and 'g' in data.
Parameters
----------
data : pg.DataContainerERT
full : bool [True]
Get distances between shot and receiver position when full is True or
only form x coordinate if full is False
Returns
-------
dists : array
Array of distances
"""
if full:
pos = data.sensors()
s, g = data.id("s"), data.id("g")
off = [pos[s[i]].distance(pos[g[i]]) for i in range(data.size())]
return np.absolute(off)
else:
px = pg.x(data)
gx = np.array([px[g] for g in data.id("g")])
sx = np.array([px[s] for s in data.id("s")])
return np.absolute(gx - sx)
[docs]
def createRAData(sensors, shotDistance=1):
"""Create a refraction data container.
Default data container for shot and geophon at every sensor position.
Predefined sensor indices's 's' as shot position and 'g' as
geophon position.
Parameters
----------
sensors: ndarray | R3Vector
Geophon and shot positions (same)
shotDistances: int [1]
Distance between shot indices.
Returns
-------
data : DataContainer
Data container with predefined sensor indices 's' and 'g'
for shot and receiver numbers.
"""
data = pg.DataContainer()
data.registerSensorIndex("s")
data.registerSensorIndex("g")
if isinstance(sensors, np.ndarray):
if len(sensors.shape) == 1:
for x in sensors:
data.createSensor([x, 0.0, 0.0])
else:
data.setSensorPositions(sensors)
else:
data.setSensorPositions(sensors)
S, G = [], []
for s in range(0, data.sensorCount(), shotDistance):
for g in range(data.sensorCount()):
if s is not g:
S.append(s)
G.append(g)
data.resize(len(S))
data.set("s", S)
data.set("g", G)
data.set("valid", np.abs(np.sign(data("g") - data("s"))))
return data
[docs]
def createGradientModel2D(data, mesh, vTop, vBot, flat=False):
"""Create 2D velocity gradient model.
Creates a smooth, linear, starting model that takes the slope
of the topography into account. This is done by fitting a straight line
and using the distance to that as the depth value.
Parameters
----------
data: pygimli DataContainer
The topography list is in here.
mesh: pygimli.Mesh
The parametric mesh used for the inversion
vTop: float
The velocity at the surface of the mesh
vBot: float
The velocity at the bottom of the mesh
Returns
-------
model: pygimli Vector, length M
A numpy array with slowness values that can be used to start
the inversion.
"""
xVals = pg.x(data)
yVals = pg.y(data)
if mesh.dim() == 3 or abs(min(yVals)) < 1e-8 and abs(max(yVals)) < 1e-8:
yVals = pg.z(data)
x = pg.x(mesh.cellCenters())
z = pg.y(mesh.cellCenters())
if mesh.dim() == 3 or abs(min(z)) < 1e-8 and abs(max(z)) < 1e-8:
z = pg.z(mesh.cellCenters())
pos = np.column_stack((x, z))
if flat:
p = np.polyfit(xVals, yVals, deg=1) # slope-intercept form
n = np.asarray([-p[0], 1.0]) # normal vector
nLen = np.sqrt(np.dot(n, n))
d = np.array([np.abs(np.dot(pos[i, :], n) - p[1]) / nLen for i
in range(pos.shape[0])])
else:
d = np.interp(x, xVals, yVals) - z
return 1.0 / np.interp(d, [min(d), max(d)], [vTop, vBot])