3333from typing import Dict , List , Tuple , Optional
3434import warnings
3535
36+ project_root = str (Path (__file__ ).parents [1 ])
37+ if project_root not in sys .path :
38+ sys .path .insert (0 , project_root )
39+
3640try :
3741 from scripts .numba_optimized import (
3842 compute_pcf_periodic_fast ,
@@ -80,8 +84,8 @@ class Config:
8084 # Simulation length
8185 warmup_steps : int = 200
8286 measurement_steps : int = 300
83- cluster_samples : int = 10
84- cluster_interval : int = 100
87+ cluster_samples : int = 3
88+ cluster_interval : int = 1000
8589
8690 # Ecological parameters
8791 evolve_sd : float = 0.10
@@ -104,7 +108,7 @@ class Config:
104108 synchronous : bool = False
105109
106110 # Snapshot settings
107- save_snapshots : bool = True
111+ save_snapshots : bool = False
108112 snapshot_times : Tuple [int , ...] = (50 , 100 , 150 , 200 , 250 )
109113
110114 n_jobs : int = - 1 # -1 = all available cores
@@ -209,6 +213,7 @@ def get_evolution_metadata(model)->Dict:
209213 return metadata
210214
211215
216+
212217def collect_comprehensive_metrics (model , step : int ) -> Dict :
213218 """Collect comprehensive metrics using built-in CA methods."""
214219 metrics = {
@@ -581,6 +586,39 @@ def save_diagnostic_snapshot(
581586 plt .savefig (output_path / f'diagnostic_{ run_id } .png' , dpi = 120 , bbox_inches = 'tight' )
582587 plt .close ()
583588
589+
590+ def save_sweep_binary (results : List [Dict ], output_path : Path ):
591+ """Saves high-volume sweep data to compressed .npz to avoid JSON overhead."""
592+ # We use a dictionary to map each run to its own key-space
593+ data_to_save = {}
594+ for i , res in enumerate (results ):
595+ prefix = f"run_{ i } _"
596+ for key , val in res .items ():
597+ # np.savez handles numbers and arrays perfectly;
598+ # objects/dicts are converted to array-wrappers
599+ data_to_save [f"{ prefix } { key } " ] = np .array (val )
600+
601+ np .savez_compressed (output_path , ** data_to_save )
602+
603+ def warmup_numba_kernels (grid_size : int ):
604+ """Compiles kernels in the main thread so workers load from cache instantly."""
605+ logging .info (f"Warming up Numba kernels for { grid_size } x{ grid_size } grid..." )
606+
607+ # Create dummy data structures matching real types
608+ dummy_grid = np .zeros ((grid_size , grid_size ), dtype = np .int32 )
609+ p_death_arr = np .full ((grid_size , grid_size ), 0.05 , dtype = np .float64 )
610+ dr = np .array ([- 1 , 1 , 0 , 0 ], dtype = np .int32 )
611+ dc = np .array ([0 , 0 , - 1 , 1 ], dtype = np .int32 )
612+
613+ # Trigger Simulation JIT
614+ from scripts .numba_optimized import _pp_async_kernel , _compute_distance_histogram
615+ _ = _pp_async_kernel (dummy_grid , p_death_arr , 0.2 , 0.05 , 0.2 , 0.1 , dr , dc , 0.1 , 0.001 , 0.1 , False )
616+
617+ # Trigger PCF JIT
618+ pos = np .ascontiguousarray (np .argwhere (dummy_grid == 0 )[:10 ], dtype = np .float64 )
619+ if len (pos ) > 0 :
620+ _ = _compute_distance_histogram (pos , pos , float (grid_size ), float (grid_size ), 20.0 , 20 , True )
621+
584622
585623##########################################################################
586624# Main Simulation Function
@@ -943,6 +981,8 @@ def run_single_simulation_fss(
943981def run_2d_sweep (cfg , output_dir , logger ) -> List [Dict ]:
944982 """Run full 2D parameter sweep with optional diagnostic snapshots."""
945983 from joblib import Parallel , delayed
984+ if USE_NUMBA :
985+ warmup_numba_kernels (cfg .default_grid )
946986
947987 prey_births = cfg .get_prey_births ()
948988 prey_deaths = cfg .get_prey_deaths ()
@@ -987,14 +1027,22 @@ def run_2d_sweep(cfg, output_dir, logger) -> List[Dict]:
9871027 for pb , pd , gs , seed , evo , save_diag in jobs
9881028 )
9891029
990- output_file = output_dir / "sweep_results.json"
991- with open (output_file , "w" ) as f :
992- json .dump (results , f )
993- logger .info (f"Saved to { output_file } " )
1030+ # REPLACE THE JSON BLOCK WITH THIS:
1031+ output_file = output_dir / "sweep_results.npz"
1032+ save_sweep_binary (results , output_file )
1033+
1034+ # Save a tiny 'metadata' JSON just for quick human reading
1035+ meta = {
1036+ "n_sims" : len (results ),
1037+ "timestamp" : time .strftime ("%Y-%m-%d %H:%M:%S" ),
1038+ "grid_size" : cfg .default_grid
1039+ }
1040+ with open (output_dir / "sweep_metadata.json" , "w" ) as f :
1041+ json .dump (meta , f , indent = 2 )
9941042
1043+ logger .info (f"SUCCESS: Saved binary sweep results to { output_file } " )
9951044 return results
9961045
997-
9981046def run_sensitivity (
9991047 cfg : Config , output_dir : Path , logger : logging .Logger
10001048) -> List [Dict ]:
0 commit comments