Source code for SyMBac.cell

import numpy as np
import pymunk
from SyMBac import cell_geometry
[docs]class Cell: """ A class defining the cell objects ... Attributes ---------- length : float Cell's length width : float Cell's width resolution : int Number of points defining cell's geometry position : (float, float) x,y coords of cell centroid angle : float rotation in radians of cell (counterclockwise) space : pymunk.Space The pymunk space of the cell dt : float Timestep the cell experiences every iteration growth_rate_constant : float The cell grows by a function of dt*growth_rate_constant depending on its growth model max_length : float The maximum length a cell reaches before dividing max_length_mean : float should be the same as max_length for reasons unless doing advanced simulations max_length_var : float The variance defining a normal distribution around max_length width_var : float The variance defining a normal distribution around width width_mean : float For reasons should be set equal to width unless using advanced features """ def __init__( self, length, width, resolution, position, angle, space, dt, growth_rate_constant, max_length, max_length_mean, max_length_var, width_var, width_mean, parent = None, daughter = None, lysis_p = 0, pinching_sep = 0 ): """ Initialising a cell Parameters ---------- length : float Cell's length width : float Cell's width resolution : int Number of points defining cell's geometry position : (float, float) x,y coords of cell centroid angle : float rotation in radians of cell (counterclockwise) space : pymunk.space.Space The pymunk space of the cell dt : float Timestep the cell experiences every iteration growth_rate_constant : float The cell grows by a function of dt*growth_rate_constant depending on its growth model max_length : float The maximum length a cell reaches before dividing max_length_mean : float should be the same as max_length for reasons unless doing advanced simulations max_length_var : float The variance defining a normal distribution around max_length width_var : float The variance defining a normal distribution around width width_mean : float For reasons should be set equal to width unless using advanced features body : pymunk.body.Body The cell's pymunk body object shape : pymunk.shapes.Poly The cell's pymunk body object ID : int A unique identifier for each cell. At the moment just a number from 0 to 100_000_000 and cross fingers that we get no collisions. For info about the Pymunk objects, see the API reference. http://www.pymunk.org/en/latest/pymunk.html Cell class has been tested and works with pymunk version 6.0.0 Returns ------- outupt : None """ self.dt = dt self.growth_rate_constant = growth_rate_constant self.length = length self.width_mean = width_mean self.width_var = width_var self.width = width self.resolution = resolution self.angle = angle self.position = position self.space = space self.max_length = max_length self.max_length_mean = max_length_mean self.max_length_var = max_length_var self.body, self.shape = self.create_pm_cell() self.angle = self.body.angle self.ID = np.random.randint(0,100_000_000) self.lysis_p = lysis_p self.parent = parent self.daughter = daughter self.pinching_sep = pinching_sep def create_pm_cell(self): if self.is_dividing(): new_length = self.length/2 daughter_length = self.length - new_length self.length = new_length self.pinching_sep = 0 cell_vertices = self.calculate_vertex_list() cell_shape = pymunk.Poly(None, cell_vertices) self.shape = cell_shape cell_moment = 1 cell_mass = 0.0001 cell_body = pymunk.Body(cell_mass,cell_moment) cell_shape.body = cell_body self.body = cell_body new_x = self.position[0] + self.length/2 * np.cos(self.angle*2) new_y = self.position[1] + self.length/2 * np.sin(self.angle*2) self.body.position = [new_x, new_y] cell_body.angle = self.angle cell_shape.friction=1 self.space.add(cell_body, cell_shape) daughter_details = { "length": daughter_length*0.9, "width": np.random.normal(self.width_mean,self.width_var), "resolution": self.resolution, "position": [self.position[0] - self.length/2 * np.cos(self.angle*2), self.position[1] - self.length/2 * np.sin(self.angle*2)], "angle": self.angle*np.random.uniform(0.95,1.05), "space": self.space, "dt": self.dt, "growth_rate_constant": self.growth_rate_constant, "max_length": np.random.normal(self.max_length_mean,self.max_length_var), "max_length_mean": self.max_length_mean, "max_length_var": self.max_length_var, "width_var": self.width_var, "width_mean": self.width_mean, "lysis_p": self.lysis_p, "parent": self.parent, "pinching_sep": 0 } return daughter_details else: cell_vertices = self.calculate_vertex_list() cell_shape = pymunk.Poly(None, cell_vertices) self.shape = cell_shape cell_moment = 1 cell_mass = 0.0001 cell_body = pymunk.Body(cell_mass,cell_moment) cell_shape.body = cell_body self.body = cell_body cell_body.position = self.position cell_body.angle = self.angle cell_shape.friction=0.01 self.space.add(cell_body, cell_shape) return cell_body, cell_shape def is_dividing(self): # This needs to be made constant or a cell can divide in one frame and not another frame if self.length > (self.max_length): return True else: return False def update_length(self): self.length = self.length + self.growth_rate_constant*self.dt*self.length*np.random.uniform(0.7,1.3) self.pinching_sep = max(0, self.length - self.max_length + self.width) self.pinching_sep = min(self.pinching_sep, self.width - 1) def update_position(self): self.position = self.body.position self.angle = self.body.angle def update_parent(self, parent): self.parent = parent def get_angle(self): return self.body.angle def calculate_vertex_list(self): return cell_geometry.get_vertices( self.length, self.width, self.angle, self.resolution ) def get_vertex_list(self): vertices = [] for v in self.shape.get_vertices(): x,y = v.rotated(self.shape.body.angle) + self.shape.body.position #.rotated(self.shape.body.angle) vertices.append((x,y)) return vertices def get_centroid(self): vertices = self.get_vertex_list() return cell_geometry.centroid(vertices)