Entities

This section introduces the different entities that can be created and stored in the geoh5 file format.

entities

Groups

Groups are effectively containers for other entities, such as Objects (Points, Curve, Surface, etc.) and other Groups. Groups are used to establish parent-child relationships and to store information about a collection of entities.

RootGroup

By default, the parent of any new Entity is the workspace RootGroup. It is the only entity in the Workspace without a parent. Users rarely have to interect with the Root group as it is mainly used to maintain the overall project hierarchy.

Root

ContainerGroup

A ContainerGroup can easily be added to the workspace and can be assigned a name and description.

[1]:
from geoh5py.groups import ContainerGroup
from geoh5py.workspace import Workspace

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

# Add a group
group = ContainerGroup.create(workspace, name='myGroup')

At creation, "myGroup" is written to the project geoh5 file and visible in the Analyst project tree.

Groups

Any entity can be accessed by its name or uid (unique identifier):

[2]:
print(group.uid)
print(workspace.get_entity("myGroup")[0] == workspace.get_entity(group.uid)[0])
c4e794ea-0043-491d-9150-241ce6b7048b
True

Objects

The geoh5 format allows to store a wide variety of Object entities that can be displayed in 3D. This section describes the collection of Objects entities currently supported by geoh5py.

Gobjects

Points

The Points object consists of a list of vertices that define the location of ponctual data in 3D space. As for all other Objects, it can be created from an array of 3D coordinates and added to any group as follow:

[3]:
from geoh5py.workspace import Workspace
from geoh5py.objects import Points
import numpy as np

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

# Generate a numpy array of xyz locations
n = 100
radius, theta = np.arange(n), np.linspace(0, np.pi*8, n)

x, y = radius * np.cos(theta), radius * np.sin(theta)
z = (x**2. + y**2.)**0.5
xyz = np.c_[x.ravel(), y.ravel(), z.ravel()] # Form a 2D array

# Create the Point object
points = Points.create(
    workspace,       # The target Workspace
    vertices=xyz     # Set vertices
)

points

Curve

The Curve object, also known as a polyline, is often used to define contours, survey lines or geological contacts. It is a sub-class of the Points object with the added cells property, that defines the line segments connecting its vertices. By default, all vertices are connected sequentially following the order of the input vertices.

[4]:
from geoh5py.objects import Curve

# Create the Curve object
curve = Curve.create(
    workspace,       # The target Workspace
    vertices=xyz
)

Alternatively, the cells property can be modified, either directly or by assigning parts identification to each vertices:

[5]:
# Split the curve into two parts
part_id = np.ones(n, dtype="int32")
part_id[:75] = 2

# Assign the part
curve.parts = part_id
workspace.finalize()

line

Surface

The Surface object is also described vertices and cells that forms a net of triangles. If omited on creation, the cells property is calculated using a 2D scipy.spatial.Delaunay triangulation.

[6]:
from geoh5py.objects import Surface
from scipy.spatial import Delaunay

# Create a triangulated surface from points
surf_2D = Delaunay(xyz[:, :2])

# Create the Surface object
surface = Surface.create(
    workspace,
    vertices=points.vertices, # Add vertices
    cells=surf_2D.simplices
)

surface

Grid2D

The Grid2D object defines a regular grid of cells often used to display model sections or to compute data derivatives. A Grid2D can be oriented in 3D space using the its origin, rotation and dip parameters.

[7]:
from geoh5py.objects import Grid2D

# Create the Surface object
grid = Grid2D.create(
    workspace,
    origin = [25, -75, 50],
    u_cell_size = 2.5,
    v_cell_size = 2.5,
    u_count = 64,
    v_count = 16,
    rotation = 90.0,
    dip = 45.0,
)

grid2d

BlockModel

The BlockModel object defines a rectilinear grid of cells, also known as a tensor mesh. The cells center position is determined by cell_delimiters (offsets) along perpendicular axes (u, v, z) and relative to the origin. BlockModel can be oriented horizontally by controling the rotation parameter.

[8]:
from geoh5py.objects import BlockModel

# Create the Surface object
blockmodel = BlockModel.create(
    workspace,
    origin = [25, -100, 50],
    u_cell_delimiters=np.cumsum(np.ones(16) * 5), # Offsets along u
    v_cell_delimiters=np.cumsum(np.ones(32) * 5), # Offsets along v
    z_cell_delimiters=np.cumsum(np.ones(16) * -2.5),  # Offsets along z (down)
    rotation = 30.0
)

blockmodel

Octree

The Octree object is type of 3D grid that uses a tree structure to define cells. Each cell can be subdivided it into eight octants allowing for a more efficient local refinement of the mesh. The Octree object can also be oriented horizontally by controling the rotation parameter.

[9]:
from geoh5py.objects import Octree

octree = Octree.create(
        workspace,
        origin=[25, -100, 50],
        u_count=16,      # Number of cells in power 2
        v_count=32,
        w_count=16,
        u_cell_size=5.0, # Base cell size (highest octree level)
        v_cell_size=5.0,
        w_cell_size=2.5, # Offsets along z (down)
        rotation=30,
)

By default, the octree mesh will be refined at the lowest level possible along each axes.

octree

Data

The geoh5 format allows to store data (values) on different part of an Object. The data_association can be one of:

  • OBJECT: Single element characterizing the parent object

  • VERTEX: Array of values associated with the parent object vertices

  • CELL: Array of values associated with the parent object cells

Note: The lenght and order of the array provided must be consistant with the corresponding element of association.

The data types supported by geoh5py are:

  • Arrays

  • Integer

  • Text

  • Color_map

data

Add data

Data can be added to an Object entity using the add_data method.

[10]:
# Create a straight Curve object
curve = Curve.create(
    workspace,       # The target Workspace
    name='FlightLine3',
    vertices=np.c_[np.linspace(0, 100, 100), np.zeros(100), np.zeros(100)]
)

# Add a single string comment
curve.add_data({
    "my_comment": {
        "association":"OBJECT",
        "values": "hello_world"
    }
})

# Add a vector of floats
curve.add_data({
    "my_cell_values": {
        "association":"CELL",
        "values": np.random.randn(curve.n_cells)
    }
})

# Add multiple data vectors on a single call
data = {}
for ii in range(8):
    data[f"Period:{ii}"] = {
        "association":"VERTEX",
        "values": (ii+1) * np.cos(ii*curve.vertices[:, 0]*np.pi/curve.vertices[:, 0].max()/4.)
    }

data_list = curve.add_data(data)
print([obj.name for obj in data_list])
['Period:0', 'Period:1', 'Period:2', 'Period:3', 'Period:4', 'Period:5', 'Period:6', 'Period:7']

The newly created data is directly added to the project’s geoh5 file and available for visualization:

adddata

Get data

Just like any Entity, data can be retrieved from the Workspace using the get_entity method. For convenience, Objects also have a get_data_list and get_data method that focusses only on their respective children Data.

[11]:
my_list = curve.get_data_list()
print(my_list, curve.get_data(my_list[0]))
['Period:0', 'Period:1', 'Period:2', 'Period:3', 'Period:4', 'Period:5', 'Period:6', 'Period:7', 'my_cell_values', 'my_comment'] [<geoh5py.data.float_data.FloatData object at 0x7f4153be6350>]

Property Groups

Data entities sharing the same parent Object and association can be linked within a property_groups and made available through profiling. This can be used to group data that would normally be stored as 2D array.

[12]:
# Add another VERTEX data and create a group with previous
curve.add_data_to_group([obj.name for obj in data_list], "my_trig_group")
[12]:
<geoh5py.groups.property_group.PropertyGroup at 0x7f4153bc6810>

propgroups

[13]:
# Update the geoh5 and re-write the Root
workspace.finalize()