import numpy as np import pandas as pd DAMAGE_STATES = ['none', 'minor', 'severe', 'collapse'] def generate_buildings(n_buildings, diameter_km, seed=42): np.random.seed(seed) buildings = [] radius = diameter_km / 2 for i in range(n_buildings): angle = np.random.uniform(0, 2 * np.pi) r = np.random.uniform(0.5, radius) x = r * np.cos(angle) y = r * np.sin(angle) distance = r building_type = np.random.choice( ['wood', 'concrete', 'steel'], p=[0.5, 0.3, 0.2] ) if building_type == 'wood': occupancy = int(np.random.uniform(10, 100)) elif building_type == 'concrete': occupancy = int(np.random.uniform(50, 300)) else: occupancy = int(np.random.uniform(100, 500)) buildings.append({ 'building_id': i, 'x': round(x, 2), 'y': round(y, 2), 'distance_km': round(distance, 2), 'building_type': building_type, 'occupancy': occupancy }) return pd.DataFrame(buildings) def compute_damage_probabilities(distance, building_type, magnitude, alpha_params): magnitude_scale = (magnitude - 5.0) / 3.0 magnitude_scale = max(0.1, min(magnitude_scale, 2.0)) base_damage = np.exp(-distance / (15.0 * magnitude_scale)) alpha = alpha_params[building_type] p_collapse = alpha * base_damage * 0.30 * magnitude_scale p_severe = alpha * base_damage * 0.25 * magnitude_scale p_minor = alpha * base_damage * 0.20 * magnitude_scale total = p_collapse + p_severe + p_minor if total > 0.95: scale = 0.95 / total p_collapse *= scale p_severe *= scale p_minor *= scale p_none = 1 - (p_collapse + p_severe + p_minor) return np.array([p_none, p_minor, p_severe, p_collapse]) def simulate_damage(buildings_df, magnitude, alpha_params, seed=42): np.random.seed(seed) buildings = buildings_df.copy() for idx, building in buildings.iterrows(): probs = compute_damage_probabilities( building['distance_km'], building['building_type'], magnitude, alpha_params ) damage_state = np.random.choice(DAMAGE_STATES, p=probs) buildings.at[idx, 'true_damage'] = damage_state buildings.at[idx, 'p_none'] = round(probs[0], 4) buildings.at[idx, 'p_minor'] = round(probs[1], 4) buildings.at[idx, 'p_severe'] = round(probs[2], 4) buildings.at[idx, 'p_collapse'] = round(probs[3], 4) return buildings def create_scenario(n_buildings=100, diameter_km=40, magnitude=6.5, alpha_params=None, seed=42): if alpha_params is None: alpha_params = {'wood': 1.5, 'concrete': 1.0, 'steel': 0.7} buildings = generate_buildings(n_buildings, diameter_km, seed) scenario = simulate_damage(buildings, magnitude, alpha_params, seed) return scenario