@@ -188,12 +188,11 @@ def run_single_simulation(
188188 warmup_steps = cfg .get_warmup_steps (grid_size )
189189 measurement_steps = cfg .get_measurement_steps (grid_size )
190190
191+
191192 # Warmup phase
192193 for _ in range (warmup_steps ):
193194 model .update ()
194195
195-
196- # FIXME: Remove the two lines below after phase 2.
197196 if with_evolution :
198197 model ._evolution_stopped = True
199198
@@ -219,7 +218,30 @@ def run_single_simulation(
219218 if with_evolution :
220219 stats = get_evolved_stats (model , "prey_death" )
221220 evolved_means .append (stats ["mean" ])
222- evolved_stds .append (stats ["std" ])
221+ evolved_stds .append (stats ["std" ])
222+
223+ # Cluster analysis (at end of measurement)
224+ if step == measurement_steps - 1 :
225+ prey_survived = prey_pops [- 1 ] > min_count
226+ pred_survived = pred_pops [- 1 ] > (min_count // 4 )
227+
228+ if prey_survived :
229+ prey_stats = get_cluster_stats_fast (model .grid , 1 )
230+ cluster_sizes_prey = prey_stats ['sizes' ].tolist ()
231+ largest_fractions_prey .append (prey_stats ['largest_fraction' ])
232+
233+ if pred_survived :
234+ pred_stats = get_cluster_stats_fast (model .grid , 2 )
235+ cluster_sizes_pred = pred_stats ['sizes' ].tolist ()
236+ largest_fractions_pred .append (pred_stats ['largest_fraction' ])
237+
238+ # PCF requires both
239+ if compute_pcf and prey_survived and pred_survived :
240+ max_dist = min (grid_size / 2 , cfg .pcf_max_distance )
241+ pcf_data = compute_all_pcfs_fast (model .grid , max_dist , cfg .pcf_n_bins )
242+ pcf_samples ['prey_prey' ].append (pcf_data ['prey_prey' ])
243+ pcf_samples ['pred_pred' ].append (pcf_data ['pred_pred' ])
244+ pcf_samples ['prey_pred' ].append (pcf_data ['prey_pred' ])
223245
224246 # Compile results
225247 result = {
@@ -375,45 +397,36 @@ def run_phase2(cfg: Config, output_dir: Path, logger: logging.Logger) -> List[Di
375397 """
376398 Phase 2: Self-organization analysis.
377399
378- SOC Hypothesis: When prey_death is allowed to evolve, the population
379- should self-organize toward the critical point (~0.095-0.105 from Phase 1)
380- regardless of initial prey_death value.
400+ SOC Hypothesis: Prey evolve toward critical critical point regardless of initial conditions.
381401
382- Test: Start evolution from different initial prey_death values.
383- If SOC holds, all runs converge to similar final evolved_prey_death.
402+ NOTE: Test is currently start evo from different intial prey_death values (?)
403+ If SOC holds, then all runs converge to the same final prey_death near critical point.
404+
405+ FIXME: This run script needs to be adjusted
384406 """
385407 from joblib import Parallel , delayed
386408
387409 warmup_numba_kernels (cfg .grid_size , directed_hunting = cfg .directed_hunting )
388410
389- # Vary initial prey_death across subcritical to supercritical range
390- # Based on Phase 1: critical point ~0.095-0.105
391- initial_prey_deaths = np .array ([0.02 , 0.04 , 0.06 , 0.08 , 0.10 , 0.12 ])
411+ # Test at multiple prey_birth values
412+ prey_births = cfg .get_prey_births ()
413+
414+ # Vary intial prey_death
415+ initial_prey_deaths = np .linspace (cfg .prey_death_range [0 ], cfg .prey_death_range [1 ], 20 )
392416
393417 jobs = []
394- for initial_pd in initial_prey_deaths :
395- for rep in range (cfg .n_replicates ):
396- params = {"initial_pd" : initial_pd , "phase" : 2 }
397- seed = generate_unique_seed (params , rep )
398-
399- # Fixed prey_birth, varying initial prey_death, evolution ON
400- jobs .append ((
401- cfg .prey_birth , # prey_birth (fixed at 0.2)
402- initial_pd , # prey_death (initial value, will evolve)
403- cfg .predator_birth , # predator_birth (fixed)
404- cfg .predator_death , # predator_death (fixed)
405- cfg .grid_size ,
406- seed ,
407- cfg ,
408- True # with_evolution=True
409- ))
410-
418+ for pb in prey_births :
419+ for initial_pd in initial_prey_deaths :
420+ for rep in range (cfg .n_replicates ):
421+ params = {"pb" : pb , "initial_pd" : initial_pd , "phase" : 2 }
422+ seed = generate_unique_seed (params , rep )
423+ jobs .append ((pb , initial_pd , cfg .predator_birth , cfg .predator_death ,
424+ cfg .grid_size , seed , cfg , True ))
411425
412426 logger .info (f"Phase 2: { len (jobs ):,} simulations" )
413- logger .info (f" Initial prey_death values: { initial_prey_deaths .tolist ()} " )
414- logger .info (f" Replicates per condition: { cfg .n_replicates } " )
415- logger .info (f" Evolution: ENABLED (sd={ cfg .evolve_sd } )" )
416- logger .info (f" Expected convergence: ~0.095-0.105 (critical point)" )
427+ logger .info (f" prey_birth values: { len (prey_births )} " )
428+ logger .info (f" initial prey_death values: { len (initial_prey_deaths )} " )
429+ logger .info (f" Replicates: { cfg .n_replicates } " )
417430
418431 output_jsonl = output_dir / "phase2_results.jsonl"
419432 all_results = []
@@ -429,13 +442,9 @@ def run_phase2(cfg: Config, output_dir: Path, logger: logging.Logger) -> List[Di
429442
430443 meta = {
431444 "phase" : 2 ,
432- "description" : "Self-organization toward criticality (SOC test) " ,
445+ "description" : "Self-organization toward criticality" ,
433446 "n_sims" : len (all_results ),
434447 "initial_prey_deaths" : initial_prey_deaths .tolist (),
435- "prey_birth" : cfg .prey_birth ,
436- "evolve_sd" : cfg .evolve_sd ,
437- "measurement_steps" : cfg .measurement_steps ,
438- "expected_convergence" : "~0.095-0.105" ,
439448 "timestamp" : time .strftime ("%Y-%m-%d %H:%M:%S" ),
440449 }
441450 with open (output_dir / "phase2_metadata.json" , "w" ) as f :
0 commit comments