"""Kinetic-to-Potential Energy Transfer Ratio (KPR) Tracks the partition between kinetic and potential wave energy, identifying bore formation and nonlinear energy transfer. KPR = E_K / E_P = (H·u²) / (g·η²) """ import numpy as np class KineticPotentialRatio: """ Kinetic-to-Potential Energy Transfer Ratio - Parameter 2 of 7 Thresholds: SAFE: KPR < 1.2 (dispersive propagation) MONITOR: 1.2 ≤ KPR < 1.6 (moderate nonlinear shoaling) ALERT: 1.6 ≤ KPR < 2.0 (kinetic dominance) CRITICAL: KPR ≥ 2.0 (hydraulic bore formation) Linear equipartition: KPR = 1.0 """ def __init__(self, g=9.81, rho=1025): self.g = g self.rho = rho self.thresholds = { 'safe': 1.2, 'alert': 1.6, 'critical': 2.0 } def compute_kinetic_energy(self, H, u): """Depth-integrated kinetic energy per unit width E_K = ½·ρ·H·u² Args: H: water depth [m] u: depth-averaged velocity [m/s] Returns: E_K: kinetic energy per unit width [J/m] """ return 0.5 * self.rho * H * u**2 def compute_potential_energy(self, eta): """Potential energy from surface displacement E_P = ½·ρ·g·η² Args: eta: wave amplitude [m] Returns: E_P: potential energy per unit width [J/m] """ return 0.5 * self.rho * self.g * eta**2 def compute_kpr(self, H, u, eta): """Compute Kinetic-to-Potential Energy Ratio KPR = E_K / E_P = (H·u²) / (g·η²) Args: H: water depth [m] u: depth-averaged velocity [m/s] eta: wave amplitude [m] Returns: dict with KPR value, status, and energy components """ E_K = self.compute_kinetic_energy(H, u) E_P = self.compute_potential_energy(eta) kpr = E_K / E_P if E_P > 0 else float('inf') return { 'value': float(kpr), 'status': self.get_status(kpr), 'kinetic_energy': float(E_K), 'potential_energy': float(E_P), 'total_energy': float(E_K + E_P) } def get_status(self, kpr): """Get alert status based on KPR value""" if kpr < self.thresholds['safe']: return 'SAFE' elif kpr < self.thresholds['alert']: return 'MONITOR' elif kpr < self.thresholds['critical']: return 'ALERT' else: return 'CRITICAL' def compute_energy_flux(self, H, eta, c): """Compute energy flux (power per unit crest width) P_flux = ρ·g·η²·c [W/m] Args: H: water depth [m] eta: wave amplitude [m] c: wave celerity [m/s] Returns: P: energy flux [W/m] """ return self.rho * self.g * eta**2 * c def compute_concentration_factor(self, P_deep, P_shore): """Compute energy concentration factor Args: P_deep: deep ocean energy flux [W/m] P_shore: nearshore energy flux [W/m] Returns: concentration: factor """ return P_shore / P_deep def validate_event(self, H, u, eta, expected_kpr=None): """Validate KPR against expected values""" result = self.compute_kpr(H, u, eta) validation = { 'kpr': result, 'validation': {} } if expected_kpr is not None: error = abs(result['value'] - expected_kpr) / expected_kpr * 100 validation['validation']['expected'] = expected_kpr validation['validation']['error_percent'] = error return validation