Skip to content

Tet-Off RMA

rma_kinetics.models.TetRMA

Tetracycline transcriptional activator (tTA) induced RMA expression model.

Attributes:

Name Type Description
rma_prod_rate float

RMA production rate, \(k_{RMA}\).

rma_rt_rate float

RMA reverse transcytosis rate, \(k_{RT}\).

rma_deg_rate float

RMA degradation rate, \(\gamma_{RMA}\).

dox_model_config DoxPKConfig

Dox PK model configuration.

dox_kd float

Dox dissocation constant, \(K_{D_{Dox}}\).

tta_prod_rate float

tTA production rate, \(k_{tTA}\).

tta_deg_rate float

tTA degradation rate, \(\gamma_{tTA}\).

tta_kd float

tTA-TetO operator dissocation constant, \(K_{D_{tTA}}\).

leaky_rma_prod_rate float

Leaky RMA production rate, \(k_{0_{RMA}}\) (Default = 0.0).

tta_coop int

tTA cooperativity, \(n_{tTA}\) (Default = 2).

time_units Time

Time units (Default = Time.hours).

conc_units Concentration

Concentration units (Default = Concentration.nanomolar).

Source code in src/rma_kinetics/models/tet_induced.py
class TetRMA(AbstractModel):
    r"""
    Tetracycline transcriptional activator (tTA) induced RMA expression model.

    Attributes:
        rma_prod_rate (float): RMA production rate, $k_{RMA}$.
        rma_rt_rate (float): RMA reverse transcytosis rate, $k_{RT}$.
        rma_deg_rate (float): RMA degradation rate, $\gamma_{RMA}$.
        dox_model_config (DoxPKConfig): Dox PK model configuration.
        dox_kd (float): Dox dissocation constant, $K_{D_{Dox}}$.
        tta_prod_rate (float): tTA production rate, $k_{tTA}$.
        tta_deg_rate (float): tTA degradation rate, $\gamma_{tTA}$.
        tta_kd (float): tTA-TetO operator dissocation constant, $K_{D_{tTA}}$.
        leaky_rma_prod_rate (float): Leaky RMA production rate, $k_{0_{RMA}}$ (Default = 0.0).
        tta_coop (int): tTA cooperativity, $n_{tTA}$ (Default = 2).
        time_units (Time): Time units (Default = Time.hours).
        conc_units (Concentration): Concentration units (Default = Concentration.nanomolar).
    """
    dox: DoxPK
    dox_kd: float
    tta_prod_rate: float
    tta_deg_rate: float
    tta_kd: float
    leaky_rma_prod_rate: float
    tta_coop: int

    def __init__(
        self,
        rma_prod_rate: float,
        rma_rt_rate: float,
        rma_deg_rate: float,
        dox_model_config: DoxPKConfig,
        dox_kd: float,
        tta_prod_rate: float,
        tta_deg_rate: float,
        tta_kd: float,
        leaky_rma_prod_rate: float = 0.0,
        tta_coop: int = 2,
        time_units: Time = Time.hours,
        conc_units: Concentration = Concentration.nanomolar
    ):

        super().__init__(rma_prod_rate, rma_rt_rate, rma_deg_rate, time_units=time_units, conc_units=conc_units)

        self.dox = DoxPK(dox_model_config)
        self.dox_kd = dox_kd

        self.tta_prod_rate = tta_prod_rate
        self.tta_deg_rate = tta_deg_rate
        self.tta_kd = tta_kd
        self.leaky_rma_prod_rate = leaky_rma_prod_rate
        self.tta_coop = tta_coop

    def _tet_rma_model(self, t: float, y: PyTree[float]) -> PyTree[float]:
        """
        Tet induced RMA expression compartments.

        Arguments:
            t (float): Time points.
            y (PyTree[float]): Concentrations of plasma/brain RMA, transcriptional activator,
                plasma/brain dox.

        Returns:
            dydt (PyTree[float]): Brain/plasma RMA and dox concentrations.
        """
        # brain and plasma dox are given as amounts here.
        brain_rma, plasma_rma, ta, brain_dox, plasma_dox = y

        dplasma_dox, dbrain_dox = self.dox._model(t, (plasma_dox, brain_dox))

        active_ta_frac = 1 / (1 + (brain_dox/self.dox_kd))
        ta_modulator = (active_ta_frac * ta / self.tta_kd)**self.tta_coop
        brain_rma_outflux = self.rma_rt_rate * brain_rma

        dbrain_rma = ((self.leaky_rma_prod_rate + (self.rma_prod_rate * ta_modulator)) / (1 + ta_modulator)) - brain_rma_outflux
        dplasma_rma = brain_rma_outflux - (self.rma_deg_rate * plasma_rma)

        return dbrain_rma, dplasma_rma, dbrain_dox, dplasma_dox

    def _model(self, t: float, y: PyTree[float], args=None) -> PyTree[float]:
        r"""
        Full ODE model implementation.

        Info: Model Equations
            Note that this model assumes constitutive expression of tTA.

            $$\begin{align}
            \dot{[TA]} &= k_{TA} - \gamma_{TA}[TA] \tag{1} \\
            [TA]_{SS} &= \frac{k_{TA}}{\gamma_{TA}} \tag{2}
            \end{align}
            $$

            Doxycycline is the preferred inhibitor (although tetracycline or other
            derivatives may be used by updating the [DoxPKConfig](https://szablowskilab/rma-kinetics/docs/api/dox/config).
            The fraction of the transcriptional activator available for inducing RMA
            expression is then modeled with a Hill function and modified for leaky expression,


            $$\begin{align}
            \theta_{tTA} &= \frac{1}{1 + \frac{[Dox]}{K_{D_{Dox}}}} \tag{3} \\
            \dot{[RMA_{B}]} &= \frac{k_{0_{RMA}} + k_{RMA}\left(\frac{\theta_{TA}[TA]}{K_{D_{TA}}}\right)^{n_{tTA}}}{1 + \left(\frac{\theta_{TA}[TA]}{K_{D_{TA}}}\right)^{n_{tTA}}} - k_{RT}[RMA_{B}] \tag{4} \\
            \dot{[RMA_{P}]} &= k_{RT}[RMA_{B}] - \gamma_{RMA}[RMA_{P}] \tag{5}
            \end{align}
            $$

            |Parameters|Description|Units (Example)|
            |----------|-----------|-----|
            |$k_{RMA}$|RMA production rate|Concentration/Time (nM/hr)|
            |$k_{0_{RMA}}$|Leaky RMA production rate|Concentration/Time (nM/hr)|
            |$k_{RT}$|RMA reverse transcytosis rate|1/Time (1/hr)|
            |$\gamma_{RMA}$|RMA degradation rate|1/Time (1/hr)|
            |$k_{tTA}$|tTA production rate|Concentration/Time (nM/hr)|
            |$\gamma_{tTA}$|tTA degradation rate|1/Time (1/hr)|
            |$K_{D_{Dox}}$|Dox-tTA binding dissocation constant|Concentration (nM)|
            |$K_{D_{tTA}}$|tTA-TetO binding dissocation constant|Concentration (nM)|
            |$n_{tTA}$|tTA cooperativity|Unitless|
            |$[RMA_B]$|Brain RMA concentration|Concentration (nM)|
            |$[RMA_P]$|Plasma RMA concentration|Concentration (nM)|
            |$[tTA]$|Brain tTA concentration|Concentration (nM)|
            |$[Dox]$|Brain Dox concentration|Concentration (nM)|
        """
        brain_rma, plasma_rma, ta, brain_dox, plasma_dox = y
        dbrain_rma, dplasma_rma, dbrain_dox, dplasma_dox = self._tet_rma_model(t, (brain_rma, plasma_rma, ta, brain_dox, plasma_dox))

        dta = self.tta_prod_rate - (self.tta_deg_rate * ta) # constitutive TA expression

        return dbrain_rma, dplasma_rma, dta, dbrain_dox, dplasma_dox

    def _terms(self) -> AbstractTerm:
        return ODETerm(self._model)

simulate(t0: float, t1: float, y0: PyTree[float], dt0: float | None = None, sampling_rate: float = 1, stepsize_controller: AbstractStepSizeController = PIDController(rtol=1e-05, atol=1e-05), max_steps: int = 4096, solver: AbstractSolver = Kvaerno3(), adjoint: AbstractAdjoint = RecursiveCheckpointAdjoint(), throw: bool = True, progress_meter: AbstractProgressMeter = NoProgressMeter())

Simulates model within the given time interval.

Wraps diffrax.diffeqsolve with specific defaults for RMA model simulation.

Parameters:

Name Type Description Default
t0 float

Start time of integration.

required
t1 float

Stop time of integration.

required
y0 PyTree[float]

Tuple of initial conditions.

required
dt0 float | None`

Initial step size if using adaptive step sizes, or size of all steps if using constant stepsize.

None
sampling_rate float

Sampling rate for saving solution.

1
stepsize_controller AbstractStepSizeController`

Determines how to change step size during integration.

PIDController(rtol=1e-05, atol=1e-05)
max_steps int

Max number of steps before stopping.

4096
solver AbstractSolver

Differential equation solver.

Kvaerno3()
adjoint AbstractAdjoint

How to differentiate.

RecursiveCheckpointAdjoint()
throw bool

Raise an exception if integration fails.

True

Returns:

Name Type Description
solution Solution

A solution object (parent of diffrax.Solution) with added plotting methods.

Source code in src/rma_kinetics/models/abstract.py
def simulate(
        self,
        t0: float,
        t1: float,
        y0: PyTree[float],
        dt0: float | None = None,
        sampling_rate: float = 1,
        stepsize_controller: AbstractStepSizeController = PIDController(rtol=1e-5, atol=1e-5),
        max_steps: int = 4096,
        solver: AbstractSolver = Kvaerno3(),
        adjoint: AbstractAdjoint = RecursiveCheckpointAdjoint(),
        throw: bool = True,
        progress_meter: AbstractProgressMeter = NoProgressMeter()
):
    """
    Simulates model within the given time interval.

    Wraps `diffrax.diffeqsolve` with specific defaults for RMA model simulation.

    Arguments:
        t0 (float): Start time of integration.
        t1 (float): Stop time of integration.
        y0 (PyTree[float]): Tuple of initial conditions.
        dt0 (float | None`): Initial step size if using adaptive
            step sizes, or size of all steps if using constant stepsize.
        sampling_rate (float): Sampling rate for saving solution.
        stepsize_controller (AbstractStepSizeController`): Determines
            how to change step size during integration.
        max_steps (int): Max number of steps before stopping.
        solver (AbstractSolver): Differential equation solver.
        adjoint (AbstractAdjoint): How to differentiate.
        throw (bool): Raise an exception if integration fails.

    Returns:
        solution (Solution): A solution object (parent of diffrax.Solution) with added plotting methods.
    """
    saveat = SaveAt(ts=jnp.linspace(t0, t1, int(t1*sampling_rate)))
    diffsol = diffeqsolve(
        self._terms(),
        solver,
        t0,
        t1,
        dt0,
        y0,
        saveat=saveat,
        stepsize_controller=stepsize_controller,
        max_steps=max_steps,
        adjoint=adjoint,
        throw=throw,
        progress_meter=progress_meter
    )

    return Solution(diffsol, self.time_units, self.conc_units)

_tet_rma_model(t: float, y: PyTree[float]) -> PyTree[float]

Tet induced RMA expression compartments.

Parameters:

Name Type Description Default
t float

Time points.

required
y PyTree[float]

Concentrations of plasma/brain RMA, transcriptional activator, plasma/brain dox.

required

Returns:

Name Type Description
dydt PyTree[float]

Brain/plasma RMA and dox concentrations.

Source code in src/rma_kinetics/models/tet_induced.py
def _tet_rma_model(self, t: float, y: PyTree[float]) -> PyTree[float]:
    """
    Tet induced RMA expression compartments.

    Arguments:
        t (float): Time points.
        y (PyTree[float]): Concentrations of plasma/brain RMA, transcriptional activator,
            plasma/brain dox.

    Returns:
        dydt (PyTree[float]): Brain/plasma RMA and dox concentrations.
    """
    # brain and plasma dox are given as amounts here.
    brain_rma, plasma_rma, ta, brain_dox, plasma_dox = y

    dplasma_dox, dbrain_dox = self.dox._model(t, (plasma_dox, brain_dox))

    active_ta_frac = 1 / (1 + (brain_dox/self.dox_kd))
    ta_modulator = (active_ta_frac * ta / self.tta_kd)**self.tta_coop
    brain_rma_outflux = self.rma_rt_rate * brain_rma

    dbrain_rma = ((self.leaky_rma_prod_rate + (self.rma_prod_rate * ta_modulator)) / (1 + ta_modulator)) - brain_rma_outflux
    dplasma_rma = brain_rma_outflux - (self.rma_deg_rate * plasma_rma)

    return dbrain_rma, dplasma_rma, dbrain_dox, dplasma_dox

_model(t: float, y: PyTree[float], args=None) -> PyTree[float]

Full ODE model implementation.

Model Equations

Note that this model assumes constitutive expression of tTA.

\[\begin{align} \dot{[TA]} &= k_{TA} - \gamma_{TA}[TA] \tag{1} \\ [TA]_{SS} &= \frac{k_{TA}}{\gamma_{TA}} \tag{2} \end{align} \]

Doxycycline is the preferred inhibitor (although tetracycline or other derivatives may be used by updating the DoxPKConfig. The fraction of the transcriptional activator available for inducing RMA expression is then modeled with a Hill function and modified for leaky expression,

\[\begin{align} \theta_{tTA} &= \frac{1}{1 + \frac{[Dox]}{K_{D_{Dox}}}} \tag{3} \\ \dot{[RMA_{B}]} &= \frac{k_{0_{RMA}} + k_{RMA}\left(\frac{\theta_{TA}[TA]}{K_{D_{TA}}}\right)^{n_{tTA}}}{1 + \left(\frac{\theta_{TA}[TA]}{K_{D_{TA}}}\right)^{n_{tTA}}} - k_{RT}[RMA_{B}] \tag{4} \\ \dot{[RMA_{P}]} &= k_{RT}[RMA_{B}] - \gamma_{RMA}[RMA_{P}] \tag{5} \end{align} \]
Parameters Description Units (Example)
\(k_{RMA}\) RMA production rate Concentration/Time (nM/hr)
\(k_{0_{RMA}}\) Leaky RMA production rate Concentration/Time (nM/hr)
\(k_{RT}\) RMA reverse transcytosis rate 1/Time (1/hr)
\(\gamma_{RMA}\) RMA degradation rate 1/Time (1/hr)
\(k_{tTA}\) tTA production rate Concentration/Time (nM/hr)
\(\gamma_{tTA}\) tTA degradation rate 1/Time (1/hr)
\(K_{D_{Dox}}\) Dox-tTA binding dissocation constant Concentration (nM)
\(K_{D_{tTA}}\) tTA-TetO binding dissocation constant Concentration (nM)
\(n_{tTA}\) tTA cooperativity Unitless
\([RMA_B]\) Brain RMA concentration Concentration (nM)
\([RMA_P]\) Plasma RMA concentration Concentration (nM)
\([tTA]\) Brain tTA concentration Concentration (nM)
\([Dox]\) Brain Dox concentration Concentration (nM)
Source code in src/rma_kinetics/models/tet_induced.py
def _model(self, t: float, y: PyTree[float], args=None) -> PyTree[float]:
    r"""
    Full ODE model implementation.

    Info: Model Equations
        Note that this model assumes constitutive expression of tTA.

        $$\begin{align}
        \dot{[TA]} &= k_{TA} - \gamma_{TA}[TA] \tag{1} \\
        [TA]_{SS} &= \frac{k_{TA}}{\gamma_{TA}} \tag{2}
        \end{align}
        $$

        Doxycycline is the preferred inhibitor (although tetracycline or other
        derivatives may be used by updating the [DoxPKConfig](https://szablowskilab/rma-kinetics/docs/api/dox/config).
        The fraction of the transcriptional activator available for inducing RMA
        expression is then modeled with a Hill function and modified for leaky expression,


        $$\begin{align}
        \theta_{tTA} &= \frac{1}{1 + \frac{[Dox]}{K_{D_{Dox}}}} \tag{3} \\
        \dot{[RMA_{B}]} &= \frac{k_{0_{RMA}} + k_{RMA}\left(\frac{\theta_{TA}[TA]}{K_{D_{TA}}}\right)^{n_{tTA}}}{1 + \left(\frac{\theta_{TA}[TA]}{K_{D_{TA}}}\right)^{n_{tTA}}} - k_{RT}[RMA_{B}] \tag{4} \\
        \dot{[RMA_{P}]} &= k_{RT}[RMA_{B}] - \gamma_{RMA}[RMA_{P}] \tag{5}
        \end{align}
        $$

        |Parameters|Description|Units (Example)|
        |----------|-----------|-----|
        |$k_{RMA}$|RMA production rate|Concentration/Time (nM/hr)|
        |$k_{0_{RMA}}$|Leaky RMA production rate|Concentration/Time (nM/hr)|
        |$k_{RT}$|RMA reverse transcytosis rate|1/Time (1/hr)|
        |$\gamma_{RMA}$|RMA degradation rate|1/Time (1/hr)|
        |$k_{tTA}$|tTA production rate|Concentration/Time (nM/hr)|
        |$\gamma_{tTA}$|tTA degradation rate|1/Time (1/hr)|
        |$K_{D_{Dox}}$|Dox-tTA binding dissocation constant|Concentration (nM)|
        |$K_{D_{tTA}}$|tTA-TetO binding dissocation constant|Concentration (nM)|
        |$n_{tTA}$|tTA cooperativity|Unitless|
        |$[RMA_B]$|Brain RMA concentration|Concentration (nM)|
        |$[RMA_P]$|Plasma RMA concentration|Concentration (nM)|
        |$[tTA]$|Brain tTA concentration|Concentration (nM)|
        |$[Dox]$|Brain Dox concentration|Concentration (nM)|
    """
    brain_rma, plasma_rma, ta, brain_dox, plasma_dox = y
    dbrain_rma, dplasma_rma, dbrain_dox, dplasma_dox = self._tet_rma_model(t, (brain_rma, plasma_rma, ta, brain_dox, plasma_dox))

    dta = self.tta_prod_rate - (self.tta_deg_rate * ta) # constitutive TA expression

    return dbrain_rma, dplasma_rma, dta, dbrain_dox, dplasma_dox

Example

from rma_kinetics.models import TetRMA, DoxPKConfig
from diffrax import SaveAt
from jax import numpy as jnp

# add dox feeding at 30 mg/kg food from time 0 to 48 hours
dox_model_config = DoxPKConfig(
    dose=30,
    t0=0,
    t1=48
)

# make a simple TetOff RMA model with no leaky expression
model = TetRMA(
    rma_prod_rate=7e-3,
    rma_rt_rate=0.6,
    rma_deg_rate=7e-3,
    dox_model_config=dox_model_config,
    dox_kd=10,
    tta_prod_rate=8e-3,
    tta_deg_rate=8e-3,
    tta_kd=1,
)

# simulate from 0 to 96 hours
t0 = 0; t1 = 96

# brain and plasma dox steady state concentrations
brain_dox_ss = dox_model_config.brain_dox_ss
plasma_dox_ss = dox_model_config.plasma_dox_ss

# initial conditions
# species order is brain RMA, plasma RMA, tTA, brain dox, plasma dox
y0 = (0, 0, 1, brain_dox_ss, plasma_dox_ss)
solution = model.simulate(t0=t0, t1=t1, y0=y0, dt0=0.1)

# print the plasma RMA concentration at the final timepoint
plasma_rma = solution.plasma_rma
print(f"Plasma RMA at {t1} hours: {plasma_rma[-1]:.3f} nM")

# plot the plasma RMA trajectory
solution.plot_plasma_rma()
plt.show()