Source code for openeurotop.special_cases

"""
Cas spécifiques et configurations complexes selon EurOtop (2018)

Pentes multiples, structures en escalier, conditions extrêmes, etc.
"""

import numpy as np
from openeurotop.constants import G, DEG_TO_RAD
from openeurotop import overtopping, wave_parameters, reduction_factors


[docs] def multi_slope_structure(Hm0, Tm_10, h, Rc, slopes_config, gamma_f_sections=None, gamma_beta=1.0, g=G): """ Calcul du franchissement pour une structure à pentes multiples EurOtop 2018 - Annexe B.3 Parameters ---------- Hm0 : float Hauteur significative spectrale (m) Tm_10 : float Période spectrale (s) h : float Profondeur d'eau (m) Rc : float Revanche totale (m) slopes_config : list of dict Configuration des pentes, chaque dict contient: - 'alpha_deg': angle de pente (degrés) - 'h_start': hauteur de début (m au-dessus SWL) - 'h_end': hauteur de fin (m au-dessus SWL) gamma_f_sections : list of float, optional Facteurs de rugosité pour chaque section gamma_beta : float, optional Facteur d'obliquité g : float, optional Accélération de la pesanteur (m/s²) Returns ------- dict Résultats avec débit et pente équivalente Examples -------- >>> # Structure avec 3 pentes : 1:3 jusqu'à 0m, 1:2 de 0 à 2m, 1:1.5 au-dessus >>> slopes = [ ... {'alpha_deg': 18.4, 'h_start': -5, 'h_end': 0}, ... {'alpha_deg': 26.6, 'h_start': 0, 'h_end': 2}, ... {'alpha_deg': 33.7, 'h_start': 2, 'h_end': 5} ... ] >>> result = multi_slope_structure(2.5, 6.0, 10.0, 4.0, slopes) References ---------- EurOtop (2018) - Annexe B.3.1 """ # Si gamma_f non fourni, utiliser 1.0 pour toutes les sections if gamma_f_sections is None: gamma_f_sections = [1.0] * len(slopes_config) # Calcul de la pente équivalente # Méthode : pondération par la longueur de run-up attendue # Estimation du run-up sans revanche (pour avoir une idée de la zone active) from openeurotop.run_up import run_up_2percent_smooth_slope Ru_estimate = run_up_2percent_smooth_slope(Hm0, Tm_10, np.mean([s['alpha_deg'] for s in slopes_config]), h, g) # Identifier les sections actives (entre SWL et Ru_estimate) total_length = 0 weighted_tan_alpha = 0 weighted_gamma_f = 0 for i, slope in enumerate(slopes_config): h_start = max(slope['h_start'], 0) # Commence au SWL minimum h_end = min(slope['h_end'], Ru_estimate) # Se termine au run-up max if h_end > h_start: # Cette section est active delta_h = h_end - h_start alpha_rad = slope['alpha_deg'] * DEG_TO_RAD length_section = delta_h / np.sin(alpha_rad) # Longueur le long de la pente total_length += length_section weighted_tan_alpha += np.tan(alpha_rad) * length_section weighted_gamma_f += gamma_f_sections[i] * length_section if total_length > 0: # Pente équivalente tan_alpha_eq = weighted_tan_alpha / total_length alpha_eq_deg = np.arctan(tan_alpha_eq) / DEG_TO_RAD # Rugosité équivalente gamma_f_eq = weighted_gamma_f / total_length else: # Cas dégénéré : utiliser la dernière pente alpha_eq_deg = slopes_config[-1]['alpha_deg'] gamma_f_eq = gamma_f_sections[-1] # Calcul du franchissement avec paramètres équivalents q = overtopping.digue_talus(Hm0, Tm_10, h, Rc, alpha_eq_deg, gamma_f=gamma_f_eq, gamma_beta=gamma_beta, g=g) return { 'q': q, 'alpha_equivalent_deg': alpha_eq_deg, 'gamma_f_equivalent': gamma_f_eq, 'active_length': total_length, 'Ru_estimate': Ru_estimate }
[docs] def very_steep_slope(Hm0, Tm_10, h, Rc, alpha_deg, gamma_f=1.0, g=G): """ Franchissement pour pentes très raides (α > 60°) Pour les pentes très raides, le comportement se rapproche d'un mur vertical Parameters ---------- Hm0, Tm_10, h, Rc : float Paramètres standard alpha_deg : float Angle de pente (degrés), devrait être > 60° gamma_f : float, optional Facteur de rugosité g : float, optional Accélération de la pesanteur (m/s²) Returns ------- float Débit de franchissement q (m³/s/m) References ---------- EurOtop (2018) - Section 5.4.3 """ if alpha_deg < 60: # Utiliser formule standard pour talus return overtopping.digue_talus(Hm0, Tm_10, h, Rc, alpha_deg, gamma_f=gamma_f, g=g) # Pour α > 60°, interpolation entre talus et mur vertical # Calculer les deux valeurs q_slope = overtopping.digue_talus(Hm0, Tm_10, h, Rc, 60.0, gamma_f=gamma_f, g=g) q_wall = overtopping.mur_vertical(Hm0, Tm_10, h, Rc, g=g) # Interpolation linéaire entre 60° et 90° if alpha_deg >= 90: return q_wall else: weight = (alpha_deg - 60) / 30 # 0 à 60°, 1 à 90° q = (1 - weight) * q_slope + weight * q_wall return q
[docs] def very_gentle_slope(Hm0, Tm_10, h, Rc, alpha_deg, gamma_f=1.0, g=G): """ Franchissement pour pentes très douces (α < 10°) Pour les pentes très douces, les formules standards deviennent moins fiables. Utilisation d'une correction empirique. Parameters ---------- Hm0, Tm_10, h, Rc : float Paramètres standard alpha_deg : float Angle de pente (degrés), devrait être < 10° gamma_f : float, optional Facteur de rugosité g : float, optional Accélération de la pesanteur (m/s²) Returns ------- float Débit de franchissement q (m³/s/m) References ---------- EurOtop (2018) - Section 5.4.4 """ if alpha_deg >= 10: # Utiliser formule standard return overtopping.digue_talus(Hm0, Tm_10, h, Rc, alpha_deg, gamma_f=gamma_f, g=g) # Pour α < 10°, correction # Formule standard peut surestimer q_standard = overtopping.digue_talus(Hm0, Tm_10, h, Rc, 10.0, gamma_f=gamma_f, g=g) # Facteur de correction empirique pour pentes douces correction_factor = (alpha_deg / 10.0)**0.5 # Réduction pour pentes plus douces q = q_standard * correction_factor return q
[docs] def stepped_revetment(Hm0, Tm_10, h, Rc, alpha_avg_deg, step_height, step_width, n_steps, gamma_f_base=1.0, g=G): """ Franchissement pour revêtement en escalier Les marches créent une rugosité supplémentaire Parameters ---------- Hm0, Tm_10, h, Rc : float Paramètres standard alpha_avg_deg : float Angle de pente moyen (degrés) step_height : float Hauteur de chaque marche (m) step_width : float Largeur de chaque marche (m) n_steps : int Nombre de marches gamma_f_base : float, optional Rugosité de base du matériau g : float, optional Accélération de la pesanteur (m/s²) Returns ------- dict Résultats avec gamma_f équivalent References ---------- EurOtop (2018) - Annexe B.4 """ # Rugosité supplémentaire due aux marches # Dépend du rapport hauteur/longueur d'onde L0 = wave_parameters.wave_length_deep_water(Tm_10, g) # Rugosité relative des marches roughness_ratio = step_height / Hm0 if roughness_ratio < 0.01: # Marches négligeables gamma_f_steps = 1.0 elif roughness_ratio < 0.1: # Marches modérées gamma_f_steps = 1.0 - 0.2 * (roughness_ratio / 0.1) else: # Marches importantes gamma_f_steps = 0.8 # Rugosité totale gamma_f_total = gamma_f_base * gamma_f_steps # Calcul du franchissement q = overtopping.digue_talus(Hm0, Tm_10, h, Rc, alpha_avg_deg, gamma_f=gamma_f_total, g=g) return { 'q': q, 'gamma_f_steps': gamma_f_steps, 'gamma_f_total': gamma_f_total, 'roughness_ratio': roughness_ratio }
[docs] def overhanging_wall(Hm0, Tm_10, h, Rc, overhang_length, gamma_f=1.0, g=G): """ Franchissement pour mur avec surplomb (angle > 90°) Le surplomb réduit significativement le franchissement Parameters ---------- Hm0, Tm_10, h, Rc : float Paramètres standard overhang_length : float Longueur du surplomb horizontal (m) gamma_f : float, optional Facteur de rugosité g : float, optional Accélération de la pesanteur (m/s²) Returns ------- dict Résultats avec facteur de réduction du surplomb References ---------- EurOtop (2018) - Section 5.4.5 """ # Franchissement sans surplomb q_no_overhang = overtopping.mur_vertical(Hm0, Tm_10, h, Rc, g=g) # Réduction due au surplomb overhang_ratio = overhang_length / Hm0 if overhang_ratio < 0.1: gamma_overhang = 1.0 elif overhang_ratio < 0.5: gamma_overhang = 1.0 - 0.5 * ((overhang_ratio - 0.1) / 0.4) else: gamma_overhang = 0.5 # Réduction de 50% pour surplomb important q = q_no_overhang * gamma_overhang return { 'q': q, 'gamma_overhang': gamma_overhang, 'overhang_ratio': overhang_ratio, 'q_no_overhang': q_no_overhang }
[docs] def shallow_water_correction(Hm0, Tm_10, h, Rc, alpha_deg, breaking_index=0.5, g=G): """ Correction pour eau très peu profonde avec déferlement En eau peu profonde, les vagues déferlent avant d'atteindre la structure, réduisant le franchissement. Parameters ---------- Hm0, Tm_10, h : float Paramètres de vague et profondeur Rc : float Revanche (m) alpha_deg : float Angle de pente (degrés) breaking_index : float, optional Indice de déferlement γ = H/h (typiquement 0.4-0.6) g : float, optional Accélération de la pesanteur (m/s²) Returns ------- dict Résultats avec hauteur de vague corrigée References ---------- EurOtop (2018) - Section 5.4.6 """ # Critère de déferlement : Hm0 > γ * h H_breaking = breaking_index * h if Hm0 <= H_breaking: # Pas de déferlement, utiliser Hm0 directement Hm0_corrected = Hm0 correction_applied = False else: # Déferlement : réduire la hauteur de vague Hm0_corrected = H_breaking correction_applied = True # Calcul avec hauteur corrigée q = overtopping.digue_talus(Hm0_corrected, Tm_10, h, Rc, alpha_deg, g=g) return { 'q': q, 'Hm0_original': Hm0, 'Hm0_corrected': Hm0_corrected, 'H_breaking': H_breaking, 'correction_applied': correction_applied, 'depth_ratio': h / Hm0 }
[docs] def complex_geometry_equivalent(geometry_description, Hm0, Tm_10, h, Rc, g=G): """ Approche générale pour géométries complexes via paramètres équivalents Cette fonction aide à déterminer les paramètres équivalents pour des géométries complexes non couvertes par les formules standard. Parameters ---------- geometry_description : dict Description de la géométrie avec clés : - 'type': type de structure - 'slopes': liste d'angles de pente - 'roughness': liste de rugosités - 'berms': informations sur les bermes etc. Hm0, Tm_10, h, Rc : float Paramètres standard g : float, optional Accélération de la pesanteur (m/s²) Returns ------- dict Recommandations et calculs avec paramètres équivalents Notes ----- Cette fonction fournit une approche conservatrice pour les cas complexes. Pour des projets critiques, des essais physiques sont recommandés. """ recommendations = { 'approach': 'equivalent_parameters', 'warnings': [], 'q_conservative': None, 'q_optimistic': None, 'recommendation': None } # Analyser la complexité if 'slopes' in geometry_description and len(geometry_description['slopes']) > 2: recommendations['warnings'].append( "Géométrie à pentes multiples : utiliser multi_slope_structure()" ) if 'berms' in geometry_description and len(geometry_description.get('berms', [])) > 1: recommendations['warnings'].append( "Plusieurs bermes : formules standard limitées, essais recommandés" ) # Estimation conservative : utiliser paramètres les plus défavorables if 'slopes' in geometry_description: alpha_min = min(geometry_description['slopes']) alpha_max = max(geometry_description['slopes']) # Calcul optimiste (pente raide) q_opt = overtopping.digue_talus(Hm0, Tm_10, h, Rc, alpha_max, g=g) # Calcul conservateur (pente douce) q_cons = overtopping.digue_talus(Hm0, Tm_10, h, Rc, alpha_min, g=g) recommendations['q_optimistic'] = q_opt recommendations['q_conservative'] = q_cons recommendations['recommendation'] = ( f"Pour conception, utiliser q = {q_cons:.6f} m³/s/m (conservateur). " f"Plage attendue : [{q_opt:.6f}, {q_cons:.6f}] m³/s/m" ) return recommendations
[docs] def extreme_conditions_check(Hm0, Tm_10, h, Rc, alpha_deg): """ Vérifie si les conditions sont dans le domaine de validité d'EurOtop Parameters ---------- Hm0, Tm_10, h, Rc, alpha_deg : float Paramètres de la structure et des vagues Returns ------- dict Résultats de validation avec warnings Examples -------- >>> check = extreme_conditions_check(2.5, 6.0, 10.0, 3.0, 35.0) >>> if check['valid']: ... print("Conditions valides") >>> else: ... print("Warnings:", check['warnings']) """ warnings = [] valid = True # Vérifier Rc/Hm0 Rc_Hm0 = Rc / Hm0 if Rc_Hm0 < 0.5: warnings.append(f"Rc/Hm0 = {Rc_Hm0:.2f} < 0.5 : hors domaine de validité (submersion)") valid = False elif Rc_Hm0 > 3.5: warnings.append(f"Rc/Hm0 = {Rc_Hm0:.2f} > 3.5 : extrapolation, incertitudes élevées") # Vérifier l'angle de pente if alpha_deg < 10: warnings.append(f"Pente {alpha_deg}° < 10° : formules moins fiables, utiliser very_gentle_slope()") elif alpha_deg > 60 and alpha_deg < 90: warnings.append(f"Pente {alpha_deg}° > 60° : proche du vertical, utiliser very_steep_slope()") # Vérifier le nombre d'Iribarren xi = wave_parameters.iribarren_number(alpha_deg, Hm0, Tm_10) if xi < 1.0: warnings.append(f"Nombre d'Iribarren {xi:.2f} < 1.0 : vagues très déferlantes") elif xi > 7.0: warnings.append(f"Nombre d'Iribarren {xi:.2f} > 7.0 : vagues très non-déferlantes, rare") # Vérifier la profondeur relative h_Hm0 = h / Hm0 if h_Hm0 < 2.0: warnings.append(f"h/Hm0 = {h_Hm0:.2f} < 2.0 : eau peu profonde, déferlement probable") # Vérifier la cambrure s0 = wave_parameters.wave_steepness(Hm0, Tm_10) if s0 < 0.01: warnings.append(f"Cambrure s0 = {s0:.4f} < 0.01 : vagues très plates, inhabituel") elif s0 > 0.06: warnings.append(f"Cambrure s0 = {s0:.4f} > 0.06 : vagues très cambrées, mer du vent") return { 'valid': valid, 'warnings': warnings, 'Rc_Hm0': Rc_Hm0, 'xi': xi, 'h_Hm0': h_Hm0, 's0': s0 }