Skip to main content

cmb-format

CMB (Cell Model Binary) is a binary file format and Python I/O library for storing UBC GIF–style tensor and octree meshes and their associated models. It provides an alternative to the ASCII mesh and model files used by UBC GIF software. CMB supports uniform and variable-spacing tensor meshes, octree meshes, multiple named models, and file- and model-level metadata.

CMB stores mesh geometry and model values as typed arrays, with metadata in JSON, so consumers can avoid parsing millions of numbers from text. Large octree consumers that need only arrays can also avoid allocating a full consumer mesh; see the discretize round trips and benchmarks.

Capabilities

  • Store mesh geometry and per-cell model arrays together in a .cmb file.
  • Store models separately from geometry to avoid duplicating large meshes.
  • Read selected model payloads without loading unrequested models.
  • Inspect model metadata and file contents without loading model payloads.
  • Verify each array's integrity with a SHA-256 checksum.

Installation

Requires Python 3.11 or newer. NumPy is the only runtime dependency.

Install from PyPI:

python -m pip install cmb-format

Or install from a local checkout:

python -m pip install .

Usage

The API accepts dictionaries of NumPy arrays describing meshes and models. CMB cell ordering differs from UBC GIF's, and these routines never reorder arrays. Tensor meshes number cells x fastest. Embedded octree cells must be stored in root-local Morton order, which the writers and read_file enforce; see Octree cell order and Cell numbering / ordering in the format specification.

Write a four-cell tensor mesh and a resistivity model, then read them back:

import numpy as np

import cmb_format as cmb

mesh = {
    "mode": "embedded",
    "mesh_class": "TensorMesh",
    "arrays": {
        "origin": np.zeros(3),
        "h_x": np.array([1.0, 2.0]),
        "h_y": np.array([1.0, 1.0]),
        "h_z": np.array([3.0]),
    },
}
models = {
    "rho": {
        "metadata": {"units": "ohm-m"},
        "array": np.array([10.0, 20.0, 30.0, 40.0]),
    }
}
cmb.write_file("example.cmb", mesh, models)

mesh, models, metadata = cmb.read_file("example.cmb")
rho = models["rho"]["array"]

# Load geometry and only the requested model. File order is preserved.
mesh, models, metadata = cmb.read_file("example.cmb", models=["rho"])

read_file loads and checksum-verifies all geometry and selected model arrays, including nested base-mesh geometry. Its three results match write_file's mesh, models, and metadata parameters, so passing them straight back preserves the mesh geometry, model arrays, and metadata. default_padding accepts a mapping with west, east, south, north, bottom, and top keys; omitted keys default to zero. Recognized padding on tensor and uniform meshes, bare references, and base_mesh descriptors is returned as a fresh complete dictionary of Python integers; an explicit null there is omitted. Unrecognized descriptor fields pass through unchanged on reads and are ignored by writers. The NumPy arrays are read-only; use .copy() if you need to modify them. models=None loads every model, models=[] loads none, and duplicate selections collapse in stored file order.

For inexpensive inspection, use the raw header summaries:

model_summaries = cmb.list_models("example.cmb")
contents = cmb.read_contents("example.cmb")

list_models returns mappings such as {"rho": {"metadata": {"units": "ohm-m"}, "dtype": "float64", "shape": [4]}} and reads no array payloads. read_contents returns {"has_mesh": bool, "mesh_type": str | None, "has_base_mesh": bool, "n_cells": int, "models": dict}; it reads only an embedded uniform mesh's three-value shape array to compute n_cells. Nested base-mesh and model payloads remain unread. Both helpers preserve model metadata, dtype, shape, and stored order.

To read individual arrays without loading the whole file:

with open("example.cmb", "rb") as f:
    header, data_start = cmb.read_header(f)
    metadata = header["metadata"]
    geometry = cmb.read_arrays(f, data_start, header["mesh"]["arrays"])
    rho = cmb.read_array(f, data_start, header["models"]["rho"]["array"])

read_header accepts the keyword read_shape_payload. Its default True performs full header validation, including the embedded uniform mesh shape checksum. Set it to False for structural header checks without reading shape payloads; shape values and dependent uniform padding or model-count checks are deferred. The returned header contains normalized named dictionaries for recognized padding, including when it reads a legacy v1 file, and uses format_version 2. Unrecognized fields remain unchanged.

Octree cell order

Embedded octree cells must be stored in root-local Morton order. The base grid is divided into cubic roots of L = min(nx, ny, nz) base cells per axis; roots are visited x fastest, then y, then z, and the cells in each root follow the Morton order of their lower corners. octree_order_keys(position, shape) returns each cell's ordering key, and the stored keys must strictly increase. write_file and build_file_bytes reject embedded octree geometry that is out of order or repeats a position; write_file does so before opening the output file. read_file rejects such files after verifying the geometry and before reading any model payload. Nothing reorders arrays, and keeping each model value aligned with the cell it describes is the caller's responsibility. To put cells in order, apply one permutation to level, position, and every model:

order = np.argsort(cmb.octree_order_keys(position, shape), kind="stable")

Reference-mode files store no octree geometry, so their model order cannot be checked. Store reference models in the root-local order of the mesh they accompany; matching n_cells or base_mesh does not show that the cells match.

read_header, read_array, and read_arrays return stored arrays without checking cell order, and list_models and read_contents do not read octree geometry, so a successful inspection does not certify the order. The low-level readers can migrate a file written in another order:

with open("unordered.cmb", "rb") as f:
    header, data_start = cmb.read_header(f)
    mesh = header["mesh"]
    mesh["arrays"] = cmb.read_arrays(f, data_start, mesh["arrays"])
    base = mesh["base_mesh"]
    base["arrays"] = cmb.read_arrays(f, data_start, base["arrays"])
    models = {
        name: {**entry, "array": cmb.read_array(f, data_start, entry["array"])}
        for name, entry in header.get("models", {}).items()
    }

keys = cmb.octree_order_keys(mesh["arrays"]["position"], base["arrays"]["shape"])
order = np.argsort(keys, kind="stable")
mesh["arrays"] = {name: values[order] for name, values in mesh["arrays"].items()}
for entry in models.values():
    entry["array"] = entry["array"][order]
cmb.write_file("ordered.cmb", mesh, models, header.get("metadata", {}))

Sorting keeps each model value with its cell only if the original file already paired them correctly. It cannot repair models that are misaligned with the geometry.

For measured large-octree and tensor round trips and timing methodology, see the discretize interoperability notes. On the measured 2.18-million-cell sample, the generated CMB file is 10.4 MiB versus 28.8 MiB for UBC, and conversion plus CMB writing was about 21× faster in measurements taken before octree cell-order validation was added.

Development

From a local checkout, with pip 25.1 or newer:

python -m pip install --group dev -e .
python -m pytest
python -m ruff check .
python -m ruff format --check .

Committed v1 and v2 reference files in tests/goldens/v1/ and tests/goldens/v2/ test compatibility with the binary format alongside round-trip tests.

The format specification defines the file layout and mesh schemas. Package and format versions are independent; see versioning and the package changelog and format changelog.

Metadata

Release files for cmb-format 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cmb-format 0.3.0
File Size Uploaded
cmb_format-0.3.0.tar.gz 59.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cmb-format 0.3.0
File Interpreter ABI Platform
cmb_format-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 83.4 kB

Release files / cmb_format-0.3.0.tar.gz

Download URL cmb_format-0.3.0.tar.gz
Size 59.8 kB
Tags Source
SHA-256 checksum
How to use checksums
765be4917ebc38000852ccf2b75341438929a58b131a3c997bb38cb80bb04b38
BLAKE2b-256 checksum
How to use checksums
f3164899efa812895ab538f4bce6706265ee4d232927f7c9f4957c32a824aa9a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.

Transparency log

Release files / cmb_format-0.3.0-py3-none-any.whl

Download URL cmb_format-0.3.0-py3-none-any.whl
Size 23.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9a454a4ee9c09d596d39bd3801edc0d41d8601992ad773bc072169d81264ca65
BLAKE2b-256 checksum
How to use checksums
9289978dd37f789d5979f73455a12001971a38af95e76c4f564f2d29862e55ad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page