Skip to content

kups.application.mcmc.analysis

Post-simulation analysis for MCMC simulations.

IsMCMCFixedData

Bases: Protocol

Contract for data from the fixed reader group.

Source code in src/kups/application/mcmc/analysis.py
class IsMCMCFixedData(Protocol):
    """Contract for data from the fixed reader group."""

    @property
    def systems(self) -> Table[SystemId, HasTemperature]: ...

IsMCMCStepData

Bases: Protocol

Contract for data from the per_step reader group.

Source code in src/kups/application/mcmc/analysis.py
class IsMCMCStepData(Protocol):
    """Contract for data from the per_step reader group."""

    @property
    def particle_count(self) -> Table[tuple[SystemId, MotifId], Array]: ...
    @property
    def systems(self) -> Table[SystemId, IsMCMCSystemStepData]: ...

IsMCMCSystemStepData

Bases: Protocol

Contract for per-system step data.

Source code in src/kups/application/mcmc/analysis.py
class IsMCMCSystemStepData(Protocol):
    """Contract for per-system step data."""

    @property
    def potential_energy(self) -> Array: ...
    @property
    def guest_stress(self) -> StressResult: ...

MCMCAnalysisResult dataclass

Results from MCMC simulation analysis for a single system.

Attributes:

Name Type Description
energy BlockAverageResult

Average total potential energy with SEM (eV).

loading BlockAverageResult

Average particle count per species with SEM (dimensionless).

heat_of_adsorption BlockAverageResult

Per-species heat of adsorption with SEM (eV).

total_heat_of_adsorption BlockAverageResult

Composition-weighted total heat of adsorption (eV).

Source code in src/kups/application/mcmc/analysis.py
@plain_dataclass
class MCMCAnalysisResult:
    """Results from MCMC simulation analysis for a single system.

    Attributes:
        energy: Average total potential energy with SEM (eV).
        loading: Average particle count per species with SEM (dimensionless).
        heat_of_adsorption: Per-species heat of adsorption with SEM (eV).
        total_heat_of_adsorption: Composition-weighted total heat of adsorption (eV).
    """

    energy: BlockAverageResult
    loading: BlockAverageResult
    heat_of_adsorption: BlockAverageResult
    total_heat_of_adsorption: BlockAverageResult
    stress: BlockAverageResult | None = None
    stress_potential: BlockAverageResult | None = None
    stress_tail_correction: BlockAverageResult | None = None
    stress_ideal_gas: BlockAverageResult | None = None
    pressure: BlockAverageResult | None = None
    pressure_potential: BlockAverageResult | None = None
    pressure_tail_correction: BlockAverageResult | None = None
    pressure_ideal_gas: BlockAverageResult | None = None

analyze_mcmc(fixed, per_step, n_blocks=None)

Analyze MCMC simulation results from pre-loaded data.

Computes energy, loading (average particle counts), and heat of adsorption per species using block averaging for error estimation. Analysis is performed independently for each system.

Parameters:

Name Type Description Default
fixed IsMCMCFixedData

Fixed (one-shot) logged data containing system metadata.

required
per_step IsMCMCStepData

Per-step logged data containing energies and particle counts.

required
n_blocks int | None

Number of blocks for error estimation. None uses :func:~kups.core.utils.block_average.optimal_block_average.

None

Returns:

Type Description
dict[SystemId, MCMCAnalysisResult]

Per-system analysis results keyed by SystemId.

Source code in src/kups/application/mcmc/analysis.py
@no_jax_tracing
def analyze_mcmc(
    fixed: IsMCMCFixedData,
    per_step: IsMCMCStepData,
    n_blocks: int | None = None,
) -> dict[SystemId, MCMCAnalysisResult]:
    """Analyze MCMC simulation results from pre-loaded data.

    Computes energy, loading (average particle counts), and heat of adsorption
    per species using block averaging for error estimation. Analysis is
    performed independently for each system.

    Args:
        fixed: Fixed (one-shot) logged data containing system metadata.
        per_step: Per-step logged data containing energies and particle counts.
        n_blocks: Number of blocks for error estimation. ``None`` uses
            :func:`~kups.core.utils.block_average.optimal_block_average`.

    Returns:
        Per-system analysis results keyed by ``SystemId``.
    """
    system_keys = fixed.systems.keys
    count_keys = per_step.particle_count.keys
    count_data = per_step.particle_count.data
    temperatures = fixed.systems.data.temperature
    all_energy = per_step.systems.data.potential_energy
    guest_stress = per_step.systems.data.guest_stress
    stress_potential = guest_stress.potential
    stress_tail = guest_stress.tail_correction
    stress_ideal = guest_stress.ideal_gas
    all_stress = stress_potential + stress_tail + stress_ideal

    results: dict[SystemId, MCMCAnalysisResult] = {}
    for i, sys_id in enumerate(system_keys):
        motif_cols = [j for j, label in enumerate(count_keys) if label[0] == sys_id]
        counts = count_data[:, motif_cols].reshape(-1, len(motif_cols))
        energy = all_energy[:, i].reshape(-1)
        s = all_stress[:, i]
        has_stress = bool(jnp.any(s != 0))
        temperature = float(temperatures[i])
        results[sys_id] = _analyze_single_system(
            energy,
            counts,
            temperature,
            n_blocks,
            stress=s if has_stress else None,
            stress_potential=stress_potential[:, i]
            if has_stress and stress_potential is not None
            else None,
            stress_tail_correction=stress_tail[:, i]
            if has_stress and stress_tail is not None
            else None,
            stress_ideal_gas=stress_ideal[:, i]
            if has_stress and stress_ideal is not None
            else None,
        )

    return results

analyze_mcmc_file(hdf5_path, n_blocks=None)

Analyze MCMC simulation results from an HDF5 file.

Convenience wrapper that reads the HDF5 file and delegates to :func:analyze_mcmc.

Parameters:

Name Type Description Default
hdf5_path str | Path

Path to HDF5 output file from :func:~kups.application.mcmc.simulation.run_mcmc.

required
n_blocks int | None

Number of blocks for error estimation. None uses :func:~kups.core.utils.block_average.optimal_block_average.

None

Returns:

Type Description
dict[SystemId, MCMCAnalysisResult]

Per-system analysis results keyed by SystemId.

Source code in src/kups/application/mcmc/analysis.py
@no_jax_tracing
def analyze_mcmc_file(
    hdf5_path: str | Path,
    n_blocks: int | None = None,
) -> dict[SystemId, MCMCAnalysisResult]:
    """Analyze MCMC simulation results from an HDF5 file.

    Convenience wrapper that reads the HDF5 file and delegates to
    :func:`analyze_mcmc`.

    Args:
        hdf5_path: Path to HDF5 output file from
            :func:`~kups.application.mcmc.simulation.run_mcmc`.
        n_blocks: Number of blocks for error estimation. ``None`` uses
            :func:`~kups.core.utils.block_average.optimal_block_average`.

    Returns:
        Per-system analysis results keyed by ``SystemId``.
    """
    with HDF5StorageReader[MCMCLoggedData](hdf5_path) as reader:
        fixed = reader.focus_group(lambda s: s.fixed)[...]
        per_step = reader.focus_group(lambda s: s.per_step)[...]

    return analyze_mcmc(fixed, per_step, n_blocks)