diff --git a/kubeflow/rsync.yaml b/kubeflow/rsync.yaml new file mode 100644 index 0000000..10d8a0b --- /dev/null +++ b/kubeflow/rsync.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Pod +metadata: + name: dataaccess52 +spec: + containers: + - name: alpine + image: zhuwq0/waveform-env:1.1 + command: ['sleep', 'infinity'] + volumeMounts: + - name: mypvc + mountPath: /data + volumes: + - name: mypvc + persistentVolumeClaim: + claimName: quakeflow-w8gfg-data-volume-52 diff --git a/kubeflow/workflow_debug.ipynb b/kubeflow/workflow_debug.ipynb new file mode 100644 index 0000000..2abbafc --- /dev/null +++ b/kubeflow/workflow_debug.ipynb @@ -0,0 +1,4943 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Earthquake Detection Workflow using QuakeFlow\n", + "\n", + "## Outline\n", + "\n", + "Here we show an example of the current modules in QuakeFlow\n", + "\n", + "1. Download data using Obpsy:\n", + "\n", + " [FDSN web service client for ObsPy](https://docs.obspy.org/packages/obspy.clients.fdsn.html#module-obspy.clients.fdsn)\n", + " \n", + " [Mass Downloader for FDSN Compliant Web Services](https://docs.obspy.org/packages/autogen/obspy.clients.fdsn.mass_downloader.html#module-obspy.clients.fdsn.mass_downloader)\n", + "\n", + "2. PhaseNet for picking P/S phases\n", + "\n", + " Find more details in [PhaseNet github page](https://wayneweiqiang.github.io/PhaseNet/)\n", + "\n", + "3. GaMMA for associating picking and estimate approximate location and magnitude\n", + "\n", + " Find more details in [GaMMA github page](https://wayneweiqiang.github.io/GaMMA/)\n", + " \n", + "4. Earthquake location, magnitude estimation, etc.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 0. Install [miniconda](https://docs.conda.io/en/latest/miniconda.html) and download packages" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "execution": { + "iopub.execute_input": "2021-07-23T07:24:29.845680Z", + "iopub.status.busy": "2021-07-23T07:24:29.845272Z", + "iopub.status.idle": "2021-07-23T07:24:29.922435Z", + "shell.execute_reply": "2021-07-23T07:24:29.917867Z", + "shell.execute_reply.started": "2021-07-23T07:24:29.845649Z" + }, + "tags": [] + }, + "source": [ + "```\n", + "git clone https://github.com/wayneweiqiang/PhaseNet.git\n", + "git clone https://github.com/wayneweiqiang/GaMMA.git\n", + "conda env update -f=env.yml -n base\n", + "```\n", + "\n", + "**Second option: install to quakeflow environment, but need to select jupyter notebook kernel to quakeflow**\n", + "```\n", + "conda env create -f=env.yml -n quakeflow\n", + "python -m ipykernel install --user --name=quakeflow\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:42.837909Z", + "iopub.status.busy": "2022-08-11T15:42:42.837825Z", + "iopub.status.idle": "2022-08-11T15:42:43.073297Z", + "shell.execute_reply": "2022-08-11T15:42:43.073016Z", + "shell.execute_reply.started": "2022-08-11T15:42:42.837882Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "import warnings\n", + "\n", + "import kfp\n", + "import kfp.components as comp\n", + "import kfp.dsl as dsl\n", + "from kfp.components import InputPath, OutputPath\n", + "\n", + "warnings.filterwarnings(\"ignore\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Set configurations" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T20:03:24.188176Z", + "iopub.status.busy": "2022-08-11T20:03:24.187935Z", + "iopub.status.idle": "2022-08-11T20:03:24.196474Z", + "shell.execute_reply": "2022-08-11T20:03:24.196164Z", + "shell.execute_reply.started": "2022-08-11T20:03:24.188158Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "import os\n", + "\n", + "import matplotlib\n", + "import matplotlib.pyplot as plt\n", + "\n", + "matplotlib.use(\"agg\")\n", + "%matplotlib inline\n", + "\n", + "region_name = \"Demo\"\n", + "# region_name = \"Ridgecrest\"\n", + "# region_name = \"SaltonSea\"\n", + "# region_name = \"Ridgecrest\"\n", + "# region_name = \"SanSimeon\"\n", + "# region_name = \"Italy\"\n", + "# region_name = \"PNSN\"\n", + "# region_name = \"Hawaii3\"\n", + "# region_name = \"Hawaii4\"\n", + "# region_name = \"Hawaii_Loa\"\n", + "# region_name = \"SierraNegra\"\n", + "# region_name = \"PuertoRico\"\n", + "# region_name = \"SmithValley\"\n", + "# region_name = \"Antilles\"\n", + "# region_name = \"LongValley\"\n", + "\n", + "dir_name = region_name\n", + "if not os.path.exists(dir_name):\n", + " os.mkdir(dir_name)\n", + "root_dir = lambda x: os.path.join(dir_name, x)\n", + "\n", + "run_local = True" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T20:03:24.601595Z", + "iopub.status.busy": "2022-08-11T20:03:24.601484Z", + "iopub.status.idle": "2022-08-11T20:03:24.613499Z", + "shell.execute_reply": "2022-08-11T20:03:24.613194Z", + "shell.execute_reply.started": "2022-08-11T20:03:24.601583Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def set_config(\n", + " region_name,\n", + " index_json: OutputPath(\"json\"),\n", + " config_json: OutputPath(\"json\"),\n", + " datetime_json: OutputPath(\"json\"),\n", + " num_parallel: int = 1,\n", + " bucket_name: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + ") -> list:\n", + "\n", + " import datetime\n", + " import json\n", + " import os\n", + " import pickle\n", + "\n", + " import numpy as np\n", + " import obspy\n", + "\n", + " degree2km = np.pi * 6371 / 180\n", + "\n", + " if region_name == \"Demo\":\n", + " center = (-117.504, 35.705)\n", + " horizontal_degree = 1.0\n", + " vertical_degree = 1.0\n", + " starttime = obspy.UTCDateTime(\"2019-07-04T17\")\n", + " endtime = obspy.UTCDateTime(\"2019-07-04T19\")\n", + " client = \"SCEDC\"\n", + " network_list = [\"CI\"]\n", + " channel_list = \"HH*,BH*,EH*,HN*\"\n", + "\n", + " if region_name == \"Ridgecrest\":\n", + " center = (-117.504, 35.705)\n", + " horizontal_degree = 1.0\n", + " vertical_degree = 1.0\n", + " starttime = obspy.UTCDateTime(\"2019-07-04T00\")\n", + " endtime = obspy.UTCDateTime(\"2019-07-10T00\")\n", + " client = \"SCEDC\"\n", + " network_list = [\"CI\"]\n", + " channel_list = \"HH*,BH*,EH*,HN*\"\n", + "\n", + " if region_name == \"Hawaii\":\n", + " center = (-155.32, 19.39)\n", + " horizontal_degree = 2.0\n", + " vertical_degree = 2.0\n", + " starttime = obspy.UTCDateTime(\"2018-01-01T00\")\n", + " endtime = obspy.UTCDateTime(\"2022-08-12T00\")\n", + " client = \"IRIS\"\n", + " network_list = [\"HV\", \"PT\"]\n", + " channel_list = \"HH*,BH*,EH*,HN*\"\n", + "\n", + " if region_name == \"Hawaii2\":\n", + " center = (-155.32, 19.39)\n", + " horizontal_degree = 2.0\n", + " vertical_degree = 2.0\n", + " starttime = obspy.UTCDateTime(\"2022-08-01T00\")\n", + " endtime = obspy.UTCDateTime(\"2022-08-16T00\")\n", + " client = \"IRIS\"\n", + " network_list = [\"HV\", \"PT\"]\n", + " channel_list = \"HH*,BH*,EH*,HN*\"\n", + "\n", + " if region_name == \"Hawaii3\":\n", + " center = (-155.32, 19.39)\n", + " horizontal_degree = 2.0\n", + " vertical_degree = 2.0\n", + " # starttime = obspy.UTCDateTime(\"2010-01-01T00\")\n", + " starttime = obspy.UTCDateTime(\"2022-08-01T00\")\n", + " endtime = obspy.UTCDateTime(\"2022-11-09T00\")\n", + " client = \"IRIS\"\n", + " network_list = [\"HV\"]\n", + " channel_list = \"HH*,BH*,EH*\"\n", + "\n", + " if region_name == \"Hawaii4\":\n", + " center = (-155.32, 19.39)\n", + " horizontal_degree = 2.0\n", + " vertical_degree = 2.0\n", + " starttime = obspy.UTCDateTime(\"2010-01-01T00\")\n", + " # starttime = obspy.UTCDateTime(\"2022-08-01T00\")\n", + " endtime = obspy.UTCDateTime(\"2022-11-09T00\")\n", + " client = \"IRIS\"\n", + " network_list = [\"HV\"]\n", + " channel_list = \"HH*,BH*,EH*\"\n", + "\n", + " if region_name == \"Hawaii_Loa\":\n", + " center = (-155.602737, 19.451827)\n", + " horizontal_degree = 0.3\n", + " vertical_degree = 0.3\n", + " starttime = obspy.UTCDateTime(\"2010-01-01T00\")\n", + " # starttime = obspy.UTCDateTime(\"2022-08-01T00\")\n", + " endtime = obspy.UTCDateTime(\"2022-11-09T00\")\n", + " client = \"IRIS\"\n", + " network_list = [\"HV\"]\n", + " channel_list = \"HH*,BH*,EH*\"\n", + "\n", + " if region_name == \"PuertoRico\":\n", + " center = (-66.5, 18)\n", + " horizontal_degree = 3.0\n", + " vertical_degree = 2.0\n", + " starttime = obspy.UTCDateTime(\"2018-05-01T00\")\n", + " endtime = obspy.UTCDateTime(\"2021-11-01T00\")\n", + " client = \"IRIS\"\n", + " network_list = [\"*\"]\n", + " channel_list = \"HH*,BH*,HN*\"\n", + "\n", + " if region_name == \"SaltonSea\":\n", + " center = (-115.53, 32.98)\n", + " horizontal_degree = 1.0\n", + " vertical_degree = 1.0\n", + " starttime = obspy.UTCDateTime(\"2020-10-01T00\")\n", + " endtime = obspy.UTCDateTime(\"2020-10-01T02\")\n", + " client = \"SCEDC\"\n", + " network_list = [\"CI\"]\n", + " channel_list = \"HH*,BH*,EH*,HN*\"\n", + "\n", + " if region_name == \"2003SanSimeon\":\n", + " center = (-121.101, 35.701)\n", + " horizontal_degree = 1.0\n", + " vertical_degree = 1.0\n", + " starttime = obspy.UTCDateTime(\"2003-12-22T00\")\n", + " endtime = obspy.UTCDateTime(\"2003-12-24T00\")\n", + " client = \"NCEDC\"\n", + " network_list = [\"*\"]\n", + " channel_list = \"HH*,BH*,EH*,HN*\"\n", + "\n", + " if region_name == \"Italy\":\n", + " center = (13.188, 42.723)\n", + " horizontal_degree = 1.0\n", + " vertical_degree = 1.0\n", + " starttime = obspy.UTCDateTime(\"2016-08-24T00\")\n", + " endtime = obspy.UTCDateTime(\"2016-08-26T00\")\n", + " client = \"INGV\"\n", + " network_list = [\"*\"]\n", + " channel_list = \"HH*,BH*,EH*,HN*\"\n", + "\n", + " if region_name == \"SmithValley\":\n", + " center = (-119.5, 38.51)\n", + " horizontal_degree = 1.0\n", + " vertical_degree = 1.0\n", + " starttime = obspy.UTCDateTime(\"2021-07-08T00:00\")\n", + " endtime = obspy.UTCDateTime(\"2021-07-16T00:00\")\n", + " client = \"NCEDC\"\n", + " network_list = [\"*\"]\n", + " channel_list = \"HH*,BH*,EH*,HN*\"\n", + "\n", + " if region_name == \"Antilles\":\n", + " center = (-61.14867, 14.79683)\n", + " horizontal_degree = 0.2\n", + " vertical_degree = 0.2\n", + " starttime = obspy.UTCDateTime(\"2021-04-10T00\")\n", + " endtime = obspy.UTCDateTime(\"2021-04-15T00\")\n", + " client = \"RESIF\"\n", + " network_list = [\"*\"]\n", + " channel_list = \"HH*,BH*,EH*,HN*\"\n", + "\n", + " if region_name == \"LongValley\":\n", + " # center = (-118.8, 37.6+0.3)\n", + " # horizontal_degree = 3.0\n", + " # vertical_degree = 3.0\n", + " center = (-118.8 - 0.1, 37.6)\n", + " horizontal_degree = 1.5\n", + " vertical_degree = 1.5\n", + " starttime = obspy.UTCDateTime(\"2020-01-01T00\")\n", + " endtime = obspy.UTCDateTime(\"2022-08-11T00\")\n", + " client = \"NCEDC\"\n", + " network_list = [\"*\"]\n", + " channel_list = \"HH*,EH*\"\n", + "\n", + " if region_name == \"SierraNegra\":\n", + " center = (-91.13, -0.81)\n", + " horizontal_degree = 1.5\n", + " vertical_degree = 1.5\n", + " starttime = obspy.UTCDateTime(\"2009-07-22T00\")\n", + " endtime = obspy.UTCDateTime(\"2011-06-20T00\")\n", + " client = \"IRIS\"\n", + " network_list = [\"*\"]\n", + " channel_list = \"BH*,HH*,EH*\"\n", + "\n", + " ####### save config ########\n", + " config = {}\n", + " config[\"region\"] = region_name\n", + " config[\"center\"] = center\n", + " config[\"xlim_degree\"] = [\n", + " center[0] - horizontal_degree / 2,\n", + " center[0] + horizontal_degree / 2,\n", + " ]\n", + " config[\"ylim_degree\"] = [\n", + " center[1] - vertical_degree / 2,\n", + " center[1] + vertical_degree / 2,\n", + " ]\n", + " config[\"min_longitude\"] = center[0] - horizontal_degree / 2\n", + " config[\"max_longitude\"] = center[0] + horizontal_degree / 2\n", + " config[\"min_latitude\"] = center[1] - vertical_degree / 2\n", + " config[\"max_latitude\"] = center[1] + vertical_degree / 2\n", + " config[\"degree2km\"] = degree2km\n", + " config[\"starttime\"] = starttime.datetime.isoformat(timespec=\"milliseconds\")\n", + " config[\"endtime\"] = endtime.datetime.isoformat(timespec=\"milliseconds\")\n", + " config[\"networks\"] = network_list\n", + " config[\"channels\"] = channel_list\n", + " config[\"client\"] = client\n", + "\n", + " ## PhaseNet\n", + " config[\"phasenet\"] = {}\n", + " ## GaMMA\n", + " config[\"gamma\"] = {}\n", + " ## HypoDD\n", + " config[\"hypodd\"] = {\"MAXEVENT\": 1e4}\n", + "\n", + " with open(config_json, \"w\") as fp:\n", + " json.dump(config, fp, indent=2)\n", + "\n", + " print(json.dumps(config, indent=4))\n", + "\n", + " ####### set paraell for cloud ########\n", + " ## split data by hours\n", + " # one_day = datetime.timedelta(days=1)\n", + " one_hour = datetime.timedelta(hours=1)\n", + " starttimes = []\n", + " tmp_start = starttime\n", + " while tmp_start < endtime:\n", + " starttimes.append(tmp_start.datetime.isoformat(timespec=\"milliseconds\"))\n", + " tmp_start += one_hour\n", + " with open(datetime_json, \"w\") as fp:\n", + " json.dump(\n", + " {\"starttimes\": starttimes, \"interval\": one_hour.total_seconds()},\n", + " fp,\n", + " indent=2,\n", + " )\n", + "\n", + " ## split stattimes into N parallel process\n", + " if num_parallel == 0:\n", + " num_parallel = min(60, int((len(starttimes) - 1) // 6 + 1))\n", + " # num_parallel = min(30, int((len(starttimes)-1)//6+1))\n", + " # num_parallel = min(24, len(starttimes))\n", + " idx = [x.tolist() for x in np.array_split(np.arange(len(starttimes)), num_parallel)]\n", + "\n", + " with open(index_json, \"w\") as fp:\n", + " json.dump(idx, fp, indent=2)\n", + "\n", + " ## upload to s3 bucket\n", + " try:\n", + " from minio import Minio\n", + "\n", + " minioClient = Minio(s3_url, access_key=\"minio\", secret_key=\"minio123\", secure=secure)\n", + " if not minioClient.bucket_exists(bucket_name):\n", + " minioClient.make_bucket(bucket_name)\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/config.json\",\n", + " config_json,\n", + " )\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/datetime.json\",\n", + " datetime_json,\n", + " )\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/index.json\",\n", + " index_json,\n", + " )\n", + "\n", + " except Exception as err:\n", + " print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " pass\n", + "\n", + " return list(range(num_parallel))" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T20:03:25.108832Z", + "iopub.status.busy": "2022-08-11T20:03:25.108714Z", + "iopub.status.idle": "2022-08-11T20:03:31.275226Z", + "shell.execute_reply": "2022-08-11T20:03:31.274848Z", + "shell.execute_reply.started": "2022-08-11T20:03:25.108820Z" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"region\": \"Demo\",\n", + " \"center\": [\n", + " -117.504,\n", + " 35.705\n", + " ],\n", + " \"xlim_degree\": [\n", + " -118.004,\n", + " -117.004\n", + " ],\n", + " \"ylim_degree\": [\n", + " 35.205,\n", + " 36.205\n", + " ],\n", + " \"min_longitude\": -118.004,\n", + " \"max_longitude\": -117.004,\n", + " \"min_latitude\": 35.205,\n", + " \"max_latitude\": 36.205,\n", + " \"degree2km\": 111.19492664455873,\n", + " \"starttime\": \"2019-07-04T17:00:00.000\",\n", + " \"endtime\": \"2019-07-04T19:00:00.000\",\n", + " \"networks\": [\n", + " \"CI\"\n", + " ],\n", + " \"channels\": \"HH*,BH*,EH*,HN*\",\n", + " \"client\": \"SCEDC\",\n", + " \"phasenet\": {},\n", + " \"gamma\": {},\n", + " \"hypodd\": {\n", + " \"MAXEVENT\": 10000.0\n", + " }\n", + "}\n", + "ERROR: can not access minio service! \n", + "HTTPSConnectionPool(host='minio-service', port=9000): Max retries exceeded with url: /catalogs?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))\n" + ] + } + ], + "source": [ + "if run_local:\n", + " idx = set_config(\n", + " region_name,\n", + " root_dir(\"index.json\"),\n", + " root_dir(\"config.json\"),\n", + " root_dir(\"datetimes.json\"),\n", + " num_parallel=1,\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T20:03:31.275970Z", + "iopub.status.busy": "2022-08-11T20:03:31.275892Z", + "iopub.status.idle": "2022-08-11T20:03:31.308479Z", + "shell.execute_reply": "2022-08-11T20:03:31.308169Z", + "shell.execute_reply.started": "2022-08-11T20:03:31.275959Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "config_op = comp.func_to_container_op(\n", + " set_config,\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\"numpy\", \"obspy\", \"minio\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Download events of the standard catalog\n", + "\n", + "This catalog is not used by QuakeFolow. It is only used for comparing detection results." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T20:03:31.309035Z", + "iopub.status.busy": "2022-08-11T20:03:31.308926Z", + "iopub.status.idle": "2022-08-11T20:03:31.314738Z", + "shell.execute_reply": "2022-08-11T20:03:31.314519Z", + "shell.execute_reply.started": "2022-08-11T20:03:31.309023Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def download_events(\n", + " config_json: InputPath(\"json\"),\n", + " standard_catalog: OutputPath(str),\n", + " bucket_name: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + "):\n", + "\n", + " import json\n", + " import os\n", + " import pickle\n", + " from collections import defaultdict\n", + "\n", + " import matplotlib\n", + " import matplotlib.pyplot as plt\n", + " import obspy\n", + " import pandas as pd\n", + " from obspy.clients.fdsn import Client\n", + "\n", + " # matplotlib.use(\"agg\")\n", + " # %matplotlib inline\n", + "\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " ####### IRIS catalog ########\n", + " try:\n", + " events = Client(config[\"client\"]).get_events(\n", + " starttime=config[\"starttime\"],\n", + " endtime=config[\"endtime\"],\n", + " minlongitude=config[\"xlim_degree\"][0],\n", + " maxlongitude=config[\"xlim_degree\"][1],\n", + " minlatitude=config[\"ylim_degree\"][0],\n", + " maxlatitude=config[\"ylim_degree\"][1],\n", + " # filename='events.xml',\n", + " )\n", + " except:\n", + " events = Client(\"iris\").get_events(\n", + " starttime=config[\"starttime\"],\n", + " endtime=config[\"endtime\"],\n", + " minlongitude=config[\"xlim_degree\"][0],\n", + " maxlongitude=config[\"xlim_degree\"][1],\n", + " minlatitude=config[\"ylim_degree\"][0],\n", + " maxlatitude=config[\"ylim_degree\"][1],\n", + " # filename='events.xml',\n", + " )\n", + "\n", + " # events = obspy.read_events('events.xml')\n", + " print(f\"Number of events: {len(events)}\")\n", + " # events.plot('local', outfile=\"events.png\")\n", + " # events.plot('local')\n", + "\n", + " ####### Save catalog ########\n", + " catalog = defaultdict(list)\n", + " for event in events:\n", + " if len(event.magnitudes) > 0:\n", + " catalog[\"time\"].append(event.origins[0].time.datetime)\n", + " catalog[\"magnitude\"].append(event.magnitudes[0].mag)\n", + " catalog[\"longitude\"].append(event.origins[0].longitude)\n", + " catalog[\"latitude\"].append(event.origins[0].latitude)\n", + " catalog[\"depth(m)\"].append(event.origins[0].depth)\n", + " catalog = pd.DataFrame.from_dict(catalog).sort_values([\"time\"])\n", + " catalog.to_csv(\n", + " standard_catalog,\n", + " # sep=\"\\t\",\n", + " index=False,\n", + " float_format=\"%.3f\",\n", + " date_format=\"%Y-%m-%dT%H:%M:%S.%f\",\n", + " columns=[\"time\", \"magnitude\", \"longitude\", \"latitude\", \"depth(m)\"],\n", + " )\n", + "\n", + " ## upload to s3 bucket\n", + " try:\n", + " from minio import Minio\n", + "\n", + " minioClient = Minio(s3_url, access_key=\"minio\", secret_key=\"minio123\", secure=secure)\n", + " if not minioClient.bucket_exists(bucket_name):\n", + " minioClient.make_bucket(bucket_name)\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/standard_catalog.csv\",\n", + " standard_catalog,\n", + " )\n", + "\n", + " except Exception as err:\n", + " print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " pass\n", + "\n", + " ####### Plot catalog ########\n", + " plt.figure()\n", + " plt.plot(catalog[\"longitude\"], catalog[\"latitude\"], \".\", markersize=1)\n", + " plt.xlabel(\"Longitude\")\n", + " plt.ylabel(\"Latitude\")\n", + " plt.axis(\"scaled\")\n", + " plt.xlim(config[\"xlim_degree\"])\n", + " plt.ylim(config[\"ylim_degree\"])\n", + " # plt.savefig(os.path.join(data_path, \"events_loc.png\"))\n", + " plt.show()\n", + "\n", + " plt.figure()\n", + " plt.plot_date(catalog[\"time\"], catalog[\"magnitude\"], \".\", markersize=1)\n", + " plt.gcf().autofmt_xdate()\n", + " plt.ylabel(\"Magnitude\")\n", + " plt.title(f\"Number of events: {len(events)}\")\n", + " # plt.savefig(os.path.join(data_path, \"events_mag_time.png\"))\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T20:03:31.315388Z", + "iopub.status.busy": "2022-08-11T20:03:31.315288Z", + "iopub.status.idle": "2022-08-11T20:04:10.274910Z", + "shell.execute_reply": "2022-08-11T20:04:10.274498Z", + "shell.execute_reply.started": "2022-08-11T20:03:31.315377Z" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of events: 252\n", + "ERROR: can not access minio service! \n", + "HTTPSConnectionPool(host='minio-service', port=9000): Max retries exceeded with url: /catalogs?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "if run_local:\n", + " download_events(root_dir(\"config.json\"), root_dir(\"standard_catalog.csv\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T20:04:10.275411Z", + "iopub.status.busy": "2022-08-11T20:04:10.275332Z", + "iopub.status.idle": "2022-08-11T20:04:10.287343Z", + "shell.execute_reply": "2022-08-11T20:04:10.287063Z", + "shell.execute_reply.started": "2022-08-11T20:04:10.275399Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "download_events_op = comp.func_to_container_op(\n", + " download_events,\n", + " # base_image='zhuwq0/quakeflow-env:latest',\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\n", + " \"obspy\",\n", + " \"pandas\",\n", + " \"matplotlib\",\n", + " \"minio\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Download stations" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T20:04:10.288008Z", + "iopub.status.busy": "2022-08-11T20:04:10.287927Z", + "iopub.status.idle": "2022-08-11T20:04:10.294533Z", + "shell.execute_reply": "2022-08-11T20:04:10.294282Z", + "shell.execute_reply.started": "2022-08-11T20:04:10.287997Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def download_stations(\n", + " config_json: InputPath(\"json\"),\n", + " station_json: OutputPath(\"json\"),\n", + " station_pkl: OutputPath(\"pickle\"),\n", + " bucket_name: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + "):\n", + "\n", + " import json\n", + " import os\n", + " import pickle\n", + " from collections import defaultdict\n", + "\n", + " import matplotlib\n", + " import matplotlib.pyplot as plt\n", + " import obspy\n", + " import pandas as pd\n", + " from obspy.clients.fdsn import Client\n", + "\n", + " # matplotlib.use(\"agg\")\n", + " # %matplotlib inline\n", + "\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " print(\"Network:\", \",\".join(config[\"networks\"]))\n", + "\n", + " ####### Download stations ########\n", + " stations = Client(config[\"client\"]).get_stations(\n", + " network=\",\".join(config[\"networks\"]),\n", + " station=\"*\",\n", + " starttime=config[\"starttime\"],\n", + " endtime=config[\"endtime\"],\n", + " minlongitude=config[\"xlim_degree\"][0],\n", + " maxlongitude=config[\"xlim_degree\"][1],\n", + " minlatitude=config[\"ylim_degree\"][0],\n", + " maxlatitude=config[\"ylim_degree\"][1],\n", + " channel=config[\"channels\"],\n", + " level=\"response\",\n", + " # filename=\"stations.xml\"\n", + " )\n", + "\n", + " # stations = obspy.read_inventory(\"stations.xml\")\n", + " print(\"Number of stations: {}\".format(sum([len(x) for x in stations])))\n", + " # stations.plot('local', outfile=\"stations.png\")\n", + " # stations.plot('local')\n", + "\n", + " ####### Save stations ########\n", + " station_locs = defaultdict(dict)\n", + " for network in stations:\n", + " for station in network:\n", + " for chn in station:\n", + " sid = f\"{network.code}.{station.code}.{chn.location_code}.{chn.code[:-1]}\"\n", + " if sid in station_locs:\n", + " if chn.code[-1] not in station_locs[sid][\"component\"]:\n", + " station_locs[sid][\"component\"].append(chn.code[-1])\n", + " station_locs[sid][\"response\"].append(round(chn.response.instrument_sensitivity.value, 2))\n", + " else:\n", + " tmp_dict = {\n", + " \"longitude\": chn.longitude,\n", + " \"latitude\": chn.latitude,\n", + " \"elevation(m)\": chn.elevation,\n", + " \"component\": [\n", + " chn.code[-1],\n", + " ],\n", + " \"response\": [\n", + " round(chn.response.instrument_sensitivity.value, 2),\n", + " ],\n", + " \"unit\": chn.response.instrument_sensitivity.input_units.lower(),\n", + " }\n", + " station_locs[sid] = tmp_dict\n", + "\n", + " with open(station_json, \"w\") as fp:\n", + " json.dump(station_locs, fp, indent=2)\n", + "\n", + " with open(station_pkl, \"wb\") as fp:\n", + " pickle.dump(stations, fp)\n", + "\n", + " ## upload to s3 bucket\n", + " try:\n", + " from minio import Minio\n", + "\n", + " minioClient = Minio(s3_url, access_key=\"minio\", secret_key=\"minio123\", secure=secure)\n", + " if not minioClient.bucket_exists(bucket_name):\n", + " minioClient.make_bucket(bucket_name)\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/stations.json\",\n", + " station_json,\n", + " )\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/stations.pkl\",\n", + " station_pkl,\n", + " )\n", + "\n", + " except Exception as err:\n", + " print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " pass\n", + "\n", + " ######## Plot stations ########\n", + " station_locs = pd.DataFrame.from_dict(station_locs, orient=\"index\")\n", + " plt.figure()\n", + " plt.plot(station_locs[\"longitude\"], station_locs[\"latitude\"], \"^\", label=\"Stations\")\n", + " plt.xlabel(\"X (km)\")\n", + " plt.ylabel(\"Y (km)\")\n", + " plt.axis(\"scaled\")\n", + " plt.xlim(config[\"xlim_degree\"])\n", + " plt.ylim(config[\"ylim_degree\"])\n", + " plt.legend()\n", + " plt.title(f\"Number of stations: {len(station_locs)}\")\n", + " # plt.savefig(os.path.join(data_path, \"stations_loc.png\"))\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T20:04:10.295020Z", + "iopub.status.busy": "2022-08-11T20:04:10.294907Z", + "iopub.status.idle": "2022-08-11T20:04:15.789908Z", + "shell.execute_reply": "2022-08-11T20:04:15.789661Z", + "shell.execute_reply.started": "2022-08-11T20:04:10.295009Z" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Network: CI\n", + "Number of stations: 17\n", + "ERROR: can not access minio service! \n", + "HTTPSConnectionPool(host='minio-service', port=9000): Max retries exceeded with url: /catalogs?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "if run_local:\n", + " download_stations(root_dir(\"config.json\"), root_dir(\"stations.json\"), root_dir(\"stations.pkl\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T20:04:15.790410Z", + "iopub.status.busy": "2022-08-11T20:04:15.790300Z", + "iopub.status.idle": "2022-08-11T20:04:15.801936Z", + "shell.execute_reply": "2022-08-11T20:04:15.801582Z", + "shell.execute_reply.started": "2022-08-11T20:04:15.790399Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "download_stations_op = comp.func_to_container_op(\n", + " download_stations,\n", + " # base_image='zhuwq0/quakeflow-env:latest',\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\n", + " \"obspy\",\n", + " \"pandas\",\n", + " \"matplotlib\",\n", + " \"minio\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Download waveform data" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.171415Z", + "iopub.status.busy": "2022-08-11T15:42:43.171308Z", + "iopub.status.idle": "2022-08-11T15:42:43.180260Z", + "shell.execute_reply": "2022-08-11T15:42:43.179978Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.171400Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def download_waveform(\n", + " node_i: int,\n", + " index_json: InputPath(\"json\"),\n", + " config_json: InputPath(\"json\"),\n", + " datetime_json: InputPath(\"json\"),\n", + " station_pkl: InputPath(\"pickle\"),\n", + " fname_csv: OutputPath(str),\n", + " data_path: str,\n", + " bucket_name: str = \"waveforms\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + ") -> str:\n", + "\n", + " import json\n", + " import os\n", + " import pickle\n", + " import random\n", + " import threading\n", + " import time\n", + "\n", + " import obspy\n", + " from obspy.clients.fdsn import Client\n", + "\n", + " lock = threading.Lock()\n", + "\n", + " upload_minio = False\n", + " # try:\n", + " # from minio import Minio\n", + "\n", + " # minioClient = Minio(s3_url, access_key='minio', secret_key='minio123', secure=secure)\n", + " # if not minioClient.bucket_exists(bucket_name):\n", + " # minioClient.make_bucket(bucket_name)\n", + " # upload_minio = True\n", + " # except Exception as err:\n", + " # # print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " # pass\n", + "\n", + " with open(index_json, \"r\") as fp:\n", + " index = json.load(fp)\n", + " idx = index[node_i]\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + " with open(datetime_json, \"r\") as fp:\n", + " tmp = json.load(fp)\n", + " starttimes = tmp[\"starttimes\"]\n", + " interval = tmp[\"interval\"]\n", + " with open(station_pkl, \"rb\") as fp:\n", + " stations = pickle.load(fp)\n", + "\n", + " waveform_dir = os.path.join(data_path, config[\"region\"], \"waveforms\")\n", + " if not os.path.exists(waveform_dir):\n", + " os.makedirs(waveform_dir)\n", + "\n", + " ####### Download data ########\n", + " client = Client(config[\"client\"])\n", + " fname_list = [\"fname\"]\n", + "\n", + " def download(i):\n", + " # for i in idx:\n", + " starttime = obspy.UTCDateTime(starttimes[i])\n", + " endtime = starttime + interval\n", + " fname = \"{}.mseed\".format(starttime.datetime.strftime(\"%Y-%m-%dT%H:%M:%S\"))\n", + " if not upload_minio:\n", + " if os.path.exists(os.path.join(waveform_dir, fname)):\n", + " print(f\"{fname} exists\")\n", + " fname_list.append(fname)\n", + " return\n", + " else:\n", + " try:\n", + " minioClient.fget_object(\n", + " bucket_name,\n", + " os.path.join(config[\"region\"], fname),\n", + " os.path.join(waveform_dir, fname),\n", + " )\n", + " print(\n", + " f\"{bucket_name}/{os.path.join(config['region'], fname)} download to {os.path.join(waveform_dir, fname)}\"\n", + " )\n", + " fname_list.append(fname)\n", + " return\n", + " except Exception as err:\n", + " print(err)\n", + "\n", + " max_retry = 10\n", + " stream = obspy.Stream()\n", + " print(f\"{fname} download starts\")\n", + " num_sta = 0\n", + " for network in stations:\n", + " for station in network:\n", + " print(f\"********{network.code}.{station.code}********\")\n", + " retry = 0\n", + " while retry < max_retry:\n", + " try:\n", + " tmp = client.get_waveforms(\n", + " network.code,\n", + " station.code,\n", + " \"*\",\n", + " config[\"channels\"],\n", + " starttime,\n", + " endtime,\n", + " )\n", + " # for trace in tmp:\n", + " # if trace.stats.sampling_rate != 100:\n", + " # print(trace)\n", + " # trace = trace.interpolate(100, method=\"linear\")\n", + " # trace = trace.detrend(\"spline\", order=2, dspline=5*trace.stats.sampling_rate)\n", + " # stream.append(trace)\n", + " stream += tmp\n", + " num_sta += len(tmp)\n", + " break\n", + " except Exception as err:\n", + " print(\"Error {}.{}: {}\".format(network.code, station.code, err))\n", + " message = \"No data available for request.\"\n", + " if str(err)[: len(message)] == message:\n", + " break\n", + " retry += 1\n", + " time.sleep(5)\n", + " continue\n", + " if retry == max_retry:\n", + " print(f\"{fname}: MAX {max_retry} retries reached : {network.code}.{station.code}\")\n", + "\n", + " if len(stream) > 0:\n", + " # stream = stream.merge(fill_value=0)\n", + " # stream = stream.trim(starttime, endtime, pad=True, fill_value=0)\n", + " stream.write(os.path.join(waveform_dir, fname))\n", + " print(f\"{fname} download succeeds\")\n", + " # if upload_minio:\n", + " # minioClient.fput_object(bucket_name, os.path.join(config['region'], fname), os.path.join(waveform_dir, fname))\n", + " # print(f\"{fname} upload to minio {os.path.join(config['region'], fname)}\")\n", + " else:\n", + " print(f\"{fname} empty data\")\n", + " lock.acquire()\n", + " fname_list.append(fname)\n", + " lock.release()\n", + "\n", + " threads = []\n", + " MAX_THREADS = 2\n", + " # MAX_THREADS = 1\n", + " for ii, i in enumerate(idx):\n", + " t = threading.Thread(target=download, args=(i,))\n", + " t.start()\n", + " time.sleep(1)\n", + " threads.append(t)\n", + " if ii % MAX_THREADS == MAX_THREADS - 1:\n", + " for t in threads:\n", + " t.join()\n", + " threads = []\n", + " for t in threads:\n", + " t.join()\n", + "\n", + " with open(fname_csv, \"w\") as fp:\n", + " fp.write(\"\\n\".join(fname_list))\n", + "\n", + " return waveform_dir" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.180912Z", + "iopub.status.busy": "2022-08-11T15:42:43.180716Z", + "iopub.status.idle": "2022-08-11T15:42:43.183361Z", + "shell.execute_reply": "2022-08-11T15:42:43.183089Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.180896Z" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2019-07-04T17:00:00.mseed exists\n", + "2019-07-04T18:00:00.mseed exists\n" + ] + } + ], + "source": [ + "if run_local:\n", + " waveform_path = download_waveform(\n", + " 0,\n", + " root_dir(\"index.json\"),\n", + " root_dir(\"config.json\"),\n", + " root_dir(\"datetimes.json\"),\n", + " root_dir(\"stations.pkl\"),\n", + " root_dir(\"fname.csv\"),\n", + " data_path=root_dir(\"\"),\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.184062Z", + "iopub.status.busy": "2022-08-11T15:42:43.183802Z", + "iopub.status.idle": "2022-08-11T15:42:43.202793Z", + "shell.execute_reply": "2022-08-11T15:42:43.202417Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.184045Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "download_waveform_op = comp.func_to_container_op(\n", + " download_waveform,\n", + " # base_image='zhuwq0/quakeflow-env:latest',\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\"obspy\", \"minio\"],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "def resume_waveform(\n", + " i: int,\n", + " index_json: InputPath(\"json\"),\n", + " config_json: InputPath(\"json\"),\n", + " datetime_json: InputPath(\"json\"),\n", + " data_path: str,\n", + " bucket_name: str = \"waveforms\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + ") -> int:\n", + "\n", + " import json\n", + " import pickle\n", + " import time\n", + " import threading\n", + " import os\n", + " from pathlib import Path\n", + "\n", + " with open(index_json, \"r\") as fp:\n", + " index = json.load(fp)\n", + " idx = index[i]\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " waveform_dir = Path(data_path, config[\"region\"], \"waveforms\")\n", + " if not waveform_dir.exists():\n", + " waveform_dir.mkdir(parents=True)\n", + "\n", + " status = -1\n", + " max_retry = 10\n", + " retry_rsync = 0\n", + "\n", + " while (status != 0) and (retry_rsync < max_retry):\n", + " status = os.system(\n", + " f\"rsync -av zhuwq@wintermute:/atomic-data/zhuwq/{config['region']}/{i:03d}/ {data_path}/{config['region']}/waveforms/\"\n", + " )\n", + " retry_rsync += 1\n", + " if status != 0:\n", + " time.sleep(5)\n", + "\n", + " if status != 0:\n", + " print(\n", + " f\"Failed: rsync -av zhuwq@wintermute:/atomic-data/zhuwq/{config['region']}/{i:03d}/ {data_path}/{config['region']}/waveforms/\"\n", + " )\n", + "\n", + " return 0" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [], + "source": [ + "resume_waveform_op = comp.func_to_container_op(\n", + " resume_waveform,\n", + " base_image=\"zhuwq0/waveform-env:1.1\",\n", + " # base_image='python:3.8',\n", + " # packages_to_install=[\"obspy\", \"minio\"],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ + "def save_waveform(\n", + " i: int,\n", + " index_json: InputPath(\"json\"),\n", + " config_json: InputPath(\"json\"),\n", + " datetime_json: InputPath(\"json\"),\n", + " data_path: str,\n", + " bucket_name: str = \"waveforms\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + ") -> int:\n", + "\n", + " import json\n", + " import pickle\n", + " import time\n", + " import threading\n", + " import os\n", + " from pathlib import Path\n", + "\n", + " with open(index_json, \"r\") as fp:\n", + " index = json.load(fp)\n", + " idx = index[i]\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " waveform_dir = Path(data_path, config[\"region\"], \"waveforms\")\n", + " mseeds = waveform_dir.glob(\"*.mseed\")\n", + "\n", + " status = -1\n", + " max_retry = 10\n", + " retry_rsync = 0\n", + " while (status != 0) and (retry_rsync < max_retry):\n", + " status = os.system(f\"ssh zhuwq@wintermute mkdir -p /atomic-data/zhuwq/{config['region']}/{i:03d}/\")\n", + " retry_rsync += 1\n", + " if status != 0:\n", + " time.sleep(5)\n", + "\n", + " if status != 0:\n", + " print(f\"Failed: ssh zhuwq@wintermute mkdir -p /atomic-data/zhuwq/{config['region']}/{i:03d}/\")\n", + "\n", + " status = -1\n", + " max_retry = 10\n", + " retry_rsync = 0\n", + "\n", + " while (status != 0) and (retry_rsync < max_retry):\n", + " status = os.system(\n", + " f\"rsync -av {data_path}/{config['region']}/waveforms/ zhuwq@wintermute:/atomic-data/zhuwq/{config['region']}/{i:03d}/\"\n", + " )\n", + " retry_rsync += 1\n", + " if status != 0:\n", + " time.sleep(5)\n", + "\n", + " if status != 0:\n", + " print(\n", + " f\"Failed: rsync -av {data_path}/{config['region']}/waveforms/ zhuwq@wintermute:/atomic-data/zhuwq/{config['region']}/{i:03d}/\"\n", + " )\n", + "\n", + " return 0" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "save_waveform_op = comp.func_to_container_op(\n", + " save_waveform,\n", + " base_image=\"zhuwq0/waveform-env:1.1\",\n", + " # base_image='python:3.8',\n", + " # packages_to_install=[\"obspy\", \"minio\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Run PhaseNet to pick P/S picks" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.203346Z", + "iopub.status.busy": "2022-08-11T15:42:43.203230Z", + "iopub.status.idle": "2022-08-11T15:42:43.206297Z", + "shell.execute_reply": "2022-08-11T15:42:43.206079Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.203331Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def phasenet_op(data_path: str, data_list: str, stations: str):\n", + "\n", + " return dsl.ContainerOp(\n", + " name=\"PhaseNet Picking\",\n", + " image=\"zhuwq0/phasenet-api:1.0\",\n", + " command=[\"python\"],\n", + " arguments=[\n", + " \"phasenet/predict.py\",\n", + " \"--model\",\n", + " \"model/190703-214543\",\n", + " \"--data_dir\",\n", + " data_path,\n", + " \"--data_list\",\n", + " dsl.InputArgumentPath(data_list),\n", + " \"--stations\",\n", + " dsl.InputArgumentPath(stations),\n", + " # '--result_dir', \"results\",\n", + " \"--format\",\n", + " \"mseed_array\",\n", + " \"--amplitude\",\n", + " ],\n", + " file_outputs={\"picks\": \"/opt/results/picks.csv\"},\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.206789Z", + "iopub.status.busy": "2022-08-11T15:42:43.206677Z", + "iopub.status.idle": "2022-08-11T15:42:43.209109Z", + "shell.execute_reply": "2022-08-11T15:42:43.208840Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.206774Z" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "python ../PhaseNet/phasenet/predict.py --model=../PhaseNet/model/190703-214543 --data_dir=Demo/Demo/waveforms --data_list=Demo/fname.csv --stations=Demo/stations.json --result_dir=Demo/phasenet --format=mseed_array --amplitude\n", + " longitude latitude elevation(m) component response unit\n", + "CI.CCC..BH -117.364530 35.524950 670.0 [E, N, Z] [627368000.0, 627368000.0, 627368000.0] m/s\n", + "CI.CCC..HH -117.364530 35.524950 670.0 [E, N, Z] [627368000.0, 627368000.0, 627368000.0] m/s\n", + "CI.CCC..HN -117.364530 35.524950 670.0 [E, N, Z] [213979.0, 214322.0, 213808.0] m/s**2\n", + "CI.CLC..BH -117.597510 35.815740 775.0 [E, N, Z] [627368000.0, 627368000.0, 627368000.0] m/s\n", + "CI.CLC..HH -117.597510 35.815740 775.0 [E, N, Z] [627368000.0, 627368000.0, 627368000.0] m/s\n", + "CI.CLC..HN -117.597510 35.815740 775.0 [E, N, Z] [213945.0, 213808.0, 213740.0] m/s**2\n", + "CI.DTP..BH -117.845810 35.267420 908.0 [E, N, Z] [627368000.0, 627368000.0, 627368000.0] m/s\n", + "CI.DTP..HH -117.845810 35.267420 908.0 [E, N, Z] [627368000.0, 627368000.0, 627368000.0] m/s\n", + "CI.DTP..HN -117.845810 35.267420 908.0 [E, N, Z] [214399.0, 213971.0, 214484.0] m/s**2\n", + "CI.JRC2..BH -117.808850 35.982490 1469.0 [E, N, Z] [784866000.0, 784866000.0, 790478000.0] m/s\n", + "CI.JRC2..HH -117.808850 35.982490 1469.0 [E, N, Z] [784866000.0, 784866000.0, 790478000.0] m/s\n", + "CI.JRC2..HN -117.808850 35.982490 1469.0 [E, N, Z] [213808.0, 213945.0, 214185.0] m/s**2\n", + "CI.LRL..BH -117.682120 35.479540 1340.0 [E, N, Z] [628306000.0, 629984000.0, 627467000.0] m/s\n", + "CI.LRL..HH -117.682120 35.479540 1340.0 [E, N, Z] [628306000.0, 629984000.0, 627467000.0] m/s\n", + "CI.LRL..HN -117.682120 35.479540 1340.0 [E, N, Z] [213757.0, 213671.0, 213201.0] m/s**2\n", + "CI.LRL.2C.HN -117.682120 35.479540 1340.0 [E, N, Z] [213757.0, 213671.0, 213201.0] m/s**2\n", + "CI.MPM..BH -117.489010 36.057990 1839.0 [E, N, Z] [627368000.0, 627368000.0, 627368000.0] m/s\n", + "CI.MPM..HH -117.489010 36.057990 1839.0 [E, N, Z] [627368000.0, 627368000.0, 627368000.0] m/s\n", + "CI.MPM..HN -117.489010 36.057990 1839.0 [E, N, Z] [213911.0, 214219.0, 213911.0] m/s**2\n", + "CI.Q0072.01.HN -117.666721 35.609617 695.0 [E, N, Z] [256354.0, 256354.0, 256354.0] m/s**2\n", + "CI.SLA..BH -117.283320 35.890950 1174.0 [E, N, Z] [622338000.0, 618992000.0, 616482000.0] m/s\n", + "CI.SLA..HH -117.283320 35.890950 1174.0 [E, N, Z] [622338000.0, 618992000.0, 616482000.0] m/s\n", + "CI.SLA..HN -117.283320 35.890950 1174.0 [E, N, Z] [214253.0, 213671.0, 213979.0] m/s**2\n", + "CI.SRT..BH -117.750510 35.692350 667.0 [E, N, Z] [633341000.0, 633341000.0, 633341000.0] m/s\n", + "CI.SRT..HH -117.750510 35.692350 667.0 [E, N, Z] [629865000.0, 629865000.0, 629865000.0] m/s\n", + "CI.SRT..HN -117.750510 35.692350 667.0 [E, N, Z] [214301.0, 213873.0, 214087.0] m/s**2\n", + "CI.TOW2..BH -117.764880 35.808560 685.0 [E, N, Z] [626915000.0, 626915000.0, 626843000.0] m/s\n", + "CI.TOW2..HH -117.764880 35.808560 685.0 [E, N, Z] [626911000.0, 626911000.0, 626839000.0] m/s\n", + "CI.TOW2..HN -117.764880 35.808560 685.0 [E, N, Z] [213800.0, 214142.0, 214356.0] m/s**2\n", + "CI.WBM..BH -117.890490 35.608390 892.0 [E, N, Z] [314573000.0, 314573000.0, 314573000.0] m/s\n", + "CI.WBM..HH -117.890490 35.608390 892.0 [E, N, Z] [314573000.0, 314573000.0, 314573000.0] m/s\n", + "CI.WBM..HN -117.890490 35.608390 892.0 [E, N, Z] [213550.0, 214064.0, 213550.0] m/s**2\n", + "CI.WBM.2C.HN -117.890490 35.608390 892.0 [E, N, Z] [213550.0, 214064.0, 213550.0] m/s**2\n", + "CI.WCS2..BH -117.765260 36.025210 1143.0 [E, N, Z] [626910000.0, 626910000.0, 626838000.0] m/s\n", + "CI.WCS2..HH -117.765260 36.025210 1143.0 [E, N, Z] [626910000.0, 626910000.0, 626838000.0] m/s\n", + "CI.WCS2..HN -117.765260 36.025210 1143.0 [E, N, Z] [213757.0, 213329.0, 213415.0] m/s**2\n", + "CI.WMF..BH -117.854860 36.117580 1537.4 [E, N, Z] [629963000.0, 631652000.0, 629963000.0] m/s\n", + "CI.WMF..HH -117.854860 36.117580 1537.4 [E, N, Z] [626506000.0, 628185000.0, 626506000.0] m/s\n", + "CI.WMF..HN -117.854860 36.117580 1537.4 [E, N, Z] [214087.0, 214087.0, 214087.0] m/s**2\n", + "CI.WMF.2C.HN -117.854860 36.117580 1537.4 [E, N, Z] [213952.0, 213952.0, 213952.0] m/s**2\n", + "CI.WNM..EH -117.906160 35.842200 974.3 [Z] [69306200.0] m/s\n", + "CI.WNM..HN -117.906160 35.842200 974.3 [E, N, Z] [214054.0, 213926.0, 214054.0] m/s**2\n", + "CI.WNM.2C.HN -117.906160 35.842200 974.3 [E, N, Z] [214048.0, 213920.0, 214048.0] m/s**2\n", + "CI.WRC2..BH -117.650380 35.947900 943.0 [E, N, Z] [629145000.0, 629145000.0, 629145000.0] m/s\n", + "CI.WRC2..HH -117.650380 35.947900 943.0 [E, N, Z] [629145000.0, 629145000.0, 629145000.0] m/s\n", + "CI.WRC2..HN -117.650380 35.947900 943.0 [E, N, Z] [214227.0, 213970.0, 214056.0] m/s**2\n", + "CI.WRV2..EH -117.890400 36.007740 1070.0 [Z] [71427500.0] m/s\n", + "CI.WRV2..HN -117.890400 36.007740 1070.0 [E, N, Z] [213883.0, 235224.0, 235139.0] m/s**2\n", + "CI.WRV2.2C.HN -117.890400 36.007740 1070.0 [E, N, Z] [213877.0, 235218.0, 235132.0] m/s**2\n", + "CI.WVP2..EH -117.817690 35.949390 1465.0 [Z] [68041300.0] m/s\n", + "CI.WVP2..HN -117.817690 35.949390 1465.0 [E, N, Z] [213764.0, 213550.0, 213721.0] m/s**2\n", + "CI.WVP2.2C.HN -117.817690 35.949390 1465.0 [E, N, Z] [213782.0, 213569.0, 213740.0] m/s**2\n", + "2022-11-29 12:10:36,186 Resampling CI.CCC..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,529 Resampling CI.CCC..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,534 Resampling CI.CCC..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,540 Resampling CI.CLC..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,545 Resampling CI.CLC..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,550 Resampling CI.CLC..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,554 Resampling CI.DTP..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,558 Resampling CI.DTP..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,562 Resampling CI.DTP..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,565 Resampling CI.JRC2..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,568 Resampling CI.JRC2..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,572 Resampling CI.JRC2..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,575 Resampling CI.LRL..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,578 Resampling CI.LRL..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,583 Resampling CI.LRL..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,588 Resampling CI.MPM..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,592 Resampling CI.MPM..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,596 Resampling CI.MPM..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,602 Resampling CI.SLA..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,606 Resampling CI.SLA..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,610 Resampling CI.SLA..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,613 Resampling CI.SRT..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,617 Resampling CI.SRT..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,620 Resampling CI.SRT..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,623 Resampling CI.TOW2..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,627 Resampling CI.TOW2..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,631 Resampling CI.TOW2..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,635 Resampling CI.WBM..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,638 Resampling CI.WBM..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,644 Resampling CI.WBM..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,648 Resampling CI.WCS2..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,652 Resampling CI.WCS2..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,655 Resampling CI.WCS2..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,659 Resampling CI.WMF..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,663 Resampling CI.WMF..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,668 Resampling CI.WMF..BHZ from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,671 Resampling CI.WRC2..BHE from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,675 Resampling CI.WRC2..BHN from 40.0 to 100 Hz\n", + "2022-11-29 12:10:36,679 Resampling CI.WRC2..BHZ from 40.0 to 100 Hz\n", + "Empty trace: CI.LRL.2C.HNE 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.LRL.2C.HNN 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.LRL.2C.HNZ 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.Q0072.01.HNE 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.Q0072.01.HNN 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.Q0072.01.HNZ 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WBM.2C.HNE 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WBM.2C.HNN 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WBM.2C.HNZ 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WMF.2C.HNE 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WMF.2C.HNN 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WMF.2C.HNZ 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WNM.2C.HNE 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WNM.2C.HNN 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WNM.2C.HNZ 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WRV2.2C.HNE 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WRV2.2C.HNN 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WRV2.2C.HNZ 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WVP2.2C.HNE 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WVP2.2C.HNN 2019-07-04T16:59:59.994500Z\n", + "Empty trace: CI.WVP2.2C.HNZ 2019-07-04T16:59:59.994500Z\n", + "2022-11-29 12:10:41,120 Pred log: Demo/phasenet\n", + "2022-11-29 12:10:41,120 Dataset size: 2\n", + "2022-11-29 12:10:41,174 Model: depths 5, filters 8, filter size 7x1, pool size: 4x1, dilation rate: 1x1\n", + "2022-11-29 12:10:41.993942: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:354] MLIR V1 optimization pass is not enabled\n", + "2022-11-29 12:10:42.045252: W tensorflow/core/platform/profile_utils/cpu_utils.cc:128] Failed to get CPU frequency: 0 Hz\n", + "2022-11-29 12:10:42,143 restoring model ../PhaseNet/model/190703-214543/model_95.ckpt\n", + "Pred: 0%| | 0/2 [00:00 str:\n", + "\n", + " import json\n", + " import os\n", + " import pickle\n", + " from datetime import datetime, timedelta\n", + "\n", + " import numpy as np\n", + " import pandas as pd\n", + " from gamma.utils import association, convert_picks_csv, from_seconds\n", + " from pyproj import Proj\n", + " from tqdm import tqdm\n", + "\n", + " catalog_dir = os.path.join(\"/tmp/\", bucket_name)\n", + " if not os.path.exists(catalog_dir):\n", + " os.makedirs(catalog_dir)\n", + "\n", + " ## read config\n", + " with open(index_json, \"r\") as fp:\n", + " index = json.load(fp)\n", + " idx = index[node_i]\n", + "\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " ## read picks\n", + " # picks = pd.read_json(pick_json)\n", + " picks = pd.read_csv(pick_csv, parse_dates=[\"begin_time\", \"phase_time\"])\n", + " picks[\"id\"] = picks[\"station_id\"]\n", + " picks[\"timestamp\"] = picks[\"phase_time\"]\n", + " picks[\"amp\"] = picks[\"phase_amp\"]\n", + " picks[\"type\"] = picks[\"phase_type\"]\n", + " picks[\"prob\"] = picks[\"phase_score\"]\n", + "\n", + " ## read stations\n", + " # stations = pd.read_csv(station_csv, delimiter=\"\\t\")\n", + " with open(station_json, \"r\") as fp:\n", + " stations = json.load(fp)\n", + " stations = pd.DataFrame.from_dict(stations, orient=\"index\")\n", + " # stations = stations.rename(columns={\"station\": \"id\"})\n", + " stations[\"id\"] = stations.index\n", + " proj = Proj(f\"+proj=sterea +lon_0={config['center'][0]} +lat_0={config['center'][1]} +units=km\")\n", + " stations[[\"x(km)\", \"y(km)\"]] = stations.apply(\n", + " lambda x: pd.Series(proj(longitude=x.longitude, latitude=x.latitude)), axis=1\n", + " )\n", + " stations[\"z(km)\"] = stations[\"elevation(m)\"].apply(lambda x: -x / 1e3)\n", + "\n", + " ## setting GMMA configs\n", + " config[\"use_dbscan\"] = True\n", + " config[\"use_amplitude\"] = True\n", + " config[\"method\"] = \"BGMM\"\n", + " if config[\"method\"] == \"BGMM\": ## BayesianGaussianMixture\n", + " config[\"oversample_factor\"] = 4\n", + " if config[\"method\"] == \"GMM\": ## GaussianMixture\n", + " config[\"oversample_factor\"] = 1\n", + "\n", + " # Earthquake location\n", + " config[\"dims\"] = [\"x(km)\", \"y(km)\", \"z(km)\"]\n", + " config[\"vel\"] = {\"p\": 6.0, \"s\": 6.0 / 1.73}\n", + " config[\"x(km)\"] = (np.array(config[\"xlim_degree\"]) - np.array(config[\"center\"][0])) * config[\"degree2km\"]\n", + " config[\"y(km)\"] = (np.array(config[\"ylim_degree\"]) - np.array(config[\"center\"][1])) * config[\"degree2km\"]\n", + " config[\"z(km)\"] = (0, 60)\n", + " config[\"bfgs_bounds\"] = (\n", + " (config[\"x(km)\"][0] - 1, config[\"x(km)\"][1] + 1), # x\n", + " (config[\"y(km)\"][0] - 1, config[\"y(km)\"][1] + 1), # y\n", + " (0, config[\"z(km)\"][1] + 1), # z\n", + " (None, None), # t\n", + " )\n", + "\n", + " # DBSCAN\n", + " config[\"dbscan_eps\"] = 10 # second\n", + " config[\"dbscan_min_samples\"] = 3 ## see DBSCAN\n", + "\n", + " # Filtering\n", + " config[\"min_picks_per_eq\"] = min(10, len(stations) // 2)\n", + " config[\"min_p_picks_per_eq\"] = 0\n", + " config[\"min_s_picks_per_eq\"] = 0\n", + " config[\"max_sigma11\"] = 2.0 # s\n", + " config[\"max_sigma22\"] = 2.0 # m/s\n", + " config[\"max_sigma12\"] = 1.0 # covariance\n", + "\n", + " # if use amplitude\n", + " if config[\"use_amplitude\"]:\n", + " picks = picks[picks[\"amp\"] != -1]\n", + "\n", + " # print(config)\n", + " for k, v in config.items():\n", + " print(f\"{k}: {v}\")\n", + "\n", + " ## run GMMA association\n", + " event_idx0 = 1\n", + " assignments = []\n", + " catalogs, assignments = association(picks, stations, config, event_idx0, method=config[\"method\"])\n", + " event_idx0 += len(catalogs)\n", + "\n", + " if len(catalogs) == 0:\n", + " with open(gamma_catalog_csv, \"w\") as fp:\n", + " fp.write(\"time,magnitude,longitude,latitude,depth(m),sigma_time,sigma_amp,cov_time_amp,gamma_score,event_index\\n\")\n", + " with open(gamma_pick_csv, \"w\") as fp:\n", + " fp.write(\"station_id,phase_time,phase_type,phase_score,phase_amp,gamma_score,event_index\\n\")\n", + "\n", + " else:\n", + " ## create catalog\n", + " catalogs = pd.DataFrame(\n", + " catalogs,\n", + " columns=[\"time\"]\n", + " + config[\"dims\"]\n", + " + [\n", + " \"magnitude\",\n", + " \"sigma_time\",\n", + " \"sigma_amp\",\n", + " \"cov_time_amp\",\n", + " \"event_index\",\n", + " \"gamma_score\",\n", + " ],\n", + " )\n", + "\n", + " catalogs[[\"longitude\", \"latitude\"]] = catalogs.apply(\n", + " lambda x: pd.Series(proj(longitude=x[\"x(km)\"], latitude=x[\"y(km)\"], inverse=True)),\n", + " axis=1,\n", + " )\n", + " catalogs[\"depth(m)\"] = catalogs[\"z(km)\"].apply(lambda x: x * 1e3)\n", + "\n", + " catalogs.sort_values(by=[\"time\"], inplace=True)\n", + " with open(gamma_catalog_csv, \"w\") as fp:\n", + " catalogs.to_csv(\n", + " fp,\n", + " # sep=\"\\t\",\n", + " index=False,\n", + " float_format=\"%.3f\",\n", + " date_format=\"%Y-%m-%dT%H:%M:%S.%f\",\n", + " columns=[\n", + " \"time\",\n", + " \"magnitude\",\n", + " \"longitude\",\n", + " \"latitude\",\n", + " \"depth(m)\",\n", + " \"sigma_time\",\n", + " \"sigma_amp\",\n", + " \"cov_time_amp\",\n", + " \"gamma_score\",\n", + " \"event_index\",\n", + " ],\n", + " )\n", + " # catalogs = catalogs[\n", + " # ['time', 'magnitude', 'longitude', 'latitude', 'depth(m)', 'sigma_time', 'sigma_amp']\n", + " # ]\n", + "\n", + " ## add assignment to picks\n", + " assignments = pd.DataFrame(assignments, columns=[\"pick_index\", \"event_index\", \"gamma_score\"])\n", + " picks = picks.join(assignments.set_index(\"pick_index\")).fillna(-1).astype({\"event_index\": int})\n", + " picks.sort_values(by=[\"timestamp\"], inplace=True)\n", + " with open(gamma_pick_csv, \"w\") as fp:\n", + " picks.to_csv(\n", + " fp,\n", + " # sep=\"\\t\",\n", + " index=False,\n", + " date_format=\"%Y-%m-%dT%H:%M:%S.%f\",\n", + " columns=[\n", + " \"station_id\",\n", + " \"phase_time\",\n", + " \"phase_type\",\n", + " \"phase_score\",\n", + " \"phase_amp\",\n", + " \"gamma_score\",\n", + " \"event_index\",\n", + " ],\n", + " )\n", + "\n", + " ## upload to s3 bucket\n", + " try:\n", + " from minio import Minio\n", + "\n", + " minioClient = Minio(s3_url, access_key=\"minio\", secret_key=\"minio123\", secure=secure)\n", + " if not minioClient.bucket_exists(bucket_name):\n", + " minioClient.make_bucket(bucket_name)\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/gamma/catalog_{node_i:03d}.csv\",\n", + " gamma_catalog_csv,\n", + " )\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/gamma/picks_{node_i:03d}.csv\",\n", + " gamma_pick_csv,\n", + " )\n", + "\n", + " except Exception as err:\n", + " print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " pass\n", + "\n", + " ## upload to mongodb\n", + " try:\n", + " from pymongo import MongoClient\n", + "\n", + " username = \"root\"\n", + " password = \"quakeflow123\"\n", + " client = MongoClient(f\"mongodb://{username}:{password}@127.0.0.1:27017\")\n", + " db = client[\"quakeflow\"]\n", + " collection = db[\"waveform\"]\n", + " for i, p in tqdm(picks.iterrows(), desc=\"Uploading to mongodb\"):\n", + " collection.update(\n", + " {\"_id\": f\"{p['station_id']}_{p['timestamp'].isoformat(timespec='milliseconds')}_{p['type']}\"},\n", + " {\"$set\": {\"event_index\": p[\"event_index\"]}},\n", + " )\n", + " except Exception as err:\n", + " print(f\"ERROR: can not access mongodb service! \\n{err}\")\n", + " pass\n", + "\n", + " return f\"catalog_{node_i:03d}.csv\"" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.225205Z", + "iopub.status.busy": "2022-08-11T15:42:43.225080Z", + "iopub.status.idle": "2022-08-11T15:42:43.227609Z", + "shell.execute_reply": "2022-08-11T15:42:43.227339Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.225188Z" + }, + "scrolled": true, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "region: Demo\n", + "center: [-117.504, 35.705]\n", + "xlim_degree: [-118.004, -117.004]\n", + "ylim_degree: [35.205, 36.205]\n", + "min_longitude: -118.004\n", + "max_longitude: -117.004\n", + "min_latitude: 35.205\n", + "max_latitude: 36.205\n", + "degree2km: 111.19492664455873\n", + "starttime: 2019-07-04T17:00:00.000\n", + "endtime: 2019-07-04T19:00:00.000\n", + "networks: ['CI']\n", + "channels: HH*,BH*,EH*,HN*\n", + "client: SCEDC\n", + "phasenet: {}\n", + "gamma: {}\n", + "hypodd: {'MAXEVENT': 10000.0}\n", + "use_dbscan: True\n", + "use_amplitude: True\n", + "method: BGMM\n", + "oversample_factor: 4\n", + "dims: ['x(km)', 'y(km)', 'z(km)']\n", + "vel: {'p': 6.0, 's': 3.468208092485549}\n", + "x(km): [-55.59746332 55.59746332]\n", + "y(km): [-55.59746332 55.59746332]\n", + "z(km): (0, 60)\n", + "bfgs_bounds: ((-56.59746332227937, 56.59746332227937), (-56.59746332227937, 56.59746332227937), (0, 61), (None, None))\n", + "dbscan_eps: 10\n", + "dbscan_min_samples: 3\n", + "min_picks_per_eq: 10\n", + "min_p_picks_per_eq: 0\n", + "min_s_picks_per_eq: 0\n", + "max_sigma11: 2.0\n", + "max_sigma22: 2.0\n", + "max_sigma12: 1.0\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Skip 34 picks: 100%|██████████| 18150/18150 [01:38<00:00, 184.29it/s] \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ERROR: can not access minio service! \n", + "HTTPConnectionPool(host='localhost', port=9000): Max retries exceeded with url: /catalogs?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 61] Connection refused'))\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Uploading to mongodb: 0it [00:30, ?it/s]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ERROR: can not access mongodb service! \n", + "127.0.0.1:27017: [Errno 61] Connection refused, Timeout: 30s, Topology Description: ]>\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "if run_local:\n", + " catalog = gamma(\n", + " 0,\n", + " root_dir(\"index.json\"),\n", + " root_dir(\"config.json\"),\n", + " root_dir(\"phasenet/picks.csv\"),\n", + " root_dir(\"stations.json\"),\n", + " root_dir(\"gamma_catalog.csv\"),\n", + " root_dir(\"gamma_picks.csv\"),\n", + " bucket_name=\"catalogs\",\n", + " s3_url=\"localhost:9000\",\n", + " secure=False,\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.228292Z", + "iopub.status.busy": "2022-08-11T15:42:43.228076Z", + "iopub.status.idle": "2022-08-11T15:42:43.257021Z", + "shell.execute_reply": "2022-08-11T15:42:43.256784Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.228276Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "gamma_op = comp.func_to_container_op(\n", + " gamma,\n", + " # base_image='zhuwq0/quakeflow-env:latest',\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\n", + " \"pandas\",\n", + " \"numpy\",\n", + " \"scikit-learn\",\n", + " \"tqdm\",\n", + " \"minio\",\n", + " \"gmma\",\n", + " \"pyproj\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plot catalogs" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.257537Z", + "iopub.status.busy": "2022-08-11T15:42:43.257425Z", + "iopub.status.idle": "2022-08-11T15:42:43.259721Z", + "shell.execute_reply": "2022-08-11T15:42:43.259471Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.257522Z" + }, + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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k7Zp95ZbbqF9+/ZcdtllAAwYMIA///nP1UXj/fffb1C+PfbYg3bt2jFjxgwAHn300eqjimOOOYbHHnuMnj170qxZM/baay8mTpxIv3796mzzlVdeYdy4cbz44ovbjFuceuqpPPnkk2zatInFixezcOFCjjjiCLp06cL8+fOpKvKTJ09udIETkcRIiyJRxd1XA1OBge6+MiwelcD9wBGpzLarzIznnnuOZ555hp49e9K+fXuaNWtW3e3Tr18/unfvzqGHHsrVV19Nnz59ADjssMPo3bs3hxxyCD/72c9q/cN81113UV5ezrXXXstvf/tbtmzZQkFBAb169eK3v/1tgzNOmDCBa665hoKCAkpKSrjpppuA4FRboPrI4aijjmLPPfekXbvgoC5qTGLkyJGsW7eOE088kcLCQi655BIgOKo666yzOPjggxk4cCB/+ctfyMnJoXPnzowaNYpjjjmmOsMNN9zQ4PwiEh9rSN94rAHMOgJb3H21me0GvAaMA2a7+4rwPb8CvufuP6mrraKiIt++a+ejjz7a5n+lyT4FdnszZ87knHPO4R//+McOA9pSv+1/npI8o4edEOMpsEWMnvBGLG1L/cxstrsX1bYu5afAAnnABDPLITiyecrdXzazR82skGAQewnw80TsbGf+oMfhyCOP5LPPIu/vISKSVlJeJNx9LtC7luVDUxBHRERqSKsxCRERSS8qEiIiEklFQkREIqlIiIhIJBWJJBgzZgyHHHIIBQUFFBYW8s47wQXld911Fxs2bEjYfvLz8/nqq692efuHH36YkSNH1vmekpISvv/971d/nr///e/V64YPH0737t2r54mqupL68ccfp6CggIKCAo488kjmzJmzyxlFJLlSfnZTsiV6Tvz65sF/++23efnll3nvvfdo1aoVX331FZs3bwaCIvHTn/40cjbVuFVUVJCTk7NT27Ru3ZpHHnmEnj17snz5cg4//HAGDBhQfb+I2267jTPOOGObbbp37860adNo164dkyZNYsSIEdWFUkTSW9YViUTPiV/fPPgrVqygQ4cO1TcYqrqRzt13383y5cs57rjj6NChA1OmTImcGjw/P59hw4bx0ksvsWXLFp5++mkOOuggysrKOOecc1i1ahVHHHHENhPo/fjHP2bZsmWUl5dz5ZVXMmLECADatGnDr3/9a1599VXuuOMOFi5cyNixY8nLy+OAAw6o90ZIBxxwQPXzzp0706lTJ1atWlVdJGpz5JFHVj/v27cvpaWldX/TRCRtqLspZieddBLLli3jgAMO4LLLLmPatGkA/OIXv6Bz585MmTKFKVOmAHVPDd6hQwfee+89Lr30Um6//XYAbr75Zo466ijef/99Tj311OpZXyGYonv27NkUFxdz9913U1ZWBsD69evp1asX77zzDj169GDUqFG89dZbTJ48eZtZZl988cXq6TmivPvuu2zevJkePXpUL7vxxhspKCjgV7/6FZs2bdphmwceeKB66nARSX8qEjFr06YNs2fPZvz48XTs2JGzzz6bhx9+uNb31jU1+GmnnQbA4YcfzpIlSwCYPn06P/3pTwE45ZRTqudUguBI5bDDDqNv374sW7aMhQsXAsFNj04//XQA3nnnHfr370/Hjh1p2bIlZ599dvX2p556KrfcEn11+ooVKxg6dCgPPfQQzZoF/4zGjh3LggULmDVrFv/+978ZN27cNttMmTKFBx54YIflIpK+sq67KRVycnLo378//fv359BDD2XChAkMHz58m/dUTQ0+a9Ys2rVrx/Dhw7eZGryqGygnJ4etW7dWL6/tXhVTp07l9ddf5+2336Z169bV95cAyM3N3WYcorbt67N27VpOOeUUfv/739O3b9/q5Xl5edVZL7jgguojHoC5c+dy0UUXMWnSJNq3b7/T+xSR1NCRRMw+/vjj6v/FQ3B20L777gtA27ZtWbduHVD/1OC1OeaYY3j88ccBmDRpEl9/HUxcuGbNGtq1a0fr1q1ZsGAB//rXv2rd/nvf+x5Tp06lrKyseqyjPps3b2bIkCGcf/75nHnmmdusW7FiBRDc2+L555+nV69eACxdupTTTjuNRx99dJsxDRFJfzqSiNk333zDFVdcwerVq2nevDn7778/48ePB2DEiBEMGjSIvLw8pkyZUj01+H777VfvPRsARo0axTnnnEOfPn049thj6datGwADBw7kvvvuo6CggAMPPHCb/+3XlJeXx+jRo/n+979PXl4effr0oaKiAgjGJIqLi3focnrqqaeYPn06ZWVl1d1mDz/8MIWFhZx33nmsWrUKd6ewsJD77rsPCO59UVZWVn3vi+bNm+9wIyYRSU8pnyo8kRoyVXiyT4GVxNJU4amjqcKbrnSfKjyp9AddRKThNCYhIiKR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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEGCAYAAACKB4k+AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAeUUlEQVR4nO3deXhU5fn/8fdNEo2IRiD4FYwY9iqLLFGpyCYuiEUKWnFpKWpNRe23vdq6tHqxWYr8SltFK4gbYFGLragoWDc2VxaNqURQvy4YgkojJoJshvv3x0yOAUIyCXMymfB5XRcXM2fmPOdOCPnMec5znsfcHREREYBGiS5ARETqD4WCiIgEFAoiIhJQKIiISEChICIigdREF3AgMjMzPTs7O9FliIgkldWrV//X3VtU9lpSh0J2djarVq1KdBkiIknFzD7Z32vqPhIRkYBCQUREAgoFEREJJOU1BTMbCgxt3759oksRaXB27dpFYWEh27dvT3QpcoDS09PJysoiLS0t5n0smec+ysnJcV1oFomvjz76iCOOOILmzZtjZokuR2rJ3SkuLubrr7+mTZs2e7xmZqvdPaey/dR9JCJ72L59uwKhATAzmjdvXuMzPoWCiOxDgdAw1ObfUaEgIiKBpLzQLBIPz/7jAXZ9uT6UttOatWbwyCtCabuujbl+LB9+tjlu7bU9pinT/zSxyvcUFhZy7bXXUlBQQFlZGUOGDOHPf/4zhx56aK2OWX6ja2ZmZrXvXbJkCcOGDQv64TMzM3nhhRcYP348TZo04be//W2taqjK9ddfz4IFCzjkkENo164dDz74IEcddRQAkydP5v777yclJYVp06ZxzjnnAPDII4/wxz/+ETOjVatW/P3vf4/p66uOQkEOWru+XM/QrPj9sqtoQWEozSbEh59tZt2xg+PX4IZnq3zZ3RkxYgRjxozhySefpKysjNzcXG644QbuuOOO+NVRhb59+/L000/XybEAzjrrLCZPnkxqaio33ngjkydPZsqUKRQUFPDoo4+yZs0aioqKOPPMM3nvvfdwd375y19SUFBAZmYmN9xwA3fddRfjx48/4FqSsvvIzIaa2cySkpJElyIicfbSSy+Rnp7O5ZdfDkBKSgp//etfmTNnDlu2bGHWrFlcd911wft/8IMfsGTJEgDGjBlDTk4OnTt3Zty4cfu0vW3bNgYPHsy9997L1q1bueKKKzj55JPp0aMHTz75ZMw15uXl0bt3b7p168bw4cPZvHkzX3zxBb169QLg7bffxsxYvz5yJtquXTu++eab/bZ39tlnk5oa+Yzeu3dvCgsjnyqefPJJLr74Yg499FDatGlD+/btWbFiBe6Ou7N161bcndLSUlq1ahVz/VVJylBw9wXunpuRkZHoUkQkztasWRP8ci135JFHkp2dzQcffFDlvpMmTWLVqlXk5+ezdOlS8vPzg9e2bNnC0KFDufTSS7nqqquYNGkSZ5xxBitXrmTx4sVcf/31bN26FYDly5fTvXt3unfvzqRJk/Y5zqhRo5gyZQr5+fl07dqVCRMmcPTRR7N9+3ZKS0tZvnw5OTk5LF++nE8++YSjjz6axo0bM2TIEIqKiqr8Gh544AHOPfdcADZs2MBxxx0XvJaVlcWGDRtIS0tj+vTpdO3alVatWlFQUMCVV15Z9Tc2RkkZCiLScLl7paNmYrmnat68efTs2ZMePXqwZs0aCgoKgteGDRvG5ZdfzqhRowB47rnnuO222+jevTsDBgxg+/btwSf7vn37kpeXR15eHjfffPMexygpKeGrr76if//+APz0pz9l2bJlAJx22mm88sorLFu2jN///vcsW7aM5cuX07dvXwAWLlxY5Sf6SZMmkZqaymWXXbbfr9nM2LVrF9OnT+ett96iqKiIbt26MXny5Gq/P7FQKIhIvdK5c+d9Zj8uLS3l888/p1OnTqSmprJ79+7gtfJx+B999BFTp07lxRdfJD8/n/POO2+PMfp9+vRh0aJFwS9ad+df//pX8Mt//fr1nHDCCQdUe9++fYOzg2HDhvH222/z8ssv069fv2r3nT17Nk8//TRz584NQjErK4tPP/00eE9hYSGtWrUiLy8PiHRLmRkXXXQRr7766gHVXk4XmqXeCnN0EMAHBW9BVnZo7UvtDBo0iJtuuok5c+YwatQoysrK+M1vfsN1113HYYcdRnZ2NnfffTe7d+9mw4YNrFixAogEx+GHH05GRgaff/45ixYtYsCAAUG7EydO5NZbb+Waa65h+vTpnHPOOdx5553ceeedmBlvvfUWPXr0qLa+jIwMmjZtGpwBPPTQQ8FZQ79+/bjlllvo168fjRo1olmzZixcuLDaT/HPPvssU6ZMYenSpTRu3DjYfv7553PppZfy61//mqKiIt5//31OOeUUPv/8cwoKCti0aRMtWrTg+eefP+BAK6dQkHorzNFBAH9eXRpa2w1J22OaVjtiqMbtVcHMmD9/Ptdeey233normzZtYuTIkUE3Tp8+fWjTpg1du3alS5cu9OzZE4CTTjqJHj160LlzZ9q2bUufPn32afv222/niiuu4IYbbmDChAn86le/olu3brg72dnZMY84mj17NldffTXffPMNbdu25cEHHwQiQ1+B4Mzg9NNPp7CwkKZNI1/zkCFDuO+++/bpQrruuuvYsWMHZ511FhC52Dxjxgw6d+7MRRddxIknnkhqaip/+9vfSElJoVWrVowbN45+/fqRlpbG8ccfz6xZs2KqvTqa+0jqrQXTx4cbCk/m85th3UJpe0FhU4aOGR9K22F799134/apMx5effVVLrnkEh5//PF9LkBL9Sr796xq7qOkPFPQLKkiB4/TTjuNTz7Z70JhEmdJeaFZQ1JFRMKRlKEgIiLhSMruIzk4LHxxCY2O2xJa+x98/CUQzjUFkWSlUJB6a/OW7ZQcflz1b6ylbTu+CK1tkWSl7iMREQnoTEFEqhTvmwhjmVZ80qRJPPzww6SkpNCoUSPuueceTj31VG6//XZyc3P3uMHrQNRkSu3KzJo1i1WrVnHXXXft9z15eXmMGTOG0tJSUlJSuPnmmxk5ciQAo0ePZunSpZQPmpk1axbdu3dn7ty5TJkyBYAmTZowffp0TjrppFrVWFMKBRGpUrxvIqxuWvHXXnuNp59+mjfffJNDDz2U//73v+zcuROI3Hz24x//OG6hUFNlZWWkpKTUaJ/GjRszZ84cOnToQFFREb169eKcc84J1kv405/+xIUXXrjHPm3atGHp0qU0bdqURYsWkZubyxtvvBGvL6NKSdl9pKmzRRqujRs3kpmZGSyok5mZSatWrZg2bRpFRUUMHDiQgQMHAvufKjs7O5tx48bRs2dPunbtytq1awEoLi7m7LPPpkePHvz85z/fY8K5H/7wh/Tq1YvOnTszc+bMYHuTJk0YO3Ysp556Kq+99hoPPvggHTt2pH///rzyyivVfj0dO3akQ4cOALRq1Yqjjz6aTZs2VbnPaaedFtwFXXEq7bqQlGcK7r4AWJCTk3NVomuR5LXtm60881L1/6lrY+GnTRg6JpSmG7yzzz6biRMn0rFjR84880xGjhxJ//79+d///V/+8pe/sHjx4qC7Z9KkSTRr1oyysjIGDRpEfn4+3bpFRpRlZmby5ptvcvfddzN16lTuu+8+JkyYwOmnn87YsWN55pln9vjl/8ADD9CsWTO2bdvGySefzAUXXEDz5s3ZunUrXbp0YeLEiWzcuJFLL72U1atXk5GRwcCBA4P5kp566ilWrVrFxIn7X1VuxYoV7Ny5k3bt2gXbbr75ZiZOnMigQYO47bbb9lld7v777w+m0q4LSRkKIvGwm0ahjW76bEM+C6aPD6VtaFjLfe6tSZMmrF69muXLl7N48WJGjhzJbbfdxujRo/d577x585g5cybffvstGzdupKCgIAiFESNGANCrVy8ef/xxAJYtWxY8Pu+884JP4wDTpk1j/vz5AHz66ae8//77NG/enJSUFC644AIA3njjDQYMGECLFi0AGDlyJO+99x4Qmbzu/PPP3+/XtXHjRn7yk58we/ZsGjWKdNJMnjyZY445hp07d5Kbm8uUKVMYO3ZssM/ixYu5//77efnll2v+jawlhYJICDJSd4U6b1NDWu6zMikpKQwYMIABAwbQtWtXZs+evU8olE+VvXLlSpo2bcro0aP3mCq7/BN3SkoK3377bbC9srUalixZwgsvvMBrr71G48aNg/UVANLT0/e4jlDZ/tUpLS3lvPPO4w9/+AO9e/cOtrds2TKo9fLLL2fq1KnBa/n5+fzsZz9j0aJFNG/evMbHrK2kvKYgIg3XunXreP/994PneXl5HH/88QAcccQRfP3110DlU2VXp1+/fsydOxeARYsWsXlzJLhLSkpo2rQpjRs3Zu3atbz++uuV7n/qqaeyZMkSiouL2bVrF4899li1x9y5cyfDhw9n1KhR/OhHP9rjtY0bNwKRtR2eeOIJunTpAsD69esZMWIEDz30EB07dqz2GPGkMwURqVJas9ZxPTNJa9a6yte3bNnCL37xC7766itSU1Np37590Pefm5vLueeeS8uWLVm8eHG1U2Xvbdy4cVxyySX07NmT/v3707p1pJbBgwczY8YMunXrRqdOnfb4NF9Ry5YtGT9+PN///vdp2bIlPXv2pKysDNj/NYV58+axbNkyiouLg+mty4eeXnbZZWzatAl3p3v37syYMQOIrP1QXFzMNddcA0Bqauo+Cw+FRVNnS7118eDenJ/TMrT25y96meHnnh5K288tXc2sG4aH0jaE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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYkAAAEGCAYAAACQO2mwAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAABAH0lEQVR4nO2deXxU1fn/3wcSCBCWGBK2IAmEoAIhLCKyhICIuKMVWnFfGpWv2vZXtV9tlWq1VOu3tVpRYxGxFdpgK24giiaC4MKWUAGVYAiEJUgMSyBAgPP7484MM5O5s97ZyPN+vfKazF3O/cydO+c55znPeY7SWiMIgiAInmgRbQGCIAhC7CJGQhAEQTBFjIQgCIJgihgJQRAEwRQxEoIgCIIpYiQEQRAEUxKiLcBKOnXqpLOzs6MtwyeHDh2iXbt20ZbhE9FpLaLTOuJBI8SPzjVr1uzVWqd52ndaGYkuXbqwevXqaMvwSWlpKQUFBdGW4RPRaS2i0zriQSPEj06lVJXZPnE3CYIgCKaIkRAEQRBMESMhCIIgmHJajUkIghAeGhsbqa6u5siRI9GWAkDHjh3ZtGlTtGX4JNZ0JiUlkZGRQWJiot/niJEQBMEn1dXVtG/fnszMTJRS0ZbDwYMHad++fbRl+CSWdGqtqa2tpbq6mqysLL/PE3eTEDp1VVA603gVTkuOHDlCampqTBgIITiUUqSmpgbcGxQjIYRO+TxY8ZzxKpy2iIGIf4L5DsVICKEzaBqMusd4FQRg7bY67pm/lsueW84989eydltdyGVWV1dz5ZVX0rdvX3Jzc7n77rs5evRo0OVlZmayd+9ev44tLS2lY8eO5OXlkZeXx4QJEwD47W9/y9NPPx20Bm/cf//9nHXWWeTm5nLVVVexb98+x76ZM2eSnZ1Nv379WLJkiWP7/PnzGThwILm5uUyaNMnvz+cNMRJC6KT0goIHjVeh2fOnD7/hupe/4N31u/hqxwHeW7+L617+gj99+E3QZWqtufrqq5k8eTKbN29m3bp1NDQ08MADD1io3DtjxoyhrKyMsrIyli5dGvbrXXjhhXz11VesX7+enJwcZs6cCcDGjRv55z//yYYNG3j//feZPn06J06c4Pjx4/zsZz+jpKSE9evXk5uby1//+teQdYiREATBMtZuq+PlZZU0NJ7AvujlSQ0NjSd4eVll0D2Kjz/+mKSkJG655RYAWrZsyZ///Gdee+016uvrefXVV7n77rsdx1922WWUlpYCcNdddzFs2DD69+/PjBkzmpTd0NDApEmTePnllzl06BC33nor5557LoMHD+att97yW2NZWRkjRoxwtPzr6ur4/vvvGTp0KADl5eUopdi2bRsAffr04fDhw6blTZw4kYQEI7ZoxIgRVFdXA/DWW2/xk5/8hNatW5OVlUV2djZffvklWmu01hw6dAitNQcOHKB79+5+6zdDjIQgCJYxZ0UlR46f8Ljv6PETzFlRGVS5GzZscFS2djp06EBmZiYVFRVez33iiSdYvXo169ev55NPPmH9+vWOffX19Vx++eVMmzaNn/70pzzxxBOMHz+eVatWUVJSwv3338+hQ4cAWL58ucPd9MQTTzS5zo033siTTz7J+vXrGThwII8++ihpaWkcOXKEAwcOsHz5coYNG8by5cupqqoiPT2dtm3bcskll7Bz506vn+GVV17h4osvBmDHjh307NnTsS8jI4MdO3aQmJjICy+8wMCBA+nevTsbN27ktttu835j/UCMhCAIllG595CjB+HOSQ1b95q3nL2htfY46KrNLuZEcXExQ4YMYfDgwWzYsIGNGzc69l155ZXccsst3HjjjQB88MEH/OEPfyAvL4+CggKOHDniaPk7u5t+/etfu1xj//797Nu3j7FjxwJw0003sWzZMgBGjhzJihUrWLZsGQ899BDLli1j+fLljBkzBoBFixZ5bfE/8cQTJCQkcN1115l+ZqUUjY2NvPDCC6xbt46dO3eSm5vrcFGFQswbCaVUJ6XUG0qpr5VSm5RS50dbkyAInsnq3I4WJgE0LRRkdm4bVLn9+/dvkrzzwIED1NTU0K9fPxISEjh58qRjnz3Ms7KykqeffpqPPvqI9evXc+mll7qEgI4aNYrFixc7Kl6tNf/+978dxmDbtm2cffbZQWm2M2bMGEfv4corr6S8vJxPP/2U/Px8n+fOnTuXd999l9dff91hJDMyMti+fbvjmOrqarp3705ZWRlguLGUUkydOpWVK1eGpB3iwEgAfwHe11qfBQwCYmf6oiAILtwyKovWCS097mud0JJbRvk/icuZCy64gMOHD/Paa68BcOLECX75y19y991306ZNGzIzMykrK+PkyZNs376dL7/8EjAMSbt27ejYsSM1NTUsXrzYpdzH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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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hmEYLmGCahiG4RImqIZhGC5hgmoYhuESJqiGYRguYYJqGIbhEiaohmEYLtFixjHt1KmT5ufnp9sNwzCynDVr1uxS1RMirWsxgpqfn8/q1avT7YZhGFmOiHwUbZ1V+Q3DMFyixUSo8fCvf/2L6dOns2LFCj7//HPX0s3JyaFLly7893//N7/85S/p0KGDa2kbhpF+TFDDePfddxkzZgz33nsvv/3tbznmmGMQcefDrnV1dWzdupXp06czatQoli9fTps2bVxJ2zBSiaqyoXofvTp3cO3+aA6YoIbx0EMP8cADD/DTn/40Kel37NiR2bNnc84551BcXMyoUaOSYiebOXLkCB6Ph0OHDqXbFSMKR+q87D5wmLrP2tKmVfNsOczNzaVbt25xBT0mqGEsW7aMJ554Iqk2cnJyGDNmDG+++aYJagQ8Hg95eXnk5+db9JOhqCqHjtSR26ZVszxHqsru3bvxeDx0797d8X7Ns2hpAgcOHOC4445Lup3jjjuOAwcOJN1ONnLo0CE6duzYLG/U5oKI0K5t62Z7jkSEjh07xl1LykhBFZFLRWSTiGwRkUkR1heKyF4RKfVP97hsv8GyyZMnM336dADefvttzjjjjOC63r17s3z5cgAeeOABrr/+egA++eQTevbsyZdffunIhvEVlj8tB1Xl4OFaMu2T9olcgxlX5ReRVsAM4CLAA7wvIvNVdUPYpm+r6mWp8Gnnzp0899xzbNmyBYARI0awadOm4Pr169cH/991113B/1//+tcZOXIkTz75JDfddFMqXDWMrOPQkTo++uwLTjn+aNq1zThJiotMjFCHAFtUdZuqHgZeBL6TTodmzZrF6NGjadeuXdz7XnXVVUlvkzXcY/fu3RQUFFBQUMBJJ51E165dg/OHDx921dby5cu57LLIMcH06dP54osvgvOjR4+mpqbGVftuUltbS6dOnZg8eXLc++a2acUpxx9NbptWDdbl5+eza9cuAM4991wAtm/fzgsvvBC3nVmzZnHjjTfGvV88ZKKgdgUqQ+Y9/mXhnCMi60TkDRHpnUyH3njjDc4///zg/PLly+nWrVtwPj8/n+LiYgDuvfderr766uC6oUOHsm3bNj76KOrLFUYG0bFjR0pLSyktLWXixInceuutwfm2bdtSW1ubEj/CBXXhwoUce+yxKbGdCIsXL+aMM87gpZdeirvq7rQ99p///CeQuKCmgkwU1Ei5Gn6G1gKnqOpZwKPAvIgJiUwQkdUisnrnzp0JO1ReXl6vzTQeWrduzTe/+U3WrVuXsH0jvVx33XXcdtttjBw5kjvvvJNVq1Zx7rnn0r9/f84999xg88/QoUPrNf8UFhayZs0aPv/8c3784x8zePBg+vfvT1FRUUx7jzzyCFVVVYwcOZKRI0cCX0Vq27dv58wzz+T666+nT58+XHXVVRQXFzNs2DBOO+00Vq1aBeDI5uWXX87ChQvrHecrr7zC+vXrGTJkCAUFBfTr149///vfjebRnDlzuPnmmzn55JN57733gsvz8/O56667OOeccxg0aBBr167lkksuoUePHjz++OOAL0A577zz+O53v0uvXr2YOHEiXq+3gY2vfe1rAEyaNIm3336bgoIC/vjHPzaIPC+77LLgM41nnnmG008/nfPPP5933nknuM3OnTv5/ve/z+DBgxk8eHC9dU0hEwXVA3wjZL4bUBW6garuU9UD/v8LgTYi0ik8IVV9UlUHqeqgE06IOJaBI2pqasjLy0t4/7y8vIyurjUHVJX1VXuT9mBj8+bNFBcX8/vf/54zzzyTFStWUFJSwn333RdsNx8/fjwvvfQSANXV1VRVVTFw4ECmTp3KBRdcwPvvv8+yZcu44447Yr6B9/Of/5wuXbqwbNkyli1b1mD9li1buPnmmykrK+ODDz7ghRdeYOXKlTz88MM88MADAI5sjh8/nrlz5wJw+PBhli5dyujRo3n88ce5+eabKS0tZfXq1fVqY5E4ePAgS5cu5bLLLuOKK65gzpw59dZ/4xvf4N1332XEiBFcd911/O1vf+O9997jnnu+epa8atUqfv/731NeXs7WrVv5+9//HtXetGnTGDFiBKWlpdx6661Rt6uuruZXv/oV77zzDkuWLGHDhq8ew9x8883ceuutvP/++7zyyivBB8lNJRMF9X3gNBHpLiJtgfHA/NANROQk8dcPRGQIvuPYnSyHjjvuOPbv35/w/vv378/o6lpzYEP1Pm6YvZYN1fuSkv7YsWNp1crXxrd3717Gjh1Lnz59uPXWW4NR6bhx43j55ZcBeOmllxg7dizgqw5PmzaNgoICCgsLOXToEB9//HHCvnTv3p2+ffuSk5ND7969+da3voWI0LdvX7Zv3+7Y5qhRo3jzzTf58ssveeONNzjvvPNo164d55xzDg888AAPPvggH330UaPPDhYsWMDIkSM5+uij+f73v8+rr75KXV1dcP2YMWMA6Nu3L0OHDiUvL48TTjiB3NzcYKAxZMgQTj31VFq1asUVV1zBypUrE86fAP/6178oLCzkhBNOoG3btlx++eXBdcXFxdx4440UFBQwZswY9u3b16R7PEDGPVJT1VoRuRFYBLQCnlbV9SIy0b/+ceAHwA0iUgscBMZrEvtc9OvXj82bNzN48OC4962trWXLli2cddZZSfDMCNCrcwdmXj2AXp2TMz5C+/btg/+nTJnCyJEjefXVV9m+fTuFhYUAdO3alY4dO1JWVsbcuXODDyNVlVdeeaVBs9Enn3wS/H/JJZfwySefMGjQIJ566qmYvhx11FHB/zk5OcH5nJycYBtvNJuh5ObmUlhYyKJFi5g7dy5XXHEFAFdeeSVDhw7l9ddf55JLLuGpp57iggsuiJrOnDlzeOeddwgMj7l7926WLVvGhRdeWM/fUF/D/Q1vP42ny1Lr1q3rNRGE9h2Nlo7X6+Xdd99N6EFzLDIxQkVVF6rq6araQ1Wn+pc97hdTVPUxVe2tqmep6tmq+s9k+jN69GjeeuuthPZdtWoV+fn5nHLKKS57ZYQiIvTu4t64C7HYu3cvXbv6npPOmjWr3rrx48fz0EMPsXfvXvr27Qv4xPLRRx8NNkeUlJQ0SHPRokWUlpYGxTQvL69JEZMTmwF/n3nmGd5++20uueQSALZt28app57Kz3/+c8aMGUNZWVlUO/v27WPlypV8/PHHbN++ne3btzNjxowG1f7GWLVqFR9++CFer5e5c+cyfPjwqNuG501+fj6lpaV4vV4qKyuD7chDhw5l+fLl7N69myNHjgRrDwAXX3wxjz32WHC+tLQ0Ln+jkZGCmmlcc801LFy4kIMHD8a97/PPP8/EiROT4JWRLn75y18yefJkhg0bVq9qC/CDH/yAF198kXHjxgWXTZkyhSNHjtCvXz/69OnDlClTGrUxYcIERo0aFXwoFS9ObV588cWsWLGCCy+8kLZt2wIwd+5c+vTpQ0FBAR988AHXXHMN4AssqqrqPc7g73//OxdccEG9yPM73/kO8+fPj/hCSzTOOeccJk2aRJ8+fejevTvf/e53o27br18/WrduzVlnncUf//hHhg0bFmwGuf322xkwYAAAnTt35t577+Wcc87hwgsvDC4H34O/1atX069fP3r16hV8QNZUJNPeTkgWgwYNUicDTLdu3ZpDhw7RunX91pC77rqLE088kVtuucWxzU8//ZTzzz+fkpIScnNz662bOXMmZWVlzJw503F6LYWNGzfSs2fPdLthpIjly5fz8MMPs2DBgnS70oBI16KIrFHVQZG2z7g21Ewl8PQ0Hk488UQ2btyYBG8Mw8hETFDDaNOmDV9++WWDCNVtvvzySxsL1XCFbB/5qbCwMPhgL9uxNtQw+vbtW69jcrJ49913gw8tjIa0lKYoNwi8C3/oSF3jGxuOSeQaNEEN40c/+hG33357g8Z3twh0Z1m2bFnMhveWTG5uLrt37zZRdUisd+GNxAiMhxr+7KMxrMofxsSJE/nkk0/o3bs3PXr0cP0TKNu2baNdu3a89tprdOrU4OUuA+jWrRsej4emvC5sGE0lMGJ/PNhT/igcPHiQdevWuToIdOAjfWeccUZWtnUZhmFP+ROiXbt2nH322el2wzCMLMLaUA3DMFzCBNUwmjHJHoUrETLRJ7cwQTWMNJJscUn2KFyJkIk+uYUJqmGkkWSLS7JH4UqETPTJLRIWVBG5SET+LCIF/vkJrnllGCkgE6qeyRaXVI7C5ZRM9MktmhKh/g9wB3C1iFwAFLjikWGkiHRXPVWVDdX76NW5Q7MUl5ZIUwR1p6rWqOrtwMVA/KMvG0YaSXfV04mgZ0IUbTinKYL6euCPqk4Cnmu6O4aROtJd9XQi6OmOoo34SFhQVTX8M4pHN9EXw4hKc4rUAscCNCro6Y6iMw1VpWJHDet3ZOa10JSHUi+FTC8D7nw20DAikMpIzS3xjpZOPMeS7Cg6lQWVG7Y2VO/j+mfX8JNnV2dk1N6UKv8+VR3nn8YCxW45ZRjhpDJSc0u8o6XjxrG4JYSpLKjcsNWrcweeunYgf7l2UGZG7aqa0AR0D5s/PtG0UjENHDhQk4nX69WKHTXq9XqTuk+2kw3H7NTHwHZ1dXURt3eSTnga0dIK36eo1KPDH1yqFTtq4ju4KPZTcT4i2WpsWTx5GGmbZBwfsFqj6IzjCFVE7g4T4g9D1k1X1c9c0nhE5FIR2SQiW0RkUoT1IiKP+NeXiciASOk0BY0QAQSWeb3eBusSKX0D+6yv2lsvPY3RThTJr1QQ69ijbRd+DKrKa2VVTJy9psExN8Unt/IikB403rYJX52/BeXVTPzrGl4rq6rni4jQq3MHNlTvC95w4XkYmkbob6zraEP1Pn73j03ccckZwSgtPC9i5U3ousaaFOJJtzFCbQXS2VD11T1QsaOGCk8Nr62r4md/Xc38dTt4bZ3veqnYUcO8kkrml3jqfTIaYH3VXn4ya3XQr9A8Xr/Dt67CU8P8dTuoq6tL6v0TT5X/e4E/IjJMRL4Wsu48txwSkVbADGAU0Au4QkR6hW02CjjNP00AXP/SXSSxC7/4Qy/6aNW40AswXCgD+6Dw42fe57V1O4J2orUTNaXa1NjNEOpf4IIM/AYu/EjHHpruhup9TPzrGh5fsZWfPLuanzy7moodNRSVenitdAcP/eMDfnHRaazYvJOfPbc6KEIB2xUe5w8cnOZFYyIf9L1qHz+ZtZoNVfscCVLPk/KYefUAvt3nJK4Y+g1+949NQV8iCUagMAnkYSD9mVf50rjtom+idV7+78r+9DwpL6rPvTp34PEfDuS/+nUJCmF4XkTLm3gLtdD7oGJHDa+V7gjmUax8Dvc9/Dg2VO/jZ8+tZvnmT5hxRQHbPj3AtU+/z7XPvM/U1zdy5dCTeWDhB0x9fSN3XHIGH+76gtvmlnHz3HU8vmJrvUJJ8OWBIPWuv4mz17B1l2/4zbe37OK2uet44u1tyW3iiBa6hk/AWv/v3cAm4N/At/zLSpym48DOOcCikPnJwOSwbZ4ArgiZ3wR0jpVuvFX+QFWhwlOjIx58M1htaKxaFl7FqNhRo8OnLdV5JZVatLZSB9y3WIdOLa5XVavw1NRb7vV6tdyzRys8iVUjo1Gx46tjiXasQ6cW69CpxVpU6tERD74Z/C337Il67KHp1tXV6Yxlm3XYb4t1Xkmlllfu0RlvbtbukxZo/18v0nkllcH5e4rKgtXWih0+25HyJ9r5iZZHkY57+LSlOmPZZh0ydUm99EN9L/fs0aFTi4PHOnzaUi0q9TRIP3xdxY4aHfbbYp2xbLPW1dXVS7fcs0fLKj/TGW/68qSo1BPMw9Brq2JHjfb/9SLtfucCfXXtx1pU6tFh03xpDr5/sQ64b7FWeL7Kk/DrIDw/AvPllb5loTYDvofabyyf562p1L6/+of2vecNHXDfYi337KnnR11dXbAZIvTaGTq1WIfcv0Qfe3OT9r9vkQ65f3EwD2Ys26ynTn7dd4y/Wax973lDX13zcdDfwPHU1dVpWeVn+uqaj3XG0s1B/wO/tbW1wWst4MewafXzura2NrhtaHNCWeVnWlTiCZ43JxCjyh+P0G0CXgH+CuQCA4B1wOPARqfpOLDzA+CpkPkfAo+FbbMAGB4yvxQYFCGtCcBqYPXJJ5/sOMNCiVfAwkUr0N41ZOoS7f/rRdr/14u0qKSyQZuRU3FoCtGOJfTmD72I42nTCy1wIonNI8UbdcbSzVr28WdB8Qm/uEMFIFQoGvPZaZvjsGk+kY+Wfvj/aO2U4etC5yMVPEWlHj110gKdsWxzzLbCeWsrtf+vF+mMpZuDYjpsWrE+9uYmHTJ1SVDEQo+/XsG8o37hH7juQgvI0Pxyem0HxP6UOxdo33veqHf9hhZW4SIWEMUi/3H1//UinfHm5mC+BcSvtrZWi0oqfQWdpyai/fCgpra2NlhwhxeUTttdi0o92v++RXrqpNe1qNQTMw9CcUtQjwC3hi1rCzwI1DpNx4GdsREE9dGwbV6PIKgDY6Wb7IdSAaI1skcSi0zBzYb7SJFTxY4aLSrxaI/Jr/sErQkFVLideKKsePM+nocdsfwJCEe0KCg8ygsIU6SoKtYxRSrYAgWIk4IxVj6UVX6m89b6osBQMa6trdXH3tzsizxLGkbzqqrlnj065P4lWlRSmdADvEjrwoU8vKBsjMD+r679OD0RaqqmTKnyG5FJVHwbE5VE7TnxJ5ooJ4NoBWosHyNFYIHfWFF4rONys5CM5XNRqUeH3L+kXjNAsn0JLUwSLSia4lO2CWprYBvQ3R8BrwN6h23zbeANQICzgVWNpWuC6g6pFCe3SLa4NEZjeRbNv8ai8GQcl9M0Q6PqVDRXhZLuazCWoGbkR/pEZDQwHWgFPK2qU0VkIoCqPi6+R5uPAZcCXwA/UtWYX+CL9yN9RmRUbYSkeGlqnqUyz9dX7eWG2WuZefUAenc5Jqm2EiXd12Csj/RlpKAmAxNUw2icdItVNhBLUG3EfsOIA9XmM0hLJNI9Ale2Y4JqGHFgw+kZsTBBjZPmHqEYscnG4fTsmk0dJqhxYhFKyyYbq8R2zaYOE9Q4ycYIxWjZ2DXrIxWRuglqnGRjhJJphF/YViVNLnbN+khFpG6CaqQcpyMjGYabpCJSt36oRsoJ7+tofR+NbCJWP9TWqXbGMAJV0GjzhpGtWJXfMAzDJUxQDcMwXMIE1TAMwyVMUA3DMFzCBNVICdbX1GgJmKAaKcH6mhotARNUIyXY649GS8AENQ20xOqvvf5otARMUNOAVX8No3ligpoGrPprGM0Te/U0DdirlobRPMkoQRWR44G5QD6wHRinqnsibLcd2A/UAbXRBiowDMNIJZlW5Z8ELFXV04Cl/vlojFTVAhNTwzAyhUwT1O8Az/r/Pwv8d/pcMYyWS0vsieIGmSaoX1fVagD/74lRtlNgsYisEZEJKfPOMFoI1hMlMVLehioixcBJEVb9vziSGaaqVSJyIrBERD5Q1RURbE0AAoJ7QEQ2RUmvE7ArDvtuY/bNfsbZlza57frceehguuynkHjtnxJtRUaN2O8XvEJVrRaRzsByVT2jkX3uBQ6o6sNNsLs6nW2xZt/sm/3mYT/TqvzzgWv9/68FisI3EJH2IpIX+A9cDFSkzEPDMIwoZJqgTgMuEpF/Axf55xGRLiKy0L/N14GVIrIOWAW8rqr/SIu3hmEYIWRUP1RV3Q18K8LyKmC0//824CyXTT/pcnpm3+yb/RZoP6PaUA3DMLKZTKvyG4ZhZC0mqIZhGC7RIgRVRE4RkbSNRmL2026/Tbpsm/30208lzVpQ/V2sfgd8CIz0L0vZCMdmP+32vyYi04EHReTcVNk1+xllf5qIjBORbqmw2WwFVUR+DPwL+Bz4I3AhgKboKZzZT7v9gcAS4EugCnguxWJu9tNrvz+wGF9PpnzgKRHpnmy7GdVtyi38b1kdjW/4vw0iciXQW0Raq2qt2W/e9v10BDar6p1+n4YBXYAdZr9F2O8MbFLV2/32hwJ3i8jdgfFCkkGziVBFpKuIHAu+gVVU9TFV3eBffRi4JJk3s9nPHPt+WgEnisgvRORd4FTg9yLSR0Ramf1mb/9E4BMROc0//w7wTaC/27ZDyXpBFR+/BiqB60MbwEUkcHyvAUf8paTZb972j/Kv+ifwG+Bs4C1VPQvYCvwU6Gr2m73994E84H4R+T1wAfBv/E1PIdemq2S9oAI98LXT3QIMw1cKAaCqXv/fY4B1JKeJw+xnlv1T/bb3quo/gU3A2/5tf4Pvxsoz+83e/npgKr4vgOwBvodvwPphIpIbcm26SnMQ1A+B51T1EWAncJWIHB26gap+im/Irf7geulk9jPUvojkAm2AHuIbSCcf3wOSw2a/WdtvD75X1lX176p6v6oexjeQ0mJVPeSi/fqoatZMQJuQ/zkh/wOv0J4GLAfOA1r7lx3l/70JmG32W4z9tv5l/w08DqwESoDxZr9F2A9ef/gehr0OrAYubco12KiPyUzcVUdhMvAMcErY8q+HZeo9wJ8j7P91s9+i7Z9v9lumfXxNTv/bFPtOp4yv8osE+671Bo4jZDQqEbkbX7sJgACo6n3ASSLyZxEpFZHz/Ms/Mfstzv46ETnfv/wts98i7Y9QX3vujETsx+2vX8EzEhERDRQ/Iq/g+7T0QWChqv5TRPJUdX/YPl8HNgKbgTsTPZFm3+yb/ay3P0lVlydqPxEyLkIVkeNF5OcicgrQ1r+sLfAeMA9fI/eZItIR8Ibt2wrfK46TVfXsRE6m2Tf7Zr/Z2F8er/0mk4p2BacT8G18JctLwBPAwyHrVvp/R+HrY/ZPoLd/2Q+A0Wbf7Jt9s5/OKdNePe0KPKWqD4lIF/yfilbVOcAKEZkI/C++/oyL8HWZANgNbIiYotk3+2bf7KeKdCk5/vbbsGV/ACaGzH8P+Lf//1J8JVMhUICvK8ZlZt/sm32znylTeoz6+yaGzOf4f38ArA9btxz4IdAu9GQAA8y+2Tf7Zj+TppQ/lBKR64F/i8g1gWWq6hWRHFX9G3BQRG4P2eXP+Eqkw/7926iPtWbf7Jt9s59JpExQReQCEVmKL4z/J3DEv1z8mRl4YvcT4H/FN9wWwOnAx6paB6CqR8y+2Tf7Zj8TSbqgikiO+N6tvR54VFVH4xt1JjjykL+EyheRZ4CPgAeB60TkHWAMvlfGzL7ZN/tmP7Nxuw0hMOF7Evcw8BgwLGzdcHz9yr4WMv82cJd+1UZyNE3oCmH2zb7Zb7n20zUlJ1FfhvwfMBu4CijG193haP/6wcBfgHz/fC7QIWT/HLNv9s2+2c+2KTmJQgd87SR5/vlLgD8BP/TPn4gv7D/DP98qkJFE6E5h9s2+2Tf72TAlpQ1VVffhe+/2Ov+id/AN3XW2iHRT3/iYy/F1k0C/anD2qj9nzb7ZN/tmP9tI5kOpV4ECEemsqgeAMnxdH04UEcH3dsMR8b2na/bNvtk3+1lPMgV1Jb5Muw5Aff3GBuNrR1FgIb7XzNwcvdvsm32zb/bTRtLe5VfVahGZB0wTkS34Xhs7BNT61y9Plm2zb/bNfsu2nzbiaXBNZMI3OszTwAfAjcm2Z/bNvtk3++maUjLAtPg+LayaxO+ym32zb/bNfrrJ6BH7DcMwsomMG7HfMAwjWzFBNQzDcAkTVMMwDJcwQTUMw3AJE1TDMAyXMEE1DMNwCRNUwzAMl/j/KKhHiCi8hDcAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "if run_local:\n", + " %run plot_catalog.ipynb" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Merge parallel processing on cloud" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.260305Z", + "iopub.status.busy": "2022-08-11T15:42:43.260193Z", + "iopub.status.idle": "2022-08-11T15:42:43.268304Z", + "shell.execute_reply": "2022-08-11T15:42:43.268088Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.260290Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + " def merge_catalog(\n", + " index_json: InputPath(\"json\"),\n", + " config_json: InputPath(\"json\"),\n", + " catalog_csv: OutputPath(str),\n", + " picks_csv: OutputPath(str),\n", + " bucket_name: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + "):\n", + "\n", + " import json\n", + " import os\n", + " from glob import glob\n", + "\n", + " import pandas as pd\n", + " from minio import Minio\n", + "\n", + " minioClient = Minio(s3_url, access_key='minio', secret_key='minio123', secure=secure)\n", + "\n", + " with open(index_json, \"r\") as fp:\n", + " index = json.load(fp)\n", + " \n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " objects = minioClient.list_objects(bucket_name, prefix=f\"{config['region']}/gamma\", recursive=True)\n", + "\n", + " tmp_path = lambda x: os.path.join(\"/tmp/\", x)\n", + " for obj in objects:\n", + " print(obj._object_name)\n", + " minioClient.fget_object(bucket_name, obj._object_name, tmp_path(obj._object_name.split(\"/\")[-1]))\n", + "\n", + " # files_catalog = sorted(glob(tmp_path(\"catalog_*.csv\")))\n", + " # files_picks = sorted(glob(tmp_path(\"picks_*.csv\")))\n", + " files_catalog = [tmp_path(f\"catalog_{node_i:03d}.csv\") for node_i in range(len(index))]\n", + " files_picks = [tmp_path(f\"picks_{node_i:03d}.csv\") for node_i in range(len(index))]\n", + " print(f\"Merge catalog: {files_catalog}\")\n", + " print(f\"Merge picks: {files_picks}\")\n", + "\n", + " if len(files_catalog) > 0:\n", + " catalog_list = []\n", + " for f in files_catalog:\n", + " if not os.path.exists(f):\n", + " continue\n", + " tmp = pd.read_csv(f, dtype=str)\n", + " tmp[\"file_index\"] = f.rstrip(\".csv\").split(\"_\")[-1]\n", + " catalog_list.append(tmp)\n", + " merged_catalog = pd.concat(catalog_list).sort_values(by=\"time\")\n", + " merged_catalog[\"match_id\"] = merged_catalog.apply(lambda x: f'{x[\"event_index\"]}_{x[\"file_index\"]}', axis=1)\n", + " merged_catalog.sort_values(by=\"time\", inplace=True, ignore_index=True)\n", + " merged_catalog.drop(columns=[\"event_index\", \"file_index\"], inplace=True)\n", + " merged_catalog[\"event_index\"] = merged_catalog.index.values + 1\n", + " mapping = dict(zip(merged_catalog[\"match_id\"], merged_catalog[\"event_index\"]))\n", + " merged_catalog.drop(columns=[\"match_id\"], inplace=True)\n", + " merged_catalog.to_csv(catalog_csv, index=False)\n", + " del merged_catalog\n", + "\n", + " pick_list = []\n", + " for f in files_picks:\n", + " if not os.path.exists(f):\n", + " continue\n", + " tmp = pd.read_csv(f, dtype=str)\n", + " tmp[\"file_index\"] = f.rstrip(\".csv\").split(\"_\")[-1]\n", + " pick_list.append(tmp)\n", + " merged_picks = pd.concat(pick_list).sort_values(by=\"phase_time\")\n", + " merged_picks[\"match_id\"] = merged_picks.apply(lambda x: f'{x[\"event_index\"]}_{x[\"file_index\"]}', axis=1)\n", + " merged_picks.drop(columns=[\"event_index\", \"file_index\"], inplace=True)\n", + " merged_picks[\"event_index\"] = merged_picks[\"match_id\"].apply(lambda x: mapping[x] if x in mapping else -1)\n", + " merged_picks.drop(columns=[\"match_id\"], inplace=True)\n", + " merged_picks.to_csv(picks_csv, index=False)\n", + " del merged_picks\n", + " \n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/gamma_catalog.csv\",\n", + " catalog_csv,\n", + " )\n", + " \n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/gamma_picks.csv\",\n", + " picks_csv,\n", + " )\n", + "\n", + " # else:\n", + " # with open(catalog_csv, \"w\") as fout:\n", + " # pass\n", + " # print(\"No catalog.csv found!\")\n", + " # with open(picks_csv, \"w\") as fout:\n", + " # pass\n", + " # print(\"No picks.csv found!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.269617Z", + "iopub.status.busy": "2022-08-11T15:42:43.269540Z", + "iopub.status.idle": "2022-08-11T15:42:43.287964Z", + "shell.execute_reply": "2022-08-11T15:42:43.287552Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.269607Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "merge_op = comp.func_to_container_op(\n", + " merge_catalog,\n", + " # base_image='zhuwq0/quakeflow-env:latest',\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\"pandas\", \"minio\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. HypoDD earthquake relocation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Download and compile HypoDD" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.288365Z", + "iopub.status.busy": "2022-08-11T15:42:43.288297Z", + "iopub.status.idle": "2022-08-11T15:42:43.290807Z", + "shell.execute_reply": "2022-08-11T15:42:43.290590Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.288356Z" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "URL transformed to HTTPS due to an HSTS policy\n", + "--2022-11-29 12:13:21-- https://www.ldeo.columbia.edu/~felixw/HYPODD/HYPODD_1.3.tar.gz\n", + "Resolving www.ldeo.columbia.edu (www.ldeo.columbia.edu)... 129.236.14.15\n", + "Connecting to www.ldeo.columbia.edu (www.ldeo.columbia.edu)|129.236.14.15|:443... connected.\n", + "HTTP request sent, awaiting response... 200 OK\n", + "Length: 1393039 (1.3M) [application/x-gzip]\n", + "Saving to: ‘HYPODD_1.3.tar.gz’\n", + "\n", + " 0K .......... .......... .......... .......... .......... 3% 377K 3s\n", + " 50K .......... .......... .......... .......... .......... 7% 754K 3s\n", + " 100K .......... .......... .......... .......... .......... 11% 94.6M 2s\n", + " 150K .......... .......... .......... .......... .......... 14% 104M 1s\n", + " 200K .......... .......... .......... .......... .......... 18% 735K 1s\n", + " 250K .......... .......... .......... .......... .......... 22% 61.7M 1s\n", + " 300K .......... .......... .......... .......... .......... 25% 83.9M 1s\n", + " 350K .......... .......... .......... .......... .......... 29% 134M 1s\n", + " 400K .......... .......... .......... .......... .......... 33% 780K 1s\n", + " 450K .......... .......... .......... .......... .......... 36% 69.8M 1s\n", + " 500K .......... .......... .......... .......... .......... 40% 41.9M 0s\n", + " 550K .......... .......... .......... .......... .......... 44% 39.0M 0s\n", + " 600K .......... .......... .......... .......... .......... 47% 55.2M 0s\n", + " 650K .......... .......... .......... .......... .......... 51% 57.6M 0s\n", + " 700K .......... .......... .......... .......... .......... 55% 75.9M 0s\n", + " 750K .......... .......... .......... .......... .......... 58% 387K 0s\n", + " 800K .......... .......... .......... .......... .......... 62% 91.4M 0s\n", + " 850K .......... .......... .......... .......... .......... 66% 313M 0s\n", + " 900K .......... .......... .......... .......... .......... 69% 313M 0s\n", + " 950K .......... .......... .......... .......... .......... 73% 313M 0s\n", + " 1000K .......... .......... .......... .......... .......... 77% 274M 0s\n", + " 1050K .......... .......... .......... .......... .......... 80% 328M 0s\n", + " 1100K .......... .......... .......... .......... .......... 84% 289M 0s\n", + " 1150K .......... .......... .......... .......... .......... 88% 274M 0s\n", + " 1200K .......... .......... .......... .......... .......... 91% 11.3M 0s\n", + " 1250K .......... .......... .......... .......... .......... 95% 279M 0s\n", + " 1300K .......... .......... .......... .......... .......... 99% 75.3K 0s\n", + " 1350K .......... 100% 72.0M=1.1s\n", + "\n", + "2022-11-29 12:13:23 (1.17 MB/s) - ‘HYPODD_1.3.tar.gz’ saved [1393039/1393039]\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "for d in hypoDD ncsn2pha ph2dt hista2ddsta; do (cd $d; echo $d; make all); done\n", + "hypoDD\n", + "g77 -I../../include -c hypoDD.f -o hypoDD.o\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "hypoDD.f:654:29:\n", + "\n", + " 654 | & f7.1,f7.1,f7.1,f7.1)'),xav,yav,zav,tav\n", + " | 1\n", + "Warning: Legacy Extension: Comma before i/o item list at (1)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "g77 -I../../include -c aprod.f -o aprod.o\n", + "g77 -I../../include -c cluster1.f -o cluster1.o\n", + "g77 -I../../include -c covar.f -o covar.o\n", + "g77 -I../../include -c datum.f -o datum.o\n", + "g77 -I../../include -c delaz.f -o delaz.o\n", + "g77 -I../../include -c delaz2.f -o delaz2.o\n", + "g77 -I../../include -c direct1.f -o direct1.o\n", + "g77 -I../../include -c dist.f -o dist.o\n", + "g77 -I../../include -c dtres.f -o dtres.o\n", + "g77 -I../../include -c exist.f -o exist.o\n", + "g77 -I../../include -c freeunit.f -o freeunit.o\n", + "g77 -I../../include -c getdata.f -o getdata.o\n", + "g77 -I../../include -c getinp.f -o getinp.o\n", + "g77 -I../../include -c ifindi.f -o ifindi.o\n", + "g77 -I../../include -c indexxi.f -o indexxi.o\n", + "g77 -I../../include -c juliam.f -o juliam.o\n", + "g77 -I../../include -c lsfit_lsqr.f -o lsfit_lsqr.o\n", + "g77 -I../../include -c lsfit_svd.f -o lsfit_svd.o\n", + "g77 -I../../include -c lsqr.f -o lsqr.o\n", + "g77 -I../../include -c matmult1.f -o matmult1.o\n", + "g77 -I../../include -c matmult2.f -o matmult2.o\n", + "g77 -I../../include -c matmult3.f -o matmult3.o\n", + "g77 -I../../include -c mdian1.f -o mdian1.o\n", + "g77 -I../../include -c normlz.f -o normlz.o\n", + "g77 -I../../include -c partials.f -o partials.o\n", + "g77 -I../../include -c ran.f -o ran.o\n", + "g77 -I../../include -c redist.f -o redist.o\n", + "g77 -I../../include -c refract.f -o refract.o\n", + "g77 -I../../include -c resstat.f -o resstat.o\n", + "g77 -I../../include -c scopy.f -o scopy.o\n", + "g77 -I../../include -c sdc2.f -o sdc2.o\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "refract.f:84:16:\n", + "\n", + " 84 | do 23151m=j1,nl\n", + " | 1\n", + "Warning: Deleted feature: Start expression in DO loop at (1) must be integer\n", + "refract.f:126:36:\n", + "\n", + " 126 | xovmax=tinj(lx)*v(lx)*v(1)/(v(lx)-v(1))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "refract.f:126:24:\n", + "\n", + " 126 | xovmax=tinj(lx)*v(lx)*v(1)/(v(lx)-v(1))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "refract.f:126:18:\n", + "\n", + " 126 | xovmax=tinj(lx)*v(lx)*v(1)/(v(lx)-v(1))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "refract.f:155:53:\n", + "\n", + " 155 | xovmax=(tinj(lx)-tid(jx))*v(lx)*v(jx)/(v(lx)-v(jx))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "refract.f:155:47:\n", + "\n", + " 155 | xovmax=(tinj(lx)-tid(jx))*v(lx)*v(jx)/(v(lx)-v(jx))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "refract.f:155:40:\n", + "\n", + " 155 | xovmax=(tinj(lx)-tid(jx))*v(lx)*v(jx)/(v(lx)-v(jx))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "refract.f:155:34:\n", + "\n", + " 155 | xovmax=(tinj(lx)-tid(jx))*v(lx)*v(jx)/(v(lx)-v(jx))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "refract.f:155:27:\n", + "\n", + " 155 | xovmax=(tinj(lx)-tid(jx))*v(lx)*v(jx)/(v(lx)-v(jx))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "refract.f:155:19:\n", + "\n", + " 155 | xovmax=(tinj(lx)-tid(jx))*v(lx)*v(jx)/(v(lx)-v(jx))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "refract.f:161:36:\n", + "\n", + " 161 | xovmax=tinj(lx)*v(lx)*v(1)/(v(lx)-v(1))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "refract.f:161:24:\n", + "\n", + " 161 | xovmax=tinj(lx)*v(lx)*v(1)/(v(lx)-v(1))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "refract.f:161:18:\n", + "\n", + " 161 | xovmax=tinj(lx)*v(lx)*v(1)/(v(lx)-v(1))\n", + " | 1\n", + "Warning: Legacy Extension: REAL array index at (1)\n", + "scopy.f:25:72:\n", + "\n", + " 25 | if(incx.eq.incy) if(incx-1) 5,20,60\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: Arithmetic IF statement at (1)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "g77 -I../../include -c setorg.f -o setorg.o\n", + "g77 -I../../include -c skip.f -o skip.o\n", + "g77 -I../../include -c snrm2.f -o snrm2.o\n", + "g77 -I../../include -c sort.f -o sort.o\n", + "g77 -I../../include -c sorti.f -o sorti.o\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "snrm2.f:67:72:\n", + "\n", + " 67 | 10 assign 30 to next\n", + " | 1\n", + "Warning: Deleted feature: ASSIGN statement at (1)\n", + "snrm2.f:72:20:\n", + "\n", + " 72 | 20 go to next,(30, 50, 70, 110)\n", + " | 1\n", + "Warning: Deleted feature: Assigned GOTO statement at (1)\n", + "snrm2.f:74:72:\n", + "\n", + " 74 | assign 50 to next\n", + " | 1\n", + "Warning: Deleted feature: ASSIGN statement at (1)\n", + "snrm2.f:83:72:\n", + "\n", + " 83 | assign 70 to next\n", + " | 1\n", + "Warning: Deleted feature: ASSIGN statement at (1)\n", + "snrm2.f:89:72:\n", + "\n", + " 89 | assign 110 to next\n", + " | 1\n", + "Warning: Deleted feature: ASSIGN statement at (1)\n", + "snrm2.f:125:72:\n", + "\n", + " 125 | 95 sum = sum + sx(j)**2\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 95 at (1)\n", + "svd.f:49:72:\n", + "\n", + " 49 | DO 1100 J=1,N\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: Shared DO termination label 1100 at (1)\n", + "svd.f:50:72:\n", + "\n", + " 50 | 1100 U(I,J)=A(I,J)\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 1100 at (1)\n", + "svd.f:59:72:\n", + "\n", + " 59 | 2100 S=U(J,I)**2 + S\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 2100 at (1)\n", + "svd.f:69:72:\n", + "\n", + " 69 | 2200 S=U(K,I)*U(K,J) + S\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 2200 at (1)\n", + "svd.f:72:72:\n", + "\n", + " 72 | 2300 U(K,J)=U(K,J) + F*U(K,I)\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 2300 at (1)\n", + "svd.f:82:72:\n", + "\n", + " 82 | 2600 S=U(I,J)**2 + S\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 2600 at (1)\n", + "svd.f:90:72:\n", + "\n", + " 90 | 2650 E(J)=U(I,J)/H\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 2650 at (1)\n", + "svd.f:97:72:\n", + "\n", + " 97 | 2670 S=U(J,K)*U(I,K) + S\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 2670 at (1)\n", + "svd.f:99:72:\n", + "\n", + " 99 | 2690 U(J,K)=U(J,K) + S*E(K)\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 2690 at (1)\n", + "svd.f:117:72:\n", + "\n", + " 117 | 3100 V(J,I)=U(I,J)/H\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 3100 at (1)\n", + "svd.f:121:72:\n", + "\n", + " 121 | 3200 S=U(I,K)*V(K,J) + S\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 3200 at (1)\n", + "svd.f:123:72:\n", + "\n", + " 123 | 3300 V(K,J)=V(K,J) + S*V(K,I)\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 3300 at (1)\n", + "svd.f:129:72:\n", + "\n", + " 129 | 3600 V(I,J)=0.0\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 3600 at (1)\n", + "svd.f:145:72:\n", + "\n", + " 145 | 4100 U(I,J)=0.0\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 4100 at (1)\n", + "svd.f:152:72:\n", + "\n", + " 152 | 4200 S=U(K,I)*U(K,J) + S\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 4200 at (1)\n", + "svd.f:155:72:\n", + "\n", + " 155 | 4300 U(K,J)=U(K,J) + F*U(K,I)\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 4300 at (1)\n", + "svd.f:159:72:\n", + "\n", + " 159 | 4550 U(J,I)=U(J,I)/G\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 4550 at (1)\n", + "svd.f:163:72:\n", + "\n", + " 163 | 4600 U(J,I)=0.0\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 4600 at (1)\n", + "svd.f:164:72:\n", + "\n", + " 164 | 4700 U(I,I)=U(I,I) + 1.0\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 4700 at (1)\n", + "svd.f:258:72:\n", + "\n", + " 258 | 8200 V(J,K)=-V(J,K)\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 8200 at (1)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "g77 -I../../include -c sscal.f -o sscal.o\n", + "g77 -I../../include -c svd.f -o svd.o\n", + "g77 -I../../include -c tiddid.f -o tiddid.o\n", + "g77 -I../../include -c trialsrc.f -o trialsrc.o\n", + "g77 -I../../include -c trimlen.f -o trimlen.o\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "trimlen.f:11:72:\n", + "\n", + " 11 | 1 if(t(trimlen:trimlen).ne.' ')RETURN\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 1 at (1)\n", + "vmodel.f:34:72:\n", + "\n", + " 34 | 10 vsq(i)=v(i)*v(i)\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 10 at (1)\n", + "vmodel.f:53:72:\n", + "\n", + " 53 | 30 thk(i)=top(i+1)-top(i)\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 30 at (1)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "g77 -I../../include -c ttime.f -o ttime.o\n", + "g77 -I../../include -c vmodel.f -o vmodel.o\n", + "g77 -I../../include -c weighting.f -o weighting.o\n", + "gcc -O -I../../include -c -o atoangle_.o atoangle_.c\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "atoangle_.c:3:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif lint\n", + " ^\n", + " //\n", + "In file included from atoangle_.c:6:\n", + "../../include/f77types.h:10:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif F77TYPES_H\n", + " ^\n", + " //\n", + "2 warnings generated.\n", + "atoangle.c:3:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif lint\n", + " ^\n", + " //\n", + "atoangle.c:9:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif NULL\n", + " ^\n", + " //\n", + "2 warnings generated.\n", + "In file included from datetime_.c:7:\n", + "../../include/f77types.h:10:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif F77TYPES_H\n", + " ^\n", + " //\n", + "1 warning generated.\n", + "In file included from rpad_.c:6:\n", + "../../include/f77types.h:10:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif F77TYPES_H\n", + " ^\n", + " //\n", + "1 warning generated.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "gcc -O -I../../include -c -o atoangle.o atoangle.c\n", + "gcc -O -I../../include -c -o datetime_.o datetime_.c\n", + "gcc -O -I../../include -c -o hypot_.o hypot_.c\n", + "gcc -O -I../../include -c -o rpad_.o rpad_.c\n", + "gcc -O -I../../include -c -o sscanf3_.o sscanf3_.c\n", + "g77 hypoDD.o aprod.o cluster1.o covar.o datum.o delaz.o delaz2.o direct1.o dist.o dtres.o exist.o freeunit.o getdata.o getinp.o ifindi.o indexxi.o juliam.o lsfit_lsqr.o lsfit_svd.o lsqr.o matmult1.o matmult2.o matmult3.o mdian1.o normlz.o partials.o ran.o redist.o refract.o resstat.o scopy.o sdc2.o setorg.o skip.o snrm2.o sort.o sorti.o sscal.o svd.o tiddid.o trialsrc.o trimlen.o ttime.o vmodel.o weighting.o atoangle_.o atoangle.o datetime_.o hypot_.o rpad_.o sscanf3_.o -o hypoDD\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "In file included from sscanf3_.c:7:\n", + "../../include/f77types.h:10:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif F77TYPES_H\n", + " ^\n", + " //\n", + "1 warning generated.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ncsn2pha\n", + "g77 -O -c ncsn2pha.f -o ncsn2pha.o\n", + "g77 ncsn2pha.o -o ncsn2pha\n", + "ph2dt\n", + "g77 -O -I../../include -c ph2dt.f -o ph2dt.o\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ncsn2pha.f:279:72:\n", + "\n", + " 279 | 1 if(t(trimlen:trimlen).ne.' ')RETURN\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 1 at (1)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "g77 -O -I../../include -c cluster.f -o cluster.o\n", + "g77 -O -I../../include -c datetime.f -o datetime.o\n", + "g77 -O -I../../include -c delaz.f -o delaz.o\n", + "g77 -O -I../../include -c ifindi.f -o ifindi.o\n", + "g77 -O -I../../include -c indexx.f -o indexx.o\n", + "g77 -O -I../../include -c indexxi.f -o indexxi.o\n", + "g77 -O -I../../include -c sorti.f -o sorti.o\n", + "g77 -O -I../../include -c trimlen.f -o trimlen.o\n", + "gcc -I../../include -O -c -o atoangle_.o atoangle_.c\n", + "gcc -I../../include -O -c -o atoangle.o atoangle.c\n", + "gcc -I../../include -O -c -o rpad_.o rpad_.c\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "trimlen.f:11:72:\n", + "\n", + " 11 | 1 if(t(trimlen:trimlen).ne.' ')RETURN\n", + " | 1\n", + "Warning: Fortran 2018 deleted feature: DO termination statement which is not END DO or CONTINUE with label 1 at (1)\n", + "atoangle_.c:3:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif lint\n", + " ^\n", + " //\n", + "In file included from atoangle_.c:6:\n", + "../../include/f77types.h:10:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif F77TYPES_H\n", + " ^\n", + " //\n", + "2 warnings generated.\n", + "atoangle.c:3:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif lint\n", + " ^\n", + " //\n", + "atoangle.c:9:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif NULL\n", + " ^\n", + " //\n", + "2 warnings generated.\n", + "In file included from rpad_.c:6:\n", + "../../include/f77types.h:10:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif F77TYPES_H\n", + " ^\n", + " //\n", + "1 warning generated.\n", + "In file included from sscanf3_.c:7:\n", + "../../include/f77types.h:10:8: warning: extra tokens at end of #endif directive [-Wextra-tokens]\n", + "#endif F77TYPES_H\n", + " ^\n", + " //\n", + "1 warning generated.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "gcc -I../../include -O -c -o sscanf3_.o sscanf3_.c\n", + "g77 ph2dt.o cluster.o datetime.o delaz.o ifindi.o indexx.o indexxi.o sorti.o trimlen.o atoangle_.o atoangle.o rpad_.o sscanf3_.o -o ph2dt\n", + "hista2ddsta\n", + "f77 -O -I../../include -c hista2ddsta.f -o hista2ddsta.o\n", + "f77 hista2ddsta.o -o hista2ddsta\n" + ] + } + ], + "source": [ + "if run_local:\n", + " if not os.path.exists(\"HYPODD\"):\n", + " os.system(\"wget -O HYPODD_1.3.tar.gz http://www.ldeo.columbia.edu/~felixw/HYPODD/HYPODD_1.3.tar.gz\")\n", + " os.system(\"tar -xf HYPODD_1.3.tar.gz\")\n", + " os.system(\"ln -s $(which gfortran) ./HYPODD/f77\")\n", + " os.system(\"ln -s $(which gfortran) ./HYPODD/g77\")\n", + " os.environ[\"PATH\"] += os.pathsep + os.getcwd() + \"/HYPODD/\"\n", + " os.system(\"make -C HYPODD/src\")\n", + " if not os.path.exists(root_dir(\"hypodd\")):\n", + " os.mkdir(root_dir(\"hypodd\"))\n", + " os.system(f\"cp HYPODD/src/ph2dt/ph2dt {root_dir('hypodd')}/\")\n", + " os.system(f\"cp HYPODD/src/hypoDD/hypoDD {root_dir('hypodd')}/\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.1. Convert station format" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.291295Z", + "iopub.status.busy": "2022-08-11T15:42:43.291139Z", + "iopub.status.idle": "2022-08-11T15:42:43.295433Z", + "shell.execute_reply": "2022-08-11T15:42:43.295218Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.291285Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def convert_station(\n", + " config_json: InputPath(\"json\"),\n", + " station_json: InputPath(\"json\"),\n", + " hypoinverse_station: OutputPath(str),\n", + " hypodd_station: OutputPath(str),\n", + " data_path: str = \"./\",\n", + " bucket_name: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + "):\n", + "\n", + " import os\n", + " import json\n", + "\n", + " import pandas as pd\n", + " from tqdm import tqdm\n", + "\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " hypodd_path = os.path.join(data_path, \"hypodd\")\n", + " if not os.path.exists(hypodd_path):\n", + " os.mkdir(hypodd_path)\n", + " hypoinv_path = os.path.join(data_path, \"hypoinv\")\n", + " if not os.path.exists(hypoinv_path):\n", + " os.mkdir(hypoinv_path)\n", + "\n", + " stations = pd.read_json(station_json, orient=\"index\")\n", + "\n", + " converted_hypoinverse = []\n", + " converted_hypodd = {}\n", + "\n", + " for sta, row in tqdm(stations.iterrows()):\n", + "\n", + " network_code, station_code, comp_code, channel_code = sta.split(\".\")\n", + " station_weight = \" \"\n", + " lat_degree = int(row[\"latitude\"])\n", + " lat_minute = (row[\"latitude\"] - lat_degree) * 60\n", + " north = \"N\" if lat_degree >= 0 else \"S\"\n", + " lng_degree = int(row[\"longitude\"])\n", + " lng_minute = (row[\"longitude\"] - lng_degree) * 60\n", + " west = \"W\" if lng_degree <= 0 else \"E\"\n", + " elevation = row[\"elevation(m)\"]\n", + " line_hypoinverse = f\"{station_code:<5} {network_code:<2} {comp_code[:-1]:<1}{channel_code:<3} {station_weight}{abs(lat_degree):2.0f} {abs(lat_minute):7.4f}{north}{abs(lng_degree):3.0f} {abs(lng_minute):7.4f}{west}{elevation:4.0f}\\n\"\n", + " converted_hypoinverse.append(line_hypoinverse)\n", + "\n", + " tmp_code = f\"{station_code}{channel_code}\"\n", + " converted_hypodd[\n", + " f\"{station_code}{channel_code}\"\n", + " ] = f\"{tmp_code:<8s} {row['latitude']:.3f} {row['longitude']:.3f}\\n\"\n", + "\n", + " with open(hypoinverse_station, \"w\") as f:\n", + " f.writelines(converted_hypoinverse)\n", + "\n", + " with open(hypodd_station, \"w\") as f:\n", + " for k, v in converted_hypodd.items():\n", + " f.write(v)\n", + "\n", + " ## upload to s3 bucket\n", + " try:\n", + " from minio import Minio\n", + "\n", + " minioClient = Minio(s3_url, access_key=\"minio\", secret_key=\"minio123\", secure=secure)\n", + " if not minioClient.bucket_exists(bucket_name):\n", + " minioClient.make_bucket(bucket_name)\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/hypodd/stations.dat\",\n", + " hypodd_station,\n", + " )\n", + "\n", + " except Exception as err:\n", + " print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.295850Z", + "iopub.status.busy": "2022-08-11T15:42:43.295777Z", + "iopub.status.idle": "2022-08-11T15:42:43.297872Z", + "shell.execute_reply": "2022-08-11T15:42:43.297673Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.295841Z" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "52it [00:00, 30932.32it/s]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ERROR: can not access minio service! \n", + "HTTPSConnectionPool(host='minio-service', port=9000): Max retries exceeded with url: /catalogs?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))\n" + ] + } + ], + "source": [ + "if run_local:\n", + " convert_station(\n", + " root_dir(\"config.json\"),\n", + " root_dir(\"stations.json\"),\n", + " root_dir(\"hypoinv/stations.dat\"),\n", + " root_dir(\"hypodd/stations.dat\"),\n", + " root_dir(\"\"),\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.298260Z", + "iopub.status.busy": "2022-08-11T15:42:43.298168Z", + "iopub.status.idle": "2022-08-11T15:42:43.307008Z", + "shell.execute_reply": "2022-08-11T15:42:43.306794Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.298251Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "convert_station_op = comp.func_to_container_op(\n", + " convert_station,\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\"pandas\", \"tqdm\", \"minio\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Split large catalog due to memory and time" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.307446Z", + "iopub.status.busy": "2022-08-11T15:42:43.307349Z", + "iopub.status.idle": "2022-08-11T15:42:43.309961Z", + "shell.execute_reply": "2022-08-11T15:42:43.309779Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.307435Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def split_hypodd(\n", + " config_json: InputPath(\"json\"),\n", + " catalog_csv: InputPath(str),\n", + ") -> list:\n", + "\n", + " import json\n", + " import pandas as pd\n", + "\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " events = pd.read_csv(catalog_csv)\n", + "\n", + " if \"MAXEVENT\" in config[\"hypodd\"]:\n", + " MAXEVENT = config[\"hypodd\"][\"MAXEVENT\"]\n", + " else:\n", + " MAXEVENT = 1e4 ## segment by time\n", + "\n", + " MAXEVENT = len(events) // ((len(events) - 1) // MAXEVENT + 1) + 1\n", + " num_parallel = int((len(events) - 1) // MAXEVENT + 1)\n", + "\n", + " return list(range(num_parallel))" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.310371Z", + "iopub.status.busy": "2022-08-11T15:42:43.310275Z", + "iopub.status.idle": "2022-08-11T15:42:43.312038Z", + "shell.execute_reply": "2022-08-11T15:42:43.311821Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.310362Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "if run_local:\n", + " nodes = split_hypodd(\n", + " root_dir(\"config.json\"),\n", + " root_dir(\"gamma_catalog.csv\"),\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.312414Z", + "iopub.status.busy": "2022-08-11T15:42:43.312323Z", + "iopub.status.idle": "2022-08-11T15:42:43.317514Z", + "shell.execute_reply": "2022-08-11T15:42:43.317317Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.312405Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "split_hypodd_op = comp.func_to_container_op(\n", + " split_hypodd,\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\n", + " \"pandas\",\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.2. Convert phase format" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.317903Z", + "iopub.status.busy": "2022-08-11T15:42:43.317834Z", + "iopub.status.idle": "2022-08-11T15:42:43.323986Z", + "shell.execute_reply": "2022-08-11T15:42:43.323639Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.317894Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def convert_phase(\n", + " node_i: int,\n", + " config_json: InputPath(\"json\"),\n", + " picks_csv: InputPath(str),\n", + " catalog_csv: InputPath(str),\n", + " hypodd_phase: OutputPath(str),\n", + " data_path: str = \"./\",\n", + " bucket_name: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + "):\n", + "\n", + " import json\n", + " import os\n", + " from datetime import datetime\n", + "\n", + " import pandas as pd\n", + " from tqdm import tqdm\n", + "\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + " hypodd_path = os.path.join(data_path, \"hypodd\")\n", + " if not os.path.exists(hypodd_path):\n", + " os.mkdir(hypodd_path)\n", + "\n", + " picks = pd.read_csv(picks_csv)\n", + " events = pd.read_csv(catalog_csv)\n", + "\n", + " if \"MAXEVENT\" in config[\"hypodd\"]:\n", + " MAXEVENT = config[\"hypodd\"][\"MAXEVENT\"]\n", + " else:\n", + " MAXEVENT = 1e4 ## segment by time\n", + " MAXEVENT = len(events) // ((len(events) - 1) // MAXEVENT + 1) + 1\n", + " num_parallel = int((len(events) - 1) // MAXEVENT + 1)\n", + "\n", + " events.sort_values(\"time\", inplace=True)\n", + " events = events.iloc[node_i::num_parallel]\n", + " picks = picks.loc[picks[\"event_index\"].isin(events[\"event_index\"])]\n", + " # output_lines = []\n", + " output_file = open(hypodd_phase, \"w\")\n", + "\n", + " picks_by_event = picks.groupby(\"event_index\").groups\n", + " # for i in tqdm(range(node_i, len(events), num_parallel)):\n", + " # event = events.iloc[i]\n", + " for i, event in events.iterrows():\n", + " event_time = datetime.strptime(event[\"time\"], \"%Y-%m-%dT%H:%M:%S.%f\")\n", + " lat = event[\"latitude\"]\n", + " lng = event[\"longitude\"]\n", + " dep = event[\"depth(m)\"] / 1e3\n", + " mag = event[\"magnitude\"]\n", + " EH = 0\n", + " EZ = 0\n", + " RMS = event[\"sigma_time\"]\n", + "\n", + " year, month, day, hour, min, sec = (\n", + " event_time.year,\n", + " event_time.month,\n", + " event_time.day,\n", + " event_time.hour,\n", + " event_time.minute,\n", + " float(event_time.strftime(\"%S.%f\")),\n", + " )\n", + " event_line = f\"# {year:4d} {month:2d} {day:2d} {hour:2d} {min:2d} {sec:5.2f} {lat:7.4f} {lng:9.4f} {dep:5.2f} {mag:5.2f} {EH:5.2f} {EZ:5.2f} {RMS:5.2f} {event['event_index']:9d}\\n\"\n", + "\n", + " # output_lines.append(event_line)\n", + " output_file.write(event_line)\n", + "\n", + " picks_idx = picks_by_event[event[\"event_index\"]]\n", + " for j in picks_idx:\n", + " # pick = picks.iloc[j]\n", + " pick = picks.loc[j]\n", + " network_code, station_code, comp_code, channel_code = pick[\"station_id\"].split(\".\")\n", + " phase_type = pick[\"phase_type\"].upper()\n", + " phase_score = pick[\"phase_score\"]\n", + " pick_time = (datetime.strptime(pick[\"phase_time\"], \"%Y-%m-%dT%H:%M:%S.%f\") - event_time).total_seconds()\n", + " tmp_code = f\"{station_code}{channel_code}\"\n", + " pick_line = f\"{tmp_code:<7s} {pick_time:6.3f} {phase_score:5.4f} {phase_type}\\n\"\n", + " # output_lines.append(pick_line)\n", + " output_file.write(pick_line)\n", + "\n", + " # with open(hypodd_phase, \"w\") as fp:\n", + " # fp.writelines(output_lines)\n", + "\n", + " ## upload to s3 bucket\n", + " try:\n", + " from minio import Minio\n", + "\n", + " minioClient = Minio(s3_url, access_key=\"minio\", secret_key=\"minio123\", secure=secure)\n", + " if not minioClient.bucket_exists(bucket_name):\n", + " minioClient.make_bucket(bucket_name)\n", + "\n", + " # minioClient.fput_object(\n", + " # bucket_name,\n", + " # f\"{config['region']}/hypodd/phase_{node_i:03d}.pha\",\n", + " # hypodd_phase,\n", + " # )\n", + "\n", + " except Exception as err:\n", + " print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " pass\n", + "\n", + " return hypodd_phase" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.324534Z", + "iopub.status.busy": "2022-08-11T15:42:43.324342Z", + "iopub.status.idle": "2022-08-11T15:42:43.326694Z", + "shell.execute_reply": "2022-08-11T15:42:43.326362Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.324524Z" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ERROR: can not access minio service! \n", + "HTTPSConnectionPool(host='minio-service', port=9000): Max retries exceeded with url: /catalogs?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))\n" + ] + } + ], + "source": [ + "if run_local:\n", + " for node_i in nodes:\n", + " convert_phase(\n", + " node_i,\n", + " root_dir(\"config.json\"),\n", + " root_dir(\"gamma_picks.csv\"),\n", + " root_dir(\"gamma_catalog.csv\"),\n", + " root_dir(\"hypodd/hypodd_phase.pha\"),\n", + " root_dir(\"\"),\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.327081Z", + "iopub.status.busy": "2022-08-11T15:42:43.327013Z", + "iopub.status.idle": "2022-08-11T15:42:43.342216Z", + "shell.execute_reply": "2022-08-11T15:42:43.341954Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.327072Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "convert_phase_op = comp.func_to_container_op(\n", + " convert_phase,\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\"pandas\", \"tqdm\", \"minio\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.3. Run ph2dt to calculate differential time between phases" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.342670Z", + "iopub.status.busy": "2022-08-11T15:42:43.342599Z", + "iopub.status.idle": "2022-08-11T15:42:43.347476Z", + "shell.execute_reply": "2022-08-11T15:42:43.347261Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.342660Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def ph2dt(\n", + " node_i: int,\n", + " config_json: InputPath(\"json\"),\n", + " hypodd_phase: InputPath(str),\n", + " station_dat: InputPath(str),\n", + " ct_file: OutputPath(str),\n", + " hypodd_event: OutputPath(str),\n", + " data_path: str = \"./\",\n", + " bucket_name: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + "):\n", + "\n", + " import json\n", + " import os\n", + " from datetime import datetime\n", + "\n", + " from minio import Minio\n", + "\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " hypodd_path = os.path.join(data_path, \"hypodd\")\n", + " if not os.path.exists(hypodd_path):\n", + " os.mkdir(hypodd_path)\n", + "\n", + " # try:\n", + " # minioClient = Minio(s3_url, access_key='minio', secret_key='minio123', secure=secure)\n", + " # minioClient.fget_object(bucket_name, f\"{config['region']}/hypodd_{node_i:03d}.pha\", os.path.join(hypodd_path, f\"hypodd_{node_i:03d}.pha\"))\n", + " # except Exception as err:\n", + " # print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " # pass\n", + "\n", + " ph2dt = \"\"\"* ph2dt.inp - input control file for program ph2dt\n", + "* Input station file:\n", + "stations.dat\n", + "* Input phase file:\n", + "hypodd.pha\n", + "*MINWGHT: min. pick weight allowed [0]\n", + "*MAXDIST: max. distance in km between event pair and stations [200]\n", + "*MAXSEP: max. hypocentral separation in km [10]\n", + "*MAXNGH: max. number of neighbors per event [10]\n", + "*MINLNK: min. number of links required to define a neighbor [8]\n", + "*MINOBS: min. number of links per pair saved [8]\n", + "*MAXOBS: max. number of links per pair saved [20]\n", + "*MINWGHT MAXDIST MAXSEP MAXNGH MINLNK MINOBS MAXOBS\n", + " 0 120 10 50 8 8 100\n", + "\"\"\"\n", + "\n", + " with open(os.path.join(hypodd_path, \"ph2dt.inp\"), \"w\") as fp:\n", + " fp.writelines(ph2dt)\n", + "\n", + " def copy_file(fp_from, fp_to):\n", + " with open(fp_from, \"r\") as fp:\n", + " lines = fp.readlines()\n", + " with open(fp_to, \"w\") as fp:\n", + " fp.writelines(lines)\n", + "\n", + " copy_file(hypodd_phase, os.path.join(hypodd_path, \"hypodd.pha\"))\n", + " copy_file(station_dat, os.path.join(hypodd_path, \"stations.dat\"))\n", + "\n", + " PH2DT_CMD = f\"cd {hypodd_path} && ./ph2dt ph2dt.inp\"\n", + " print(PH2DT_CMD)\n", + " if os.system(PH2DT_CMD) != 0:\n", + " raise (\"{PH2DT_CMD}\" + \" failed!\")\n", + "\n", + " copy_file(os.path.join(hypodd_path, \"dt.ct\"), ct_file)\n", + " copy_file(os.path.join(hypodd_path, \"event.sel\"), hypodd_event)\n", + "\n", + " ## upload to s3 bucket\n", + " try:\n", + " from minio import Minio\n", + "\n", + " minioClient = Minio(s3_url, access_key=\"minio\", secret_key=\"minio123\", secure=secure)\n", + " if not minioClient.bucket_exists(bucket_name):\n", + " minioClient.make_bucket(bucket_name)\n", + "\n", + " # minioClient.fput_object(\n", + " # bucket_name,\n", + " # f\"{config['region']}/hypodd/dt_{node_i:03d}.ct\",\n", + " # ct_file,\n", + " # )\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/hypodd/event_{node_i:03d}.sel\",\n", + " hypodd_event,\n", + " )\n", + "\n", + " except Exception as err:\n", + " print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " pass\n", + "\n", + " # try:\n", + " # minioClient.fput_object(\n", + " # bucket_name,\n", + " # f\"{config['region']}/dt_{node_i:03d}.ct\",\n", + " # f\"{os.path.join(hypodd_path, 'dt.ct')}\",\n", + " # )\n", + " # minioClient.fput_object(\n", + " # bucket_name,\n", + " # f\"{config['region']}/event_{node_i:03d}.dat\",\n", + " # f\"{os.path.join(hypodd_path, 'event.dat')}\",\n", + " # )\n", + " # minioClient.fput_object(\n", + " # bucket_name,\n", + " # f\"{config['region']}/event_{node_i:03d}.sel\",\n", + " # f\"{os.path.join(hypodd_path, 'event.sel')}\",\n", + " # )\n", + " # except Exception as err:\n", + " # print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " # pass\n", + "\n", + " return 0" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.347866Z", + "iopub.status.busy": "2022-08-11T15:42:43.347786Z", + "iopub.status.idle": "2022-08-11T15:42:43.350092Z", + "shell.execute_reply": "2022-08-11T15:42:43.349843Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.347857Z" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cd Demo/hypodd && ./ph2dt ph2dt.inp\n", + "starting ph2dt (v1.3 - 08/2010)... \u0000\u0000\u0000\u0000\u0000\n", + "\n", + "reading data ...\n", + " > stations = 46\n", + " > events total = 208\n", + " > events selected = 208\n", + " > phases = 10907\n", + "forming dtimes...\n", + " > P-phase pairs total = 101464\n", + " > S-phase pairs total = 111906\n", + " > outliers = 1855 ( 0 %)\n", + " > phases at stations not in station list = 0\n", + " > phases at distances larger than MAXDIST = 0\n", + " > P-phase pairs selected = 99279 ( 97 %)\n", + " > S-phase pairs selected = 110831 ( 99 %)\n", + " > weakly linked events = 80 ( 38 %)\n", + " > linked event pairs = 4953\n", + " > average links per pair = 42\n", + " > average offset (km) betw. linked events = 5.32930326 \n", + " > average offset (km) betw. strongly linked events = 5.32930326 \n", + " > maximum offset (km) betw. strongly linked events = 9.99880028 \n", + "\n", + "Done. \u0000\u0000\u0000\u0000\u0000\n", + "\n", + "Output files: dt.ct; event.dat; event.sel; ph2dt.log\n", + "ph2dt parameters were: \n", + " (minwght,maxdist,maxsep,maxngh,minlnk,minobs,maxobs)\n", + " 0.00000000 120.000000 10.0000000 50 8 8 100\n", + "ERROR: can not access minio service! \n", + "HTTPSConnectionPool(host='minio-service', port=9000): Max retries exceeded with url: /catalogs?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))\n" + ] + } + ], + "source": [ + "if run_local:\n", + " ph2dt(\n", + " 0,\n", + " root_dir(\"config.json\"),\n", + " root_dir(\"hypodd/hypodd_phase.pha\"),\n", + " root_dir(\"hypodd/stations.dat\"),\n", + " root_dir(\"hypodd/dt.ct\"),\n", + " root_dir(\"hypodd/event.sel\"),\n", + " root_dir(\"\"),\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.350518Z", + "iopub.status.busy": "2022-08-11T15:42:43.350398Z", + "iopub.status.idle": "2022-08-11T15:42:43.361412Z", + "shell.execute_reply": "2022-08-11T15:42:43.361184Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.350509Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "ph2dt_op = comp.func_to_container_op(ph2dt, base_image=\"zhuwq0/hypodd-api:1.0\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.4. Run HypoDD re-location" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.361862Z", + "iopub.status.busy": "2022-08-11T15:42:43.361761Z", + "iopub.status.idle": "2022-08-11T15:42:43.366876Z", + "shell.execute_reply": "2022-08-11T15:42:43.366650Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.361852Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def hypodd_ct(\n", + " node_i: int,\n", + " config_json: InputPath(\"json\"),\n", + " ct_file: InputPath(str),\n", + " event: InputPath(str),\n", + " station: InputPath(str),\n", + " catalog_txt: OutputPath(str),\n", + " data_path: str = \"./\",\n", + " bucket_name: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + "):\n", + " import json\n", + " import os\n", + " from datetime import datetime\n", + "\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + " hypodd_path = os.path.join(data_path, \"hypodd\")\n", + "\n", + " ct_inp = \"\"\"* RELOC.INP:\n", + "*--- input file selection\n", + "* cross correlation diff times:\n", + "\n", + "*\n", + "*catalog P diff times:\n", + "dt.ct\n", + "*\n", + "* event file:\n", + "event.sel\n", + "*\n", + "* station file:\n", + "stations.dat\n", + "*\n", + "*--- output file selection\n", + "* original locations:\n", + "hypodd.loc\n", + "* relocations:\n", + "hypodd.reloc\n", + "* station information:\n", + "hypodd.sta\n", + "* residual information:\n", + "hypodd.res\n", + "* source paramater information:\n", + "hypodd.src\n", + "*\n", + "*--- data type selection: \n", + "* IDAT: 0 = synthetics; 1= cross corr; 2= catalog; 3= cross & cat \n", + "* IPHA: 1= P; 2= S; 3= P&S\n", + "* DIST:max dist [km] between cluster centroid and station \n", + "* IDAT IPHA DIST\n", + " 2 3 120\n", + "*\n", + "*--- event clustering:\n", + "* OBSCC: min # of obs/pair for crosstime data (0= no clustering)\n", + "* OBSCT: min # of obs/pair for network data (0= no clustering)\n", + "* OBSCC OBSCT \n", + " 0 8 \n", + "*\n", + "*--- solution control:\n", + "* ISTART: \t1 = from single source; 2 = from network sources\n", + "* ISOLV:\t1 = SVD, 2=lsqr\n", + "* NSET: \tnumber of sets of iteration with specifications following\n", + "* ISTART ISOLV NSET\n", + " 2 2 4\n", + "*\n", + "*--- data weighting and re-weighting: \n", + "* NITER: \t\tlast iteration to used the following weights\n", + "* WTCCP, WTCCS:\t\tweight cross P, S \n", + "* WTCTP, WTCTS:\t\tweight catalog P, S \n", + "* WRCC, WRCT:\t\tresidual threshold in sec for cross, catalog data \n", + "* WDCC, WDCT: \t\tmax dist [km] between cross, catalog linked pairs\n", + "* DAMP: \t\tdamping (for lsqr only) \n", + "* --- CROSS DATA ----- ----CATALOG DATA ----\n", + "* NITER WTCCP WTCCS WRCC WDCC WTCTP WTCTS WRCT WDCT DAMP\n", + " 4 -9 -9 -9 -9 1 1 8 -9 70 \n", + " 4 -9 -9 -9 -9 1 1 6 4 70 \n", + " 4 -9 -9 -9 -9 1 0.8 4 2 70 \n", + " 4 -9 -9 -9 -9 1 0.8 3 2 70 \n", + "*\n", + "*--- 1D model:\n", + "* NLAY:\t\tnumber of model layers \n", + "* RATIO:\tvp/vs ratio \n", + "* TOP:\t\tdepths of top of layer (km) \n", + "* VEL: \t\tlayer velocities (km/s)\n", + "* NLAY RATIO \n", + " 12 1.82\n", + "* TOP \n", + "0.0 1.0 3.0 5.0 7.0 9.0 11.0 13.0 17.0 21.0 31.00 31.10\n", + "* VEL\n", + "5.30 5.65 5.93 6.20 6.20 6.20 6.20 6.20 6.20 6.20 7.50 8.11\n", + "*\n", + "*--- event selection:\n", + "* CID: \tcluster to be relocated (0 = all)\n", + "* ID:\tcuspids of event to be relocated (8 per line)\n", + "* CID \n", + " 0 \n", + "* ID\n", + "\"\"\"\n", + "\n", + " with open(os.path.join(hypodd_path, \"ct.inp\"), \"w\") as fp:\n", + " fp.writelines(ct_inp)\n", + "\n", + " def copy_file(fp_from, fp_to):\n", + " with open(fp_from, \"r\") as fp:\n", + " lines = fp.readlines()\n", + " with open(fp_to, \"w\") as fp:\n", + " fp.writelines(lines)\n", + "\n", + " copy_file(ct_file, os.path.join(hypodd_path, \"dt.ct\"))\n", + " copy_file(event, os.path.join(hypodd_path, \"event.sel\"))\n", + " copy_file(station, os.path.join(hypodd_path, \"stations.dat\"))\n", + "\n", + " # os.system(f\"cat {ct_file}\")\n", + " # os.system(f\"cat {event}\")\n", + " # os.system(f\"cat {station}\")\n", + "\n", + " HYPODD_CMD = f\"cd {hypodd_path} && ./hypoDD ct.inp\"\n", + " print(HYPODD_CMD)\n", + " if os.system(HYPODD_CMD) != 0:\n", + " raise (\"{HYPODD_CMD}\" + \" failed!\")\n", + "\n", + " copy_file(os.path.join(hypodd_path, \"hypodd.reloc\"), catalog_txt)\n", + "\n", + " try:\n", + " from minio import Minio\n", + "\n", + " minioClient = Minio(s3_url, access_key=\"minio\", secret_key=\"minio123\", secure=secure)\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/hypodd/hypodd_ct_{node_i:03d}.reloc\",\n", + " catalog_txt,\n", + " )\n", + " except Exception as err:\n", + " print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.367464Z", + "iopub.status.busy": "2022-08-11T15:42:43.367254Z", + "iopub.status.idle": "2022-08-11T15:42:43.369716Z", + "shell.execute_reply": "2022-08-11T15:42:43.369497Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.367448Z" + }, + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cd Demo/hypodd && ./hypoDD ct.inp\n", + "ERROR: can not access minio service! \n", + "HTTPSConnectionPool(host='minio-service', port=9000): Max retries exceeded with url: /catalogs?location= (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known'))\n" + ] + } + ], + "source": [ + "if run_local:\n", + " hypodd_ct(\n", + " 0,\n", + " root_dir(\"config.json\"),\n", + " root_dir(\"hypodd/dt.ct\"),\n", + " root_dir(\"hypodd/event.sel\"),\n", + " root_dir(\"hypodd/stations.dat\"),\n", + " root_dir(\"hypodd_ct_catalog.txt\"),\n", + " root_dir(\"\"),\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.370228Z", + "iopub.status.busy": "2022-08-11T15:42:43.370081Z", + "iopub.status.idle": "2022-08-11T15:42:43.383077Z", + "shell.execute_reply": "2022-08-11T15:42:43.382825Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.370214Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "hypodd_ct_op = comp.func_to_container_op(hypodd_ct, base_image=\"zhuwq0/hypodd-api:1.0\")" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.383583Z", + "iopub.status.busy": "2022-08-11T15:42:43.383476Z", + "iopub.status.idle": "2022-08-11T15:42:43.387261Z", + "shell.execute_reply": "2022-08-11T15:42:43.387048Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.383569Z" + }, + "tags": [] + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "if run_local:\n", + " from datetime import datetime\n", + "\n", + " import matplotlib.pyplot as plt\n", + " import pandas as pd\n", + "\n", + " catalog_hypodd = pd.read_csv(\n", + " root_dir(f\"hypodd/hypodd.reloc\"),\n", + " sep=\"\\s+\",\n", + " names=[\n", + " \"ID\",\n", + " \"LAT\",\n", + " \"LON\",\n", + " \"DEPTH\",\n", + " \"X\",\n", + " \"Y\",\n", + " \"Z\",\n", + " \"EX\",\n", + " \"EY\",\n", + " \"EZ\",\n", + " \"YR\",\n", + " \"MO\",\n", + " \"DY\",\n", + " \"HR\",\n", + " \"MI\",\n", + " \"SC\",\n", + " \"MAG\",\n", + " \"NCCP\",\n", + " \"NCCS\",\n", + " \"NCTP\",\n", + " \"NCTS\",\n", + " \"RCC\",\n", + " \"RCT\",\n", + " \"CID\",\n", + " ],\n", + " )\n", + " catalog_hypodd[\"time\"] = catalog_hypodd.apply(\n", + " lambda x: f'{x[\"YR\"]:04.0f}-{x[\"MO\"]:02.0f}-{x[\"DY\"]:02.0f}T{x[\"HR\"]:02.0f}:{x[\"MI\"]:02.0f}:{min(x[\"SC\"], 59.999):05.3f}',\n", + " axis=1,\n", + " )\n", + " catalog_hypodd[\"time\"] = catalog_hypodd[\"time\"].apply(lambda x: datetime.strptime(x, \"%Y-%m-%dT%H:%M:%S.%f\"))\n", + " plt.figure()\n", + " plt.plot(catalog_hypodd[\"LON\"], catalog_hypodd[\"LAT\"], \".\")\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.387833Z", + "iopub.status.busy": "2022-08-11T15:42:43.387723Z", + "iopub.status.idle": "2022-08-11T15:42:43.397330Z", + "shell.execute_reply": "2022-08-11T15:42:43.397111Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.387817Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def cross_correlation(\n", + " ct_file: InputPath(str),\n", + " catalog_file: InputPath(str),\n", + " picks_file: InputPath(str),\n", + " cc_file: OutputPath(str),\n", + "):\n", + "\n", + " import time\n", + " from multiprocessing import Manager, Process\n", + "\n", + " import numpy as np\n", + " import pandas as pd\n", + " from pymongo import MongoClient\n", + " from tqdm import tqdm\n", + "\n", + " catalog = pd.read_csv(\n", + " catalog_file,\n", + " sep=\"\\t\",\n", + " parse_dates=[\"time\"],\n", + " index_col=[\"event_idx\"],\n", + " dtype={\"event_idx\": str},\n", + " )\n", + " picks = pd.read_csv(picks_file, sep=\"\\t\", parse_dates=[\"timestamp\"], dtype={\"event_idx\": str})\n", + " picks[\"station\"] = picks[\"id\"].apply(lambda x: x.split(\".\")[1] + x.split(\".\")[3])\n", + " picks = picks.set_index([\"event_idx\", \"station\", \"type\"])\n", + " picks = picks.sort_index()\n", + "\n", + " pick_index = 100\n", + " lo = pick_index - 50\n", + " hi = pick_index + 100\n", + " dt = 0.01\n", + "\n", + " ct_dict = Manager().dict()\n", + " cc_dict = Manager().dict()\n", + " with open(ct_file) as fct:\n", + " meta = fct.readlines()\n", + " for i, line in enumerate(meta):\n", + " if line[0] == \"#\":\n", + " if i > 0:\n", + " ct_dict[key] = value\n", + " key = line\n", + " value = []\n", + " continue\n", + " value.append(line)\n", + " ct_dict[key] = value\n", + " keys = sorted(list(ct_dict.keys()))\n", + "\n", + " def calc_cross_correlation(keys, ct_dict, cc_dict):\n", + " username = \"root\"\n", + " password = \"quakeflow123\"\n", + " # client = MongoClient(f\"mongodb://{username}:{password}@127.0.0.1:27017\")\n", + " client = MongoClient(f\"mongodb://{username}:{password}@quakeflow-mongodb.default.svc.cluster.local:27017\")\n", + " db = client[\"quakeflow\"]\n", + " collection = db[\"waveform\"]\n", + " # normalize = lambda x: (x - np.mean(x, axis=0, keepdims=True)) / np.std(x, axis=0, keepdims=True)\n", + "\n", + " for key in keys:\n", + " tmp = key.split()\n", + " ID1, ID2 = tmp[1], tmp[2]\n", + " key_cc = f\"# {ID1} {ID2} 0.0\\n\"\n", + " lines_cc = []\n", + " for line in ct_dict[key]:\n", + " tmp = line.split()\n", + " STA, TT1, TT2, WGT, PHA = (\n", + " tmp[0],\n", + " tmp[1],\n", + " tmp[2],\n", + " tmp[3],\n", + " tmp[4],\n", + " ) ##HypoDD format\n", + "\n", + " for i, row1 in picks.loc[(ID1, STA, PHA)].iterrows():\n", + "\n", + " data1 = collection.find_one(\n", + " {\"_id\": f\"{row1['id']}_{row1['timestamp'].isoformat(timespec='milliseconds')}_{PHA}\"}\n", + " )\n", + "\n", + " for j, row2 in picks.loc[(ID2, STA, PHA)].iterrows():\n", + "\n", + " data2 = collection.find_one(\n", + " {\"_id\": f\"{row2['id']}_{row2['timestamp'].isoformat(timespec='milliseconds')}_{PHA}\"}\n", + " )\n", + "\n", + " # if PHA == \"P\": # Z\n", + " # waveform1 = np.array(data1[\"waveform\"])[lo:hi, -1:]\n", + " # waveform2 = np.array(data2[\"waveform\"])[lo:hi, -1:]\n", + " # elif PHA == \"S\": # E, N\n", + " # waveform1 = np.array(data1[\"waveform\"])[lo:hi, :-1]\n", + " # waveform2 = np.array(data2[\"waveform\"])[lo:hi, :-1]\n", + " # else:\n", + " # raise (Exception(\"PHA must be P or S\"))\n", + " waveform1 = np.array(data1[\"waveform\"])[lo:hi, :]\n", + " waveform2 = np.array(data2[\"waveform\"])[lo:hi, :]\n", + "\n", + " cc = np.zeros(waveform1.shape[0])\n", + " for k in range(waveform1.shape[1]):\n", + " cc += np.correlate(waveform1[:, k], waveform2[:, k], mode=\"same\")\n", + " norm = np.sqrt(np.sum(waveform1**2) * np.sum(waveform2**2))\n", + " if norm == 0:\n", + " continue\n", + " else:\n", + " cc /= norm\n", + " shift = (np.argmax(np.abs(cc)) - waveform1.shape[0] // 2) * dt + float(TT1) - float(TT2)\n", + " coeff = np.max(np.abs(cc))\n", + "\n", + " if not np.isnan(coeff):\n", + " lines_cc.append(f\"{STA:<7s} {shift:.5f} {coeff:.3f} {PHA}\\n\")\n", + "\n", + " cc_dict[key_cc] = lines_cc\n", + "\n", + " return 0\n", + "\n", + " t0 = time.time()\n", + " processes = []\n", + " num_process = 16\n", + " for i in range(num_process):\n", + " p = Process(target=calc_cross_correlation, args=(keys[i::num_process], ct_dict, cc_dict))\n", + " p.start()\n", + " processes.append(p)\n", + " for p in processes:\n", + " p.join()\n", + " print(f\"{num_process} process: time = {time.time()-t0:.1f}\")\n", + "\n", + " with open(cc_file, \"w\") as fcc:\n", + " for key in cc_dict:\n", + " fcc.write(key)\n", + " for line in cc_dict[key]:\n", + " fcc.write(line)" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.397856Z", + "iopub.status.busy": "2022-08-11T15:42:43.397747Z", + "iopub.status.idle": "2022-08-11T15:42:43.415203Z", + "shell.execute_reply": "2022-08-11T15:42:43.414898Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.397841Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "cc_op = comp.func_to_container_op(\n", + " cross_correlation,\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\"pandas\", \"tqdm\", \"minio\", \"pymongo\"],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.415715Z", + "iopub.status.busy": "2022-08-11T15:42:43.415599Z", + "iopub.status.idle": "2022-08-11T15:42:43.419952Z", + "shell.execute_reply": "2022-08-11T15:42:43.419712Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.415700Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def hypodd_cc(\n", + " i: int,\n", + " config_json: InputPath(\"json\"),\n", + " ct_file: InputPath(str),\n", + " cc_file: InputPath(str),\n", + " event: InputPath(str),\n", + " station: InputPath(str),\n", + " inp_file: str = \"hypodd_cc.inp\",\n", + " bucket_name: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + "):\n", + " import json\n", + " import os\n", + "\n", + " from minio import Minio\n", + "\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " minioClient = Minio(s3_url, access_key=\"minio\", secret_key=\"minio123\", secure=secure)\n", + "\n", + " os.system(f\"cat {ct_file} > dt.ct\")\n", + " os.system(f\"cat {cc_file} > dt.cc\")\n", + " os.system(f\"cat {event} > event.sel\")\n", + " os.system(f\"cat {station} > stations_hypodd.dat \")\n", + "\n", + " HYPODD_CMD = f\"HYPODD/src/hypodd/hypodd {inp_file}\"\n", + " if os.system(HYPODD_CMD) != 0:\n", + " raise (\"{HYPODD_CMD}\" + \" failed!\")\n", + " os.system(f\"mv hypodd.reloc hypodd_cc_{i:03d}.reloc\")\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/hypodd_cc_{i:03d}.reloc\",\n", + " f\"hypodd_cc_{i:03d}.reloc\",\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.420476Z", + "iopub.status.busy": "2022-08-11T15:42:43.420355Z", + "iopub.status.idle": "2022-08-11T15:42:43.430476Z", + "shell.execute_reply": "2022-08-11T15:42:43.430247Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.420461Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "hypodd_cc_op = comp.func_to_container_op(hypodd_cc, base_image=\"zhuwq0/hypodd-api:1.0\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Merge hypodd results" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.431076Z", + "iopub.status.busy": "2022-08-11T15:42:43.430959Z", + "iopub.status.idle": "2022-08-11T15:42:43.436084Z", + "shell.execute_reply": "2022-08-11T15:42:43.435851Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.431061Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def merge_hypodd(\n", + " index: list,\n", + " config_json: InputPath(\"json\"),\n", + " catalog_ct: OutputPath(str),\n", + " catalog_cc: OutputPath(str),\n", + " bucket_name: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + "):\n", + " import json\n", + " import os\n", + " from glob import glob\n", + "\n", + " from minio import Minio\n", + "\n", + " minioClient = Minio(s3_url, access_key=\"minio\", secret_key=\"minio123\", secure=secure)\n", + "\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " objects = minioClient.list_objects(bucket_name, prefix=f\"{config['region']}/hypodd/hypodd_\", recursive=True)\n", + "\n", + " tmp_path = lambda x: os.path.join(\"/tmp/\", x)\n", + " for obj in objects:\n", + " print(obj._object_name)\n", + " minioClient.fget_object(bucket_name, obj._object_name, tmp_path(obj._object_name.split(\"/\")[-1]))\n", + "\n", + " # tmp_ct_catalogs = sorted(glob(tmp_path(\"hypodd_ct_*.reloc\")))\n", + " hypodd_ct_catalogs = [tmp_path(f\"hypodd_ct_{i:03d}.reloc\") for i in index]\n", + " print(f\"cat {' '.join(hypodd_ct_catalogs)} > {tmp_path('hypodd_ct_catalog.txt')}\")\n", + " os.system(f\"cat {' '.join(hypodd_ct_catalogs)} > {tmp_path('hypodd_ct_catalog.txt')}\")\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/hypodd_ct_catalog.txt\",\n", + " tmp_path(\"hypodd_ct_catalog.txt\"),\n", + " )\n", + " os.system(f\"cat {tmp_path('hypodd_ct_catalog.txt')} > {catalog_ct}\")\n", + "\n", + " # hypodd_cc_catalogs = sorted(glob(tmp_path(\"hypodd_cc_*.reloc\")))\n", + " hypodd_cc_catalogs = [tmp_path(f\"hypodd_cc_{i:03d}.reloc\") for i in index]\n", + " print(f\"cat {' '.join(hypodd_cc_catalogs)} > {tmp_path('hypodd_cc_catalog.txt')}\")\n", + " os.system(f\"cat {' '.join(hypodd_cc_catalogs)} > {tmp_path('hypodd_cc_catalog.txt')}\")\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/hypodd_cc_catalog.txt\",\n", + " tmp_path(\"hypodd_cc_catalog.txt\"),\n", + " )\n", + " os.system(f\"cat {tmp_path('hypodd_cc_catalog.txt')} > {catalog_cc}\")\n", + "\n", + " return 0" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.436589Z", + "iopub.status.busy": "2022-08-11T15:42:43.436478Z", + "iopub.status.idle": "2022-08-11T15:42:43.447253Z", + "shell.execute_reply": "2022-08-11T15:42:43.446996Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.436574Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "merge_hypodd_op = comp.func_to_container_op(\n", + " merge_hypodd,\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\"pandas\", \"tqdm\", \"minio\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. Visulization" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.447911Z", + "iopub.status.busy": "2022-08-11T15:42:43.447801Z", + "iopub.status.idle": "2022-08-11T15:42:43.457632Z", + "shell.execute_reply": "2022-08-11T15:42:43.457433Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.447896Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "def visulization(\n", + " config_json: InputPath(\"json\"),\n", + " hypodd_catalog_ct: InputPath(str),\n", + " hypodd_catalog_cc: InputPath(str),\n", + " gamma_catalog: InputPath(str),\n", + " standard_catalog: InputPath(str),\n", + " data_path: str = \"./\",\n", + " bucket_name: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = True,\n", + "):\n", + " import pandas as pd\n", + " import plotly.graph_objects as go\n", + " import numpy as np\n", + " import json\n", + " import os\n", + " from datetime import datetime\n", + " import matplotlib.pyplot as plt\n", + " import matplotlib.dates as mdates\n", + "\n", + " with open(config_json, \"r\") as fp:\n", + " config = json.load(fp)\n", + "\n", + " def plot3d(x, y, z, fig_name):\n", + " fig = go.Figure(\n", + " data=[\n", + " go.Scatter3d(\n", + " x=x,\n", + " y=y,\n", + " z=z,\n", + " mode=\"markers\",\n", + " marker=dict(size=3.0, color=-z, cmin=-60, cmax=2, colorscale=\"Viridis\", opacity=0.8),\n", + " )\n", + " ],\n", + " )\n", + "\n", + " fig.update_layout(\n", + " scene=dict(\n", + " xaxis=dict(\n", + " nticks=4,\n", + " range=config[\"xlim_degree\"],\n", + " ),\n", + " yaxis=dict(\n", + " nticks=4,\n", + " range=config[\"ylim_degree\"],\n", + " ),\n", + " zaxis=dict(\n", + " nticks=4,\n", + " # range=[z.max(), z.min()],\n", + " range=[60, -2],\n", + " ),\n", + " # aspectratio = dict(x=(xlim[1]-xlim[0])/2, y=(ylim[1]-ylim[0])/2, z=1),\n", + " aspectratio=dict(x=1, y=1, z=0.5),\n", + " ),\n", + " margin=dict(r=0, l=0, b=0, t=0),\n", + " )\n", + " fig.write_html(fig_name)\n", + "\n", + " hypodd_ct_catalog = pd.read_csv(\n", + " hypodd_catalog_ct,\n", + " sep=\"\\s+\",\n", + " names=[\n", + " \"ID\",\n", + " \"LAT\",\n", + " \"LON\",\n", + " \"DEPTH\",\n", + " \"X\",\n", + " \"Y\",\n", + " \"Z\",\n", + " \"EX\",\n", + " \"EY\",\n", + " \"EZ\",\n", + " \"YR\",\n", + " \"MO\",\n", + " \"DY\",\n", + " \"HR\",\n", + " \"MI\",\n", + " \"SC\",\n", + " \"MAG\",\n", + " \"NCCP\",\n", + " \"NCCS\",\n", + " \"NCTP\",\n", + " \"NCTS\",\n", + " \"RCC\",\n", + " \"RCT\",\n", + " \"CID\",\n", + " ],\n", + " )\n", + "\n", + " hypodd_ct_catalog[\"MO\"][hypodd_ct_catalog[\"MO\"] == 0] = 1\n", + " hypodd_ct_catalog[\"DY\"][hypodd_ct_catalog[\"DY\"] == 0] = 1\n", + " hypodd_ct_catalog[\"time\"] = hypodd_ct_catalog.apply(\n", + " lambda x: f'{x[\"YR\"]:04.0f}-{x[\"MO\"]:02.0f}-{x[\"DY\"]:02.0f}T{x[\"HR\"]:02.0f}:{x[\"MI\"]:02.0f}:{min(x[\"SC\"], 59.999):05.3f}',\n", + " axis=1,\n", + " )\n", + " hypodd_ct_catalog[\"magnitude\"] = hypodd_ct_catalog[\"MAG\"]\n", + " hypodd_ct_catalog[\"time\"] = hypodd_ct_catalog[\"time\"].apply(lambda x: datetime.strptime(x, \"%Y-%m-%dT%H:%M:%S.%f\"))\n", + " plot3d(\n", + " hypodd_ct_catalog[\"LON\"],\n", + " hypodd_ct_catalog[\"LAT\"],\n", + " hypodd_ct_catalog[\"DEPTH\"],\n", + " f\"{data_path}/hypodd_ct_catalog.html\",\n", + " )\n", + "\n", + " gamma_catalog = pd.read_csv(gamma_catalog, parse_dates=[\"time\"])\n", + " gamma_catalog[\"depth_km\"] = gamma_catalog[\"depth(m)\"] / 1e3\n", + " plot3d(\n", + " gamma_catalog[\"longitude\"],\n", + " gamma_catalog[\"latitude\"],\n", + " gamma_catalog[\"depth_km\"],\n", + " f\"{data_path}/gamma_catalog.html\",\n", + " )\n", + "\n", + " standard_catalog = pd.read_csv(standard_catalog, parse_dates=[\"time\"])\n", + " standard_catalog[\"depth_km\"] = standard_catalog[\"depth(m)\"] / 1e3\n", + " plot3d(\n", + " standard_catalog[\"longitude\"],\n", + " standard_catalog[\"latitude\"],\n", + " standard_catalog[\"depth_km\"],\n", + " f\"{data_path}/standard_catalog.html\",\n", + " )\n", + "\n", + " ## histogram\n", + " bins = 30\n", + " config[\"starttime\"] = datetime.fromisoformat(config[\"starttime\"])\n", + " config[\"endtime\"] = datetime.fromisoformat(config[\"endtime\"])\n", + " fig, ax = plt.subplots()\n", + " ax.hist(\n", + " gamma_catalog[\"time\"],\n", + " range=(config[\"starttime\"], config[\"endtime\"]),\n", + " bins=bins,\n", + " edgecolor=\"k\",\n", + " alpha=1.0,\n", + " linewidth=0.5,\n", + " label=f\"GaMMA: {len(gamma_catalog)}\",\n", + " )\n", + " ax.hist(\n", + " hypodd_ct_catalog[\"time\"],\n", + " range=(config[\"starttime\"], config[\"endtime\"]),\n", + " bins=bins,\n", + " edgecolor=\"k\",\n", + " alpha=0.8,\n", + " linewidth=0.5,\n", + " label=f\"HypoDD: {len(hypodd_ct_catalog)}\",\n", + " )\n", + " ax.hist(\n", + " standard_catalog[\"time\"],\n", + " range=(config[\"starttime\"], config[\"endtime\"]),\n", + " bins=bins,\n", + " edgecolor=\"k\",\n", + " alpha=0.6,\n", + " linewidth=0.5,\n", + " label=f\"Standard: {len(standard_catalog)}\",\n", + " )\n", + " # ax.set_xlabel(\"Date\")\n", + " ax.set_ylabel(\"Frequency\")\n", + " ax.autoscale(enable=True, axis=\"x\", tight=True)\n", + " # ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))\n", + " fig.autofmt_xdate()\n", + " ax.legend()\n", + " fig.savefig(f\"{data_path}/earthquake_frequency_time.png\", bbox_inches=\"tight\", dpi=300)\n", + " # fig.savefig(f\"{data_path}/earthquake_number.pdf\", bbox_inches=\"tight\")\n", + " plt.show()\n", + "\n", + " fig, ax = plt.subplots()\n", + " xrange = (-1.0, max(standard_catalog[\"magnitude\"].max(), gamma_catalog[\"magnitude\"].max()))\n", + " ax.hist(\n", + " gamma_catalog[\"magnitude\"],\n", + " range=xrange,\n", + " bins=bins,\n", + " alpha=1.0,\n", + " edgecolor=\"k\",\n", + " linewidth=0.5,\n", + " label=f\"GaMMA: {len(gamma_catalog['magnitude'])}\",\n", + " )\n", + " ax.hist(\n", + " hypodd_ct_catalog[\"magnitude\"],\n", + " range=xrange,\n", + " bins=bins,\n", + " alpha=0.6,\n", + " edgecolor=\"k\",\n", + " linewidth=0.5,\n", + " label=f\"HypoDD: {len(hypodd_ct_catalog['magnitude'])}\",\n", + " )\n", + " ax.hist(\n", + " standard_catalog[\"magnitude\"],\n", + " range=xrange,\n", + " bins=bins,\n", + " alpha=0.6,\n", + " edgecolor=\"k\",\n", + " linewidth=0.5,\n", + " label=f\"Standard: {len(standard_catalog['magnitude'])}\",\n", + " )\n", + " ax.legend()\n", + " ax.autoscale(enable=True, axis=\"x\", tight=True)\n", + " ax.set_xlabel(\"Magnitude\")\n", + " ax.set_ylabel(\"Frequency\")\n", + " ax.set_yscale(\"log\")\n", + " fig.savefig(f\"{data_path}/earthquake_magnitude_frequency.png\", bbox_inches=\"tight\", dpi=300)\n", + " # fig.savefig(f\"{data_path}/earthquake_magnitude_frequency.pdf\", bbox_inches=\"tight\")\n", + " plt.show()\n", + "\n", + " fig, ax = plt.subplots()\n", + " ax.plot(\n", + " gamma_catalog[\"time\"],\n", + " gamma_catalog[\"magnitude\"],\n", + " \".\",\n", + " markersize=5.0,\n", + " alpha=1.0,\n", + " rasterized=True,\n", + " label=f\"GaMMA: {len(gamma_catalog['magnitude'])}\",\n", + " )\n", + " ax.plot(\n", + " hypodd_ct_catalog[\"time\"],\n", + " hypodd_ct_catalog[\"magnitude\"],\n", + " \".\",\n", + " markersize=5.0,\n", + " alpha=1.0,\n", + " rasterized=True,\n", + " label=f\"HypoDD: {len(hypodd_ct_catalog['magnitude'])}\",\n", + " )\n", + " ax.plot(\n", + " standard_catalog[\"time\"],\n", + " standard_catalog[\"magnitude\"],\n", + " \".\",\n", + " markersize=5.0,\n", + " alpha=1.0,\n", + " rasterized=True,\n", + " label=f\"Standard: {len(standard_catalog['magnitude'])}\",\n", + " )\n", + " ax.set_xlim(config[\"starttime\"], config[\"endtime\"])\n", + " ax.set_ylabel(\"Magnitude\")\n", + " # ax.set_xlabel(\"Date\")\n", + " ax.set_ylim(bottom=-1)\n", + " ax.legend(markerscale=2)\n", + " ax.grid()\n", + " # ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))\n", + " fig.autofmt_xdate()\n", + " fig.savefig(f\"{data_path}/earthquake_magnitude_time.png\", bbox_inches=\"tight\", dpi=300)\n", + " # fig.savefig(f\"{data_path}/earthquake_magnitude_time.pdf\", bbox_inches=\"tight\", dpi=300)\n", + " plt.show()\n", + "\n", + " try:\n", + " hypodd_cc_catalog = pd.read_csv(\n", + " hypodd_catalog_cc,\n", + " sep=\"\\s+\",\n", + " names=[\n", + " \"ID\",\n", + " \"LAT\",\n", + " \"LON\",\n", + " \"DEPTH\",\n", + " \"X\",\n", + " \"Y\",\n", + " \"Z\",\n", + " \"EX\",\n", + " \"EY\",\n", + " \"EZ\",\n", + " \"YR\",\n", + " \"MO\",\n", + " \"DY\",\n", + " \"HR\",\n", + " \"MI\",\n", + " \"SC\",\n", + " \"MAG\",\n", + " \"NCCP\",\n", + " \"NCCS\",\n", + " \"NCTP\",\n", + " \"NCTS\",\n", + " \"RCC\",\n", + " \"RCT\",\n", + " \"CID\",\n", + " ],\n", + " )\n", + " hypodd_cc_catalog[\"time\"] = hypodd_cc_catalog.apply(\n", + " lambda x: f'{x[\"YR\"]:04.0f}-{x[\"MO\"]:02.0f}-{x[\"DY\"]:02.0f}T{x[\"HR\"]:02.0f}:{x[\"MI\"]:02.0f}:{min(x[\"SC\"], 59.999):05.3f}',\n", + " axis=1,\n", + " )\n", + " hypodd_cc_catalog[\"time\"] = hypodd_cc_catalog[\"time\"].apply(\n", + " lambda x: datetime.strptime(x, \"%Y-%m-%dT%H:%M:%S.%f\")\n", + " )\n", + " plot3d(\n", + " hypodd_cc_catalog[\"LON\"],\n", + " hypodd_cc_catalog[\"LAT\"],\n", + " hypodd_cc_catalog[\"DEPTH\"],\n", + " f\"{data_path}/hypodd_cc_catalog.html\",\n", + " )\n", + " except Exception as err:\n", + " print(f\"{err}\")\n", + "\n", + " ## upload to s3 bucket\n", + " try:\n", + " from minio import Minio\n", + "\n", + " minioClient = Minio(s3_url, access_key=\"minio\", secret_key=\"minio123\", secure=secure)\n", + " if not minioClient.bucket_exists(bucket_name):\n", + " minioClient.make_bucket(bucket_name)\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/hypodd_ct_catalog.html\",\n", + " f\"{data_path}/hypodd_ct_catalog.html\",\n", + " )\n", + "\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/gamma_catalog.html\",\n", + " f\"{data_path}/gamma_catalog.html\",\n", + " )\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/standard_catalog.html\",\n", + " f\"{data_path}/standard_catalog.html\",\n", + " )\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/earthquake_frequency_time.png\",\n", + " f\"{data_path}/earthquake_frequency_time.png\",\n", + " )\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/earthquake_magnitude_frequency.png\",\n", + " f\"{data_path}/earthquake_magnitude_frequency.png\",\n", + " )\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/earthquake_magnitude_time.png\",\n", + " f\"{data_path}/earthquake_magnitude_time.png\",\n", + " )\n", + " if os.path.exists(f\"{data_path}/hypodd_cc_catalog.html\"):\n", + " minioClient.fput_object(\n", + " bucket_name,\n", + " f\"{config['region']}/hypodd_cc_catalog.html\",\n", + " f\"{data_path}/hypodd_cc_catalog.html\",\n", + " )\n", + "\n", + " except Exception as err:\n", + " print(f\"ERROR: can not access minio service! \\n{err}\")\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.458125Z", + "iopub.status.busy": "2022-08-11T15:42:43.458012Z", + "iopub.status.idle": "2022-08-11T15:42:43.460480Z", + "shell.execute_reply": "2022-08-11T15:42:43.460272Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.458110Z" + }, + "tags": [] + }, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'plotly'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m/Users/weiqiang/Research/QuakeFlow_cleanup/kubeflow/workflow.ipynb Cell 71\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[39mif\u001b[39;00m run_local:\n\u001b[0;32m----> 2\u001b[0m visulization(\n\u001b[1;32m 3\u001b[0m root_dir(\u001b[39m\"\u001b[39;49m\u001b[39mconfig.json\u001b[39;49m\u001b[39m\"\u001b[39;49m),\n\u001b[1;32m 4\u001b[0m root_dir(\u001b[39m\"\u001b[39;49m\u001b[39mhypodd_ct_catalog.txt\u001b[39;49m\u001b[39m\"\u001b[39;49m),\n\u001b[1;32m 5\u001b[0m root_dir(\u001b[39m\"\u001b[39;49m\u001b[39mhypodd_cc_catalog.txt\u001b[39;49m\u001b[39m\"\u001b[39;49m),\n\u001b[1;32m 6\u001b[0m root_dir(\u001b[39m\"\u001b[39;49m\u001b[39mgamma_catalog.csv\u001b[39;49m\u001b[39m\"\u001b[39;49m),\n\u001b[1;32m 7\u001b[0m root_dir(\u001b[39m\"\u001b[39;49m\u001b[39mstandard_catalog.csv\u001b[39;49m\u001b[39m\"\u001b[39;49m),\n\u001b[1;32m 8\u001b[0m root_dir(\u001b[39m\"\u001b[39;49m\u001b[39m\"\u001b[39;49m),\n\u001b[1;32m 9\u001b[0m )\n", + "\u001b[1;32m/Users/weiqiang/Research/QuakeFlow_cleanup/kubeflow/workflow.ipynb Cell 71\u001b[0m in \u001b[0;36mvisulization\u001b[0;34m(config_json, hypodd_catalog_ct, hypodd_catalog_cc, gamma_catalog, standard_catalog, data_path, bucket_name, s3_url, secure)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mvisulization\u001b[39m(\n\u001b[1;32m 2\u001b[0m config_json: InputPath(\u001b[39m\"\u001b[39m\u001b[39mjson\u001b[39m\u001b[39m\"\u001b[39m),\n\u001b[1;32m 3\u001b[0m hypodd_catalog_ct: InputPath(\u001b[39mstr\u001b[39m),\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 10\u001b[0m secure: \u001b[39mbool\u001b[39m \u001b[39m=\u001b[39m \u001b[39mTrue\u001b[39;00m,\n\u001b[1;32m 11\u001b[0m ):\n\u001b[1;32m 12\u001b[0m \u001b[39mimport\u001b[39;00m \u001b[39mpandas\u001b[39;00m \u001b[39mas\u001b[39;00m \u001b[39mpd\u001b[39;00m\n\u001b[0;32m---> 13\u001b[0m \u001b[39mimport\u001b[39;00m \u001b[39mplotly\u001b[39;00m\u001b[39m.\u001b[39;00m\u001b[39mgraph_objects\u001b[39;00m \u001b[39mas\u001b[39;00m \u001b[39mgo\u001b[39;00m\n\u001b[1;32m 14\u001b[0m \u001b[39mimport\u001b[39;00m \u001b[39mnumpy\u001b[39;00m \u001b[39mas\u001b[39;00m \u001b[39mnp\u001b[39;00m\n\u001b[1;32m 15\u001b[0m \u001b[39mimport\u001b[39;00m \u001b[39mjson\u001b[39;00m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'plotly'" + ] + } + ], + "source": [ + "if run_local:\n", + " visulization(\n", + " root_dir(\"config.json\"),\n", + " root_dir(\"hypodd_ct_catalog.txt\"),\n", + " root_dir(\"hypodd_cc_catalog.txt\"),\n", + " root_dir(\"gamma_catalog.csv\"),\n", + " root_dir(\"standard_catalog.csv\"),\n", + " root_dir(\"\"),\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.461051Z", + "iopub.status.busy": "2022-08-11T15:42:43.460862Z", + "iopub.status.idle": "2022-08-11T15:42:43.480652Z", + "shell.execute_reply": "2022-08-11T15:42:43.480381Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.461035Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "visulization_op = comp.func_to_container_op(\n", + " visulization,\n", + " base_image=\"python:3.8\",\n", + " packages_to_install=[\"matplotlib\", \"pandas\", \"plotly\", \"minio\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 9. Parallel process on cloud" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.481317Z", + "iopub.status.busy": "2022-08-11T15:42:43.481182Z", + "iopub.status.idle": "2022-08-11T15:42:43.491801Z", + "shell.execute_reply": "2022-08-11T15:42:43.491517Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.481301Z" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "@dsl.pipeline(name=\"QuakeFlow\", description=\"\")\n", + "def quakeflow_pipeline(\n", + " data_path: str = \"/tmp/\",\n", + " num_parallel=0,\n", + " bucket_catalog: str = \"catalogs\",\n", + " s3_url: str = \"minio-service:9000\",\n", + " secure: bool = False,\n", + "):\n", + "\n", + " config = (\n", + " config_op(region_name, num_parallel, bucket_name=f\"catalogs\", s3_url=s3_url, secure=secure)\n", + " .set_retry(3)\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-2g\")\n", + " .set_cpu_request(\"700m\")\n", + " )\n", + " config.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + "\n", + " events = (\n", + " download_events_op(config.outputs[\"config_json\"], bucket_name=f\"catalogs\", s3_url=s3_url, secure=secure)\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-16g\")\n", + " .set_retry(3)\n", + " .set_memory_request(\"4G\")\n", + " .set_cpu_request(\"700m\")\n", + " .set_display_name(\"Download Events\")\n", + " )\n", + " events.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + "\n", + " stations = (\n", + " download_stations_op(config.outputs[\"config_json\"], bucket_name=f\"catalogs\", s3_url=s3_url, secure=secure)\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-2g\")\n", + " .set_retry(3)\n", + " .set_cpu_request(\"700m\")\n", + " .set_display_name(\"Download Stations\")\n", + " )\n", + " stations.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + "\n", + " with kfp.dsl.ParallelFor(config.outputs[\"output\"]) as i:\n", + "\n", + " vop_ = dsl.VolumeOp(\n", + " name=f\"Create volume {region_name}\",\n", + " resource_name=f\"data-volume-{str(i)}\",\n", + " size=\"120Gi\",\n", + " modes=dsl.VOLUME_MODE_RWO,\n", + " ).set_retry(3)\n", + "\n", + " download_op_ = (\n", + " download_waveform_op(\n", + " i,\n", + " config.outputs[\"index_json\"],\n", + " config.outputs[\"config_json\"],\n", + " config.outputs[\"datetime_json\"],\n", + " stations.outputs[\"station_pkl\"],\n", + " data_path=data_path,\n", + " bucket_name=\"waveforms\",\n", + " s3_url=s3_url,\n", + " secure=secure,\n", + " )\n", + " .add_pvolumes({data_path: vop_.volume})\n", + " .set_cpu_request(\"700m\")\n", + " # .set_cpu_request(\"350m\")\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-2g\")\n", + " .set_retry(5)\n", + " .set_display_name(\"Download Waveforms\")\n", + " )\n", + " download_op_.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + "\n", + " phasenet_op_ = (\n", + " phasenet_op(\n", + " download_op_.outputs[\"Output\"],\n", + " download_op_.outputs[\"fname_csv\"],\n", + " stations.outputs[\"station_json\"],\n", + " )\n", + " .add_pvolumes({data_path: download_op_.pvolume})\n", + " .set_memory_request(\"9G\")\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"pool-16g\")\n", + " .set_retry(5)\n", + " .set_display_name(\"PhaseNet Picking\")\n", + " )\n", + " phasenet_op_.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + " phasenet_op_.set_image_pull_policy(\"Always\")\n", + "\n", + " gamma_op_ = (\n", + " gamma_op(\n", + " i,\n", + " config.outputs[\"index_json\"],\n", + " config.outputs[\"config_json\"],\n", + " phasenet_op_.outputs[\"picks\"],\n", + " stations.outputs[\"station_json\"],\n", + " bucket_name=f\"catalogs\",\n", + " s3_url=s3_url,\n", + " secure=secure,\n", + " )\n", + " .set_cpu_request(\"800m\")\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"pool-16g\")\n", + " .set_retry(3)\n", + " .set_display_name(\"GaMMA Association\")\n", + " )\n", + " gamma_op_.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + "\n", + " # resume_op_ = (\n", + " # resume_waveform_op(\n", + " # i,\n", + " # config.outputs[\"index_json\"],\n", + " # config.outputs[\"config_json\"],\n", + " # config.outputs[\"datetime_json\"],\n", + " # data_path=data_path,\n", + " # bucket_name=\"waveforms\",\n", + " # s3_url=s3_url,\n", + " # secure=secure,\n", + " # )\n", + " # .add_pvolumes({data_path: vop_.volume})\n", + " # .set_cpu_request(\"700m\")\n", + " # # .set_cpu_request(\"350m\")\n", + " # .set_retry(5)\n", + " # .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-2g\")\n", + " # .set_display_name(\"Resume Waveforms\")\n", + " # )\n", + " # resume_op_.execution_options.caching_strategy.max_cache_staleness = \"P0D\"\n", + "\n", + " # save_op_ = (\n", + " # save_waveform_op(\n", + " # i,\n", + " # config.outputs[\"index_json\"],\n", + " # config.outputs[\"config_json\"],\n", + " # config.outputs[\"datetime_json\"],\n", + " # data_path=data_path,\n", + " # bucket_name=\"waveforms\",\n", + " # s3_url=s3_url,\n", + " # secure=secure,\n", + " # )\n", + " # .add_pvolumes({data_path: vop_.volume})\n", + " # .set_cpu_request(\"700m\")\n", + " # # .set_cpu_request(\"350m\")\n", + " # .set_retry(5)\n", + " # .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-2g\")\n", + " # .set_display_name(\"Save Waveforms\")\n", + " # )\n", + " # save_op_.execution_options.caching_strategy.max_cache_staleness = \"P0D\"\n", + "\n", + " merge_op_ = (\n", + " merge_op(\n", + " config.outputs[\"index_json\"],\n", + " config.outputs[\"config_json\"],\n", + " bucket_name=f\"catalogs\",\n", + " s3_url=s3_url,\n", + " secure=secure,\n", + " )\n", + " .after(gamma_op_)\n", + " .set_memory_request(\"12G\")\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-64g\")\n", + " .set_display_name(\"Merge Catalog\")\n", + " )\n", + " merge_op_.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + "\n", + " convert_station_op_ = (\n", + " convert_station_op(\n", + " config_json=config.outputs[\"config_json\"],\n", + " station_json=stations.outputs[\"station_json\"],\n", + " bucket_name=f\"catalogs\",\n", + " s3_url=s3_url,\n", + " secure=secure,\n", + " )\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-2g\")\n", + " .set_display_name(\"Convert Station Format\")\n", + " )\n", + " split_hypodd_op_ = (\n", + " split_hypodd_op(\n", + " config.outputs[\"config_json\"],\n", + " catalog_csv=merge_op_.outputs[\"catalog_csv\"],\n", + " )\n", + " .after(merge_op_)\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-64g\")\n", + " .set_display_name(\"Split Catalog\")\n", + " )\n", + " split_hypodd_op_.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + " split_hypodd_op_.set_image_pull_policy(\"Always\")\n", + "\n", + " with kfp.dsl.ParallelFor(split_hypodd_op_.outputs[\"output\"]) as i:\n", + "\n", + " convert_phase_op_ = (\n", + " convert_phase_op(\n", + " i,\n", + " config_json=config.outputs[\"config_json\"],\n", + " picks_csv=merge_op_.outputs[\"picks_csv\"],\n", + " catalog_csv=merge_op_.outputs[\"catalog_csv\"],\n", + " bucket_name=\"catalogs\",\n", + " s3_url=s3_url,\n", + " secure=secure,\n", + " )\n", + " .set_retry(3)\n", + " .set_display_name(\"Convert Phase Format\")\n", + " # .set_memory_request(\"48G\")\n", + " # .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-64g\")\n", + " .set_memory_request(\"12G\")\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"pool-16g\")\n", + " )\n", + " convert_phase_op_.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + " convert_phase_op_.set_image_pull_policy(\"Always\")\n", + "\n", + " ph2dt_op_ = (\n", + " ph2dt_op(\n", + " i,\n", + " config_json=config.outputs[\"config_json\"],\n", + " hypodd_phase=convert_phase_op_.outputs[\"hypodd_phase\"],\n", + " station_dat=convert_station_op_.outputs[\"hypodd_station\"],\n", + " bucket_name=\"catalogs\",\n", + " s3_url=s3_url,\n", + " secure=secure,\n", + " )\n", + " .set_display_name(\"PH2DT\")\n", + " .set_memory_request(\"12G\")\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-16g\")\n", + " )\n", + " ph2dt_op_.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + " ph2dt_op_.set_image_pull_policy(\"Always\")\n", + "\n", + " hypodd_ct_op_ = (\n", + " hypodd_ct_op(\n", + " i,\n", + " config_json=config.outputs[\"config_json\"],\n", + " ct=ph2dt_op_.outputs[\"ct\"],\n", + " event=ph2dt_op_.outputs[\"hypodd_event\"],\n", + " station=convert_station_op_.outputs[\"hypodd_station\"],\n", + " bucket_name=\"catalogs\",\n", + " s3_url=s3_url,\n", + " secure=secure,\n", + " )\n", + " .set_display_name(\"HypoDD\")\n", + " .set_memory_request(\"12G\")\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"pool-16g\")\n", + " )\n", + " hypodd_ct_op_.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + " hypodd_ct_op_.set_image_pull_policy(\"Always\")\n", + "\n", + " # cc_op_ = cc_op(\n", + " # ct=ph2dt_op_.outputs[\"ct\"],\n", + " # picks=merge_op_.outputs[\"picks_csv\"],\n", + " # catalog=merge_op_.outputs[\"catalog_csv\"],\n", + " # ).set_display_name('Cross Correlation')\n", + " # cc_op_.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + " # cc_op_.set_image_pull_policy(\"Always\")\n", + "\n", + " # hypodd_cc_op_ = hypodd_cc_op(\n", + " # i,\n", + " # config_json=config.outputs[\"config_json\"],\n", + " # ct=ph2dt_op_.outputs[\"ct\"],\n", + " # cc=cc_op_.outputs[\"cc\"],\n", + " # event=ph2dt_op_.outputs[\"hypodd_event\"],\n", + " # station=convert_station_op_.outputs[\"hypodd_station\"],\n", + " # bucket_name=\"catalogs\",\n", + " # s3_url=s3_url,\n", + " # secure=secure,\n", + " # ).set_display_name('HypoDD + CC')\n", + " # hypodd_cc_op_.execution_options.caching_strategy.max_cache_staleness = \"P30D\"\n", + " # hypodd_cc_op_.set_image_pull_policy(\"Always\")\n", + "\n", + " merge_hypodd_op_ = (\n", + " merge_hypodd_op(\n", + " split_hypodd_op_.outputs[\"output\"],\n", + " config_json=config.outputs[\"config_json\"],\n", + " bucket_name=f\"catalogs\",\n", + " s3_url=s3_url,\n", + " secure=secure,\n", + " )\n", + " .after(hypodd_ct_op_)\n", + " # .after(hypodd_cc_op_)\n", + " .set_display_name(\"Merge Catalog\")\n", + " .add_node_selector_constraint(\"cloud.google.com/gke-nodepool\", \"spot-16g\")\n", + " )\n", + " merge_hypodd_op_.execution_options.caching_strategy.max_cache_staleness = \"P0D\"\n", + " merge_hypodd_op_.set_image_pull_policy(\"Always\")\n", + "\n", + " visulization_op_ = (\n", + " visulization_op(\n", + " config_json=config.outputs[\"config_json\"],\n", + " hypodd_catalog_ct=merge_hypodd_op_.outputs[\"catalog_ct\"],\n", + " hypodd_catalog_cc=merge_hypodd_op_.outputs[\"catalog_cc\"],\n", + " gamma_catalog=merge_op_.outputs[\"catalog_csv\"],\n", + " standard_catalog=events.outputs[\"standard_catalog\"],\n", + " bucket_name=f\"catalogs\",\n", + " s3_url=s3_url,\n", + " secure=secure,\n", + " )\n", + " .after(merge_hypodd_op_)\n", + " .set_display_name(\"Visulization\")\n", + " )\n", + " visulization_op_.execution_options.caching_strategy.max_cache_staleness = \"P0D\"\n", + " visulization_op_.set_image_pull_policy(\"Always\")\n", + "\n", + " #### vop_.delete().after(merge_hypodd_op_)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "execution": { + "iopub.execute_input": "2022-08-11T15:42:43.492378Z", + "iopub.status.busy": "2022-08-11T15:42:43.492260Z", + "iopub.status.idle": "2022-08-11T15:42:45.316808Z", + "shell.execute_reply": "2022-08-11T15:42:45.316527Z", + "shell.execute_reply.started": "2022-08-11T15:42:43.492362Z" + }, + "tags": [] + }, + "outputs": [ + { + "data": { + "text/html": [ + "Experiment details." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "Run details." + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import os\n", + "\n", + "os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"] = \"/Users/weiqiang/.dotbot/cloud/quakeflow_zhuwq.json\"\n", + "experiment_name = \"QuakeFlow\"\n", + "pipeline_func = quakeflow_pipeline\n", + "run_name = f\"{pipeline_func.__name__}_{region_name.lower()}\"\n", + "\n", + "arguments = {\n", + " \"data_path\": \"/tmp\",\n", + " \"num_parallel\": 0,\n", + " \"bucket_catalog\": \"catalogs\",\n", + " \"s3_url\": \"minio-service:9000\",\n", + " # \"s3_url\": \"quakeflow-minio:9000\",\n", + " \"secure\": False,\n", + "}\n", + "\n", + "if not run_local:\n", + " pipeline_conf = kfp.dsl.PipelineConf()\n", + " pipeline_conf.set_image_pull_policy(\"Always\")\n", + " pipeline_conf.ttl_seconds_after_finished = 60 * 10\n", + " client = kfp.Client(host=\"56496b41855e5ce2-dot-us-west1.pipelines.googleusercontent.com\")\n", + " # client = kfp.Client(host=\"http://localhost:8080\")\n", + " kfp.compiler.Compiler().compile(pipeline_func, \"{}.zip\".format(experiment_name), pipeline_conf=pipeline_conf)\n", + " results = client.create_run_from_pipeline_func(\n", + " pipeline_func,\n", + " experiment_name=experiment_name,\n", + " run_name=run_name,\n", + " arguments=arguments,\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13 | packaged by conda-forge | (main, May 27 2022, 17:00:33) \n[Clang 13.0.1 ]" + }, + "vscode": { + "interpreter": { + "hash": "0efb5d07c150d814a79610ed835fac9f37a29f75f64726a0e33cb3dca03bca5e" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}