def test_produce_cytokines_n( macrophage_list: MacrophageCellList, grid: RectangularGrid, populated_fungus: FungusCellList, cyto, ): m_n = 10 macrophage_list.append( MacrophageCellData.create_cell(point=Point(x=grid.x[3], y=grid.y[3], z=grid.z[3]), )) vox = grid.get_voxel(macrophage_list[0]['point']) assert vox.z == 3 and vox.y == 3 and vox.x == 3 for cell in populated_fungus.cell_data: vox = grid.get_voxel(cell['point']) assert vox.z in [1, 2, 3, 4, 5] and vox.y in [1, 2, 3, 4, 5] and vox.x in [ 1, 2, 3, 4, 5 ] # 1 m_det = 1 assert cyto[3, 3, 3] == 0 macrophage_list.produce_cytokines(m_det, m_n, grid, populated_fungus, cyto) assert cyto[3, 3, 3] == 30 # 2 m_det = 2 cyto[3, 3, 3] = 0 macrophage_list.produce_cytokines(m_det, m_n, grid, populated_fungus, cyto) assert cyto[3, 3, 3] == 50
def test_internalize_conidia_0(macrophage_list: MacrophageCellList, grid: RectangularGrid, fungus_list: FungusCellList): m_det = 0 point = Point(x=35, y=35, z=35) macrophage_list.append(MacrophageCellData.create_cell(point=point)) fungus_list.append( FungusCellData.create_cell(point=point, status=FungusCellData.Status.RESTING)) vox = grid.get_voxel(macrophage_list[0]['point']) assert len(fungus_list.get_cells_in_voxel(vox)) == 1 f_index = fungus_list.get_cells_in_voxel(vox) # 0 assert f_index == 0 fungus_list[f_index]['form'] = FungusCellData.Form.CONIDIA fungus_list[f_index]['status'] = FungusCellData.Status.RESTING macrophage_list.internalize_conidia(m_det, 50, 1, grid, fungus_list) assert grid.get_voxel(fungus_list[f_index]['point']) == vox assert fungus_list.cell_data['internalized'][f_index] assert macrophage_list.len_phagosome(0) == 1
def test_produce_cytokines_n( neutrophil_list: NeutrophilCellList, grid: RectangularGrid, populated_fungus: FungusCellList, cyto, ): n_n = 10 neutrophil_list.append( NeutrophilCellData.create_cell( point=Point(x=grid.x[3], y=grid.y[3], z=grid.z[3]), status=NeutrophilCellData.Status.NONGRANULATING, granule_count=5, ) ) vox = grid.get_voxel(neutrophil_list[0]['point']) assert vox.z == 3 and vox.y == 3 and vox.x == 3 for cell in populated_fungus.cell_data: vox = grid.get_voxel(cell['point']) assert vox.z in [1, 2, 3, 4, 5] and vox.y in [1, 2, 3, 4, 5] and vox.x in [1, 2, 3, 4, 5] # 1 n_det = 1 assert cyto[3, 3, 3] == 0 neutrophil_list.produce_cytokines(n_det, n_n, grid, populated_fungus, cyto) assert cyto[3, 3, 3] == 30 # 2 n_det = 2 cyto[3, 3, 3] = 0 neutrophil_list.produce_cytokines(n_det, n_n, grid, populated_fungus, cyto) assert cyto[3, 3, 3] == 50
def periodic_discrete_laplacian( grid: RectangularGrid, mask: np.ndarray, dtype: np.dtype = _dtype_float64) -> csr_matrix: """Return a laplacian operator with periodic boundary conditions. This computes a standard laplacian operator as a scipy linear operator, except it is restricted to a grid mask. The use case for this is to compute surface diffusion on a gridded variable. The mask is generated from a category on the lung_tissue variable. """ graph_shape = len(grid), len(grid) z_extent, y_extent, x_extent = grid.shape laplacian = dok_matrix(graph_shape, dtype=dtype) delta_z = grid.delta(0) delta_y = grid.delta(1) delta_x = grid.delta(2) for k, j, i in zip(*(mask).nonzero()): voxel = Voxel(x=i, y=j, z=k) voxel_index = grid.get_flattened_index(voxel) for offset in [(-1, 0, 0), (1, 0, 0), (0, -1, 0), (0, 1, 0), (0, 0, -1), (0, 0, 1)]: # voxel coordinate displacements dk, dj, di = offset # find the neighbor for periodic boundary conditions neighbor: Voxel = Voxel(x=(i + di) % x_extent, y=(j + dj) % y_extent, z=(k + dk) % z_extent) # but maybe it isn't in the mask (i.e. air) if not mask[neighbor.z, neighbor.y, neighbor.x]: continue neighbor_index = grid.get_flattened_index(neighbor) # continuous space displacements dx = delta_x[k, j, i] * di dy = delta_y[k, j, i] * dj dz = delta_z[k, j, i] * dk inverse_distance2 = 1 / (dx * dx + dy * dy + dz * dz ) # units: 1/(µm^2) laplacian[voxel_index, voxel_index] -= inverse_distance2 laplacian[voxel_index, neighbor_index] += inverse_distance2 return laplacian.tocsr()
def test_move_1(populated_macrophage: MacrophageCellList, grid: RectangularGrid, cyto, tissue, fungus_list): rec_r = 10 cell = populated_macrophage[0] vox = grid.get_voxel(cell['point']) assert vox.z == 3 and vox.y == 3 and vox.x == 3 assert cyto.all() == 0 cyto[4, 3, 3] = 10 populated_macrophage.move(rec_r, grid, cyto, tissue, fungus_list) vox = grid.get_voxel(cell['point']) assert vox.z == 4 and vox.y == 3 and vox.x == 3
def test_move_1(populated_neutrophil: NeutrophilCellList, grid: RectangularGrid, cyto, tissue): rec_r = 10 cell = populated_neutrophil[0] vox = grid.get_voxel(cell['point']) assert vox.z == 3 and vox.y == 3 and vox.x == 3 assert cyto.all() == 0 cyto[4, 3, 3] = 10 populated_neutrophil.move(rec_r, grid, cyto, tissue) cell = populated_neutrophil[0] vox = grid.get_voxel(cell['point']) assert vox.z == 4 and vox.y == 3 and vox.x == 3
def load(cls, arg: Union[str, bytes, PurePath, IO[bytes]]) -> 'State': """Load a pickled state from either a path, a file, or blob of bytes.""" from nlisim.config import SimulationConfig # prevent circular imports if isinstance(arg, bytes): arg = BytesIO(arg) with H5File(arg, 'r') as hf: time = hf.attrs['time'] grid = RectangularGrid.load(hf) with StringIO(hf.attrs['config']) as cf: config = SimulationConfig(cf) state = cls(time=time, grid=grid, config=config) for module in config.modules: group = hf.get(module.name) if group is None: raise ValueError( f'File contains no group for {module.name}') try: module_state = module.StateClass.load_state(state, group) except Exception: print(f'Error loading state for {module.name}') raise state._extra[module.name] = module_state return state
def test_recruit_new_neutopenic_day_3(neutrophil_list, tissue, grid: RectangularGrid, cyto): rec_r = 2 rec_rate_ph = 6 granule_count = 5 neutropenic = True previous_time = 64 # between days 2 -4 # no cytokines assert cyto[5, 5, 5] == 0 cyto[5, 5, 5] = 2 # test recruit less due to neutropenic neutrophil_list.recruit_new( rec_rate_ph, rec_r, granule_count, neutropenic, previous_time, grid, tissue, cyto ) assert len(neutrophil_list) == 6 # test correct location recruitment neutropenic = False neutrophil_list.recruit_new( rec_rate_ph, rec_r, granule_count, neutropenic, previous_time, grid, tissue, cyto ) vox = grid.get_voxel(neutrophil_list[-1]['point']) assert vox.x == 5 and vox.y == 5 and vox.z == 5 assert len(neutrophil_list) == 12
def test_produce_cytokines_0( neutrophil_list: NeutrophilCellList, grid: RectangularGrid, populated_fungus: FungusCellList, cyto, ): n_det = 0 n_n = 10 assert cyto[3, 3, 3] == 0 neutrophil_list.append( NeutrophilCellData.create_cell( point=Point(x=grid.x[3], y=grid.y[3], z=grid.z[3]), status=NeutrophilCellData.Status.NONGRANULATING, granule_count=5, ) ) vox = grid.get_voxel(neutrophil_list[0]['point']) assert vox.z == 3 and vox.y == 3 and vox.x == 3 neutrophil_list.produce_cytokines(n_det, n_n, grid, populated_fungus, cyto) assert cyto[3, 3, 3] == 10
def test_damage_hyphae_0( neutrophil_list: NeutrophilCellList, grid: RectangularGrid, fungus_list: FungusCellList, iron ): n_det = 0 n_kill = 2 t = 1 health = 100 point = Point(x=35, y=35, z=35) neutrophil_list.append( NeutrophilCellData.create_cell( point=point, status=NeutrophilCellData.Status.NONGRANULATING, granule_count=5 ) ) # hyphae fungus_list.append( FungusCellData.create_cell( point=point, status=FungusCellData.Status.RESTING, form=FungusCellData.Form.HYPHAE ) ) neutrophil_list.damage_hyphae(n_det, n_kill, t, health, grid, fungus_list, iron) assert fungus_list[0]['health'] == 50 assert neutrophil_list[0]['granule_count'] == 4 assert neutrophil_list[0]['status'] == NeutrophilCellData.Status.GRANULATING vox = grid.get_voxel(neutrophil_list[0]['point']) assert iron[vox.z, vox.y, vox.x] == 0
def test_recruit_new(neutrophil_list, tissue, grid: RectangularGrid, cyto): rec_r = 2 rec_rate_ph = 2 granule_count = 5 neutropenic = False previous_time = 1 # no cytokines assert cyto[5, 5, 5] == 0 cyto[5, 5, 5] = 2 # test correct location recruitment neutrophil_list.recruit_new( rec_rate_ph, rec_r, granule_count, neutropenic, previous_time, grid, tissue, cyto ) vox = grid.get_voxel(neutrophil_list[-1]['point']) assert len(neutrophil_list) == 2 # TODO: why are x=y=z? what is the point of this? assert vox.x == 5 and vox.y == 5 and vox.z == 5 # test recruit none due to below threshold rec_r = 20 rec_rate_ph = 2 neutrophil_list.recruit_new( rec_rate_ph, rec_r, granule_count, neutropenic, previous_time, grid, tissue, cyto ) assert len(neutrophil_list) == 2
def test_internalize_conidia_1(epithelium_list: EpitheliumCellList, grid: RectangularGrid, fungus_list: FungusCellList): point = Point(x=35, y=35, z=35) epithelium_list.append(EpitheliumCellData.create_cell(point=point)) fungus_list.append( FungusCellData.create_cell(point=point, status=FungusCellData.Status.RESTING)) vox = grid.get_voxel(epithelium_list[0]['point']) epithelium_list.internalize_conidia(0, 10, 1, grid, fungus_list) assert grid.get_voxel(fungus_list[0]['point']) == vox assert epithelium_list.len_phagosome(0) == 1 assert 0 in epithelium_list[0]['phagosome']
def create(cls, config: 'SimulationConfig'): """Generate a new state object from a config.""" shape = ( config.getint('simulation', 'nz'), config.getint('simulation', 'ny'), config.getint('simulation', 'nx'), ) spacing = ( config.getfloat('simulation', 'dz'), config.getfloat('simulation', 'dy'), config.getfloat('simulation', 'dx'), ) grid = RectangularGrid.construct_uniform(shape, spacing) state = State(time=0.0, grid=grid, config=config) for module in state.config.modules: if hasattr(state, module.name): # prevent modules from overriding existing class attributes raise ValueError( f'The name "{module.name}" is a reserved token.') with validation_context(f'{module.name} (construction)'): state._extra[module.name] = module.StateClass( global_state=state) module.construct(state) return state
def test_recruit_new(macrophage_list, tissue, grid: RectangularGrid, cyto): rec_r = 2 p_rec_r = 1.0 rec_rate_ph = 2 # no cytokines assert cyto[1, 2, 3] == 0 cyto[1, 2, 3] = 2 # test correct location recruitment macrophage_list.recruit_new(rec_rate_ph, rec_r, p_rec_r, tissue, grid, cyto) vox = grid.get_voxel(macrophage_list[-1]['point']) assert len(macrophage_list) == 2 assert vox.x == 3 and vox.y == 2 and vox.z == 1 # test recruit none due to below threshold rec_r = 20 p_rec_r = 1.0 rec_rate_ph = 2 macrophage_list.recruit_new(rec_rate_ph, rec_r, p_rec_r, tissue, grid, cyto) assert len(macrophage_list) == 2
def discrete_laplacian(grid: RectangularGrid, mask: np.ndarray, dtype: np.dtype = np.float64) -> csr_matrix: """Return a discrete laplacian operator for the given restricted grid. This computes a standard laplacian operator as a scipy linear operator, except it is restricted to a grid mask. The use case for this is to compute surface diffusion on a gridded variable. The mask is generated from a category on the lung_tissue variable. """ graph_shape = len(grid), len(grid) laplacian = dok_matrix(graph_shape) delta_z = grid.delta(0) delta_y = grid.delta(1) delta_x = grid.delta(2) for k, j, i in zip(*(mask).nonzero()): voxel = Voxel(x=i, y=j, z=k) voxel_index = grid.get_flattened_index(voxel) normalization = 0 for neighbor in grid.get_adjecent_voxels(voxel, corners=False): ni = neighbor.x nj = neighbor.y nk = neighbor.z if not mask[nk, nj, ni]: continue neighbor_index = grid.get_flattened_index(neighbor) dx = delta_x[k, j, i] * (i - ni) dy = delta_y[k, j, i] * (j - nj) dz = delta_z[k, j, i] * (k - nk) distance2 = 1 / (dx * dx + dy * dy + dz * dz) normalization -= distance2 laplacian[voxel_index, neighbor_index] = distance2 laplacian[voxel_index, voxel_index] = normalization return laplacian.tocsr()
def test_move_cell(grid: RectangularGrid): point = Point(x=4.5, y=4.5, z=4.5) raw_cells = [CellData.create_cell(point=point) for _ in range(5)] raw_cells[1]['point'] = Point(x=-1, y=4.5, z=4.5) raw_cells[4]['point'] = Point(x=4.5, y=4.5, z=-1) cells = CellList(grid=grid) cells.extend(raw_cells) cells[0]['point'] = Point(x=50, y=50, z=50) # updating an incorrect index will not update the cell at index 0 cells.update_voxel_index([1, 3]) assert_array_equal(cells.get_neighboring_cells(cells[2]), [0, 2, 3]) assert cells._reverse_voxel_index[0] == grid.get_voxel(point) # this should correctly update the voxel index cells.update_voxel_index([0]) assert_array_equal(cells.get_neighboring_cells(cells[0]), [0]) assert cells._reverse_voxel_index[0] == grid.get_voxel(cells[0]['point'])
def test_internalize_and_move( macrophage_list: MacrophageCellList, grid: RectangularGrid, fungus_list: FungusCellList, cyto, tissue, ): point = Point(x=35, y=35, z=35) macrophage_list.append(MacrophageCellData.create_cell(point=point)) fungus_list.append( FungusCellData.create_cell(point=point, status=FungusCellData.Status.RESTING)) fungus_list.append( FungusCellData.create_cell(point=point, status=FungusCellData.Status.RESTING)) macrophage_list.internalize_conidia(1, 50, 1, grid, fungus_list) assert fungus_list.cell_data['internalized'][0] assert fungus_list.cell_data['internalized'][1] assert macrophage_list.len_phagosome(0) == 2 rec_r = 10 cell = macrophage_list[0] vox = grid.get_voxel(cell['point']) assert vox.z == 3 and vox.y == 3 and vox.x == 3 assert cyto.all() == 0 cyto[4, 3, 3] = 10 macrophage_list.move(rec_r, grid, cyto, tissue, fungus_list) vox = grid.get_voxel(cell['point']) assert vox.z == 4 and vox.y == 3 and vox.x == 3 for f in fungus_list: vox = grid.get_voxel(f['point']) assert vox.z == 4 and vox.y == 3 and vox.x == 3
def test_internalize_conidia_none( populated_epithelium: EpitheliumCellList, grid: RectangularGrid, fungus_list: FungusCellList, ): cell = populated_epithelium[0] vox = grid.get_voxel(cell['point']) assert len(fungus_list.get_cells_in_voxel(vox)) == 0 populated_epithelium.internalize_conidia(0, 10, 1, grid, fungus_list) assert populated_epithelium.len_phagosome(0) == 0 for v in cell['phagosome']: assert v == -1
def __init__(self, shape: ShapeType, space: SpacingType, scale: int, randomness: int): self.scale = scale self.randomness = randomness self.shape = (shape[0] * scale, shape[1] * scale, shape[2] * scale) self.space = space self.grid = RectangularGrid.construct_uniform(self.shape, self.space) self.geo = self.grid.allocate_variable(dtype=np.dtype(np.int8)) self.geo.fill(2) self.fixed = np.zeros(self.shape) self.duct_f: List[Union[Sphere, Cylinder]] = [] self.sac_f: List[Union[Sphere, Cylinder]] = []
def test_internalize_conidia_none( populated_macrophage: MacrophageCellList, grid: RectangularGrid, populated_fungus: FungusCellList, ): m_det = 0 cell = populated_macrophage[0] vox = grid.get_voxel(cell['point']) assert len(populated_fungus.get_cells_in_voxel(vox)) == 1 populated_macrophage.internalize_conidia(m_det, 50, 1, grid, populated_fungus) assert populated_macrophage.len_phagosome(0) == 0 for v in cell['phagosome']: assert v == -1
def test_recruit_new_multiple_locations(macrophage_list: MacrophageCellList, tissue, grid: RectangularGrid, cyto): rec_r = 2 p_rec_r = 1.0 rec_rate_ph = 50 cyto[1, 2, 3] = 2 cyto[4, 5, 6] = 2 macrophage_list.recruit_new(rec_rate_ph, rec_r, p_rec_r, tissue, grid, cyto) assert len(macrophage_list) == 50 for cell in macrophage_list.cell_data: vox = grid.get_voxel(cell['point']) assert vox.x in [3, 6] and vox.y in [2, 5] and vox.z in [1, 4]
def kill_fungal_cell( afumigatus: AfumigatusState, afumigatus_cell: AfumigatusCellData, afumigatus_cell_index: int, iron: IronState, grid: RectangularGrid, ): """Kill a fungal cell. Unlinks the cell from its fungal tree and releases its iron. """ # unlink from any children if afumigatus_cell['next_septa'] != -1: next_septa = afumigatus_cell['next_septa'] afumigatus_cell['next_septa'] = -1 afumigatus.cells[next_septa]['is_root'] = True afumigatus.cells[next_septa]['previous_septa'] = -1 if afumigatus_cell['next_branch'] != -1: next_branch = afumigatus_cell['next_branch'] afumigatus_cell['next_branch'] = -1 afumigatus.cells[next_branch]['is_root'] = True afumigatus.cells[next_branch]['previous_septa'] = -1 # unlink from parent, if exists parent_id = afumigatus_cell['previous_septa'] if parent_id != -1: afumigatus_cell['previous_septa'] = -1 parent_cell: AfumigatusCellData = afumigatus.cells[parent_id] if parent_cell['next_septa'] == afumigatus_cell_index: parent_cell['next_septa'] = -1 elif parent_cell['next_branch'] == afumigatus_cell_index: parent_cell['next_branch'] = -1 else: raise AssertionError("The fungal tree structure is malformed.") # kill the cell off and release its iron voxel: Voxel = grid.get_voxel(afumigatus_cell['point']) iron.grid[voxel.z, voxel.y, voxel.x] += afumigatus_cell['iron_pool'] afumigatus_cell['iron_pool'] = 0.0 afumigatus_cell['dead'] = True afumigatus_cell['status'] = AfumigatusCellStatus.DEAD
def test_recruit_new_multiple_locations( neutrophil_list: NeutrophilCellList, tissue, grid: RectangularGrid, cyto ): rec_r = 2 rec_rate_ph = 50 granule_count = 5 neutropenic = False previous_time = 1 cyto[5, 5, 5] = 2 cyto[4, 5, 5] = 2 neutrophil_list.recruit_new( rec_rate_ph, rec_r, granule_count, neutropenic, previous_time, grid, tissue, cyto ) assert len(neutrophil_list) == 50 for cell in neutrophil_list.cell_data: vox = grid.get_voxel(cell['point']) assert vox.x == 5 and vox.y == 5 and vox.z in [4, 5]
def create(cls, config: 'SimulationConfig'): """Generate a new state object from a config.""" voxel_volume = config.getfloat('simulation', 'voxel_volume') lung_tissue = get_geometry_file( config.get('simulation', 'geometry_path')) # python type checker isn't enough to understand this assert len(lung_tissue.shape) == 3 # noinspection PyTypeChecker shape: Tuple[int, int, int] = lung_tissue.shape space_volume = voxel_volume * np.product(shape) spacing = ( config.getfloat('simulation', 'dz'), config.getfloat('simulation', 'dy'), config.getfloat('simulation', 'dx'), ) grid = RectangularGrid.construct_uniform(shape, spacing) state = State( time=0.0, grid=grid, config=config, lung_tissue=lung_tissue, voxel_volume=voxel_volume, space_volume=space_volume, ) for module in state.config.modules: if hasattr(state, module.name): # prevent modules from overriding existing class attributes raise ValueError( f'The name "{module.name}" is a reserved token.') with validation_context(f'{module.name} (construction)'): state._extra[module.name] = module.StateClass( global_state=state) module.construct(state) return state
def test_produce_cytokines_0( macrophage_list: MacrophageCellList, grid: RectangularGrid, populated_fungus: FungusCellList, cyto, ): m_det = 0 m_n = 10 assert cyto[3, 3, 3] == 0 macrophage_list.append( MacrophageCellData.create_cell(point=Point(x=grid.x[3], y=grid.y[3], z=grid.z[3]), )) vox = grid.get_voxel(macrophage_list[0]['point']) assert vox.z == 3 and vox.y == 3 and vox.x == 3 macrophage_list.produce_cytokines(m_det, m_n, grid, populated_fungus, cyto) assert cyto[3, 3, 3] == 10
def grid(): # a 100 x 100 x 100 unit grid yield RectangularGrid.construct_uniform((10, 10, 10), (10, 10, 10))
def test_get_flattened_index(voxel, index, grid: RectangularGrid): assert grid.get_flattened_index(voxel) == index assert grid.voxel_from_flattened_index(index) == voxel
def test_get_voxel(grid: RectangularGrid, point, voxel): assert grid.get_voxel(point) == voxel
def test_valid_voxel(grid: RectangularGrid, voxel, valid): assert grid.is_valid_voxel(voxel) == valid
def test_get_adjacent_voxels(grid: RectangularGrid, voxel, neighbors): assert set(grid.get_adjacent_voxels(voxel)) == neighbors