kups.core.potential
¶
Potential energy calculations with gradients and Hessians.
This module provides the infrastructure for computing potential energies and their derivatives in molecular simulations. Potentials are composable and can be cached for efficient evaluation.
Key components: - PotentialOut: Container for energy, gradients, and Hessians - Potential: Protocol for energy computation with optional state patches - SummedPotential: Compose multiple potentials by summation - CachedPotential: Cache potential outputs - ScaledPotential: Scale a potential by a constant factor
Potentials support linearity: energies, gradients, and Hessians can be summed, enabling modular force field composition (e.g., bonded + non-bonded + Coulomb).
EMPTY = EmptyType()
module-attribute
¶
Singleton instance of EmptyType.
Use this instead of constructing EmptyType() directly.
EMPTY_LENS = const_lens(EMPTY)
module-attribute
¶
Lens that always returns EMPTY, ignoring input. Set is a no-op.
This is useful for potentials that don't compute gradients or Hessians.
Energy = Array
¶
Type alias for energy arrays, typically shape (n_systems,).
CachedPotential
¶
Bases: Potential[State, Gradients, Hessians, StatePatch]
Wrap a potential with caching for efficient incremental updates.
Caches the potential output in the state and updates it via patches. Crucial for Monte Carlo simulations where only small perturbations are made and you want to avoid recomputing the entire potential.
Attributes:
| Name | Type | Description |
|---|---|---|
potential |
Potential[State, Gradients, Hessians, StatePatch]
|
Base potential to wrap |
cache |
Lens[State, PotentialOut[Gradients, Hessians]]
|
Lens to the cache location in state |
patch_idx_view |
View[State, PotentialOut[Gradients, Hessians]] | None
|
Maps acceptance mask indices to cached structure.
If |
The patch_idx_view provides the indexing structure matching the potential output, used to selectively update cached values based on acceptance masks.
Example
# Cache LJ potential for MC simulation
cached_lj = CachedPotential(
potential=lj_potential,
cache=lens(lambda s: s.lj_cache),
patch_idx_view=lambda s: s.particle_indices
)
# First call computes and caches
result = cached_lj(state, patch=None)
state = result.patch(state, accept_mask)
# The previous value can be easily accessed
result = cached_lj.cached_value(state)
Source code in src/kups/core/potential.py
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | |
__call__(state, patch=None)
¶
Evaluate potential and update cache.
Computes the base potential, then creates a patch that will update the cached value when applied with an acceptance mask. The cache update uses the patch_idx_view to determine which cached entries to modify.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
State
|
Current simulation state |
required |
patch
|
StatePatch | None
|
Optional state patch for incremental updates |
None
|
Returns:
| Type | Description |
|---|---|
WithPatch[PotentialOut[Gradients, Hessians], Patch[State]]
|
Potential output with cache update patch composed |
Source code in src/kups/core/potential.py
cached_value(state)
¶
Retrieve the cached potential output from state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
State
|
Simulation state containing cached values |
required |
Returns:
| Type | Description |
|---|---|
PotentialOut[Gradients, Hessians]
|
Previously computed and cached potential output |
Source code in src/kups/core/potential.py
EmptyType
¶
Sentinel type indicating empty gradients or Hessians.
Use this when a potential does not compute gradients or Hessians, rather than None, to maintain type safety.
MappedPotential
¶
Bases: Potential[State, OutGrad, OutHess, StatePatch]
Wrap a potential and transform its gradient and hessian outputs.
Applies mapping functions to gradients and hessians returned by the inner potential, enabling projection (e.g., extracting position gradients from a combined position+lattice gradient structure).
Attributes:
| Name | Type | Description |
|---|---|---|
potential |
Potential[State, InGrad, InHess, StatePatch]
|
Base potential to wrap |
gradient_map |
View[InGrad, OutGrad]
|
Function to transform gradients from InGrad to OutGrad |
hessian_map |
View[InHess, OutHess]
|
Function to transform hessians from InHess to OutHess |
Example
# Extract position gradients from VirialTheoremGradients
position_potential = MappedPotential(
potential=full_potential, # Returns VirialTheoremGradients
gradient_map=lambda g: g.positions,
hessian_map=lambda h: h, # Pass through hessians unchanged
)
result = position_potential(state)
# result.data.gradients is now just the position array
Source code in src/kups/core/potential.py
Potential
¶
Bases: Protocol
Protocol for potential energy functions.
A potential computes energy, gradients, and optionally Hessians for a given simulation state. Potentials can optionally accept a state patch describing recent changes, enabling efficient incremental updates.
Class Type Parameters:
| Name | Bound or Constraints | Description | Default |
|---|---|---|---|
State
|
Simulation state type |
required | |
Gradients
|
Structure of first derivatives |
required | |
Hessians
|
Structure of second derivatives (subset of gradients) |
required | |
StatePatch
|
Patch
|
Type of state modification patches |
required |
The patch argument enables incremental computation:
- Monte Carlo: Only recompute for moved particles
- Molecular dynamics: Reuse neighbor lists
- General: Avoid redundant calculations
Example
class LennardJonesPotential:
def __call__(self, state, patch=None):
# Compute LJ energy and forces
energy = compute_lj_energy(state.positions)
forces = compute_lj_forces(state.positions)
return WithPatch(
PotentialOut(energy, {"positions": forces}, EMPTY),
IdPatch() # No state caching needed
)
# Use in simulation
potential = LennardJonesPotential()
result = potential(state)
energy = result.data.total_energies
forces = result.data.gradients.positions
Source code in src/kups/core/potential.py
__call__(state, patch=None)
¶
Compute potential energy and derivatives.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
State
|
Current simulation state |
required |
patch
|
StatePatch | None
|
Optional state patch for incremental updates |
None
|
Returns:
| Type | Description |
|---|---|
WithPatch[PotentialOut[Gradients, Hessians], Patch[State]]
|
Potential output and state patch |
Source code in src/kups/core/potential.py
PotentialAsPropagator
¶
Bases: Propagator[State]
Adapt a potential to the Propagator interface.
Converts a potential into a propagator that computes energies and applies the resulting patch to the state. Useful for integrating potential evaluations into propagator pipelines.
Attributes:
| Name | Type | Description |
|---|---|---|
potential |
Potential[State, Gradients, Hessians, StatePatch]
|
Potential to wrap as a propagator |
Note
The propagator accepts all patches (acceptance mask all True). This is typically used for energy/force evaluations rather than Monte Carlo moves.
Example
Source code in src/kups/core/potential.py
__call__(key, state)
¶
Evaluate potential and apply patch to state.
Computes the potential energy and applies the resulting patch with all acceptance flags set to True (all updates accepted). Ignores the random key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
Array
|
JAX PRNG key (unused) |
required |
state
|
State
|
Current simulation state |
required |
Returns:
| Type | Description |
|---|---|
State
|
Updated state after applying potential patch |
Source code in src/kups/core/potential.py
PotentialOut
¶
Output of a potential energy calculation.
Contains the total energy per system, gradients with respect to specified tensors (e.g., positions, charges), and optionally Hessians (second derivatives).
Assumes linearity: energies, gradients, and Hessians can be summed, enabling composition of multiple potentials via SummedPotential (e.g., U_total = U_bonded + U_vdw + U_elec).
Class Type Parameters:
| Name | Bound or Constraints | Description | Default |
|---|---|---|---|
Gradients
|
PyTree structure containing first derivatives |
required | |
Hessians
|
PyTree structure containing second derivatives (subset of gradients) |
required |
Attributes:
| Name | Type | Description |
|---|---|---|
total_energies |
Table[SystemId, Energy]
|
Total energy per system as a |
gradients |
Gradients
|
First derivatives (e.g., forces = -∇U) |
hessians |
Hessians
|
Second derivatives (e.g., for normal mode analysis) |
Example
# Simple potential output with position gradients only
out = PotentialOut(
total_energies=jnp.array([10.5, 12.3]), # 2 systems
gradients={"positions": force_array}, # Forces on particles
hessians=EMPTY # No Hessians computed
)
# Combine potentials
total = lj_out + coulomb_out # Element-wise addition
Source code in src/kups/core/potential.py
ScaledPotential
¶
Bases: Potential[State, Gradients, Hessians, StatePatch]
Scale a potential's output by a constant factor.
Multiplies energies, gradients, and Hessians by a scalar. Useful for thermodynamic integration, replica exchange, or applying coupling parameters.
Attributes:
| Name | Type | Description |
|---|---|---|
potential |
Potential[State, Gradients, Hessians, StatePatch]
|
Base potential to scale |
scale |
float
|
Multiplicative factor (lambda in thermodynamic integration) |
Example
Source code in src/kups/core/potential.py
__call__(state, patch=None)
¶
Evaluate potential and scale the output.
Computes the base potential then multiplies energies, gradients, and Hessians by the scale factor. The patch is passed through unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
State
|
Current simulation state |
required |
patch
|
StatePatch | None
|
Optional state patch for incremental updates |
None
|
Returns:
| Type | Description |
|---|---|
WithPatch[PotentialOut[Gradients, Hessians], Patch[State]]
|
Scaled potential output with original patch |
Source code in src/kups/core/potential.py
SummedPotential
¶
Bases: Potential[State, Gradients, Hessians, StatePatch]
Compose multiple potentials by summing their outputs.
Enables modular force field composition where total energy is the sum of individual contributions (e.g., bonded + Lennard-Jones + Coulomb).
Class Type Parameters:
| Name | Bound or Constraints | Description | Default |
|---|---|---|---|
State
|
Simulation state type |
required | |
Gradients
|
Gradient structure type |
required | |
Hessians
|
Hessian structure type |
required | |
StatePatch
|
Patch
|
State patch type |
required |
Attributes:
| Name | Type | Description |
|---|---|---|
potentials |
tuple[Potential[State, Gradients, Hessians, StatePatch], ...]
|
Tuple of potentials to sum (must have at least one) |
Example
Source code in src/kups/core/potential.py
__call__(state, patch=None)
¶
Evaluate all potentials and sum their outputs.
Calls each potential in sequence with the same state and patch, then sums the resulting energies, gradients, and Hessians element-wise. Patches are composed in order.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
state
|
State
|
Current simulation state |
required |
patch
|
StatePatch | None
|
Optional state patch for incremental updates |
None
|
Returns:
| Type | Description |
|---|---|
WithPatch[PotentialOut[Gradients, Hessians], Patch[State]]
|
Combined potential output with composed patches |
Source code in src/kups/core/potential.py
empty_patch_idx_view(state)
¶
Default patch index view covering all systems with no gradient/Hessian outputs.
Source code in src/kups/core/potential.py
sum_potentials(*potentials)
¶
Compose multiple potentials by summing their outputs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
potentials
|
Potential[State, Gradients, Hessians, StatePatch]
|
Potentials to sum. |
()
|
Returns:
| Type | Description |
|---|---|
Potential[State, Gradients, Hessians, StatePatch]
|
A single potential producing the summed output. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If no potentials are provided. |