{ "cells": [ { "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "# Airborne Time-Domain\n", "\n", "This type of survey can be used to store airborne time-domain electromagnetic (ATEM) data defined by a fixed transmitter-receiver loop configuration. The survey is made up of two entities ([AirborneTEMTransmitters](../api/geoh5py.objects.surveys.electromagnetics.rst#geoh5py.objects.surveys.electromagnetics.airborne_tem.AirborneTEMTransmitters) and [AirborneTEMReceivers](../api/geoh5py.objects.surveys.electromagnetics.rst#geoh5py.objects.surveys.electromagnetics.airborne_tem.AirborneTEMReceivers)) linked by their metadata.\n", "\n", "The following example shows how to generate an airborne TEM survey with associated data stored in `geoh5` format and accessible from [Geoscience ANALYST](https://mirageoscience.com/mining-industry-software/geoscience-analyst/).\n", "\n", "![atemSurvey](./images/atem_survey.png)" ] }, { "cell_type": "code", "execution_count": null, "id": "1", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from geoh5py.workspace import Workspace\n", "from geoh5py.objects import AirborneTEMReceivers, AirborneTEMTransmitters\n", "\n", "# Create a new project\n", "workspace = Workspace(\"my_project.geoh5\")\n", "\n", "# Define the pole locations\n", "n_stations = 9\n", "n_lines = 2\n", "x_loc, y_loc = np.meshgrid(np.linspace(0, 60, n_stations), np.linspace(-20, 20., n_lines))\n", "vertices = np.c_[x_loc.ravel(), y_loc.ravel(), np.zeros_like(x_loc).ravel()]\n", "\n", "# Assign a line ID to the poles (vertices)\n", "parts = np.kron(np.arange(n_lines), np.ones(n_stations)).astype('int')\n", "\n", "# Create the survey as a coincident loop system\n", "aem_receivers = AirborneTEMReceivers.create(workspace, vertices=vertices, parts=parts)\n", "aem_transmitters = AirborneTEMTransmitters.create(workspace, vertices=vertices, parts=parts)" ] }, { "cell_type": "markdown", "id": "2", "metadata": {}, "source": [ "We have so far created two seperate entities, one for transmitter locations and another for the receivers. In order to finalize the survey, the association must be made between the two entities:" ] }, { "cell_type": "code", "execution_count": null, "id": "3", "metadata": {}, "outputs": [], "source": [ "aem_receivers.transmitters = aem_transmitters" ] }, { "cell_type": "markdown", "id": "4", "metadata": {}, "source": [ "or equivalently" ] }, { "cell_type": "code", "execution_count": null, "id": "5", "metadata": {}, "outputs": [], "source": [ "aem_transmitters.receivers = aem_receivers" ] }, { "cell_type": "markdown", "id": "6", "metadata": {}, "source": [ "Only one of the two options above is needed. \n", "\n", "Once linked, the two entities will share changes applied to the metadata. For example, changing the `input_type` property on the transmitters yield:" ] }, { "cell_type": "code", "execution_count": null, "id": "7", "metadata": {}, "outputs": [], "source": [ "aem_transmitters.input_type = \"Tx and Rx\"\n", "print(aem_receivers.input_type)" ] }, { "cell_type": "markdown", "id": "8", "metadata": {}, "source": [ "## Metadata\n", "\n", "Along with the survey object itself, the metadata contains all the necessary information to define the geophysical experiment." ] }, { "cell_type": "code", "execution_count": null, "id": "9", "metadata": {}, "outputs": [], "source": [ "aem_receivers.metadata" ] }, { "cell_type": "markdown", "id": "10", "metadata": {}, "source": [ "### Channels\n", "\n", "List of time channels at which the data are provided." ] }, { "cell_type": "code", "execution_count": null, "id": "11", "metadata": {}, "outputs": [], "source": [ "aem_receivers.channels = np.logspace(-5, -2, 10) # Simple sweep from 1 to 10 ms" ] }, { "cell_type": "markdown", "id": "12", "metadata": {}, "source": [ "### Input type\n", "\n", "Label defining how the survey was created.\n", "\n", "- `Rx`: Survey defined from the `AirborneTEMReceivers` positions, with the`AirborneTEMTransmitters` added from offsets.\n", "- `Tx`: Survey defined from the `AirborneTEMTransmitters` position, with the`AirborneTEMReceivers` added from offsets.\n", "- `Tx and Rx`: Survey defined by both the `AirborneTEMTransmitters` and the`AirborneTEMReceivers` positions." ] }, { "cell_type": "markdown", "id": "13", "metadata": {}, "source": [ "### Property groups\n", "\n", "List of [PropertyGroup](../api/geoh5py.groups.rst#module-geoh5py.groups.property_group)s defining the various data components (e.g. `dBzdt`, `Bz`, ...). It is expected that each component contains data channels at all times and in the same order as defined in `Channels`.\n", "\n", "The class method [add_component_data](../api/geoh5py.objects.surveys.electromagnetics.rst#geoh5py.objects.surveys.electromagnetics.base.BaseEMSurvey.add_components_data) can help users add data from nested dictionaries. Below is an example using four components:" ] }, { "cell_type": "code", "execution_count": null, "id": "14", "metadata": {}, "outputs": [], "source": [ "# Create some simple data\n", "data_fun = lambda t: 1./ t * np.sin(np.pi * (x_loc * y_loc).ravel() / 800.)\n", "\n", "# Create a nested dictionary of time data.\n", "data = {\n", " \"dBdt\" : {\n", " f\"time[{tt}]\": {\"values\": data_fun(time)} for tt, time in enumerate(aem_receivers.channels)\n", " }\n", "}\n", " \n", "aem_receivers.add_components_data(data)" ] }, { "cell_type": "markdown", "id": "15", "metadata": {}, "source": [ "Metadata are also updated to reflect the addition of component data." ] }, { "cell_type": "code", "execution_count": null, "id": "16", "metadata": {}, "outputs": [], "source": [ "aem_receivers.metadata" ] }, { "cell_type": "markdown", "id": "17", "metadata": {}, "source": [ "Data channels associated with each component can be quickly accessed through the [BaseEMSurvey.components](../api/geoh5py.objects.surveys.electromagnetics.rst#geoh5py.objects.surveys.electromagnetics.base.BaseEMSurvey.components) property:" ] }, { "cell_type": "code", "execution_count": null, "id": "18", "metadata": {}, "outputs": [], "source": [ "aem_receivers.components['dBdt']" ] }, { "cell_type": "markdown", "id": "19", "metadata": {}, "source": [ "### Receivers\n", "\n", "Generic label used for surveys to identify the receiver entity. References to itself in the case of `AirborneTEMReceivers`." ] }, { "cell_type": "markdown", "id": "20", "metadata": {}, "source": [ "### Survey type\n", "\n", "Static label identifier for `Airborne TEM` survey type." ] }, { "cell_type": "markdown", "id": "21", "metadata": {}, "source": [ "### Transmitters\n", "\n", "Generic label used for surveys to identify the transmitter entity. References to itself in the case of `AirborneTEMTransmitters`." ] }, { "cell_type": "markdown", "id": "22", "metadata": {}, "source": [ "### Unit\n", "\n", "Units for time sampling of the data - must be one of `Seconds (s)`, `Milliseconds (ms)`, `Microseconds (us)` or `Nanoseconds (ns)`." ] }, { "cell_type": "markdown", "id": "23", "metadata": {}, "source": [ "### Loop radius\n", "\n", "Specifies the transmitter loop radius." ] }, { "cell_type": "markdown", "id": "24", "metadata": {}, "source": [ "### Custom fields\n", "\n", "`Metadata` are stored in `geoh5` as a `json` structure allowing for custom data fields to be added to the survey. Information such as flight data, date/time, offsets, etc. can be added as `string`, `float` and `int`." ] }, { "cell_type": "code", "execution_count": null, "id": "25", "metadata": {}, "outputs": [], "source": [ "aem_receivers.edit_metadata({\"Weather\": \"sunny\"}) " ] }, { "cell_type": "markdown", "id": "26", "metadata": {}, "source": [ "![atem_custom](./images/atem_metadata_custom.png)\n", "\n", "Aternatively, a `uuid.UUID` value can be used if the information is to be provided at every survey position." ] }, { "cell_type": "code", "execution_count": null, "id": "27", "metadata": {}, "outputs": [], "source": [ "# Add a new data entry\n", "abc = aem_receivers.add_data({\n", " \"abc\": {\"values\": np.random.randn(aem_receivers.n_vertices)}\n", "})\n", "\n", "# Assign the data as 'Weather' metadata\n", "aem_receivers.edit_metadata({\"Weather\": abc.uid})" ] }, { "cell_type": "markdown", "id": "28", "metadata": {}, "source": [ "`Geoscience ANALYST` will automatically create a link referencing the data field to the entity in the project tree.\n", "\n", "![atem_uid](./images/atem_metadata_uid.png)" ] }, { "cell_type": "markdown", "id": "29", "metadata": {}, "source": [ "#### Reserved keywords\n", "\n", "For known metadata, such as flight dynamics (`yaw`, `pitch`, `roll`) and offsets (`inline`, `crossline`, `vertical`) the suffix `property` and `value` will get replaced based on the input value:" ] }, { "cell_type": "code", "execution_count": null, "id": "30", "metadata": {}, "outputs": [], "source": [ "aem_receivers.yaw = 15." ] }, { "cell_type": "markdown", "id": "31", "metadata": {}, "source": [ "![atem_yaw_value](./images/atem_metadata_yaw_value.png)" ] }, { "cell_type": "code", "execution_count": null, "id": "32", "metadata": {}, "outputs": [], "source": [ "aem_receivers.yaw = abc.uid # Assign to the yaw property" ] }, { "cell_type": "markdown", "id": "33", "metadata": {}, "source": [ "![atem_yaw_property](./images/atem_metadata_yaw_property.png)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.7" } }, "nbformat": 4, "nbformat_minor": 5 }