@@ -508,60 +508,79 @@ def run_phase3(cfg: Config, output_dir: Path, logger: logging.Logger) -> List[Di
508508
509509def run_phase4 (cfg : Config , output_dir : Path , logger : logging .Logger ) -> List [Dict ]:
510510 """
511- Phase 4: Sensitivity analysis.
512- - Vary predator_birth and predator_death
513- - For each combo, sweep prey_death
514-
515-
516- NOTE: This phase should be subjected to changes depeding on what we are interested in varying
517- in terms of parameters.
511+ Phase 4: Global Sensitivity Analysis.
512+ Vary: prey_birth, prey_death, predator_birth, predator_death
513+ Range: 0-1 (11 values each)
514+ Reps: 10
515+ Grid size: 250
518516 """
519517 from joblib import Parallel , delayed
518+ import itertools
520519
521520 warmup_numba_kernels (cfg .grid_size , directed_hunting = cfg .directed_hunting )
522521
523- prey_deaths = np .linspace (cfg .prey_death_range [0 ], cfg .prey_death_range [1 ], cfg .n_prey_death )
522+ # Define the global sweep values
523+ sweep_values = np .linspace (0.0 , 1.0 , 11 )
524+
525+ # Logging
526+ logger .info (f"Phase 4: Full 4D Parameter Sweep" )
527+ logger .info (f" Parameters: prey_birth, prey_death, pred_birth, pred_death" )
528+ logger .info (f" Range: 0.0 to 1.0 (11 steps)" )
529+ logger .info (f" Grid Size: { cfg .grid_size } " )
530+ logger .info (f" Replicates: { cfg .n_replicates } " )
531+
532+ param_grid = itertools .product (sweep_values , repeat = 4 )
524533
525534 jobs = []
526- for pred_b in cfg .predator_birth_values :
527- for pred_d in cfg .predator_death_values :
528- for pd in prey_deaths :
529- for rep in range (cfg .n_replicates ):
530- params = {"pred_b" : pred_b , "pred_d" : pred_d , "pd" : pd }
531-
532- # Non-evolution
533- seed = generate_unique_seed (params , rep )
534- jobs .append ((cfg .prey_birth , pd , pred_b , pred_d ,
535- cfg .grid_size , seed , cfg , False ))
536-
537- # Evolution
538- evo_seed = generate_unique_seed (params , rep + 1_000_000 )
539- jobs .append ((cfg .prey_birth , pd , pred_b , pred_d ,
540- cfg .grid_size , evo_seed , cfg , True ))
541-
542- logger .info (f"Phase 4: { len (jobs ):,} simulations" )
543- logger .info (f" predator_birth: { cfg .predator_birth_values } " )
544- logger .info (f" predator_death: { cfg .predator_death_values } " )
545535
536+ for pb , pd , pred_b , pred_d in param_grid :
537+ for rep in range (cfg .n_replicates ):
538+ # Create params dict for unique seed generation
539+ params_id = {
540+ "pb" : pb ,
541+ "pd" : pd ,
542+ "pred_b" : pred_b ,
543+ "pred_d" : pred_d ,
544+ "rep" : rep
545+ }
546+ seed = generate_unique_seed (params_id , rep )
547+
548+ # Job Signature:
549+ # (prey_birth, prey_death, predator_birth, predator_death, grid_size, seed, cfg, with_evolution)
550+ jobs .append ((
551+ pb ,
552+ pd ,
553+ pred_b ,
554+ pred_d ,
555+ cfg .grid_size ,
556+ seed ,
557+ cfg ,
558+ False
559+ ))
560+
561+ logger .info (f" Total simulations: { len (jobs ):,} " )
546562 output_jsonl = output_dir / "phase4_results.jsonl"
547563 all_results = []
548564
549565 with open (output_jsonl , "w" , encoding = "utf-8" ) as f :
550566 executor = Parallel (n_jobs = cfg .n_jobs , return_as = "generator" )
551567 tasks = (delayed (run_single_simulation )(* job ) for job in jobs )
552568
553- for result in tqdm (executor (tasks ), total = len (jobs ), desc = "Phase 4" ):
569+ # tqdm shows progress for the massive job list
570+ for result in tqdm (executor (tasks ), total = len (jobs ), desc = "Phase 4 (4D Sweep)" ):
554571 f .write (json .dumps (result , default = str ) + "\n " )
555572 f .flush ()
556573 all_results .append (result )
557574
575+ # 4. Save Metadata
558576 meta = {
559577 "phase" : 4 ,
560- "description" : "Sensitivity analysis " ,
561- "predator_birth_values " : list ( cfg . predator_birth_values ),
562- "predator_death_values " : list ( cfg . predator_death_values ) ,
578+ "description" : "Global 4D Sensitivity Analysis " ,
579+ "sweep_values " : sweep_values . tolist ( ),
580+ "parameters_varied " : [ "prey_birth" , "prey_death" , "predator_birth" , "predator_death" ] ,
563581 "n_sims" : len (all_results ),
564582 "timestamp" : time .strftime ("%Y-%m-%d %H:%M:%S" ),
583+ "config" : asdict (cfg ),
565584 }
566585 with open (output_dir / "phase4_metadata.json" , "w" ) as f :
567586 json .dump (meta , f , indent = 2 , default = str )
0 commit comments