Skip to content

Commit fed1de6

Browse files
committed
large restructure of project
- restructure force calculation - expose more functionality to python
1 parent fab11a5 commit fed1de6

File tree

3 files changed

+304
-243
lines changed

3 files changed

+304
-243
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .cr_tissue import (
2+
Agent,
23
SimulationSettings,
34
run_simulation,
45
)

cellular_raza-examples/tissue/cr_tissue/run2.py

Lines changed: 41 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -2,110 +2,11 @@
22
import matplotlib as mpl
33
import numpy as np
44
import scipy as sp
5-
from tqdm.contrib.concurrent import process_map
5+
from tqdm import tqdm
6+
import multiprocessing as mp
67
import itertools
78

8-
import cr_tissue as crf
9-
10-
11-
def get_area(middle, vertices) -> float:
12-
area = 0.0
13-
14-
for n in range(len(vertices)):
15-
x = vertices[n] - middle
16-
y = vertices[(n + 1) % len(vertices)] - middle
17-
area += 0.5 * np.abs(x[1] * y[0] - x[0] * y[1])
18-
return area
19-
20-
21-
def is_circle_in_convex_polygon(middle, radius, polygon):
22-
"""
23-
Checks if a circle is entirely contained within a convex polygon.
24-
:param polygon: List of tuples [(x1, y1), (x2, y2), ...]
25-
"""
26-
n = len(polygon)
27-
28-
for i in range(n):
29-
# Current edge vertices
30-
p1 = polygon[i]
31-
p2 = polygon[(i + 1) % n] # Wraps around to the first point
32-
33-
# 1. Check if center is on the 'inside' of the edge using cross product
34-
# For CCW polygons, the point must be to the left of the edge
35-
edge_dx = p2[0] - p1[0]
36-
edge_dy = p2[1] - p1[1]
37-
point_dx = middle[0] - p1[0]
38-
point_dy = middle[1] - p1[1]
39-
40-
# # Z-component of cross product
41-
cross_product = edge_dx * point_dy - edge_dy * point_dx
42-
43-
# # If cross_product < 0, the center is outside the convex hull
44-
# if cross_product < 0:
45-
# return False
46-
47-
# 2. Check distance from center to the infinite line of the edge
48-
# Distance from point (x0, y0) to line Ax + By + C = 0
49-
# Line eq: (y1-y2)x + (x2-x1)y + (x1y2 - x2y1) = 0
50-
dist = abs(cross_product) / np.sqrt(edge_dx**2 + edge_dy**2)
51-
52-
if dist < radius:
53-
return False
54-
55-
return True
56-
57-
58-
def min_max_exact_dist_point_to_segment(p, a, b, dist):
59-
"""
60-
Calculates the minimum distance between point P(px, py)
61-
and line segment AB defined by points A(ax, ay) and B(bx, by).
62-
"""
63-
# Vector AB
64-
dx = b - a
65-
66-
# If A and B are the same point, distance is just P to A
67-
d = np.linalg.norm(dx) ** 2
68-
if d == 0:
69-
return np.linalg.norm(p - a), a, a, [a]
70-
71-
# Calculate the projection of P onto the line AB
72-
# t is the "parameter" along the line: t=0 is A, t=1 is B
73-
t = np.dot((p - a), dx) / d
74-
75-
# Clamp t to the range [0, 1] to stay on the segment
76-
t = np.clip(t, 0, 1)
77-
78-
# Find the closest point on the segment
79-
closest = a + t * dx
80-
81-
d1 = np.linalg.norm(a - p)
82-
d2 = np.linalg.norm(b - p)
83-
furthest = a if d1 > d2 else b
84-
min_dist = np.linalg.norm(closest - p)
85-
exact = []
86-
if d1 >= dist >= min_dist:
87-
h = (dist - min_dist) / (d1 - min_dist)
88-
exact.append(closest + h * (a - closest))
89-
if d2 >= dist >= min_dist:
90-
h = (dist - min_dist) / (d2 - min_dist)
91-
exact.append(closest + h * (b - closest))
92-
# Return the distance from P to the closest point
93-
return min_dist, closest, furthest, exact
94-
95-
96-
def determine_new_radius(middle, vertices, radius):
97-
# Construct new polygon
98-
radius_new = radius
99-
new_polygon = []
100-
for n in range(len(vertices)):
101-
v1 = vertices[n]
102-
v2 = vertices[(n + 1) % len(vertices)]
103-
_, closest, furthest, exact = min_max_exact_dist_point_to_segment(
104-
middle, v1, v2, radius_new
105-
)
106-
new_polygon.extend(exact)
107-
108-
return np.array(new_polygon)
9+
import cr_tissue as crt
10910

11011

11112
def __construct_polygon(path, resolution):
@@ -134,8 +35,8 @@ def __construct_polygon(path, resolution):
13435

13536
def save_snapshot(iteration, domain_size, result, resolution=30):
13637
fig, ax = plt.subplots(figsize=(8, 8))
137-
for middle, path, species in result[iteration]:
138-
color = mpl.colormaps["Set1"](species)
38+
for _, path, area_ratio in result[iteration]:
39+
color = mpl.colormaps["Spectral"](area_ratio)
13940
if len(path) > 0:
14041
polygon = __construct_polygon(path, resolution)
14142
ax.add_patch(
@@ -163,55 +64,61 @@ def __pool_save_snapshot_helper(args):
16364

16465

16566
if __name__ == "__main__":
166-
settings = crf.SimulationSettings()
67+
settings = crt.SimulationSettings()
68+
69+
domain_size = 500
70+
domain_size_start = 200
71+
n_agents = 700
16772

168-
settings.n_plants = 40
169-
settings.n_threads = 1
17073
settings.dt = 0.5
171-
settings.t_max = 11_000.0
172-
settings.save_interval = 50.0
173-
settings.domain_size = 200.0
174-
175-
settings.target_area = 80
176-
settings.force_strength = 0.05
177-
settings.force_strength_weak = -0.001
178-
settings.force_strength_species = 0.03
179-
settings.force_relative_cutoff = 5.0
180-
settings.damping_constant = 1.0
181-
settings.cell_diffusion_constant = 0.002
74+
settings.t_max = 20_000.0
75+
settings.save_interval = 200.0
76+
settings.domain_size = domain_size
77+
settings.n_voxels = 50
78+
settings.approximation_steps = 10
79+
80+
radius = 5.0
81+
target_area = np.pi * radius**2
82+
target_perimeter = 2 * np.pi * radius * 1.0
18283

18384
sampler = sp.stats.qmc.LatinHypercube(d=2, seed=10)
18485
domain_size = settings.domain_size
185-
samples = sampler.random(300)
186-
samples = sp.stats.qmc.scale(samples, 0.05 * domain_size, 0.95 * domain_size)
86+
samples = sampler.random(n_agents)
87+
dlow = domain_size / 2 - domain_size_start / 2
88+
dhigh = domain_size / 2 + domain_size_start / 2
89+
samples = sp.stats.qmc.scale(samples, dlow, dhigh)
18790

18891
# samples = np.array(
18992
# [
19093
# [0.49 * domain_size, 0.49 * domain_size],
19194
# [0.49 * domain_size, 0.51 * domain_size],
19295
# [0.51 * domain_size, 0.49 * domain_size],
19396
# [0.51 * domain_size, 0.51 * domain_size],
97+
# [0.55 * domain_size, 0.50 * domain_size],
19498
# ]
19599
# )
196100

197-
species = np.zeros(samples.shape[0], dtype=int)
198-
species[::3] = 1
199-
species[1::3] = 2
101+
agents = []
102+
for pos in samples:
103+
agent = crt.Agent(
104+
pos,
105+
force_area=0.0001,
106+
force_perimeter=0.0001,
107+
force_dist=0.1,
108+
min_dist=0.6 * radius,
109+
target_area=target_area,
110+
target_perimeter=target_perimeter,
111+
damping=1.0,
112+
diffusion_constant=0.0001,
113+
)
114+
agents.append(agent)
200115

201-
result = crf.run_simulation(
202-
settings,
203-
plant_points=samples,
204-
plant_species=species,
205-
)
116+
result = crt.run_simulation(settings, agents)
206117
print()
207118

208119
arglist = zip(
209120
result, itertools.repeat(settings.domain_size), itertools.repeat(result)
210121
)
211122

212-
r = process_map(__pool_save_snapshot_helper, arglist, workers=-1)
213-
# pool = mp.Pool(30)
214-
# _ = list(tqdm(pool.imap(__pool_save_snapshot_helper, arglist), total=len(result)))
215-
216-
# for iteration in tqdm(result, desc="Rendering Snapshots"):
217-
# save_snapshot(iteration, settings.domain_size, result)
123+
pool = mp.Pool()
124+
_ = list(tqdm(pool.imap(__pool_save_snapshot_helper, arglist), total=len(result)))

0 commit comments

Comments
 (0)