"""Defines specimens, blocks, and slides."""
from enum import IntEnum
from abc import ABC
from typing import TYPE_CHECKING, Generic, TypeVar
import salabim as sim
if TYPE_CHECKING:
from .model import Model
[docs]
class Priority(IntEnum):
"""Specimen priority. Lower value = higher priority."""
ROUTINE = 0
CANCER = -1
PRIORITY = -2
URGENT = -3
[docs]
class Component(sim.Component, ABC):
"""A salabim component with additional fields."""
prio: Priority
"""Priority of the component (Urgent, Priority, Cancer, or Routine)."""
parent: 'Component | None'
"""The parent component, if it exists."""
C = TypeVar('C', bound=Component)
[docs]
class Specimen(Component):
"""A tissue specimen.
Atrributes:
blocks:
The list of blocks produced from this specimen, empty if cut-up has not yet started.
"""
[docs]
def setup(self, **kwargs) -> None:
"""Set up the component, called immediately after initialisation."""
self.env: Model
self.env.specimen_data[self.name()] = kwargs
self.blocks: list[Block] = []
self.env.specimen_data[self.name()]['source'] = sim.CumPdf(
spec=('Internal', 'External'),
cumprobabilities=(self.env.globals.prob_internal, 1),
randomstream=self.env.rng,
env=self.env
).sample()
dist = 'cancer' if kwargs.get('cancer', False) else 'non_cancer'
self.prio: Priority = sim.CumPdf(
spec=(
Priority.URGENT,
Priority.PRIORITY,
Priority.CANCER if dist == 'cancer' else Priority.ROUTINE
),
cumprobabilities=(
getattr(self.env.globals, f'prob_urgent_{dist}'),
getattr(self.env.globals, f'prob_urgent_{dist}')
+ getattr(self.env.globals, f'prob_priority_{dist}'),
1
),
randomstream=self.env.rng,
env=self.env
).sample()
self.env.specimen_data[self.name()]['priority'] = self.prio.name
[docs]
def process(self):
"""Insert specimen into the `arrive_reception` in-queue."""
self.enter(self.env.processes['arrive_reception'].in_queue)
[docs]
def timestamp(self, name: str):
"""Save timestamp data to `self.env.specimen_data`."""
self.env.specimen_data[self.name()][name] = self.env.now()
[docs]
class Block(Component):
"""A wax block (or cassette to be turned into a wax block).
Atrributes:
slides:
The list of slides produced from this specimen, empty if microtomy has not yet started.
data:
A dict of additional data associated with the block.
"""
[docs]
def setup(self, parent: Specimen, **kwargs) -> None: # pylint: disable=arguments-differ
"""Set up the component, called immediately after initialisation."""
self.env: Model
self.parent = parent
self.prio = self.parent.prio
self.slides: list[Slide] = []
self.data = kwargs
[docs]
class Slide(Component):
"""A glass slide.
Atrributes:
data:
A dict of additional data associated with the slide.
"""
[docs]
def setup(self, parent: Block, **kwargs) -> None: # pylint: disable=arguments-differ
"""Set up the component, called immediately after initialisation."""
self.env: Model
self.parent: Block = parent
self.prio = self.parent.prio
self.data = kwargs
[docs]
class Batch(Component, Generic[C]):
"""A batch of Component objects.
Attributes:
items: The list of items within the batch.
data:
A dict of additional data associated with the batch.
"""
[docs]
def setup(self, **kwargs) -> None: # pylint: disable=arguments-differ
"""Set up the component, called immediately after initialisation."""
self.env: Model
self.data = kwargs
self.items: list[C] = []