Repository navigation
Python API and CLI Tools
python-cmat provides both a pure Python library API (cmat.py) for integration into custom scripts and Jupyter notebooks, and a standalone command-line converter (cmat2amat.py) for converting .cmat files into standard ASCII formats.
The core library revolves around the CMATReader class, which handles binary parsing, IVF segment navigation, and on-demand block decompression.
from cmat import CMATReader
# 1. Open .cmat file (supports symmetric, asymmetric, and arbitrary step sizes)
reader = CMATReader("GeE-symm.cmat")
# 2. Inspect file header and IVF metadata
info = reader.get_info()
print("Filename: ", info["filename"])
print("Shape: ", info["shape"]) # (res1, res2)
print("Matrix Mode: ", info["matrix_mode"]) # 0 = symmetric, 1 = normal, etc.
print("Step Size: ", info["step"]) # (step1, step2)
print("Total Blocks: ", info["blocks"])
# 3. Decompress the full matrix into a NumPy 2D array (int32)
# Resulting array shape is (res2, res1) = (Height/Y, Width/X)
matrix = reader.to_numpy()
print(f"Decompressed shape: {matrix.shape}")
print(f"Total matrix counts: {matrix.sum():,}")
# 4. Extract total 1D projections
# axis=0: Det 1 (X) projection; axis=1: Det 2 (Y) projection
proj_det1 = reader.get_projection(axis=0)
proj_det2 = reader.get_projection(axis=1)
# 5. Extract coincidence-gated 1D projection
# Gate channels 500 to 520 on Det 1 -> returns coincidence spectrum on Det 2
net_spec, bg_spec, raw_spec = reader.get_gate(500, 520, axis=0)
# 6. Extract 2D Banana Graphical Polygon ROI & Net Counts
# Computes pixel mask, geometric area, raw counts, and normalized subtraction
banana = reader.get_banana_roi(
polygon_peak=[[100, 100], [150, 120], [140, 160], [90, 140]],
polygon_bg=[[80, 80], [170, 100], [160, 180], [70, 160]]
)
print(f"Net Banana Area: {banana['net_counts']:,.1f} +/- {banana['net_err']:,.1f}")
# 7. Export directly to ASCII (.amat) format
reader.export_amat("GeE-symm.amat", format_type="dense")Initializes the reader, parses IVF header records, builds block offset tables, and extracts stored projections if available.
Returns a metadata dictionary containing:
-
filename: Absolute path to the matrix file. -
shape: Tuple(res1, res2)representing matrix dimensions. -
step: Tuple(step1, step2)representing sub-matrix block size. -
matrix_mode: Integer mode flag (e.g. 0 for folded symmetric, 1 for normal full). -
blocks: Total count of IVF blocks stored in the container.
Decompresses all sub-blocks into a 2D NumPy array of int32 elements.
- Returns array with shape
(res2, res1). - For symmetric matrices, automatically mirrors the triangular blocks across the diagonal (
$M_{ij} = M_{ji}$ ).
Returns a 1D NumPy array representing the total projection:
-
axis=0: Det 1 / X projection. -
axis=1: Det 2 / Y projection. - Uses IVF pre-computed projection segments when available, falling back to full-matrix summation if missing.
get_gate(gate_min: int, gate_max: int, axis: int = 0, bg_min: int = None, bg_max: int = None) -> tuple
Extracts a coincidence-gated 1D slice along the specified axis:
- Slices between
gate_minandgate_max. - If
bg_minandbg_maxare provided, performs normalized background subtraction scaled by channel window width. - Returns
(net_spectrum, bg_spectrum, raw_spectrum).
Calculates discrete pixel containment, continuous geometric Shoelace area, raw counts, area-normalized scale factor, and net background-subtracted counts for arbitrary 2D polygon ROIs:
-
polygon_peak: List of[x, y]coordinate pairs defining the Peak polygon ROI. -
polygon_bg: Optional list of[x, y]coordinate pairs defining the Background polygon ROI. - Returns dictionary containing:
-
peak: Sub-dictionary witharea_geom,pixels,counts, andvertices. -
bg: Sub-dictionary with background metrics (orNone). -
scale: Area normalization factor ($\text{Area}{\text{peak}} / \text{Area}{\text{bg}}$). -
net_counts: Area-normalized net peak counts ($C_{\text{peak}} - \text{scale} \times C_{\text{bg}}$ ). -
net_err: Statistical uncertainty$\sqrt{C_{\text{peak}} + \text{scale}^2 \times C_{\text{bg}}}$ .
-
Exports matrix counts to an ASCII .amat file:
-
format_type="dense": Rectangular grid of count values. -
format_type="sparse": Triplet list ofx y countsfor non-zero channels. -
roi: Optional(xmin, xmax, ymin, ymax)tuple to restrict exported area.
pycmat is a standalone executable Python dispatcher that automatically inspects input .cmat file headers in ndim), seamlessly forwarding all CLI flags and options to the appropriate viewer:
-
2D Matrices (
ndim == 2): Launchescmat_webviewer.py -
3D Matrices (
ndim == 3): Launchescmat3d_webviewer.py
# Launch interactive viewer for any 2D or 3D matrix (auto-detected)
./pycmat /path/to/matrix.cmat
# Forward options such as custom port, calibration, or browser settings
./pycmat run1.cmat --port 8085 --no-browser
# Execute batch headless spectroscopy commands
./pycmat GeE-symm.cmat -c "info; search 0"cmat2amat.py provides a convenient command-line interface for converting proprietary .cmat files into standard plain-text ASCII files compatible with ROOT, GNUplot, MATLAB, and spreadsheet software.
# Convert entire matrix to a dense 2D ASCII grid:
python3 cmat2amat.py GeE-symm.cmat GeE-symm.amat
# Convert a specific Region of Interest (ROI):
# Channels 0 to 200 on X, 0 to 200 on Y
python3 cmat2amat.py GeE-symm.cmat GeE_roi.amat --roi 0 200 0 200
# Export as a sparse list of non-zero channels (x y counts):
python3 cmat2amat.py GeE-symm.cmat GeE_sparse.amat --format sparse| Argument | Description |
|---|---|
input_file |
Path to the source .cmat binary matrix file. |
output_file |
Destination path for the generated ASCII .amat file. |
--format |
Output structure: dense (default grid) or sparse (x y counts). |
--roi xmin xmax ymin ymax |
Bounding box coordinates to export a sub-region rather than the whole matrix. |
--verbose |
Output detailed decompression diagnostics and block statistics to stdout. |
python-cmat includes CMAT3DReader for handling 3D matrix cubes with memory-mapped array caching and multi-plane slicing.
from cmat3d import CMAT3DReader
# 1. Initialize reader and build/load memory-mapped cache
reader3d = CMAT3DReader("GeE-Rings3D.cmat")
print(f"3D Shape: {reader3d.shape}") # (4096, 4096, 128)
print(f"Total counts: {reader3d.total_counts:,}")
# 2. Access 3D volume directly as NumPy array / memmap (int32)
vol = reader3d.to_memmap()
# 3. Extract 2D orthogonal plane projection
# plane: '0-1' (Det 1 vs Det 2), '0-2' (Det 1 vs Rings), '1-2' (Det 2 vs Rings)
plane_01 = reader3d.get_2d_plane("0-1")
plane_01_sub = reader3d.get_2d_plane("0-1", x0=1000, x1=2000, y0=1000, y1=2000)
# 4. Extract total 1D projection along any axis (0, 1, or 2)
spec_det1 = reader3d.get_projection_1d(axis=0)
# 5. Extract 1D coincidence cuts with background subtraction
net_spec, bg_spec = reader3d.get_gate_1d(
target_axis=0,
w_gates={2: [[11, 11]]}, # Gate on Ring 11 (axis 2)
b_gates={2: [[1, 2], [20, 21]]} # Background rings
)
# 6. Extract 2D Banana Graphical Polygon Cut
banana_cut = reader3d.get_banana_gate(
plane="0-2",
polygon=[[1000, 10], [1500, 12], [1480, 15], [980, 13]]
)
print("Banana cut net spectrum sum:", banana_cut["net_spec"].sum())python-cmat includes ENSDFSearchEngine for automated offline isotope identification of 1D photopeaks and 2D coincidence cascades using physical cascade topologies and global mass-clustering parsimony.
# Identify full fit results log file:
python3 ensdf_search.py fit_results_20260922_155405.txt --top 5
# Manual 2D coincidence search:
python3 ensdf_search.py -c 1434.2 935.3 --tol 1.5 --top 5
# Manual 1D single-energy search:
python3 ensdf_search.py -g 1480.3 --tol 1.5
# Database status & statistics:
python3 ensdf_search.py --statusfrom ensdf_search import ENSDFSearchEngine
engine = ENSDFSearchEngine()
# Identify entire fit results file with global parsimonious set cover
report = engine.identify_fit_results_file(
"fit_results_20260922_155405.txt",
tol=1.5,
top_candidates=5
)
print(f"Dominant Mass Center: A ≈ {report['dominant_mass']}")
print(f"Minimal Isotope Set: {report['parsimonious_isotopes']}")
for res in report["results_2d"]:
fit = res["fit"]
best = res["best_match"]
print(f"2D Fit {fit['energy1']} x {fit['energy2']} keV -> {best['nuclide']} (Score: {best['score']}, {best['cascade_type']})")python-cmat © 2026. Released under the MIT License. Return to GitHub Repository
Interactive 2D & 3D Matrix Analysis & Spectroscopy
- Home
- Interactive Web Viewer
- 3D Matrix Analysis & Web Viewer
- Keyboard Shortcuts & Controls
- ROOT Files & Live Histograms
- ENSDF Isotope Identification
- Spectroscopy Commands & Macros
- Configuration Guide
- Python API & CLI Tools