Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
216 commits
Select commit Hold shift + click to select a range
ac8a768
Initial commit, notebook loading and plotting data
Jul 31, 2024
5183a91
prep data for inference
Aug 1, 2024
502b5c2
Remove notebook outputs, exceed github's size limits
Aug 2, 2024
f54ed23
make format; make lint
Aug 2, 2024
923ea52
post meeting
Aug 6, 2024
8365331
add_velocity function
PalkaPuri Aug 7, 2024
a44a37a
format lint
rfl-urbaniak Aug 7, 2024
5fd038f
gerbir rewrite in progress
rfl-urbaniak Aug 7, 2024
bcb0be8
berbil data processed
rfl-urbaniak Aug 8, 2024
26e83e5
model started WIP
rfl-urbaniak Aug 8, 2024
850f790
gerbil modeling in progress
rfl-urbaniak Aug 8, 2024
e2ee500
velocity predictor WIP
PalkaPuri Aug 8, 2024
6a19ae4
wip
PalkaPuri Aug 8, 2024
b5dde8a
format/lint
PalkaPuri Aug 8, 2024
ab1cd20
models and preds
rfl-urbaniak Aug 8, 2024
997210b
rerun notebook
rfl-urbaniak Aug 9, 2024
134ddb9
plotting gerbil by gerbil
Aug 11, 2024
a923457
specify forager column as int
PalkaPuri Aug 12, 2024
8cc4111
add warning
PalkaPuri Aug 12, 2024
892da93
format/lint
PalkaPuri Aug 12, 2024
f675d23
rename f,t for clarity
PalkaPuri Aug 13, 2024
1ee7caa
rerun notebook
PalkaPuri Aug 13, 2024
fcd34b2
add docstrings
PalkaPuri Aug 13, 2024
dc950c2
format/lint
PalkaPuri Aug 13, 2024
205235f
use inbuilt function for gaussian pdf
PalkaPuri Aug 13, 2024
b476a17
merge changes from pp-collab2-compute-velocity
PalkaPuri Aug 13, 2024
045e7d0
updated visualization
PalkaPuri Aug 13, 2024
05b3d90
add handling of nan values in visualization
PalkaPuri Aug 15, 2024
5774858
add _generate_pairwise_copying predictor
PalkaPuri Aug 15, 2024
41a7787
format/lint
PalkaPuri Aug 15, 2024
ab6ee7e
type hints
PalkaPuri Aug 15, 2024
47679f3
add pairwise predictor and animation function
PalkaPuri Aug 21, 2024
fac3f10
change velocity to backward looking
PalkaPuri Aug 21, 2024
ddf4572
Merge branch 'pp-collab2-compute-velocity' of https://github.com/Basi…
PalkaPuri Aug 21, 2024
4b242d8
docstrings and type hints
PalkaPuri Aug 21, 2024
82223c0
generate function and typehints
PalkaPuri Aug 21, 2024
11f5dce
Merge branch 'staging-collab-2' of https://github.com/BasisResearch/c…
PalkaPuri Aug 21, 2024
0dec71b
fixed naming, nan handling
PalkaPuri Aug 21, 2024
ea399b2
refactoring
PalkaPuri Aug 22, 2024
9a2ec97
vicsek wip
PalkaPuri Aug 23, 2024
033e565
update normalization of velocity predictors
PalkaPuri Aug 26, 2024
9c6854b
distance_to_next_move WIP
PalkaPuri Aug 26, 2024
8bfa2d0
Merge branch 'pp-collab2-vicsek-predictor' of https://github.com/Basi…
PalkaPuri Aug 26, 2024
e61915f
added alternates for distance_to_next_pos
PalkaPuri Aug 26, 2024
e79917e
lint/format
PalkaPuri Aug 26, 2024
ab7df53
updated nb example
PalkaPuri Aug 26, 2024
21e0361
update scores wip
PalkaPuri Aug 27, 2024
fca3235
merge rafal's changes
PalkaPuri Aug 27, 2024
d9cadcf
absolute paths for imports in modules
PalkaPuri Aug 27, 2024
3999139
update module to allow chnaging n
PalkaPuri Aug 27, 2024
540b11b
renaming
PalkaPuri Aug 27, 2024
a7b0495
format
PalkaPuri Aug 27, 2024
d0018bd
trace code in place
rfl-urbaniak Aug 27, 2024
319aa97
rename n
PalkaPuri Aug 28, 2024
cf3d543
merge staging-collab-2
PalkaPuri Aug 28, 2024
e47d161
Merge branch 'staging-collab-2' of https://github.com/BasisResearch/c…
PalkaPuri Aug 29, 2024
92a1957
add derive_predictors
PalkaPuri Aug 29, 2024
fd2a3f3
test inference wip
PalkaPuri Aug 29, 2024
d573538
Merge branch 'staging-collab-2' of https://github.com/BasisResearch/c…
PalkaPuri Aug 29, 2024
e2d3615
derive WIP
PalkaPuri Aug 29, 2024
f897604
test inference pipeline
PalkaPuri Aug 29, 2024
5230e77
format/lint
PalkaPuri Aug 29, 2024
e8dba19
format again
PalkaPuri Aug 29, 2024
a0f024c
one more format
PalkaPuri Aug 29, 2024
e07b3ff
lint
PalkaPuri Aug 29, 2024
5faaa13
format
PalkaPuri Aug 29, 2024
b01c8cf
adding doc to local_windows WIP
PalkaPuri Aug 29, 2024
e7bfeaf
small typos in docstrings
rfl-urbaniak Aug 30, 2024
4476c6b
added predictor time to logging
rfl-urbaniak Aug 30, 2024
bcbd8d6
added time to score logging
rfl-urbaniak Aug 30, 2024
72d28f4
time to logging, a few typos
rfl-urbaniak Aug 30, 2024
8d6a2ce
format lint
rfl-urbaniak Aug 30, 2024
5c70d1f
refactored proximity
rfl-urbaniak Aug 30, 2024
eb406a7
removed old proximity code
rfl-urbaniak Aug 30, 2024
bfbf187
format lint
rfl-urbaniak Aug 30, 2024
065518c
refactored trace
rfl-urbaniak Aug 30, 2024
20b89c1
Merge branch 'staging-collab-2' of https://github.com/BasisResearch/c…
rfl-urbaniak Aug 30, 2024
bdc5bff
added generate food to init
rfl-urbaniak Aug 30, 2024
0de9af7
format, lint
rfl-urbaniak Aug 30, 2024
1f0e506
update parameter names in docstring
PalkaPuri Sep 3, 2024
a7c55cc
explanation of score_kwargs
PalkaPuri Sep 3, 2024
b14029d
update next_step_score notebook
PalkaPuri Sep 3, 2024
2b8126f
update warning and add docstring to dataObject
PalkaPuri Sep 3, 2024
f00ce02
removing reusing velocity warning
PalkaPuri Sep 3, 2024
4d11e85
removed individual drop warning, add to derive_predictors_and_scores
PalkaPuri Sep 3, 2024
66688b8
lint/format
PalkaPuri Sep 3, 2024
c3f875e
fix bug in test
PalkaPuri Sep 3, 2024
d7fe531
format
PalkaPuri Sep 3, 2024
21083e8
Merge branch 'pp-collab2-derivepredictors' into pp-collab2-housekeeping
PalkaPuri Sep 3, 2024
2b8ecb2
local_windows update constraint implementation, add docstring
PalkaPuri Sep 3, 2024
5df34c7
rename variables
PalkaPuri Sep 3, 2024
62f0cb2
filter_by_distance update constraint implementation
PalkaPuri Sep 3, 2024
728a182
remove fps argument from subsampling func
PalkaPuri Sep 3, 2024
c7bc9bf
velocity- rename predictorID, update constraint implementation, docst…
PalkaPuri Sep 3, 2024
b583275
ensure all test notebooks run
PalkaPuri Sep 3, 2024
a621300
format/lint WIP
PalkaPuri Sep 3, 2024
e33c5f8
Merge branch 'ru-new-trace' into pp-collab2-housekeeping
PalkaPuri Sep 3, 2024
1b28cc3
ensure rafals nbs run
PalkaPuri Sep 3, 2024
c4ddd34
Merge branch 'staging-collab-2' of https://github.com/BasisResearch/c…
PalkaPuri Sep 4, 2024
2d9829e
type hints for kwargs in constraint func
PalkaPuri Sep 4, 2024
2ea9f12
add collab2 notebooks to automatic testing
PalkaPuri Sep 4, 2024
953558e
small fixes to local_windows.py docstrings
rfl-urbaniak Sep 4, 2024
f75ec48
interpunction in filtering.py
rfl-urbaniak Sep 4, 2024
d9249c1
proximity notebook now works
rfl-urbaniak Sep 5, 2024
575db78
wip
rfl-urbaniak Sep 5, 2024
2bd0546
fixed trace and derivation notebooks
rfl-urbaniak Sep 5, 2024
5913050
resolved type hinting problems
rfl-urbaniak Sep 5, 2024
5c02393
wip
PalkaPuri Sep 5, 2024
f3f7e4f
fix some bugs
PalkaPuri Sep 5, 2024
bba492b
Merge branch 'staging-collab-2' of https://github.com/BasisResearch/c…
PalkaPuri Sep 5, 2024
dd1816c
notebook issue fix
PalkaPuri Sep 5, 2024
b4edb96
fix type hint in proximity
PalkaPuri Sep 5, 2024
ca693a8
Merge branch 'pp-collab2-housekeeping' of https://github.com/BasisRes…
rfl-urbaniak Sep 5, 2024
b74f053
Merge branch 'staging-collab-2' of https://github.com/BasisResearch/c…
PalkaPuri Sep 5, 2024
ec87f20
simulations wip
PalkaPuri Sep 5, 2024
e0b4a97
formatting
PalkaPuri Sep 5, 2024
5e07e39
simulations + animations
PalkaPuri Sep 6, 2024
ddbb318
simulations + animations
PalkaPuri Sep 6, 2024
2f79e36
refactoring
PalkaPuri Sep 8, 2024
c077a8a
examples
PalkaPuri Sep 9, 2024
b88937e
grid_constraint_params updated to dict
PalkaPuri Sep 9, 2024
35f9131
interaction_constraint_params updated to dict
PalkaPuri Sep 9, 2024
1bcf668
make sure all notebooks pass + format/lint
PalkaPuri Sep 9, 2024
8b379ea
velocity peristence predictor
PalkaPuri Sep 9, 2024
199a9e7
renamed predictor
PalkaPuri Sep 9, 2024
30a9e0c
format/lint
PalkaPuri Sep 9, 2024
5821493
wip
PalkaPuri Sep 9, 2024
1d27c58
Merge branch 'pp-collab2-velocityDiffusion' into pp-fish-analysis
PalkaPuri Sep 9, 2024
26fad38
wip
PalkaPuri Sep 9, 2024
5572734
lint
rfl-urbaniak Sep 9, 2024
59e6215
lint
rfl-urbaniak Sep 9, 2024
f9b92da
lint
rfl-urbaniak Sep 9, 2024
bdd9965
lint
rfl-urbaniak Sep 9, 2024
1e1a548
lint
rfl-urbaniak Sep 9, 2024
5467b05
lint
rfl-urbaniak Sep 9, 2024
cc63147
lint
rfl-urbaniak Sep 9, 2024
d2b6994
wip
PalkaPuri Sep 9, 2024
bf27bd1
grab gerbil notebook as model template
PalkaPuri Sep 9, 2024
c2f4c82
suspended old velocity test
rfl-urbaniak Sep 9, 2024
7f32e87
wip
PalkaPuri Sep 9, 2024
5dfbbc3
wip
PalkaPuri Sep 10, 2024
6ebf6f1
Merge branch 'staging-collab-2' of https://github.com/BasisResearch/c…
PalkaPuri Sep 10, 2024
6380beb
fix bug
PalkaPuri Sep 10, 2024
b2bb27e
wip
PalkaPuri Sep 10, 2024
88eaadf
Merge branch 'staging-collab-2' of https://github.com/BasisResearch/c…
PalkaPuri Sep 10, 2024
1a017f5
lint/format
PalkaPuri Sep 10, 2024
4c7c883
Merge branch 'staging-collab-2' of https://github.com/BasisResearch/c…
PalkaPuri Sep 10, 2024
8433c83
Merge branch 'pp-add-velocity-bug' of https://github.com/BasisResearc…
PalkaPuri Sep 10, 2024
549becd
wip
PalkaPuri Sep 11, 2024
235fb07
changed DF merge to concat
PalkaPuri Sep 11, 2024
bcf5fac
dont return nan anymore
PalkaPuri Sep 11, 2024
954d9e5
rhf old update
rfl-urbaniak Sep 17, 2024
032b3f4
Merge branch 'ru-random-hungry-2' of https://github.com/BasisResearch…
rfl-urbaniak Sep 17, 2024
944b20a
re-ran hungry and random foragers
rfl-urbaniak Sep 17, 2024
5780fef
following foragers replicated
rfl-urbaniak Sep 17, 2024
4ee8c47
format, lint
rfl-urbaniak Sep 18, 2024
1d31c6b
change to sublinear
rfl-urbaniak Sep 18, 2024
f0293fb
fixing velocity_predicts WIP
rfl-urbaniak Sep 18, 2024
e3d75c6
updated trace_predictor
rfl-urbaniak Sep 18, 2024
c1c0b8b
suspend animations in velocity predictors
rfl-urbaniak Sep 18, 2024
5205da4
added access predictor
rfl-urbaniak Sep 19, 2024
ec21ab4
updated random with access
rfl-urbaniak Sep 19, 2024
233c693
updateg hungry foragers
rfl-urbaniak Sep 19, 2024
bab23a2
updated followers with access
rfl-urbaniak Sep 19, 2024
b349262
format, lint
rfl-urbaniak Sep 19, 2024
9b6e058
Merge branch 'staging-collab-2' of https://github.com/BasisResearch/c…
rfl-urbaniak Sep 19, 2024
52b339b
fixed lint
rfl-urbaniak Sep 19, 2024
22104de
fixed imports in random foragers
rfl-urbaniak Sep 19, 2024
f20a472
fixing init
rfl-urbaniak Sep 19, 2024
605ed17
format, lint
rfl-urbaniak Sep 19, 2024
f3a6aa1
restored init fix
rfl-urbaniak Sep 19, 2024
8f61e4e
bump pyro to 1.9.1
rfl-urbaniak Sep 20, 2024
e0dfbaf
revert (chirho), remove deterministic from rendering
rfl-urbaniak Sep 20, 2024
72a1f4d
updated simulation model
PalkaPuri Sep 25, 2024
420446f
updated simulation animation
PalkaPuri Sep 25, 2024
dba82cf
visualization notebook and small changes to simulation model and viz
PalkaPuri Sep 25, 2024
249bc3b
updated model to log interaction type and number of neighbors
PalkaPuri Sep 25, 2024
07d525c
Merge remote-tracking branch 'origin/pp-collab2-upgrade-derive' into …
PalkaPuri Sep 25, 2024
1b204de
updated warning and added eCDF normalization
PalkaPuri Sep 25, 2024
bec5cbe
Merge remote-tracking branch 'origin/pp-collab2-upgrade-derive' into …
PalkaPuri Sep 25, 2024
0ebd761
Merge remote-tracking branch 'origin/pp-add-velocity-bug' into pp-fis…
PalkaPuri Sep 25, 2024
5b7659f
added nan condition
PalkaPuri Sep 25, 2024
c9b289d
Merge branch 'pp-add-velocity-bug' into pp-fish-analysis
PalkaPuri Sep 25, 2024
4cc7d95
refactored predictors
PalkaPuri Sep 25, 2024
52d0f14
Some polishing of the random/hungry/followers notebooks and fixing st…
dimkab Oct 2, 2024
2150069
format lint
rfl-urbaniak Oct 3, 2024
58f526c
Merge branch 'ru-random-hungry-2' of https://github.com/BasisResearch…
rfl-urbaniak Oct 3, 2024
9b2910a
looking for Palka's large files
rfl-urbaniak Oct 3, 2024
3e43280
fixing conflicts
rfl-urbaniak Oct 3, 2024
9afabbf
fixing conflicts
rfl-urbaniak Oct 3, 2024
33e500c
Merge branch 'pp-velocity-predictor-refactor' of https://github.com/B…
rfl-urbaniak Oct 3, 2024
101af5e
fixing some conflicts
rfl-urbaniak Oct 3, 2024
f485798
Merge branch 'staging-collab-2' into pp-collab2-velocityDiffusion
PalkaPuri Oct 6, 2024
63e3a87
Merge branch 'staging-collab-2' into pp-collab2-upgrade-derive
PalkaPuri Oct 6, 2024
7ca4051
Merge remote-tracking branch 'origin/staging-collab-2' into pp-veloci…
PalkaPuri Oct 7, 2024
99f1247
fix bug in animations
PalkaPuri Oct 7, 2024
e76e2bc
refactoring velocity_predictors.nb
PalkaPuri Oct 7, 2024
955951f
format/lint
PalkaPuri Oct 7, 2024
6337acf
delete compute_velocity notebook
PalkaPuri Oct 7, 2024
a696ab0
Merge branch 'pp-velocity-predictor-refactor' into pp-collab2-velocit…
PalkaPuri Oct 7, 2024
523bfe6
fix merge typos
PalkaPuri Oct 7, 2024
6d7ba1c
one more bug from merge
PalkaPuri Oct 7, 2024
a38a64a
fix notebook
PalkaPuri Oct 7, 2024
abf1121
format/lint
PalkaPuri Oct 7, 2024
5fccd79
Merge branch 'pp-collab2-velocityDiffusion' into pp-fish-analysis
PalkaPuri Oct 7, 2024
5398a38
Merge branch 'pp-collab2-upgrade-derive' into pp-fish-analysis
PalkaPuri Oct 7, 2024
0406b84
wip inference notebook
PalkaPuri Oct 7, 2024
f26fdee
add next step exponential
PalkaPuri Oct 7, 2024
d569496
Merge branch 'pp-nextstep-exponential' into pp-fish-analysis
PalkaPuri Oct 7, 2024
b099e43
wip vicsek inference
PalkaPuri Oct 7, 2024
113f242
add rescaling
PalkaPuri Oct 7, 2024
7f003d6
Merge branch 'pp-nextstep-exponential' into pp-fish-analysis
PalkaPuri Oct 7, 2024
0a25da7
inference reproduced
PalkaPuri Oct 8, 2024
b48cfd0
add comparisons
PalkaPuri Oct 8, 2024
10b9fc8
file reorganization
PalkaPuri Oct 8, 2024
8730d4f
added predictor correlation nb
PalkaPuri Oct 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions collab2/foraging/fish/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .simulation_models import StochasticFish_IndependentRates # noqa: F401
from .simulation_viz import animate_trajectories # noqa: F401
327 changes: 327 additions & 0 deletions collab2/foraging/fish/simulation_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@
from typing import Any, Optional

import numpy as np

class StochasticFish_IndependentRates:
def __init__(
self,
N: Optional[int] = 4,
arena_size: Optional[float] = 50,
Tmax: Optional[float] = 10,
dt: Optional[float] = None,
random_state: Optional[int] = 0,
interaction_params: Optional[dict[str, dict[str, Any]]] = None,
vscale : Optional[float] = None
):
"""
:param N: number of fish
:param arena_size: Radius of arena
:param Tmax: simulation end time
:param dt: time-step for logging fish positions, speed, and heading.
If None, a timestep is chosen based on total interaction rate
:param random_state: random seed for reproducibility
:param interaction_params: nested dictionary of parameters of the interactions in the model.
the keys of the dictionary are interaction names, each corresponding value is a dictionary of
parameters for the interaction, eg, "rate" (required for all interactions). There must exist a method
named "{interaction}_interaction" to implement each interaction.
:param vscale: Scale used to sample initial velocity magnitude from Rayleigh distribution
If None, vscale is chosen based on avg_rate and arena_size
"""
self.N = N
self.arena_size = arena_size
self.Tmax = Tmax
self.dt = dt
self.interaction_params = interaction_params
self.random_state = random_state
self.vscale = vscale

def init_for_simulation(self):

# initialize random number generator
self.rng = np.random.default_rng(seed=self.random_state)

# initialize simulation time
self.time = 0

# choose default params if interaction_params not specified
if self.interaction_params is None :
self.interaction_params = {
"vicsek": {
"rate": 0.5 * np.ones(self.N),
"interaction_length": self.arena_size / 3 * np.ones(self.N),
"sigma_v": 5 * np.ones(self.N),
"sigma_t": 1 * np.ones(self.N),
},
"pairwiseCopying": {
"rate": 0.5 * np.ones(self.N),
"interaction_length": self.arena_size / 3 * np.ones(self.N),
"sigma_v": 5 * np.ones(self.N),
"sigma_t": 1 * np.ones(self.N),
},
"diffusion": {
"rate": 0.5 * np.ones(self.N),
"sigma_v": 5 * np.ones(self.N),
"sigma_t": 1 * np.ones(self.N),
}
}

# calculate total rate
total_rate = 0
for param_dict in self.interaction_params.values():
total_rate += np.sum(param_dict["rate"])

self.total_rate = total_rate

# choose dt based on total_rate if not specified
if self.dt is None:
self.dt = 0.1/self.total_rate

print(f"Logging time step: {self.dt}")

# choose vscale based on arena_size and avg_rate if not provided
if self.vscale is None:
avg_rate = self.total_rate/(len(self.interaction_params) * self.N)
self.vscale = 0.01 * self.arena_size*avg_rate

print(f"Velocity scale for initialization: {self.vscale : .2f}")

# initialize arrays
# add 1 since we also log time=0
total_time_steps = np.ceil(self.Tmax/self.dt).astype(int) + 1
self.total_time_steps = total_time_steps

print(f"Total time steps: {total_time_steps}")

# trajectories matrix has shape (N x total_time_steps x 2), with the last dimension representing x,y
self.trajectories = np.full((self.N, total_time_steps, 2), np.nan)

# velocities matrix has shape (N x total_time_steps x 2), with the last column representing v, theta
self.velocities = np.full((self.N, total_time_steps, 2), np.nan)

# randomly choose intial conditions
# choose random positions inside the arena from uniform distribution
r1 = self.arena_size * self.rng.random(self.N)
r2 = 2 * np.pi * self.rng.random(self.N)
self.trajectories[:, 0, 0] = r1 * np.cos(r2)
self.trajectories[:, 0, 1] = r1 * np.sin(r2)

# choose theta from uniform distribution, v from rayleigh
self.velocities[:, 0, 1] = (
2 * np.pi * self.rng.random(self.N) - np.pi
) # heading angles in [-np.pi, np.pi)

self.velocities[:, 0 ,0] = self.rng.rayleigh(scale=self.vscale,size=self.N)

# for each interaction, estimate avg interaction number before leaving interaction radius
for interaction,params in self.interaction_params.items():
try:
L = np.mean(params["interaction_length"])
rate = np.mean(params["rate"])
print(f"Average number of {interaction} interactions before leaving interaction radius: {int(L*rate/(self.vscale))}")
except KeyError:
pass



def apply_reflective_bc(self, t_ind):
"""
Implement reflective boundary conditions (w/ a circular arena of R=arena_size) for row index `t_ind` of trajectory, velocity matrices
"""

x = self.trajectories[:, t_ind, 0]
y = self.trajectories[:, t_ind, 1]
theta = self.velocities[:, t_ind, 1]

distances_from_center = np.sqrt(x**2 + y**2)

for i, d in enumerate(distances_from_center):
if d > self.arena_size:
# Calculate the unit vector pointing from the center of the arena to the current position
ux = x[i] / d
uy = y[i] / d

# Calculate the projection of the heading direction onto this unit vector
h_parallel = np.cos(theta[i]) * ux + np.sin(theta[i]) * uy

# Calculate the reflection of the heading vector
hx_new = np.cos(theta[i]) - 2 * h_parallel * ux
hy_new = np.sin(theta[i]) - 2 * h_parallel * uy

# Calculate new heading angle, and update velocity matrix
self.velocities[i, t_ind, 1] = np.arctan2(hy_new, hx_new)
# Note that velocity magnitude is unchanged by reflection!

# Set the new position to the intersection point with the boundary
self.trajectories[i, t_ind, 0] = self.arena_size * ux
self.trajectories[i, t_ind, 1] = self.arena_size * uy

def evolve_positions(self, idx_0, idx_f):
"""
Evolve kinematic variables for all fish from idx_0 to idx_f
"""
while idx_0 < idx_f:
# update positions
vx = self.velocities[:, idx_0, 0] * np.cos(self.velocities[:, idx_0, 1])
vy = self.velocities[:, idx_0, 0] * np.sin(self.velocities[:, idx_0, 1])
self.trajectories[:, idx_0 + 1, 0] = (
self.trajectories[:, idx_0, 0] + vx * self.dt
)
self.trajectories[:, idx_0 + 1, 1] = (
self.trajectories[:, idx_0, 1] + vy * self.dt
)

# copy previous velocities
self.velocities[:, idx_0 + 1, 0] = self.velocities[:, idx_0, 0]
self.velocities[:, idx_0 + 1, 1] = self.velocities[:, idx_0, 1]

# apply boundary conditions
self.apply_reflective_bc(idx_0 + 1)

# update index
idx_0 += 1

def time_to_next_interaction(self):
r1 = self.rng.random()
return 1 / self.total_rate * np.log(1 / r1)

def sample_next_interaction(self):
rate_matrix = np.stack(
(
[
self.interaction_params[key]["rate"]
for key in self.interaction_params.keys()
]
),
axis=1,
) # each fish corresponds to a separate row

p_fish = np.sum(rate_matrix, axis=1) / np.sum(rate_matrix, axis=None)

# sample a fish
f = self.rng.choice(range(self.N), p=p_fish)

# sample which reaction occurs
interactions_list = list(self.interaction_params.keys())
p_interactions = rate_matrix[f, :] / np.sum(rate_matrix[f, :])
interaction = self.rng.choice(interactions_list, p=p_interactions)
return f, interaction

def find_neighbors(self, f, t_ind, L):
"""
find neighbors of fish f at time index t_ind given interaction length L
"""
dist2 = (
self.trajectories[f, t_ind, 0] - self.trajectories[:, t_ind, 0]
) ** 2 + (self.trajectories[f, t_ind, 1] - self.trajectories[:, t_ind, 1]) ** 2
dist2[f] = np.nan
neighbors = np.flatnonzero(dist2 < L**2)
return neighbors

def vicsek_interaction(self, f):
t_ind = int(self.time / self.dt)
L = self.interaction_params["vicsek"]["interaction_length"][f]
sigma_v = self.interaction_params["vicsek"]["sigma_v"][f]
sigma_t = self.interaction_params["vicsek"]["sigma_t"][f]

neighbors = self.find_neighbors(f, t_ind, L)

if len(neighbors):
# find average velocity
vx = np.mean(
self.velocities[neighbors, t_ind, 0]
* np.cos(self.velocities[neighbors, t_ind, 1])
)
vy = np.mean(
self.velocities[neighbors, t_ind, 0]
* np.sin(self.velocities[neighbors, t_ind, 1])
)
v = np.sqrt(vx**2 + vy**2)

if v:
theta = np.arctan2(vy, vx)
else:
# resample theta since there is no reason for it to default to zero
theta = 2*np.pi*self.rng.random()

# add noise and update f
# preferred velocity magnitude is same as before interactions
self.velocities[f, t_ind, 0] += self.rng.normal(loc=0, scale=sigma_v)
self.velocities[f, t_ind, 1] = theta + self.rng.normal(loc=0, scale=sigma_t)

# make sure velocity magnitude is not negative!
self.velocities[f, t_ind, 0] = np.maximum(0, self.velocities[f, t_ind, 0])
return len(neighbors)

def pairwiseCopying_interaction(self, f):
t_ind = int(self.time / self.dt)
L = self.interaction_params["pairwiseCopying"]["interaction_length"][f]
sigma_v = self.interaction_params["pairwiseCopying"]["sigma_v"][f]
sigma_t = self.interaction_params["pairwiseCopying"]["sigma_t"][f]

neighbors = self.find_neighbors(f, t_ind, L)

if len(neighbors):
# choose a neighbor to randomly copy
j = self.rng.choice(neighbors)

# add noise and update f
self.velocities[f, t_ind, 0] = self.velocities[
j, t_ind, 0
] + self.rng.normal(loc=0, scale=sigma_v)
self.velocities[f, t_ind, 1] = self.velocities[
j, t_ind, 1
] + self.rng.normal(loc=0, scale=sigma_t)

# make sure velocity magnitude is not negative!
self.velocities[f, t_ind, 0] = np.maximum(0, self.velocities[f, t_ind, 0])

return len(neighbors)

def diffusion_interaction(self, f):
t_ind = int(self.time / self.dt)
sigma_v = self.interaction_params["diffusion"]["sigma_v"][f]
sigma_t = self.interaction_params["diffusion"]["sigma_t"][f]
# add noise
self.velocities[f, t_ind, 0] += self.rng.normal(loc=0, scale=sigma_v)
self.velocities[f, t_ind, 1] += self.rng.normal(loc=0, scale=sigma_t)
# make sure velocity magnitude is not negative!
self.velocities[f, t_ind, 0] = np.maximum(0, self.velocities[f, t_ind, 0])

return -1 # since interaction does not involve neighbors

def simulate(self):
self.init_for_simulation()

# number of neighbors involved in each interaction type
interaction_nn = {key : [] for key in self.interaction_params.keys()}

while True:
# find time to next reaction
tau = self.time_to_next_interaction()

# evolve positions until next reaction
idx_0 = int(self.time / self.dt)
idx_f = np.minimum(
idx_0 + np.round(tau / self.dt), np.ceil(self.Tmax / self.dt)
).astype(int)
self.evolve_positions(idx_0, idx_f)

# update time in increments of dt
self.time = idx_f * self.dt

# choose which reaction occurs
f, interaction = self.sample_next_interaction()

# apply transformation
interaction_func = getattr(self, f"{interaction}_interaction")
nn = interaction_func(f)
interaction_nn[interaction].append(nn)

if self.time >= self.Tmax:
break

# print statistics of interactions
for interaction,nn in interaction_nn.items():
print(f"Time-steps with {interaction} interaction: {len(nn)} ({100*len(nn)/self.total_time_steps :.2f}%)")
nn = np.array(nn)
print(f"Number {interaction} interactions with more than 1 neighbor: {np.sum(nn>1)} ({100*np.sum(nn>1)/len(nn) :.2f}%)")
57 changes: 57 additions & 0 deletions collab2/foraging/fish/simulation_viz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import matplotlib.pyplot as plt
import numpy as np
from IPython.display import HTML
from matplotlib.animation import FuncAnimation


def animate_trajectories(sim, frames_skipped = 1, Tmin=None, Tmax = None):

x = sim.trajectories[:, :, 0] # shape : nfish x time
y = sim.trajectories[:, :, 1]
theta = sim.velocities[:, :, 1]
N = sim.N
arena_size = sim.arena_size
dt = sim.dt
L = sim.arena_size/10

if Tmin is None:
Tmin = 0
if Tmax is None:
Tmax = sim.Tmax


# Set up the figure and axis
fig, ax = plt.subplots()
ax.set_xlim(-arena_size, arena_size)
ax.set_ylim(-arena_size, arena_size)
ax.set_aspect("equal")

# Initialize scatter for particle positions and lines for velocity directions
particles = ax.scatter(x[:, 0], y[:, 0], color="blue")
velocity_lines = [ax.plot([], [], color="blue")[0] for _ in range(N)]

# plot arena outline
temp = np.linspace(0, 2 * np.pi, 100)
ax.plot(arena_size * np.cos(temp), arena_size * np.sin(temp), "k")

# Update function for each frame
def update(frame):
# Update the particle positions
particles.set_offsets(np.c_[x[:, frame], y[:, frame]])

# Update velocity direction lines
for i, line in enumerate(velocity_lines):
dx = -L * np.cos(theta[i, frame])
dy = -L * np.sin(theta[i, frame])
line.set_data(
[x[i, frame], x[i, frame] + dx], [y[i, frame], y[i, frame] + dy]
)
ax.set_title(f"t={frame*dt : .0f}")
return particles, *velocity_lines

# Create the animation
interval = 1000*frames_skipped*dt #multiple by 1000 to convert to ms
anim = FuncAnimation(fig, update, frames=range(int(Tmin/dt),int(Tmax/dt),frames_skipped), interval=interval, blit=False)

# Display the animation inline in Jupyter Notebook
return HTML(anim.to_jshtml())
Loading