Skip to main content

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

MIT


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

cmslh5-0.1.3.tar.gz (31.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cmslh5-0.1.3-py3-none-any.whl (19.4 kB view details)

Uploaded Python 3

File details

Details for the file cmslh5-0.1.3.tar.gz.

File metadata

  • Download URL: cmslh5-0.1.3.tar.gz
  • Upload date:
  • Size: 31.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for cmslh5-0.1.3.tar.gz
Algorithm Hash digest
SHA256 c3f0422a5f3dcde8778f1d83c81814487a75f752d9d8c4c52e8e0592870ea3b3
MD5 910c60888a0a08175cf16747bcb7974f
BLAKE2b-256 a3cf98a8c3a40fbdb0d8b9a57e5adda68d0858883f2038f8603e65ec18464e1e

See more details on using hashes here.

Provenance

The following attestation bundles were made for cmslh5-0.1.3.tar.gz:

Publisher: workflow.yaml on smartgeotechnics/cmslh5

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cmslh5-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: cmslh5-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 19.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for cmslh5-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 5d379057690c597893b91cd8ec2fa9c6e0506d8dc273a328b409ca87638c7b55
MD5 022b020f8e59877242b9b92d548e7df2
BLAKE2b-256 5bec6468214d342fc1e481602e592e71fafc8ab2b0f1e54ea621e94bb14a7d05

See more details on using hashes here.

Provenance

The following attestation bundles were made for cmslh5-0.1.3-py3-none-any.whl:

Publisher: workflow.yaml on smartgeotechnics/cmslh5

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page