Coverage for src/cell_abm_pipeline/flows/initialize_physicell_simulations.py: 0%
62 statements
« prev ^ index » next coverage.py v7.1.0, created at 2024-06-05 19:14 +0000
« prev ^ index » next coverage.py v7.1.0, created at 2024-06-05 19:14 +0000
1"""
2Workflow for initializing PhysiCell simulations.
4Working location structure:
6.. code-block:: bash
8 (name)
9 ├── inits
10 │ └── inits.PHYSICELL
11 │ └── (name)_(key)_(resolution).csv
12 └── plots
13 └── plots.COORDINATES
14 └── (name)_(key)_(resolution).COORDINATES.png
16Initialization consist of a single cell of the specified height and volume,
17sampled at the given spatial resolution. Coordinates are saved to
18**inits.PHYSICELL**.
19"""
21from dataclasses import dataclass, field
22from math import ceil, pi, sqrt
24import pandas as pd
25from abm_initialization_collection.coordinate import filter_coordinate_bounds, make_grid_coordinates
26from abm_initialization_collection.image import plot_contact_sheet
27from io_collection.keys import make_key
28from io_collection.save import save_dataframe, save_figure
29from prefect import flow
31# Default average cell height in um.
32AVERAGE_CELL_HEIGHT = 9.0
34# Default average cell volume in um^3.
35AVERAGE_CELL_VOLUME = 1300.0
37# Default cell id.
38DEFAULT_CELL_ID = 1
40# Substrate id.
41SUBSTRATE_ID = -1
44@dataclass
45class ParametersConfig:
46 """Parameter configuration for initialize PhysiCell simulations flow."""
48 grid: str = "rect"
49 """Type of sampling grid (rect = rectangular, hex = hexagonal)."""
51 ds: list[float] = field(default_factory=lambda: [1.0])
52 """Spatial scaling in um/voxel."""
54 bounding_box: tuple[int, int] = (100, 100)
55 """Size of bounding box in um."""
57 cell_height: float = AVERAGE_CELL_HEIGHT
58 """Average cell height in um."""
60 cell_volume: float = AVERAGE_CELL_VOLUME
61 """Average cell volume in um^3."""
63 substrate: bool = True
64 """True to include substrate in initialization, False otherwise."""
66 contact_sheet: bool = True
67 """True to save contact sheet of initialization, False otherwise."""
70@dataclass
71class ContextConfig:
72 """Context configuration for initialize PhysiCell simulations flow."""
74 working_location: str
75 """Location for input and output files (local path or S3 bucket)."""
78@dataclass
79class SeriesConfig:
80 """Series configuration for initialize PhysiCell simulations flow."""
82 name: str
83 """Name of the simulation series."""
86@flow(name="initialize-physicell-simulations")
87def run_flow(context: ContextConfig, series: SeriesConfig, parameters: ParametersConfig) -> None:
88 """Main initialize PhysiCell simulations flow."""
90 for ds in parameters.ds:
91 # Calculate cell radius and height.
92 cell_radius = sqrt(parameters.cell_volume / parameters.cell_height / pi)
93 cell_height = parameters.cell_height
95 # Adjust size of bounding box.
96 x_bound = ceil(parameters.bounding_box[0] / ds) * ds
97 y_bound = ceil(parameters.bounding_box[1] / ds) * ds
98 z_bound = ceil(cell_height)
100 # Generate full coordinates list.
101 grid_bounds = (ceil(x_bound + ds), ceil(y_bound + ds), ceil(z_bound + ds))
102 coords_list = make_grid_coordinates(parameters.grid, grid_bounds, ds, ds)
104 # Filter coordinates list for cell coordinates.
105 cell_coords_list = [
106 (x, y, z)
107 for x, y, z in coords_list
108 if x_bound / 2 - cell_radius <= x <= x_bound / 2 + cell_radius
109 and y_bound / 2 - cell_radius <= y <= y_bound / 2 + cell_radius
110 and z > 0
111 ]
112 cell_coords = filter_coordinate_bounds(cell_coords_list, cell_radius, center=False)
113 cell_coords["id"] = DEFAULT_CELL_ID
115 # If substrate is included, add the z = 0 coordinates. If not, adjust
116 # all the z positions of the cell coordinates.
117 if parameters.substrate:
118 substrate_coords_list = [(x, y, z) for x, y, z in coords_list if z == 0]
119 substrate_coords = pd.DataFrame(substrate_coords_list, columns=["x", "y", "z"])
120 substrate_coords["id"] = SUBSTRATE_ID
121 else:
122 cell_coords["z"] = cell_coords["z"] - ds
123 substrate_coords = pd.DataFrame()
125 # Save final list of coordinates.
126 coords = pd.concat([substrate_coords, cell_coords])
127 init_key = make_key(series.name, "inits", "inits.PHYSICELL", f"{series.name}_{ds}.csv")
128 save_dataframe(context.working_location, init_key, coords, index=False, header=False)
130 # Plot contact sheet of coordinates.
131 if parameters.contact_sheet:
132 contact_sheet = plot_contact_sheet(coords)
133 plot_key = make_key(
134 series.name, "plots", "plots.COORDINATES", f"{series.name}_{ds}.COORDINATES.png"
135 )
136 save_figure(context.working_location, plot_key, contact_sheet)