API Reference

Contents

API Reference#

class parq_blockmodel.LocalGeometry(corner, block_size, shape)[source]#

Local dense grid geometry with C-order indexing.

This class models the logical/local lattice only (local corner/origin, block size, shape). It has no rotation, CRS, or world-frame meaning.

corner#

Local (u0, v0, w0) corner of the (i=0, j=0, k=0) block.

Type:

Point

block_size#

Block dimensions (dx, dy, dz) along the local i/j/k (u/v/w) axes.

Type:

BlockSize

shape#

Grid shape (ni, nj, nk) - number of blocks along each axis.

Type:

Shape3D

property centroids_uvw: ndarray#

Compute local centroids as a (3, N) array in C-order.

ijk_from_row_index(rows)[source]#

Convert row index/indices into (i, j, k) using C-order.

ijk_from_uvw(u, v, w, tol=1e-06)[source]#

Map local centroid coordinates to integer logical ijk indices.

Return type:

tuple[ndarray, ndarray, ndarray]

row_index_from_ijk(i, j, k)[source]#

Convert (i, j, k) into row index using C-order.

uvw_from_ijk(i, j, k)[source]#

Convert logical indices to local centroid coordinates.

Return type:

tuple[ndarray, ndarray, ndarray]

class parq_blockmodel.ParquetBlockModel(blockmodel_path, name=None, geometry=None)[source]#

A class to represent a regular Parquet block model.

Canonical on-disk representation:

We treat .pbm files as ParquetBlockModel containers:

The geometry is ijk-first: logical indices (i, j, k) enumerate the dense grid, and centroid coordinates (x, y, z) are derived from those indices plus geometry (corner, block size, axis orientation). In non-rotated models the grid axes align with the global X, Y, Z directions; in rotated models they do not.

Parquet storage order follows NumPy C-order with respect to ijk: i varies fastest, then j, then k. This aligns with numpy.ravel(order="C") and how RegularGeometry computes row indices. For xyz-defined, non-rotated models this corresponds to an increasing lexicographic ordering in (x, y, z), but callers should treat ijk + geometry as the canonical view.

blockmodel_path#

Path to the canonical .pbm file backing this block model.

Type:

Path

name#

The name of the block model, derived from the file name.

Type:

str

geometry#

Geometry of the block model, loaded from Parquet metadata or inferred from centroid columns.

Type:

RegularGeometry

property centroid_index: MultiIndex#

Get the centroid index of the block model as (x, y, z).

This index is built from the centroid columns x, y, z stored in the underlying .pbm Parquet file. It is primarily a backwards-compatibility view for xyz-first workflows which treat world-space centroids as the primary index.

Canonical ordering is defined by the C-order ijk layout in RegularGeometry, not by lexicographic sorting of (x, y, z). We therefore require this index to be unique but do not enforce global monotonicity in xyz.

Returns:

The MultiIndex representing centroid coordinates (x, y, z).

Return type:

pd.MultiIndex

property corner: tuple[float, float, float] | list[float]#

Backward-compatible access to the local grid corner.

classmethod create_demo_block_model(filename, **demo_kwargs)[source]#

Convenience helper used in tests to write a demo Parquet file and wrap it as a ParquetBlockModel.

Parameters:
  • filename (Path) – Target .parquet file to hold the raw demo data. The canonical blockmodel file will be written alongside it with a .pbm suffix via from_parquet().

  • **demo_kwargs – Additional keyword arguments forwarded to parq_blockmodel.utils.demo_block_model.create_demo_blockmodel(), for example shape or block_size. This allows tests and examples to control the logical grid used for the demo model.

Return type:

ParquetBlockModel

create_heatmap_from_threshold(attribute, threshold, axis='z', return_array=False)[source]#

Create a 2D heatmap from a 3D block model at a specified attribute threshold.

Parameters:
  • attribute (str) – The name of the attribute to threshold.

  • threshold (float) – The threshold value for the attribute.

  • axis (str) – The axis to view from (‘x’, ‘y’, or ‘z’). Defaults to ‘z’.

  • return_array (bool) – If True, returns the heatmap as a NumPy array. Defaults to False.

Returns:

A 2D heatmap as a PyVista ImageData object or a NumPy array.

Return type:

Union[pv.ImageData, np.ndarray]

create_report(columns=None, column_batch_size=10, show_progress=True, open_in_browser=False)[source]#

Create a ydata-profiling report for the block model. The report will be of the same name as the block model, with a ‘.html’ extension.

Parameters:
  • columns (Optional[list[str]]) – List of column names to include in the profile. If None, all columns are used.

  • column_batch_size (int) – The number of columns to process in each batch. If None, processes all columns at once.

  • show_progress (bool) – bool: If True, displays a progress bar during profiling.

  • open_in_browser (bool) – bool: If True, opens the report in a web browser after generation.

Return type:

Path

Returns

Path: The path to the generated profile report.

classmethod create_toy_blockmodel(filename, shape=(3, 3, 3), block_size=(1, 1, 1), corner=(-0.5, -0.5, -0.5), axis_azimuth=0.0, axis_dip=0.0, axis_plunge=0.0, deposit_bearing=20.0, deposit_dip=30.0, deposit_plunge=10.0, grade_name='grade', grade_min=50.0, grade_max=65.0, deposit_center=(10.0, 7.5, 5.0), deposit_radii=(8.0, 5.0, 3.0), noise_std=0.0, noise_rel=None, noise_seed=None)[source]#

Create a synthetic toy block model.

The toy model is generated on a regular ijk grid with the specified shape and block_size, anchored at corner in world coordinates. A simple ellipsoidal grade distribution is created in xyz space and stored under grade_name alongside any supporting attributes.

Parameters:
  • filename (Path) – Path to the source .parquet file to hold the raw toy data. A canonical .pbm file will be written alongside it with the same stem.

  • shape (tuple of int, default (3, 3, 3)) – Number of blocks along the logical ijk axes.

  • block_size (tuple of float, default (1, 1, 1)) – Block dimensions along each logical axis.

  • corner (tuple of float, default (-0.5, -0.5, -0.5)) – World‑space coordinates of the block with indices (i=0, j=0, k=0) lower corner.

  • axis_azimuth (float, default 0.0) – Rotation angles defining orientation of the logical ijk axes relative to the world xyz frame. These are converted to an orthonormal basis (axis_u, axis_v, axis_w) used by RegularGeometry.

  • axis_dip (float, default 0.0) – Rotation angles defining orientation of the logical ijk axes relative to the world xyz frame. These are converted to an orthonormal basis (axis_u, axis_v, axis_w) used by RegularGeometry.

  • axis_plunge (float, default 0.0) – Rotation angles defining orientation of the logical ijk axes relative to the world xyz frame. These are converted to an orthonormal basis (axis_u, axis_v, axis_w) used by RegularGeometry.

  • deposit_bearing (float) – Orientation of the synthetic deposit in degrees.

  • deposit_dip (float) – Orientation of the synthetic deposit in degrees.

  • deposit_plunge (float) – Orientation of the synthetic deposit in degrees.

  • grade_name (str, default "grade") – Name of the column storing the simulated grade values.

  • grade_min (float) – Minimum and maximum grade values for the toy distribution.

  • grade_max (float) – Minimum and maximum grade values for the toy distribution.

  • deposit_center (tuple of float) – Center of the ellipsoidal deposit in world xyz coordinates.

  • deposit_radii (tuple of float) – Semi‑axes of the deposit ellipsoid in world units.

  • noise_std (float, default 0.0) – Absolute standard deviation of Gaussian noise added to grades.

  • noise_rel (float, optional) – Relative standard deviation expressed as a fraction of (grade_max - grade_min). Mutually exclusive with noise_std.

  • noise_seed (int, optional) – Seed used for reproducible Gaussian noise.

Returns:

A ParquetBlockModel backed by a canonical .pbm file with the generated toy data and geometry metadata.

Return type:

ParquetBlockModel

Notes

For rotated geometries (non‑zero rotation angles), xyz centroids will appear rotated in world coordinates relative to the ijk axes of the grid. Geometry validation is skipped in this case to avoid imposing axis‑aligned assumptions on the rotated layout.

downsample(new_block_size, aggregation_config)[source]#

Downsample the block model to a coarser grid with specified aggregation methods for each attribute. This function supports downsampling of both categorical and numeric attributes. :type new_block_size: :param new_block_size: tuple of floats (dx, dy, dz) for the new block size. :type aggregation_config: :param aggregation_config: dict mapping attribute names to aggregation methods.

Example

aggregation_config = {

‘grade’: {‘method’: ‘weighted_mean’, ‘weight’: ‘dry_mass’}, ‘density’: {‘method’: ‘weighted_mean’, ‘weight’: ‘volume’}, ‘dry_mass’: {‘method’: ‘sum’}, ‘volume’: {‘method’: ‘sum’}, ‘rock_type’: {‘method’: ‘mode’}

}

Returns:

A new ParquetBlockModel instance with the downsampled grid.

Return type:

ParquetBlockModel

classmethod from_dataframe(dataframe, filename, geometry=None, name=None, overwrite=False, axis_azimuth=0.0, axis_dip=0.0, axis_plunge=0.0, chunk_size=1000000)[source]#

Create a ParquetBlockModel from a pandas DataFrame.

This constructor is oriented towards xyz-indexed DataFrames, where the index is a centroid MultiIndex with levels ("x", "y", "z") in world coordinates.

The DataFrame is written to a sibling .pbm file (replacing the .parquet suffix of filename) with embedded RegularGeometry metadata. Geometry is either supplied explicitly or inferred from the xyz centroids via RegularGeometry.from_multi_index().

Parameters:
  • dataframe (pandas.DataFrame) – Block model data indexed by centroid coordinates with dataframe.index.names == ["x", "y", "z"].

  • filename (Path) – Path to the source .parquet file which will be used as the basis for the sibling .pbm container.

  • geometry (RegularGeometry, optional) – Geometry of the logical ijk grid. If omitted, it is inferred from the centroid MultiIndex, using the optional rotation angles to define the ijk axis orientation.

  • name (str, optional) – Optional name for the resulting ParquetBlockModel. Defaults to filename.stem.

  • overwrite (bool, default False) – If True, allows overwriting an existing .pbm file at the derived path.

  • axis_azimuth (float, default 0.0) – Optional rotation angle used when inferring geometry from the xyz centroids. Defines the orientation of the logical ijk axes relative to the world coordinate frame.

  • axis_dip (float, default 0.0) – Optional rotation angle. See axis_azimuth.

  • axis_plunge (float, default 0.0) – Optional rotation angle. See axis_azimuth.

  • chunk_size (int, default 1_000_000) – Batch size for writing Parquet data.

Returns:

A block model backed by the newly written .pbm file.

Return type:

ParquetBlockModel

Note

New ijk-first workflows are encouraged to construct a RegularGeometry explicitly and use ParquetBlockModel.from_geometry() or ParquetBlockModel.from_parquet(). This helper remains for backwards compatibility with xyz-indexed DataFrames.

classmethod from_geometry(geometry, path, name=None)[source]#

Create a ParquetBlockModel from a geometry only.

This constructor materialises a dense ijk grid defined by a RegularGeometry into a Parquet file with xyz centroid columns but no additional attributes. It is useful for creating an empty block model skeleton that can be joined with external attribute data.

Parameters:
  • geometry (RegularGeometry) – Geometry of the logical ijk grid.

  • path (Path) – Path to the target .pbm file. The file will contain a row for every ijk block with derived xyz centroid columns and embedded geometry metadata.

  • name (str, optional) – Optional name for the resulting ParquetBlockModel.

Returns:

A block model with geometry defined but no attribute columns.

Return type:

ParquetBlockModel

classmethod from_parquet(parquet_path, columns=None, overwrite=False, axis_azimuth=0.0, axis_dip=0.0, axis_plunge=0.0, chunk_size=1000000)[source]#

Create a ParquetBlockModel from a source Parquet file.

This helper promotes a source .parquet file (typically xyz-centric) into a canonical .pbm container with embedded RegularGeometry metadata.

The input Parquet is expected to contain centroid columns x, y, z describing block centroids in world coordinates. RegularGeometry is reconstructed from those centroids and/or any existing "parq-blockmodel" metadata via RegularGeometry.from_parquet(). Geometry becomes the authoritative description of the dense ijk grid; xyz centroids are treated as a derived view.

Parameters:
  • parquet_path (Path) – Path to the source Parquet file. If the suffix is .pbm and overwrite is False, a ValueError is raised to avoid mutating an existing canonical container.

  • columns (list[str], optional) – Optional subset of columns to copy from the source file into the resulting .pbm file. If None, all columns are copied.

  • overwrite (bool, default False) – If True, allows overwriting an existing .pbm file at the target location.

  • axis_azimuth (float, default 0.0) – Optional rotation angle used by RegularGeometry.from_parquet() to define the orientation of the logical ijk axes in world coordinates when inferring geometry. In the common case geometry is read directly from existing metadata and this parameter is 0.

  • axis_dip (float, default 0.0) – Optional rotation angle. See axis_azimuth.

  • axis_plunge (float, default 0.0) – Optional rotation angle. See axis_azimuth.

  • chunk_size (int, default 1_000_000) – Batch size for reading Parquet data.

Returns:

A block model backed by a newly written .pbm file

located alongside parquet_path.

Return type:

ParquetBlockModel

property index_c: ndarray#

Zero-based C-order indices for the dense ijk grid.

The returned array has length ni * nj * nk and corresponds to linearised logical indices (i, j, k) using NumPy C‑order:

r = i + ni * (j + nj * k).

This is mainly a low‑level helper for downstream APIs that need a stable mapping between a flat row index and ijk; most callers should use read() with index="ijk" instead.

property index_f: ndarray#

Zero-based Fortran-order indices for the dense ijk grid.

Uses the same ijk logical grid as :pyattr:`index_c`, but flattened with order="F". This is useful when interacting with tools (such as some VTK/PyVista paths) that expect F‑order layouts.

property origin: tuple[float, float, float] | list[float]#

Backward-compatible access to the world-frame origin.

plot(scalar, grid_type='image', frame='world', threshold=True, show_edges=True, show_axes=True, enable_picking=False, picked_attributes=None)[source]#

Plot the block model using PyVista.

Parameters:
  • scalar (str) – The name of the scalar attribute to visualize.

  • grid_type (Literal['image', 'structured', 'unstructured']) – The type of grid to use for plotting. Options are “image”, “structured”, or “unstructured”.

  • frame (Literal['world', 'local']) – Coordinate frame for image grids. "world" applies geometry axis vectors; "local" uses axis-aligned local ijk orientation. Only supported for grid_type="image".

  • threshold (bool) – The thresholding option for the mesh. If True, applies a threshold to the scalar values.

  • show_edges (bool) – Show edges of the mesh.

  • show_axes (bool) – Show the axes in the plot.

  • enable_picking (bool) – If True, enables picking mode to interactively select cells in the plot.

  • picked_attributes (Optional[list[str]]) – A list of attributes that will be returned in picking mode. If None, all attributes are returned.

Return type:

Plotter

Returns:

plot_heatmap(attribute, threshold, axis='z', title=None)[source]#

Create a 2D heatmap plotly figure from a 3D block model at a specified attribute threshold.

Parameters:
  • attribute (str) – The name of the attribute to threshold.

  • threshold (float) – The threshold value for the attribute.

  • axis (str) – The axis to view from (‘x’, ‘y’, or ‘z’). Defaults to ‘z’.

  • title (Optional[str]) – The title of the heatmap. If None, a default title is used.

Returns:

A Plotly figure containing the heatmap.

Return type:

go.Figure

read(columns=None, index='xyz', dense=False)[source]#

Read the Parquet file and return a DataFrame.

Notes

Current behaviour (for backwards compatibility):

  • index="xyz" (the default) returns a DataFrame indexed by centroid coordinates (x, y, z). This matches the original design where xyz are treated as canonical.

  • index="ijk" returns a DataFrame whose index is derived from RegularGeometry via to_ijk_multi_index.

Option B design (future change, not yet enforced):

  • The canonical in-memory representation will become an (i, j, k) MultiIndex with attributes-only columns.

  • xyz (centroid) coordinates will be treated as a derived view computed from (i, j, k) + geometry, exposed via a helper such as as_xyz() or via pandas accessors that read geometry from df.attrs["parq-blockmodel"].

  • Plotting helpers (PyVista, Plotly) will consume ijk + geometry and compute xyz internally when needed, so they do not rely on xyz being persisted as data columns.

Until that refactor is complete, this method preserves the existing xyz-first semantics so that external callers continue to work.

Parameters:
  • columns (Optional[list[str]]) – List of column names to read. If None, all columns are read.

  • index (Literal['xyz', 'ijk', None]) – The index type to use for the DataFrame. Options are "xyz" for centroid coordinates, "ijk" for block indices, or None for no index.

  • dense (bool) – If True, reads/reindexes to the full dense grid. If False, returns the sparse layout in the underlying file.

Returns:

The DataFrame containing the block model data.

Return type:

pd.DataFrame

Notes

index="xyz" is preserved as the default for backwards compatibility with earlier versions of parq_blockmodel that treated centroid coordinates as canonical. New code is encouraged to pass index="ijk" explicitly and work in terms of logical grid indices plus geometry.

to_dense_parquet(filepath, chunk_size=100000, show_progress=False)[source]#

Export the block model as a dense xyz-indexed Parquet file.

The underlying .pbm may be sparse with respect to the dense ijk grid encoded by geometry. This helper iterates over the on‑disk data in chunks, reindexes each chunk to the full dense centroid MultiIndex geometry.to_multi_index_xyz() and writes the result to filepath.

Parameters:
  • filepath (Path) – Target path for the exported Parquet file.

  • chunk_size (int, default 100_000) – Number of rows to process per chunk when reading from the backing .pbm file.

  • show_progress (bool, default False) – If True, display a progress bar while exporting.

Return type:

None

Notes

This export is primarily intended for interoperability with tools that expect a fully populated xyz grid. The canonical representation of the block model remains the .pbm file with embedded RegularGeometry metadata.

to_glb(output_path, attributes=None, texture_attribute=None, colormap='viridis', surface_only=True, sparse=None)[source]#

Export the block model as a GLB (glTF 2.0 binary) mesh.

GLB is a derived format for external visualization in 3D viewers. Optionally applies vertex colors based on a scalar attribute (e.g., grade, density). Geometry metadata is embedded in the glTF extras field for reference.

Parameters:
  • output_path (str or Path) – Target GLB file path.

  • attributes (list[str], optional) – Block attributes to include (stored in glTF extensions).

  • texture_attribute (str, optional) – Attribute name to use for vertex coloring (e.g., “grade”). Must be numeric. If None, uses default gray material.

  • colormap (str, default "viridis") – Matplotlib colormap name for mapping texture_attribute to colors. Examples: “viridis”, “plasma”, “coolwarm”, “Greys”.

  • surface_only (bool, default True) – If True, export only exterior surface faces.

  • sparse (bool, optional) – If True, export only existing blocks. If None, infer from model sparsity.

Returns:

The output file path (pathlib.Path).

Return type:

Path

Notes

GLB format is optimized for visualization and may lose some precision compared to PLY. For scientific workflows requiring lossless data preservation, prefer to_ply().

The texture_attribute is normalized to [0, 1] and mapped to the specified colormap. NaN values are rendered as transparent.

Examples

>>> pbm = ParquetBlockModel(Path("model.pbm"))
>>> pbm.to_glb("model.glb", texture_attribute="grade", colormap="viridis")
to_ply(output_path, attributes=None, surface_only=True, sparse=None, binary=False)[source]#

Export the block model as a PLY (Polygon File Format) mesh.

PLY is the canonical format for mesh storage, supporting lossless round-tripping of all geometry and attribute data. The output file includes: - Vertex coordinates in world space - Face connectivity (triangles) - Per-vertex and per-face attributes (grades, rock type, etc.) - Block logical indices (i, j, k) for traceability - Geometry metadata (corner, block_size, shape, axes, CRS)

Parameters:
  • output_path (str or Path) – Target PLY file path.

  • attributes (list[str], optional) – Block attributes to include. If None, only geometry is exported.

  • surface_only (bool, default True) – If True, export only exterior surface faces.

  • sparse (bool, optional) – If True, export only existing blocks. If None, infer from model sparsity.

  • binary (bool, default False) – If True, write binary PLY (smaller file, less readable). If False, write ASCII PLY (larger, human-readable).

Returns:

The output file path (pathlib.Path).

Return type:

Path

Notes

Units and coordinate system are inherited from geometry. For rotated geometries, world-space coordinates reflect the rotation.

Examples

>>> pbm = ParquetBlockModel(Path("model.pbm"))
>>> pbm.to_ply("model.ply", attributes=["grade", "density"])
triangulate(attributes=None, surface_only=True, sparse=None)[source]#

Generate a triangulated mesh from the block model.

Creates a triangle mesh representation of the block model geometry, optionally including block attributes (grades, rock types, etc.) as vertex or face attributes.

Parameters:
  • attributes (list[str], optional) – List of attribute columns to include in the mesh. If None, only geometry is included (no attributes). Attributes must be in self.attributes.

  • surface_only (bool, default True) – If True, include only exterior surface faces. If False, include all interior faces as well. Useful for sparse models.

  • sparse (bool, optional) – If True (or None and sparse model detected), include only blocks that exist in the data. If False, generate mesh for full dense grid.

Returns:

Triangle mesh with vertices, faces, and optional attributes.

Return type:

parq_blockmodel.mesh.TriangleMesh

Notes

The mesh uses right-handed coordinates in world space, with rotation applied via geometry axis vectors. Attributes are preserved as per-vertex or per-face properties. For sparse models, only surface faces are typically needed (surface_only=True).

Examples

>>> pbm = ParquetBlockModel(Path("model.pbm"))
>>> mesh = pbm.triangulate(attributes=["grade", "density"], surface_only=True)
>>> print(f"Mesh: {mesh.n_vertices} vertices, {mesh.n_faces} faces")
upsample(new_block_size, interpolation_config)[source]#

Upsample the block model to a finer grid with specified interpolation methods for each attribute. This function supports upsampling of both categorical and numeric attributes. :type new_block_size: :param new_block_size: tuple of floats (dx, dy, dz) for the new block size. :type interpolation_config: :param interpolation_config: dict mapping attribute names to interpolation methods.

Example

interpolation_config = {

‘grade’: {‘method’: ‘linear’}, ‘density’: {‘method’: ‘nearest’}, ‘dry_mass’: {‘method’: ‘linear’}, ‘volume’: {‘method’: ‘linear’}, ‘rock_type’: {‘method’: ‘nearest’}

}

Returns:

A new ParquetBlockModel instance with the upsampled grid.

Return type:

ParquetBlockModel

classmethod validate_xyz_parquet(parquet_path, axis_azimuth=0.0, axis_dip=0.0, axis_plunge=0.0, chunk_size=1000000, tol=1e-06)[source]#

Validate xyz-defined Parquet input and return inferred geometry.

Return type:

RegularGeometry

class parq_blockmodel.RegularGeometry(local=None, world=None, schema_version='1.0', world_id_encoding=None, corner=None, block_size=None, shape=None, axis_u=None, axis_v=None, axis_w=None, srs=None)[source]#

Dense, metadata-defined block model geometry (C-order canonical).

This class describes all block model geometry in parq-blockmodel. It does not store x, y, z or i, j, k per block. All coordinates are derived from metadata + implicit row ordering.

local#

The local lattice geometry (corner, block_size, shape, C-order).

Type:

LocalGeometry

world#

The world embedding with origin, axes, and CRS.

Type:

WorldFrame

schema_version#

Version of the metadata schema. Default: “1.0”

Type:

str

world_id_encoding#

Encoding for world IDs.

Type:

dict, optional

Note

Internal Storage Ordering (C-order canonical)

parq-blockmodel uses NumPy C-order as its canonical definition of block ordering:

  • i varies fastest

  • j varies next

  • k varies slowest

  • r = i + ni * (j + nj * k)

This matches:

  • Parquet row-oriented storage naturally

  • NumPy operations (ravel, reshape)

  • Efficient dense arrays

  • Our metadata-based geometry model

This does NOT match lexicographic MultiIndex sorting (.sort_index([“x”, “y”, “z”])) which yields x slowest, z fastest. MultiIndex lexicographic sorting must NOT define canonical storage.

F-order is NOT used (even though OMF/VTK are sometimes described this way). PyVista accepts C-order 1D arrays perfectly fine.

Canonical = C-order. Do not switch to F-order.

property axis_u: tuple[float, float, float] | list[float] | ndarray[Any, dtype[floating]]#

Backward-compatible access to U-axis.

property axis_v: tuple[float, float, float] | list[float] | ndarray[Any, dtype[floating]]#

Backward-compatible access to V-axis.

property axis_w: tuple[float, float, float] | list[float] | ndarray[Any, dtype[floating]]#

Backward-compatible access to W-axis.

property block_size: tuple[float, float, float]#

Backward-compatible access to local-axis block spacing (dx, dy, dz).

property corner: tuple[float, float, float] | list[float]#

Backward-compatible access to local corner.

classmethod create(corner=(0.0, 0.0, 0.0), block_size=(1.0, 1.0, 1.0), shape=(1, 1, 1), axis_u=(1.0, 0.0, 0.0), axis_v=(0.0, 1.0, 0.0), axis_w=(0.0, 0.0, 1.0), srs=None)[source]#

Convenience factory for creating RegularGeometry with keyword arguments.

This is the recommended way to construct geometries when you have individual parameters rather than pre-built LocalGeometry and WorldFrame.

Parameters:
  • corner (Point, optional) – Local corner (u₀, v₀, w₀) of block (i=0, j=0, k=0). Defaults to (0, 0, 0).

  • block_size (BlockSize, optional) – Block dimensions (dx, dy, dz) along the local i/j/k (u/v/w) axes. Defaults to (1, 1, 1).

  • shape (Shape3D, optional) – Number of blocks (nᵢ, nⱼ, nₖ). Defaults to (1, 1, 1).

  • axis_u (Vector, optional) – Orthonormal U-axis for world embedding. Defaults to (1, 0, 0).

  • axis_v (Vector, optional) – Orthonormal V-axis for world embedding. Defaults to (0, 1, 0).

  • axis_w (Vector, optional) – Orthonormal W-axis for world embedding. Defaults to (0, 0, 1).

  • srs (str, optional) – Spatial reference system identifier.

Returns:

New geometry instance.

Return type:

RegularGeometry

property extents: tuple[float, float, float, float, float, float]#

Return the axis-aligned bounding box (xmin, xmax, ymin, ymax, zmin, zmax).

For unrotated geometries this is derived directly from corner, block_size, and shape. For rotated geometries, we conservatively compute extents from the centroid cloud.

classmethod from_attrs(attrs, key='parq-blockmodel')[source]#

Reconstruct geometry from a DataFrame.attrs-style mapping.

attrs[key] is expected to contain the dict produced by to_metadata_dict() (or a compatible future schema that from_metadata() can consume).

Return type:

RegularGeometry

classmethod from_metadata(meta)[source]#

Reconstruct geometry from stored metadata.

Return type:

RegularGeometry

classmethod from_multi_index(index, axis_azimuth=0.0, axis_dip=0.0, axis_plunge=0.0)[source]#

Infer geometry from an xyz centroid MultiIndex.

Convenience constructor used by ParquetBlockModel.from_dataframe() when no explicit geometry is provided. The index must have levels ("x", "y", "z") in world coordinates.

Parameters:
  • index (pd.MultiIndex) – Centroid coordinates with names ["x", "y", "z"].

  • axis_azimuth (float) – Optional rotation angles (degrees) defining the orientation of the logical ijk axes in world space.

  • axis_dip (float) – Optional rotation angles (degrees) defining the orientation of the logical ijk axes in world space.

  • axis_plunge (float) – Optional rotation angles (degrees) defining the orientation of the logical ijk axes in world space.

Return type:

RegularGeometry

classmethod from_parquet(filepath, axis_azimuth=0.0, axis_dip=0.0, axis_plunge=0.0, chunk_size=1000000)[source]#

Reconstruct geometry from a Parquet file.

Preferred path is to read geometry metadata from the Parquet key_value_metadata under the reserved key "parq-blockmodel". If that key is missing, fall back to centroid-based inference using x, y, z columns and provided rotation angles. :rtype: RegularGeometry

Todo

Consider efficiency gains by staying in numpy versus using python sets.

classmethod from_parquet_metadata(metadata, key='parq-blockmodel')[source]#

Reconstruct geometry from Parquet file metadata.

Parameters:
  • metadata (Any) – Either a pyarrow.parquet.FileMetaData instance or a mapping of key-value metadata (usually dict[str, str]).

  • key (str) – Metadata key under which the geometry payload is stored.

Returns:

The reconstructed geometry.

Return type:

RegularGeometry

Raises:
  • KeyError – If the key is not present in the provided metadata.

  • TypeError – If metadata is not a valid type.

  • ValueError – If the payload cannot be interpreted as valid geometry metadata.

ijk_from_row_index(rows)[source]#

Convert row index/indices into (i, j, k) using C‑order.

ijk_from_xyz(x, y, z, tol=1e-06)[source]#

Map world-space centroid coordinates to integer logical ijk indices.

Return type:

tuple[ndarray, ndarray, ndarray]

property is_rotated: bool#

Return True if axes differ from the identity orientation.

property origin: tuple[float, float, float] | list[float]#

Backward-compatible access to world origin.

row_index_from_ijk(i, j, k)[source]#

Convert (i, j, k) into row index using C‑order.

row_index_from_xyz(x, y, z, tol=1e-06)[source]#

Map world-space centroid coordinates directly to C-order row indices.

Return type:

ndarray

property shape: tuple[int, int, int] | list[float]#

Backward-compatible access to grid shape.

property srs: str | None#

Backward-compatible access to spatial reference system.

to_dataframe()[source]#

Backward-compatible alias for to_dataframe_xyz().

Return type:

DataFrame

to_dataframe_xyz()[source]#

Return a DataFrame of XYZ centroids for export/inspection.

Return type:

DataFrame

to_metadata_dict()[source]#

Serialize geometry metadata for Parquet storage.

Return type:

dict

to_multi_index_ijk()[source]#

Export (i, j, k) indices as a MultiIndex in C‑order.

Return type:

MultiIndex

to_multi_index_xyz()[source]#

Return XYZ centroid coordinates as a MultiIndex. :rtype: MultiIndex

Note

This MultiIndex preserves C‑order row layout. If you want lexicographic (‘x slowest, z fastest’), sort it explicitly:

mi = geom.to_multi_index_xyz().sort_index()

to_pyvista(*, frame='world')[source]#

Return a pyvista.ImageData representing the dense grid.

Parameters:

frame (str, optional) – Coordinate frame used for the returned grid. - "world" (default): apply world orientation from axis_u/v/w. - "local": return axis-aligned local grid (no rotation).

Returns:

The grid representation.

Return type:

pyvista.ImageData

Note

In "world" mode, rotation is encoded using the ImageData direction matrix, so plotting reflects geometry orientation.

xyz_from_ijk(i, j, k)[source]#

Convert logical indices to world-space centroid coordinates.

Return type:

tuple[ndarray, ndarray, ndarray]

xyz_from_row_index(rows)[source]#

Convert C-order row index/indices to world-space centroid coordinates.

Return type:

tuple[ndarray, ndarray, ndarray]

class parq_blockmodel.WorldFrame(origin=(0.0, 0.0, 0.0), axis_u=(1.0, 0.0, 0.0), axis_v=(0.0, 1.0, 0.0), axis_w=(0.0, 0.0, 1.0), srs=None)[source]#

World embedding for local geometry.

Holds world origin, orthonormal axes, and optional CRS. It is responsible for local<->world coordinate transforms.

origin#

World origin coordinates (x0, y0, z0).

Type:

Point

axis_u#

Unit vector for U-axis in world coordinates.

Type:

Vector

axis_v#

Unit vector for V-axis in world coordinates.

Type:

Vector

axis_w#

Unit vector for W-axis in world coordinates.

Type:

Vector

srs#

Spatial reference system (CRS) identifier.

Type:

str, optional

local_to_world(local_points)[source]#

Map local 3xN points into world coordinates.

Return type:

ndarray

property rotation_matrix: ndarray#

Return matrix whose columns are world axes (u, v, w).

world_to_local(world_points)[source]#

Map world 3xN points into local coordinates.

Return type:

ndarray

parq_blockmodel.create_demo_blockmodel(shape=(3, 3, 3), block_size=(1.0, 1.0, 1.0), corner=(0.0, 0.0, 0.0), azimuth=0.0, dip=0.0, plunge=0.0, parquet_filepath=None, index_type='block_index')[source]#

Create a synthetic block model DataFrame or Parquet file.

This function generates a rectilinear block model defined in logical index space (i, j, k), together with world–space centroids and optional rotation. The function is intended for testing, exploration, and examples.

───────────────────────────────────────────────────────────────────────────── BLOCK MODEL INDEXING :rtype: DataFrame | Path

───────────────────────────────────────────────────────────────────────────── Logical indices:

  • (i, j, k) represent block indices along the x, y, and z axes.

  • Sorting by (i, j, k) gives the canonical logical block‑model order:

    i varies slowest j varies next k varies fastest

This ordering is purely logical and independent of how NumPy stores the data in memory.

Canonical block id:
  • block_id:

    Canonical linear id obtained by flattening logical (i,j,k) coordinates in NumPy C-order. This is frame-invariant and remains stable regardless of world-space rotation.

───────────────────────────────────────────────────────────────────────────── WORLD COORDINATES ───────────────────────────────────────────────────────────────────────────── World centroids are computed using:

x = corner_x + (i + 0.5) * dx y = corner_y + (j + 0.5) * dy z = corner_z + (k + 0.5) * dz

If azimuth, dip, or plunge are non‑zero, the world positions are rotated about the origin after centroid generation.

───────────────────────────────────────────────────────────────────────────── DEPTH INFORMATION ───────────────────────────────────────────────────────────────────────────── - depth:

Computed as (maximum z centroid + dz/2) − z.

  • depth_category:

    Categorical split into ‘shallow’ and ‘deep’.

───────────────────────────────────────────────────────────────────────────── DATAFRAME INDEXING OPTION ───────────────────────────────────────────────────────────────────────────── index_type:

  • “block_index”: the DataFrame is indexed by (i, j, k).

  • “world_centroids”: indexed by (x, y, z).

  • “block_id”: indexed by canonical block_id.

───────────────────────────────────────────────────────────────────────────── ATTRIBUTES ───────────────────────────────────────────────────────────────────────────── The DataFrame is assigned lightweight geometry metadata under:

df.attrs[“geometry”] = {

“shape”: (nx, ny, nz), “block_size”: (dx, dy, dz), “corner”: (corner_x, corner_y, corner_z), “rotation”: { “azimuth”: …, “dip”: …, “plunge”: … }, “geometry_type”: “rectilinear_blockmodel”, “canonical_identity”: “block_id”, “index_type”: index_type

}

These attrs are intentionally simpler than the full “parq‑blockmodel” production schema, but pseudo‑compatible and useful for testing.

───────────────────────────────────────────────────────────────────────────── PARAMETERS ───────────────────────────────────────────────────────────────────────────── shape : tuple[int, int, int]

Logical block model size (nx, ny, nz).

block_sizetuple[float, float, float]

Block dimensions (dx, dy, dz).

cornertuple[float, float, float]

World‑space minimum corner of the unrotated model.

azimuth, dip, plungefloat

Rotation angles applied to world centroids.

parquet_filepathPath | None

If supplied, the DataFrame is written to Parquet.

index_type{“block_index”, “world_centroids”, “block_id”}

Specifies which index is assigned to the returned DataFrame.

───────────────────────────────────────────────────────────────────────────── RETURNS ───────────────────────────────────────────────────────────────────────────── DataFrame or Path

The block model DataFrame, or the Parquet path if saved.

blockmodel

blockmodel.py

geometry

utils