ModalDyn
Turn time-ordered snapshots into interpretable modes and short-horizon forecasts.
ModalDyn is a compact Dynamic Mode Decomposition (DMD) toolkit for researchers and engineers who want to understand evolving systems, not just fit a black box. Start with NumPy, inspect the model's diagnostics, and use the same estimator API with optional PyTorch CPU or CUDA execution.
PyPI · API guide · Examples · Limitations
Why ModalDyn?
- A small starting point. The basic installation needs only NumPy; PyTorch is optional.
- A model you can inspect. Examine eigenvalues, modes, numerical rank, conditioning and fitted one-step error instead of relying on a forecast alone.
- Several workflows, one package. Reconstruct snapshots, forecast dynamics, include measured controls, or add delay coordinates for partial observations.
- Explicit computation. Choose the backend and device. A request for unavailable CUDA fails clearly rather than silently falling back to CPU.
Where it fits
These are application ideas, not claims of validation on production datasets:
| Your data | A useful starting question |
|---|---|
| Time-ordered fluid or simulation fields | Which coherent patterns evolve together, and at which rates? |
| Vibration or multi-sensor recordings | Can a low-dimensional model describe oscillations and forecast a held-out interval? |
| Measurements from an actuated experiment | How do the observed states respond to known control inputs? |
DMD approximates dynamics with a linear evolution model. It is especially useful when a few modes explain the behavior over the time window you care about. Choose rank and other settings on training/validation data, then test a future interval that the model has never seen.
Install
Python 3.10+ and NumPy 1.24+ are required.
python -m pip install modaldyn
Optional PyTorch support:
python -m pip install 'modaldyn[torch]'
For a specific CPU or CUDA build, follow the official PyTorch installation guide. The extra does not install a GPU driver or guarantee CUDA availability.
Quickstart: forecast a held-out oscillation
Each column is a snapshot and each row is a feature. In this reproducible synthetic example, two sensor channels follow a damped oscillation. The first 80 snapshots train the model; the last 20 are used only for evaluation.
import numpy as np
from modaldyn import DMD
angle = 0.16
operator = 0.995 * np.array([
[np.cos(angle), -np.sin(angle)],
[np.sin(angle), np.cos(angle)],
])
snapshots = np.empty((2, 100)) # 2 channels, 100 equally spaced observations
snapshots[:, 0] = [1.0, 0.2]
for k in range(99):
snapshots[:, k + 1] = operator @ snapshots[:, k]
model = DMD(rank=2, dt=0.1).fit(snapshots[:, :80])
reconstruction = model.reconstruct() # shape (2, 80), includes the first snapshot
forecast = model.forecast(20) # shape (2, 20), starts AFTER the last training point
truth = snapshots[:, 80:]
relative_error = np.linalg.norm(forecast - truth) / np.linalg.norm(truth)
print("Reconstruction:", reconstruction.shape)
print("Forecast:", forecast.shape)
print("Held-out relative error:", f"{relative_error:.2e}")
print("Retained rank:", model.diagnostics()["rank"])
assert relative_error < 1e-10 # check for this noiseless linear example only
The output shapes are (2, 80) and (2, 20), with retained rank 2.
The error is near numerical precision because the example follows an exact
linear model. This is a reproducibility check, not a real-world accuracy claim.
For measured data, compare against a simple baseline and evaluate multiple
held-out windows. Complex-valued modes and forecasts are normal for oscillations;
only discard the imaginary part when its residual is negligible.
Example: forecast a system with known controls
Suppose an experiment records two state variables and one actuator input.
DMDc fits the relationship x[k+1] = A @ x[k] + B @ u[k].
This synthetic example shows the required alignment: 81 state snapshots pair
with 80 control inputs, one input for each transition.
import numpy as np
from modaldyn import DMDc
rng = np.random.default_rng(12)
A = np.array([[0.93, 0.08], [-0.05, 0.97]])
B = np.array([[0.15], [0.40]])
controls = rng.standard_normal((1, 120))
states = np.empty((2, 121))
states[:, 0] = [0.4, -0.2]
for k in range(120):
states[:, k + 1] = A @ states[:, k] + B @ controls[:, k]
model = DMDc().fit(states[:, :81], controls[:, :80])
forecast = model.forecast(controls[:, 80:]) # 40 supplied FUTURE control inputs
truth = states[:, 81:]
relative_error = np.linalg.norm(forecast - truth) / np.linalg.norm(truth)
print("Controlled forecast:", forecast.shape) # (2, 40)
print("Held-out relative error:", f"{relative_error:.2e}")
assert forecast.shape == truth.shape
assert relative_error < 1e-10
The future controls are inputs you provide, not values predicted by the model. Reliable identification needs sufficiently informative state/control data. This noiseless example verifies the API and alignment; it does not establish performance on a physical experiment.
Pick the right estimator
| Estimator | Use it when | Keep in mind |
|---|---|---|
DMD |
You want an exact-DMD baseline | Uniform time spacing and a useful low-rank linear approximation |
TLSqDMD / FbDMD |
You are exploring noise-aware formulations | Tune TLS rank; forward/backward DMD has experimental spectral-root limits |
RandomizedDMD |
You want a seeded low-rank approximation | Specify an integer rank; measure the accuracy/cost trade-off |
HankelDMD |
Delay coordinates may expose hidden dynamics | More memory; choose delays without leaking test data |
DMDc |
Measured controls influence the evolution | Align each control with its state transition |
RobustDMD |
Sparse corruptions motivate RPCA preprocessing | Assumes low-rank structure plus sparse corruption; iterative dense SVDs |
StreamingDMD |
You cannot retain the full snapshot history | Dense sufficient statistics still need O(features²) memory |
See the API guide for parameters, alignment rules and variant-specific diagnostics.
CPU, PyTorch and CUDA
The examples above use NumPy on CPU. For the PyTorch backend, use
backend="torch", device="cpu" in the estimator; device="cuda" requests CUDA
explicitly. Forecasts use the selected backend. backend="auto" follows an
input tensor's backend/device; NumPy input defaults to NumPy unless CUDA is
explicitly requested.
Validation: CI exercises NumPy on Python 3.10–3.13 and PyTorch on CPU. CUDA code and optional tests are included, but GPU hardware correctness and performance have not been established for this release. Skipped CUDA tests are not GPU validation. Small problems may be faster on CPU because transfers and synchronization have a cost.
Scope and trade-offs
This is an alpha research package, not a universal forecasting solution. A small training residual does not guarantee useful future predictions. Nonstationarity, noise, rank choice and insufficient measurements can all change results. Read the limitations before interpreting a model.
ModalDyn favors a compact NumPy-first API and explicit diagnostics/device choice. PyDMD offers a broader variant catalogue; GPU-enabled DMD also exists elsewhere. There is no claim of universal speed or accuracy superiority. The source-backed comparison covers PyDMD, PyKoopman, datafold and flowTorch. Optimized/bagged DMD, EDMD, multiresolution DMD and sparsity-promoting DMD are outside this release.
Learn more and contribute
- API reference
- Runnable examples
- Validation notes
- Reproducible benchmarking
- Report an issue
- Release guide
Original implementation by Giovanny Torres, released under the MIT license. Please cite the relevant algorithm papers listed in the comparison and references when using these methods in research.
Metadata
Release files for modaldyn 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| modaldyn-0.1.2.tar.gz | 47.9 kB | With provenance | Details for modaldyn-0.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| modaldyn-0.1.2-py3-none-any.whl | Python 3 | none | any | Details for modaldyn-0.1.2-py3-none-any.whl |
Total release size: 68.8 kB
Release files / modaldyn-0.1.2.tar.gz
| Download URL | modaldyn-0.1.2.tar.gz |
|---|---|
| Size | 47.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c0a2b3998f9b5d909199d3e875fd5f1fc8db66b8d1f614e132e7ddc7b241a713
|
|
BLAKE2b-256 checksum How to use checksums |
458173db8c50665fad5b6a7d5fc050faa552bfc6fd0d51388cd297c9d51ec11f
|
| 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 Oct 31, 2026.
Transparency logRelease files / modaldyn-0.1.2-py3-none-any.whl
| Download URL | modaldyn-0.1.2-py3-none-any.whl |
|---|---|
| Size | 20.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
268ebf572b39d5484c4d048a96e4b22e9a6e776fb8044c135c904e62ffcc9035
|
|
BLAKE2b-256 checksum How to use checksums |
1453ce7047e9669381b3cf2745766a103c7cbc6cc486ceedf4a1eb279594913c
|
| 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 Oct 31, 2026.
Transparency logSecurity for modaldyn 0.1.2
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.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for modaldyn-0.1.2.tar.gz
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 Oct 31, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.