File size: 9,277 Bytes
63cc479
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
import asyncio
import random
import math
import networkx as nx

from app.core.state import sim_state
from app.core.config import DATA_GEN_RATE_MB_STEP, MAX_BUFFER_MB, WIFI_RANGE_METERS
from app.simulation.utils import euclidean_dist

def init_sim_entities():
    nodes = list(sim_state.graph.nodes(data=True))
    sim_state.hubs = []
    sim_state.vehicles = []
    sim_state.step = 0
    sim_state.total_generated_mb = 0.0
    sim_state.total_offloaded_mb = 0.0
    sim_state.total_buffer_overflows = 0
    sim_state.priority_latency_sum = 0
    sim_state.priority_events_completed = 0
    sim_state.recent_events = []

    center_lat = 33.6515
    center_lon = 73.0801
    top_right_nodes = [n for n in nodes if n[1]["y"] > center_lat + 0.005 and n[1]["x"] > center_lon + 0.005]
    if len(top_right_nodes) >= 2 and sim_state.num_hubs >= 2:
        tr_hubs = random.sample(top_right_nodes, 2)
        other_nodes = [n for n in nodes if n not in tr_hubs]
        hub_nodes = tr_hubs + random.sample(other_nodes, sim_state.num_hubs - 2)
    else:
        hub_nodes = random.sample(nodes, sim_state.num_hubs)

    for hid, node in enumerate(hub_nodes):
        sim_state.hubs.append({
            "id": hid,
            "lat": node[1]["y"],
            "lon": node[1]["x"],
            "range": WIFI_RANGE_METERS,
            "rate": random.choice([1.0, 2.5, 5.0]),
            "active": False,
            "online": True,
            "total_offloaded_mb": 0.0
        })
    
    node_ids = list(sim_state.graph.nodes())
    for vid in range(sim_state.num_vehicles):
        n1 = random.choice(node_ids)
        n2 = random.choice(node_ids)
        try:
            path = nx.shortest_path(sim_state.graph, n1, n2, weight='length')
        except:
            path = [n1]

        start_data = sim_state.graph.nodes[n1]
        target_lat = start_data["y"]
        target_lon = start_data["x"]
        
        if len(path) > 1:
            next_node = path[1]
            target_lat = sim_state.graph.nodes[next_node]["y"]
            target_lon = sim_state.graph.nodes[next_node]["x"]

        base_spd = random.uniform(0.00004, 0.00008)
        sim_state.vehicles.append({
            "id": vid,
            "lat": start_data["y"],
            "lon": start_data["x"],
            "buffer_mb": 0.0,
            "routine_mb": 0.0,
            "priority_mb": 0.0,
            "panic": False,
            "target_lat": target_lat,
            "target_lon": target_lon,
            "path": path,
            "path_idx": 1 if len(path) > 1 else 0,
            "base_speed": base_spd,
            "speed": base_spd,
            "events": []
        })

async def simulation_loop():
    while True:
        if sim_state.running:
            run_step()
        await asyncio.sleep(0.05) 

def run_step():
    sim_state.step += 1
    
    for hub in sim_state.hubs:
        hub["active"] = False
        if random.random() < 0.001:
            hub["online"] = not hub["online"]

    node_ids = list(sim_state.graph.nodes())
    edge_traffic = {}
    for v in sim_state.vehicles:
        if v["path"] and v["path_idx"] < len(v["path"]):
            prev = v["path"][v["path_idx"]-1] if v["path_idx"] > 0 else v["path"][0]
            curr = v["path"][v["path_idx"]]
            edge_traffic[(prev, curr)] = edge_traffic.get((prev, curr), 0) + 1

    EVENT_TYPES = ["Pothole", "Minor Crash", "Debris", "Speed Trap", "Traffic Jam"]

    for v in sim_state.vehicles:
        v["routine_mb"] += DATA_GEN_RATE_MB_STEP
        sim_state.total_generated_mb += DATA_GEN_RATE_MB_STEP
        
        if v["path"] and v["path_idx"] < len(v["path"]):
            prev = v["path"][v["path_idx"]-1] if v["path_idx"] > 0 else v["path"][0]
            curr = v["path"][v["path_idx"]]
            vehicles_on_edge = edge_traffic.get((prev, curr), 1)
            v["speed"] = v["base_speed"] / max(1, vehicles_on_edge)

        if random.random() < sim_state.event_rate:
            evt_type = random.choice(EVENT_TYPES)
            evt_size = random.uniform(5.0, 10.0)
            v["events"].append({"type": evt_type, "size": evt_size, "timestamp": sim_state.step})
            v["priority_mb"] += evt_size
            sim_state.total_generated_mb += evt_size

        total_buf = v["routine_mb"] + v["priority_mb"]
        if total_buf > MAX_BUFFER_MB:
            overflow_amt = total_buf - MAX_BUFFER_MB
            dropped_mb = min(overflow_amt, v["routine_mb"])
            if dropped_mb > 0:
                v["routine_mb"] -= dropped_mb
                sim_state.total_buffer_overflows += 1
        
        v["buffer_mb"] = v["routine_mb"] + v["priority_mb"]

        dx = v["target_lon"] - v["lon"]
        dy = v["target_lat"] - v["lat"]
        dist = math.sqrt(dx*dx + dy*dy)
        if dist < v["speed"]:
            v["lon"] = v["target_lon"]
            v["lat"] = v["target_lat"]
            v["path_idx"] += 1
            if v["path_idx"] < len(v["path"]):
                next_node = v["path"][v["path_idx"]]
                v["target_lat"] = sim_state.graph.nodes[next_node]["y"]
                v["target_lon"] = sim_state.graph.nodes[next_node]["x"]
            else:
                start_node = v["path"][-1] if v["path"] else random.choice(node_ids)
                end_node = random.choice(node_ids)
                try:
                    new_path = nx.shortest_path(sim_state.graph, start_node, end_node, weight='length')
                except:
                    new_path = [start_node]
                
                v["path"] = new_path
                v["path_idx"] = 1
                if len(new_path) > 1:
                    next_node = new_path[1]
                    v["target_lat"] = sim_state.graph.nodes[next_node]["y"]
                    v["target_lon"] = sim_state.graph.nodes[next_node]["x"]
                else:
                    v["target_lat"] = v["lat"]
                    v["target_lon"] = v["lon"]
        else:
            v["lon"] += (dx/dist) * v["speed"]
            v["lat"] += (dy/dist) * v["speed"]
        
        closest_hub = None
        min_dist = float('inf')
        for hub in sim_state.hubs:
            d = euclidean_dist(v["lat"], v["lon"], hub["lat"], hub["lon"])
            if d < min_dist:
                min_dist = d
                closest_hub = hub
                
        if closest_hub and min_dist <= closest_hub["range"]:
            if not closest_hub["online"]:
                v["panic"] = True
            else:
                skip_offload = False
                
                if sim_state.algorithm == "predictive" and not v.get("panic", False) and (v["routine_mb"] + v["priority_mb"]) < MAX_BUFFER_MB * 0.8:
                    future_nodes = v["path"][v["path_idx"]:v["path_idx"]+10]
                    for f_node in future_nodes:
                        ny = sim_state.graph.nodes[f_node]["y"]
                        nx_coord = sim_state.graph.nodes[f_node]["x"]
                        for h in sim_state.hubs:
                            if h["online"] and h["rate"] > closest_hub["rate"] and euclidean_dist(ny, nx_coord, h["lat"], h["lon"]) <= h["range"]:
                                skip_offload = True
                                break
                        if skip_offload:
                            break
                
                if not skip_offload:
                    amt_to_offload = closest_hub["rate"]
                    
                    while v["events"] and amt_to_offload > 0:
                        evt = v["events"][0]
                        if evt["size"] <= amt_to_offload:
                            amt_to_offload -= evt["size"]
                            v["priority_mb"] -= evt["size"]
                            sim_state.total_offloaded_mb += evt["size"]
                            closest_hub["total_offloaded_mb"] += evt["size"]
                            latency = sim_state.step - evt["timestamp"]
                            sim_state.priority_latency_sum += latency
                            sim_state.priority_events_completed += 1
                            v["events"].pop(0)
                            sim_state.recent_events.insert(0, f"[{sim_state.step}] Veh {v['id']} offloaded '{evt['type']}' to Hub {closest_hub['id']} (Lat: {latency}s)")
                        else:
                            evt["size"] -= amt_to_offload
                            v["priority_mb"] -= amt_to_offload
                            sim_state.total_offloaded_mb += amt_to_offload
                            closest_hub["total_offloaded_mb"] += amt_to_offload
                            amt_to_offload = 0
                            
                    if amt_to_offload > 0 and v["routine_mb"] > 0:
                        off_routine = min(v["routine_mb"], amt_to_offload)
                        v["routine_mb"] -= off_routine
                        sim_state.total_offloaded_mb += off_routine
                        closest_hub["total_offloaded_mb"] += off_routine
                        
                    closest_hub["active"] = True
                    v["panic"] = False 
            
            v["buffer_mb"] = v["routine_mb"] + v["priority_mb"]
            sim_state.recent_events = sim_state.recent_events[:30]