forked from SachitDeshmukh/territory-simulation-model
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathterritory_simulate.py
More file actions
136 lines (109 loc) · 6.49 KB
/
territory_simulate.py
File metadata and controls
136 lines (109 loc) · 6.49 KB
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
import os # Importing OS module for file operations
import pandas as pd # Import Pandas for data processing
import numpy as np # Import Numpy
import logging # Logging setup for monitoring execution
import time # Time module for delays
import jpype # Interface for Java-Python interactions
from datetime import datetime # Date/time handling utilities
from itertools import product # Cartesian product for param combinations
from joblib import Parallel, delayed # Parallel execution for simulations
from pynetlogo import NetLogoLink # Interface for NetLogo simulations
import territory_config # To import all GLOBALS
# Function to introduce a delay
def rest():
time.sleep(3)
# Generate all possible parameter combinations
def gen_param_combos(all_params):
return [dict(zip(all_params.keys(), values)) for values in product(*all_params.values())]
# Save simulation data in CSV and Excel formats
def save_data(data, backup_file_name, sheet_prefix):
data.to_csv(f"{backup_file_name}.csv")
xlsx_file_name = f"{territory_config.file_name}_{datetime.now().strftime('%Y-%m-%d')}.xlsx"
mode = 'a' if os.path.exists(xlsx_file_name) else 'w'
with pd.ExcelWriter(xlsx_file_name, mode=mode, engine='openpyxl') as writer:
data.to_excel(writer, sheet_name=f"{sheet_prefix}_{datetime.now().strftime("%H-%M-%S")}", index=False)
logging.info(f"RESULTED SAVED TO {xlsx_file_name}")
# NetLogo simulation class handling execution
class NetLogoSim:
def __init__(self, parameters, runs, ticks):
self.params = parameters # Store parameter combinations
self.runs = runs # Define the number of simulation runs
self.max_ticks = ticks
self.tick_start = territory_config.tick_start
self.tick_step = territory_config.tick_step
# Run simulation for a parameter combination
def params_stability(self, combo, iter):
netlogo = NetLogoLink(gui=False, netlogo_home=territory_config.netlogo_exe)
netlogo.load_model(territory_config.model)
combo_serial = self.params.index(combo)
try:
for param, value in combo.items():
netlogo.command(f"set {param} {value}") # Set model parameters
netlogo.command("setup") # Initialize simulation
results = {
"Combo": combo_serial,
"Iteration": iter+1,
"Green-Count-start": combo.get("num-green-clan"),
"Blue-Count-start": combo.get("num-blue-clan")
}
for tick_target in range(self.tick_start, self.max_ticks, self.tick_step):
while netlogo.report("ticks") < tick_target and netlogo.report("count turtles") > 0:
netlogo.command("go")
if netlogo.report("count turtles") > 0:
results[f"Green-Territory-{tick_target}"] = netlogo.report("count green-patches")
results[f"Blue-Territory-{tick_target}"] = netlogo.report("count blue-patches")
else:
# If all turtles are dead before this tick, record NA
results[f"Green-Territory-{tick_target}"] = np.nan
results[f"Blue-Territory-{tick_target}"] = np.nan
logging.info(f"Combination {combo_serial} iteration {iter+1} complete.")
except Exception as e:
logging.error(f"Simulation error with params {combo}: {e}")
return None # Ensure failed runs don’t corrupt output
finally:
netlogo.kill_workspace() # Close NetLogo workspace
return results
# Filter valid results and compute averages
def filter_params(self, results):
results = [res for res in results if res is not None]
result_data = pd.DataFrame(results)
for i in range(self.tick_start, self.max_ticks, self.tick_step):
green_avg_territory = result_data.groupby("Combo")[f"Green-Territory-{i}"].mean().reset_index()
green_avg_territory.rename(columns={f"Green-Territory-{i}": f"Green-Avg-Territory-{i}"}, inplace=True)
blue_avg_territory = result_data.groupby("Combo")[f"Blue-Territory-{i}"].mean().reset_index()
blue_avg_territory.rename(columns={f"Blue-Territory-{i}": f"Blue-Avg-Territory-{i}"}, inplace=True)
result_data = result_data.merge(green_avg_territory, on="Combo").merge(blue_avg_territory, on="Combo")
return result_data
def clean_data_ratio(self, dataset):
dataset = pd.DataFrame(dataset)
dataset = dataset.drop_duplicates(subset=["Combo", "Blue-Count-start", "Green-Count-start"])
clean_data = dataset[["Combo", "Blue-Count-start", "Green-Count-start"]].copy()
for i in range(self.tick_start, self.max_ticks, self.tick_step):
clean_data[f"{i}_avg_ratio"] = (dataset[f"Green-Avg-Territory-{i}"]/dataset[f"Blue-Avg-Territory-{i}"]).fillna(1.0)
return clean_data
# Main execution function
def simulate():
os.chdir(territory_config.main_dir) # Change working directory to main directory
if not jpype.isJVMStarted():
jpype.startJVM() # Start Java Virtual Machine
try:
logging.info(f"Starting iteration...")
param_combinations = gen_param_combos(territory_config.input_parameters)
start_time_temp = datetime.now()
simulation = NetLogoSim(param_combinations, runs=territory_config.runs, ticks=territory_config.max_ticks) # Initialize simulation object
iter_data = Parallel(n_jobs=territory_config.parallel_jobs, backend="multiprocessing")(
delayed(simulation.params_stability)(combo, x) for combo in simulation.params for x in range(simulation.runs)
) # Run simulations in parallel
end_time_temp = datetime.now()
time.sleep(3)
total_time = (end_time_temp - start_time_temp).total_seconds()
logging.info(f"Time taken: {total_time}.")
finally:
logging.info("CLEANING UP RESOURCES...")
jpype.shutdownJVM() # Shut down Java Virtual Machine
logging.info("ALL SIMULATIONS COMPLETE.")
territory_results = simulation.filter_params(iter_data)
save_data(territory_results, backup_file_name="Territory_output_raw", sheet_prefix="H00_RAW")
clean_results = simulation.clean_data_ratio(territory_results)
save_data(clean_results, backup_file_name="Territory_output_clean", sheet_prefix="H00_CLEAN")
return clean_results