Source code for pyserep.analysis.performance

"""
pyserep.analysis.performance
================================
Performance metrics: FLOP counts, timing, reduction ratios.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Dict, Optional


[docs] @dataclass class PerformanceMetrics: """All performance and efficiency metrics for a pipeline run.""" # Size n_full_dofs: int n_selected_modes: int n_master_dofs: int # Reduction dof_reduction_pct: float # = n_master / n_full × 100 mode_retention_pct: float # = n_selected / n_total × 100 # Condition kappa: float # FRF frf_method: str n_freq_points: int n_bands: int frf_flops_rom: int frf_flops_ref: int frf_speedup: float # ref_flops / rom_flops # Timing t_eigensolver_s: float t_mode_select_s: float t_dof_select_s: float t_rom_build_s: float t_frf_s: float t_total_s: float
[docs] def summary(self) -> str: """Return a formatted multi-line performance summary string.""" return "\n".join([ f"\n{'─'*55}", " PERFORMANCE SUMMARY", f"{'─'*55}", f" Full DOFs : {self.n_full_dofs:>12,}", f" Master DOFs : {self.n_master_dofs:>12,}", f" DOF reduction : {self.dof_reduction_pct:>11.4f}%", f" Modes retained : {self.n_selected_modes:>12,}", f" Mode retention : {self.mode_retention_pct:>11.4f}%", f" κ(Φₐ) : {self.kappa:>12.4e}", f"{'─'*55}", f" FRF method : {self.frf_method:>12s}", f" Freq points : {self.n_freq_points:>12,}", f" FLOPs (ROM) : {self.frf_flops_rom:>12,}", f" FLOPs (reference) : {self.frf_flops_ref:>12,}", f" FLOP speedup : {self.frf_speedup:>11.1f}×", f"{'─'*55}", f" Eigensolver : {self.t_eigensolver_s:>9.2f}s", f" Mode selection : {self.t_mode_select_s:>9.2f}s", f" DOF selection : {self.t_dof_select_s:>9.2f}s", f" ROM build : {self.t_rom_build_s:>9.2f}s", f" FRF computation : {self.t_frf_s:>9.2f}s", f" TOTAL : {self.t_total_s:>9.2f}s", f"{'─'*55}", ])
[docs] def flop_count( n_modes: int, n_freq: int, n_pairs: int, method: str = "direct", ) -> int: """ Estimate FRF computation FLOP count. Parameters ---------- n_modes : int Number of retained modes (m for ROM, all elastic for reference). n_freq : int Number of evaluation frequency points. n_pairs : int Number of force/output DOF pairs. method : str ``"direct"`` or ``"modal"``. Returns ------- int Approximate floating-point operation count. Notes ----- **Modal FRF**: per frequency per mode per pair: ~8 FLOPs (2 multiplications + complex division + addition) **Direct FRF**: per frequency: one m×m complex LU factor + m×m backsolve LU factor: (2/3) m³ FLOPs Backsolve: m² FLOPs per right-hand side × n_pairs """ if method == "modal": return 8 * n_modes * n_freq * n_pairs elif method == "direct": lu_flops = int(2 / 3 * n_modes ** 3) * n_freq sol_flops = n_modes ** 2 * n_pairs * n_freq return lu_flops + sol_flops else: raise ValueError(f"Unknown method '{method}'")
[docs] def reduction_metrics( n_full_dofs: int, n_master_dofs: int, n_all_modes: int, n_selected_modes: int, ) -> Dict[str, float]: """ Compute reduction ratio metrics. Returns ------- dict with keys: ``dof_reduction_ratio``, ``dof_retention_pct``, ``mode_retention_pct``, ``size_ratio`` """ return { "dof_reduction_ratio": n_master_dofs / n_full_dofs, "dof_retention_pct": n_master_dofs / n_full_dofs * 100.0, "mode_retention_pct": n_selected_modes / n_all_modes * 100.0, "size_ratio": n_master_dofs / n_full_dofs, }
[docs] def summarise_performance( n_full_dofs: int, n_selected_modes: int, n_master_dofs: int, n_all_modes: int, kappa: float, n_freq: int, n_bands: int, n_pairs: int, frf_method: str = "direct", frf_flops_rom: Optional[int] = None, frf_flops_ref: Optional[int] = None, t_eigensolver_s: float = 0.0, t_mode_select_s: float = 0.0, t_dof_select_s: float = 0.0, t_rom_build_s: float = 0.0, t_frf_s: float = 0.0, t_total_s: float = 0.0, ) -> PerformanceMetrics: """ Collect all performance metrics into a :class:`PerformanceMetrics`. Parameters are self-explanatory from the return type documentation. """ if frf_flops_rom is None: frf_flops_rom = flop_count(n_selected_modes, n_freq, n_pairs, frf_method) if frf_flops_ref is None: n_elastic = n_all_modes # approximate frf_flops_ref = flop_count(n_elastic, n_freq, n_pairs, "modal") return PerformanceMetrics( n_full_dofs = n_full_dofs, n_selected_modes = n_selected_modes, n_master_dofs = n_master_dofs, dof_reduction_pct = n_master_dofs / max(n_full_dofs, 1) * 100.0, mode_retention_pct = n_selected_modes / max(n_all_modes, 1) * 100.0, kappa = kappa, frf_method = frf_method, n_freq_points = n_freq, n_bands = n_bands, frf_flops_rom = frf_flops_rom, frf_flops_ref = frf_flops_ref, frf_speedup = frf_flops_ref / max(frf_flops_rom, 1), t_eigensolver_s = t_eigensolver_s, t_mode_select_s = t_mode_select_s, t_dof_select_s = t_dof_select_s, t_rom_build_s = t_rom_build_s, t_frf_s = t_frf_s, t_total_s = t_total_s, )