Skip to content

Paclitaxel and trastuzumab with antibody binding

HER2+ breast cancer cells under trastuzumab and paclitaxel, with antibody binding and drug uptake.

  • Name: her2_targeted_therapy
  • Field: biology/oncology
  • Formalism: ordinary differential equations
  • References: Padmanabhan, Meskin, and Al Moustafa 2021; Jarrett et al. 2019

Factory

@register_model(
    field='biology/oncology',
    tags=('chemotherapy', 'targeted therapy', 'combination therapy', 'HER2', 'antibody', 'ode'),
    references=(BOOK, 'Jarrett et al. 2019'),
    defaults={'until': 10.0, 'dt': 0.02, 'solver': ScipyODESolver(method='LSODA', rtol=1e-8, atol=1e-10)},
)
def her2_targeted_therapy(
    A: float = 0.035,
    *,
    antibody: float = 0.2,
    paclitaxel: float = 2.0,
    t_antibody: float = 1.0,
    t_a: float = 2.0,
    t_p: float = 1.0,
    sigma: float = 1.0,
) -> System:
    """Return HER2+ breast cancer cells under trastuzumab and paclitaxel, with antibody binding and drug uptake.

    The free antibody and the free paclitaxel are drivers held at their levels from their doses on. The antibody binds
    the receptors, which are in excess, so the bound antibody rises to the free antibody, and from the time `t_a` on it
    lowers the growth rate to `r (1 - a1 Ab)`. The paclitaxel enters the cells and briefly lowers the carrying capacity.
    The cytotoxicity falls from one at the dose, so `t_p` is the dose time. The book's units cannot hold 35,000 cells
    with a capacity of 0.67, so cells are counted in millions and the antibody in millions of molecules. The dose levels
    and times are a choice. Time is in days.

    Args:
        A:
            The initial number of cells, in millions.

        antibody:
            The level of free antibody from its dose on.

        paclitaxel:
            The level of free paclitaxel from its dose on, in pmol.

        t_antibody:
            The time of the antibody dose.

        t_a:
            The time from which the bound antibody inhibits proliferation.

        t_p:
            The time of the paclitaxel dose.

        sigma:
            The synergy of the two drugs, 1 for none.

    Returns:
        system:
            The model, with the cells `tumour.A`, the bound antibody `tumour.Ab`, and the internalized paclitaxel
            `tumour.Pin`.

    Examples:
        >>> from skcomplex.models.biology.oncology import her2_targeted_therapy
        >>> her2_targeted_therapy(sigma=1.5).elements[0].sigma
        1.5
    """
    tumour = Her2TumourElement(
        'tumour',
        A=A,
        antibody=antibody,
        paclitaxel=paclitaxel,
        t_antibody=t_antibody,
        t_a=t_a,
        t_p=t_p,
        sigma=sigma,
    )
    return System(elements=[tumour])

Components

class Her2TumourElement(Element):
    """HER2+ breast cancer cells under trastuzumab and paclitaxel, with antibody binding and drug uptake.

    The tumour grows logistically, `dA/dt = r (1 - DIm) (1 - A / (kc - DCh)) A`. The bound antibody `Ab` lowers the
    proliferation by `DIm = a1 Ab` from the time `t_a` on, and the internalized paclitaxel `Pin` lowers the carrying
    capacity by `DCh = sigma a2 exp(-gamma_p (t - t_p)) Pin` from the dose time `t_p` on. The free antibody and the
    free paclitaxel are drivers, held at the levels `antibody` and `paclitaxel` from their dose times on. The antibody
    binds the receptors, `dAb/dt = theta_ab (Af - Ab) (theta_r A - Ab)`, and the paclitaxel enters the cells,
    `dPin/dt = alpha_p (Pf - Pin) A`, while the free drugs are present. Cells are counted in millions, so the carrying
    capacity is 0.67, the antibody is in millions of molecules, and time is in days.

    Args:
        label:
            The label of the tumour.

        visual:
            How the element is drawn, or `None` for `default_visual_`.

        A:
            The initial number of cells.

        Ab:
            The initial bound antibody.

        Pin:
            The initial internalized paclitaxel.

        r:
            The growth rate.

        kc:
            The carrying capacity.

        a1:
            The inhibition of proliferation per unit of bound antibody.

        a2:
            The reduction of the carrying capacity per unit of internalized paclitaxel.

        gamma_p:
            The decay rate of the cytotoxicity of paclitaxel.

        sigma:
            The synergy of the two drugs, 1 for none.

        theta_ab:
            The binding rate of the antibody.

        theta_r:
            The number of receptors per cell.

        alpha_p:
            The uptake rate of paclitaxel.

        antibody:
            The level of free antibody from its dose on.

        paclitaxel:
            The level of free paclitaxel from its dose on, in pmol.

        t_antibody:
            The time of the antibody dose.

        t_a:
            The time from which the bound antibody inhibits proliferation.

        t_p:
            The time of the paclitaxel dose.

    Examples:
        >>> from skcomplex.models.biology.oncology import Her2TumourElement
        >>> Her2TumourElement('tumour').kc
        0.67
    """

    def __init__(
        self,
        label: str,
        visual: VisualSpec | None = None,
        *,
        A: Annotated[float, StateSpec(domain=RealSet.closed_open(0, oo))] = 0.035,
        Ab: Annotated[float, StateSpec(domain=RealSet.closed_open(0, oo))] = 0.0,
        Pin: Annotated[float, StateSpec(domain=RealSet.closed_open(0, oo))] = 0.0,
        r: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.83,
        kc: Annotated[float, ParameterSpec(domain=RealSet.open(0, oo))] = 0.67,
        a1: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 2.51,
        a2: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 23.0,
        gamma_p: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 6.35,
        sigma: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 1.0,
        theta_ab: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 8.78,
        theta_r: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 1940000.0,
        alpha_p: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.68,
        antibody: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.2,
        paclitaxel: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 2.0,
        t_antibody: float = 1.0,
        t_a: float = 2.0,
        t_p: float = 1.0,
    ) -> None:
        super().__init__(label, visual=visual)
        self.A = A
        self.Ab = Ab
        self.Pin = Pin
        self.r = r
        self.kc = kc
        self.a1 = a1
        self.a2 = a2
        self.gamma_p = gamma_p
        self.sigma = sigma
        self.theta_ab = theta_ab
        self.theta_r = theta_r
        self.alpha_p = alpha_p
        self.antibody = antibody
        self.paclitaxel = paclitaxel
        self.t_antibody = t_antibody
        self.t_a = t_a
        self.t_p = t_p

    def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
        """Return the growth of the tumour, the binding of the antibody, and the uptake of paclitaxel.

        Args:
            s:
                The namespace of the symbols the laws can use.

        Returns:
            laws:
                The laws of the component.
        """
        A, Ab, Pin, t = s.A, s.Ab, s.Pin, s.t
        free_antibody = where(t >= self.t_antibody, s.antibody, 0)
        free_paclitaxel = where(t >= self.t_p, s.paclitaxel, 0)
        inhibition = where(t > self.t_a, s.a1 * Ab, 0)
        cytotoxicity = where(t >= self.t_p, s.sigma * s.a2 * exp(-s.gamma_p * (t - self.t_p)) * Pin, 0)
        binding = s.theta_ab * (free_antibody - Ab) * (s.theta_r * A - Ab)
        return [
            RateLaw(A, s.r * (1 - inhibition) * (1 - A / (s.kc - cytotoxicity)) * A),
            RateLaw(Ab, where(free_antibody > 0, binding, 0)),
            RateLaw(Pin, where(free_paclitaxel > 0, s.alpha_p * (free_paclitaxel - Pin) * A, 0)),
        ]

Equations

tumour.A: diff(A_tumour(t), t) == r_tumour*(A_tumour(t)/(kc_tumour - where(t >= 1.0, a2_tumour*sigma_tumour*Pin_tumour(t)*e^(-gamma_p_tumour*(t - 1.0)), 0)) - 1)*(where(t > 2.0, a1_tumour*Ab_tumour(t), 0) - 1)*A_tumour(t)
tumour.Ab: diff(Ab_tumour(t), t) == where(where(t >= 1.0, antibody_tumour, 0) > 0, -(theta_r_tumour*A_tumour(t) - Ab_tumour(t))*theta_ab_tumour*(Ab_tumour(t) - where(t >= 1.0, antibody_tumour, 0)), 0)
tumour.Pin: diff(Pin_tumour(t), t) == where(where(t >= 1.0, paclitaxel_tumour, 0) > 0, -alpha_p_tumour*(Pin_tumour(t) - where(t >= 1.0, paclitaxel_tumour, 0))*A_tumour(t), 0)