Skip to content

Commit 74cb79a

Browse files
committed
added images and code formatting
1 parent 7268055 commit 74cb79a

25 files changed

Lines changed: 6478 additions & 3782 deletions

.DS_Store

0 Bytes
Binary file not shown.

README.md

Lines changed: 442 additions & 0 deletions
Large diffs are not rendered by default.

images/coeffs_phase4.png

-1013 Bytes
Loading

images/coeffs_phase6.png

422 Bytes
Loading

images/cube_phase4.png

1.13 KB
Loading

images/cube_phase6.png

1.63 KB
Loading

models/CA.py

Lines changed: 438 additions & 379 deletions
Large diffs are not rendered by default.

models/config.py

Lines changed: 101 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -64,137 +64,172 @@
6464
@dataclass
6565
class Config:
6666
"""Central configuration for all experiments."""
67-
67+
6868
# Grid settings
69-
grid_size: int = 1000 #FIXME: Decide default configuration
70-
densities: Tuple[float, float] = (0.30, 0.15) # (prey, predator) #FIXME: Default densities
71-
69+
grid_size: int = 1000 # FIXME: Decide default configuration
70+
densities: Tuple[float, float] = (
71+
0.30,
72+
0.15,
73+
) # (prey, predator) #FIXME: Default densities
74+
7275
# For FSS experiments: multiple grid sizes
7376
grid_sizes: Tuple[int, ...] = (50, 100, 250, 500, 1000, 2500)
74-
77+
7578
# Default/fixed parameters
7679
prey_birth: float = 0.2
7780
prey_death: float = 0.05
78-
predator_birth: float = 0.8 # FIXME: Default predator death rate
79-
predator_death: float = 0.05 # FIXME: Default predator death rate
80-
81+
predator_birth: float = 0.8 # FIXME: Default predator death rate
82+
predator_death: float = 0.05 # FIXME: Default predator death rate
83+
8184
# Critical point (UPDATE AFTER PHASE 1)
82-
critical_prey_birth: float = 0.20
85+
critical_prey_birth: float = 0.20
8386
critical_prey_death: float = 0.947
84-
87+
8588
# Prey parameter sweep (Phase 1)
8689
prey_death_range: Tuple[float, float] = (0.0, 0.2)
87-
n_prey_birth: int = 15 # FIXME: Decide number of grid points along prey axes
90+
n_prey_birth: int = 15 # FIXME: Decide number of grid points along prey axes
8891
n_prey_death: int = 5
89-
92+
9093
# Predator parameter sweep (Phase 4 sensitivity)
91-
predator_birth_values: Tuple[float, ...] = (0.15, 0.20, 0.25, 0.30) #FIXME: Bogus values for now
92-
predator_death_values: Tuple[float, ...] = (0.05, 0.10, 0.15, 0.20) #FIXME: Bogus values for now
93-
94+
predator_birth_values: Tuple[float, ...] = (
95+
0.15,
96+
0.20,
97+
0.25,
98+
0.30,
99+
) # FIXME: Bogus values for now
100+
predator_death_values: Tuple[float, ...] = (
101+
0.05,
102+
0.10,
103+
0.15,
104+
0.20,
105+
) # FIXME: Bogus values for now
106+
94107
# Perturbation offsets from critical point (Phase 5)
95-
prey_death_offsets: Tuple[float, ...] = (-0.02, -0.01, 0.0, 0.01, 0.02) #FIXME: Bogus values for now
108+
prey_death_offsets: Tuple[float, ...] = (
109+
-0.02,
110+
-0.01,
111+
0.0,
112+
0.01,
113+
0.02,
114+
) # FIXME: Bogus values for now
96115

97116
# Number of replicates per parameter configuration
98-
n_replicates: int = 15 # FIXME: Decide number of indep. runs per parameter config
99-
117+
n_replicates: int = 15 # FIXME: Decide number of indep. runs per parameter config
118+
100119
# Simulation steps
101120
warmup_steps: int = 300 # FIXME: Steps to run before measuring
102-
measurement_steps: int = 500 # FIXME: Decide measurement steps
103-
121+
measurement_steps: int = 500 # FIXME: Decide measurement steps
122+
104123
# Evo
105124
with_evolution: bool = False
106125
evolve_sd: float = 0.10
107126
evolve_min: float = 0.0
108127
evolve_max: float = 0.10
109-
128+
110129
# Sensitivity: mutation strength values to test
111-
sensitivity_sd_values: Tuple[float, ...] = (0.02, 0.05, 0.10, 0.15, 0.20) #FIXME: Don't know if we use yet
112-
130+
sensitivity_sd_values: Tuple[float, ...] = (
131+
0.02,
132+
0.05,
133+
0.10,
134+
0.15,
135+
0.20,
136+
) # FIXME: Don't know if we use yet
137+
113138
# Update mode
114139
synchronous: bool = False # Always False for this model
115140
directed_hunting: bool = False
116-
141+
117142
# For Phase 6: compare model variants
118143
directed_hunting_values: Tuple[bool, ...] = (False, True)
119-
144+
120145
# Temporal data collection (time series)
121146
save_timeseries: bool = False
122147
timeseries_subsample: int = 10 # FIXME: Save every how many steps
123-
148+
124149
# PCF settings
125150
collect_pcf: bool = True
126151
pcf_sample_rate: float = 0.2 # Fraction of runs to compute PCF
127152
pcf_max_distance: float = 20.0
128153
pcf_n_bins: int = 20
129-
154+
130155
# Cluster analysis
131-
min_density_for_analysis: float = 0.002 # FIXME: Minimum prey density (fraction of grid) to analyze clusters/PCF
132-
156+
min_density_for_analysis: float = (
157+
0.002 # FIXME: Minimum prey density (fraction of grid) to analyze clusters/PCF
158+
)
159+
133160
# Perturbation settings (Phase 5)
134-
perturbation_magnitude: float = 0.1 # FIXME: Fractional change to apply at perturbation time
135-
161+
perturbation_magnitude: float = (
162+
0.1 # FIXME: Fractional change to apply at perturbation time
163+
)
164+
136165
# Parallelization
137-
n_jobs: int = -1 # Use all available cores by default
138-
166+
n_jobs: int = -1 # Use all available cores by default
167+
139168
# Helpers
140169
def get_prey_births(self) -> np.ndarray:
141170
"""Generate prey birth rate sweep values."""
142-
return np.linspace(self.prey_birth_range[0], self.prey_birth_range[1], self.n_prey_birth)
143-
171+
return np.linspace(
172+
self.prey_birth_range[0], self.prey_birth_range[1], self.n_prey_birth
173+
)
174+
144175
def get_prey_deaths(self) -> np.ndarray:
145176
"""Generate prey death rate sweep values."""
146-
return np.linspace(self.prey_death_range[0], self.prey_death_range[1], self.n_prey_death)
147-
148-
def get_warmup_steps(self, L: int) -> int: #FIXME: This method will be updated depending on Sary's results.
177+
return np.linspace(
178+
self.prey_death_range[0], self.prey_death_range[1], self.n_prey_death
179+
)
180+
181+
def get_warmup_steps(
182+
self, L: int
183+
) -> int: # FIXME: This method will be updated depending on Sary's results.
149184
"""Scale warmup with grid size."""
150185
return self.warmup_steps
151-
186+
152187
def get_measurement_steps(self, L: int) -> int:
153188
"""Scale measurement with grid size."""
154189
return self.measurement_steps
155-
190+
156191
def estimate_runtime(self, n_cores: int = 32) -> str:
157192
"""Estimate total runtime based on benchmark data."""
158193
# Benchmark: ~1182 steps/sec for 100x100 grid
159194
ref_size = 100
160195
ref_steps_per_sec = 1182
161-
196+
162197
size_scaling = (self.grid_size / ref_size) ** 2
163198
actual_steps_per_sec = ref_steps_per_sec / size_scaling
164-
199+
165200
total_steps = self.warmup_steps + self.measurement_steps
166201
base_time_s = total_steps / actual_steps_per_sec
167-
202+
168203
# PCF overhead (~8ms for 100x100)
169204
pcf_time_s = (0.008 * size_scaling) if self.collect_pcf else 0
170-
205+
171206
# Count simulations
172207
n_sims = self.n_prey_birth * self.n_prey_death * self.n_replicates
173208
if self.with_evolution:
174209
n_sims *= 2 # Both evo and non-evo runs
175-
210+
176211
total_seconds = n_sims * (base_time_s + pcf_time_s * self.pcf_sample_rate)
177212
total_seconds /= n_cores
178-
213+
179214
hours = total_seconds / 3600
180215
core_hours = n_sims * (base_time_s + pcf_time_s * self.pcf_sample_rate) / 3600
181-
216+
182217
return f"{n_sims:,} sims, ~{hours:.1f}h on {n_cores} cores (~{core_hours:.0f} core-hours)"
183218

184219

185220
############################################################################################
186221
# Experimental Phase Configurations
187222
############################################################################################
188223

189-
#FIXME: These configs are arbitraty and should be finalized before running experiments.
224+
# FIXME: These configs are arbitraty and should be finalized before running experiments.
190225

191226
PHASE1_CONFIG = Config(
192227
grid_size=1000,
193228
n_prey_death=20,
194229
prey_birth=0.2,
195230
prey_death_range=(0.0963, 0.0973),
196-
predator_birth=0.8,
197-
predator_death=0.05,
231+
predator_birth=0.8,
232+
predator_death=0.05,
198233
n_replicates=30,
199234
warmup_steps=1000,
200235
measurement_steps=1000,
@@ -209,17 +244,15 @@ def estimate_runtime(self, n_cores: int = 32) -> str:
209244
grid_size=1000,
210245
n_prey_birth=1, # Fixed at cfg.prey_birth (0.2)
211246
n_replicates=10,
212-
warmup_steps=1000, # Shorter warmup (evolution starts immediately)
213-
measurement_steps=10000, # Longer measurement to see convergence
214-
247+
warmup_steps=1000, # Shorter warmup (evolution starts immediately)
248+
measurement_steps=10000, # Longer measurement to see convergence
215249
# Evolution settings
216250
with_evolution=True,
217-
evolve_sd=0.01, # Smaller mutation rate for smoother convergence
251+
evolve_sd=0.01, # Smaller mutation rate for smoother convergence
218252
evolve_min=0.0,
219-
evolve_max=0.20, # Allow full range
220-
253+
evolve_max=0.20, # Allow full range
221254
collect_pcf=False,
222-
save_timeseries=False, # Track evolution trajectory
255+
save_timeseries=False, # Track evolution trajectory
223256
)
224257

225258
# Phase 3: Finite-size scaling at critical point
@@ -228,8 +261,8 @@ def estimate_runtime(self, n_cores: int = 32) -> str:
228261
n_replicates=20,
229262
warmup_steps=1000,
230263
measurement_steps=1000,
231-
critical_prey_birth=0.20, # Add explicitly
232-
critical_prey_death=0.947, # Add explicitly - verify from Phase 1!
264+
critical_prey_birth=0.20, # Add explicitly
265+
critical_prey_death=0.947, # Add explicitly - verify from Phase 1!
233266
collect_pcf=True,
234267
pcf_sample_rate=1.0,
235268
save_timeseries=False,
@@ -239,9 +272,9 @@ def estimate_runtime(self, n_cores: int = 32) -> str:
239272

240273
# Phase 4: Sensitivity analysis
241274
PHASE4_CONFIG = Config(
242-
grid_size=250, # As requested
243-
n_replicates=10, # As requested
244-
warmup_steps=500, # As requested
275+
grid_size=250, # As requested
276+
n_replicates=10, # As requested
277+
warmup_steps=500, # As requested
245278
measurement_steps=500, # As requested
246279
with_evolution=False,
247280
collect_pcf=False,
@@ -254,7 +287,7 @@ def estimate_runtime(self, n_cores: int = 32) -> str:
254287
# Phase 5: Perturbation analysis (critical slowing down)
255288
PHASE5_CONFIG = Config(
256289
grid_size=100,
257-
prey_death_offsets=(-0.02, -0.01, 0.0, 0.01, 0.02), #FIXME: Is this what we vary?
290+
prey_death_offsets=(-0.02, -0.01, 0.0, 0.01, 0.02), # FIXME: Is this what we vary?
258291
n_replicates=20,
259292
warmup_steps=500,
260293
measurement_steps=2000,
@@ -286,8 +319,11 @@ def estimate_runtime(self, n_cores: int = 32) -> str:
286319
6: PHASE6_CONFIG,
287320
}
288321

322+
289323
def get_phase_config(phase: int) -> Config:
290324
"""Get config for a specific phase."""
291325
if phase not in PHASE_CONFIGS:
292-
raise ValueError(f"Unknown phase {phase}. Valid phases: {list(PHASE_CONFIGS.keys())}")
293-
return PHASE_CONFIGS[phase]
326+
raise ValueError(
327+
f"Unknown phase {phase}. Valid phases: {list(PHASE_CONFIGS.keys())}"
328+
)
329+
return PHASE_CONFIGS[phase]

models/mean_field.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ def sweep_death_rate(
184184
"net_growth": self.birth - d_r_values,
185185
}
186186

187+
187188
if __name__ == "__main__":
188189
print("Mean-Field Model Module")
189190
mf = MeanFieldModel()

0 commit comments

Comments
 (0)