Gompertz growth with a vascular carrying capacity
Gompertz growth under a carrying capacity that the vessels on the tumour surface keep raising.
- Name:
dynamic_carrying_capacity - Field:
biology/oncology - Formalism: ordinary differential equations
- References: Padmanabhan, Meskin, and Al Moustafa 2021; Benzekry et al. 2014; Hahnfeldt et al. 1999
Factory
@register_model(
field='biology/oncology',
tags=('tumour growth', 'ode', 'angiogenesis', 'sigmoid'),
references=(*GROWTH_REFERENCES, 'Hahnfeldt et al. 1999'),
defaults={'until': 20.0, 'dt': 0.05},
)
def dynamic_carrying_capacity(n: float = 1.0, K: float = 12.7, *, r: float = 2.63, d: float = 0.829) -> System:
"""Return Gompertz growth under a carrying capacity that the vessels on the tumour surface keep raising.
The tumour follows `dn/dt = r n log(K / n)` and the capacity `dK/dt = d n^(2/3)`, so the tumour first fills its
initial capacity and then grows as fast as its vasculature, roughly as `t^3`. The defaults are the fit to breast
cancer volumes in mm³ and days.
Args:
n:
The initial volume.
K:
The initial carrying capacity.
r:
The rate at which the growth slows.
d:
The rate at which the surface of the tumour raises the capacity.
Returns:
system:
The model, with the volume `tumour.n` and the capacity `vessels.K`.
Examples:
>>> from skcomplex.models.biology.oncology import dynamic_carrying_capacity
>>> dynamic_carrying_capacity().elements[1].K
12.7
"""
return System(
elements=[PopulationElement('tumour', n=n), VasculatureElement('vessels', K=K)],
interactions=[VascularSupportInteraction('support', tumour='tumour', vasculature='vessels', r=r, d=d)],
)
Components
class PopulationElement(CompartmentElement):
"""Population of one species, a compartment whose state `n` holds its size.
Args:
label:
The label of the population.
visual:
How the element is drawn, or `None` for `default_visual_`.
n:
The initial size.
Examples:
>>> from skcomplex.models.biology.common.populations import PopulationElement
>>> PopulationElement('rabbits', n=40).n
40
"""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
n: Annotated[float, StateSpec(domain=RealSet.closed_open(0, oo))] = 1.0,
) -> None:
super().__init__(label, visual=visual, n=n)
class VasculatureElement(Element):
"""Vasculature of a tumour, which sets its carrying capacity.
Args:
label:
The label of the vasculature.
visual:
How the element is drawn, or `None` for `default_visual_`.
K:
The initial carrying capacity.
Examples:
>>> from skcomplex.models.biology.oncology import VasculatureElement
>>> VasculatureElement('vessels', K=12.7).K
12.7
"""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
K: Annotated[float, StateSpec(domain=RealSet.open(0, oo))] = 1.0,
) -> None:
super().__init__(label, visual=visual)
self.K = K
class VascularSupportInteraction(Interaction):
"""Gompertz growth under a carrying capacity that the vessels on the tumour surface raise.
The tumour follows `dn/dt = r n log(K / n)` and the capacity `dK/dt = d n^(2/3)`.
Args:
label:
The label of the interaction.
tumour:
The path of the tumour.
vasculature:
The path of the vasculature.
r:
The rate at which the growth slows.
d:
The rate at which the surface of the tumour raises the capacity.
Examples:
>>> from skcomplex.models.biology.oncology import VascularSupportInteraction
>>> VascularSupportInteraction('support', tumour='tumour', vasculature='vessels').d
0.829
"""
def __init__(
self,
label: str,
*,
tumour: Annotated[str, RoleSpec()],
vasculature: Annotated[str, RoleSpec()],
r: Annotated[float, ParameterSpec(domain=RealSet.open(0, oo))] = 2.63,
d: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.829,
) -> None:
super().__init__(label)
self.tumour = tumour
self.vasculature = vasculature
self.r = r
self.d = d
def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
"""Return the Gompertz growth of the tumour and the growth of the capacity.
Args:
s:
The namespace of the symbols the laws can use.
Returns:
laws:
The laws of the component.
"""
n, K = s.tumour.n, s.vasculature.K
return [RateLaw(n, s.r * n * log(K / n)), RateLaw(K, s.d * n ** (2 / 3))]
Equations
tumour.n: diff(n_tumour(t), t) == r_support*log(K_vessels(t)/n_tumour(t))*n_tumour(t)
vessels.K: diff(K_vessels(t), t) == d_support*n_tumour(t)^0.6666666666666666