Direct Current and Induced Polarization (DC-IP)

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.

The following example shows how to generate a DC-IP survey with associated data stored in geoh5 format and accessible from Geoscience ANALYST.

dcipSurvey

Current Electrode (transmitters)

The CurrentElectrode entity defines the A-B dipole pairs used to inject current into the ground. It is a sub-class of the PotentialElectrode object defined by vertices (poles) and cells (dipoles). Here we generate four (4) parallel EW lines with eight dipoles per line.

[1]:
import uuid
from pathlib import Path

import numpy as np

from geoh5py.objects import CurrentElectrode, PotentialElectrode
from geoh5py.workspace import Workspace


# Create a new project
workspace = Workspace("my_project.geoh5")

# Define the pole locations
n_poles = 9
n_lines = 2
x_loc, y_loc = np.meshgrid(np.linspace(0, 60, n_poles), np.linspace(-20, 20.0, n_lines))
vertices = np.c_[x_loc.ravel(), y_loc.ravel(), np.zeros_like(x_loc).ravel()]

# Assign a line ID to the poles (vertices)
parts = np.kron(np.arange(n_lines), np.ones(n_poles)).astype("int")

# Create the CurrentElectrode object
currents = CurrentElectrode.create(workspace, vertices=vertices, parts=parts)

currentElectrodes

At this stage the CurrentElectrode object has segments (cells) connecting all poles in series along line.

AB Cell ID

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.

The utility function add_default_ab_cell_id can help generate this map with a simple name string incrementor.

[2]:
currents.add_default_ab_cell_id()
print(currents.ab_cell_id.value_map.map)
[( 0, b'Unknown') ( 1, b'1') ( 2, b'2') ( 3, b'3') ( 4, b'4') ( 5, b'5')
 ( 6, b'6') ( 7, b'7') ( 8, b'8') ( 9, b'9') (10, b'10') (11, b'11')
 (12, b'12') (13, b'13') (14, b'14') (15, b'15') (16, b'16')]

In this specific case, every cell on the curve corresponds to a unique dipole source current. For more complex survey configurations, users can edit the cell property in order to define different combinations of connections between poles.

abCellId

Note: The first entry {0:Unknown} is a reserved field used by Geoscience ANALYST to flag unknown data entries.

Potential Electrode (receivers)

The PotentialElectrode object defines the M-N dipole pairs used to measure the electric potential (receivers). It is a sub-class of the Curve object defined by vertices (poles) and cells (dipoles).

Although poles could be set independently on the CurrentElectrode and PotentialElectrode objects, here we re-uses the same locations for simplicity. We must also define the receiver dipoles. The following routine generates a maximum of six (6) receivers dipoles per injection currents along line.

[3]:
N = 6
dipoles = []
current_id = []

for val in currents.ab_cell_id.values:  # For each source dipole
    if val == 0:  # Skip the unknown
        continue

    cell_id = val - 1  # Python 0 indexing
    line = currents.parts[currents.cells[cell_id, 0]]
    for m_n in range(N):
        dipole_ids = (currents.cells[cell_id, :] + 2 + m_n).astype(
            "uint32"
        )  # Skip two poles

        # Shorten the array as we get to the end of the line
        if any(dipole_ids > (len(vertices) - 1)) or any(
            currents.parts[dipole_ids] != line
        ):
            continue

        dipoles += [dipole_ids]  # Save the receiver id
        current_id += [val]  # Save the source id

potentials = PotentialElectrode.create(
    workspace, vertices=vertices, cells=np.vstack(dipoles)
)

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.

[4]:
potentials.ab_cell_id = np.asarray(current_id, dtype="int32")

Metadata

The link between the sources CurrentElectrode and the receivers PotentialElectrode is established by the metadata, shared by both entities. The connection can be made by assigning current_electrodes to the receivers:

[5]:
potentials.current_electrodes = currents

or equivalently by setting potential_electrodes to the currents

[6]:
currents.potential_electrodes = potentials

In both cases, the link between the two objects gets encoded automatically to their respective metadata.

[7]:
print(potentials.metadata == currents.metadata)
currents.metadata
True
[7]:
{'Current Electrodes': UUID('8d933913-4efe-46e4-971a-4f738d2f5a83'),
 'Potential Electrodes': UUID('6f52952b-c7f8-43d7-902f-7f477d7eefdd')}

potentialElectrodes

Note: The ab_cell_id property of the CurrentElectrode and PotentialElectrode are two different ReferenceData entities:

[8]:
print(potentials.ab_cell_id == currents.ab_cell_id)
False

but share the same DataType that holds the map of unique source dipoles.

[9]:
print(potentials.ab_cell_id.entity_type == currents.ab_cell_id.entity_type)
True

This link between DataType allows users to query the data by dipole sources and display the values as pseudo-section in Geoscience ANALYST

dcipPseudo

[10]:
workspace.close()