"""Wave front propagation map visualization""" import streamlit as st import numpy as np import matplotlib.pyplot as plt from matplotlib.patches import Circle import plotly.graph_objects as go from typing import Optional, Tuple def create_synthetic_bathymetry(size: int = 100) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: """Create synthetic bathymetry for demonstration""" x = np.linspace(-500, 500, size) y = np.linspace(-500, 500, size) X, Y = np.meshgrid(x, y) # Simple continental shelf profile r = np.sqrt(X**2 + Y**2) depth = -5000 + 0.1 * r # Depth increases with distance depth = np.clip(depth, -6000, 0) return X, Y, depth def create_wave_front(r: np.ndarray, t: float, speed: float = 0.5) -> np.ndarray: """Create synthetic wave front""" return 5 * np.exp(-(r - 300 - speed * t)**2 / 5000) def display_wave_front_map(zone: str = "global", show_bathymetry: bool = True, show_front: bool = True, time_step: int = 0): """Display interactive wave front map""" # Create data X, Y, depth = create_synthetic_bathymetry() r = np.sqrt(X**2 + Y**2) wave = create_wave_front(r, time_step) # Create figure fig, ax = plt.subplots(figsize=(12, 8)) if show_bathymetry: contour = ax.contourf(X, Y, depth, levels=20, cmap='Blues_r', alpha=0.6) plt.colorbar(contour, ax=ax, label='Depth (m)') if show_front: front_contour = ax.contour(X, Y, wave, levels=[2, 4, 6], colors='red', linewidths=2) ax.clabel(front_contour, inline=True, fontsize=10) # Mark shoreline ax.axhline(y=0, color='brown', linestyle='-', linewidth=2, label='Shoreline') # Add coast coast_x = np.linspace(-500, 500, 100) coast_y = 50 * np.exp(-coast_x**2 / 50000) ax.fill_between(coast_x, 0, coast_y, color='green', alpha=0.3, label='Land') # Labels and formatting ax.set_xlabel('Distance (km)', fontsize=12) ax.set_ylabel('Distance (km)', fontsize=12) ax.set_title(f'Tsunami Wave Front Propagation - {zone}', fontsize=14) ax.grid(True, alpha=0.3) ax.legend() # Set limits ax.set_xlim(-500, 500) ax.set_ylim(-500, 200) # Add scale bar ax.plot([-400, -300], [-450, -450], 'k-', linewidth=3) ax.text(-350, -470, '100 km', ha='center') return fig def display_interactive_map(): """Display interactive map with Plotly""" # Create data x = np.linspace(-500, 500, 100) y = np.linspace(-500, 200, 70) X, Y = np.meshgrid(x, y) # Bathymetry r = np.sqrt(X**2 + Y**2) depth = -5000 + 0.1 * r depth = np.clip(depth, -6000, 0) # Wave front wave = 5 * np.exp(-(r - 300)**2 / 5000) # Create figure fig = go.Figure() # Add bathymetry heatmap fig.add_trace(go.Contour( z=depth, x=x, y=y, colorscale='Blues', showscale=True, colorbar=dict(title="Depth (m)"), name="Bathymetry" )) # Add wave front contours fig.add_trace(go.Contour( z=wave, x=x, y=y, contours=dict( coloring='none', showlabels=True, labelfont=dict(size=12, color='red') ), line=dict(color='red', width=2), showscale=False, name="Wave Front" )) # Add shoreline fig.add_shape( type="line", x0=-500, y0=0, x1=500, y1=0, line=dict(color="brown", width=3, dash="solid"), name="Shoreline" ) # Update layout fig.update_layout( title="Tsunami Wave Front - Interactive Map", xaxis_title="Distance (km)", yaxis_title="Distance (km)", width=800, height=600, hovermode='closest' ) return fig def get_front_properties(wcc: float = 1.31, hfsi: float = 0.63, distance: float = 180) -> dict: """Get wave front properties""" # Calculate ETA based on distance and speed speed = 200 # m/s approximate eta_minutes = distance * 1000 / speed / 60 return { "celerity": wcc, "stability": hfsi, "distance_to_shore_km": distance, "eta_minutes": eta_minutes, "status": "ALERT" if hfsi < 0.6 else "MONITOR", "front_width_km": 50, "amplification_factor": 2.5 } def display_front_properties_panel(properties: dict): """Display wave front properties panel""" col1, col2 = st.columns(2) with col1: st.metric("Celerity (WCC)", f"{properties['celerity']:.2f}") st.metric("Distance to Shore", f"{properties['distance_to_shore_km']} km") st.metric("Front Width", f"{properties['front_width_km']} km") with col2: st.metric("Stability (HFSI)", f"{properties['stability']:.2f}") st.metric("ETA to Landfall", f"{properties['eta_minutes']:.0f} min") st.metric("Amplification", f"{properties['amplification_factor']:.1f}x") # Status indicator if properties['stability'] < 0.4: st.error("⚠️ CRITICAL: Breaking imminent") elif properties['stability'] < 0.6: st.warning("⚠️ ALERT: Front unstable") elif properties['stability'] < 0.8: st.info("ℹ️ MONITOR: Weakly unstable") else: st.success("✅ SAFE: Stable front")