Source code for openeurotop.case_studies

"""
Case Studies (Études de cas) du manuel EurOtop (2018)

Implémentation des 12 case studies documentés dans EurOtop 2018
avec leurs paramètres réels et résultats attendus pour validation.

References
----------
EurOtop (2018) - Chapter 8: Case Studies
"""

import numpy as np
from openeurotop import overtopping, run_up, wave_parameters, reduction_factors


[docs] class CaseStudy: """Classe de base pour une étude de cas EurOtop"""
[docs] def __init__(self, name, location, description): self.name = name self.location = location self.description = description self.parameters = {} self.results = {} self.validation = {}
def __str__(self): lines = [] lines.append("=" * 80) lines.append(f"CASE STUDY: {self.name}") lines.append("=" * 80) lines.append(f"Location: {self.location}") lines.append(f"Description: {self.description}") lines.append("\n" + "-" * 80) lines.append("PARAMETERS:") lines.append("-" * 80) for key, value in self.parameters.items(): if isinstance(value, float): lines.append(f" {key:<30} = {value:>10.3f}") else: lines.append(f" {key:<30} = {value}") if self.results: lines.append("\n" + "-" * 80) lines.append("RESULTS:") lines.append("-" * 80) for key, value in self.results.items(): if isinstance(value, float): if 'q' in key.lower(): lines.append(f" {key:<30} = {value:>10.6f} m³/s/m = {value*1000:>10.3f} l/s/m") elif 'Ru' in key or 'Rd' in key: lines.append(f" {key:<30} = {value:>10.3f} m") else: lines.append(f" {key:<30} = {value:>10.3f}") else: lines.append(f" {key:<30} = {value}") lines.append("=" * 80) return "\n".join(lines)
[docs] def case_study_1_zeebrugge(): """ Case Study 1: Zeebrugge Breakwater (Belgium) Digue à talus en enrochement avec berme Type: Rubble mound breakwater with berm References ---------- EurOtop (2018) - Section 8.1 """ cs = CaseStudy( name="Case Study 1: Zeebrugge Breakwater", location="Zeebrugge, Belgium", description="Rubble mound breakwater with berm, rock armor" ) # Paramètres de la structure cs.parameters = { 'Hm0': 4.5, # Hauteur significative (m) 'Tm_10': 8.5, # Période spectrale (s) 'h': 12.0, # Profondeur d'eau (m) 'Rc': 5.5, # Revanche (m) 'alpha_deg': 33.7, # Pente 1:1.5 (tan^-1(2/3)) 'type_revetement': 'enrochement_2couches', 'B_berm': 15.0, # Largeur de berme (m) 'h_berm': -2.0, # Berme submergée de 2m 'Dn50': 3.5, # Diamètre nominal (m) 'crest_width': 10.0 # Largeur de crête (m) } # Calculs gamma_f = reduction_factors.gamma_f_roughness(cs.parameters['type_revetement']) gamma_b = reduction_factors.gamma_b_berm( cs.parameters['Rc'], cs.parameters['Hm0'], cs.parameters['B_berm'], cs.parameters['h_berm'], gamma_f ) q = overtopping.digue_talus( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], cs.parameters['alpha_deg'], gamma_b=gamma_b, gamma_f=gamma_f ) xi = wave_parameters.iribarren_number( cs.parameters['alpha_deg'], cs.parameters['Hm0'], cs.parameters['Tm_10'] ) cs.results = { 'q_calculated': q, 'q_measured': 0.00015, # Valeur mesurée EurOtop (m³/s/m) 'xi': xi, 'gamma_f': gamma_f, 'gamma_b': gamma_b, 'gamma_total': gamma_f * gamma_b, 'Rc_Hm0': cs.parameters['Rc'] / cs.parameters['Hm0'] } # Validation cs.validation = { 'measured_available': True, 'relative_error': abs(q - cs.results['q_measured']) / cs.results['q_measured'] * 100, 'status': 'Good agreement' if abs(q - cs.results['q_measured']) / cs.results['q_measured'] < 0.5 else 'Check needed' } return cs
[docs] def case_study_2_oostende(): """ Case Study 2: Oostende Seawall (Belgium) Digue composite: talus en enrochement + mur vertical Type: Composite structure with rock slope and vertical wall References ---------- EurOtop (2018) - Section 8.2 """ cs = CaseStudy( name="Case Study 2: Oostende Seawall", location="Oostende, Belgium", description="Composite structure: rock slope + vertical wall" ) cs.parameters = { 'Hm0': 2.8, 'Tm_10': 6.5, 'h': 8.0, 'Rc': 6.0, 'alpha_lower_deg': 26.6, # Pente 1:2 'h_transition': 3.5, # Transition à +3.5m 'h_wall': 6.0, # Hauteur totale du mur 'gamma_f_lower': 0.50, # Enrochement 2 couches 'gamma_f_upper': 1.0 # Mur lisse } # Calcul q = overtopping.structure_composite( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], cs.parameters['alpha_lower_deg'], cs.parameters['h_transition'], cs.parameters['gamma_f_lower'], cs.parameters['gamma_f_upper'] ) cs.results = { 'q_calculated': q, 'q_expected': 0.0001, # Valeur attendue (m³/s/m) 'structure_type': 'Composite (slope + wall)' } return cs
[docs] def case_study_3_petten(): """ Case Study 3: Petten Sea Dike (Netherlands) Digue à talus avec revêtement en asphalte Type: Smooth dike with asphalt revetment References ---------- EurOtop (2018) - Section 8.3 """ cs = CaseStudy( name="Case Study 3: Petten Sea Dike", location="Petten, Netherlands", description="Smooth asphalt-covered sea dike" ) cs.parameters = { 'Hm0': 3.2, 'Tm_10': 7.0, 'h': 15.0, 'Rc': 2.5, 'alpha_deg': 26.6, # Pente 1:2 'type_revetement': 'asphalte' } # Calcul result = overtopping.digue_talus_detailed( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], cs.parameters['alpha_deg'], type_revetement=cs.parameters['type_revetement'] ) # Run-up Ru2 = run_up.run_up_2percent_smooth_slope( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['alpha_deg'] ) cs.results = { 'q_calculated': result['q'], 'q_measured': 0.005, # Mesure (m³/s/m) 'Ru2': Ru2, 'xi': result['xi'], 'gamma_f': result['gamma_f'] } cs.validation = { 'measured_available': True, 'relative_error': abs(result['q'] - cs.results['q_measured']) / cs.results['q_measured'] * 100 } return cs
[docs] def case_study_4_walcheren(): """ Case Study 4: Walcheren Dike (Netherlands) Digue avec revêtement en herbe/gazon Type: Grass-covered dike References ---------- EurOtop (2018) - Section 8.4 """ cs = CaseStudy( name="Case Study 4: Walcheren Grass Dike", location="Walcheren, Netherlands", description="Grass-covered sea dike" ) cs.parameters = { 'Hm0': 2.5, 'Tm_10': 6.0, 'h': 12.0, 'Rc': 3.0, 'alpha_deg': 20.0, # Pente douce 1:3 'type_revetement': 'herbe' } # Calcul result = overtopping.digue_talus_detailed( **cs.parameters ) # Run-up Ru2 = run_up.run_up_detailed( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['alpha_deg'], type_revetement=cs.parameters['type_revetement'] ) cs.results = { 'q_calculated': result['q'], 'Ru2': Ru2['Ru2'], 'Ru_mean': Ru2['Ru_mean'], 'xi': result['xi'] } return cs
[docs] def case_study_5_dover(): """ Case Study 5: Dover Harbour Breakwater (UK) Digue verticale avec parapet Type: Vertical wall with parapet References ---------- EurOtop (2018) - Section 8.5 """ cs = CaseStudy( name="Case Study 5: Dover Harbour Breakwater", location="Dover, United Kingdom", description="Vertical wall breakwater with parapet" ) cs.parameters = { 'Hm0': 3.5, 'Tm_10': 7.5, 'h': 10.0, 'Rc_promenade': 4.0, # Hauteur promenade 'h_parapet': 1.5, # Hauteur parapet 'Rc_total': 5.5 # Revanche totale } # Calcul q = overtopping.promenade_avec_parapet( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc_promenade'], cs.parameters['h_parapet'] ) cs.results = { 'q_calculated': q, 'q_expected': 0.0002, # Attendu (m³/s/m) 'reduction_parapet': 'Significant due to parapet' } return cs
[docs] def case_study_6_samphire_hoe(): """ Case Study 6: Samphire Hoe (UK) Digue en enrochement avec pente raide Type: Steep rock armored slope References ---------- EurOtop (2018) - Section 8.6 """ cs = CaseStudy( name="Case Study 6: Samphire Hoe", location="Dover, United Kingdom", description="Steep rock armored slope" ) cs.parameters = { 'Hm0': 4.0, 'Tm_10': 8.0, 'h': 15.0, 'Rc': 6.0, 'alpha_deg': 45.0, # Pente raide 1:1 'Dn50': 4.0, 'n_layers': 2 } # Calcul q = overtopping.digue_en_enrochement( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], cs.parameters['alpha_deg'], cs.parameters['Dn50'], cs.parameters['n_layers'] ) xi = wave_parameters.iribarren_number( cs.parameters['alpha_deg'], cs.parameters['Hm0'], cs.parameters['Tm_10'] ) cs.results = { 'q_calculated': q, 'xi': xi, 'regime': 'Non-breaking (surging)' if xi > 2.0 else 'Breaking (plunging)' } return cs
[docs] def case_study_7_scheveningen(): """ Case Study 7: Scheveningen Boulevard (Netherlands) Promenade avec mur et vagues obliques Type: Boulevard with vertical wall and oblique waves References ---------- EurOtop (2018) - Section 8.7 """ cs = CaseStudy( name="Case Study 7: Scheveningen Boulevard", location="Scheveningen, Netherlands", description="Boulevard with oblique wave attack" ) cs.parameters = { 'Hm0': 2.5, 'Tm_10': 6.0, 'h': 8.0, 'Rc': 3.5, 'beta_deg': 30.0, # Obliquité 30° 'alpha_deg': 90.0 # Mur vertical } # Calculs gamma_beta = reduction_factors.gamma_beta_obliquity(cs.parameters['beta_deg']) q_perpendicular = overtopping.mur_vertical( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'] ) q_oblique = q_perpendicular * gamma_beta cs.results = { 'q_perpendicular': q_perpendicular, 'q_oblique': q_oblique, 'gamma_beta': gamma_beta, 'reduction_percent': (1 - gamma_beta) * 100 } return cs
[docs] def case_study_8_westkapelle(): """ Case Study 8: Westkapelle Sea Dike (Netherlands) Digue avec berme large Type: Dike with wide berm References ---------- EurOtop (2018) - Section 8.8 """ cs = CaseStudy( name="Case Study 8: Westkapelle with Berm", location="Westkapelle, Netherlands", description="Sea dike with wide submerged berm" ) cs.parameters = { 'Hm0': 3.0, 'Tm_10': 7.0, 'h': 12.0, 'Rc': 4.0, 'alpha_lower_deg': 20.0, 'alpha_upper_deg': 26.6, 'B_berm': 25.0, # Berme très large 'h_berm': -1.5, # Submergée 'gamma_f': 1.0 # Asphalte lisse } # Calcul avec berme gamma_b = reduction_factors.gamma_b_berm( cs.parameters['Rc'], cs.parameters['Hm0'], cs.parameters['B_berm'], cs.parameters['h_berm'], cs.parameters['gamma_f'] ) q_with_berm = overtopping.digue_talus( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], cs.parameters['alpha_upper_deg'], gamma_b=gamma_b, gamma_f=cs.parameters['gamma_f'] ) # Sans berme pour comparaison q_without_berm = overtopping.digue_talus( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], cs.parameters['alpha_upper_deg'], gamma_f=cs.parameters['gamma_f'] ) cs.results = { 'q_with_berm': q_with_berm, 'q_without_berm': q_without_berm, 'gamma_b': gamma_b, 'reduction_percent': (1 - q_with_berm/q_without_berm) * 100 } return cs
[docs] def case_study_9_zoutkamp(): """ Case Study 9: Zoutkamp (Netherlands) Digue composite complexe avec multiple pentes Type: Complex composite structure with multiple slopes References ---------- EurOtop (2018) - Section 8.9 """ cs = CaseStudy( name="Case Study 9: Zoutkamp Multi-slope", location="Zoutkamp, Netherlands", description="Complex multi-slope structure" ) from openeurotop import special_cases cs.parameters = { 'Hm0': 2.0, 'Tm_10': 5.5, 'h': 6.0, 'Rc': 3.5 } # Configuration multi-pentes slopes_config = [ {'alpha_deg': 18.4, 'h_start': -4, 'h_end': 0}, # 1:3 {'alpha_deg': 26.6, 'h_start': 0, 'h_end': 1.5}, # 1:2 {'alpha_deg': 45.0, 'h_start': 1.5, 'h_end': 3.5} # 1:1 ] gamma_f_sections = [1.0, 0.9, 0.7] # Calcul multi-pentes result = special_cases.multi_slope_structure( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], slopes_config, gamma_f_sections ) cs.results = { 'q_calculated': result['q'], 'alpha_equivalent': result['alpha_equivalent_deg'], 'gamma_f_equivalent': result['gamma_f_equivalent'], 'active_length': result['active_length'] } return cs
[docs] def case_study_10_reykjavik(): """ Case Study 10: Reykjavik Harbour (Iceland) Digue en blocs artificiels (Accropode) Type: Breakwater with artificial blocks References ---------- EurOtop (2018) - Section 8.10 """ cs = CaseStudy( name="Case Study 10: Reykjavik Accropode Breakwater", location="Reykjavik, Iceland", description="Breakwater armored with Accropode blocks" ) cs.parameters = { 'Hm0': 5.5, 'Tm_10': 9.5, 'h': 18.0, 'Rc': 7.0, 'alpha_deg': 33.7, # 1:1.5 'armor_unit': 'accropode', 'Dn50': 4.5 } # Calcul q = overtopping.rubble_mound_breakwater( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], cs.parameters['alpha_deg'], cs.parameters['armor_unit'], cs.parameters['Dn50'] ) gamma_f = reduction_factors.gamma_f_roughness(cs.parameters['armor_unit']) cs.results = { 'q_calculated': q, 'gamma_f': gamma_f, 'armor_type': 'Accropode', 'comment': 'High wave conditions, deep water' } return cs
[docs] def case_study_11_gijon(): """ Case Study 11: Gijón Harbour (Spain) Digue verticale avec caisson Type: Vertical caisson breakwater References ---------- EurOtop (2018) - Section 8.11 """ cs = CaseStudy( name="Case Study 11: Gijón Caisson Breakwater", location="Gijón, Spain", description="Vertical caisson breakwater" ) cs.parameters = { 'Hm0': 4.5, 'Tm_10': 8.5, 'h': 16.0, 'Rc': 5.0, 'h_structure': 21.0, 'impulsive': False # Conditions non-impulsives } # Calcul q = overtopping.mur_vertical( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], cs.parameters['h_structure'], cs.parameters['impulsive'] ) d_star = cs.parameters['h'] / cs.parameters['Hm0'] cs.results = { 'q_calculated': q, 'd_star': d_star, 'regime': 'Non-impulsive' if d_star > 0.3 else 'Potentially impulsive', 'q_measured': 0.0003 # Mesure (m³/s/m) } cs.validation = { 'measured_available': True, 'relative_error': abs(q - cs.results['q_measured']) / cs.results['q_measured'] * 100 } return cs
[docs] def case_study_12_alderney(): """ Case Study 12: Alderney Breakwater (UK) Digue en enrochement avec conditions extrêmes Type: Rock breakwater under extreme conditions References ---------- EurOtop (2018) - Section 8.12 """ cs = CaseStudy( name="Case Study 12: Alderney Extreme Conditions", location="Alderney, Channel Islands", description="Rock breakwater under extreme wave attack" ) from openeurotop import special_cases, validation cs.parameters = { 'Hm0': 6.5, # Conditions extrêmes 'Tm_10': 11.0, 'h': 20.0, 'Rc': 8.0, 'alpha_deg': 38.7, # Pente 1:1.25 'Dn50': 5.0, 'n_layers': 2 } # Vérification des conditions check = special_cases.extreme_conditions_check( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], cs.parameters['alpha_deg'] ) # Calcul q = overtopping.digue_en_enrochement( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], cs.parameters['alpha_deg'], cs.parameters['Dn50'], cs.parameters['n_layers'] ) # Incertitudes from openeurotop import probabilistic unc = probabilistic.uncertainty_overtopping( cs.parameters['Hm0'], cs.parameters['Tm_10'], cs.parameters['h'], cs.parameters['Rc'], cs.parameters['alpha_deg'], structure_type='rough_slope' ) cs.results = { 'q_calculated': q, 'q_lower_90': unc['q_5'], 'q_upper_90': unc['q_95'], 'xi': check['xi'], 'Rc_Hm0': check['Rc_Hm0'], 'conditions': 'Extreme waves' } cs.validation = { 'domain_check': check, 'warnings': check['warnings'] } return cs
[docs] def run_all_case_studies(): """ Exécute tous les case studies et affiche les résultats Returns ------- dict Dictionnaire avec tous les case studies """ case_studies = { 'CS1': case_study_1_zeebrugge(), 'CS2': case_study_2_oostende(), 'CS3': case_study_3_petten(), 'CS4': case_study_4_walcheren(), 'CS5': case_study_5_dover(), 'CS6': case_study_6_samphire_hoe(), 'CS7': case_study_7_scheveningen(), 'CS8': case_study_8_westkapelle(), 'CS9': case_study_9_zoutkamp(), 'CS10': case_study_10_reykjavik(), 'CS11': case_study_11_gijon(), 'CS12': case_study_12_alderney() } return case_studies
[docs] def compare_with_measurements(case_study): """ Compare les résultats calculés avec les mesures (si disponibles) Parameters ---------- case_study : CaseStudy Étude de cas à comparer Returns ------- dict Résultats de comparaison """ if 'validation' not in case_study.__dict__ or not case_study.validation: return {'comparison_available': False} if not case_study.validation.get('measured_available', False): return {'comparison_available': False} return { 'comparison_available': True, 'calculated': case_study.results.get('q_calculated', 0), 'measured': case_study.results.get('q_measured', 0), 'relative_error_percent': case_study.validation.get('relative_error', 0), 'status': case_study.validation.get('status', 'Unknown') }
[docs] def generate_case_studies_report(): """ Génère un rapport complet de tous les case studies Returns ------- str Rapport formaté """ case_studies = run_all_case_studies() lines = [] lines.append("=" * 80) lines.append("EUROTOP 2018 - CASE STUDIES VALIDATION REPORT") lines.append("=" * 80) lines.append("") lines.append("This report presents the 12 case studies from EurOtop (2018) Chapter 8") lines.append("implemented with the OpenEurOtop package.") lines.append("") for cs_id, cs in case_studies.items(): lines.append(str(cs)) lines.append("") # Comparaison si disponible comp = compare_with_measurements(cs) if comp['comparison_available']: lines.append("VALIDATION:") lines.append(f" Measured: {comp['measured']*1000:.3f} l/s/m") lines.append(f" Calculated: {comp['calculated']*1000:.3f} l/s/m") lines.append(f" Error: {comp['relative_error_percent']:.1f}%") lines.append(f" Status: {comp['status']}") lines.append("") lines.append("") lines.append("=" * 80) lines.append("END OF REPORT") lines.append("=" * 80) return "\n".join(lines)