Disaster Management Simulation

28 views
Skip to first unread message

Gama

unread,
Mar 19, 2025, 1:41:13 AMMar 19
to GAMA
Dear all,

I am working on implementing a GAMA simulation to simulate a disaster management that involves clearing roads from snow using a leader plow and then a helper plow that responds to the leader call under the BDI architecture. However I am facing some issues regarding my clearing logic as I am not sure how to make the plows clear in a logical and consistant  manner that would not make them look as if they are plowing randomly. I have tried numerous attempts since I am working with shapefiles to simulate the roads, one of them being road scores, based on the width of the road and the snow level accumulated, so that roads with higher scores get targeted first, then I have tried multiple targets based on road connectivity but that didn't work either because it caused a back and forth movement of the plows and not an effective execution of the clearing. I feel like GAMA and the way I wish to implement vs. what I actually get as a simulation output is very different and it becomes frustrating. Can you suggest me an effective solution and implementation that would show and mimic a real world scenario of snow clearing across an area of emergency.   
Below is my code for accumulating snow:

reflex snow_accumulation when: allow_snow_accumulation {

if (debug_snow){

//write "Accumulating snow in cycle: " + current_cycle;

}

float new_snow <- 0.0;

ask road {

float random_rate <- base_snow_accumulation_rate * (1.0 + rnd(0.2));

geometry road_line <- shape;

list<point>road_points <- points_on(road_line, 5.0);

loop pt over: road_points {

float new_value <- snow_field[pt] + random_rate;

snow_field[pt] <- new_value;

new_snow <- new_snow + random_rate;

total_snow <- total_snow + new_snow;

}

//save [current_cycle, self.name, total_snow] to:"snow_roads.csv" header:true rewrite:false;

}

diffuse var: snow_field on: snow_field proportion: 0.9;

}



And for the plows, I am now at the point where I have decided to move on with a logic of dividing the roads into chunks and each plow gets assigned a chunk to clear it from snow , but it is not working as expected:

species plows skills: [moving] control: simple_bdi {

// Existing variables

float view_dist <- 200.0;

float speed <- 900 #m/#h;

point target;

road current_road;

road selected_road;

road target_road;

list<road> zone_roads <- [];

path shortest_path;

// Helper plow coordination

plow helper_plow;

list<plow> helper_plows <- [];

float snow_threshold <- 1.0;

bool needs_help <- false;

bool is_waiting <- false;

bool helper_has_arrived <- false;

// Road clearing variables - restructured for better management

list<road> all_roads_to_clear <- []; // Master list of all roads that need clearing

list<road> current_clearing_batch <- []; // Current batch of roads being cleared

int batch_size <- 5; // Number of roads to process in each batch

//Road clearing variables CHUNKS !!!!

map<road, list<point>> road_chunks <- []; // Stores divided chunks per road

map<point, bool> chunk_cleared <- []; // Tracks which chunks are cleared



// Log that the simulation is initializing

init {

write "Simulation started: Road chunking system initialized.";

}


map<plows, point> plow_target <- [];

// road current_clearing_road <- nil;

// list<point> points_to_clear <-[];

// int current_road_index <- 0; // Index of the current road being cleared

// bool road_completed <- false;

// Road state tracking

map<road, float> road_initial_snow <- []; // Initial snow amount on each road

map<road, float> road_cleared_percentage <- []; // Percentage of snow cleared on each road

// Performance tracking

map<plows, float> snow_cleared <- [];

float total_snow_cleared <- 0.0;

list<list<string>> snow_cleared_log <- [];

string assigned_zone <- "Unknown";

// Road evaluation function - enhanced for better decision making

float calculate_road_score(road rd) {

float snow_amount <- snow_field[rd.location];

float priority_score <- 1.5 - (rd.priority * 0.5);

// Enhanced distance calculation with diminishing returns

float distance_to_road <- self.location distance_to rd.location;

float distance_factor <- exp(-distance_to_road / 500) * 0.1;

// Snow factor with threshold consideration

float snow_factor;

if (snow_amount < snow_threshold) {

snow_factor <- 0.1; // Very low priority if snow is below threshold

} else {

snow_factor <- (1 - exp(-snow_amount / 50)) * 0.7;

}

// Road connectivity factor - prioritize connected roads for efficient clearing

float connectivity_factor <- 0.0;

if (current_road != nil) {

list<road> connected_roads <- road_network neighbors_of current_road;

if (connected_roads contains rd) {

connectivity_factor <- 0.2; // Bonus for connected roads

}

}

// Final Score - with connectivity consideration

float final_score <- snow_factor + (distance_factor * 0.2) + priority_score + connectivity_factor;

return final_score;

}

// Initialize snow clearing system

reflex start_plow_movement when: current_cycle = 60 {

do add_desire(initialize_road_clearing);

}

action divide_road_into_chunks(road rd) {

float chunk_size <- 10.0;

list<point> road_points <- [];

list<point> chunks <- []; // Store generated chunks

float distance_traveled <- 0.0;

float total_length <- 0.0;




road_points <- rd.shape.points;

write "Processing Road " + rd + " with " + length(road_points) + " points.";

if (empty(road_points) or length(road_points) < 2) {

write "Warning: Road " + rd + " has too few points.";

return;

}


point last_point <- road_points[0];

// Calculate total road length

loop pt over: road_points {

float segment_distance <- last_point distance_to pt;

total_length <- total_length + segment_distance;

last_point <- pt;

}


write "Debug: Road " + rd + " total length: " + total_length + " meters.";


if (total_length < chunk_size) {

write "Warning: Road " + rd + " is too short for a chunk.";

return;

}

// Reset for chunking process

distance_traveled <- 0.0;

last_point <- road_points[0];


// Loop through points and create chunks

loop pt over: road_points {

float segment_distance <- last_point distance_to pt;

distance_traveled <- distance_traveled + segment_distance;


if (distance_traveled >= chunk_size) {

add pt to: chunks;

chunk_cleared[pt] <- false;

write "Chunk created at: " + pt;

distance_traveled <- 0.0;

}


last_point <- pt;

}


// Store chunks

if (!empty(chunks)) {

put chunks at: rd in: road_chunks;

write "Road " + rd + " divided into " + length(chunks) + " chunks.";

} else {

write "Warning: Road " + rd + " had points but no valid chunks.";

}

write "Finished chunking for road: " + rd;

}



action prepare_next_batch {

current_clearing_batch <- [];

int assigned <- 0;

write "Debug: Running prepare_next_batch...";


// Log how many roads have chunks

write "Debug: Total roads with chunks: " + length(road_chunks.keys);


loop rd over: all_roads_to_clear {

if (rd in road_chunks and !empty(road_chunks[rd])) {

loop chunk over: road_chunks[rd] {

if (chunk_cleared[chunk] = false and !(chunk in plow_target.values)) {

put chunk at: self in: plow_target;

assigned <- assigned + 1;

write name + " assigned to chunk at " + chunk;

break;

}

}

}

if (assigned >= 1) { break; } // Assign only one chunk per plow for now

}


// if (assigned = 0) {

// write name + " found no new chunks, retrying next cycle.";

// do prepare_next_batch;

// } else {

// do add_desire(clear_current_batch);

// }



}

plan clear_current_batch intention: clear_current_batch {

// If no target, get new chunk

if (!(self in plow_target) or chunk_cleared[plow_target[self]]) {

do remove_intention(clear_current_batch, true);

do prepare_next_batch();

return;

}


// Move to assigned chunk

target <- plow_target[self];

path followed_path <- goto(target: target, on: road_network, speed: speed);


// Clear snow only in assigned chunk

if (followed_path != nil and followed_path.shape != nil) {

float current_snow <- snow_field[location];

if (current_snow > 0) {

float snow_removed <- min(current_snow, 30.0);

snow_field[location] <- max(0, current_snow - snow_removed);

// Mark chunk as cleared if no snow remains

if (snow_field[location] = 0) {

chunk_cleared[plow_target[self]] <- true;

write name + " completed clearing chunk.";

//remove plow_targets[self]; // Remove plow's assignment

do prepare_next_batch(); // Assign next chunk

}

}

}

}


plan call_for_help intention: call_for_help {

if (length(helper_plows) > 0) {

is_waiting <- false;

helper_has_arrived <- true;

do remove_intention(call_for_help, true);

write name + " received help from " + length(helper_plows) + " helper plows";

}

}

// Perception of roads

perceive target: road {

float current_snow <- snow_field[location];

}

aspect default {

draw rectangle(6, 12) rotated_by (heading + 90) color: rgb(255, 95, 21) depth: 1 size: 20;

if (target != nil) {

// Visual indicators can be added here

}

}

}


Thank you.

Reply all
Reply to author
Forward
0 new messages