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.

Current Electrode (transmitters)#
The 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 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.
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
h5file = Path("my_project.geoh5")
workspace = Workspace(h5file) if h5file.exists() else Workspace.create(h5file)
# 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)

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 a name.
The utility function geoh5py.objects.surveys.direct_current.CurrentElectrode.add_default_ab_cell_id() can help generate this map with a simple name string incrementor.
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.

Note: The first entry {0:Unknown} is a reserved field used by Geoscience ANALYST to flag unknown data entries.
Potential Electrode (receivers)#
The geoh5py.objects.surveys.direct_current.PotentialElectrode object defines the M-N dipole pairs used to measure the electric potential (receivers). It is a subclass of the geoh5py.objects.curve.Curve object defined by vertices (poles) and cells (dipoles).
Although poles could be set independently on the CurrentElectrode and PotentialElectrode objects, here we reuse the same locations for simplicity. We must also define the receiver dipoles. The following routine generates up to six (6) receiver dipoles per injection current along the line.
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.
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:
potentials.current_electrodes = currents
or equivalently by setting potential_electrodes to the currents
currents.potential_electrodes = potentials
In both cases, the link between the two objects gets encoded automatically to their respective metadata.
print(potentials.metadata == currents.metadata)
currents.metadata
True
{'Current Electrodes': UUID('533e0f8e-76f8-4145-9eee-91014c80eb49'),
'Potential Electrodes': UUID('880fbadd-957a-4ecf-b9b3-7d9b23ee8809')}

Note: The ab_cell_id property of the CurrentElectrode and PotentialElectrode are two different ReferenceData entities:
print(potentials.ab_cell_id == currents.ab_cell_id)
False
but share the same DataType that holds the map of unique source dipoles.
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

workspace.close()