Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Sebastian Heimann
lassie
Commits
3af729e0
Commit
3af729e0
authored
Jun 23, 2017
by
Marius Isken
Browse files
Merge branch 'master' of
https://gitext.gfz-potsdam.de/heimann/lassie
parents
5cba895a
839978e1
Changes
16
Expand all
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
3af729e0
...
@@ -189,3 +189,18 @@ Now run the detector with
...
@@ -189,3 +189,18 @@ Now run the detector with
lassie scan config.yaml
lassie scan config.yaml
```
```
#### Scrutinize detections
After the detection has finished have a look at the results using Pyrocko's
[
Snuffler
](
http://emolch.github.io/pyrocko/current/snuffler.html
)
:
```
bash
lassie snuffle config.yaml
```

Snuffler opens loading waveform data together with station meta data and
detections as event markers. Load a reference catalog to compare the detections
to and scrutinize detection performance at different detection thresholds,
interactively.
apps/lassie
View file @
3af729e0
...
@@ -27,14 +27,16 @@ def str_to_time(s):
...
@@ -27,14 +27,16 @@ def str_to_time(s):
subcommand_descriptions
=
{
subcommand_descriptions
=
{
'init'
:
'create initial configuration file'
,
'init'
:
'create initial configuration file'
,
'scan'
:
'detect seismic events'
,
'search'
:
'detect seismic events'
,
'map-geometry'
:
'make station map'
'map-geometry'
:
'make station map'
,
'snuffle'
:
'snuffle'
}
}
subcommand_usages
=
{
subcommand_usages
=
{
'init'
:
'init'
,
'init'
:
'init'
,
'scan'
:
'scan <configfile> [options]'
,
'search'
:
'search <configfile> [options]'
,
'map-geometry'
:
'map-geometry <configfile> [options]'
,
'map-geometry'
:
'map-geometry <configfile> [options] <output.(png|pdf)'
,
'snuffle'
:
'snuffle <configfile>'
,
}
}
subcommands
=
subcommand_descriptions
.
keys
()
subcommands
=
subcommand_descriptions
.
keys
()
...
@@ -49,8 +51,9 @@ usage = program_name + ''' <subcommand> [options] [--] <arguments> ...
...
@@ -49,8 +51,9 @@ usage = program_name + ''' <subcommand> [options] [--] <arguments> ...
Subcommands:
Subcommands:
init %(init)s
init %(init)s
s
can
%(s
can
)s
s
earch
%(s
earch
)s
map-geometry %(map_geometry)s
map-geometry %(map_geometry)s
snuffle %(snuffle)s
To get further help and a list of available options for any subcommand run:
To get further help and a list of available options for any subcommand run:
...
@@ -67,9 +70,9 @@ def add_common_options(parser):
...
@@ -67,9 +70,9 @@ def add_common_options(parser):
type
=
'choice'
,
type
=
'choice'
,
choices
=
(
'critical'
,
'error'
,
'warning'
,
'info'
,
'debug'
),
choices
=
(
'critical'
,
'error'
,
'warning'
,
'info'
,
'debug'
),
default
=
'info'
,
default
=
'info'
,
help
=
'set logger level to '
help
=
'set logger level to '
'"critical", "error", "warning", "info", or "debug". '
'"critical", "error", "warning", "info", or "debug". '
'Default is "%default".'
)
'Default is "%default".'
)
def
process_common_options
(
options
):
def
process_common_options
(
options
):
...
@@ -169,6 +172,10 @@ stations_path: '%(stations_path)s'
...
@@ -169,6 +172,10 @@ stations_path: '%(stations_path)s'
data_paths:
data_paths:
%(s_data_paths)s
%(s_data_paths)s
## name template for Lassie's output directory. The placeholder
## "${config_name}" will be replaced with the basename of the config file.
run_path: '${config_name}.turd'
## Processing time interval (default: use time interval of available data)
## Processing time interval (default: use time interval of available data)
# tmin: '2012-02-06 04:20:00'
# tmin: '2012-02-06 04:20:00'
# tmax: '2012-02-06 04:30:00'
# tmax: '2012-02-06 04:30:00'
...
@@ -193,39 +200,90 @@ autogrid_radius_factor: 1.5
...
@@ -193,39 +200,90 @@ autogrid_radius_factor: 1.5
## Grid density factor used when automatically choosing a grid
## Grid density factor used when automatically choosing a grid
autogrid_density_factor: 10.0
autogrid_density_factor: 10.0
##
I
mage function
composition
##
Composition of i
mage function
image_function_contributions:
image_function_contributions:
- !lassie.WavePacketIFC
- !lassie.OnsetIFC
name: 'P'
name: 'P'
weight:
1
.0
weight:
30
.0
fmin: 1.0
fmin: 1.0
fmax: 15.0
fmax: 15.0
fsmooth_factor: 0.1
short_window: 1.0
shifter: !lassie.VelocityShifter
window_ratio: 8.0
velocity: 3500.
fsmooth: 0.2
fnormalize: 0.02
#shifter: !lassie.VelocityShifter
# velocity: 6000.
shifter: !lassie.CakePhaseShifter
timing: '{stored:p}'
earthmodel_id: 'swiss'
- !lassie.WavePacketIFC
- !lassie.WavePacketIFC
name: 'S'
name: 'S'
weight: 1.0
weight: 1.0
fmin: 1.0
fmin: 1.0
fmax: 10.0
fmax: 8.0
fsmooth_factor: 0.1
fsmooth: 0.05
shifter: !lassie.VelocityShifter
#shifter: !lassie.VelocityShifter
velocity: 2500.
# velocity: 3300.
shifter: !lassie.CakePhaseShifter
# factor: 1.0
# offset: 1.0
timing: '{stored:s}'
earthmodel_id: 'swiss'
## Whether to divide image function frames by their mean value
## Whether to divide image function frames by their mean value
sharpness_normalization:
tru
e
sharpness_normalization:
fals
e
## Threshold on detector function
## Threshold on detector function
detector_threshold: 100.0
detector_threshold: 150.
## Output filename for detections
## Whether to create a figure for every detection and save it in the output
detections_path: 'detections.txt'
## directory
save_figures: true
## Mapping of phase ID to phase definition in cake syntax (used e.g. in the
## CakePhaseShifter config sections)
tabulated_phases:
- !pf.TPDef
id: 'p'
definition: 'P,p'
- !pf.TPDef
id: 's'
definition: 'S,s'
## Mapping of earthmodel ID to the actual earth model in nd format (used in
## the CakePhaseShifter config sections)
earthmodels:
- !lassie.CakeEarthmodel
id: 'swiss'
earthmodel_1d: |2
0.0 5.53 3.10 2.75
2.0 5.53 3.10 2.75
2.0 5.80 3.25 2.75
5.0 5.80 3.25 2.75
5.0 5.83 3.27 2.75
8.0 5.83 3.27 2.75
8.0 5.95 3.34 2.8
13.0 5.95 3.34 2.8
13.0 5.96 3.34 2.8
22.0 5.96 3.34 2.8
22.0 6.53 3.66 2.8
30.0 6.53 3.66 2.8
30.0 7.18 4.03 3.3
40.0 7.18 4.03 3.3
40.0 7.53 4.23 3.3
50.0 7.53 4.23 3.3
50.0 7.83 4.39 3.3
60.0 7.83 4.39 3.3
60.0 8.15 4.57 3.3
120.0 8.15 4.57 3.3
'''
%
dict
(
'''
%
dict
(
stations_path
=
stations_path
,
stations_path
=
stations_path
,
s_data_paths
=
s_data_paths
)
s_data_paths
=
s_data_paths
)
def
command_s
can
(
args
):
def
command_s
earch
(
args
):
def
setup
(
parser
):
def
setup
(
parser
):
parser
.
add_option
(
parser
.
add_option
(
'--force'
,
dest
=
'force'
,
action
=
'store_true'
,
'--force'
,
dest
=
'force'
,
action
=
'store_true'
,
...
@@ -239,6 +297,11 @@ def command_scan(args):
...
@@ -239,6 +297,11 @@ def command_scan(args):
'--show-movie'
,
dest
=
'show_movie'
,
action
=
'store_true'
,
'--show-movie'
,
dest
=
'show_movie'
,
action
=
'store_true'
,
help
=
'show movie when showing detections'
)
help
=
'show movie when showing detections'
)
parser
.
add_option
(
'--show-window-traces'
,
dest
=
'show_window_traces'
,
action
=
'store_true'
,
help
=
'show preprocessed traces for every processing time window'
)
parser
.
add_option
(
parser
.
add_option
(
'--stop-after-first'
,
dest
=
'stop_after_first'
,
action
=
'store_true'
,
'--stop-after-first'
,
dest
=
'stop_after_first'
,
action
=
'store_true'
,
help
=
'show plot for every detection found'
)
help
=
'show plot for every detection found'
)
...
@@ -253,7 +316,15 @@ def command_scan(args):
...
@@ -253,7 +316,15 @@ def command_scan(args):
help
=
'end of processing time window '
help
=
'end of processing time window '
'(overrides config file settings)'
)
'(overrides config file settings)'
)
parser
,
options
,
args
=
cl_parse
(
'scan'
,
args
,
setup
=
setup
)
parser
.
add_option
(
'--nworkers'
,
dest
=
'nworkers'
,
metavar
=
"N"
,
help
=
'use N cpus in parallel'
)
parser
.
add_option
(
'--speak'
,
dest
=
'bark'
,
action
=
'store_true'
,
help
=
'alert on detection of events'
)
parser
,
options
,
args
=
cl_parse
(
'search'
,
args
,
setup
=
setup
)
if
len
(
args
)
!=
1
:
if
len
(
args
)
!=
1
:
help_and_die
(
parser
,
'missing argument'
)
help_and_die
(
parser
,
'missing argument'
)
...
@@ -268,14 +339,22 @@ def command_scan(args):
...
@@ -268,14 +339,22 @@ def command_scan(args):
if
options
.
tmax
:
if
options
.
tmax
:
tmax
=
str_to_time
(
options
.
tmax
)
tmax
=
str_to_time
(
options
.
tmax
)
lassie
.
scan
(
if
options
.
nworkers
:
nparallel
=
int
(
options
.
nworkers
)
else
:
nparallel
=
None
lassie
.
search
(
config
,
config
,
override_tmin
=
tmin
,
override_tmin
=
tmin
,
override_tmax
=
tmax
,
override_tmax
=
tmax
,
force
=
options
.
force
,
force
=
options
.
force
,
show_detections
=
options
.
show_detections
,
show_detections
=
options
.
show_detections
,
show_movie
=
options
.
show_movie
,
show_movie
=
options
.
show_movie
,
stop_after_first
=
options
.
stop_after_first
)
show_window_traces
=
options
.
show_window_traces
,
stop_after_first
=
options
.
stop_after_first
,
nparallel
=
nparallel
,
bark
=
options
.
bark
)
except
lassie
.
LassieError
,
e
:
except
lassie
.
LassieError
,
e
:
die
(
str
(
e
))
die
(
str
(
e
))
...
@@ -292,6 +371,17 @@ def command_map_geometry(args):
...
@@ -292,6 +371,17 @@ def command_map_geometry(args):
lassie
.
map_geometry
(
config
,
output_path
)
lassie
.
map_geometry
(
config
,
output_path
)
def
command_snuffle
(
args
):
parser
,
options
,
args
=
cl_parse
(
'snuffle'
,
args
)
if
len
(
args
)
!=
1
:
help_and_die
(
parser
,
'missing arguments'
)
config_path
=
args
[
0
]
config
=
lassie
.
read_config
(
config_path
)
lassie
.
snuffle
(
config
)
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
usage_sub
=
'fomosto %s [options]'
usage_sub
=
'fomosto %s [options]'
...
...
doc/gx/snuffling_example.png
0 → 100644
View file @
3af729e0
65.3 KB
setup.py
View file @
3af729e0
...
@@ -7,4 +7,4 @@ setup(
...
@@ -7,4 +7,4 @@ setup(
packages
=
[
'lassie'
],
packages
=
[
'lassie'
],
package_dir
=
{
'lassie'
:
'src'
},
package_dir
=
{
'lassie'
:
'src'
},
scripts
=
[
'apps/lassie'
],
scripts
=
[
'apps/lassie'
],
package_data
=
{
'lassie'
:
[]})
package_data
=
{
'lassie'
:
[
'data/*.wav'
]})
src/__init__.py
View file @
3af729e0
...
@@ -6,6 +6,7 @@ from lassie.ifc import * # noqa
...
@@ -6,6 +6,7 @@ from lassie.ifc import * # noqa
from
lassie.core
import
*
# noqa
from
lassie.core
import
*
# noqa
from
lassie.plot
import
*
# noqa
from
lassie.plot
import
*
# noqa
from
lassie.config
import
*
# noqa
from
lassie.config
import
*
# noqa
from
lassie.snuffling
import
*
# noqa
__version__
=
'0.2'
__version__
=
'0.2'
src/common.py
View file @
3af729e0
import
os.path
as
op
from
string
import
Template
from
collections
import
defaultdict
from
collections
import
defaultdict
from
pyrocko.guts
import
Object
,
String
from
pyrocko.gf
import
Earthmodel1D
guts_prefix
=
'lassie'
guts_prefix
=
'lassie'
def
data_file
(
fn
):
return
op
.
join
(
op
.
split
(
__file__
)[
0
],
'data'
,
fn
)
class
LassieError
(
Exception
):
class
LassieError
(
Exception
):
pass
pass
class
Earthmodel
(
Object
):
id
=
String
.
T
()
class
CakeEarthmodel
(
Earthmodel
):
earthmodel_1d
=
Earthmodel1D
.
T
()
def
grouped_by
(
l
,
key
):
def
grouped_by
(
l
,
key
):
d
=
defaultdict
(
list
)
d
=
defaultdict
(
list
)
for
x
in
l
:
for
x
in
l
:
...
@@ -14,6 +31,103 @@ def grouped_by(l, key):
...
@@ -14,6 +31,103 @@ def grouped_by(l, key):
return
d
return
d
def
xjoin
(
basepath
,
path
):
if
path
is
None
and
basepath
is
not
None
:
return
basepath
elif
op
.
isabs
(
path
)
or
basepath
is
None
:
return
path
else
:
return
op
.
join
(
basepath
,
path
)
def
xrelpath
(
path
,
start
):
if
op
.
isabs
(
path
):
return
path
else
:
return
op
.
relpath
(
path
,
start
)
class
Path
(
String
):
pass
class
HasPaths
(
Object
):
path_prefix
=
Path
.
T
(
optional
=
True
)
def
__init__
(
self
,
*
args
,
**
kwargs
):
Object
.
__init__
(
self
,
*
args
,
**
kwargs
)
self
.
_basepath
=
None
self
.
_parent_path_prefix
=
None
def
set_basepath
(
self
,
basepath
,
parent_path_prefix
=
None
):
self
.
_basepath
=
basepath
self
.
_parent_path_prefix
=
parent_path_prefix
for
(
prop
,
val
)
in
self
.
T
.
ipropvals
(
self
):
if
isinstance
(
val
,
HasPaths
):
val
.
set_basepath
(
basepath
,
self
.
path_prefix
or
self
.
_parent_path_prefix
)
def
get_basepath
(
self
):
assert
self
.
_basepath
is
not
None
return
self
.
_basepath
def
change_basepath
(
self
,
new_basepath
,
parent_path_prefix
=
None
):
assert
self
.
_basepath
is
not
None
self
.
_parent_path_prefix
=
parent_path_prefix
if
self
.
path_prefix
or
not
self
.
_parent_path_prefix
:
self
.
path_prefix
=
op
.
normpath
(
xjoin
(
xrelpath
(
self
.
_basepath
,
new_basepath
),
self
.
path_prefix
))
for
val
in
self
.
T
.
ivals
(
self
):
if
isinstance
(
val
,
HasPaths
):
val
.
change_basepath
(
new_basepath
,
self
.
path_prefix
or
self
.
_parent_path_prefix
)
self
.
_basepath
=
new_basepath
def
expand_path
(
self
,
path
,
extra
=
None
):
assert
self
.
_basepath
is
not
None
if
extra
is
None
:
def
extra
(
path
):
return
path
path_prefix
=
self
.
path_prefix
or
self
.
_parent_path_prefix
if
path
is
None
:
return
None
elif
isinstance
(
path
,
basestring
):
return
extra
(
op
.
normpath
(
xjoin
(
self
.
_basepath
,
xjoin
(
path_prefix
,
path
))))
else
:
return
[
extra
(
op
.
normpath
(
xjoin
(
self
.
_basepath
,
xjoin
(
path_prefix
,
p
))))
for
p
in
path
]
def
expand_template
(
template
,
d
):
try
:
return
Template
(
template
).
substitute
(
d
)
except
KeyError
as
e
:
raise
LassieError
(
'invalid placeholder "%s" in template: "%s"'
%
(
str
(
e
),
template
))
except
ValueError
:
raise
LassieError
(
'malformed placeholder in template: "%s"'
%
template
)
def
bark
():
import
subprocess
subprocess
.
call
([
'aplay'
,
data_file
(
'bark.wav'
)])
__all__
=
[
__all__
=
[
'LassieError'
,
'LassieError'
,
'Earthmodel'
,
'CakeEarthmodel'
,
'HasPaths'
,
'Path'
,
]
]
src/config.py
View file @
3af729e0
import
logging
import
logging
import
os.path
as
op
from
pyrocko.guts
import
Object
,
String
,
Float
,
Timestamp
,
List
,
Bool
,
load
from
pyrocko.guts
import
Object
,
String
,
Float
,
Timestamp
,
List
,
Bool
from
pyrocko
import
model
from
pyrocko
import
model
,
guts
from
pyrocko.fdsn
import
station
as
fs
from
pyrocko.gf
import
TPDef
from
lassie
import
receiver
,
ifc
,
grid
,
geo
from
lassie
import
receiver
,
ifc
,
grid
,
geo
from
lassie.common
import
Earthmodel
,
HasPaths
,
Path
,
LassieError
,
\
expand_template
guts_prefix
=
'lassie'
guts_prefix
=
'lassie'
logger
=
logging
.
getLogger
(
'lassie.config'
)
logger
=
logging
.
getLogger
(
'lassie.config'
)
class
Config
(
Object
):
class
Config
(
HasPaths
):
stations_path
=
String
.
T
(
stations_path
=
Path
.
T
(
optional
=
True
,
optional
=
True
,
help
=
'stations file in Pyrocko format'
)
help
=
'stations file in Pyrocko format'
)
stations_stationxml_path
=
Path
.
T
(
optional
=
True
,
help
=
'stations file in StationXML format'
)
receivers
=
List
.
T
(
receivers
=
List
.
T
(
receiver
.
Receiver
.
T
(),
receiver
.
Receiver
.
T
(),
help
=
'receiver coordinates if not read from file'
)
help
=
'receiver coordinates if not read from file'
)
data_paths
=
List
.
T
(
data_paths
=
List
.
T
(
String
.
T
(),
Path
.
T
(),
help
=
'list of directories paths to search for data'
)
help
=
'list of directories paths to search for data'
)
events_path
=
Path
.
T
(
optional
=
True
,
help
=
'limit processing to time windows around given events'
)
event_time_window_factor
=
Float
.
T
(
default
=
2.
,
help
=
'controls length of time windows for event-wise processing'
)
blacklist
=
List
.
T
(
blacklist
=
List
.
T
(
String
.
T
(),
String
.
T
(),
help
=
'codes in the form NET.STA.LOC of receivers to be excluded'
)
help
=
'codes in the form NET.STA.LOC of receivers to be excluded'
)
whitelist
=
List
.
T
(
String
.
T
(),
help
=
'codes in the form NET.STA.LOC of receivers to be included'
)
distance_max
=
Float
.
T
(
optional
=
True
,
help
=
'receiver maximum distance from grid'
)
tmin
=
Timestamp
.
T
(
tmin
=
Timestamp
.
T
(
optional
=
True
,
optional
=
True
,
help
=
'beginning of time interval to be processed'
)
help
=
'beginning of time interval to be processed'
)
...
@@ -36,9 +61,13 @@ class Config(Object):
...
@@ -36,9 +61,13 @@ class Config(Object):
optional
=
True
,
optional
=
True
,
help
=
'end of time interval to be processed'
)
help
=
'end of time interval to be processed'
)
detections
_path
=
String
.
T
(
run
_path
=
Path
.
T
(
optional
=
True
,
optional
=
True
,
help
=
'output file name for for detections'
)
help
=
'output is saved to this directory'
)
save_figures
=
Bool
.
T
(
default
=
False
,
help
=
'flag to activate saving of detection figures'
)
grid
=
grid
.
Grid
.
T
(
grid
=
grid
.
Grid
.
T
(
optional
=
True
,
optional
=
True
,
...
@@ -66,26 +95,99 @@ class Config(Object):
...
@@ -66,26 +95,99 @@ class Config(Object):
default
=
200.
,
default
=
200.
,
help
=
'threshold on detector function'
)
help
=
'threshold on detector function'
)
fill_incomplete_with_zeros
=
Bool
.
T
(
default
=
False
,
help
=
'fill incomplete trace time windows with zeros '
'(and let edge effects ruin your day)'
)
earthmodels
=
List
.
T
(
Earthmodel
.
T
(),
help
=
'list of earthmodels usable in shifters'
)
tabulated_phases
=
List
.
T
(
TPDef
.
T
(),
help
=
'list of tabulated phase definitions usable shifters'
)
cache_path
=
Path
.
T
(
default
=
'lassie_phases.cache'
,
help
=
'directory where lassie stores tabulated phases etc.'
)
def
__init__
(
self
,
*
args
,
**
kwargs
):
def
__init__
(
self
,
*
args
,
**
kwargs
):
Object
.
__init__
(
self
,
*
args
,
**
kwargs
)
Object
.
__init__
(
self
,
*
args
,
**
kwargs
)
self
.
_receivers
=
None
self
.
_receivers
=
None
self
.
_grid
=
None
self
.
_grid
=
None
self
.
_events
=
None
self
.
_config_name
=
'untitled'
def
set_config_name
(
self
,
config_name
):
self
.
_config_name
=
config_name
def
expand_path
(
self
,
path
):
def
extra
(
path
):
return
expand_template
(
path
,
dict
(
config_name
=
self
.
_config_name
))
return
HasPaths
.
expand_path
(
self
,
path
,
extra
=
extra
)
def
get_events_path
(
self
):
run_path
=
self
.
expand_path
(
self
.
run_path
)
return
op
.
join
(
run_path
,
'events.list'
)
def
get_ifm_dir_path
(
self
):
run_path
=
self
.
expand_path
(
self
.
run_path
)