Note
Go to the end to download the full example code.
Rotated Blockmodel#
Minimal example of a rotated block model using the new ijk‑first geometry design.
The key idea is:
ijk indices and
shapedefine the canonical dense grid.Rotation is represented via the orthonormal basis vectors
axis_u, axis_v, axis_wonparq_blockmodel.geometry.RegularGeometry.World coordinates
(x, y, z)are a derived view of(i, j, k) + geometry. Changing the axes rotates the xyz centroids without changing ijk.
This example:
Constructs a small
RegularGeometrywith a 30° azimuth rotation.Builds a canonical
.pbmfile from that geometry usingParquetBlockModel.from_geometry().Derives a simple scalar
z_centroidfrom the rotated xyz and visualises it usingParquetBlockModel.plot().
import tempfile
from pathlib import Path
import pyvista as pv
from parq_blockmodel import ParquetBlockModel, RegularGeometry
from parq_blockmodel.utils.geometry_utils import angles_to_axes
Define a small rotated RegularGeometry#
corner = (0.0, 0.0, 0.0)
block_size = (1.0, 1.0, 1.0)
shape = (3, 3, 3)
axis_u, axis_v, axis_w = angles_to_axes(
axis_azimuth=30.0,
axis_dip=0.0,
axis_plunge=0.0,
)
geometry = RegularGeometry(
corner=corner,
block_size=block_size,
shape=shape,
axis_u=axis_u,
axis_v=axis_v,
axis_w=axis_w,
)
Materialise a canonical .pbm from geometry only#
temp_dir: Path = Path(tempfile.gettempdir()) / "rotated_block_model_example"
temp_dir.mkdir(parents=True, exist_ok=True)
pbm_path = temp_dir / "rotated_block_model.pbm"
pbm = ParquetBlockModel.from_geometry(geometry=geometry, path=pbm_path)
print("Block Model Path:", pbm.blockmodel_path)
print("Name:", pbm.name)
print("Shape (ijk):", pbm.geometry.shape)
print("Corner:", pbm.geometry.corner)
print("Block size (local i/j/k spacing):", pbm.geometry.block_size)
print("Axis U:", pbm.geometry.axis_u)
print("Axis V:", pbm.geometry.axis_v)
print("Axis W:", pbm.geometry.axis_w)
print("Rotated centroids (head):\n", pbm.geometry.to_dataframe_xyz().head())
Block Model Path: /tmp/rotated_block_model_example/rotated_block_model.pbm
Name: rotated_block_model
Shape (ijk): (3, 3, 3)
Corner: (0.0, 0.0, 0.0)
Block size (local i/j/k spacing): (1.0, 1.0, 1.0)
Axis U: (0.8660254037844387, 0.49999999999999994, 0.0)
Axis V: (-0.49999999999999994, 0.8660254037844387, 0.0)
Axis W: (0.0, 0.0, 1.0)
Rotated centroids (head):
x y z
0 0.183013 0.683013 0.5
1 0.183013 0.683013 1.5
2 0.183013 0.683013 2.5
3 -0.316987 1.549038 0.5
4 -0.316987 1.549038 1.5
Derive a simple scalar from rotated xyz centroids#
For visualisation we use the rotated Z centroid as a scalar field.
df = pbm.read(index="xyz", dense=True)
df["z_centroid"] = df.index.get_level_values("z")
# Persist the derived scalar back to the pbm Parquet file so that
# ParquetBlockModel.plot can see it as an attribute.
df.to_parquet(pbm.blockmodel_path)
# Refresh the ParquetBlockModel's view of available columns/attributes
# now that we've updated the underlying file.
import pyarrow.parquet as pq
pbm.columns = pq.read_schema(pbm.blockmodel_path).names
pbm.attributes = [col for col in pbm.columns if col not in ["x", "y", "z"]]
pbm.attributes
['block_id', 'world_id', 'z_centroid', '__index_level_0__', '__index_level_1__', '__index_level_2__']
Plot#
plotter: pv.Plotter = pbm.plot(scalar="z_centroid", grid_type="image")
plotter.show()

Total running time of the script: (0 minutes 0.596 seconds)