def advance(self, state: State, previous_time: float) -> State: """Advance the state by a single time step.""" from nlisim.modules.macrophage import MacrophageState hepcidin: HepcidinState = state.hepcidin macrophage: MacrophageState = state.macrophage voxel_volume: float = state.voxel_volume # interaction with macrophages activated_voxels = zip(*np.where( activation_function( x=hepcidin.grid, k_d=hepcidin.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) > rg.random(size=hepcidin.grid.shape))) for z, y, x in activated_voxels: for macrophage_cell_index in macrophage.cells.get_cells_in_voxel( Voxel(x=x, y=y, z=z)): macrophage_cell = macrophage.cells[macrophage_cell_index] macrophage_cell['fpn'] = False macrophage_cell['fpn_iteration'] = 0 # Degrading Hepcidin is done by the "liver" # hepcidin does not diffuse 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 single_step_probabilistic_drift(self, state: State, cell: PhagocyteCellData, voxel: Voxel) -> Point: """ Calculate a 1µm movement of a neutrophil Parameters ---------- state : State global simulation state cell : NeutrophilCellData a neutrophil cell voxel : Voxel current voxel position of the neutrophil Returns ------- Point the new position of the neutrophil """ # neutrophils are attracted by MIP2 neutrophil: NeutrophilState = state.neutrophil mip2: MIP2State = state.mip2 grid: RectangularGrid = state.grid lung_tissue: np.ndarray = state.lung_tissue voxel_volume: float = state.voxel_volume # neutrophil has a non-zero probability of moving into non-air voxels nearby_voxels: Tuple[Voxel, ...] = tuple(grid.get_adjacent_voxels(voxel)) weights = np.array( [ 0.0 if lung_tissue[tuple(vxl)] == TissueType.AIR else activation_function( x=mip2.grid[tuple(vxl)], k_d=mip2.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) + neutrophil.drift_bias for vxl in nearby_voxels ], dtype=np.float64, ) voxel_movement_direction: Voxel = choose_voxel_by_prob( voxels=nearby_voxels, default_value=voxel, weights=weights) # get normalized direction vector dp_dt: np.ndarray = grid.get_voxel_center( voxel_movement_direction) - grid.get_voxel_center(voxel) norm = np.linalg.norm(dp_dt) if norm > 0.0: dp_dt /= norm return cell['point'] + dp_dt
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 advance(self, state: State, previous_time: float): erythrocyte: ErythrocyteState = state.erythrocyte molecules: MoleculesState = state.molecules hemoglobin: HemoglobinState = state.hemoglobin hemolysin: HemolysinState = state.hemolysin macrophage: MacrophageState = state.macrophage afumigatus: AfumigatusState = state.afumigatus grid: RectangularGrid = state.grid voxel_volume: float = state.voxel_volume shape = erythrocyte.cells['count'].shape # erythrocytes replenish themselves avg_number_of_new_erythrocytes = (1 - molecules.turnover_rate) * ( 1 - erythrocyte.cells['count'] / erythrocyte.max_erythrocyte_voxel) mask = avg_number_of_new_erythrocytes > 0 erythrocyte.cells['count'][mask] += np.random.poisson( avg_number_of_new_erythrocytes[mask], avg_number_of_new_erythrocytes[mask].shape) # ---------- interactions # uptake hemoglobin erythrocyte.cells['hemoglobin'] += hemoglobin.grid hemoglobin.grid.fill(0.0) # interact with hemolysin. pop goes the blood cell # TODO: avg? variable name improvement? avg_lysed_erythrocytes = erythrocyte.cells[ 'count'] * activation_function( x=hemolysin.grid, k_d=erythrocyte.kd_hemo, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) number_lysed = np.minimum( np.random.poisson(avg_lysed_erythrocytes, shape), erythrocyte.cells['count']) erythrocyte.cells[ 'hemoglobin'] += number_lysed * erythrocyte.hemoglobin_quantity erythrocyte.cells['count'] -= number_lysed # interact with Macrophage erythrocytes_to_hemorrhage = erythrocyte.cells[ 'hemorrhage'] * np.random.poisson( erythrocyte.pr_macrophage_phagocytize_erythrocyte * erythrocyte.cells['count'], shape) for z, y, x in zip(*np.where(erythrocytes_to_hemorrhage > 0)): local_macrophages = macrophage.cells.get_cells_in_voxel( Voxel(x=x, y=y, z=z)) num_local_macrophages = len(local_macrophages) for macrophage_index in local_macrophages: macrophage_cell = macrophage.cells[macrophage_index] if macrophage_cell['dead']: continue macrophage_cell['iron_pool'] += ( 4 # number of iron atoms in hemoglobin * erythrocyte.hemoglobin_quantity * erythrocytes_to_hemorrhage[z, y, x] / num_local_macrophages) erythrocyte.cells['count'] -= erythrocytes_to_hemorrhage # interact with fungus for fungal_cell_index in afumigatus.cells.alive(): fungal_cell = afumigatus.cells[fungal_cell_index] if fungal_cell['status'] == AfumigatusCellStatus.HYPHAE: fungal_voxel: Voxel = grid.get_voxel(fungal_cell['point']) erythrocyte.cells['hemorrhage'][tuple(fungal_voxel)] = True 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 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 single_step_probabilistic_drift(self, state: State, cell: PhagocyteCellData, voxel: Voxel) -> Point: """ Calculate a 1µm movement of a macrophage Parameters ---------- state : State global simulation state cell : MacrophageCellData a macrophage cell voxel : Voxel current voxel position of the macrophage Returns ------- Point the new position of the macrophage """ # macrophages are attracted by MIP1b from nlisim.modules.mip1b import MIP1BState from nlisim.util import TissueType, activation_function macrophage: MacrophageState = state.macrophage mip1b: MIP1BState = state.mip1b grid: RectangularGrid = state.grid lung_tissue: np.ndarray = state.lung_tissue voxel_volume: float = state.voxel_volume # compute chemokine influence on velocity, with some randomness. # macrophage has a non-zero probability of moving into non-air voxels. # if not any of these, stay in place. This could happen if e.g. you are # somehow stranded in air. nearby_voxels: Tuple[Voxel, ...] = tuple( grid.get_adjacent_voxels(voxel, corners=True)) weights = np.array( [ 0.0 if lung_tissue[tuple(vxl)] == TissueType.AIR else activation_function( x=mip1b.grid[tuple(vxl)], k_d=mip1b.k_d, h=self.time_step / 60, # units: (min/step) / (min/hour) volume=voxel_volume, b=1, ) + macrophage.drift_bias for vxl in nearby_voxels ], dtype=np.float64, ) voxel_movement_direction: Voxel = choose_voxel_by_prob( voxels=nearby_voxels, default_value=voxel, weights=weights) # get normalized direction vector dp_dt: np.ndarray = grid.get_voxel_center( voxel_movement_direction) - grid.get_voxel_center(voxel) norm = np.linalg.norm(dp_dt) if norm > 0.0: dp_dt /= norm # average and re-normalize with existing velocity dp_dt += cell['velocity'] norm = np.linalg.norm(dp_dt) if norm > 0.0: dp_dt /= norm # we need to determine if this movement will put us into an air voxel. This can happen # when pushed there by momentum. If that happens, we stay in place and zero out the # momentum. Otherwise, velocity is updated to dp/dt and movement is as expected. new_position = cell['point'] + dp_dt new_voxel: Voxel = grid.get_voxel(new_position) if state.lung_tissue[tuple(new_voxel)] == TissueType.AIR: cell['velocity'][:] = np.zeros(3, dtype=np.float64) return cell['point'] else: cell['velocity'][:] = dp_dt return new_position
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 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
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 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), )