Read, write, and analyse COMSOL HDF5 result files (.cmslh5)
Project description
cmslh5
Read, write, and analyse COMSOL Multiphysics simulation results in HDF5.
cmslh5 is a Python toolkit that bridges COMSOL Multiphysics and the scientific Python ecosystem. It converts COMSOL .mph model files into a structured, open HDF5 archive (.cmslh5), then provides a rich API to extract, interpolate, compare, and analyse the results — without needing a COMSOL license for post-processing.
Why?
COMSOL's native .mph format is proprietary and requires a running COMSOL server to read. This creates friction when you want to:
- Post-process results on a laptop without a COMSOL license
- Share simulation data with collaborators who don't have COMSOL
- Run automated analysis pipelines in Python
- Load results into ParaView, matplotlib, or Jupyter notebooks
- Compare results across mesh refinements or parameter sweeps
- Archive simulation data in a long-term, vendor-neutral format
cmslh5 solves all of these by extracting everything into HDF5 once, then providing fast, license-free access forever.
Features
| Feature | Description |
|---|---|
| Convert | Extract mesh, elements, physical groups, and all physics fields from .mph to .cmslh5 |
| Parallel extraction | Split node range across multiple COMSOL worker processes for large models |
| Read | Query nodes, elements, domains, studies, timesteps, and field data |
| Interpolate | Temporal interpolation between stored timesteps; spatial IDW interpolation to arbitrary points |
| Line extraction | Sample any field along parametric curves defined by equations in x, y, z |
| Point probes | Evaluate any component at any spatial point and time |
| Time histories | Extract full time series at monitoring points |
| Compare | Diff two .cmslh5 files field-by-field for regression testing |
| Statistics | Time-average, RMS, min/max, FFT at points |
| Export | Write to CSV, VTK (for ParaView via meshio) |
| ParaView plugin | Native ParaView reader with animation bar, study selection, domain colouring |
Installation
# Core (reader, compare, stats, export) — no COMSOL needed
pip install cmslh5
# With COMSOL conversion support (requires mph + COMSOL license)
pip install cmslh5[convert]
# With plotting
pip install cmslh5[plot]
# Everything
pip install cmslh5[all]
# Development
git clone https://github.com/smartgeomechanics/cmslh5.git
cd cmslh5
pip install -e ".[dev]"
Requirements
- Python ≥ 3.9
- Core:
h5py,numpy,scipy - Conversion:
mph(+ COMSOL Multiphysics installation) - Plotting:
matplotlib - VTK export:
meshio
Quick start
1. Convert a COMSOL model to HDF5
On your COMSOL server:
# Mesh, solve, and extract
cmslh5-convert model.mph --cores 8
# Extract from an already-solved model
cmslh5-convert Results_Model.mph --extract-results
# Extract only specific fields
cmslh5-convert Results_Model.mph --extract-results --fields Temperature Pressure Velocity
This produces a .cmslh5 file that you can copy anywhere.
2. Read and analyse (no COMSOL needed)
from cmslh5 import CmslH5Reader
reader = CmslH5Reader('Results_Model.cmslh5')
print(reader.summary())
Output:
File : Results_Model.cmslh5
Size : 847.3 MB
Mesh:
Nodes : 1,245,678
BBox min : [0, -0.025, 0]
BBox max : [0.5, 0.025, 0.025]
Elements : 7,123,456 (tet)
Domains : 1
1 : Fluid
Studies: 1
[0] "Time Dependent" (time-dep, T=201)
t : [0 .. 2] s
Velocity [vx, vy, vz] unit=m/s shape=(1245678, 3, 201)
Pressure [p] unit=Pa shape=(1245678, 1, 201)
Temperature [T] unit=K shape=(1245678, 1, 201)
Available components:
Pressure : p
Temperature : T
Velocity : vx, vy, vz
3. Extract data along a line
# Temperature along the pipe centreline at t=1.0s
result = reader.extract_along_line(
component='T',
time=1.0,
x_expr='s * 0.5', # x sweeps from 0 to 0.5
y_expr='0.0', # constant y
z_expr='0.0', # constant z
n_points=500,
)
z = result['coords'][:, 0] # x-coordinates
T = result['values'] # temperature values
arc = result['arc_length'] # cumulative arc length
The s parameter goes from 0 to 1. Use any math expressions:
# Circular path
x_expr='0.01 * cos(2*pi*s)'
y_expr='0.01 * sin(2*pi*s)'
z_expr='0.25'
# Non-uniform spacing
z_expr='0.5 * s**2'
4. Multiple components on the same line
result = reader.extract_components_along_line(
components=['vx', 'vy', 'vz', 'p', 'T'],
time=1.0,
x_expr='s * 0.5', y_expr='0.0', z_expr='0.0',
)
x = result['coords'][:, 0]
vx = result['data']['vx']['values']
p = result['data']['p']['values']
T = result['data']['T']['values']
5. Probe a single point
p = reader.probe_point('p', time=0.5, point=[0.25, 0.0, 0.0])
print(f'Pressure: {p["value"]:.2f} {p["unit"]}')
print(f'Nearest mesh node: {p["nearest_distance"]:.2e} m away')
6. Time history at a monitoring point
th = reader.extract_time_history('vx', point=[0.25, 0.0, 0.0])
import matplotlib.pyplot as plt
plt.plot(th['times'], th['values'])
plt.xlabel('Time [s]')
plt.ylabel(f'vx [{th["unit"]}]')
plt.show()
7. Statistical analysis
from cmslh5.stats import time_average, fft_at_point, field_statistics
# Time-averaged temperature field
avg_T, unit = time_average(reader, 'T')
# FFT of pressure at a monitoring point
fft = fft_at_point(reader, 'p', point=[0.25, 0.0, 0.0])
print(f'Dominant frequency: {fft["dominant_freq"]:.2f} Hz')
# Spatial statistics at a given time
stats = field_statistics(reader, 'T', time=1.0)
print(f'T range: [{stats["min"]:.1f}, {stats["max"]:.1f}] {stats["unit"]}')
8. Compare two simulation results
from cmslh5 import compare_files
diff = compare_files('coarse_mesh.cmslh5', 'fine_mesh.cmslh5')
print(diff['summary'])
Output:
Comparing: coarse_mesh.cmslh5 vs fine_mesh.cmslh5
Time: 2.0 s
Mesh match: False (A=312,456 nodes, B=1,245,678 nodes)
T PASS max_abs=0.1234 max_rel=0.0004 rms=nan
p PASS max_abs=12.34 max_rel=0.0012 rms=nan
vx FAIL max_abs=0.0567 max_rel=0.0234 rms=nan
Overall: DIFFERENCES FOUND
9. Export to other formats
from cmslh5.export import to_csv, to_vtk, line_to_csv
# Nodal fields to CSV
to_csv(reader, 'output.csv', components=['T', 'p'], time=1.0)
# Line extraction to CSV
result = reader.extract_along_line(component='T', time=1.0,
x_expr='s*0.5', y_expr='0', z_expr='0')
line_to_csv('centreline_T.csv', result)
# VTK for ParaView (requires meshio)
to_vtk(reader, 'output.vtk', time=1.0)
10. ParaView plugin
1. pvpython -m pip install h5py
2. ParaView → Tools → Manage Plugins → Load New → select cmslh5/paraview/plugin.py
3. Tick "Auto Load"
4. File → Open → select .cmslh5 file
Features: study selection dropdown, animation bar with all timesteps, domain colouring via DomainId cell data.
HDF5 file structure
/Model/
Nodes/
Id int32 [N_nodes]
Coordinates float32 [N_nodes, 3]
Elements/
Id, Type, NumNodes, Connectivity
DomainId, DomainName, DomainLegend/
Physical_Groups/
{dim}D_{label}/
Id, Type, NumNodes, Connectivity
/Analysis/
{idx}_{StudyLabel}/
Times float64 [T]
Velocity float32 [N, 3, T]
Pressure float32 [N, 1, T]
Temperature float32 [N, 1, T]
Displacement float32 [N, 3, T]
Stress float32 [N, 6, T]
Strain float32 [N, 6, T]
You can inspect any .cmslh5 file with standard HDF5 tools:
h5dump -H Results_Model.cmslh5 # structure
h5ls -r Results_Model.cmslh5 # recursive listing
Or in Python:
import h5py
with h5py.File('Results_Model.cmslh5', 'r') as f:
f.visititems(lambda name, obj: print(name, obj.shape if hasattr(obj, 'shape') else ''))
Available components
| Component | Field | Unit |
|---|---|---|
T |
Temperature | K |
p |
Pressure | Pa |
vx, vy, vz |
Velocity | m/s |
ux, uy, uz |
Displacement | m |
sx, sy, sz, sxy, sxz, syz |
Stress | Pa |
exx, eyy, ezz, exy, exz, eyz |
Strain | 1 |
Aliases: 'temperature' → T, 'pressure' → p, 'temp' → T.
Converter CLI reference
cmslh5-convert MODEL_FILE [OPTIONS]
positional:
MODEL_FILE Path to COMSOL .mph file
options:
-o, --output OUTPUT_FILE Output .cmslh5 path
--extract-results Skip meshing/solving; extract from solved model
--cores N CPU cores for COMSOL solver
--studies TAG [TAG ...] Restrict to specific study tags
--fields FIELD [FIELD ...] Fields to extract (e.g. Temperature Pressure)
--chunk-size N Nodes per extraction chunk (default: 200000)
--workers N Parallel worker processes (default: 1)
--comp COMP_TAG Component tag (default: comp1)
--no-start-server Connect to external COMSOL server
--host HOST COMSOL server host (default: localhost)
--port PORT COMSOL server port (default: 2036)
Performance guidelines
| Nodes | Workers | Chunk size | JVM heap | Approx. speedup |
|---|---|---|---|---|
| < 200k | 1 | 200,000 | 16 GB | baseline |
| 200k–1M | 1–2 | 200,000 | 32 GB | 1–1.5× |
| 1M–5M | 2–4 | 250,000–500,000 | 24 GB per worker | 2–3× |
| > 5M | 4–8 | 500,000 | 16–24 GB per worker | 3–6× |
The --workers flag splits the node range across independent COMSOL processes. Each worker needs its own JVM heap and COMSOL license token. The master process handles mesh/element writing and merges the worker outputs.
# Typical large-model invocation
export _JAVA_OPTIONS='-Xmx24G'
cmslh5-convert Results_LargeModel.mph \
--extract-results \
--workers 4 \
--chunk-size 500000 \
--fields Velocity Pressure Temperature
Package structure
cmslh5/
├── __init__.py # public API
├── reader.py # CmslH5Reader class
├── convert.py # .mph → .cmslh5 (requires mph); includes parallel worker mode
├── compare.py # diff two files
├── stats.py # time_average, fft_at_point, etc.
├── export.py # to_csv, to_vtk
├── _fields.py # field configs, component map (single source of truth)
├── _interp.py # IDW + temporal interpolation
├── _expr.py # parametric expression evaluator
├── cli/
│ └── convert_cli.py # cmslh5-convert entry point
└── paraview/
└── plugin.py # ParaView Python plugin
Contributing
Contributions are welcome. Please open an issue first to discuss what you'd like to change.
git clone https://github.com/smartgeomechanics/cmslh5.git
cd cmslh5
pip install -e ".[dev]"
pytest
License
Citation
If you use cmslh5 in your research, please cite:
@software{cmslh5,
author = {Sinha, S. K.},
title = {cmslh5: Read, write, and analyse COMSOL simulation results in HDF5},
url = {https://github.com/smartgeomechanics/cmslh5},
year = {2025},
}
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cmslh5-0.1.4.tar.gz.
File metadata
- Download URL: cmslh5-0.1.4.tar.gz
- Upload date:
- Size: 53.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
26437ddd3f4fe8651734afa85dc562df4a89ceac0eb95ba5f2d84a41cccf929e
|
|
| MD5 |
f54617211b71286c56466bdecfa4f3ad
|
|
| BLAKE2b-256 |
03af5a7b184ce00d362146f808fb063f7ec433459ebc7b4745ef6d476bf13eaa
|
Provenance
The following attestation bundles were made for cmslh5-0.1.4.tar.gz:
Publisher:
workflow.yaml on smartgeotechnics/cmslh5
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cmslh5-0.1.4.tar.gz -
Subject digest:
26437ddd3f4fe8651734afa85dc562df4a89ceac0eb95ba5f2d84a41cccf929e - Sigstore transparency entry: 1231274989
- Sigstore integration time:
-
Permalink:
smartgeotechnics/cmslh5@72999e42edc37bdb5a37ffc1b57a343dc775c9ca -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/smartgeotechnics
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yaml@72999e42edc37bdb5a37ffc1b57a343dc775c9ca -
Trigger Event:
push
-
Statement type:
File details
Details for the file cmslh5-0.1.4-py3-none-any.whl.
File metadata
- Download URL: cmslh5-0.1.4-py3-none-any.whl
- Upload date:
- Size: 41.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d95bbe515e0e6413337fca65305907e661fac7b6823dd8c315587ea4b1881564
|
|
| MD5 |
b7a6f1a4c512e8989fbcfb0dc1cf7805
|
|
| BLAKE2b-256 |
f76074f13dcad84f1190b6b6366cd02ed5f24e41d6cb6d68889e6d8cb57289e4
|
Provenance
The following attestation bundles were made for cmslh5-0.1.4-py3-none-any.whl:
Publisher:
workflow.yaml on smartgeotechnics/cmslh5
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cmslh5-0.1.4-py3-none-any.whl -
Subject digest:
d95bbe515e0e6413337fca65305907e661fac7b6823dd8c315587ea4b1881564 - Sigstore transparency entry: 1231274993
- Sigstore integration time:
-
Permalink:
smartgeotechnics/cmslh5@72999e42edc37bdb5a37ffc1b57a343dc775c9ca -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/smartgeotechnics
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yaml@72999e42edc37bdb5a37ffc1b57a343dc775c9ca -
Trigger Event:
push
-
Statement type: