Source code for cell_abm_pipeline.flows.convert_physicell_format

"""
Workflow for converting PhysiCell simulations to other formats.

Working location structure:

.. code-block:: bash

    (name)
    ├── converted
    │   └── converted.SIMULARIUM
    │       └── (name)_(key)_(seed).simularium
    └── data
        └── (name)_(key)_(seed).tar.xz

Formatted data are saved to **converted**.
"""

from dataclasses import dataclass, field

from io_collection.keys import make_key
from io_collection.load import load_tar
from io_collection.save import save_text
from prefect import flow

from cell_abm_pipeline.tasks.physicell import convert_physicell_to_simularium

FORMATS: list[str] = [
    "simularium",
]

SUBSTRATE_COLOR = "#d0c5c8"

CELL_COLORS = [
    "#fee34d",
    "#f7b232",
    "#bf5736",
    "#94a7fc",
    "#ce8ec9",
    "#58606c",
    "#0ba345",
    "#9267cb",
    "#81dbe6",
    "#bd7800",
    "#bbbb99",
    "#5b79f0",
    "#89a500",
    "#da8692",
    "#418463",
    "#9f516c",
    "#00aabf",
]


[docs]@dataclass class ParametersConfig: """Parameter configuration for convert PhysiCell format flow.""" box_size: tuple[float, float, float] = (1.0, 1.0, 1.0) """Size of bounding box.""" timestep: float = 1.0 """Simulation timestep.""" formats: list[str] = field(default_factory=lambda: FORMATS) """List of convert formats.""" substrate_color: str = SUBSTRATE_COLOR """Color for substrate.""" cell_colors: list[str] = field(default_factory=lambda: CELL_COLORS) """Colors for individual cells.""" frame_spec: tuple[int, int, int] = (0, 1, 1) """Specification for simulation ticks to use for converting to simularium."""
[docs]@dataclass class ContextConfig: """Context configuration for convert PhysiCell format flow.""" working_location: str """Location for input and output files (local path or S3 bucket)."""
[docs]@dataclass class SeriesConfig: """Series configuration for convert PhysiCell format flow.""" name: str """Name of the simulation series.""" seeds: list[int] """List of series random seeds.""" conditions: list[dict] """List of series condition dictionaries (must include unique condition "key")."""
[docs]@flow(name="convert-physicell-format") def run_flow(context: ContextConfig, series: SeriesConfig, parameters: ParametersConfig) -> None: """Main convert PhysiCell format flow.""" if "simularium" in parameters.formats: run_flow_convert_to_simularium(context, series, parameters)
[docs]@flow(name="convert-physicell-format_convert-to-simularium") def run_flow_convert_to_simularium( context: ContextConfig, series: SeriesConfig, parameters: ParametersConfig ) -> None: """Convert PhysiCell format subflow for Simularium.""" data_key = make_key(series.name, "data") converted_key = make_key(series.name, "converted", "converted.SIMULARIUM") keys = [condition["key"] for condition in series.conditions] for key in keys: for seed in series.seeds: series_key = f"{series.name}_{key}_{seed:04d}" tar_key = make_key(data_key, f"{series_key}.tar.xz") tar_file = load_tar(context.working_location, tar_key) simularium = convert_physicell_to_simularium( tar_file, parameters.box_size, parameters.timestep, parameters.frame_spec, parameters.substrate_color, parameters.cell_colors, ) simularium_key = make_key(converted_key, f"{series_key}.simularium") save_text(context.working_location, simularium_key, simularium)