Skip to content

Commit

Permalink
Dev (#1)
Browse files Browse the repository at this point in the history
* Initial release
  • Loading branch information
miili authored Jul 11, 2023
1 parent 6676737 commit a9f9fc1
Show file tree
Hide file tree
Showing 51 changed files with 5,061 additions and 427 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Build and test

on: [push]

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11"]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
cache: "pip" # caching pip dependencies
cache-dependency-path: "**/pyproject.toml"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install .[dev]
- name: Test with pytest
run: |
pytest
2 changes: 1 addition & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: pre-commit
name: linting

on:
pull_request:
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,8 @@ cython_debug/
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
.vscode

# Data files
*.mseed

test/data/
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ repos:
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/psf/black
rev: 23.1.0
rev: 23.3.0
hooks:
- id: black
# It is recommended to specify the latest version of Python
# supported by your project here, or alternatively use
# pre-commit's default_language_version, see
# https://pre-commit.com/#top_level-default_language_version
language_version: python3.9
# language_version: python3.9
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: "v0.0.241"
rev: "v0.0.275"
hooks:
- id: ruff
75 changes: 75 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Lassie

*The friendly earthquake detector*

![Python 3.10+](https://img.shields.io/badge/python-3.10-blue.svg)
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://pre-commit.com/)
<!-- [![PyPI](https://img.shields.io/pypi/v/lassie)](https://pypi.org/project/lassie/) -->

Lassie is an earthquake detector based on stacking and migration method. It combines neural network phase picks with an iterative octree localisation approach.

Key features are of the tools are:

* Phase detection using SeisBench
* Efficient and accurate Octree localisation approach
* Extraction of event features
* Local magnitudes
* Ground motion attributes
* Determination of station corrections

## Installation

```sh
git clone https://github.com/miili/lassie-v2
cd lassie-v2
pip3 install .
```

## Project Initialisation

Initialize a new project in a fresh directory.

```sh
lassie new project-dir/
```

Edit the `search.json`

Start the detection

```sh
lassie run search.json
```

## Packaging

The simplest and recommended way of installing from source:

### Development

Local development through pip.

```sh
cd lightguide
pip3 install .[dev]
```

The project utilizes pre-commit for clean commits, install the hooks via:

```sh
pip install pre-commit
pre-commit install
```

## Citation

Please cite lassie as:

> TBD
## License

Contribution and merge requests by the community are welcome!

Lassie-v@ was written by Marius Paul Isken and is licensed under the GNU GENERAL PUBLIC LICENSE v3.
206 changes: 192 additions & 14 deletions lassie/apps/lassie.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,208 @@
from __future__ import annotations

import argparse
import asyncio
import logging
from datetime import datetime
from pathlib import Path

from lassie.config import Config
import nest_asyncio
from pkg_resources import get_distribution

from lassie.console import console
from lassie.images import ImageFunctions
from lassie.images.phase_net import PhaseNet
from lassie.models import Stations
from lassie.search import SquirrelSearch
from lassie.server import WebServer
from lassie.station_corrections import StationCorrections
from lassie.tracers import RayTracers
from lassie.tracers.cake import CakeTracer
from lassie.utils import ANSI, setup_rich_logging

nest_asyncio.apply()

logger = logging.getLogger(__name__)

def main():

def main() -> None:
parser = argparse.ArgumentParser(
prog="lassie",
description="The friendly earthquake detector - V2",
)
parser.add_argument(
"--verbose",
"-v",
action="count",
default=0,
help="increase verbosity of the log messages, default level is INFO",
)
parser.add_argument(
"--version",
action="version",
version=get_distribution("lassie").version,
help="show version and exit",
)

subparsers = parser.add_subparsers(title="commands", required=True, dest="command")
subparsers.add_parser("dump-config", help="Print a new config to terminal.")

run = subparsers.add_parser("run", help="Start a run.")
run = subparsers.add_parser(
"run",
help="start a new detection run",
description="detect, localize and characterize earthquakes in a dataset",
)
run.add_argument("config", type=Path, help="path to config file")
run.add_argument(
"config",
type=Path,
help="Path to config file.",
"--force",
action="store_true",
default=False,
help="backup old rundir and create a new",
)

continue_run = subparsers.add_parser(
"continue",
help="continue an aborted run",
description="continue a run from an existing rundir",
)
continue_run.add_argument("rundir", type=Path, help="existing runding to continue")

features = subparsers.add_parser(
"feature-extraction",
help="extract features from an existing run",
description="modify the search.json for re-evaluation of the event's features",
)
features.add_argument("rundir", type=Path, help="path of existing run")

station_corrections = subparsers.add_parser(
"station-corrections",
help="analyse station corrections from existing run",
description="analyze and plot station corrections from a finished run",
)
station_corrections.add_argument(
"--plot",
action="store_true",
default=False,
help="plot station correction results and save to rundir",
)
station_corrections.add_argument("rundir", type=Path, help="path of existing run")

serve = subparsers.add_parser(
"serve",
help="serve results from an existing run",
description="start a webserver and serve detections and results from a run",
)
serve.add_argument("rundir", type=Path, help="rundir to serve")

new = subparsers.add_parser(
"new",
help="initialize a new project",
)
new.add_argument("folder", type=Path, help="folder to initialize project in")

dump_schemas = subparsers.add_parser(
"dump-schemas",
help="dump models to json-schema (development)",
)
dump_schemas.add_argument("folder", type=Path, help="folder to dump schemas to")

args = parser.parse_args()
if args.command == "dump-config":
config = Config.construct()
print(config.json(indent=2))
return
setup_rich_logging(level=logging.INFO - args.verbose * 10)

if args.command == "new":
folder: Path = args.folder
if folder.exists():
raise FileExistsError(f"Folder {folder} already exists")
folder.mkdir()

pyrocko_stations = folder / "pyrocko-stations.yaml"
pyrocko_stations.touch()

config = SquirrelSearch(
ray_tracers=RayTracers(root=[CakeTracer()]),
image_functions=ImageFunctions(
root=[PhaseNet(phase_map={"P": "cake:P", "S": "cake:S"})]
),
stations=Stations(pyrocko_station_yamls=[pyrocko_stations]),
waveform_data=[Path("/data/")],
time_span=(
datetime.fromisoformat("2023-04-11T00:00:00+00:00"),
datetime.fromisoformat("2023-04-18T00:00:00+00:00"),
),
)

config_file = folder / "config.json"
config_file.write_text(config.model_dump_json(by_alias=False, indent=2))
logger.info("initialized new project in folder %s", folder)
logger.info(
"start detecting with:\n\t%slassie run config.json%s", ANSI.Bold, ANSI.Reset
)

elif args.command == "run":
...
else:
raise ValueError("No command provided")
search = SquirrelSearch.from_config(args.config)
search.init_rundir(force=args.force)

webserver = WebServer(search)

async def _run() -> None:
http = asyncio.create_task(webserver.start())
await search.scan_squirrel()
await http

asyncio.run(_run())

elif args.command == "continue":
search = SquirrelSearch.load_rundir(args.rundir)
if search.progress.time_progress:
console.rule(f"Continuing search from {search.progress.time_progress}")
else:
console.rule("Starting search from scratch")

webserver = WebServer(search)

async def _run() -> None:
http = asyncio.create_task(webserver.start())
await search.scan_squirrel()
await http

asyncio.run(_run())

elif args.command == "feature-extraction":
search = SquirrelSearch.load_rundir(args.rundir)

async def extract() -> None:
for detection in search._detections.detections:
await search.add_features(detection)

asyncio.run(extract())

elif args.command == "station-corrections":
rundir = Path(args.rundir)
station_corrections = StationCorrections(rundir=rundir)
if args.plot:
station_corrections.save_plots(rundir / "station_corrections")
station_corrections.save_csv(filename=rundir / "station_corrections_stats.csv")

elif args.command == "serve":
search = SquirrelSearch.load_rundir(args.rundir)
webserver = WebServer(search)

loop = asyncio.get_event_loop()
loop.create_task(webserver.start())
loop.run_forever()

elif args.command == "dump-schemas":
from lassie.models.detection import EventDetections

if not args.folder.exists():
raise EnvironmentError(f"folder {args.folder} does not exist")

file = args.folder / "search.schema.json"
print(f"writing JSON schemas to {args.folder}")
file.write_text(SquirrelSearch.model_json_schema(indent=2))

file = args.folder / "detections.schema.json"
file.write_text(EventDetections.model_json_schema(indent=2))


if __name__ == "__main__":
main()
Loading

0 comments on commit a9f9fc1

Please sign in to comment.