Skip to content

kups.application.md.analysis

Post-simulation analysis for molecular dynamics.

IsMDInitData

Bases: Protocol

Contract for the init reader group.

Source code in src/kups/application/md/analysis.py
class IsMDInitData(Protocol):
    """Contract for the init reader group."""

    @property
    def atoms(self) -> Table[ParticleId, _IsMDInitAtoms]: ...

IsMDStepData

Bases: HasPotentialEnergy, HasStressTensor, Protocol

Contract for the step reader group.

Source code in src/kups/application/md/analysis.py
class IsMDStepData(HasPotentialEnergy, HasStressTensor, Protocol):
    """Contract for the step reader group."""

    @property
    def kinetic_energy(self) -> Array: ...

    @property
    def internal_kinetic_energy(self) -> Array: ...

    @property
    def volume(self) -> Array: ...

MDAnalysisResult dataclass

Results from MD simulation analysis for a single system.

Attributes:

Name Type Description
potential_energy BlockAverageResult

Average potential energy with SEM (eV).

kinetic_energy BlockAverageResult

Average kinetic energy with SEM (eV).

total_energy BlockAverageResult

Average total energy with SEM (eV).

temperature BlockAverageResult

Average temperature with SEM (K).

energy_drift float

Linear drift rate of total energy (eV/step).

energy_drift_per_atom float

Energy drift normalized by number of atoms.

pressure BlockAverageResult

Average pressure with SEM (Pa).

volume BlockAverageResult

Average cell volume with SEM (A^3).

n_atoms int

Number of atoms in this system.

n_steps int

Number of simulation steps analyzed.

Source code in src/kups/application/md/analysis.py
@plain_dataclass
class MDAnalysisResult:
    """Results from MD simulation analysis for a single system.

    Attributes:
        potential_energy: Average potential energy with SEM (eV).
        kinetic_energy: Average kinetic energy with SEM (eV).
        total_energy: Average total energy with SEM (eV).
        temperature: Average temperature with SEM (K).
        energy_drift: Linear drift rate of total energy (eV/step).
        energy_drift_per_atom: Energy drift normalized by number of atoms.
        pressure: Average pressure with SEM (Pa).
        volume: Average cell volume with SEM (A^3).
        n_atoms: Number of atoms in this system.
        n_steps: Number of simulation steps analyzed.
    """

    potential_energy: BlockAverageResult
    kinetic_energy: BlockAverageResult
    total_energy: BlockAverageResult
    temperature: BlockAverageResult
    energy_drift: float
    energy_drift_per_atom: float
    pressure: BlockAverageResult
    volume: BlockAverageResult
    n_atoms: int
    n_steps: int

analyze_md(init_data, step_data, n_blocks=None)

Analyze MD simulation from pre-loaded data.

Computes thermodynamic averages and energy conservation metrics independently for each system.

Parameters:

Name Type Description Default
init_data IsMDInitData

Initial simulation state providing the per-atom system index.

required
step_data IsMDStepData

Per-step thermodynamic data with shape (n_steps, n_systems).

required
n_blocks int | None

Number of blocks for error estimation. None auto-selects via optimal_block_average.

None

Returns:

Type Description
dict[SystemId, MDAnalysisResult]

Per-system analysis results keyed by SystemId.

Source code in src/kups/application/md/analysis.py
def analyze_md(
    init_data: IsMDInitData,
    step_data: IsMDStepData,
    n_blocks: int | None = None,
) -> dict[SystemId, MDAnalysisResult]:
    """Analyze MD simulation from pre-loaded data.

    Computes thermodynamic averages and energy conservation metrics
    independently for each system.

    Args:
        init_data: Initial simulation state providing the per-atom system index.
        step_data: Per-step thermodynamic data with shape ``(n_steps, n_systems)``.
        n_blocks: Number of blocks for error estimation. ``None`` auto-selects via
            ``optimal_block_average``.

    Returns:
        Per-system analysis results keyed by ``SystemId``.
    """
    return _analyze_md_systems(
        init_data.atoms.data.system,
        step_data.potential_energy,
        step_data.kinetic_energy,
        step_data.internal_kinetic_energy,
        step_data.stress_tensor,
        step_data.volume,
        n_blocks,
    )

analyze_md_file(hdf5_path, n_blocks=None)

Analyze MD simulation results from an HDF5 file.

Reads only the per-step thermodynamic scalars (energies, stress, volume) and the initial system index, leaving the per-atom trajectory on disk. Internal kinetic energy is logged per step, so no momenta are read here.

Parameters:

Name Type Description Default
hdf5_path str | Path

Path to HDF5 file from MD simulation.

required
n_blocks int | None

Number of blocks for error estimation. None auto-selects via optimal_block_average.

None

Returns:

Type Description
dict[SystemId, MDAnalysisResult]

Per-system analysis results keyed by SystemId.

Source code in src/kups/application/md/analysis.py
def analyze_md_file(
    hdf5_path: str | Path,
    n_blocks: int | None = None,
) -> dict[SystemId, MDAnalysisResult]:
    """Analyze MD simulation results from an HDF5 file.

    Reads only the per-step thermodynamic scalars (energies, stress, volume) and
    the initial system index, leaving the per-atom trajectory on disk. Internal
    kinetic energy is logged per step, so no momenta are read here.

    Args:
        hdf5_path: Path to HDF5 file from MD simulation.
        n_blocks: Number of blocks for error estimation. ``None`` auto-selects via
            ``optimal_block_average``.

    Returns:
        Per-system analysis results keyed by ``SystemId``.
    """
    with HDF5StorageReader[MDLoggedData](hdf5_path) as reader:
        system = reader.focus_group(lambda s: s.init).read(
            select=lambda d: d.atoms.data.system
        )
        potential_energy, kinetic_energy, internal_kinetic_energy, stress, volume = (
            reader.focus_group(lambda s: s.step).read(
                select=lambda d: (
                    d.potential_energy,
                    d.kinetic_energy,
                    d.internal_kinetic_energy,
                    d.stress_tensor,
                    d.volume,
                )
            )
        )
    return _analyze_md_systems(
        system,
        potential_energy,
        kinetic_energy,
        internal_kinetic_energy,
        stress,
        volume,
        n_blocks,
    )