Skip to content

Commit cdde4b6

Browse files
committed
Merge branch 'main' into storm
2 parents 2563c30 + 5bc2df7 commit cdde4b6

39 files changed

Lines changed: 8389 additions & 1130 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ results/
99
# Jupyter Notebook checkpoints
1010
.ipynb_checkpoints/
1111
# Data files
12-
data/
12+
data/
13+
.pytest_cache/

benchmarks/benchmark.txt

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
======================================================================
2+
PREDATOR-PREY SIMULATION - OPTIMIZATION BENCHMARKS
3+
======================================================================
4+
Time: 2026-01-22 15:11:24
5+
Numba: Available
6+
Scipy: Available
7+
======================================================================
8+
9+
======================================================================
10+
PP KERNEL BENCHMARK
11+
======================================================================
12+
13+
Grid size: 50x50
14+
--------------------------------------------------
15+
Numba (random) 8.08 ± 2.38 ms
16+
Numba (directed) 18.19 ± 4.53 ms
17+
→ Directed hunting overhead: +125.2%
18+
Python baseline 474.44 ± 39.77 ms ( 58.7x vs Numba)
19+
20+
Grid size: 100x100
21+
--------------------------------------------------
22+
Numba (random) 25.59 ± 0.23 ms
23+
Numba (directed) 17.68 ± 0.72 ms
24+
→ Directed hunting overhead: -30.9%
25+
26+
Grid size: 150x150
27+
--------------------------------------------------
28+
Numba (random) 93.28 ± 29.97 ms
29+
Numba (directed) 40.18 ± 4.25 ms
30+
→ Directed hunting overhead: -56.9%
31+
32+
======================================================================
33+
PCF COMPUTATION BENCHMARK
34+
======================================================================
35+
36+
Grid: 50x50, Prey: 746
37+
--------------------------------------------------
38+
Cell-list PCF (Numba) 9.99 ± 6.74 ms
39+
Brute-force PCF (Python) 835.34 ± 4.51 ms ( 83.7x vs Cell-list)
40+
41+
Grid: 75x75, Prey: 1696
42+
--------------------------------------------------
43+
Cell-list PCF (Numba) 7.56 ± 0.73 ms
44+
Brute-force PCF (Python) 4253.93 ± 8.26 ms (562.5x vs Cell-list)
45+
46+
Grid: 100x100, Prey: 2946
47+
--------------------------------------------------
48+
Cell-list PCF (Numba) 7.49 ± 0.35 ms
49+
50+
======================================================================
51+
CLUSTER MEASUREMENT BENCHMARK
52+
======================================================================
53+
54+
Grid: 50x50, Prey: 746
55+
--------------------------------------------------
56+
Numba flood-fill 0.06 ± 0.00 ms
57+
Scipy label 0.93 ± 0.07 ms ( 14.9x vs Numba)
58+
59+
Grid: 100x100, Prey: 2946
60+
--------------------------------------------------
61+
Numba flood-fill 0.25 ± 0.00 ms
62+
Scipy label 6.05 ± 0.06 ms ( 24.6x vs Numba)
63+
64+
Grid: 150x150, Prey: 6700
65+
--------------------------------------------------
66+
Numba flood-fill 0.55 ± 0.01 ms
67+
Scipy label 23.30 ± 0.07 ms ( 42.6x vs Numba)
68+
69+
======================================================================
70+
FULL SIMULATION BENCHMARK
71+
======================================================================
72+
73+
Grid: 50x50, Steps: 200
74+
--------------------------------------------------
75+
Full sim (random) 42.15 ± 0.84 ms
76+
Full sim (directed) 19.25 ± 0.14 ms
77+
→ Throughput: 4744 steps/sec
78+
79+
Grid: 100x100, Steps: 200
80+
--------------------------------------------------
81+
Full sim (random) 164.50 ± 4.51 ms
82+
Full sim (directed) 69.01 ± 0.93 ms
83+
→ Throughput: 1216 steps/sec
84+
85+
======================================================================
86+
SCALING ANALYSIS
87+
======================================================================
88+
89+
Size Kernel (ms) PCF (ms) Total (ms)
90+
-------------------------------------------------------
91+
30 1.07 1.21 2.29
92+
64 5.09 4.91 10.00
93+
98 11.62 9.12 20.73
94+
132 21.23 13.70 34.93
95+
166 33.57 20.54 54.11
96+
200 49.26 27.42 76.68
97+
98+
======================================================================
99+
BENCHMARK SUMMARY
100+
======================================================================
101+
102+
KEY FINDINGS:
103+
--------------------------------------------------
104+
• Numba kernel speedup: 58.7x (vs Python)
105+
• Cell-list PCF speedup: 83.7x (vs brute-force)
106+
• Numba cluster speedup: 24.6x (vs scipy)
107+
• Directed hunting overhead: -30.9%
108+
• Simulation throughput: 1216 steps/sec (100x100)
109+
110+
======================================================================

benchmarks/benchmark_plots.png

151 KB
Loading

benchmarks/simulation_profile.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
1424296 function calls (1403459 primitive calls) in 1.094 seconds
2+
3+
Ordered by: internal time
4+
List reduced from 3270 to 15 due to restriction <15>
5+
6+
ncalls tottime percall cumtime percall filename:lineno(function)
7+
500 0.293 0.001 0.298 0.001 /Users/kimonanagnostopoulos/CSS_Project/scripts/numba_optimized.py:309(update)
8+
7030 0.077 0.000 0.082 0.000 /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/inspect.py:2729(__init__)
9+
835/832 0.062 0.000 0.067 0.000 /Users/kimonanagnostopoulos/CSS_Project/.venv/lib/python3.12/site-packages/llvmlite/binding/ffi.py:210(__call__)
10+
257 0.049 0.000 0.049 0.000 {method 'read' of '_io.BufferedReader' objects}
11+
7547 0.045 0.000 0.095 0.000 /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/inspect.py:879(cleandoc)
12+
13 0.043 0.003 0.043 0.003 {built-in method _imp.create_dynamic}
13+
251 0.028 0.000 0.028 0.000 {built-in method marshal.loads}
14+
204142/203012 0.020 0.000 0.020 0.000 {built-in method builtins.len}
15+
1069 0.015 0.000 0.015 0.000 /Users/kimonanagnostopoulos/CSS_Project/.venv/lib/python3.12/site-packages/scipy/_lib/_docscrape.py:86(is_unindented)
16+
456 0.014 0.000 0.014 0.000 {built-in method builtins.dir}
17+
227 0.013 0.000 0.047 0.000 /Users/kimonanagnostopoulos/CSS_Project/.venv/lib/python3.12/site-packages/matplotlib/artist.py:1433(get_aliases)
18+
10242 0.013 0.000 0.013 0.000 {method 'search' of 're.Pattern' objects}
19+
104235 0.013 0.000 0.013 0.000 {method 'startswith' of 'str' objects}
20+
92646 0.011 0.000 0.011 0.000 {method 'lstrip' of 'str' objects}
21+
1813 0.011 0.000 0.011 0.000 {method 'reduce' of 'numpy.ufunc' objects}

docs/HPC_GUIDE.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
### Snellius Usage Breakdown
22

33
```
4-
ssh <your_username>@snellius.surf.nl
4+
ssh kanagnostopoul@snellius.surf.nl
55
66
# On a separate terminal run the following
77
88
# Upload the entire project directory (including your models/ folder)
9-
scp -r ~/Documents/CSS_Project <your_username>@snellius.surf.nl:~/
9+
scp -r ~/CSS_Project kanagnostopoul@snellius.surf.nl:~/
1010
1111
# On the Snellius terminal
1212
@@ -39,9 +39,13 @@ scancel <JOBID>
3939
4040
tail -f logs_<JOBID>.err
4141
42+
# Watch task completetion
43+
44+
watch -n 10 "ls -1 results_JOBID | wc -l"
45+
4246
# Fetching the results once the job is done
4347
44-
scp -r <your_username>@snellius.surf.nl:~/results_18514601 ~/Downloads/
48+
scp -r kanagnostopoul@snellius.surf.nl:~/results_18532145 ~/Downloads/
4549
```
4650

4751
The jobscript template can be found in ```run_analysis.sh``` (default rome paritition).

docs/Mean_Field_Model.pdf

197 KB
Binary file not shown.

docs/PREDATOR_HUNTING_FEATURE.md

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# Predator-Prey Directed Movement Implementation
2+
3+
## Overview
4+
5+
Predators now use **directed hunting behavior** instead of random movement. When predators attempt to reproduce, they:
6+
7+
1. **Check all neighboring cells** for prey
8+
2. **If prey neighbors exist**: Pick one prey neighbor uniformly at random and move toward it
9+
3. **If no prey neighbors**: Pick a random neighbor (exploration mode)
10+
11+
This creates a realistic predator-prey dynamic where spatial proximity and visibility matter.
12+
13+
## Technical Details
14+
15+
### Implementation Location
16+
17+
- **File**: `models/CA.py`
18+
- **Functions**:
19+
- `PP.update_sync()` - Synchronous update with directed hunting
20+
- `PP.update_async()` - Asynchronous update with directed hunting
21+
22+
### Key Changes
23+
24+
#### 1. Synchronous Update (`update_sync`)
25+
26+
A new helper function `_process_predator_hunting()` was added to handle predator reproduction with intelligent movement:
27+
28+
```python
29+
def _process_predator_hunting(sources, birth_param_key, birth_prob):
30+
"""Handle predator reproduction with directed movement toward prey."""
31+
```
32+
33+
**Algorithm**:
34+
1. Filter predators that attempt reproduction (based on `predator_birth` probability)
35+
2. For each attempting predator:
36+
- Get all neighbor positions using precomputed `dr_arr`, `dc_arr`
37+
- Check grid reference to identify which neighbors have prey (`state == 1`)
38+
- If prey visible: randomly select one prey neighbor
39+
- If no prey: randomly select any neighbor
40+
3. Apply successful hunts: predators convert prey to predators
41+
4. Handle parameter inheritance/mutation for evolved traits
42+
43+
#### 2. Asynchronous Update (`update_async`)
44+
45+
The predator reproduction branch was modified to use the same hunting logic:
46+
47+
```python
48+
elif state == 2: # Predator
49+
# Check all neighbors for prey
50+
neighbors_r = (r + dr_arr) % rows
51+
neighbors_c = (c + dc_arr) % cols
52+
prey_neighbors = (grid_ref[neighbors_r, neighbors_c] == 1)
53+
54+
if np.any(prey_neighbors):
55+
# Directed hunt: pick one prey neighbor
56+
prey_indices = np.where(prey_neighbors)[0]
57+
chosen_idx = int(gen.choice(prey_indices))
58+
else:
59+
# No prey visible: explore randomly
60+
chosen_idx = int(gen.integers(0, n_shifts))
61+
```
62+
63+
### Behavior Differences
64+
65+
#### Before (Random Movement)
66+
- Predators pick a random neighbor regardless of state
67+
- Predation is purely stochastic
68+
- No hunting advantage from spatial proximity
69+
- Success depends only on probability and random chance
70+
71+
#### After (Directed Hunting)
72+
- Predators scan all neighbors for prey
73+
- If prey is visible, predators hunt toward it
74+
- Creates emergent "predator pursuit" behavior
75+
- Predators benefit from spatial clustering
76+
- Matches realistic predator-prey ecologies
77+
78+
## Neighborhood Support
79+
80+
The implementation works with both neighborhood types:
81+
82+
- **Moore (8-neighbor)**: Predators scan 8 surrounding cells
83+
- **Neumann (4-neighbor)**: Predators scan 4 adjacent cells (up/down/left/right)
84+
85+
Periodic boundary conditions are maintained (wraparound at edges).
86+
87+
## Test Results
88+
89+
All tests pass successfully:
90+
91+
```
92+
✓ Synchronous predator hunting executed successfully
93+
✓ Asynchronous predator hunting executed successfully
94+
✓ Neumann neighborhood predator hunting works
95+
✓ Hunting vs. exploration behavior demonstrated
96+
```
97+
98+
### Observed Dynamics
99+
100+
With default parameters (predator_birth=0.8, prey_death=0.01):
101+
102+
| Update | Prey | Predators | Notes |
103+
|--------|------|-----------|-------|
104+
| Initial | 120 | 40 | Starting state |
105+
| Step 3 | 109 | 140 | Predators hunting prey |
106+
| Step 5 | 41 | 232 | Prey collapsing |
107+
| Step 9 | 0 | 270 | Prey extinct |
108+
109+
The faster predator population growth compared to previous random movement indicates successful directed hunting.
110+
111+
## Impact on Research
112+
113+
This enhancement is critical for:
114+
115+
1. **Hydra Effect Studies**:
116+
- Directional hunting makes spatial fragmentation more important
117+
- Prey clustering and "firebreak" effects become more pronounced
118+
- Easier to observe paradoxical density increases with mortality
119+
120+
2. **Self-Organized Criticality (SOC)**:
121+
- Hunting creates more realistic predator dynamics
122+
- Cluster formation becomes spatially meaningful
123+
- Power-law distributions more likely to emerge
124+
125+
3. **Evolutionary Dynamics**:
126+
- Creates selective pressure on prey clustering
127+
- Evolution of death rates becomes coupled to spatial structure
128+
- Observed critical thresholds more ecologically realistic
129+
130+
## Usage
131+
132+
No API changes required. Existing code works unchanged:
133+
134+
```python
135+
pp = PP(
136+
rows=100, cols=100,
137+
densities=(0.3, 0.15),
138+
params={
139+
"prey_birth": 0.2,
140+
"prey_death": 0.05,
141+
"predator_birth": 0.8,
142+
"predator_death": 0.045
143+
},
144+
synchronous=True # Or False for async
145+
)
146+
147+
pp.update() # Uses directed hunting automatically
148+
```
149+
150+
## Next Steps
151+
152+
To extend the hunting behavior further, consider:
153+
154+
1. **Prey Flight**: Implement prey movement away from predators
155+
2. **Gaussian Kernels**: Replace Moore/Neumann with continuous interaction kernels
156+
3. **Sensing Distance**: Add parameter for predator vision range
157+
4. **Hunting Efficiency**: Modulate capture probability based on predator/prey numbers
158+
5. **Fatigue**: Add energy costs to directed movement
159+
160+
## Files Modified
161+
162+
- `models/CA.py` - Added predator hunting logic to `PP.update_sync()` and `PP.update_async()`
163+
- `test_predator_hunting.py` - New test suite (created)
164+
165+
## Testing
166+
167+
Run the test suite with:
168+
```bash
169+
python test_predator_hunting.py
170+
```
171+
172+
This validates:
173+
- Synchronous hunting mechanics
174+
- Asynchronous hunting mechanics
175+
- Neighborhood type independence
176+
- Correct parameter inheritance
177+
- Proper collision resolution

0 commit comments

Comments
 (0)