{ "cells": [ { "cell_type": "markdown", "id": "5347b43d", "metadata": {}, "source": [ "# Example 0: Convert external data\n", "\n", "In this example we will download external data that will be used to estimate relative moment tensors for seismic aftershocks related to the 2015-2017 Pamir earthquake sequence and convert them to the data formats required by *relMT*. For background information on the data set, please refer to [Bloch et al. (2023, GJI)](https://doi.org/10.1093/gji/ggac473).\n", "\n", "> **Note**\n", ">\n", "> This tutorial relies on the command line tools `cd` `mkdir` and `wget`.\n", ">\n", "> They are part of most operating systems, but not all.\n", ">\n", "> `head` and `ls` are also used, but not required.\n", "\n", "We will start by importing modules required for this tutorial." ] }, { "cell_type": "code", "execution_count": 1, "id": "f0081707", "metadata": { "execution": { "iopub.execute_input": "2026-02-02T09:17:46.028283Z", "iopub.status.busy": "2026-02-02T09:17:46.028141Z", "iopub.status.idle": "2026-02-02T09:17:46.824381Z", "shell.execute_reply": "2026-02-02T09:17:46.823309Z" } }, "outputs": [], "source": [ "\n", "from relmt import io, extra, mt, utils" ] }, { "cell_type": "markdown", "id": "f3931253", "metadata": {}, "source": [ "## Download external data\n", "\n", "We create a folder `ext/` to store the external data. For this example, we access the data publications\n", "\n", "Bloch et al. (2022) Earthquake and Moment Tensor Catalogs of the 2015-2017 Pamir Earthquake Sequence. *GFZ Data Services*. https://doi.org/10.5880/fidgeo.2022.007\n", "\n", "and\n", "\n", "Bloch et al. (2026): Earthquake Phase Arrival Times of the 2015-2017 Pamir Earthquake Sequence. GFZ Data Services. https://doi.org/10.5880/fidgeo.2026.006\n", "\n", "Let us create the directory, change into it and download the data." ] }, { "cell_type": "code", "execution_count": 2, "id": "66992114", "metadata": { "execution": { "iopub.execute_input": "2026-02-02T09:17:46.828692Z", "iopub.status.busy": "2026-02-02T09:17:46.828481Z", "iopub.status.idle": "2026-02-02T09:17:49.560269Z", "shell.execute_reply": "2026-02-02T09:17:49.558441Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2026-02-02 10:17:47 URL:https://datapub.gfz.de/download/10.5880.FIDGEO.2022.007Geazgf/2022-007_Bloch-et-al_seismic_event_catalog.txt [1885974/1885974] -> \"ext/2022-007_Bloch-et-al_seismic_event_catalog.txt\" [1]\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2026-02-02 10:17:48 URL:https://datapub.gfz.de/download/10.5880.FIDGEO.2022.007Geazgf/2022-007_Bloch-et-al_moment_tensor_catalog_correct_norm_v2.0.txt [5200/5200] -> \"ext/2022-007_Bloch-et-al_moment_tensor_catalog_correct_norm_v2.0.txt\" [1]\r\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "2026-02-02 10:17:49 URL:https://datapub.gfz.de/download/10.5880.FIDGEO.2026.006-Kacenu/2026-006_Bloch-et-al_2015-2017_pamir_catalog_bulletin.xml [53511277/53511277] -> \"ext/2026-006_Bloch-et-al_2015-2017_pamir_catalog_bulletin.xml\" [1]\r\n" ] } ], "source": [ "# Make the directory, no warning if exists\n", "! mkdir -p ext data\n", "\n", "# -nc avoids re-downloading, -nv is less verbose, -P sets target directory\n", "! wget -nc -nv -P ext https://datapub.gfz.de/download/10.5880.FIDGEO.2022.007Geazgf/2022-007_Bloch-et-al_seismic_event_catalog.txt\n", "! wget -nc -nv -P ext https://datapub.gfz.de/download/10.5880.FIDGEO.2022.007Geazgf/2022-007_Bloch-et-al_moment_tensor_catalog_correct_norm_v2.0.txt\n", "! wget -nc -nv -P ext https://datapub.gfz.de/download/10.5880.FIDGEO.2026.006-Kacenu/2026-006_Bloch-et-al_2015-2017_pamir_catalog_bulletin.xml\n" ] }, { "cell_type": "markdown", "id": "6f9e51dd", "metadata": {}, "source": [ "## Create a *relMT* event file\n", "\n", "We will now create a *relMT* compliant event file. Let us have a look at the provided catalog file." ] }, { "cell_type": "code", "execution_count": 3, "id": "24f2d95d", "metadata": { "execution": { "iopub.execute_input": "2026-02-02T09:17:49.564688Z", "iopub.status.busy": "2026-02-02T09:17:49.564490Z", "iopub.status.idle": "2026-02-02T09:17:49.724918Z", "shell.execute_reply": "2026-02-02T09:17:49.723493Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# License: Creative Commons Attribution 4.0 International License (CC BY 4.0), https://creativecommons.org/licenses/by/4.0/\r\n", "# Citation: Bloch, W.; Schurr, B.; Yuan, X.; Xu, Q.; Zhao, J.; Murodkulov, S.; Oimuhammadzoda, I. (2022): Earthquake and Moment Tensor Catalogs of the 2015--2017 Pamir Earthquake Sequence. GFZ Data Services. https://doi.org/10.5880/fidgeo.2022.007\r\n", "#\r\n", "#Year Month Day Hour Minute Second Timestamp(s) Longitude(deg) Latitude(deg) Depth(km) P-picks S-picks revised? Method RMS(s) Magnitude error type Sequence\r\n", " 2015 08 03 14 37 08.00 1438612628.00 73.95270 38.48570 130.39 9 6 0 simulps 0.280 3.70 0.42 ML Z \r\n", " 2015 08 04 02 10 29.00 1438654229.00 71.71370 37.19950 135.87 8 0 0 simulps 0.270 4.30 0.33 ML Z \r\n", " 2015 08 04 22 19 21.00 1438726761.00 76.81780 39.48380 -3.00 6 0 0 simulps 0.330 2.37 0.33 ML O \r\n", " 2015 08 05 03 16 08.00 1438744568.00 75.24200 39.00650 27.69 6 1 0 simulps 0.620 2.40 0.22 ML O \r\n", " 2015 08 06 06 54 12.00 1438844052.00 72.15470 37.80350 96.07 6 0 0 simulps 0.480 3.02 0.29 ML Z \r\n", " 2015 08 06 07 34 03.00 1438846443.00 73.72970 38.34800 126.44 9 5 0 simulps 0.480 3.07 0.35 ML Z \r\n" ] } ], "source": [ "\n", "! head ext/2022-007_Bloch-et-al_seismic_event_catalog.txt" ] }, { "cell_type": "markdown", "id": "b3c198ff", "metadata": {}, "source": [ "We find that the seismic event catalog contains the locations of the events in columns 7, 8 and 9 (0-based indexing), the origin time in column 6 (as a time stamp in seconds since 1970), and the magnitude in column 15. Some of the tools of the `extra` module will help us to:\n", "\n", "* Convert the locations from geographic (degree) to UTM (meter) coordinates\n", "* Provide a date string as an event name\n", "* Save it in the `data/` subdirectory for use in the later examples\n", "\n", "The Pamir highlands are located in [UTM zone 43 S](https://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system), in the Tajik Chinese border region." ] }, { "cell_type": "code", "execution_count": 4, "id": "0ef5fecc", "metadata": { "execution": { "iopub.execute_input": "2026-02-02T09:17:49.728180Z", "iopub.status.busy": "2026-02-02T09:17:49.728027Z", "iopub.status.idle": "2026-02-02T09:17:50.006049Z", "shell.execute_reply": "2026-02-02T09:17:50.005258Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The seismic event catalog has 11784 records.\n", "The first event is:\n", "Event(north=np.float64(4260226.228515374), east=np.float64(408658.4556633276), depth=np.float64(130389.99999999999), time=1438612628.0, mag=np.float64(3.7), name='20150803143708')\n" ] } ], "source": [ "# The external seismic event catalog file\n", "catf = \"ext/2022-007_Bloch-et-al_seismic_event_catalog.txt\"\n", "\n", "# Geoconverter for UTM zone 43S (Pamir region)\n", "def geoconv(lat, lon, dep):\n", " return extra.geoconverter_latlon2utm(lat, lon, dep, 43, \"S\")\n", "\n", "\n", "# Event name is the origin time in YYYYMMDDHHMMSS format\n", "def nameconv(timetuple):\n", " yr, mo, da, hr, mn, sc = timetuple\n", " return f\"{yr}{mo}{da}{hr}{mn}{sc[:2]}\"\n", "\n", "\n", "# Read the seismic event catalog into an event dictionary\n", "evd = io.read_ext_event_table(\n", " catf,\n", " *(8, 7, 9, 6, 15), # north, east, depth, magnitude, time\n", " (0, 1, 2, 3, 4, 5), # year, month, day, hour, minute, second\n", " geoconv,\n", " nameconverter=nameconv,\n", ")\n", "\n", "# And save it to file for later use\n", "io.write_event_table(evd, \"data/events.txt\")\n", "\n", "print(f\"The seismic event catalog has {len(evd)} records.\")\n", "print(\"The first event is:\")\n", "print(evd[0])" ] }, { "cell_type": "markdown", "id": "102c79ec", "metadata": {}, "source": [ "## Create a reference MT file\n", "\n", "Next we will convert the moment tensor file. First, we inspect the file." ] }, { "cell_type": "code", "execution_count": 5, "id": "dc0bfff4", "metadata": { "execution": { "iopub.execute_input": "2026-02-02T09:17:50.008793Z", "iopub.status.busy": "2026-02-02T09:17:50.008647Z", "iopub.status.idle": "2026-02-02T09:17:50.169844Z", "shell.execute_reply": "2026-02-02T09:17:50.168467Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#Date Time Longitude(deg) Latitude(deg) CentroidDepth(km) Mw mrr mtt mff mrt mrf mtf exp Strike(deg) Dip(deg) Rake(deg)\r\n", "2015/12/07 10:34:22 72.90430 38.28920 9 4.4 0.897 -3.776 2.880 0.386 1.884 -3.049 22 26 81 24 \r\n", "2015/12/07 15:23:57 73.22530 38.71950 4 4.6 -1.816 -2.846 4.662 6.116 -0.731 -2.215 22 198 40 -16 \r\n", "2015/12/27 23:05:28 72.69670 38.06920 6 4.2 -1.633 0.083 1.550 -0.955 -0.228 0.725 22 181 40 -126 \r\n", "2016/01/13 21:37:37 73.32220 38.74230 9 4.8 -0.594 -0.782 1.376 0.489 -0.965 0.211 23 225 40 -22 \r\n", "2016/03/18 16:11:00 72.61820 38.00300 4 5.3 -0.025 -0.854 0.879 0.217 -0.339 -0.221 24 219 68 5 \r\n", "2016/03/21 05:32:28 72.58100 38.00170 4 4.1 -0.740 -0.285 1.025 0.333 -0.790 0.504 22 230 38 -35 \r\n", "2016/04/09 16:19:33 73.50194 39.42820 9 4.4 2.088 -0.458 -1.631 0.370 -2.683 -3.822 22 79 50 157 \r\n", "2016/06/27 06:25:38 73.46270 39.43750 12 4.6 6.512 -7.984 1.471 -2.013 2.103 -2.587 22 278 55 120 \r\n", "2016/06/27 07:34:13 73.65710 39.44735 6 4.3 -0.736 -1.178 1.914 -1.176 -2.193 -1.066 22 123 37 -166 \r\n" ] } ], "source": [ "! head ext/2022-007_Bloch-et-al_moment_tensor_catalog_correct_norm_v2.0.txt" ] }, { "cell_type": "markdown", "id": "e3ff4813", "metadata": {}, "source": [ "The moment tensor catalog contains the components of the moment tensor. The format follows the Harvard convention used by the [Global CMT project](https://docs.generic-mapping-tools.org/latest/supplements/seis/meca.html) and documented e.g. in [GMT meca -Sm](https://docs.generic-mapping-tools.org/latest/supplements/seis/meca.html). The elements of the moment tensor in [dyne cm] units are described in columns 6 to 12 (0-based indexing).\n", "\n", "For use in *relMT* we will next\n", "* Convert the event time to a string that matches the event name of the catalog\n", "* Convert from Harvard (R, $\\theta$, $\\phi$) to North-East-Down coordinates\n", "* Convert from dyne cm to Newton meter (Nm)\n", "* Write the moment tensor table" ] }, { "cell_type": "code", "execution_count": 6, "id": "04244026", "metadata": { "execution": { "iopub.execute_input": "2026-02-02T09:17:50.172841Z", "iopub.status.busy": "2026-02-02T09:17:50.172695Z", "iopub.status.idle": "2026-02-02T09:17:50.233336Z", "shell.execute_reply": "2026-02-02T09:17:50.232711Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The MT catalog has 33 records, namely:\n", "498, 515, 877, 972, 2050, 2190, 2695, 4181, 4189, 4273, 4370, 4414, 4472, 4569, 4664, 4839, 5037, 5508, 5883, 5888, 6101, 6102, 7440, 7508, 7640, 8919, 9617, 10715, 10847, 11447, 11481, 11551, 11685\n" ] } ], "source": [ "\n", "# The external moment tensor catalog file\n", "mtf = \"ext/2022-007_Bloch-et-al_moment_tensor_catalog_correct_norm_v2.0.txt\"\n", "\n", "# Event date times in the catalog\n", "evdatetimes = [ev.name for ev in evd.values()]\n", "\n", "# Function to convert date and time strings to event names\n", "def nameconverter(datestr, timestr):\n", " # Remove delimiters from date and time strings and concatenate\n", " date = datestr.replace(\"/\", \"\")\n", " time = timestr.replace(\":\", \"\")\n", " \n", " # Times do not match exactly, so look up closest event time\n", " datetime = f\"{date}{time}\"\n", " evdatetime = utils.approx_time_lookup([datetime], evdatetimes)\n", "\n", " # Look up in single-element dict\n", " return evdatetime[datetime]\n", "\n", "# Function to convert moment tensors from Harvard format to north-east-down in Nm\n", "def mtconverter(mrr, mtt, mff, mrt, mrf, mtf, exp):\n", " # Convert to north, east, down ...\n", " mnn, mee, mdd, mne, mnd, med = mt.rtf2ned(mrr, mtt, mff, mrt, mrf, mtf)\n", "\n", " # ... and from dyne cm to Nm\n", " fac = 10**exp * 1e-7\n", " return (mnn * fac, mee * fac, mdd * fac, mne * fac, mnd * fac, med * fac)\n", "\n", "# Read the moment tensor catalog into a moment tensor dictionary\n", "mtd = io.read_ext_mt_table(\n", " mtf,\n", " (6, 7, 8, 9, 10, 11), # mrr, mtt, mff, mrt, mrf, mtf\n", " (0, 1), # Date strings\n", " evd,\n", " mtconverter, # This mtconverter converts from Harvad to north-east-down convention\n", " 12, # exponent\n", " nameconverter, # The names are used to associate MTs to events\n", ")\n", "\n", "# And save it to disk\n", "io.write_mt_table(mtd, \"data/reference_mts.txt\")\n", "\n", "print(f\"The MT catalog has {len(mtd)} records, namely:\")\n", "print(\", \".join(map(str, mtd.keys())))" ] }, { "cell_type": "markdown", "id": "c557cf74", "metadata": {}, "source": [ "## Conclusion\n", "Let's have a look at the catalog and reference moment tensor file we just created. They now obey the *relMT* conventions, that is:\n", "* units are in meter\n", "* the axes point north, east and down, and\n", "* a global event index (first column) is used to refer to the events" ] }, { "cell_type": "code", "execution_count": 7, "id": "d92da0fb", "metadata": { "execution": { "iopub.execute_input": "2026-02-02T09:17:50.234963Z", "iopub.status.busy": "2026-02-02T09:17:50.234835Z", "iopub.status.idle": "2026-02-02T09:17:50.393770Z", "shell.execute_reply": "2026-02-02T09:17:50.391640Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#Number Northing Easting Depth Origintime Magnitude Name\r\n", "# (int) (meter) (meter) (meter) (seconds) (-) (str)\r\n", " 0 4260226.229 408658.456 130390.000 1438612628.000000 3.7000 20150803143708\r\n", " 1 4122064.455 208320.271 135870.000 1438654229.000000 4.3000 20150804021029\r\n", " 2 4372043.832 656334.005 -3000.000 1438726761.000000 2.3700 20150804221921\r\n", " 3 4317525.747 520953.300 27690.000 1438744568.000000 2.4000 20150805031608\r\n", " 4 4187827.608 249499.335 96070.000 1438844052.000000 3.0200 20150806065412\r\n", " 5 4245191.012 388998.036 126440.000 1438846443.000000 3.0700 20150806073403\r\n", " 6 4112039.663 219505.413 92410.000 1438868721.000000 3.3400 20150806134521\r\n", " 7 4321404.819 518995.792 35030.000 1438931919.000000 2.8800 20150807071839\r\n" ] } ], "source": [ "! head data/events.txt" ] }, { "cell_type": "code", "execution_count": 8, "id": "c6ae8329", "metadata": { "execution": { "iopub.execute_input": "2026-02-02T09:17:50.398205Z", "iopub.status.busy": "2026-02-02T09:17:50.398047Z", "iopub.status.idle": "2026-02-02T09:17:50.557050Z", "shell.execute_reply": "2026-02-02T09:17:50.555650Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#Number nn ee dd ne nd ed\r\n", "# (int) (Nm) (Nm) (Nm) (Nm) (Nm) (Nm)\r\n", " 498 -3.776000e+15 2.880000e+15 8.970000e+14 3.049000e+15 3.860000e+14 -1.884000e+15\r\n", " 515 -2.846000e+15 4.662000e+15 -1.816000e+15 2.215000e+15 6.116000e+15 7.310000e+14\r\n", " 877 8.300000e+13 1.550000e+15 -1.633000e+15 -7.250000e+14 -9.550000e+14 2.280000e+14\r\n", " 972 -7.820000e+15 1.376000e+16 -5.940000e+15 -2.110000e+15 4.890000e+15 9.650000e+15\r\n", " 2050 -8.540000e+16 8.790000e+16 -2.500000e+15 2.210000e+16 2.170000e+16 3.390000e+16\r\n", " 2190 -2.850000e+14 1.025000e+15 -7.400000e+14 -5.040000e+14 3.330000e+14 7.900000e+14\r\n", " 2695 -4.580000e+14 -1.631000e+15 2.088000e+15 3.822000e+15 3.700000e+14 2.683000e+15\r\n", " 4181 -7.984000e+15 1.471000e+15 6.512000e+15 2.587000e+15 -2.013000e+15 -2.103000e+15\r\n" ] } ], "source": [ "! head data/reference_mts.txt" ] } ], "metadata": { "kernelspec": { "display_name": "relmt", "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.13.7" } }, "nbformat": 4, "nbformat_minor": 5 }