import numpy as np
from scipy.optimize import root
from scipy.integrate import solve_ivp
from bone_models.bone_cell_population_models.parameters.base_parameters import Base_Parameters
[docs]
class Base_Model:
"""This class implements the base model for bone cell population models. It essentially includes the ODE system that is shared across future models and the functions to solve for steady-state and solution.
It is not intended to be used as a model itself but only indicates the most basic version of the bone cell population models.
Functions that are specific to a certain model should be implemented in the respective model class, otherwise the functions return 0 (additive) or 1 (multiplicative) values.
:param OBp: precursor osteoblast cell concentration
:type OBp: float
:param OBa: active osteoblast cell concentration
:type OBa: float
:param OCa: osteoclast cell concentration
:type OCa: float
:param parameters: Model parameters, see :class:`Parameters` for details.
:type parameters: Parameters
:param initial_guess_root: initial guess for the root-finding algorithm for steady-state
:type initial_guess_root: numpy.ndarray
:param steady_state: steady state values of the model
:type steady_state: object
:param t: time variable
:type t: float
:param tspan: time span for the ODE solver
:type tspan: numpy.ndarray with start and end time
:param x: state variables of the model
:type x: list
:param solution: solution of the ODE system
:type solution: scipy.integrate._ivp.ivp.OdeResult
:param initial_bone_volume_fraction: initial bone volume fraction
:type initial_bone_volume_fraction: float
:param dOBpdt: rate of change of precursor osteoblast cell concentration
:type dOBpdt: float
:param dOBadt: rate of change of active osteoblast cell concentration
:type dOBadt: float
:param dOCadt: rate of change of osteoclast cell concentration
:type dOCadt: float
:param dxdt: rate of change of state variables
:type dxdt: list
:param bone_volume_fraction: bone volume fraction over time
:type bone_volume_fraction: list
"""
def __init__(self):
""" Constructor for the Base_Model class. """
self.parameters = Base_Parameters()
self.initial_guess_root = np.array([None, None, None])
self.steady_state = type('', (), {})()
self.steady_state.OBp = None
self.steady_state.OBa = None
self.steady_state.OCa = None
[docs]
def bone_cell_population_model(self, x, t=None):
""" Calculates the system of ordinary differential equations for the bone cell population model.
This function is inherited by the specific models. If a function is not relevant in the specific model
(e.g. mechanical effects), it returns 0 (additive) or 1 (multiplicative) as neutral values.
:param x: state variables of the model
:type x: list
:param t: time variable
:type t: float
:return: rate of change of state variables
:rtype: list
"""
OBp, OBa, OCa = x
dOBpdt = ((self.parameters.differentiation_rate.OBu * self.calculate_TGFb_activation_OBu(OCa,t) -
self.parameters.differentiation_rate.OBp * OBp *
self.calculate_TGFb_repression_OBp(OCa,t) + self.calculate_external_injection_OBp(t)) +
self.apply_mechanical_effects(OBp, OBa, OCa, t) + self.apply_medication_effects_OBp())
dOBadt = (self.parameters.differentiation_rate.OBp * OBp * self.calculate_TGFb_repression_OBp(OCa,t) -
self.parameters.apoptosis_rate.OBa * OBa * self.apply_medication_effects_OBa()
+ self.calculate_external_injection_OBa(t))
dOCadt = (self.parameters.differentiation_rate.OCp * self.calculate_RANKL_activation_OCp(OBp,OBa,t) -
self.parameters.apoptosis_rate.OCa * OCa * self.calculate_TGFb_activation_OCa(OCa,t) +
self.calculate_external_injection_OCa(t))
dxdt = [dOBpdt, dOBadt, dOCadt]
return dxdt
[docs]
def calculate_steady_state(self):
""" Calculate the steady state of the bone cell population model using root finding of the ODE system.
:return: steady state values of the model
:rtype: numpy.ndarray
"""
print('Calculating steady state ...', end='')
steady_state = root(self.bone_cell_population_model, self.initial_guess_root, tol=1e-30, method="lm", options={'xtol': 1e-30}) #tol=1e-5)
self.steady_state.OBp = steady_state.x[0]
self.steady_state.OBa = steady_state.x[1]
self.steady_state.OCa = steady_state.x[2]
print(f'done \n Steady state: {steady_state.x}')
return steady_state.x
[docs]
def solve_bone_cell_population_model(self, tspan):
""" Solve the bone cell population model using the ODE system over a given time interval.
The initial conditions are set to the steady-state values.
:param tspan: time span for the ODE solver
:type tspan: numpy.ndarray with start and end time
:return: solution of the ODE system
:rtype: scipy.integrate._ivp.ivp.OdeResult
"""
x0 = self.calculate_steady_state()
print('Solving bone cell population model ...', end='')
solution = solve_ivp(lambda t, x: self.bone_cell_population_model(x, t), tspan, x0, rtol=1e-8, atol=1e-8)
print('done')
return solution
[docs]
def calculate_TGFb_activation_OBu(self, OCa, t):
""" Calculate the activation of uncommitted osteoblasts by TGFb.
:param OCa: osteoclast cell concentration
:type OCa: float
:param t: time variable
:type t: float
:return: activation of uncommitted osteoblasts by TGFb
:rtype: float
"""
pass
[docs]
def calculate_TGFb_repression_OBp(self, OCa, t):
""" Calculate the repression of precursor osteoblasts by TGFb.
:param OCa: osteoclast cell concentration
:type OCa: float
:param t: time variable
:type t: float
:return: repression of precursor osteoblasts by TGFb"""
pass
[docs]
def calculate_TGFb_activation_OCa(self, OCa, t):
""" Calculate the activation of active osteoclasts by TGFb.
:param OCa: osteoclast cell concentration
:type OCa: float
:param t: time variable
:type t: float
:return: activation of active osteoclasts by TGFb
:rtype: float"""
pass
[docs]
def calculate_RANKL_activation_OCp(self, OBp, OBa, t):
""" Calculate the activation of precursor osteoclasts by RANKL.
:param OBp: precursor osteoblast cell concentration
:type OBp: float
:param OBa: active osteoblast cell concentration
:type OBa: float
:param t: time variable
:type t: float
:return: activation of precursor osteoclasts by RANKL
:rtype: float"""
pass
[docs]
def calculate_external_injection_OBp(self, t):
""" Calculate the external injection of precursor osteoblasts (used in load case scenarios).
:param t: time variable
:type t: float
:return: external injection of precursor osteoblasts
:rtype: float"""
pass
[docs]
def calculate_external_injection_OBa(self, t):
""" Calculate the external injection of active osteoblasts (used in load case scenarios).
:param t: time variable
:type t: float
:return: external injection of active osteoblasts
:rtype: float"""
pass
[docs]
def calculate_external_injection_OCa(self, t):
""" Calculate the external injection of active osteoclasts (used in load case scenarios).
:param t: time variable
:type t: float
:return: external injection of active osteoclasts
:rtype: float"""
pass
[docs]
def calculate_bone_volume_fraction_change(self, solution, steady_state, initial_bone_volume_fraction):
""" Calculate the change in bone volume fraction over time.
:param solution: solution of the ODE system
:type solution: scipy.integrate._ivp.ivp.OdeResult
:param steady_state: steady state values of the model
:type steady_state: numpy.ndarray
:param initial_bone_volume_fraction: initial bone volume fraction
:type initial_bone_volume_fraction: float
:return: bone volume fraction over time
:rtype: list
"""
bone_volume_fraction = [initial_bone_volume_fraction]
for i in range(len(solution)):
bone_volume_fraction.append(
bone_volume_fraction[-1] +
self.parameters.bone_volume.formation_rate * (solution[i][1] - steady_state[1]) -
self.parameters.bone_volume.resorption_rate * (solution[i][2] - steady_state[2])
)
return bone_volume_fraction
[docs]
def apply_mechanical_effects(self, OBp, OBa, OCa, t):
""" Apply mechanical effects to the bone cell population model. Returns 0 (additive) as neutral value if not relevant to the specific model.
:return: mechanical effects acting on the bone cell population model
:rtype: float
"""
return 0
[docs]
def apply_medication_effects_OBp(self):
""" Apply medication effects to precursor osteoblasts. Returns 0 (additive) as neutral value if not relevant to the specific model.
:return: medication effects acting on precursor osteoblasts
:rtype: float
"""
return 0
[docs]
def apply_medication_effects_OBa(self):
""" Apply medication effects to active osteoblasts. Returns 1 (multiplicative) as neutral value if not relevant to the specific model.
:return: medication effects acting on active osteoblasts
:rtype: float
"""
return 1