Skip to content

kups.application.relaxation.analysis

Post-simulation analysis for structure relaxation.

IsRelaxStepData

Bases: HasPotentialEnergy, Protocol

Contract for a single relaxation step from the reader.

Source code in src/kups/application/relaxation/analysis.py
class IsRelaxStepData(HasPotentialEnergy, Protocol):
    """Contract for a single relaxation step from the reader."""

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

RelaxAnalysisResult dataclass

Summary of a completed relaxation for a single system.

Attributes:

Name Type Description
final_energy float

Final potential energy (eV).

final_max_force float

Maximum atomic force at the last step (eV/Ang).

n_steps int

Number of steps actually taken.

Source code in src/kups/application/relaxation/analysis.py
@plain_dataclass
class RelaxAnalysisResult:
    """Summary of a completed relaxation for a single system.

    Attributes:
        final_energy: Final potential energy (eV).
        final_max_force: Maximum atomic force at the last step (eV/Ang).
        n_steps: Number of steps actually taken.
    """

    final_energy: float
    final_max_force: float
    n_steps: int

analyze_relax(init_data, step_data, n_steps)

Extract per-system analysis results from a relaxation step.

Parameters:

Name Type Description Default
init_data _IsRelaxInitData

Initial state providing system keys.

required
step_data IsRelaxStepData

Final step data with per-system potential_energy and max_force.

required
n_steps int

Number of steps actually taken.

required

Returns:

Type Description
dict[SystemId, RelaxAnalysisResult]

Per-system relaxation results keyed by SystemId.

Source code in src/kups/application/relaxation/analysis.py
def analyze_relax(
    init_data: _IsRelaxInitData,
    step_data: IsRelaxStepData,
    n_steps: int,
) -> dict[SystemId, RelaxAnalysisResult]:
    """Extract per-system analysis results from a relaxation step.

    Args:
        init_data: Initial state providing system keys.
        step_data: Final step data with per-system potential_energy and
            max_force.
        n_steps: Number of steps actually taken.

    Returns:
        Per-system relaxation results keyed by ``SystemId``.
    """
    results: dict[SystemId, RelaxAnalysisResult] = {}
    for i, sys_id in enumerate(init_data.systems.keys):
        results[sys_id] = RelaxAnalysisResult(
            final_energy=float(step_data.potential_energy[i]),
            final_max_force=float(step_data.max_force[i]),
            n_steps=n_steps,
        )
    return results

analyze_relax_file(hdf5_path)

Analyse relaxation results from an HDF5 file.

Parameters:

Name Type Description Default
hdf5_path str | Path

Path to HDF5 output from a relaxation run.

required

Returns:

Type Description
dict[SystemId, RelaxAnalysisResult]

Per-system relaxation results keyed by SystemId.

Source code in src/kups/application/relaxation/analysis.py
def analyze_relax_file(
    hdf5_path: str | Path,
) -> dict[SystemId, RelaxAnalysisResult]:
    """Analyse relaxation results from an HDF5 file.

    Args:
        hdf5_path: Path to HDF5 output from a relaxation run.

    Returns:
        Per-system relaxation results keyed by ``SystemId``.
    """

    with HDF5StorageReader[RelaxLoggedData](hdf5_path) as reader:
        n_steps = int(reader.file.attrs.get("actual_steps", -1))
        init_data = reader.focus_group(lambda s: s.init)[...]
        step_data = reader.focus_group(lambda s: s.step)[n_steps - 1]

    return analyze_relax(init_data, step_data, n_steps)