forked from pyrocko/grond
initial version
commit
91397f7ca8
@ -0,0 +1,2 @@
|
||||
build
|
||||
*.pyc
|
@ -0,0 +1,277 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import math
|
||||
import sys
|
||||
import logging
|
||||
from optparse import OptionParser
|
||||
|
||||
from pyrocko import util
|
||||
from pyrocko.gf import Range
|
||||
|
||||
import grond
|
||||
from grond import plot
|
||||
|
||||
logger = logging.getLogger('main')
|
||||
|
||||
km = 1000.
|
||||
|
||||
|
||||
def d2u(d):
|
||||
if isinstance(d, dict):
|
||||
return dict((k.replace('-', '_'), v) for (k, v) in d.iteritems())
|
||||
else:
|
||||
return d.replace('-', '_')
|
||||
|
||||
|
||||
subcommand_descriptions = {
|
||||
'init': 'print example configuration',
|
||||
'go': 'run Grond optimization',
|
||||
'forward': 'run forward modelling',
|
||||
'harvest': 'manually run harvesting',
|
||||
'map-geometry': 'make station map',
|
||||
'plot': 'plot optimization result',
|
||||
'export': 'export results',
|
||||
}
|
||||
|
||||
subcommand_usages = {
|
||||
'init': 'init [options]',
|
||||
'go': 'go <configfile> [options]',
|
||||
'forward': 'forward <rundir> [options]',
|
||||
'harvest': 'harvest <rundir> [options]',
|
||||
'map-geometry': 'map-geometry <configfile> [options]',
|
||||
'plot': 'plot <plotnames> <rundir> [options]',
|
||||
'export': 'export <rundir> <outputfile> [options]',
|
||||
}
|
||||
|
||||
subcommands = subcommand_descriptions.keys()
|
||||
|
||||
program_name = 'grond'
|
||||
|
||||
usage_tdata = d2u(subcommand_descriptions)
|
||||
usage_tdata['program_name'] = program_name
|
||||
|
||||
usage = '''%(program_name)s <subcommand> [options] [--] <arguments> ...
|
||||
|
||||
Subcommands:
|
||||
|
||||
init %(init)s
|
||||
go %(go)s
|
||||
forward %(forward)s
|
||||
harvest %(harvest)s
|
||||
map-geometry %(map_geometry)s
|
||||
plot %(plot)s
|
||||
export %(export)s
|
||||
|
||||
To get further help and a list of available options for any subcommand run:
|
||||
|
||||
%(program_name)s <subcommand> --help
|
||||
|
||||
''' % usage_tdata
|
||||
|
||||
|
||||
def add_common_options(parser):
|
||||
parser.add_option(
|
||||
'--loglevel',
|
||||
action='store',
|
||||
dest='loglevel',
|
||||
type='choice',
|
||||
choices=('critical', 'error', 'warning', 'info', 'debug'),
|
||||
default='info',
|
||||
help ='set logger level to '
|
||||
'"critical", "error", "warning", "info", or "debug". '
|
||||
'Default is "%default".')
|
||||
|
||||
|
||||
def process_common_options(options):
|
||||
util.setup_logging(program_name, options.loglevel)
|
||||
|
||||
|
||||
def cl_parse(command, args, setup=None):
|
||||
usage = subcommand_usages[command]
|
||||
descr = subcommand_descriptions[command]
|
||||
|
||||
if isinstance(usage, basestring):
|
||||
usage = [usage]
|
||||
|
||||
susage = '%s %s' % (program_name, usage[0])
|
||||
for s in usage[1:]:
|
||||
susage += '\n%s%s %s' % (' '*7, program_name, s)
|
||||
|
||||
parser = OptionParser(
|
||||
usage=susage,
|
||||
description=descr[0].upper() + descr[1:] + '.')
|
||||
|
||||
if setup:
|
||||
setup(parser)
|
||||
|
||||
add_common_options(parser)
|
||||
(options, args) = parser.parse_args(args)
|
||||
process_common_options(options)
|
||||
return parser, options, args
|
||||
|
||||
|
||||
def die(message, err=''):
|
||||
if err:
|
||||
sys.exit('%s: error: %s \n %s' % (program_name, message, err))
|
||||
else:
|
||||
sys.exit('%s: error: %s' % (program_name, message))
|
||||
|
||||
|
||||
def help_and_die(parser, message):
|
||||
parser.print_help(sys.stderr)
|
||||
sys.stderr.write('\n')
|
||||
die(message)
|
||||
|
||||
|
||||
def command_init(args):
|
||||
|
||||
dataset_config = grond.DatasetConfig(
|
||||
stations_path='stations.txt',
|
||||
events_path='events.txt',
|
||||
waveform_paths=['data'])
|
||||
|
||||
target_configs = [grond.TargetConfig(
|
||||
distance_min=10*km,
|
||||
distance_max=1000*km,
|
||||
channels=['Z', 'R', 'T'],
|
||||
interpolation='multilinear',
|
||||
store_id='global_2s',
|
||||
inner_misfit_config=grond.InnerMisfitConfig(
|
||||
fmin=0.01,
|
||||
fmax=0.1))]
|
||||
|
||||
s2 = math.sqrt(2.0)
|
||||
|
||||
problem_config = grond.CMTProblemConfig(
|
||||
name_template='cmt_%(event_name)s',
|
||||
distance_min=2.*km,
|
||||
nbootstrap=100,
|
||||
mt_type='deviatoric',
|
||||
ranges=dict(
|
||||
time=Range(0, 10.0, relative='add'),
|
||||
north_shift=Range(-16*km, 16*km),
|
||||
east_shift=Range(-16*km, 16*km),
|
||||
depth=Range(1*km, 11*km),
|
||||
magnitude=Range(4.0, 6.0),
|
||||
rmnn=Range(-s2, s2),
|
||||
rmee=Range(-s2, s2),
|
||||
rmdd=Range(-s2, s2),
|
||||
rmne=Range(-1.0, 1.0),
|
||||
rmnd=Range(-1.0, 1.0),
|
||||
rmed=Range(-1.0, 1.0),
|
||||
duration=Range(1.0, 15.0)))
|
||||
|
||||
config = grond.Config(
|
||||
dataset_config=dataset_config,
|
||||
target_configs=target_configs,
|
||||
problem_config=problem_config)
|
||||
|
||||
print config
|
||||
|
||||
|
||||
def command_go(args):
|
||||
def setup(parser):
|
||||
parser.add_option(
|
||||
'--force', dest='force', action='store_true',
|
||||
help='overwrite existing run directory')
|
||||
parser.add_option(
|
||||
'--status', dest='status', default='state',
|
||||
help='status output selection (choices: state, matrix)')
|
||||
|
||||
parser, options, args = cl_parse('go', args, setup)
|
||||
if len(args) != 1:
|
||||
help_and_die(parser, 'no config file given')
|
||||
|
||||
config_path = args[0]
|
||||
config = grond.read_config(config_path)
|
||||
if options.status == 'quiet':
|
||||
status = ()
|
||||
else:
|
||||
status = tuple(options.status.split(','))
|
||||
|
||||
grond.go(config, force=options.force, status=status)
|
||||
|
||||
|
||||
def command_forward(args):
|
||||
parser, options, args = cl_parse('forward', args)
|
||||
if len(args) != 1:
|
||||
help_and_die(parser, 'incorrect number of arguments')
|
||||
|
||||
run_path, = args
|
||||
grond.forward(run_path)
|
||||
|
||||
|
||||
def command_harvest(args):
|
||||
def setup(parser):
|
||||
parser.add_option(
|
||||
'--force', dest='force', action='store_true',
|
||||
help='overwrite existing harvest directory')
|
||||
parser.add_option(
|
||||
'--neach', dest='neach', type=int, default=10,
|
||||
help='take NEACH best samples from each chain (default: 10)')
|
||||
|
||||
parser, options, args = cl_parse('harvest', args, setup)
|
||||
if len(args) != 1:
|
||||
help_and_die(parser, 'no rundir')
|
||||
|
||||
run_path, = args
|
||||
grond.harvest(run_path, force=options.force, nbest=options.neach)
|
||||
|
||||
|
||||
def command_map_geometry(args):
|
||||
parser, options, args = cl_parse('map-geometry', args)
|
||||
if len(args) != 2:
|
||||
help_and_die(parser, 'two arguments required')
|
||||
|
||||
config_path = args[0]
|
||||
output_path = args[1]
|
||||
config = grond.read_config(config_path)
|
||||
plot.map_geometry(config, output_path)
|
||||
|
||||
|
||||
def command_plot(args):
|
||||
parser, options, args = cl_parse('plot', args)
|
||||
if len(args) != 2:
|
||||
help_and_die(parser, 'two arguments required')
|
||||
|
||||
plotnames = args[0].split(',')
|
||||
dirname = args[1]
|
||||
plot.plot_result(dirname, plotnames)
|
||||
|
||||
|
||||
def command_export(args):
|
||||
parser, options, args = cl_parse('export', args)
|
||||
if len(args) not in (1, 2):
|
||||
help_and_die(parser, 'one or two arguments required')
|
||||
|
||||
dirname = args[0]
|
||||
if len(args) == 2:
|
||||
filename = args[1]
|
||||
else:
|
||||
filename = None
|
||||
|
||||
grond.export(dirname, filename)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
sys.exit('Usage: %s' % usage)
|
||||
|
||||
args = list(sys.argv)
|
||||
args.pop(0)
|
||||
command = args.pop(0)
|
||||
|
||||
if command in subcommands:
|
||||
globals()['command_' + d2u(command)](args)
|
||||
|
||||
elif command in ('--help', '-h', 'help'):
|
||||
if command == 'help' and args:
|
||||
acommand = args[0]
|
||||
if acommand in subcommands:
|
||||
globals()['command_' + acommand](['--help'])
|
||||
|
||||
sys.exit('Usage: %s' % usage)
|
||||
|
||||
else:
|
||||
die('no such subcommand: %s' % command)
|
@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from distutils.core import setup
|
||||
|
||||
setup(
|
||||
name='grond',
|
||||
description='What do you want to bust today?!',
|
||||
author='Sebastian Heimann',
|
||||
author_email='sebastian.heimann@gfz-potsdam.de',
|
||||
packages=['grond'],
|
||||
package_dir={'grond': 'src'},
|
||||
scripts=['apps/grond'],
|
||||
package_data={'grond': []})
|
@ -0,0 +1,3 @@
|
||||
from core import * # noqa
|
||||
from cmt import * # noqa
|
||||
from dataset import * # noqa
|
@ -0,0 +1,283 @@
|
||||
import math
|
||||
import logging
|
||||
|
||||
import numpy as num
|
||||
|
||||
from pyrocko import gf, moment_tensor as mtm, util
|
||||
from pyrocko.guts import Float, String, Dict, List, Int, StringChoice
|
||||
from grond import core
|
||||
|
||||
guts_prefix = 'grond'
|
||||
|
||||
|
||||
logger = logging.getLogger('grond.cmt')
|
||||
|
||||
km = 1000.
|
||||
|
||||
as_km = dict(scale_factor=km, scale_unit='km')
|
||||
|
||||
|
||||
class CMTProblem(core.Problem):
|
||||
|
||||
parameters = [
|
||||
core.Parameter('time', 's'),
|
||||
core.Parameter('north_shift', 'm', **as_km),
|
||||
core.Parameter('east_shift', 'm', **as_km),
|
||||
core.Parameter('depth', 'm', **as_km),
|
||||
core.Parameter('magnitude'),
|
||||
core.Parameter('rmnn'),
|
||||
core.Parameter('rmee'),
|
||||
core.Parameter('rmdd'),
|
||||
core.Parameter('rmne'),
|
||||
core.Parameter('rmnd'),
|
||||
core.Parameter('rmed'),
|
||||
core.Parameter('duration')]
|
||||
|
||||
dependants = [
|
||||
core.Parameter('rel_moment_iso'),
|
||||
core.Parameter('rel_moment_clvd')]
|
||||
|
||||
base_source = gf.Source.T()
|
||||
targets = List.T(core.MisfitTarget.T())
|
||||
|
||||
ranges = Dict.T(String.T(), gf.Range.T())
|
||||
distance_min = Float.T(default=0.0)
|
||||
nbootstrap = Int.T(default=10)
|
||||
mt_type = StringChoice.T(choices=['full', 'deviatoric'])
|
||||
|
||||
def unpack(self, x):
|
||||
d = self.parameter_dict(x)
|
||||
rm6 = num.array([d.rmnn, d.rmee, d.rmdd, d.rmne, d.rmnd, d.rmed],
|
||||
dtype=num.float)
|
||||
|
||||
m0 = mtm.magnitude_to_moment(d.magnitude)
|
||||
m6 = rm6 * m0
|
||||
|
||||
p = {}
|
||||
for k in self.base_source.keys():
|
||||
if k in d:
|
||||
p[k] = float(
|
||||
self.ranges[k].make_relative(self.base_source[k], d[k]))
|
||||
|
||||
stf = gf.HalfSinusoidSTF(duration=float(d.duration))
|
||||
|
||||
source = self.base_source.clone(m6=m6, stf=stf, **p)
|
||||
return source
|
||||
|
||||
def make_dependant(self, xs, pname):
|
||||
if xs.ndim == 1:
|
||||
return self.make_dependant(xs[num.newaxis, :], pname)[0]
|
||||
|
||||
if pname in ('rel_moment_iso', 'rel_moment_clvd'):
|
||||
y = num.zeros(xs.shape[0])
|
||||
for i, x in enumerate(xs):
|
||||
source = self.unpack(x)
|
||||
mt = source.pyrocko_moment_tensor()
|
||||
res = mt.standard_decomposition()
|
||||
|
||||
if pname == 'rel_moment_iso':
|
||||
ratio_iso, m_iso = res[0][1:3]
|
||||
y[i] = ratio_iso * num.sign(m_iso[0, 0])
|
||||
else:
|
||||
ratio_clvd, m_clvd = res[2][1:3]
|
||||
evals, evecs = mtm.eigh_check(m_clvd)
|
||||
ii = num.argmax(num.abs(evals))
|
||||
y[i] = ratio_clvd * num.sign(evals[ii])
|
||||
|
||||
return y
|
||||
|
||||
else:
|
||||
raise KeyError(pname)
|
||||
|
||||
def extract(self, xs, i):
|
||||
if xs.ndim == 1:
|
||||
return self.extract(xs[num.newaxis, :], i)[0]
|
||||
|
||||
if i < self.nparameters:
|
||||
return xs[:, i]
|
||||
else:
|
||||
return self.make_dependant(
|
||||
xs, self.dependants[i-self.nparameters].name)
|
||||
|
||||
def pack(self, source):
|
||||
m6 = source.m6
|
||||
mt = source.pyrocko_moment_tensor()
|
||||
rm6 = m6 / mt.scalar_moment()
|
||||
|
||||
x = num.array([
|
||||
source.time,
|
||||
source.north_shift,
|
||||
source.east_shift,
|
||||
source.depth,
|
||||
mt.moment_magnitude(),
|
||||
] + rm6.tolist() + [source.stf.duration], dtype=num.float)
|
||||
|
||||
return x
|
||||
|
||||
def preconstrain(self, x):
|
||||
|
||||
d = self.parameter_dict(x)
|
||||
m6 = num.array([d.rmnn, d.rmee, d.rmdd, d.rmne, d.rmnd, d.rmed],
|
||||
dtype=num.float)
|
||||
|
||||
m9 = mtm.symmat6(*m6)
|
||||
if self.mt_type == 'deviatoric':
|
||||
trace_m = num.trace(m9)
|
||||
m_iso = num.diag([trace_m / 3., trace_m / 3., trace_m / 3.])
|
||||
m9 -= m_iso
|
||||
|
||||
m0_unscaled = math.sqrt(num.sum(m9.A**2)) / math.sqrt(2.)
|
||||
|
||||
m9 /= m0_unscaled
|
||||
m6 = mtm.to6(m9)
|
||||
d.rmnn, d.rmee, d.rmdd, d.rmne, d.rmnd, d.rmed = m6
|
||||
x = self.parameter_array(d)
|
||||
|
||||
source = self.unpack(x)
|
||||
if any(self.distance_min > source.distance_to(t)
|
||||
for t in self.targets):
|
||||
raise core.Forbidden()
|
||||
|
||||
return x
|
||||
|
||||
def bounds(self):
|
||||
out = []
|
||||
for p in self.parameters:
|
||||
r = self.ranges[p.name]
|
||||
out.append((r.start, r.stop))
|
||||
|
||||
return out
|
||||
|
||||
def dependant_bounds(self):
|
||||
out = [
|
||||
(-1., 1.),
|
||||
(-1., 1.)]
|
||||
|
||||
return out
|
||||
|
||||
def evaluate(self, x, return_traces=False):
|
||||
source = self.unpack(x)
|
||||
engine = gf.get_engine()
|
||||
for target in self.targets:
|
||||
target.set_return_traces(return_traces)
|
||||
|
||||
resp = engine.process(source, self.targets)
|
||||
data = []
|
||||
results = []
|
||||
for source, target, result in resp.iter_results('results'):
|
||||
if isinstance(result, gf.SeismosizerError):
|
||||
logger.debug(
|
||||
'%s.%s.%s.%s: %s' % (target.codes + (str(result),)))
|
||||
|
||||
data.append((None, None))
|
||||
if return_traces:
|
||||
results.append(None)
|
||||
else:
|
||||
data.append((result.misfit_value, result.misfit_norm))
|
||||
if return_traces:
|
||||
results.append(result)
|
||||
|
||||
ms, ns = num.array(data, dtype=num.float).T
|
||||
if return_traces:
|
||||
return ms, ns, results
|
||||
else:
|
||||
return ms, ns
|
||||
|
||||
def forward(self, x):
|
||||
source = self.unpack(x)
|
||||
engine = gf.get_engine()
|
||||
plain_targets = [target.get_plain_target() for target in self.targets]
|
||||
|
||||
resp = engine.process(source, plain_targets)
|
||||
results = []
|
||||
for source, target, result in resp.iter_results('results'):
|
||||
if isinstance(result, gf.SeismosizerError):
|
||||
logger.debug(
|
||||
'%s.%s.%s.%s: %s' % (target.codes + (str(result),)))
|
||||
|
||||
results.append(None)
|
||||
else:
|
||||
results.append(result)
|
||||
|
||||
return results
|
||||
|
||||
def get_target_weights(self):
|
||||
if self._target_weights is None:
|
||||
self._target_weights = num.array(
|
||||
[target.get_combined_weight(
|
||||
apply_balancing_weights=self.apply_balancing_weights)
|
||||
for target in self.targets], dtype=num.float)
|
||||
|
||||
return self._target_weights
|
||||
|
||||
def bootstrap_misfit(self, ms, ns, ibootstrap=None):
|
||||
w = self.get_bootstrap_weights(ibootstrap) * self.get_target_weights()
|
||||
if ibootstrap is None:
|
||||
return num.sqrt(
|
||||
num.nansum((w*ms[num.newaxis, :])**2, axis=1) /
|
||||
num.nansum((w*ns[num.newaxis, :])**2, axis=1))
|
||||
else:
|
||||
return num.sqrt(num.nansum((w*ms)**2) / num.nansum((w*ns)**2))
|
||||
|
||||
def bootstrap_misfits(self, misfits, ibootstrap):
|
||||
w = self.get_bootstrap_weights(ibootstrap)[num.newaxis, :] * \
|
||||
self.get_target_weights()[num.newaxis, :]
|
||||
|
||||
bms = num.sqrt(num.nansum((w*misfits[:, :, 0])**2, axis=1) /
|
||||
num.nansum((w*misfits[:, :, 1])**2, axis=1))
|
||||
return bms
|
||||
|
||||
def global_misfit(self, ms, ns):
|
||||
ws = self.get_target_weights()
|
||||
m = num.sqrt(num.nansum((ws*ms)**2) / num.nansum((ws*ns)**2))
|
||||
return m
|
||||
|
||||
def global_misfits(self, misfits):
|
||||
ws = self.get_target_weights()[num.newaxis, :]
|
||||
gms = num.sqrt(num.nansum((ws*misfits[:, :, 0])**2, axis=1) /
|
||||
num.nansum((ws*misfits[:, :, 1])**2, axis=1))
|
||||
return gms
|
||||
|
||||
def global_contributions(self, misfits):
|
||||
ws = self.get_target_weights()[num.newaxis, :]
|
||||
gcms = (ws*misfits[:, :, 0])**2 / \
|
||||
num.nansum((ws*misfits[:, :, 1])**2, axis=1)[:, num.newaxis]
|
||||
|
||||
return gcms
|
||||
|
||||
|
||||
class CMTProblemConfig(core.ProblemConfig):
|
||||
|
||||
ranges = Dict.T(String.T(), gf.Range.T())
|
||||
distance_min = Float.T(default=0.0)
|
||||
nbootstrap = Int.T(default=10)
|
||||
mt_type = StringChoice.T(choices=['full', 'deviatoric'])
|
||||
|
||||
def get_problem(self, event, targets):
|
||||
if event.depth is None:
|
||||
event.depth = 0.
|
||||
|
||||
base_source = gf.MTSource.from_pyrocko_event(event)
|
||||
base_source.stf = gf.HalfSinusoidSTF(duration=1.0)
|
||||
|
||||
subs = dict(
|
||||
event_name=event.name,
|
||||
event_time=util.time_to_str(event.time))
|
||||
|
||||
problem = CMTProblem(
|
||||
name=self.name_template % subs,
|
||||
apply_balancing_weights=self.apply_balancing_weights,
|
||||
base_source=base_source,
|
||||
targets=targets,
|
||||
ranges=self.ranges,
|
||||
distance_min=self.distance_min,
|
||||
nbootstrap=self.nbootstrap,
|
||||
mt_type=self.mt_type)
|
||||
|
||||
return problem
|
||||
|
||||
|
||||
__all__ = [
|
||||
'CMTProblem',
|
||||
'CMTProblemConfig',
|
||||
]
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,475 @@
|
||||
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
import numpy as num
|
||||
from pyrocko import util, pile, model, config, trace, snuffling
|
||||
from pyrocko.fdsn import enhanced_sacpz, station as fs
|
||||
from pyrocko.guts import Object, Tuple, String, Float, dump_all, load_all
|
||||
|
||||
|
||||
logger = logging.getLogger('grond.dataset')
|
||||
|
||||
|
||||
class InvalidObject(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NotFound(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class StationCorrection(Object):
|
||||
codes = Tuple.T(4, String.T())
|
||||
delay = Float.T()
|
||||
factor = Float.T()
|
||||
|
||||
|
||||
def load_station_corrections(filename):
|
||||
scs = load_all(filename=filename)
|
||||
for sc in scs:
|
||||
assert isinstance(sc, StationCorrection)
|
||||
|
||||
return scs
|
||||
|
||||
|
||||
def dump_station_corrections(station_corrections, filename):
|
||||
return dump_all(station_corrections, filename=filename)
|
||||
|
||||
|
||||
class Dataset(object):
|
||||
|
||||
def __init__(self):
|
||||
self.events = []
|
||||
self.pile = pile.Pile()
|
||||
self.stations = {}
|
||||
self.responses = defaultdict(list)
|
||||
self.responses_stationxml = []
|
||||
self.clippings = {}
|
||||
self.blacklist = set()
|
||||
self.whitelist_nslc = None
|
||||
self.whitelist_nsl = None
|
||||
self.station_corrections = {}
|
||||
self.station_factors = {}
|
||||
self.apply_correction_delays = True
|
||||
self.apply_correction_factors = True
|
||||
self.clip_handling = 'by_nsl'
|
||||
self.synthetic_test = None
|
||||
self._cache = {}
|
||||
|
||||
def empty_cache(self):
|
||||
self._cache = {}
|
||||
|
||||
def set_synthetic_test(self, synthetic_test):
|
||||
self.synthetic_test = synthetic_test
|
||||
|
||||
def add_stations(self, stations=None, filename=None):
|
||||
if stations is not None:
|
||||
for station in stations:
|
||||
self.stations[station.nsl()] = station
|
||||
|
||||
if filename is not None:
|
||||
for station in model.load_stations(filename):
|
||||
self.stations[station.nsl()] = station
|
||||
|
||||
def add_events(self, events=None, filename=None):
|
||||
if events is not None:
|
||||
self.events.extend(events)
|
||||
|
||||
if filename is not None:
|
||||
self.events.extend(model.load_events(filename))
|
||||
|
||||
def add_waveforms(self, paths, regex=None, fileformat='detect',
|
||||
show_progress=True):
|
||||
cachedirname = config.config().cache_dir
|
||||
fns = util.select_files(paths, regex=regex,
|
||||
show_progress=show_progress)
|
||||
cache = pile.get_cache(cachedirname)
|
||||
self.pile.load_files(sorted(fns), cache=cache,
|
||||
fileformat=fileformat,
|
||||
show_progress=show_progress)
|
||||
|
||||
def add_responses(self, sacpz_dirname=None, stationxml_filenames=None):
|
||||
if sacpz_dirname:
|
||||
for x in enhanced_sacpz.iload_dirname(sacpz_dirname):
|
||||
self.responses[x.codes].append(x)
|
||||
|
||||
if stationxml_filenames:
|
||||
for stationxml_filename in stationxml_filenames:
|
||||
self.responses_stationxml.append(
|
||||
fs.load_xml(filename=stationxml_filename))
|
||||
|
||||
def add_clippings(self, markers_filename):
|
||||
markers = snuffling.load_markers(markers_filename)
|
||||
clippings = {}
|
||||
for marker in markers:
|
||||
nslc = marker.one_nslc()
|
||||
nsl = nslc[:3]
|
||||
if nsl not in clippings:
|
||||
clippings[nsl] = []
|
||||
|
||||
if nslc not in clippings:
|
||||
clippings[nslc] = []
|
||||
|
||||
clippings[nsl].append(marker.tmin)
|
||||
clippings[nslc].append(marker.tmin)
|
||||
|
||||
for k, times in clippings.iteritems():
|
||||
atimes = num.array(times, dtype=num.float)
|
||||
if k not in self.clippings:
|
||||
self.clippings[k] = atimes
|
||||
else:
|
||||
self.clippings[k] = num.concatenate(self.clippings, atimes)
|
||||
|
||||
def add_blacklist(self, blacklist):
|
||||
for x in blacklist:
|
||||
if isinstance(x, basestring):
|
||||
x = tuple(x.split('.'))
|
||||
self.blacklist.add(x)
|
||||
|
||||
def add_whitelist(self, whitelist):
|
||||
if self.whitelist_nslc is None:
|
||||
self.whitelist_nslc = set()
|
||||
self.whitelist_nsl = set()
|
||||
self.whitelist_nsl_xx = set()
|
||||
|
||||
for x in whitelist:
|
||||
if isinstance(x, basestring):
|
||||
x = tuple(x.split('.'))
|
||||
assert len(x) in (3, 4)
|
||||
if len(x) == 4:
|
||||
self.whitelist_nslc.add(x)
|
||||
self.whitelist_nsl_xx.add(x[:3])
|
||||
if len(x) == 3:
|
||||
self.whitelist_nsl.add(x)
|
||||
|
||||
def add_station_corrections(self, filename):
|
||||
self.station_corrections.update(
|
||||
(sc.codes, sc) for sc in load_station_corrections(filename))
|
||||
|
||||
def is_blacklisted(self, obj):
|
||||
try:
|
||||
nslc = self.get_nslc(obj)
|
||||
if nslc in self.blacklist:
|
||||
return True
|
||||
|
||||
except InvalidObject:
|
||||
pass
|
||||
|
||||
nsl = self.get_nsl(obj)
|
||||
return (
|
||||
nsl in self.blacklist or
|
||||
nsl[1:2] in self.blacklist or
|
||||
nsl[:2] in self.blacklist)
|
||||
|
||||
def is_whitelisted(self, obj):
|
||||
if self.whitelist_nslc is None:
|
||||
return True
|
||||
|
||||
nsl = self.get_nsl(obj)
|
||||
try:
|
||||
nslc = self.get_nslc(obj)
|
||||
if nslc in self.whitelist_nslc:
|
||||
return True
|
||||
|
||||
return nsl in self.whitelist_nsl
|
||||
|
||||
except InvalidObject:
|
||||
return nsl in self.whitelist_nsl_xx or nsl in self.whitelist_nsl
|
||||
|
||||
def has_clipping(self, nsl_or_nslc, tmin, tmax):
|
||||
if nsl_or_nslc not in self.clippings:
|
||||
return False
|
||||
|
||||
atimes = self.clippings[nsl_or_nslc]
|
||||
return num.any(num.logical_and(tmin < atimes, atimes <= tmax))
|
||||
|
||||
def get_nsl(self, obj):
|
||||
if isinstance(obj, trace.Trace):
|
||||
net, sta, loc, _ = obj.nslc_id
|
||||
elif isinstance(obj, model.Station):
|
||||
net, sta, loc = obj.nsl()
|
||||
elif isinstance(obj, tuple) and len(obj) in (3, 4):
|
||||
net, sta, loc = obj[:3]
|
||||
else:
|
||||
raise InvalidObject(
|
||||
'cannot get nsl code from given object of type %s' % type(obj))
|
||||
|
||||
return net, sta, loc
|
||||
|
||||
def get_nslc(self, obj):
|
||||
if isinstance(obj, trace.Trace):
|
||||
return obj.nslc_id
|
||||
elif isinstance(obj, tuple) and len(obj) == 4:
|
||||
return obj
|
||||
else:
|
||||
raise InvalidObject(
|
||||
'cannot get nslc code from given object %s' % type(obj))
|
||||
|
||||
def get_tmin_tmax(self, obj):
|
||||
if isinstance(obj, trace.Trace):
|
||||
return obj.tmin, obj.tmax
|
||||
else:
|
||||
raise InvalidObject(
|
||||
'cannot get tmin and tmax from given object of type %s' %
|
||||
type(obj))
|
||||
|
||||
def get_station(self, obj):
|
||||
if self.is_blacklisted(obj):
|
||||
raise NotFound('station is blacklisted', self.get_nsl(obj))
|
||||
|
||||
if not self.is_whitelisted(obj):
|
||||
raise NotFound('station is not on whitelist', self.get_nsl(obj))
|
||||
|
||||
if isinstance(obj, model.Station):
|
||||
return obj
|
||||
|
||||
net, sta, loc = self.get_nsl(obj)
|
||||
|
||||
keys = [(net, sta, loc), (net, sta, ''), ('', sta, '')]
|
||||
for k in keys:
|
||||
if k in self.stations:
|
||||
return self.stations[k]
|
||||
|
||||
raise NotFound('station', keys)
|
||||
|
||||
def get_stations(self):
|
||||
return [self.stations[k] for k in sorted(self.stations)
|
||||
if not self.is_blacklisted(self.stations[k])
|
||||
and self.is_whitelisted(self.stations[k])]
|
||||
|
||||
def get_response(self, obj):
|
||||
if self.is_blacklisted(obj):
|
||||
raise NotFound('response is blacklisted', self.get_nslc(obj))
|
||||
|
||||
if not self.is_whitelisted(obj):
|
||||
raise NotFound('response is not on whitelist', self.get_nslc(obj))
|
||||
|
||||
net, sta, loc, cha = self.get_nslc(obj)
|
||||
tmin, tmax = self.get_tmin_tmax(obj)
|
||||
|
||||
keys_x = [
|
||||
(net, sta, loc, cha), (net, sta, '', cha), ('', sta, '', cha)]
|
||||
|
||||
keys = []
|
||||
for k in keys_x:
|
||||
if k not in keys:
|
||||
keys.append(k)
|
||||
|
||||
candidates = []
|
||||
for k in keys:
|
||||
if k in self.responses:
|
||||
for x in self.responses[k]:
|
||||
if x.tmin < tmin and (x.tmax is None or tmax < x.tmax):
|
||||
candidates.append(x.response)
|
||||
|
||||
for sx in self.responses_stationxml:
|
||||
try:
|
||||
candidates.append(
|
||||
sx.get_pyrocko_response(
|
||||
(net, sta, loc, cha),
|
||||
timespan=(tmin, tmax),
|
||||
fake_input_units='M'))
|
||||
|
||||
except fs.NoResponseInformation, fs.MultipleResponseInformation:
|
||||
pass
|
||||
|
||||
if len(candidates) == 1:
|
||||
return candidates[0]
|
||||
|
||||
elif len(candidates) == 0:
|
||||
raise NotFound('no response', (net, sta, loc, cha))
|
||||
else:
|
||||
raise NotFound('multiple responses', (net, sta, loc, cha))
|
||||
|
||||
def get_waveforms_raw(self, obj, tmin=None, tmax=None, tpad=0.):
|
||||
net, sta, loc = self.get_nsl(obj)
|
||||
|
||||
trs = self.pile.all(
|
||||
tmin=tmin, tmax=tmax, tpad=tpad,
|
||||
trace_selector=lambda tr: tr.nslc_id[:3] == (net, sta, loc),
|
||||
want_incomplete=False)
|
||||
|
||||
return trs
|
||||
|
||||
def get_waveform_raw(self, obj, tmin=None, tmax=None, tpad=0.):
|
||||
net, sta, loc, cha = self.get_nslc(obj)
|
||||
|
||||
if self.is_blacklisted((net, sta, loc, cha)):
|
||||
raise NotFound(
|
||||
'waveform is blacklisted', (net, sta, loc, cha))
|
||||
|
||||
if not self.is_whitelisted((net, sta, loc, cha)):
|
||||
raise NotFound(
|
||||
'waveform is not on whitelist', (net, sta, loc, cha))
|
||||
|
||||
if self.clip_handling == 'by_nsl':
|
||||
if self.has_clipping((net, sta, loc), tmin, tmax):
|
||||
raise NotFound(
|
||||
'waveform clipped', (net, sta, loc))
|
||||
|
||||
elif self.clip_handling == 'by_nslc':
|
||||
if self.has_clipping((net, sta, loc, cha), tmin, tmax):
|
||||
raise NotFound(
|
||||
'waveform clipped', (net, sta, loc, cha))
|
||||
|
||||
trs = self.pile.all(
|
||||
tmin=tmin, tmax=tmax, tpad=tpad,
|
||||
trace_selector=lambda tr: tr.nslc_id == (net, sta, loc, cha),
|
||||
want_incomplete=False)
|
||||
|
||||
if len(trs) == 1:
|
||||
return trs[0]
|
||||
|
||||
else:
|
||||
raise NotFound(
|
||||
'waveform missing or incomplete', (net, sta, loc, cha))
|
||||
|
||||
def get_waveform_restituted(
|
||||
self,
|
||||
obj, quantity='displacement',
|
||||
tmin=None, tmax=None, tpad=0.,
|
||||
tfade=0., freqlimits=None, deltat=None):
|
||||
|
||||
tr = self.get_waveform_raw(obj, tmin=tmin, tmax=tmax, tpad=tpad+tfade)
|
||||
|
||||
if deltat is not None:
|
||||
tr.downsample_to(deltat, snap=True)
|
||||
|
||||
resp = self.get_response(tr)
|
||||
return tr.transfer(tfade=tfade, freqlimits=freqlimits,
|
||||
transfer_function=resp, invert=True)
|
||||
|
||||
def get_waveform(
|
||||
self,
|
||||
obj, quantity='displacement',
|
||||
tmin=None, tmax=None, tpad=0.,
|
||||
tfade=0., freqlimits=None, deltat=None, cache=None,
|
||||
backazimuth=None,
|
||||
source=None,
|
||||
target=None):
|
||||
|
||||
if cache is True:
|
||||
cache = self._cache
|
||||
|
||||
_, _, _, channel = self.get_nslc(obj)
|
||||
station = self.get_station(self.get_nsl(obj))
|
||||
|
||||
nslc = station.nsl() + (channel,)
|
||||
|
||||
if tmin is not None:
|
||||
tmin = float(tmin)
|
||||
|
||||
if tmax is not None:
|
||||
tmax = float(tmax)
|
||||
|
||||
if cache is not None and (nslc, tmin, tmax) in cache:
|
||||
obj = cache[nslc, tmin, tmax]
|
||||
if isinstance(obj, Exception):
|
||||
raise obj
|
||||
else:
|
||||
return obj
|
||||
|
||||
if self.synthetic_test:
|
||||
tr = self.synthetic_test.get_waveform(
|
||||
nslc, tmin, tmax,
|
||||
tfade=tfade, freqlimits=freqlimits)
|
||||
if cache is not None:
|
||||
cache[tr.nslc_id, tmin, tmax] = tr
|
||||
|
||||
return tr
|
||||
|
||||
abs_delays = []
|
||||
for ocha in 'ENZRT':
|
||||
sc = self.station_corrections.get(station.nsl() + (channel,), None)
|
||||
if sc:
|
||||
abs_delays.append(abs(sc.delay))
|
||||
|
||||
if abs_delays:
|
||||
abs_delay_max = max(abs_delays)
|
||||
else:
|
||||
abs_delay_max = 0.0
|
||||
|
||||
mios = []
|
||||
mios.extend(station.guess_projections_to_enu(
|
||||
out_channels=('E', 'N', 'Z')))
|
||||
|
||||
if source is not None and target is not None:
|
||||
backazimuth = source.azibazi_to(target)[1]
|
||||
|
||||
if backazimuth is not None:
|
||||
mios.extend(station.guess_projections_to_rtu(
|
||||
out_channels=('R', 'T', 'Z'),
|
||||
backazimuth=backazimuth))
|
||||
|
||||
try:
|
||||
trs_projected = []
|
||||
for matrix, in_channels, out_channels in mios:
|
||||
deps = trace.project_dependencies(
|
||||
matrix, in_channels, out_channels)
|
||||
|
||||
trs = []
|
||||
if channel in deps:
|
||||
for cha in deps[channel]:
|
||||
trs.append(self.get_waveform_restituted(
|
||||
station.nsl() + (cha,),
|
||||
tmin=tmin, tmax=tmax, tpad=tpad+abs_delay_max,
|
||||
tfade=tfade, freqlimits=freqlimits, deltat=deltat))
|
||||
|
||||
trs_projected.extend(
|
||||
trace.project(trs, matrix, in_channels, out_channels))
|
||||
|
||||
for tr in trs_projected:
|
||||
sc = self.station_corrections.get(tr.nslc_id, None)
|
||||
if sc:
|
||||
if self.apply_correction_factors:
|
||||
tr.ydata /= sc.factor
|
||||
|
||||
if self.apply_correction_delays:
|
||||
tr.shift(-sc.delay)
|
||||
|
||||
if tmin is not None and tmax is not None:
|
||||
tr.chop(tmin, tmax)
|
||||
|
||||
if cache is not None:
|
||||
for tr in trs_projected:
|
||||
cache[tr.nslc_id, tmin, tmax] = tr
|
||||
|
||||
for tr in trs_projected:
|
||||
if tr.channel == channel:
|
||||
return tr
|
||||
|
||||
raise NotFound('waveform', station.nsl() + (channel,))
|
||||
|
||||
except NotFound, e:
|
||||
cache[nslc, tmin, tmax] = e
|
||||
raise
|
||||
|
||||
def get_events(self, magmin=None):
|
||||
evs = []
|
||||
for ev in self.events:
|
||||
if magmin is None or ev.magnitude >= magmin:
|
||||
evs.append(ev)
|
||||
|
||||
return evs
|
||||
|
||||
def get_event(self, t, magmin=None):
|
||||
evs = self.get_events(magmin=magmin)
|
||||
ev_x = None
|
||||
for ev in evs:
|
||||
if ev_x is None or abs(ev.time - t) < abs(ev_x.time - t):
|
||||
ev_x = ev
|
||||
|
||||
if not ev_x:
|
||||
raise NotFound
|
||||
|
||||
return ev_x
|
||||
|
||||
|
||||
__all__ = '''
|
||||
InvalidObject
|
||||
NotFound
|
||||
StationCorrection
|
||||
Dataset
|
||||
load_station_corrections
|
||||
dump_station_corrections
|
||||
'''.split()
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,49 @@
|
||||
import unittest
|
||||
from pyrocko import util
|
||||
from grond import HasPaths, Path
|
||||
|
||||
|
||||
class PathTestCase(unittest.TestCase):
|
||||
|
||||
def test_pathstuff(self):
|
||||
|
||||
class B(HasPaths):
|
||||
p1 = Path.T()
|
||||
p2 = Path.T()
|
||||
|
||||
class A(HasPaths):
|
||||
p1 = Path.T()
|
||||
p2 = Path.T()
|
||||
b = B.T()
|
||||
|
||||
for path_prefix_a in (
|
||||
None, 'relative_prefix_a', '/absolute_prefix_a'):
|
||||
for path_prefix_b in (
|
||||
None, 'relative_prefix_b', '/absolute_prefix_b'):
|
||||
a = A(
|
||||
path_prefix=path_prefix_a,
|
||||
p1='abc/x.txt',
|
||||
p2='/absolute/x.txt',
|
||||
b=B(
|
||||
path_prefix=path_prefix_b,
|
||||
p1='abc/y.txt',
|
||||
p2='/absolute/y.txt'))
|
||||
|
||||
a.set_basepath('rundir')
|
||||
|
||||
t1 = a.expand_path(a.p1)
|
||||
t2 = a.expand_path(a.p2)
|
||||
t3 = a.b.expand_path(a.b.p1)
|
||||
t4 = a.b.expand_path(a.b.p2)
|
||||
|
||||
a.change_basepath('resultdir')
|
||||
|
||||
assert t1 == a.expand_path(a.p1)
|
||||
assert t2 == a.expand_path(a.p2)
|
||||
assert t3 == a.b.expand_path(a.b.p1)
|
||||
assert t4 == a.b.expand_path(a.b.p2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
util.setup_logging('test_path', 'warning')
|
||||
unittest.main()
|
Loading…
Reference in New Issue