Skip to content

Feat/physicell microenvironment - #6

Open
emcramer wants to merge 2 commits into
mainfrom
feat/physicell-microenvironment
Open

Feat/physicell microenvironment#6
emcramer wants to merge 2 commits into
mainfrom
feat/physicell-microenvironment

Conversation

@emcramer

Copy link
Copy Markdown
Owner

No description provided.

emcramer added 2 commits July 23, 2026 16:28
Implement the previously-empty microenvironment/ stub with three
composed, domain-framed analyses of tissue microenvironment structure:

- niches: identify_niches clusters neighborhood-composition vectors
  (k-means) into spatial niches — recurring local cell-type mixtures.
  Returns NicheResult with per-cell labels and per-niche profiles.

- boundaries: detect_boundaries scores each cell's neighborhood
  "foreignness" and flags interface cells. Generalizes the pairwise
  spatial.interface_cells to any grouping; accepts niche labels to find
  niche interfaces. Returns BoundaryResult.

- gradients: spatial_gradient estimates a scalar field's gradient by
  local linear regression (grid-agnostic); substrate_gradient wraps it
  over the voxel substrate field (dropping constant axes), and
  density_gradient over local cell density. Returns GradientField with
  magnitude and direction. Validated against a finite-difference
  reference on the regular voxel grid (corr > 0.97 interior).

Adds tests/test_microenvironment.py (24 tests), including known-answer
checks (linear field recovers exact gradient; two composition regions
split into two niches).
A pair-review of the substrate access and microenvironment module
surfaced one real bug and two hardening items:

- HIGH: internalized_substrates() hardcoded '_0.._n' column suffixes,
  but the parser names a size-1 vector with the bare field name and a
  size-3 vector with _x/_y/_z. So single- and triple-substrate models
  (the two most common PhysiCell setups) raised a misleading "not
  recorded" error even though the data was present. The 5-substrate
  example fixture never exercised it. Now derive the column names from
  the field's own <labels> entry via expand_cell_labels.

- MEDIUM: spatial_gradient returned a silent minimum-norm gradient for
  under-determined local fits (fewer than ndim+1 points, or collinear
  neighbors). Now clamp k to at least ndim+1 and return NaN for
  rank-deficient fits rather than a plausible-but-wrong vector.

- LOW: substrate_at flattened multi-dimensional queries despite
  documenting shape preservation. Now broadcast the inputs and reshape
  the result to match, so a grid of points in yields a grid out.

Adds regression tests: internalized mapping for 1/3/5 substrates,
substrate_at output-shape and broadcasting, and gradient NaN on
degenerate neighbor sets.
@emcramer emcramer self-assigned this Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant