def initialize_spores(self, tissue: np.ndarray, init_num: int): """Initialize spores on epithelium cells.""" grid = self.grid if init_num > 0: points = np.zeros((init_num, 3)) indices = np.argwhere(tissue == TissueTypes.EPITHELIUM.value) if len(indices) > 0: rg.shuffle(indices) for i in range(init_num): # putting in some protection for the occasional time that we place the cell on # the boundary of the voxel-space if indices[i][2] == grid.xv.shape[0] - 1: x = grid.xv[indices[i][2]] else: x = rg.uniform(grid.xv[indices[i][2]], grid.xv[indices[i][2] + 1]) if indices[i][1] == grid.yv.shape[0] - 1: y = grid.yv[indices[i][1]] else: y = rg.uniform(grid.yv[indices[i][1]], grid.yv[indices[i][1] + 1]) if indices[i][0] == grid.zv.shape[0] - 1: z = grid.zv[indices[i][0]] else: z = rg.uniform(grid.zv[indices[i][0]], grid.zv[indices[i][0] + 1]) point = Point(x=x, y=y, z=z) points[i] = point self.spawn_spores(points)
def initialize(self, state: State): pneumocyte: PneumocyteState = state.pneumocyte voxel_volume: float = state.voxel_volume time_step_size: float = self.time_step lung_tissue: np.ndarray = state.lung_tissue pneumocyte.max_conidia = self.config.getint( 'max_conidia') # units: conidia pneumocyte.time_to_rest = self.config.getint( 'time_to_rest') # units: hours pneumocyte.time_to_change_state = self.config.getint( 'time_to_change_state') # units: hours pneumocyte.p_tnf_qtty = self.config.getfloat( 'p_tnf_qtty') # units: atto-mol * cell^-1 * h^-1 pneumocyte.pr_p_int_param = self.config.getfloat('pr_p_int_param') # computed values pneumocyte.iter_to_rest = int( pneumocyte.time_to_rest * (60 / self.time_step)) # units: hours * (min/hour) / (min/step) = step pneumocyte.iter_to_change_state = int( pneumocyte.time_to_change_state * (60 / self.time_step)) # units: hours * (min/hour) / (min/step) = step pneumocyte.pr_p_int = -math.expm1( -time_step_size / 60 / (voxel_volume * pneumocyte.pr_p_int_param)) # units: probability # initialize cells, placing one per epithelial voxel dz_field: np.ndarray = state.grid.delta(axis=0) dy_field: np.ndarray = state.grid.delta(axis=1) dx_field: np.ndarray = state.grid.delta(axis=2) epithelial_voxels = list( zip(*np.where(lung_tissue == TissueType.EPITHELIUM))) rg.shuffle(epithelial_voxels) for vox_z, vox_y, vox_x in epithelial_voxels[:self.config. getint('count')]: # the x,y,z coordinates are in the centers of the grids z = state.grid.z[vox_z] y = state.grid.y[vox_y] x = state.grid.x[vox_x] dz = dz_field[vox_z, vox_y, vox_x] dy = dy_field[vox_z, vox_y, vox_x] dx = dx_field[vox_z, vox_y, vox_x] pneumocyte.cells.append( PneumocyteCellData.create_cell(point=Point( x=x + rg.uniform(-dx / 2, dx / 2), y=y + rg.uniform(-dy / 2, dy / 2), z=z + rg.uniform(-dz / 2, dz / 2), ))) return state
def advance(self, state: State, previous_time: float) -> State: """Advance the state by a single time step.""" from nlisim.modules.macrophage import MacrophageCellData, MacrophageState from nlisim.modules.phagocyte import PhagocyteState, PhagocyteStatus il10: IL10State = state.il10 macrophage: MacrophageState = state.macrophage molecules: MoleculesState = state.molecules voxel_volume: float = state.voxel_volume grid: RectangularGrid = state.grid # active Macrophages secrete il10 and non-dead macrophages can become inactivated by il10 for macrophage_cell_index in macrophage.cells.alive(): macrophage_cell: MacrophageCellData = macrophage.cells[ macrophage_cell_index] macrophage_cell_voxel: Voxel = grid.get_voxel( macrophage_cell['point']) if (macrophage_cell['status'] == PhagocyteStatus.ACTIVE and macrophage_cell['state'] == PhagocyteState.INTERACTING): il10.grid[tuple(macrophage_cell_voxel )] += il10.macrophage_secretion_rate_unit_t if macrophage_cell['status'] not in { PhagocyteStatus.DEAD, PhagocyteStatus.APOPTOTIC, PhagocyteStatus.NECROTIC, } and (activation_function( x=il10.grid[tuple(macrophage_cell_voxel)], k_d=il10.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) > rg.uniform()): # inactive cells stay inactive, others become inactivating if macrophage_cell['status'] != PhagocyteStatus.INACTIVE: macrophage_cell['status'] = PhagocyteStatus.INACTIVATING macrophage_cell['status_iteration'] = 0 # Degrade IL10 il10.grid *= il10.half_life_multiplier il10.grid *= turnover_rate( x=np.ones(shape=il10.grid.shape, dtype=np.float64), x_system=0.0, base_turnover_rate=molecules.turnover_rate, rel_cyt_bind_unit_t=molecules.rel_cyt_bind_unit_t, ) # Diffusion of IL10 il10.grid[:] = apply_diffusion( variable=il10.grid, laplacian=molecules.laplacian, diffusivity=molecules.diffusion_constant, dt=self.time_step, ) return state
def advance(self, state: State, previous_time: float) -> State: """Advance the state by a single time step.""" from nlisim.modules.neutrophil import NeutrophilCellData, NeutrophilState from nlisim.modules.phagocyte import PhagocyteStatus il8: IL8State = state.il8 molecules: MoleculesState = state.molecules neutrophil: NeutrophilState = state.neutrophil voxel_volume: float = state.voxel_volume grid: RectangularGrid = state.grid # IL8 activates neutrophils for neutrophil_cell_index in neutrophil.cells.alive(): neutrophil_cell: NeutrophilCellData = neutrophil.cells[ neutrophil_cell_index] if neutrophil_cell['status'] in { PhagocyteStatus.RESTING or PhagocyteStatus.ACTIVE }: neutrophil_cell_voxel: Voxel = grid.get_voxel( neutrophil_cell['point']) if (activation_function( x=il8.grid[tuple(neutrophil_cell_voxel)], k_d=il8.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) > rg.uniform()): neutrophil_cell['status'] = PhagocyteStatus.ACTIVE neutrophil_cell['status_iteration'] = 0 # Degrade IL8 il8.grid *= il8.half_life_multiplier il8.grid *= turnover_rate( x=np.ones(shape=il8.grid.shape, dtype=np.float64), x_system=0.0, base_turnover_rate=molecules.turnover_rate, rel_cyt_bind_unit_t=molecules.rel_cyt_bind_unit_t, ) # Diffusion of IL8 il8.grid[:] = apply_diffusion( variable=il8.grid, laplacian=molecules.laplacian, diffusivity=molecules.diffusion_constant, dt=self.time_step, ) return state
def update_status(self, state: State, neutrophil_cell: NeutrophilCellData) -> None: """ Update the status of the cell, progressing between states after a certain number of ticks. Parameters ---------- state : State global simulation state neutrophil_cell : NeutrophilCellData Returns ------- nothing """ neutrophil: NeutrophilState = state.neutrophil if neutrophil_cell['status'] in { PhagocyteStatus.NECROTIC, PhagocyteStatus.APOPTOTIC }: self.release_phagosome(state, neutrophil_cell) # releases iron & dies later elif rg.uniform() < neutrophil.apoptosis_probability: neutrophil_cell['status'] = PhagocyteStatus.APOPTOTIC elif neutrophil_cell['status'] == PhagocyteStatus.ACTIVE: if neutrophil_cell[ 'status_iteration'] >= neutrophil.iter_to_change_state: neutrophil_cell['status_iteration'] = 0 neutrophil_cell['tnfa'] = False neutrophil_cell['status'] = PhagocyteStatus.RESTING neutrophil_cell['state'] = PhagocyteState.FREE else: neutrophil_cell['status_iteration'] += 1 elif neutrophil_cell['status'] == PhagocyteStatus.ACTIVATING: if neutrophil_cell[ 'status_iteration'] >= neutrophil.iter_to_change_state: neutrophil_cell['status_iteration'] = 0 neutrophil_cell['status'] = PhagocyteStatus.ACTIVE else: neutrophil_cell['status_iteration'] += 1
def advance(self, state: State, previous_time: float): """Advance the state by a single time step.""" macrophage: MacrophageState = state.macrophage for macrophage_cell_index in macrophage.cells.alive(): macrophage_cell = macrophage.cells[macrophage_cell_index] num_cells_in_phagosome = np.sum(macrophage_cell['phagosome'] >= 0) self.update_status(state, macrophage_cell, num_cells_in_phagosome) if (num_cells_in_phagosome == 0 and rg.uniform() < macrophage.prob_death_per_timestep and len(macrophage.cells.alive()) > macrophage.min_ma): macrophage_cell['status'] = PhagocyteStatus.DEAD macrophage_cell['dead'] = True if not macrophage_cell['fpn']: if macrophage_cell[ 'fpn_iteration'] >= macrophage.iter_to_change_state: macrophage_cell['fpn_iteration'] = 0 macrophage_cell['fpn'] = True else: macrophage_cell['fpn_iteration'] += 1 # Movement if macrophage_cell['status'] == PhagocyteStatus.ACTIVE: max_move_step = (macrophage.ma_move_rate_act * self.time_step ) # (µm/min) * (min/step) = µm * step else: max_move_step = (macrophage.ma_move_rate_rest * self.time_step ) # (µm/min) * (min/step) = µm * step move_step: int = rg.poisson(max_move_step) # move the cell 1 µm, move_step number of times for _ in range(move_step): self.single_step_move(state, macrophage_cell, macrophage_cell_index, macrophage.cells) # Recruitment self.recruit_macrophages(state) return state
def choose_voxel_by_prob(voxels: Tuple[Voxel, ...], default_value: Voxel, weights: np.ndarray) -> Voxel: """ Choose a voxels using a non-normalized probability distribution. If weights are all zero, the default value is chosen. Parameters ---------- voxels an tuple of voxels default_value default return value for when weights are uniformly zero weights an array of non-negative (unchecked) unnormalized probabilities/weights for the voxels Returns ------- a Voxel, from voxels, chosen by the probability distribution, or the default """ normalization_constant = np.sum(weights) if normalization_constant <= 0: # e.g. if all neighbors are air return default_value # prepend a zero to detect `failure by zero' in the argmax below normalized_weights = np.concatenate( (np.array([0.0]), weights / normalization_constant)) # sample from distribution given by normalized weights random_voxel_idx: int = int( np.argmax(np.cumsum(normalized_weights) - rg.uniform() > 0.0) - 1) if random_voxel_idx < 0: # the only way the 0th could be chosen is by argmax failing return default_value else: return voxels[random_voxel_idx]
def advance(self, state: State, previous_time: float) -> State: """Advance the state by a single time step.""" from nlisim.modules.macrophage import MacrophageCellData, MacrophageState from nlisim.modules.neutrophil import NeutrophilCellData, NeutrophilState from nlisim.modules.phagocyte import PhagocyteStatus from nlisim.modules.pneumocyte import PneumocyteCellData, PneumocyteState mip2: MIP2State = state.mip2 molecules: MoleculesState = state.molecules neutrophil: NeutrophilState = state.neutrophil pneumocyte: PneumocyteState = state.pneumocyte macrophage: MacrophageState = state.macrophage grid: RectangularGrid = state.grid voxel_volume = state.voxel_volume # interact with neutrophils neutrophil_activation: np.ndarray = activation_function( x=mip2.grid, k_d=mip2.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) for neutrophil_cell_index in neutrophil.cells.alive(): neutrophil_cell: NeutrophilCellData = neutrophil.cells[neutrophil_cell_index] neutrophil_cell_voxel: Voxel = grid.get_voxel(neutrophil_cell['point']) if ( neutrophil_cell['status'] == PhagocyteStatus.RESTING and neutrophil_activation[tuple(neutrophil_cell_voxel)] > rg.uniform() ): neutrophil_cell['status'] = PhagocyteStatus.ACTIVATING neutrophil_cell['status_iteration'] = 0 elif neutrophil_cell['tnfa']: mip2.grid[tuple(neutrophil_cell_voxel)] += mip2.neutrophil_secretion_rate_unit_t if neutrophil_activation[tuple(neutrophil_cell_voxel)] > rg.uniform(): neutrophil_cell['status_iteration'] = 0 # interact with pneumocytes for pneumocyte_cell_index in pneumocyte.cells.alive(): pneumocyte_cell: PneumocyteCellData = pneumocyte.cells[pneumocyte_cell_index] if pneumocyte_cell['tnfa']: pneumocyte_cell_voxel: Voxel = grid.get_voxel(pneumocyte_cell['point']) mip2.grid[tuple(pneumocyte_cell_voxel)] += mip2.pneumocyte_secretion_rate_unit_t # interact with macrophages for macrophage_cell_index in macrophage.cells.alive(): macrophage_cell: MacrophageCellData = macrophage.cells[macrophage_cell_index] if macrophage_cell['tnfa']: macrophage_cell_voxel: Voxel = grid.get_voxel(macrophage_cell['point']) mip2.grid[tuple(macrophage_cell_voxel)] += mip2.macrophage_secretion_rate_unit_t # Degrade MIP2 mip2.grid *= mip2.half_life_multiplier mip2.grid *= turnover_rate( x=np.array(1.0, dtype=np.float64), x_system=0.0, base_turnover_rate=molecules.turnover_rate, rel_cyt_bind_unit_t=molecules.rel_cyt_bind_unit_t, ) # Diffusion of MIP2 mip2.grid[:] = apply_diffusion( variable=mip2.grid, laplacian=molecules.laplacian, diffusivity=molecules.diffusion_constant, dt=self.time_step, ) return state
def recruit_macrophages(self, state: State) -> None: """ Recruit macrophages based on MIP1b activation Parameters ---------- state : State global simulation state Returns ------- nothing """ from nlisim.modules.mip1b import MIP1BState from nlisim.util import TissueType, activation_function macrophage: MacrophageState = state.macrophage mip1b: MIP1BState = state.mip1b voxel_volume: float = state.voxel_volume space_volume: float = state.space_volume lung_tissue = state.lung_tissue # 1. compute number of macrophages to recruit num_live_macrophages = len(macrophage.cells.alive()) avg = (macrophage.recruitment_rate * np.sum(mip1b.grid) * (1 - num_live_macrophages / macrophage.max_ma) / (mip1b.k_d * space_volume)) number_to_recruit = max( np.random.poisson(avg) if avg > 0 else 0, macrophage.min_ma - num_live_macrophages) # 2. get voxels for new macrophages, based on activation if number_to_recruit > 0: activation_voxels = zip(*np.where( np.logical_and( activation_function( x=mip1b.grid, k_d=mip1b.k_d, h=self.time_step / 60, volume=voxel_volume, b=macrophage.rec_bias, ) < rg.uniform(size=mip1b.grid.shape), lung_tissue != TissueType.AIR, ))) dz_field: np.ndarray = state.grid.delta(axis=0) dy_field: np.ndarray = state.grid.delta(axis=1) dx_field: np.ndarray = state.grid.delta(axis=2) for coordinates in rg.choice(tuple(activation_voxels), size=number_to_recruit, replace=True): vox_z, vox_y, vox_x = coordinates # the x,y,z coordinates are in the centers of the grids z = state.grid.z[vox_z] y = state.grid.y[vox_y] x = state.grid.x[vox_x] dz = dz_field[vox_z, vox_y, vox_x] dy = dy_field[vox_z, vox_y, vox_x] dx = dx_field[vox_z, vox_y, vox_x] self.create_macrophage( state=state, x=x + rg.uniform(-dx / 2, dx / 2), y=y + rg.uniform(-dy / 2, dy / 2), z=z + rg.uniform(-dz / 2, dz / 2), )
def initialize(self, state: State): from nlisim.util import TissueType macrophage: MacrophageState = state.macrophage lung_tissue = state.lung_tissue time_step_size: float = self.time_step macrophage.max_conidia = self.config.getint( 'max_conidia') # (from phagocyte model) units: count macrophage.time_to_rest = self.config.getint( 'time_to_rest') # units: min macrophage.time_to_change_state = self.config.getint( 'time_to_change_state') # units: hours macrophage.ma_internal_iron = self.config.getfloat( 'ma_internal_iron') # units: atto-mols macrophage.max_ma = self.config.getint('max_ma') # units: count macrophage.min_ma = self.config.getint('min_ma') # units: count macrophage.init_num_macrophages = self.config.getint( 'init_num_macrophages') # units: count macrophage.recruitment_rate = self.config.getfloat('recruitment_rate') macrophage.rec_bias = self.config.getfloat('rec_bias') macrophage.drift_bias = self.config.getfloat('drift_bias') macrophage.ma_move_rate_act = self.config.getfloat( 'ma_move_rate_act') # µm/min macrophage.ma_move_rate_rest = self.config.getfloat( 'ma_move_rate_rest') # µm/min macrophage.half_life = self.config.getfloat( 'ma_half_life') # units: hours # UNUSED: # macrophage.kd_ma_iron = self.config.getfloat('kd_ma_iron') # macrophage.ma_vol = self.config.getfloat('ma_vol') # computed values macrophage.iter_to_rest = int( macrophage.time_to_rest / self.time_step) # units: min / (min/step) = steps macrophage.iter_to_change_state = int( macrophage.time_to_change_state * (60 / time_step_size)) # units: hours * (min/hour) / (min/step) = step macrophage.prob_death_per_timestep = -math.log(0.5) / ( macrophage.half_life * (60 / time_step_size) ) # units: 1/( hours * (min/hour) / (min/step) ) = 1/step # initialize cells, placing them randomly locations = list(zip(*np.where(lung_tissue != TissueType.AIR))) dz_field: np.ndarray = state.grid.delta(axis=0) dy_field: np.ndarray = state.grid.delta(axis=1) dx_field: np.ndarray = state.grid.delta(axis=2) for vox_z, vox_y, vox_x in random.choices( locations, k=macrophage.init_num_macrophages): # the x,y,z coordinates are in the centers of the grids z = state.grid.z[vox_z] y = state.grid.y[vox_y] x = state.grid.x[vox_x] dz = dz_field[vox_z, vox_y, vox_x] dy = dy_field[vox_z, vox_y, vox_x] dx = dx_field[vox_z, vox_y, vox_x] self.create_macrophage( state=state, x=x + rg.uniform(-dx / 2, dx / 2), y=y + rg.uniform(-dy / 2, dy / 2), z=z + rg.uniform(-dz / 2, dz / 2), iron_pool=macrophage.ma_internal_iron, ) return state
def advance(self, state: State, previous_time: float): """Advance the state by a single time step.""" from nlisim.modules.afumigatus import ( Afumigatus, AfumigatusCellData, AfumigatusCellStatus, AfumigatusState, ) from nlisim.modules.iron import IronState from nlisim.modules.macrophage import MacrophageCellData, MacrophageState neutrophil: NeutrophilState = state.neutrophil macrophage: MacrophageState = state.macrophage afumigatus: AfumigatusState = state.afumigatus iron: IronState = state.iron grid: RectangularGrid = state.grid voxel_volume: float = state.voxel_volume space_volume: float = state.space_volume for neutrophil_cell_index in neutrophil.cells.alive(): neutrophil_cell = neutrophil.cells[neutrophil_cell_index] neutrophil_cell_voxel: Voxel = grid.get_voxel( neutrophil_cell['point']) self.update_status(state, neutrophil_cell) # ---------- interactions # dead and dying cells release iron if neutrophil_cell['status'] in { PhagocyteStatus.NECROTIC, PhagocyteStatus.APOPTOTIC, PhagocyteStatus.DEAD, }: iron.grid[tuple( neutrophil_cell_voxel)] += neutrophil_cell['iron_pool'] neutrophil_cell['iron_pool'] = 0 neutrophil_cell['dead'] = True # interact with fungus if neutrophil_cell[ 'state'] == PhagocyteState.FREE and neutrophil_cell[ 'status'] not in { PhagocyteStatus.APOPTOTIC, PhagocyteStatus.NECROTIC, PhagocyteStatus.DEAD, }: # get fungal cells in this voxel local_aspergillus = afumigatus.cells.get_cells_in_voxel( neutrophil_cell_voxel) for aspergillus_cell_index in local_aspergillus: aspergillus_cell: AfumigatusCellData = afumigatus.cells[ aspergillus_cell_index] if aspergillus_cell['dead']: continue if aspergillus_cell['status'] in { AfumigatusCellStatus.HYPHAE, AfumigatusCellStatus.GERM_TUBE, }: # possibly kill the fungal cell, extracellularly if rg.uniform() < neutrophil.pr_n_hyphae: interact_with_aspergillus( phagocyte_cell=neutrophil_cell, phagocyte_cell_index=neutrophil_cell_index, phagocyte_cells=neutrophil.cells, aspergillus_cell=aspergillus_cell, aspergillus_cell_index=aspergillus_cell_index, phagocyte=neutrophil, ) Afumigatus.kill_fungal_cell( afumigatus=afumigatus, afumigatus_cell=aspergillus_cell, afumigatus_cell_index=aspergillus_cell_index, iron=iron, grid=grid, ) else: neutrophil_cell[ 'state'] = PhagocyteState.INTERACTING elif aspergillus_cell[ 'status'] == AfumigatusCellStatus.SWELLING_CONIDIA: if rg.uniform() < neutrophil.pr_n_phagocyte: interact_with_aspergillus( phagocyte_cell=neutrophil_cell, phagocyte_cell_index=neutrophil_cell_index, phagocyte_cells=neutrophil.cells, aspergillus_cell=aspergillus_cell, aspergillus_cell_index=aspergillus_cell_index, phagocyte=neutrophil, ) # interact with macrophages: # if we are apoptotic, give our iron and phagosome to a nearby # present macrophage (if empty) if neutrophil_cell['status'] == PhagocyteStatus.APOPTOTIC: local_macrophages = macrophage.cells.get_cells_in_voxel( neutrophil_cell_voxel) for macrophage_index in local_macrophages: macrophage_cell: MacrophageCellData = macrophage.cells[ macrophage_index] macrophage_num_cells_in_phagosome = np.sum( macrophage_cell['phagosome'] >= 0) # TODO: Henrique, why only if empty? if macrophage_num_cells_in_phagosome == 0: macrophage_cell['phagosome'] = neutrophil_cell[ 'phagosome'] macrophage_cell['iron_pool'] += neutrophil_cell[ 'iron_pool'] neutrophil_cell['iron_pool'] = 0.0 neutrophil_cell['status'] = PhagocyteStatus.DEAD macrophage_cell['status'] = PhagocyteStatus.INACTIVE # Movement if neutrophil_cell['status'] == PhagocyteStatus.ACTIVE: max_move_step = neutrophil.n_move_rate_act * self.time_step else: max_move_step = neutrophil.n_move_rate_rest * self.time_step move_step: int = rg.poisson(max_move_step) # move the cell 1 µm, move_step number of times for _ in range(move_step): self.single_step_move(state, neutrophil_cell, neutrophil_cell_index, neutrophil.cells) # TODO: understand the meaning of the parameter here: moving randomly n steps is # different than moving n steps in a random direction. Which is it? # Recruitment self.recruit_neutrophils(state, space_volume, voxel_volume) return state
def advance(self, state: State, previous_time: float): """Advance the state by a single time step.""" from nlisim.modules.afumigatus import ( AfumigatusCellData, AfumigatusCellStatus, AfumigatusState, ) # from nlisim.modules.il6 import IL6State # from nlisim.modules.il8 import IL8State from nlisim.modules.tnfa import TNFaState pneumocyte: PneumocyteState = state.pneumocyte afumigatus: AfumigatusState = state.afumigatus # il6: IL6State = getattr(state, 'il6', None) # il8: IL8State = getattr(state, 'il8', None) tnfa: TNFaState = state.tnfa grid: RectangularGrid = state.grid voxel_volume: float = state.voxel_volume for pneumocyte_cell_index in pneumocyte.cells.alive(): pneumocyte_cell = pneumocyte.cells[pneumocyte_cell_index] pneumocyte_cell_voxel: Voxel = grid.get_voxel( pneumocyte_cell['point']) # self update if pneumocyte_cell['status'] == PhagocyteStatus.ACTIVE: if pneumocyte_cell[ 'status_iteration'] >= pneumocyte.iter_to_rest: pneumocyte_cell['status_iteration'] = 0 pneumocyte_cell['status'] = PhagocyteStatus.RESTING pneumocyte_cell['tnfa'] = False else: pneumocyte_cell['status_iteration'] += 1 elif pneumocyte_cell['status'] == PhagocyteStatus.ACTIVATING: if pneumocyte_cell[ 'status_iteration'] >= pneumocyte.iter_to_change_state: pneumocyte_cell['status_iteration'] = 0 pneumocyte_cell['status'] = PhagocyteStatus.ACTIVE else: pneumocyte_cell['status_iteration'] += 1 # ----------- interactions # interact with fungus if pneumocyte_cell['status'] not in { PhagocyteStatus.APOPTOTIC, PhagocyteStatus.NECROTIC, PhagocyteStatus.DEAD, }: local_aspergillus = afumigatus.cells.get_cells_in_voxel( pneumocyte_cell_voxel) for aspergillus_index in local_aspergillus: aspergillus_cell: AfumigatusCellData = afumigatus.cells[ aspergillus_index] # skip resting conidia if aspergillus_cell[ 'status'] == AfumigatusCellStatus.RESTING_CONIDIA: continue if pneumocyte_cell['status'] != PhagocyteStatus.ACTIVE: if rg.uniform() < pneumocyte.pr_p_int: pneumocyte_cell[ 'status'] = PhagocyteStatus.ACTIVATING else: # TODO: I don't get this, looks like it zeros out the iteration # when activating pneumocyte_cell['status_iteration'] = 0 # # secrete IL6 # if il6 is not None and pneumocyte_cell['status'] == PhagocyteStatus.ACTIVE: # il6.grid[tuple(pneumocyte_cell_voxel)] += pneumocyte.p_il6_qtty # # # secrete IL8 # if il8 is not None and pneumocyte_cell['tnfa']: # il8.grid[tuple(pneumocyte_cell_voxel)] += pneumocyte.p_il8_qtty # interact with TNFa if pneumocyte_cell['status'] == PhagocyteStatus.ACTIVE: if (activation_function( x=tnfa.grid[tuple(pneumocyte_cell_voxel)], k_d=tnfa.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) < rg.uniform()): pneumocyte_cell['status_iteration'] = 0 pneumocyte_cell['tnfa'] = True # secrete TNFa tnfa.grid[tuple( pneumocyte_cell_voxel)] += pneumocyte.p_tnf_qtty return state
def advance(self, state: State, previous_time: float) -> State: """Advance the state by a single time step.""" from nlisim.modules.macrophage import MacrophageCellData, MacrophageState from nlisim.modules.phagocyte import PhagocyteStatus tgfb: TGFBState = state.tgfb molecules: MoleculesState = state.molecules macrophage: MacrophageState = state.macrophage voxel_volume: float = state.voxel_volume grid: RectangularGrid = state.grid for macrophage_cell_index in macrophage.cells.alive(): macrophage_cell: MacrophageCellData = macrophage.cells[ macrophage_cell_index] macrophage_cell_voxel: Voxel = grid.get_voxel( macrophage_cell['point']) if macrophage_cell['status'] == PhagocyteStatus.INACTIVE: tgfb.grid[tuple(macrophage_cell_voxel )] += tgfb.macrophage_secretion_rate_unit_t if (activation_function( x=tgfb.grid[tuple(macrophage_cell_voxel)], k_d=tgfb.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) > rg.uniform()): macrophage_cell['status_iteration'] = 0 elif macrophage_cell['status'] not in { PhagocyteStatus.APOPTOTIC, PhagocyteStatus.NECROTIC, PhagocyteStatus.DEAD, }: if (activation_function( x=tgfb.grid[tuple(macrophage_cell_voxel)], k_d=tgfb.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) > rg.uniform()): macrophage_cell['status'] = PhagocyteStatus.INACTIVATING macrophage_cell[ 'status_iteration'] = 0 # Previously, was no reset of the status iteration # Degrade TGFB tgfb.grid *= tgfb.half_life_multiplier tgfb.grid *= turnover_rate( x=np.array(1.0, dtype=np.float64), x_system=0.0, base_turnover_rate=molecules.turnover_rate, rel_cyt_bind_unit_t=molecules.rel_cyt_bind_unit_t, ) # Diffusion of TGFB tgfb.grid[:] = apply_diffusion( variable=tgfb.grid, laplacian=molecules.laplacian, diffusivity=molecules.diffusion_constant, dt=self.time_step, ) return state
def initialize(self, state: State): neutrophil: NeutrophilState = state.neutrophil voxel_volume = state.voxel_volume lung_tissue = state.lung_tissue neutrophil.init_num_neutrophils = self.config.getint( 'init_num_neutrophils') # units: count neutrophil.time_to_change_state = self.config.getfloat( 'time_to_change_state') # units: hours neutrophil.max_conidia = self.config.getint( 'max_conidia') # (from phagocyte model) units: count neutrophil.recruitment_rate = self.config.getfloat('recruitment_rate') neutrophil.rec_bias = self.config.getfloat('rec_bias') neutrophil.max_neutrophils = self.config.getfloat( 'max_neutrophils') # units: count neutrophil.n_frac = self.config.getfloat('n_frac') neutrophil.drift_bias = self.config.getfloat('drift_bias') neutrophil.n_move_rate_act = self.config.getfloat('n_move_rate_act') neutrophil.n_move_rate_rest = self.config.getfloat('n_move_rate_rest') neutrophil.pr_n_hyphae_param = self.config.getfloat( 'pr_n_hyphae_param') neutrophil.pr_n_phagocyte_param = self.config.getfloat( 'pr_n_phagocyte_param') neutrophil.half_life = self.config.getfloat( 'half_life') # units: hours # computed values neutrophil.apoptosis_probability = -math.log(0.5) / ( neutrophil.half_life * (60 / self.time_step) # units: hours*(min/hour)/(min/step)=steps ) # units: probability neutrophil.iter_to_change_state = int( neutrophil.time_to_change_state * 60 / self.time_step) # units: hours * (min/hour) / (min/step) = steps neutrophil.pr_n_hyphae = -math.expm1(-self.time_step / 60 / ( voxel_volume * neutrophil.pr_n_hyphae_param)) # units: probability neutrophil.pr_n_phagocyte = -math.expm1( -self.time_step / 60 / (voxel_volume * neutrophil.pr_n_phagocyte_param)) # units: probability # place initial neutrophils locations = list(zip(*np.where(lung_tissue != TissueType.AIR))) dz_field: np.ndarray = state.grid.delta(axis=0) dy_field: np.ndarray = state.grid.delta(axis=1) dx_field: np.ndarray = state.grid.delta(axis=2) for vox_z, vox_y, vox_x in random.choices( locations, k=neutrophil.init_num_neutrophils): # the x,y,z coordinates are in the centers of the grids z = state.grid.z[vox_z] y = state.grid.y[vox_y] x = state.grid.x[vox_x] dz = dz_field[vox_z, vox_y, vox_x] dy = dy_field[vox_z, vox_y, vox_x] dx = dx_field[vox_z, vox_y, vox_x] self.create_neutrophil( state=state, x=x + rg.uniform(-dx / 2, dx / 2), y=y + rg.uniform(-dy / 2, dy / 2), z=z + rg.uniform(-dz / 2, dz / 2), ) return state
def recruit_neutrophils(self, state: State, space_volume: float, voxel_volume: float) -> None: """ Recruit neutrophils based on MIP2 activation Parameters ---------- state : State global simulation state space_volume : float voxel_volume : float Returns ------- nothing """ from nlisim.modules.mip2 import MIP2State from nlisim.util import TissueType, activation_function neutrophil: NeutrophilState = state.neutrophil mip2: MIP2State = state.mip2 lung_tissue = state.lung_tissue # 1. compute number of neutrophils to recruit num_live_neutrophils = len(neutrophil.cells.alive()) avg = (neutrophil.recruitment_rate * neutrophil.n_frac * np.sum(mip2.grid) * (1 - num_live_neutrophils / neutrophil.max_neutrophils) / (mip2.k_d * space_volume)) number_to_recruit = np.random.poisson(avg) if avg > 0 else 0 if number_to_recruit <= 0: return # 2. get voxels for new macrophages, based on activation activation_voxels = tuple( zip(*np.where( np.logical_and( activation_function( x=mip2.grid, k_d=mip2.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=neutrophil.rec_bias, ) < rg.uniform(size=mip2.grid.shape), lung_tissue != TissueType.AIR, )))) dz_field: np.ndarray = state.grid.delta(axis=0) dy_field: np.ndarray = state.grid.delta(axis=1) dx_field: np.ndarray = state.grid.delta(axis=2) for coordinates in rg.choice(activation_voxels, size=number_to_recruit, replace=True): vox_z, vox_y, vox_x = coordinates # the x,y,z coordinates are in the centers of the grids z = state.grid.z[vox_z] y = state.grid.y[vox_y] x = state.grid.x[vox_x] dz = dz_field[vox_z, vox_y, vox_x] dy = dy_field[vox_z, vox_y, vox_x] dx = dx_field[vox_z, vox_y, vox_x] self.create_neutrophil( state=state, x=x + rg.uniform(-dx / 2, dx / 2), y=y + rg.uniform(-dy / 2, dy / 2), z=z + rg.uniform(-dz / 2, dz / 2), )
def initialize(self, state: State): afumigatus: AfumigatusState = state.afumigatus voxel_volume = state.voxel_volume # units: L lung_tissue = state.lung_tissue afumigatus.pr_ma_hyphae_param = self.config.getfloat('pr_ma_hyphae_param') afumigatus.pr_ma_phag_param = self.config.getfloat('pr_ma_phag_param') afumigatus.phag_affinity_t = self.config.getfloat('phag_affinity_t') afumigatus.pr_branch = self.config.getfloat('pr_branch') # units: probability afumigatus.steps_to_bn_eval = self.config.getint('steps_to_bn_eval') # units: steps afumigatus.conidia_vol = self.config.getfloat('conidia_vol') # units: L afumigatus.hyphae_volume = self.config.getfloat('hyphae_volume') # units: L afumigatus.hyphal_length = self.config.getfloat('hyphal_length') # units: µm afumigatus.kd_lip = self.config.getfloat('kd_lip') # units: aM afumigatus.time_to_swelling = self.config.getfloat('time_to_swelling') # units: hours afumigatus.time_to_germinate = self.config.getfloat('time_to_germinate') # units: hours afumigatus.time_to_grow = self.config.getfloat('time_to_grow') # units: hours afumigatus.aspergillus_change_half_life = self.config.getfloat( 'aspergillus_change_half_life' ) # units: hours # computed values afumigatus.init_iron = afumigatus.kd_lip * afumigatus.conidia_vol # units: aM*L = atto-mols afumigatus.rel_phag_affinity_unit_t = self.time_step / afumigatus.phag_affinity_t afumigatus.pr_ma_hyphae = -math.expm1( -afumigatus.rel_phag_affinity_unit_t / (afumigatus.pr_ma_hyphae_param * voxel_volume) ) # exponent units: ?/(?*L) = TODO afumigatus.pr_ma_phag = -math.expm1( -afumigatus.rel_phag_affinity_unit_t / (voxel_volume * afumigatus.pr_ma_phag_param) ) # exponent units: ?/(?*L) = TODO afumigatus.iter_to_swelling = max( 0, int(afumigatus.time_to_swelling * (60 / self.time_step) - 2) ) # units: hours * (min/hour) / (min/step) = steps TODO: -2? afumigatus.iter_to_germinate = max( 0, int(afumigatus.time_to_germinate * (60 / self.time_step) - 2) ) # units: hours * (min/hour) / (min/step) = steps TODO: -2? afumigatus.iter_to_grow = max( 0, int(afumigatus.time_to_grow * 60 / self.time_step) - 1 ) # units: hours * (min/hour) / (min/step) = steps afumigatus.pr_aspergillus_change = -math.log(0.5) / ( afumigatus.aspergillus_change_half_life * (60 / self.time_step) ) # place cells for initial infection locations = list(zip(*np.where(lung_tissue == TissueType.EPITHELIUM))) dz_field: np.ndarray = state.grid.delta(axis=0) dy_field: np.ndarray = state.grid.delta(axis=1) dx_field: np.ndarray = state.grid.delta(axis=2) for vox_z, vox_y, vox_x in random.choices( locations, k=self.config.getint('init_infection_num') ): # the x,y,z coordinates are in the centers of the grids z = state.grid.z[vox_z] y = state.grid.y[vox_y] x = state.grid.x[vox_x] dz = dz_field[vox_z, vox_y, vox_x] dy = dy_field[vox_z, vox_y, vox_x] dx = dx_field[vox_z, vox_y, vox_x] afumigatus.cells.append( AfumigatusCellData.create_cell( point=Point( x=x + rg.uniform(-dx / 2, dx / 2), y=y + rg.uniform(-dy / 2, dy / 2), z=z + rg.uniform(-dz / 2, dz / 2), ), iron_pool=afumigatus.init_iron, ) ) return state
def advance(self, state: State, previous_time: float) -> State: """Advance the state by a single time step.""" from nlisim.modules.macrophage import MacrophageCellData, MacrophageState from nlisim.modules.neutrophil import NeutrophilCellData, NeutrophilState from nlisim.modules.phagocyte import PhagocyteStatus tnfa: TNFaState = state.tnfa molecules: MoleculesState = state.molecules macrophage: MacrophageState = state.macrophage neutrophil: NeutrophilState = state.neutrophil voxel_volume: float = state.voxel_volume grid: RectangularGrid = state.grid for macrophage_cell_index in macrophage.cells.alive(): macrophage_cell: MacrophageCellData = macrophage.cells[macrophage_cell_index] macrophage_cell_voxel: Voxel = grid.get_voxel(macrophage_cell['point']) if macrophage_cell['status'] == PhagocyteStatus.ACTIVE: tnfa.grid[tuple(macrophage_cell_voxel)] += tnfa.macrophage_secretion_rate_unit_t if macrophage_cell['status'] in {PhagocyteStatus.RESTING, PhagocyteStatus.ACTIVE}: if ( activation_function( x=tnfa.grid[tuple(macrophage_cell_voxel)], k_d=tnfa.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) > rg.uniform() ): if macrophage_cell['status'] == PhagocyteStatus.RESTING: macrophage_cell['status'] = PhagocyteStatus.ACTIVATING else: macrophage_cell['status'] = PhagocyteStatus.ACTIVE # Note: multiple activations will reset the 'clock' macrophage_cell['status_iteration'] = 0 macrophage_cell['tnfa'] = True for neutrophil_cell_index in neutrophil.cells.alive(): neutrophil_cell: NeutrophilCellData = neutrophil.cells[neutrophil_cell_index] neutrophil_cell_voxel: Voxel = grid.get_voxel(neutrophil_cell['point']) if neutrophil_cell['status'] == PhagocyteStatus.ACTIVE: tnfa.grid[tuple(neutrophil_cell_voxel)] += tnfa.neutrophil_secretion_rate_unit_t if neutrophil_cell['status'] in {PhagocyteStatus.RESTING, PhagocyteStatus.ACTIVE}: if ( activation_function( x=tnfa.grid[tuple(neutrophil_cell_voxel)], k_d=tnfa.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) > rg.uniform() ): if neutrophil_cell['status'] == PhagocyteStatus.RESTING: neutrophil_cell['status'] = PhagocyteStatus.ACTIVATING else: neutrophil_cell['status'] = PhagocyteStatus.ACTIVE # Note: multiple activations will reset the 'clock' neutrophil_cell['status_iteration'] = 0 neutrophil_cell['tnfa'] = True # Degrade TNFa tnfa.grid *= tnfa.half_life_multiplier tnfa.grid *= turnover_rate( x=np.array(1.0, dtype=np.float64), x_system=0.0, base_turnover_rate=molecules.turnover_rate, rel_cyt_bind_unit_t=molecules.rel_cyt_bind_unit_t, ) # Diffusion of TNFa tnfa.grid[:] = apply_diffusion( variable=tnfa.grid, laplacian=molecules.laplacian, diffusivity=molecules.diffusion_constant, dt=self.time_step, ) return state