{ "cells": [ { "attachments": {}, "cell_type": "markdown", "id": "0", "metadata": {}, "source": [ "# Direct Current and Induced Polarization (DC-IP)\n", "\n", "This survey type is meant to handle direct-current resistivity data. The survey object is made up of two curve entities defining the transmitter (current) and receiver (potential) electrodes. \n", "\n", "The following example shows how to generate a DC-IP survey with associated data stored in `geoh5` format and accessible from [Geoscience ANALYST](https://mirageoscience.com/mining-industry-software/geoscience-analyst/).\n", "\n", "![dcipSurvey](./images/dcip_survey.png)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "1", "metadata": {}, "source": [ "## Current Electrode (transmitters)\n", "\n", "The [CurrentElectrode](../api/geoh5py.objects.surveys.rst#geoh5py.objects.surveys.direct_current.CurrentElectrode) entity defines the A-B dipole pairs used to inject current into the ground. It is a sub-class of the [PotentialElectrode](../api/geoh5py.objects.surveys.rst#geoh5py.objects.surveys.direct_current.PotentialElectrode) object defined by vertices (poles) and cells (dipoles). Here we generate four (4) parallel EW lines with eight dipoles per line." ] }, { "cell_type": "code", "execution_count": null, "id": "2", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import uuid\n", "from geoh5py.workspace import Workspace\n", "from geoh5py.objects import CurrentElectrode, PotentialElectrode\n", "\n", "# Create a new project\n", "workspace = Workspace(\"my_project.geoh5\")\n", "\n", "# Define the pole locations\n", "n_poles = 9\n", "n_lines = 2\n", "x_loc, y_loc = np.meshgrid(np.linspace(0, 60, n_poles), 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_poles)).astype('int')\n", "\n", "# Create the CurrentElectrode object\n", "currents = CurrentElectrode.create(workspace, vertices=vertices, parts=parts)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "3", "metadata": {}, "source": [ "![currentElectrodes](./images/current_electrodes.png)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "4", "metadata": {}, "source": [ "At this stage the `CurrentElectrode` object has segments (`cells`) connecting all poles in series along line. \n", "\n", "### AB Cell ID\n", "A key element of the DCIP survey objects is the `ab_cell_id` property. This `ReferenceData` contains the map referencing each cell of the `CurrentElectrode` object to a unique A-B source identifier with name.\n", "\n", "The utility function [add_default_ab_cell_id](../api/geoh5py.objects.surveys.rst#geoh5py.objects.surveys.direct_current.CurrentElectrode.add_default_ab_cell_id) can help generate this map with a simple name string incrementor." ] }, { "cell_type": "code", "execution_count": null, "id": "5", "metadata": {}, "outputs": [], "source": [ "currents.add_default_ab_cell_id()\n", "print(currents.ab_cell_id.value_map.map)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "6", "metadata": {}, "source": [ "In this specific case, every `cell` on the curve corresponds to a unique dipole source current. \n", "For more complex survey configurations, users can edit the `cell` property in order to define different combinations of connections between poles." ] }, { "attachments": {}, "cell_type": "markdown", "id": "7", "metadata": {}, "source": [ "![abCellId](./images/ab_cell_id.png)\n", "\n", "**Note:** The first entry `{0:Unknown}` is a reserved field used by Geoscience ANALYST to flag unknown data entries. " ] }, { "attachments": {}, "cell_type": "markdown", "id": "8", "metadata": {}, "source": [ "## Potential Electrode (receivers)\n", "\n", "The [PotentialElectrode](../api/geoh5py.objects.surveys.rst#geoh5py.objects.surveys.direct_current.PotentialElectrode) object defines the M-N dipole pairs used to measure the electric potential (receivers). It is a sub-class of the [Curve](../api/geoh5py.objects.rst#geoh5py.objects.curve.Curve) object defined by `vertices` (poles) and `cells` (dipoles). \n", "\n", "Although poles could be set independently on the `CurrentElectrode` and `PotentialElectrode` objects, here we re-uses the same locations for simplicity:" ] }, { "cell_type": "code", "execution_count": null, "id": "9", "metadata": {}, "outputs": [], "source": [ "potentials = PotentialElectrode.create(workspace, vertices=vertices)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "10", "metadata": {}, "source": [ "Next, we must define the receiver dipoles. The following routine generates a maximum of six (6) receivers dipoles per injection currents along line." ] }, { "cell_type": "code", "execution_count": null, "id": "11", "metadata": {}, "outputs": [], "source": [ "N = 6\n", "dipoles = []\n", "current_id = []\n", "\n", "for val in currents.ab_cell_id.values: # For each source dipole\n", " if val == 0: # Skip the unknown\n", " continue\n", " \n", " cell_id = val - 1 # Python 0 indexing\n", " line = currents.parts[currents.cells[cell_id, 0]]\n", " for m_n in range(N):\n", " dipole_ids = (currents.cells[cell_id, :] + 2 + m_n).astype(\"uint32\") # Skip two poles\n", "\n", " # Shorten the array as we get to the end of the line\n", " if (\n", " any(dipole_ids > (potentials.n_vertices - 1)) \n", " or any(currents.parts[dipole_ids] != line)\n", " ):\n", " continue\n", " \n", " dipoles += [dipole_ids] # Save the receiver id\n", " current_id += [val] # Save the source id\n", "\n", "potentials.cells = np.vstack(dipoles)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "12", "metadata": {}, "source": [ "Finally, users need to create an association between each receiver dipole (M-N) to a dipole current (A-B). The mapping is done through the `ab_cell_id` property of the `PotentialElectrode`. An integer (ID) value must be assigned to each cell, corresponding to the `AB Cell ID` pairs stored on the associated `CurrentElectrode` object. " ] }, { "cell_type": "code", "execution_count": null, "id": "13", "metadata": {}, "outputs": [], "source": [ "potentials.ab_cell_id = np.asarray(current_id, dtype=\"int32\")" ] }, { "attachments": {}, "cell_type": "markdown", "id": "14", "metadata": {}, "source": [ "## Metadata" ] }, { "attachments": {}, "cell_type": "markdown", "id": "15", "metadata": {}, "source": [ "The link between the sources [CurrentElectrode](../api/geoh5py.objects.surveys.rst#geoh5py.objects.surveys.direct_current.CurrentElectrode) and the receivers [PotentialElectrode](../api/geoh5py.objects.surveys.rst#geoh5py.objects.surveys.direct_current.PotentialElectrode) is established by the `metadata`, shared by both entities. The connection can be made by assigning `current_electrodes` to the receivers: " ] }, { "cell_type": "code", "execution_count": null, "id": "16", "metadata": {}, "outputs": [], "source": [ "potentials.current_electrodes = currents" ] }, { "attachments": {}, "cell_type": "markdown", "id": "17", "metadata": {}, "source": [ "or equivalently by setting `potential_electrodes` to the currents" ] }, { "cell_type": "code", "execution_count": null, "id": "18", "metadata": {}, "outputs": [], "source": [ "currents.potential_electrodes = potentials" ] }, { "attachments": {}, "cell_type": "markdown", "id": "19", "metadata": {}, "source": [ "In both cases, the link between the two objects gets encoded automatically to their respective `metadata`." ] }, { "cell_type": "code", "execution_count": null, "id": "20", "metadata": {}, "outputs": [], "source": [ "print(potentials.metadata == currents.metadata)\n", "currents.metadata" ] }, { "attachments": {}, "cell_type": "markdown", "id": "21", "metadata": {}, "source": [ "![potentialElectrodes](./images/potential_electrodes.png)\n", "\n", "Note: The `ab_cell_id` property of the `CurrentElectrode` and `PotentialElectrode` are two different `ReferenceData` entities:" ] }, { "cell_type": "code", "execution_count": null, "id": "22", "metadata": {}, "outputs": [], "source": [ "print(potentials.ab_cell_id == currents.ab_cell_id) " ] }, { "attachments": {}, "cell_type": "markdown", "id": "23", "metadata": {}, "source": [ "but share the same `DataType` that holds the map of unique source dipoles." ] }, { "cell_type": "code", "execution_count": null, "id": "24", "metadata": {}, "outputs": [], "source": [ "print(potentials.ab_cell_id.entity_type == currents.ab_cell_id.entity_type) " ] }, { "attachments": {}, "cell_type": "markdown", "id": "25", "metadata": {}, "source": [ "This link between `DataType` allows users to query the data by dipole sources and display the values as pseudo-section in [Geoscience ANALYST](https://mirageoscience.com/mining-industry-software/geoscience-analyst/)\n", "\n", "![dcipPseudo](./images/dcip_pseudo_section.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 }