diff --git a/.DS_Store b/.DS_Store index a942ca24..8011cdf5 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/_modules/goo/cell.html b/_modules/goo/cell.html index c7fe0ba6..639a1616 100644 --- a/_modules/goo/cell.html +++ b/_modules/goo/cell.html @@ -216,6 +216,7 @@
import numpy as np
from scipy.spatial.distance import cdist, pdist, squareform
from scipy.spatial import KDTree
+from scipy.ndimage import laplace
import bpy
import bmesh
@@ -410,9 +412,28 @@ Source code for goo.handler
self.kd_tree = self.diffusionSystem._build_kdtree()
-
-[docs]
- def update_cell_concentration(
+
+[docs]
+ def read_molecular_signal(
+ self,
+ cell: Cell,
+ cell_distances: np.ndarray,
+ indices: np.ndarray,
+ radius: float
+ ) -> None:
+ """Read the concentration of molecules in the cell."""
+ for mol_idx, molecule in enumerate(self.diffusionSystem._molecules):
+ valid_indices = ~np.isinf(cell_distances) & (cell_distances >= radius)
+ if valid_indices.any():
+ index = indices[valid_indices][0]
+ total_conc = self.diffusionSystem.get_concentration(mol_idx, index)
+ print(f"Conc of cell {cell.name} for {molecule._name}: {total_conc}")
+ cell.molecules_conc.update({molecule._name: total_conc})
+
+
+
+[docs]
+ def update_molecular_signal(
self,
cell: Cell,
cell_distances: np.ndarray,
@@ -420,21 +441,46 @@ Source code for goo.handler
radius: float
) -> None:
"""Update the concentration of molecules in the cell."""
+
+ k = 0.1
for mol_idx, molecule in enumerate(self.diffusionSystem._molecules):
total_conc = 0
valid_indices = ~np.isinf(cell_distances) & (cell_distances >= radius)
- for cell_distance, index in zip(cell_distances[valid_indices],
- indices[valid_indices]):
- k = 0.1
+ valid_distances = cell_distances[valid_indices]
+ valid_indices = indices[valid_indices]
+
+ for cell_distance, index in zip(valid_distances, valid_indices):
add_conc = k * (cell_distance / radius)
self.diffusionSystem.update_concentration(mol_idx, index, add_conc)
- # total_conc = self.diffusionSystem.get_concentration(mol_idx, index)
cell.molecules_conc.update({molecule._name: total_conc})
- print(cell.molecules_conc)
- print(f"Total conc of cell {cell.name} for {molecule._name}: {total_conc}")
+ print(f"Molecular concentrations: {cell.molecules_conc}")
+
+[docs]
+ def diffuse(self, mol_idx: int):
+ """Update the concentration of molecules based on diffusion."""
+ conc = self.diffusionSystem._grid_concentrations[mol_idx]
+ laplacian = laplace(conc, mode='wrap')
+ diff_coeff = self.diffusionSystem._molecules[mol_idx]._D
+ conc += self.diffusionSystem._time_step * diff_coeff * laplacian
+ conc = np.clip(conc, 0, None)
+ self.diffusionSystem._grid_concentrations[mol_idx] = conc
+
+
+
+[docs]
+ def simulate_diffusion(self):
+ """Run the diffusion simulation over the total time."""
+ tot_time = self.diffusionSystem._total_time
+ t_step = self.diffusionSystem._time_step
+ num_steps = int(tot_time / t_step)
+ for _ in range(num_steps):
+ for mol_idx in range(len(self.diffusionSystem._molecules)):
+ self.diffuse(mol_idx)
+
+
[docs]
@override
@@ -443,18 +489,24 @@ Source code for goo.handler
self.build_kd_tree()
print("Current frame", scene.frame_current)
+
+ # diffuse molecules on grid
+ self.simulate_diffusion()
+
cells = self.get_cells()
for cell in cells:
radius = cell.get_radius()
com = cell.COM()
+ scaling_factor = 1 / self.diffusionSystem._element_size[0]
cell_distances, indices = self.kd_tree.query(com,
- k=500,
+ k=500 * scaling_factor**2,
distance_upper_bound=1.5*radius,
p=2)
if len(cell_distances) > 0 and not np.all(np.isinf(cell_distances)):
- self.update_cell_concentration(cell, cell_distances, indices, radius)
+ self.update_molecular_signal(cell, cell_distances, indices, radius)
+ self.read_molecular_signal(cell, cell_distances, indices, radius)
else:
# If no valid distances, set concentration to 0
for molecule in self.diffusionSystem._molecules:
@@ -465,52 +517,6 @@ Source code for goo.handler
-
-[docs]
-class MolecularSensingHandler(Handler):
- """Handler for simulating cells sensing molecular concentrations at their surfaces.
-
- Args:
- diffusionSystem: The reaction-diffusion system to simulate.
-
- """
-
- def __init__(self, diffusionSystem: DiffusionSystem) -> None:
- self.diffusionSystem = diffusionSystem
-
-
-[docs]
- @override
- def run(self, scene, depsgraph):
-
- for cell in self.get_cells():
- major_axis = cell.major_axis()
- length_major = (major_axis._start - major_axis._end).length
- minor_axis = cell.minor_axis()
- length_minor = (minor_axis._start - minor_axis._end).length
- radius = (length_major + length_minor) / 2
- com = cell.COM()
-
- cell_distances, indices = self.kd_tree.query(com,
- k=500,
- distance_upper_bound=1.5*radius,
- p=2)
- print(cell_distances, indices)
- print("radius", radius)
-
- for mol_idx, molecule in enumerate(self.diffusionSystem._molecules):
- for idx, (cell_distance, index) in enumerate(zip(cell_distances, indices)):
- # conservative estimate using the minor axis
- if np.isinf(cell_distance):
- continue
- elif (cell_distance >= radius):
- total_conc += self.diffusionSystem.get_concentration(mol_idx,
- index)
- print(f"Total conc of cell for {molecule._name}", total_conc)
-
-
-
-
[docs]
class AdhesionLocationHandler(Handler):
diff --git a/_modules/goo/molecule.html b/_modules/goo/molecule.html
index 2ee7f7ad..a9295b3b 100644
--- a/_modules/goo/molecule.html
+++ b/_modules/goo/molecule.html
@@ -216,6 +216,7 @@
- Installation
+- Install dependencies in Blender
- Learning resources
- Example scripts
- Running Goo on O2
@@ -369,11 +370,11 @@ Source code for goo.molecule
def __init__(
self,
molecules: list[Molecule],
- grid_size: Tuple[int, int, int] = (25, 25, 25),
+ grid_size: Tuple[int, int, int] = (50, 50, 50),
grid_center: Tuple[int, int, int] = (0, 0, 0),
time_step: float = 0.1,
total_time: int = 10,
- element_size=(1.0, 1.0, 1.0)
+ element_size=(0.5, 0.5, 0.5)
) -> None:
self._molecules = molecules
self._grid_size = grid_size
@@ -383,11 +384,6 @@ Source code for goo.molecule
self._grid_concentrations = None
self._kd_tree = None
self._element_size = element_size
- self._laplacian_kernel = np.array([
- [[1, 1, 1], [1, 1, 1], [1, 1, 1]],
- [[1, 1, 1], [1, -26, 1], [1, 1, 1]],
- [[1, 1, 1], [1, 1, 1], [1, 1, 1]]
- ]) / 26.0
def _build_kdtree(self):
"""Initialize the grid and build its corresponding KD-Tree."""
@@ -481,6 +477,28 @@ Source code for goo.molecule
return self._grid_concentrations[mol_idx, z_index, y_index, x_index]
+
+[docs]
+ def diffuse(self, mol_idx):
+ """Update the concentration of molecules based on diffusion."""
+ # get grid
+ grid = self._grid_concentrations
+ conc = grid[mol_idx]
+ laplacian = laplace(conc, mode='wrap')
+ conc += self._time_step * self._molecules[mol_idx]._D * laplacian
+ conc = np.clip(conc, 0, None)
+ grid[mol_idx] = conc
+
+
+
+[docs]
+ def simulate(self):
+ """Run the diffusion simulation over the total time."""
+ num_steps = int(self._total_time / self._time_step)
+ for _ in range(num_steps):
+ self.diffuse()
+
+
@property
def molecules(self) -> list[Molecule]:
"""The list of molecules in the system."""
@@ -524,44 +542,7 @@ Source code for goo.molecule
@total_time.setter
def total_time(self, total_time: int):
- self.total_time = total_time
-
-
-[docs]
- def diffuse(self, t, y):
- concentrations = []
- offset = 0
- for i, molecule in enumerate(self.molecules):
- C = y[offset:offset + self.grid_size_prod].reshape(self.grid_size)
- dC_dt = self.diffusion_rates[i] * laplace(C)
- concentrations.append(dC_dt.ravel())
- offset += self.grid_size_prod
- return np.concatenate(concentrations)
-
-
-
-[docs]
- def run(self):
- # Initialize the combined state for all molecules
- y0 = np.concatenate(
- [molecule.concentration.flatten() for molecule in self.molecules]
- )
- t_span = (0, self.total_time)
- t_eval = np.arange(0, self.total_time, self.time_step)
-
- # Solve the diffusion system
- solution = solve_ivp(self.diffuse(), t_span, y0, method='RK45', t_eval=t_eval)
-
- # Reshape the solution for each molecule
- results = []
- offset = 0
- for molecule in self.molecules:
- concentration_sol = solution.y[offset:offset + np.prod(self.grid_size)]
- concentration_sol = concentration_sol.reshape(self.grid_size + (len(t_eval),))
- results.append(concentration_sol)
- offset += np.prod(self.grid_size)
- return results
-
+ self.total_time = total_time
diff --git a/_modules/goo/reloader.html b/_modules/goo/reloader.html
index 8764fb32..8c4543b6 100644
--- a/_modules/goo/reloader.html
+++ b/_modules/goo/reloader.html
@@ -216,6 +216,7 @@
- Installation
+- Install dependencies in Blender
- Learning resources
- Example scripts
- Running Goo on O2
diff --git a/_modules/goo/simulator.html b/_modules/goo/simulator.html
index da6815b3..f7661134 100644
--- a/_modules/goo/simulator.html
+++ b/_modules/goo/simulator.html
@@ -216,6 +216,7 @@
- Installation
+- Install dependencies in Blender
- Learning resources
- Example scripts
- Running Goo on O2
diff --git a/_modules/goo/utils.html b/_modules/goo/utils.html
index 0606ef0e..5432ecc1 100644
--- a/_modules/goo/utils.html
+++ b/_modules/goo/utils.html
@@ -216,6 +216,7 @@
- Installation
+- Install dependencies in Blender
- Learning resources
- Example scripts
- Running Goo on O2
diff --git a/_modules/index.html b/_modules/index.html
index 48b7c27b..0c6b1329 100644
--- a/_modules/index.html
+++ b/_modules/index.html
@@ -216,6 +216,7 @@
- Installation
+- Install dependencies in Blender
- Learning resources
- Example scripts
- Running Goo on O2
diff --git a/_sources/getting_started/installation.rst.txt b/_sources/getting_started/installation.rst.txt
index fb74e586..cc8cde17 100644
--- a/_sources/getting_started/installation.rst.txt
+++ b/_sources/getting_started/installation.rst.txt
@@ -38,17 +38,21 @@ Dependencies
.. _mathutils: https://pypi.org/project/mathutils/
.. _scipy: https://pypi.org/project/scipy/
-Install Dependencies in Blender
--------------------------------
+
+Install dependencies in Blender
+================================
+
+MacOS/Linux
+------------
Blender comes with its own Python interpreter, which is isolated from the system's Python environment.
Goo requires a few additional Python packages that need to be installed directly into Blender's Python environment.
-To install Goo's dependencies:
+To install Goo's dependencies from the terminal:
1. Find the paths of the Blender executable and its Python interpreter.
- For macOS, it is usually in the Applications folder, e.g., `/Applications/Blender.app/Contents/MacOS/Blender` and `/Applications/Blender.app/Contents/Resources/3.6/python/bin/python3.10`. For Windows, it is usually in the Program Files folder.
+ For macOS, it is usually in the Applications folder, e.g., `/Applications/Blender.app/Contents/MacOS/Blender` and `/Applications/Blender.app/Contents/Resources/3.6/python/bin/python3.10`.
2. Create a new environment using Blender's Python interpreter:
@@ -79,3 +83,50 @@ To install Goo's dependencies:
.. code-block:: bash
/Applications/Blender.app/Contents/MacOS/Blender
+
+
+Windows
+------------
+
+Blender comes with its own Python interpreter, which is isolated from the system's Python environment.
+Goo requires a few additional Python packages that need to be installed directly into Blender's Python environment.
+
+To install Goo's dependencies from a terminal:
+
+1. Find the paths of the Blender executable and its Python interpreter.
+
+ For Windows, it is usually in the Program Files, e.g., `C:\\Program Files\\Blender Foundation\\Blender 4.1\\Blender.exe` and `C:\\Program Files\\Blender Foundation\\Blender 4.1\\4.1\python\\bin\\python.exe`.
+
+2. Create a new virtual environment using Blender's Python interpreter:
+
+ .. code-block:: bash
+
+ C:\\Program Files\\Blender Foundation\\Blender 4.1\\4.1\\python\\bin\\python.exe -m venv .blender_env
+
+
+3. Activate the environment:
+
+ .. code-block:: bash
+
+ .blender_env\\Scripts\\activate
+
+4. Install the dependencies:
+
+ .. code-block:: bash
+
+ C:\\Program Files\\Blender Foundation\\Blender 4.1\\4.1\\python\\bin\\python.exe -m pip install setuptools numpy scipy sphinx sphinx_copybutton furo typing_extensions
+
+5. Check that the dependencies are installed:
+
+ .. code-block:: bash
+
+ C:\\Program Files\\Blender Foundation\\Blender 4.1\\4.1\\python\\bin\\python.exe -m pip list
+
+6. Launch Blender from within the activated virtual environment:
+
+ .. code-block:: bash
+
+ C:\\Program Files\\Blender Foundation\\Blender 3.3\\Blender.exe
+
+
+Blender supports virtual environment and the installed packages will be available to use for scripting in Blender.
diff --git a/credits/credits_and_citation.html b/credits/credits_and_citation.html
index fffa6945..761c30d0 100644
--- a/credits/credits_and_citation.html
+++ b/credits/credits_and_citation.html
@@ -217,6 +217,7 @@
- Installation
+- Install dependencies in Blender
- Learning resources
- Example scripts
- Running Goo on O2
diff --git a/developer_guide/developers.html b/developer_guide/developers.html
index d2b7f1ea..f08abdc6 100644
--- a/developer_guide/developers.html
+++ b/developer_guide/developers.html
@@ -217,6 +217,7 @@
- Installation
+- Install dependencies in Blender
- Learning resources
- Example scripts
- Running Goo on O2
diff --git a/docs/.DS_Store b/docs/.DS_Store
deleted file mode 100644
index a6c65586..00000000
Binary files a/docs/.DS_Store and /dev/null differ
diff --git a/genindex.html b/genindex.html
index 74ac7686..ecb59c42 100644
--- a/genindex.html
+++ b/genindex.html
@@ -215,6 +215,7 @@
- Installation
+- Install dependencies in Blender
- Learning resources
- Example scripts
- Running Goo on O2
@@ -429,12 +430,16 @@ D
- default_celltype() (goo.cell.CellType static method)
- - diffuse() (goo.molecule.DiffusionSystem method)
-
- - DiffusionHandler (class in goo.handler)
+
- diffuse() (goo.handler.DiffusionHandler method)
+
+
+ - DiffusionHandler (class in goo.handler)
+
- DiffusionSystem (class in goo.molecule)
- disable() (goo.force.Force method)
@@ -700,8 +705,6 @@
M
- - MolecularSensingHandler (class in goo.handler)
-
- Molecule (class in goo.molecule)
- molecules (goo.molecule.DiffusionSystem property)
@@ -801,6 +804,8 @@
R
- RANDOM (goo.handler.Colorizer attribute)
- RandomMotionHandler (class in goo.handler)
+
+ - read_molecular_signal() (goo.handler.DiffusionHandler method)
- recenter() (goo.cell.Cell method)
@@ -821,11 +826,11 @@ R
- render() (goo.simulator.Simulator method)
- reset_modules() (in module goo.reloader)
-
- - reset_scene() (in module goo.reloader)
+ - reset_scene() (in module goo.reloader)
+
- run() (goo.division.DivisionHandler method)
@@ -844,14 +849,10 @@ R
- (goo.handler.GrowthPIDHandler method)
- (goo.handler.Handler method)
-
- - (goo.handler.MolecularSensingHandler method)
- (goo.handler.RandomMotionHandler method)
- (goo.handler.RemeshHandler method)
-
- - (goo.molecule.DiffusionSystem method)
- (goo.simulator.Simulator method)
@@ -911,6 +912,10 @@ S
- shape (goo.force.Force property)
- SimpleType (class in goo.cell)
+
+ - simulate() (goo.molecule.DiffusionSystem method)
+
+ - simulate_diffusion() (goo.handler.DiffusionHandler method)
- Simulator (class in goo.simulator)
@@ -973,10 +978,10 @@ U