wip
parent
6abdc60167
commit
846df545dd
@ -0,0 +1,11 @@
|
||||
{
|
||||
"python.testing.pytestArgs": [
|
||||
"tests"
|
||||
],
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.nosetestsEnabled": false,
|
||||
"python.testing.pytestEnabled": true,
|
||||
"python.pythonPath": "/usr/bin/python3",
|
||||
"python.linting.flake8Enabled": true,
|
||||
"python.linting.enabled": true
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "install pip",
|
||||
"type": "process",
|
||||
"command": "${config:python.pythonPath}",
|
||||
"args": ["-m", "pip", "install", "."]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
[build-system]
|
||||
requires = [
|
||||
"setuptools>=42",
|
||||
"wheel"
|
||||
]
|
||||
build-backend = "setuptools.build_meta"
|
@ -1,27 +0,0 @@
|
||||
import pyrocko
|
||||
import numpy as num
|
||||
|
||||
from .utils import traces_to_numpy_and_meta
|
||||
|
||||
|
||||
def remove_idas_instrument_vibration(traces, copy=True, return_ref=False):
|
||||
data, meta = traces_to_numpy_and_meta(traces)
|
||||
|
||||
ntraces_ref = int((meta.start_distance * 0.9) / meta.spatial_resolution)
|
||||
|
||||
ref = num.mean(data[:ntraces_ref], axis=1)
|
||||
|
||||
out_traces = []
|
||||
for tr in traces:
|
||||
if copy:
|
||||
tr = tr.copy()
|
||||
tr.ydata -= ref
|
||||
out_traces.append(tr)
|
||||
|
||||
if return_ref:
|
||||
trace_ref = tr.copy(data=False)
|
||||
trace_ref.ydata = ref
|
||||
trace_ref.station = "ref"
|
||||
out_traces.append(trace_ref)
|
||||
|
||||
return out_traces
|
@ -0,0 +1,264 @@
|
||||
import numpy as num
|
||||
from scipy import interpolate
|
||||
from collections.abc import Iterable
|
||||
|
||||
from pyrocko.guts import Object, Float, List, Tuple, String, Timestamp
|
||||
from pyrocko import gf
|
||||
from pyrocko.model import Location
|
||||
import pyrocko.orthodrome as od
|
||||
|
||||
r2d = 180./num.pi
|
||||
km = 1e3
|
||||
|
||||
META = {
|
||||
'measure_length': None,
|
||||
'start_distance': None,
|
||||
'stop_distance': None,
|
||||
'gauge_length': None,
|
||||
'spatial_resolution': None,
|
||||
|
||||
'geo_lat': None,
|
||||
'geo_lon': None,
|
||||
'geo_elevation': None,
|
||||
|
||||
'channel': None,
|
||||
'unit': None
|
||||
}
|
||||
|
||||
|
||||
class QuantityType(gf.meta.QuantityType):
|
||||
choices = gf.meta.QuantityType.choices + ['strain', 'strain_rate']
|
||||
|
||||
|
||||
class Fiber(Object):
|
||||
lat = Float.T(
|
||||
default=0.)
|
||||
lon = Float.T(
|
||||
default=0.)
|
||||
|
||||
codes = Tuple.T(
|
||||
4, String.T(), default=('', '', '', 'HSF'),
|
||||
help='network, station, location and channel codes to be set on '
|
||||
'the response trace. If station code is empty it will be filled'
|
||||
' by the channel number')
|
||||
quantity = QuantityType.T(
|
||||
default='strain',
|
||||
help='Measurement quantity type. If not given, it is guessed from the '
|
||||
'channel code. For some common cases, derivatives of the stored '
|
||||
'quantities are supported by using finite difference '
|
||||
'approximations (e.g. displacement to velocity or acceleration). '
|
||||
'4th order central FD schemes are used.')
|
||||
|
||||
elevation = Float.T(
|
||||
default=0.0,
|
||||
help='station surface elevation in [m]')
|
||||
|
||||
store_id = gf.meta.StringID.T(
|
||||
optional=True,
|
||||
help='ID of Green\'s function store to use for the computation. '
|
||||
'If not given, the processor may use a system default.')
|
||||
|
||||
sample_rate = Float.T(
|
||||
optional=True,
|
||||
help='sample rate to produce. '
|
||||
'If not given the GF store\'s default sample rate is used. '
|
||||
'GF store specific restrictions may apply.')
|
||||
|
||||
tmin = Timestamp.T(
|
||||
optional=True,
|
||||
help='time of first sample to request in [s]. '
|
||||
'If not given, it is determined from the Green\'s functions.')
|
||||
tmax = Timestamp.T(
|
||||
optional=True,
|
||||
help='time of last sample to request in [s]. '
|
||||
'If not given, it is determined from the Green\'s functions.')
|
||||
interpolation = gf.meta.InterpolationMethod.T(
|
||||
default='multilinear',
|
||||
help='Interpolation method between Green\'s functions. Supported are'
|
||||
' ``nearest_neighbor`` and ``multilinear``')
|
||||
|
||||
coordinates = List.T(
|
||||
help='coordinates of the cable as ``pyrocko.model.Location`` or a tuple'
|
||||
' of (north_shift, east_shift, [elevation]).')
|
||||
|
||||
channel_spacing = Float.T(
|
||||
default=4.,
|
||||
help='Channel spacing [m].')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self._locations = []
|
||||
for coord in self.coordinates:
|
||||
if isinstance(coord, Location):
|
||||
loc = coord
|
||||
elif isinstance(coord, Iterable) and len(coord) in (2, 3):
|
||||
loc = Location(
|
||||
lat=self.lat,
|
||||
lon=self.lon,
|
||||
north_shift=coord[0],
|
||||
east_shift=coord[1],
|
||||
elevation=self.elevation if len(coord) == 2 else coord[2])
|
||||
else:
|
||||
raise AttributeError(
|
||||
'coordinates have to be a list of pyrocko.model.Location'
|
||||
' or tuples of (north_shift, east_shifts, [elevation]),'
|
||||
' not %s' % type(coord))
|
||||
|
||||
self._locations.append(loc)
|
||||
assert len(self._locations) > 1, 'Fiber needs more than 1 coordinates'
|
||||
|
||||
|
||||
@classmethod
|
||||
def from_stations(cls, stations, **kwargs):
|
||||
return cls(
|
||||
coordinates=stations,
|
||||
**kwargs)
|
||||
|
||||
@property
|
||||
def distances(self):
|
||||
locations = self._locations
|
||||
nlocs = len(locations)
|
||||
|
||||
dists = [0.]
|
||||
for il in range(1, nlocs):
|
||||
dists.append(
|
||||
locations[il-1].distance_3d_to(locations[il]))
|
||||
|
||||
return num.array(dists)
|
||||
|
||||
@property
|
||||
def length(self):
|
||||
return num.sum(self.distances)
|
||||
|
||||
@property
|
||||
def nchannels(self):
|
||||
dists = self.length
|
||||
return int(dists // self.channel_spacing)
|
||||
|
||||
def interpolate_channels(self, start_channel=0):
|
||||
dists = num.cumsum(self.distances)
|
||||
|
||||
interp_lat = interpolate.interp1d(
|
||||
dists,
|
||||
tuple(loc.effective_lat for loc in self._locations))
|
||||
interp_lon = interpolate.interp1d(
|
||||
dists,
|
||||
tuple(loc.effective_lon for loc in self._locations))
|
||||
interp_elevation = interpolate.interp1d(
|
||||
dists,
|
||||
tuple(loc.elevation for loc in self._locations))
|
||||
|
||||
interp_distances = num.arange(
|
||||
0., dists.max(),
|
||||
step=self.channel_spacing)
|
||||
|
||||
channels = num.arange(interp_distances.size) + start_channel
|
||||
nchannels = channels.size
|
||||
|
||||
lats = interp_lat(interp_distances)
|
||||
lons = interp_lon(interp_distances)
|
||||
elevations = interp_elevation(interp_distances)
|
||||
|
||||
azis = num.empty(nchannels)
|
||||
azis[:-1] = od.azimuth_numpy(
|
||||
lats[:-1], lons[:-1],
|
||||
lats[1:], lons[1:],
|
||||
)
|
||||
azis[-1] = azis[-2]
|
||||
|
||||
ds = num.full(nchannels, self.channel_spacing)
|
||||
dips = -num.arctan2(
|
||||
num.gradient(elevations), ds) * r2d
|
||||
|
||||
return lats, lons, elevations, azis, dips, channels
|
||||
|
||||
def get_targets(self):
|
||||
lats, lons, elevations, azis, dips, channels = \
|
||||
self.interpolate_channels()
|
||||
nchannels = self.nchannels
|
||||
|
||||
quantity = self.quantity
|
||||
if self.quantity in ('strain', 'strain_rate'):
|
||||
quantity = 'displacement'
|
||||
|
||||
targets = []
|
||||
for icha in range(nchannels):
|
||||
codes = list(self.codes)
|
||||
if not codes[1]:
|
||||
codes[1] = '%05d' % icha
|
||||
|
||||
t = gf.Target(
|
||||
lat=lats[icha],
|
||||
lon=lons[icha],
|
||||
elevation=elevations[icha],
|
||||
azimuth=azis[icha],
|
||||
dip=dips[icha],
|
||||
north_shift=0.,
|
||||
east_shift=0.,
|
||||
sample_rate=self.sample_rate,
|
||||
|
||||
codes=codes,
|
||||
store_id=self.store_id,
|
||||
quantity=quantity,
|
||||
interpolation=self.interpolation
|
||||
)
|
||||
targets.append(t)
|
||||
return targets
|
||||
|
||||
def get_locations(self):
|
||||
return self._locations
|
||||
|
||||
|
||||
class LocalEngine(gf.LocalEngine):
|
||||
|
||||
def process_fiber(self, source, fiber, **kwargs):
|
||||
assert isinstance(source, Iterable), \
|
||||
'Currently only one source is supported!'
|
||||
|
||||
targets = fiber.get_targets()
|
||||
resp = self.process(source, targets, **kwargs)
|
||||
|
||||
traces = resp.pyrocko_traces()
|
||||
ntraces = len(traces)
|
||||
|
||||
all_times = [(tr.tmin, tr.tmax) for tr in traces]
|
||||
all_tmin = num.min(all_times)
|
||||
all_tmax = num.max(all_times)
|
||||
|
||||
meta = {
|
||||
'measure_length': fiber.length,
|
||||
'start_distance': 0.,
|
||||
'stop_distance': fiber.length,
|
||||
'gauge_length': fiber.channel_spacing,
|
||||
'spatial_resolution': fiber.channel_spacing
|
||||
}
|
||||
|
||||
for icha, (tr, target) in enumerate(zip(traces, targets)):
|
||||
tr.extend(tmin=all_tmin, tmax=all_tmax, fillmethod='repeat')
|
||||
tr.meta = meta.copy()
|
||||
tr.meta['channel'] = icha
|
||||
tr.meta['geo_lat'] = target.lat
|
||||
tr.meta['geo_lon'] = target.lon
|
||||
tr.meta['geo_elevation'] = target.elevation
|
||||
|
||||
nsamples = set([tr.ydata.size for tr in traces])
|
||||
assert len(nsamples) == 1
|
||||
nsamples = nsamples.pop()
|
||||
|
||||
if fiber.quantity in ('strain', 'strain_rate'):
|
||||
assert ntraces > 3, \
|
||||
'Too few channels in fiber for finite-difference derivation'
|
||||
|
||||
trs_strain_grad = num.gradient(
|
||||
num.array([tr.ydata for tr in traces]), fiber.channel_spacing,
|
||||
axis=0)
|
||||
|
||||
for itr, tr in enumerate(traces):
|
||||
tr.set_ydata(trs_strain_grad[itr])
|
||||
|
||||
if fiber.quantity == 'strain_rate':
|
||||
for tr in traces:
|
||||
tr.differentiate()
|
||||
|
||||
return traces
|
@ -0,0 +1,110 @@
|
||||
from pyrocko_das import gf
|
||||
from pyrocko.model import Location
|
||||
from pyrocko import trace
|
||||
import numpy as num
|
||||
|
||||
km = 1e3
|
||||
|
||||
|
||||
def test_fiber():
|
||||
|
||||
fiber = gf.Fiber(
|
||||
lat=0.5,
|
||||
lon=0.5,
|
||||
store_id='test',
|
||||
|
||||
coordinates=(
|
||||
(0, 0),
|
||||
(100, 0)
|
||||
),
|
||||
channel_spacing=1.
|
||||
)
|
||||
assert fiber.distances.size == 2
|
||||
assert fiber.distances[0] == 0.
|
||||
assert fiber.distances[1] == 100.
|
||||
|
||||
assert fiber.length == 100.
|
||||
assert fiber.nchannels == 100
|
||||
|
||||
northings, eastings, elevations, azis, dips, channels = \
|
||||
fiber.interpolate_channels()
|
||||
assert channels.size == 100.
|
||||
|
||||
num.testing.assert_equal(azis, 0.)
|
||||
num.testing.assert_equal(dips, 0.)
|
||||
|
||||
targets = fiber.get_targets()
|
||||
|
||||
assert len(targets) == 100
|
||||
assert len(targets) == fiber.nchannels
|
||||
|
||||
fiber = gf.Fiber(
|
||||
lat=0.,
|
||||
lon=0.,
|
||||
store_id='test',
|
||||
|
||||
coordinates=(
|
||||
(0, 0, 0.),
|
||||
(-20, 0, 20.),
|
||||
(-40, 0, 40.),
|
||||
),
|
||||
channel_spacing=1.,
|
||||
interpolation='multilinear'
|
||||
)
|
||||
|
||||
northings, eastings, elevations, azis, dips, channels = \
|
||||
fiber.interpolate_channels()
|
||||
num.testing.assert_equal(azis, 180.)
|
||||
num.testing.assert_equal(dips, -45.)
|
||||
|
||||
fiber = gf.Fiber(
|
||||
lat=0.,
|
||||
lon=0.,
|
||||
store_id='test',
|
||||
|
||||
coordinates=(
|
||||
Location(
|
||||
north_shift=0.,
|
||||
east_shift=0,
|
||||
elevation=0),
|
||||
Location(
|
||||
north_shift=-100.,
|
||||
east_shift=0,
|
||||
elevation=100),
|
||||
),
|
||||
channel_spacing=1.,
|
||||
interpolation='multilinear'
|
||||
)
|
||||
|
||||
northings, eastings, elevations, azis, dips, channels = \
|
||||
fiber.interpolate_channels()
|
||||
num.testing.assert_equal(azis, 180.)
|
||||
num.testing.assert_equal(dips, -45.)
|
||||
|
||||
|
||||
def test_process_fiber():
|
||||
import pyrocko.gf as pgf
|
||||
|
||||
fiber = gf.Fiber(
|
||||
lat=0.0,
|
||||
lon=0.0,
|
||||
quantity='acceleration',
|
||||
store_id='das_test',
|
||||
|
||||
coordinates=(
|
||||
(1100, 0),
|
||||
(2000, 1000)
|
||||
),
|
||||
channel_spacing=4.
|
||||
)
|
||||
engine = gf.LocalEngine(use_config=True)
|
||||
|
||||
source = pgf.DCSource(
|
||||
lat=0., lon=0.,
|
||||
depth=2*km,
|
||||
strike=45.,
|
||||
dip=30.
|
||||
)
|
||||
|
||||
traces = engine.process_fiber(source, fiber)
|
||||
trace.snuffle(traces)
|
@ -1,9 +0,0 @@
|
||||
from pyrocko import io
|
||||
from pyrocko_das import remove_idas_instrument_vibration
|
||||
|
||||
|
||||
traces = io.read("")
|
||||
|
||||
|
||||
def test_remove_idas_vibration():
|
||||
remove_idas_instrument_vibration(traces)
|
@ -0,0 +1,14 @@
|
||||
import numpy as num
|
||||
|
||||
from pyrocko import io
|
||||
from pyrocko import trace
|
||||
|
||||
|
||||
def generate_data(ncha=100, deltat=0.001, cha_spacing=1.):
|
||||
meta = io.tdms_idas.META_KEYS.copy()
|
||||
|
||||
cha_dist = num.arange(ncha) * cha_spacing
|
||||
traces = []
|
||||
|
||||
for icha in range(ncha):
|
||||
dist = cha_dist[icha]
|
Loading…
Reference in New Issue