Module nlisim.modules.erythrocyte
Expand source code
import math
from typing import Any, Dict
import attr
from attr import attrib, attrs
import numpy as np
from nlisim.coordinates import Voxel
from nlisim.grid import RectangularGrid
from nlisim.module import ModuleModel, ModuleState
from nlisim.modules.afumigatus import AfumigatusCellStatus, AfumigatusState
from nlisim.modules.hemoglobin import HemoglobinState
from nlisim.modules.hemolysin import HemolysinState
from nlisim.modules.macrophage import MacrophageState
from nlisim.modules.molecules import MoleculesState
from nlisim.state import State
from nlisim.util import TissueType, activation_function
# note: treating these a bit more like molecules than cells.
# hence the adaptation of molecule_grid_factory
def cell_grid_factory(self: 'ErythrocyteState') -> np.ndarray:
return np.zeros(
shape=self.global_state.grid.shape,
dtype=[('count', np.int64), ('hemoglobin', np.float64), ('hemorrhage', bool)],
)
@attrs(kw_only=True)
class ErythrocyteState(ModuleState):
cells: np.ndarray = attrib(default=attr.Factory(cell_grid_factory, takes_self=True))
kd_hemo: float
init_erythrocyte_level: int # units: count
max_erythrocyte_voxel: int # units: count
hemoglobin_quantity: float # units: atto-mols
pr_macrophage_phagocytize_erythrocyte_param: float
pr_macrophage_phagocytize_erythrocyte: float # units: probability
class ErythrocyteModel(ModuleModel):
name = 'erythrocyte'
StateClass = ErythrocyteState
def initialize(self, state: State):
erythrocyte: ErythrocyteState = state.erythrocyte
voxel_volume = state.voxel_volume
lung_tissue = state.lung_tissue
time_step_size: float = self.time_step
erythrocyte.kd_hemo = self.config.getfloat('kd_hemo')
erythrocyte.init_erythrocyte_level = self.config.getint(
'init_erythrocyte_level'
) # units: count
erythrocyte.max_erythrocyte_voxel = self.config.getint(
'max_erythrocyte_voxel'
) # units: count
erythrocyte.hemoglobin_quantity = self.config.getfloat(
'hemoglobin_concentration'
) # units: atto-mols
erythrocyte.pr_macrophage_phagocytize_erythrocyte_param = self.config.getfloat(
'pr_macrophage_phagocytize_erythrocyte_param'
)
# initialize cells
# TODO: discuss
erythrocyte.cells[lung_tissue == TissueType.BLOOD] = erythrocyte.init_erythrocyte_level
erythrocyte.pr_macrophage_phagocytize_erythrocyte = -math.expm1(
-time_step_size
/ 60
/ voxel_volume
/ erythrocyte.pr_macrophage_phagocytize_erythrocyte_param
)
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 summary_stats(self, state: State) -> Dict[str, Any]:
erythrocyte: ErythrocyteState = state.erythrocyte
# voxel_volume = state.voxel_volume
return {
'count': int(np.sum(erythrocyte.cells['count'])),
}
def visualization_data(self, state: State):
erythrocyte: ErythrocyteState = state.erythrocyte
return 'molecule', erythrocyte.cells
Functions
def cell_grid_factory(self: ErythrocyteState) ‑> numpy.ndarray
-
Expand source code
def cell_grid_factory(self: 'ErythrocyteState') -> np.ndarray: return np.zeros( shape=self.global_state.grid.shape, dtype=[('count', np.int64), ('hemoglobin', np.float64), ('hemorrhage', bool)], )
Classes
class ErythrocyteModel (config: SimulationConfig)
-
Expand source code
class ErythrocyteModel(ModuleModel): name = 'erythrocyte' StateClass = ErythrocyteState def initialize(self, state: State): erythrocyte: ErythrocyteState = state.erythrocyte voxel_volume = state.voxel_volume lung_tissue = state.lung_tissue time_step_size: float = self.time_step erythrocyte.kd_hemo = self.config.getfloat('kd_hemo') erythrocyte.init_erythrocyte_level = self.config.getint( 'init_erythrocyte_level' ) # units: count erythrocyte.max_erythrocyte_voxel = self.config.getint( 'max_erythrocyte_voxel' ) # units: count erythrocyte.hemoglobin_quantity = self.config.getfloat( 'hemoglobin_concentration' ) # units: atto-mols erythrocyte.pr_macrophage_phagocytize_erythrocyte_param = self.config.getfloat( 'pr_macrophage_phagocytize_erythrocyte_param' ) # initialize cells # TODO: discuss erythrocyte.cells[lung_tissue == TissueType.BLOOD] = erythrocyte.init_erythrocyte_level erythrocyte.pr_macrophage_phagocytize_erythrocyte = -math.expm1( -time_step_size / 60 / voxel_volume / erythrocyte.pr_macrophage_phagocytize_erythrocyte_param ) 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 summary_stats(self, state: State) -> Dict[str, Any]: erythrocyte: ErythrocyteState = state.erythrocyte # voxel_volume = state.voxel_volume return { 'count': int(np.sum(erythrocyte.cells['count'])), } def visualization_data(self, state: State): erythrocyte: ErythrocyteState = state.erythrocyte return 'molecule', erythrocyte.cells
Ancestors
Inherited members
class ErythrocyteState (*, global_state: State, cells: numpy.ndarray = NOTHING)
-
Base type intended to store the state for simulation modules.
This class contains serialization support for basic types (float, int, str, bool) and numpy arrays of those types. Modules containing more complicated state must override the serialization mechanism with custom behavior.
Method generated by attrs for class ErythrocyteState.
Expand source code
class ErythrocyteState(ModuleState): cells: np.ndarray = attrib(default=attr.Factory(cell_grid_factory, takes_self=True)) kd_hemo: float init_erythrocyte_level: int # units: count max_erythrocyte_voxel: int # units: count hemoglobin_quantity: float # units: atto-mols pr_macrophage_phagocytize_erythrocyte_param: float pr_macrophage_phagocytize_erythrocyte: float # units: probability
Ancestors
Class variables
var cells : numpy.ndarray
var hemoglobin_quantity : float
var init_erythrocyte_level : int
var kd_hemo : float
var max_erythrocyte_voxel : int
var pr_macrophage_phagocytize_erythrocyte : float
var pr_macrophage_phagocytize_erythrocyte_param : float
Inherited members