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 numpy as np
import uuid
from geoh5py.workspace import Workspace
from geoh5py.objects import CurrentElectrode, PotentialElectrode

# 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., 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: 'Unknown', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: '10', 11: '11', 12: '12', 13: '13', 14: '14', 15: '15', 16: '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:

[3]:
potentials = PotentialElectrode.create(workspace, vertices=vertices)

Next, we must define the receiver dipoles. The following routine generates a maximum of six (6) receivers dipoles per injection currents along line.

[4]:
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 > (potentials.n_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.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.

[5]:
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:

[6]:
potentials.current_electrodes = currents

or equivalently by setting potential_electrodes to the currents

[7]:
currents.potential_electrodes = potentials

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

[8]:
print(potentials.metadata == currents.metadata)
currents.metadata
True
[8]:
{'Current Electrodes': UUID('86abd619-a0e0-44e8-9d2a-ca74d7b7b09a'),
 'Potential Electrodes': UUID('21fb3840-c2b7-40c6-9127-60399a7e5fa2')}

potentialElectrodes

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

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

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

[10]:
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