The Python package phsi-models (imported as phsi) learns port-Hamiltonian models from observed trajectories. Either analytic functions or neural networks can be fitted to represent the Hamiltonian function
The package supports fully observed canonical coordinates, diagonal damping and one external input. The models can be fitted with gradient-based optimization using either an integration-scheme loss or a simulation-error loss, or, for fully analytic models, sparse regression using estimated derivatives or midpoint observations.
phsi-models requires Python 3.11 or newer. Install the alpha preview with pip:
python -m pip install 'phsi-models==1.0.0a1'In your own uv project, add the package once, then run your script:
uv add 'phsi-models==1.0.0a1'
uv run your_script.pyIn a cloned PHSI repository, run from the repository root; uv installs the local package and its dependencies automatically:
uv run your_script.pyTo open the notebooks with their optional dependencies, use uv run --extra examples jupyter lab. With pip, install an editable checkout using python -m pip install -e '.[examples]'.
This alpha precedes the paper release; the interface may still change.
import phsi
model = phsi.model(
hamiltonian="analytic",
damping="constant",
forcing_gain="analytic",
forced_state=1, # the external input acts on the momentum equation
gain_state=0, # its gain depends on position
)This example uses states ordered as (position, momentum) and learns polynomial energy and forcing gain. Use "nn" for a neural network model instead of an analytic expression. For analytic damping, use phsi.DampingLibrary(kind="polynomial") or phsi.DampingLibrary(kind="gaussian"). See the method notes for component choices and fitting options.
model.fit(X, t=t, u=u, method="integration_scheme")Rows of X are observed states, t contains equally spaced observation times, and u is the applied force or voltage at those times. Lists of trajectories are also accepted. The method options are "integration_scheme", "simulation_error", "derivative" and "midpoint"; the latter two require fully analytic models. Unless separate validation data are supplied, the final 20% of each trajectory is reserved for validation.
model.print()
prediction = model.simulate(x0, t=t_new, u=u_new)
model.save("model.phsi")
restored = phsi.load("model.phsi")Printing shows the fitted equations, with analytic coefficients and neural network functions. Simulation starts from x0 with the new external input u_new.
This is a deliberately narrow implementation. The agent guide helps users and coding agents extend it, for example by adding more candidate functions for the analytic models, editing the neural network architectures, or testing the methods on different data. See AGENTS.md for the code map, extension points and checks to run.
This package accompanies the manuscript Comparing model representations and fitting methods for port-Hamiltonian system identification, by Sølve Eidnes and Håkon Noren Myhr (in preparation).
The package builds on the following code and publications, with adaptations described in the attribution notes:
- Holmsen, Eidnes and Riemer-Sørensen: Pseudo-Hamiltonian system identification (code).
- Eidnes and coauthors: Pseudo-Hamiltonian neural networks with state-dependent external forces (code).
- Meltzer, Eidnes and Stasik: Learning partially observed systems with neural Hamiltonian ordinary differential equations (code).
- Myhr, Eidnes and Kutz: SIPHy: Sparse identification of port-Hamiltonian systems from noisy data (code not yet public).
Licensed under the MIT license.