cmb-format 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cmb_format-0.1.0/.github/workflows/ci.yml +85 -0
- cmb_format-0.1.0/.github/workflows/release.yml +61 -0
- cmb_format-0.1.0/.gitignore +32 -0
- cmb_format-0.1.0/CHANGELOG.md +14 -0
- cmb_format-0.1.0/LICENSE +21 -0
- cmb_format-0.1.0/PKG-INFO +131 -0
- cmb_format-0.1.0/README.md +106 -0
- cmb_format-0.1.0/docs/binary-format.md +320 -0
- cmb_format-0.1.0/docs/discretize.md +171 -0
- cmb_format-0.1.0/pyproject.toml +67 -0
- cmb_format-0.1.0/src/cmb_format/__init__.py +58 -0
- cmb_format-0.1.0/src/cmb_format/_codec.py +861 -0
- cmb_format-0.1.0/src/cmb_format/_detect.py +32 -0
- cmb_format-0.1.0/src/cmb_format/_file.py +189 -0
- cmb_format-0.1.0/src/cmb_format/_padding.py +114 -0
- cmb_format-0.1.0/src/cmb_format/py.typed +0 -0
- cmb_format-0.1.0/tests/cases.py +183 -0
- cmb_format-0.1.0/tests/generate_goldens.py +35 -0
- cmb_format-0.1.0/tests/goldens/all_dtypes.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/all_dtypes.header.json +120 -0
- cmb_format-0.1.0/tests/goldens/octree_base_padding_models.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/octree_base_padding_models.header.json +86 -0
- cmb_format-0.1.0/tests/goldens/octree_embedded.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/octree_embedded.header.json +61 -0
- cmb_format-0.1.0/tests/goldens/octree_rectangular_models.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/octree_rectangular_models.header.json +76 -0
- cmb_format-0.1.0/tests/goldens/reference_explicit_n_cells.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/reference_explicit_n_cells.header.json +24 -0
- cmb_format-0.1.0/tests/goldens/reference_models_only.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/reference_models_only.header.json +24 -0
- cmb_format-0.1.0/tests/goldens/reference_with_base_mesh.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/reference_with_base_mesh.header.json +56 -0
- cmb_format-0.1.0/tests/goldens/tensor_embedded.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/tensor_embedded.header.json +47 -0
- cmb_format-0.1.0/tests/goldens/tensor_padding.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/tensor_padding.header.json +55 -0
- cmb_format-0.1.0/tests/goldens/tensor_with_models.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/tensor_with_models.header.json +79 -0
- cmb_format-0.1.0/tests/goldens/uniform_embedded.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/uniform_embedded.header.json +38 -0
- cmb_format-0.1.0/tests/goldens/uniform_padding_models.cmb +0 -0
- cmb_format-0.1.0/tests/goldens/uniform_padding_models.header.json +61 -0
- cmb_format-0.1.0/tests/test_codec.py +233 -0
- cmb_format-0.1.0/tests/test_detect.py +71 -0
- cmb_format-0.1.0/tests/test_file.py +122 -0
- cmb_format-0.1.0/tests/test_goldens.py +134 -0
- cmb_format-0.1.0/tests/test_helpers.py +58 -0
- cmb_format-0.1.0/tests/test_octree_order.py +72 -0
- cmb_format-0.1.0/tests/test_public_api.py +52 -0
- cmb_format-0.1.0/tests/test_validation.py +570 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
python-version: ["3.11", "3.12", "3.13", "3.14"]
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
cache: pip
|
|
26
|
+
|
|
27
|
+
- name: Install
|
|
28
|
+
run: |
|
|
29
|
+
python -m pip install --upgrade pip
|
|
30
|
+
python -m pip install --group test -e .
|
|
31
|
+
|
|
32
|
+
- name: Test
|
|
33
|
+
run: python -m pytest -q
|
|
34
|
+
|
|
35
|
+
lint:
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v4
|
|
39
|
+
|
|
40
|
+
- uses: actions/setup-python@v5
|
|
41
|
+
with:
|
|
42
|
+
python-version: "3.12"
|
|
43
|
+
cache: pip
|
|
44
|
+
|
|
45
|
+
- name: Install
|
|
46
|
+
run: |
|
|
47
|
+
python -m pip install --upgrade pip
|
|
48
|
+
python -m pip install --group lint -e .
|
|
49
|
+
|
|
50
|
+
- name: Lint
|
|
51
|
+
run: python -m ruff check .
|
|
52
|
+
|
|
53
|
+
- name: Format
|
|
54
|
+
run: python -m ruff format --check .
|
|
55
|
+
|
|
56
|
+
package:
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
|
|
61
|
+
- uses: actions/setup-python@v5
|
|
62
|
+
with:
|
|
63
|
+
python-version: "3.12"
|
|
64
|
+
cache: pip
|
|
65
|
+
|
|
66
|
+
- name: Install build tools
|
|
67
|
+
run: |
|
|
68
|
+
python -m pip install --upgrade pip
|
|
69
|
+
python -m pip install build twine
|
|
70
|
+
|
|
71
|
+
- name: Build distributions
|
|
72
|
+
# Build the wheel from the sdist to verify both distribution paths.
|
|
73
|
+
run: python -m build
|
|
74
|
+
|
|
75
|
+
- name: Check distribution metadata
|
|
76
|
+
run: python -m twine check --strict dist/*
|
|
77
|
+
|
|
78
|
+
- name: Install wheel and test dependencies
|
|
79
|
+
run: python -m pip install --group test dist/*.whl
|
|
80
|
+
|
|
81
|
+
- name: Test installed wheel
|
|
82
|
+
run: |
|
|
83
|
+
cd "$RUNNER_TEMP"
|
|
84
|
+
python -c 'from importlib.resources import files; assert files("cmb_format").joinpath("py.typed").is_file()'
|
|
85
|
+
python -m pytest -q "$GITHUB_WORKSPACE/tests"
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: "3.12"
|
|
16
|
+
cache: pip
|
|
17
|
+
|
|
18
|
+
- name: Install build tools
|
|
19
|
+
run: |
|
|
20
|
+
python -m pip install --upgrade pip
|
|
21
|
+
python -m pip install build twine
|
|
22
|
+
|
|
23
|
+
- name: Verify the tag matches the packaged version
|
|
24
|
+
# PyPI versions are immutable, so catch a tag/version mismatch here
|
|
25
|
+
# rather than after an upload that cannot be replaced.
|
|
26
|
+
run: |
|
|
27
|
+
version=$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml","rb"))["project"]["version"])')
|
|
28
|
+
if [ "$version" != "${GITHUB_REF_NAME#v}" ]; then
|
|
29
|
+
echo "::error::tag ${GITHUB_REF_NAME} does not match pyproject version ${version}"
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
|
|
33
|
+
- name: Build distributions
|
|
34
|
+
# Build the wheel from the sdist to verify both distribution paths.
|
|
35
|
+
run: python -m build
|
|
36
|
+
|
|
37
|
+
- name: Check distribution metadata
|
|
38
|
+
run: python -m twine check --strict dist/*
|
|
39
|
+
|
|
40
|
+
- uses: actions/upload-artifact@v4
|
|
41
|
+
with:
|
|
42
|
+
name: dist
|
|
43
|
+
path: dist/
|
|
44
|
+
|
|
45
|
+
publish:
|
|
46
|
+
needs: build
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
# Must match the pending publisher configured at
|
|
49
|
+
# https://pypi.org/manage/account/publishing/
|
|
50
|
+
environment: pypi
|
|
51
|
+
permissions:
|
|
52
|
+
# Required for Trusted Publishing; the job requests an OIDC token
|
|
53
|
+
# instead of holding a long-lived API token.
|
|
54
|
+
id-token: write
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/download-artifact@v4
|
|
57
|
+
with:
|
|
58
|
+
name: dist
|
|
59
|
+
path: dist/
|
|
60
|
+
|
|
61
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
|
|
9
|
+
# Environments (the workspace venv lives in the parent dev/ directory)
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
.env
|
|
13
|
+
|
|
14
|
+
# Tooling caches
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
.mypy_cache/
|
|
18
|
+
.coverage
|
|
19
|
+
.coverage.*
|
|
20
|
+
htmlcov/
|
|
21
|
+
coverage.xml
|
|
22
|
+
|
|
23
|
+
# Editors / OS
|
|
24
|
+
.vscode/
|
|
25
|
+
.idea/
|
|
26
|
+
.DS_Store
|
|
27
|
+
|
|
28
|
+
# NOTE: tests/goldens/ is deliberately NOT ignored. Those committed bytes are
|
|
29
|
+
# the format's reference -- they are the whole point of this repository.
|
|
30
|
+
|
|
31
|
+
# Local Claude Code instructions -- not meant to be committed
|
|
32
|
+
/CLAUDE.md
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes to `cmb-format`, the Python reference implementation.
|
|
4
|
+
|
|
5
|
+
This file tracks the **package**. The CMB **format** versions separately —
|
|
6
|
+
see `docs/binary-format.md`'s Versioning section. Which format versions a
|
|
7
|
+
build handles is stated in code, as `WRITTEN_FORMAT_VERSION` and
|
|
8
|
+
`READABLE_FORMAT_VERSIONS`.
|
|
9
|
+
|
|
10
|
+
## [0.1.0]
|
|
11
|
+
|
|
12
|
+
Initial release.
|
|
13
|
+
|
|
14
|
+
[0.1.0]: https://github.com/dwfmarchant/cmb-format/releases/tag/v0.1.0
|
cmb_format-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 David Marchant
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: cmb-format
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Specification and reference implementation of CMB (Cell Model Binary), a file format for cell-based meshes and the models defined on them
|
|
5
|
+
Project-URL: Homepage, https://github.com/dwfmarchant/cmb-format
|
|
6
|
+
Project-URL: Repository, https://github.com/dwfmarchant/cmb-format
|
|
7
|
+
Project-URL: Changelog, https://github.com/dwfmarchant/cmb-format/blob/main/CHANGELOG.md
|
|
8
|
+
Project-URL: Issues, https://github.com/dwfmarchant/cmb-format/issues
|
|
9
|
+
Project-URL: Specification, https://github.com/dwfmarchant/cmb-format/blob/main/docs/binary-format.md
|
|
10
|
+
Author-email: David Marchant <dwfmarchant@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: binary-format,cmb,file-format,geophysics,mesh,octree
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Requires-Dist: numpy>=1.26
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# cmb-format
|
|
27
|
+
|
|
28
|
+
**CMB (Cell Model Binary)** is a binary file format and Python I/O library
|
|
29
|
+
for storing UBC GIF–style tensor and octree meshes and their associated
|
|
30
|
+
models. It provides an alternative to the ASCII mesh and model files used
|
|
31
|
+
by UBC GIF software. CMB supports uniform and variable-spacing tensor
|
|
32
|
+
meshes, octree meshes, multiple named models, and file- and model-level
|
|
33
|
+
metadata.
|
|
34
|
+
|
|
35
|
+
CMB stores mesh geometry and model values as typed arrays, with metadata in
|
|
36
|
+
JSON, so consumers can avoid parsing millions of numbers from text. Large
|
|
37
|
+
octree consumers that need only arrays can also avoid allocating a full
|
|
38
|
+
consumer mesh; see the [discretize round trips and benchmarks](https://github.com/dwfmarchant/cmb-format/blob/main/docs/discretize.md).
|
|
39
|
+
|
|
40
|
+
## Capabilities
|
|
41
|
+
|
|
42
|
+
- Store mesh geometry and per-cell model arrays together in a `.cmb` file.
|
|
43
|
+
- Store models separately from geometry to avoid duplicating large meshes.
|
|
44
|
+
- Read individual arrays without loading the whole file.
|
|
45
|
+
- Verify each array's integrity with a SHA-256 checksum.
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
Requires Python 3.11 or newer. NumPy is the only runtime dependency.
|
|
50
|
+
From a local checkout:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
python -m pip install .
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
The API accepts dictionaries of NumPy arrays describing meshes and models.
|
|
59
|
+
CMB uses a different cell ordering from UBC GIF; these routines do not
|
|
60
|
+
convert between the two. See
|
|
61
|
+
[Cell numbering / ordering](https://github.com/dwfmarchant/cmb-format/blob/main/docs/binary-format.md#cell-numbering-ordering)
|
|
62
|
+
in the format specification.
|
|
63
|
+
|
|
64
|
+
Write a four-cell tensor mesh and a resistivity model, then read them back:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import numpy as np
|
|
68
|
+
|
|
69
|
+
import cmb_format as cmb
|
|
70
|
+
|
|
71
|
+
mesh = {
|
|
72
|
+
"mode": "embedded",
|
|
73
|
+
"mesh_class": "TensorMesh",
|
|
74
|
+
"arrays": {
|
|
75
|
+
"origin": np.zeros(3),
|
|
76
|
+
"h_x": np.array([1.0, 2.0]),
|
|
77
|
+
"h_y": np.array([1.0, 1.0]),
|
|
78
|
+
"h_z": np.array([3.0]),
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
models = {
|
|
82
|
+
"rho": {
|
|
83
|
+
"metadata": {"units": "ohm-m"},
|
|
84
|
+
"array": np.array([10.0, 20.0, 30.0, 40.0]),
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
cmb.write_file("example.cmb", mesh, models)
|
|
88
|
+
|
|
89
|
+
mesh, models, metadata = cmb.read_file("example.cmb")
|
|
90
|
+
rho = models["rho"]["array"]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`read_file` loads and checksum-verifies all geometry and model arrays,
|
|
94
|
+
including nested base-mesh geometry. Its three results match `write_file`'s
|
|
95
|
+
`mesh`, `models`, and `metadata` parameters, so passing them straight back
|
|
96
|
+
preserves the mesh geometry, model arrays, and metadata. The NumPy arrays are
|
|
97
|
+
read-only; use `.copy()` if you need to modify them.
|
|
98
|
+
|
|
99
|
+
To read individual arrays without loading the whole file:
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
with open("example.cmb", "rb") as f:
|
|
103
|
+
header, data_start = cmb.read_header(f)
|
|
104
|
+
metadata = header["metadata"]
|
|
105
|
+
geometry = cmb.read_arrays(f, data_start, header["mesh"]["arrays"])
|
|
106
|
+
rho = cmb.read_array(f, data_start, header["models"]["rho"]["array"])
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
For measured large-octree and tensor round trips and timing methodology, see
|
|
110
|
+
[the discretize interoperability notes](https://github.com/dwfmarchant/cmb-format/blob/main/docs/discretize.md). On the measured
|
|
111
|
+
2.18-million-leaf sample, the generated CMB file is 10.4 MiB versus 28.8 MiB
|
|
112
|
+
for UBC, and conversion plus CMB writing is about 21× faster.
|
|
113
|
+
|
|
114
|
+
## Development
|
|
115
|
+
|
|
116
|
+
From a local checkout, with pip 25.1 or newer:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
python -m pip install --group dev -e .
|
|
120
|
+
python -m pytest
|
|
121
|
+
python -m ruff check .
|
|
122
|
+
python -m ruff format --check .
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Committed reference files in `tests/goldens/` test compatibility with the
|
|
126
|
+
binary format alongside round-trip tests.
|
|
127
|
+
|
|
128
|
+
The [format specification](https://github.com/dwfmarchant/cmb-format/blob/main/docs/binary-format.md) defines the file layout
|
|
129
|
+
and mesh schemas. Package and format versions are independent; see
|
|
130
|
+
[versioning](https://github.com/dwfmarchant/cmb-format/blob/main/docs/binary-format.md#versioning) and the
|
|
131
|
+
[package changelog](https://github.com/dwfmarchant/cmb-format/blob/main/CHANGELOG.md).
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# cmb-format
|
|
2
|
+
|
|
3
|
+
**CMB (Cell Model Binary)** is a binary file format and Python I/O library
|
|
4
|
+
for storing UBC GIF–style tensor and octree meshes and their associated
|
|
5
|
+
models. It provides an alternative to the ASCII mesh and model files used
|
|
6
|
+
by UBC GIF software. CMB supports uniform and variable-spacing tensor
|
|
7
|
+
meshes, octree meshes, multiple named models, and file- and model-level
|
|
8
|
+
metadata.
|
|
9
|
+
|
|
10
|
+
CMB stores mesh geometry and model values as typed arrays, with metadata in
|
|
11
|
+
JSON, so consumers can avoid parsing millions of numbers from text. Large
|
|
12
|
+
octree consumers that need only arrays can also avoid allocating a full
|
|
13
|
+
consumer mesh; see the [discretize round trips and benchmarks](https://github.com/dwfmarchant/cmb-format/blob/main/docs/discretize.md).
|
|
14
|
+
|
|
15
|
+
## Capabilities
|
|
16
|
+
|
|
17
|
+
- Store mesh geometry and per-cell model arrays together in a `.cmb` file.
|
|
18
|
+
- Store models separately from geometry to avoid duplicating large meshes.
|
|
19
|
+
- Read individual arrays without loading the whole file.
|
|
20
|
+
- Verify each array's integrity with a SHA-256 checksum.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
Requires Python 3.11 or newer. NumPy is the only runtime dependency.
|
|
25
|
+
From a local checkout:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
python -m pip install .
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
The API accepts dictionaries of NumPy arrays describing meshes and models.
|
|
34
|
+
CMB uses a different cell ordering from UBC GIF; these routines do not
|
|
35
|
+
convert between the two. See
|
|
36
|
+
[Cell numbering / ordering](https://github.com/dwfmarchant/cmb-format/blob/main/docs/binary-format.md#cell-numbering-ordering)
|
|
37
|
+
in the format specification.
|
|
38
|
+
|
|
39
|
+
Write a four-cell tensor mesh and a resistivity model, then read them back:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import numpy as np
|
|
43
|
+
|
|
44
|
+
import cmb_format as cmb
|
|
45
|
+
|
|
46
|
+
mesh = {
|
|
47
|
+
"mode": "embedded",
|
|
48
|
+
"mesh_class": "TensorMesh",
|
|
49
|
+
"arrays": {
|
|
50
|
+
"origin": np.zeros(3),
|
|
51
|
+
"h_x": np.array([1.0, 2.0]),
|
|
52
|
+
"h_y": np.array([1.0, 1.0]),
|
|
53
|
+
"h_z": np.array([3.0]),
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
models = {
|
|
57
|
+
"rho": {
|
|
58
|
+
"metadata": {"units": "ohm-m"},
|
|
59
|
+
"array": np.array([10.0, 20.0, 30.0, 40.0]),
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
cmb.write_file("example.cmb", mesh, models)
|
|
63
|
+
|
|
64
|
+
mesh, models, metadata = cmb.read_file("example.cmb")
|
|
65
|
+
rho = models["rho"]["array"]
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`read_file` loads and checksum-verifies all geometry and model arrays,
|
|
69
|
+
including nested base-mesh geometry. Its three results match `write_file`'s
|
|
70
|
+
`mesh`, `models`, and `metadata` parameters, so passing them straight back
|
|
71
|
+
preserves the mesh geometry, model arrays, and metadata. The NumPy arrays are
|
|
72
|
+
read-only; use `.copy()` if you need to modify them.
|
|
73
|
+
|
|
74
|
+
To read individual arrays without loading the whole file:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
with open("example.cmb", "rb") as f:
|
|
78
|
+
header, data_start = cmb.read_header(f)
|
|
79
|
+
metadata = header["metadata"]
|
|
80
|
+
geometry = cmb.read_arrays(f, data_start, header["mesh"]["arrays"])
|
|
81
|
+
rho = cmb.read_array(f, data_start, header["models"]["rho"]["array"])
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For measured large-octree and tensor round trips and timing methodology, see
|
|
85
|
+
[the discretize interoperability notes](https://github.com/dwfmarchant/cmb-format/blob/main/docs/discretize.md). On the measured
|
|
86
|
+
2.18-million-leaf sample, the generated CMB file is 10.4 MiB versus 28.8 MiB
|
|
87
|
+
for UBC, and conversion plus CMB writing is about 21× faster.
|
|
88
|
+
|
|
89
|
+
## Development
|
|
90
|
+
|
|
91
|
+
From a local checkout, with pip 25.1 or newer:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
python -m pip install --group dev -e .
|
|
95
|
+
python -m pytest
|
|
96
|
+
python -m ruff check .
|
|
97
|
+
python -m ruff format --check .
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Committed reference files in `tests/goldens/` test compatibility with the
|
|
101
|
+
binary format alongside round-trip tests.
|
|
102
|
+
|
|
103
|
+
The [format specification](https://github.com/dwfmarchant/cmb-format/blob/main/docs/binary-format.md) defines the file layout
|
|
104
|
+
and mesh schemas. Package and format versions are independent; see
|
|
105
|
+
[versioning](https://github.com/dwfmarchant/cmb-format/blob/main/docs/binary-format.md#versioning) and the
|
|
106
|
+
[package changelog](https://github.com/dwfmarchant/cmb-format/blob/main/CHANGELOG.md).
|