Skip to content

Commit 9cd39c5

Browse files
committed
added notes on my config and phase exp questions to be reviewed.
1 parent 71a553b commit 9cd39c5

6 files changed

Lines changed: 49 additions & 155 deletions

File tree

benchmarks/benchmark.txt

Lines changed: 0 additions & 110 deletions
This file was deleted.

benchmarks/benchmark_plots.png

-151 KB
Binary file not shown.

benchmarks/simulation_profile.txt

Lines changed: 0 additions & 21 deletions
This file was deleted.

models/CA.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
sys.path.insert(0, str(Path(__file__).parent.parent))
1616

1717
from models.numba_optimized import PPKernel, set_numba_seed
18-
from models.cluster_analysis import ClusterAnalyzer
1918

2019
# Module logger
2120
logger = logging.getLogger(__name__)

models/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def estimate_runtime(self, n_cores: int = 32) -> str:
208208
# Phase 5: Perturbation analysis (critical slowing down)
209209
PHASE5_CONFIG = Config(
210210
grid_size=100,
211-
prey_death_offsets=(-0.02, -0.01, 0.0, 0.01, 0.02),
211+
prey_death_offsets=(-0.02, -0.01, 0.0, 0.01, 0.02), #FIXME: Is this what we vary?
212212
n_replicates=20,
213213
warmup_steps=500,
214214
measurement_steps=2000,

scripts/experiments.py

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@
1818
"""
1919

2020

21-
# NOTE: The soc_analysis script used temporal avalache data to assess SOC.
21+
# NOTE (1): The soc_analysis script used temporal avalache data to assess SOC.
2222
# This functionality is not yet implemented here. We can still derive that data
2323
# from the full time series using np.diff(prey_timeseries)
2424

2525

26+
# NOTE (2): Post-processing utilities and plotting are in scripts/analysis.py. This script should
27+
# solely focus on running the experiments and saving raw results.
28+
29+
2630
import argparse
2731
import hashlib
2832
import json
@@ -166,7 +170,7 @@ def run_single_simulation(
166170
rows=grid_size,
167171
cols=grid_size,
168172
densities=cfg.densities,
169-
neighborhood="moore",
173+
neighborhood="moore", #NOTE: Default neighborhood
170174
params={
171175
"prey_birth": prey_birth,
172176
"prey_death": prey_death,
@@ -185,15 +189,16 @@ def run_single_simulation(
185189
warmup_steps = cfg.get_warmup_steps(grid_size)
186190
measurement_steps = cfg.get_measurement_steps(grid_size)
187191

192+
193+
# Warmup phase
188194
for _ in range(warmup_steps):
189195
model.update()
190196

191-
# Measurement phase
192-
prey_pops, pred_pops = [], []
193-
evolved_means, evolved_stds = [], []
194-
cluster_sizes_prey, cluster_sizes_pred = [], []
195-
largest_fractions_prey, largest_fractions_pred = [], []
196-
percolates_prey, percolates_pred = [], []
197+
# Measurement phase: start collecting our mertics
198+
prey_pops, pred_pops = [], [] # Prey populations and predator populations
199+
evolved_means, evolved_stds = [], [] # Evolution stats over time
200+
cluster_sizes_prey, cluster_sizes_pred = [], [] # Cluster sizes
201+
largest_fractions_prey, largest_fractions_pred = [], [] # Largest cluster fractions = size of largest cluster / total population
197202
pcf_samples = {'prey_prey': [], 'pred_pred': [], 'prey_pred': []}
198203

199204

@@ -223,11 +228,7 @@ def run_single_simulation(
223228

224229
largest_fractions_prey.append(prey_stats['largest_fraction'])
225230
largest_fractions_pred.append(pred_stats['largest_fraction'])
226-
227-
prey_perc, _, _, _ = get_percolating_cluster_fast(model.grid, 1)
228-
pred_perc, _, _, _ = get_percolating_cluster_fast(model.grid, 2)
229-
percolates_prey.append(prey_perc)
230-
percolates_pred.append(pred_perc)
231+
# NOTE: Change in largest fraction calculation if needed for critical point location
231232

232233
# PCF
233234
if compute_pcf:
@@ -266,14 +267,12 @@ def run_single_simulation(
266267
# Order parameters
267268
"prey_largest_fraction": float(np.mean(largest_fractions_prey)) if largest_fractions_prey else np.nan,
268269
"pred_largest_fraction": float(np.mean(largest_fractions_pred)) if largest_fractions_pred else np.nan,
269-
"prey_percolates": bool(any(percolates_prey)) if percolates_prey else False,
270-
"pred_percolates": bool(any(percolates_pred)) if percolates_pred else False,
271270
}
272271

273272
# Time series (if requested)
274273
if cfg.save_timeseries:
275274
subsample = cfg.timeseries_subsample
276-
result["prey_timeseries"] = prey_pops[::subsample]
275+
result["prey_timeseries"] = prey_pops[::subsample] #NOTE: Sample temporal data every 'subsample' steps
277276
result["pred_timeseries"] = pred_pops[::subsample]
278277

279278

@@ -300,6 +299,28 @@ def run_single_simulation(
300299
result["pcf_prey_pred"] = pcf_cr.tolist()
301300

302301
# Short-range indices
302+
"""
303+
NOTE: The Pair Correlation function measures spatial correlation at distance r.
304+
g(r) = 1: random (poisson distribution)
305+
g(r) > 1: clustering (more pairs than random)
306+
g(r) < 1: segregation (fewer pairs than random)
307+
308+
prey_clustering_index: Do prey clump together?
309+
pred_clustering_index: Do predators clump together?
310+
segregation_index: Are prey and predators segregated?
311+
312+
For the Hydra effect model:
313+
segregation_index < 1: Prey and predators are spatially separated
314+
prey_clustering_index > 1: Prey form clusters
315+
pred_clustering_index > 1: Predators form clusters
316+
317+
High segregation (low segregation index): prey can reproduce in predator-free zones
318+
High prey clustering: prey form groups that can survive predation
319+
At criticality: expect sepcific balance where clusters are large enough to sustain but
320+
fragmented enough to avoid total predation.
321+
322+
If segregation_index = 1 approx, no Hydra effect -> follow mean field dynamics.
323+
"""
303324
short_mask = dist < 3.0
304325
if np.any(short_mask):
305326
result["segregation_index"] = float(np.mean(pcf_cr[short_mask]))
@@ -308,8 +329,6 @@ def run_single_simulation(
308329

309330
return result
310331

311-
312-
313332
# =============================================================================
314333
# Experiment Phases
315334
# =============================================================================
@@ -331,12 +350,13 @@ def run_phase1(cfg: Config, output_dir: Path, logger: logging.Logger) -> List[Di
331350

332351
# Build job list
333352
jobs = []
353+
# Sweep through prey_birth and prey_death
334354
for pb in prey_births:
335355
for pd in prey_deaths:
336356
for rep in range(cfg.n_replicates):
337357
params = {"pb": pb, "pd": pd}
338358

339-
# Non-evolution run
359+
# Non-evolution run #FIXME: Check if both evo and non-evo are needed for phase 1
340360
seed = generate_unique_seed(params, rep)
341361
jobs.append((pb, pd, cfg.predator_birth, cfg.predator_death,
342362
cfg.grid_size, seed, cfg, False))
@@ -383,7 +403,7 @@ def run_phase2(cfg: Config, output_dir: Path, logger: logging.Logger) -> List[Di
383403
384404
SOC Hypothesis: Prey evolve toward critical critical point regardless of initial conditions.
385405
386-
Test: Start evo from different intial prey_death values (?)
406+
NOTE: Test is currently start evo from different intial prey_death values (?)
387407
If SOC holds, then all runs converge to the same final prey_death near critical point.
388408
"""
389409
from joblib import Parallel, delayed
@@ -445,13 +465,14 @@ def run_phase3(cfg: Config, output_dir: Path, logger: logging.Logger) -> List[Di
445465
"""
446466
from joblib import Parallel, delayed
447467

448-
pb = cfg.critical_prey_birth
468+
# NOTE: Tuned to critical points from phase 1
469+
pb = cfg.critical_prey_birth
449470
pd = cfg.critical_prey_death
450471

451472
logger.info(f"Phase 3: FSS at critical point (pb={pb}, pd={pd})")
452473

453474
jobs = []
454-
for L in cfg.grid_sizes:
475+
for L in cfg.grid_sizes: # Sweep through grid sizes
455476
warmup_numba_kernels(L, directed_hunting=cfg.directed_hunting)
456477

457478
for rep in range(cfg.n_replicates):
@@ -475,6 +496,7 @@ def run_phase3(cfg: Config, output_dir: Path, logger: logging.Logger) -> List[Di
475496
f.flush()
476497
all_results.append(result)
477498

499+
# Post-run metadata: postprocessing will fit cluster cutoffs vs L
478500
meta = {
479501
"phase": 3,
480502
"description": "Finite-size scaling",
@@ -496,6 +518,10 @@ def run_phase4(cfg: Config, output_dir: Path, logger: logging.Logger) -> List[Di
496518
497519
- Vary predator_birth and predator_death
498520
- For each combo, sweep prey_death
521+
522+
523+
NOTE: This phase should be subjected to changes depeding on what we are interested in varying
524+
in terms of parameters.
499525
"""
500526
from joblib import Parallel, delayed
501527

0 commit comments

Comments
 (0)