Source code for circadapt.model.vanosta2023

"""
VanOsta2023 model.

"""

from circadapt.model import Model
from circadapt.adapt import ModelAdapt
from circadapt.plot import triseg2022
import matplotlib.pyplot as plt
import numpy as np
import warnings

colors = {
    'Lv': None, #[213/255, 96/255, 98/255],
    'Sv': None, #[236/255, 195/255, 11/255],
    'Rv': None, #[6/255, 123/255, 194/255],
    'Ra': None, #[27/255, 231/255, 255/255],
    'La': None, #[243/255, 119/255, 72/255],
    'PuArt': None, #'k',
    'SyArt': None, #'k',
    'RaRv': None, #'k',
    'RvPuArt': None, #'k',
    'LaLv': None, #'k',
    'LvSyArt': None, #'k',

    }
# colors = {
#     'Lv': [213/255, 96/255, 98/255],
#     'Sv': [236/255, 195/255, 11/255],
#     'Rv': [6/255, 123/255, 194/255],
#     'Ra': [27/255, 231/255, 255/255],
#     'La': [243/255, 119/255, 72/255],
#     'PuArt': 'k',
#     'SyArt': 'k',
#     'RaRv': 'k',
#     'RvPuArt': 'k',
#     'LaLv': 'k',
#     'LvSyArt': 'k',

#     }


[docs] class VanOsta2023(Model, ModelAdapt): def __init__(self, solver: str = None, path_to_circadapt: str = None, model_state: dict = None, ): # warnings.warn('VanOsta2023 uses old structure. Use VanOsta2024.') if solver is None: solver = 'backward_differential' self._local_save_reference = True ModelAdapt.__init__(self) Model.__init__(self, solver, path_to_circadapt=path_to_circadapt, model_state=model_state, ) def _update_settings(self): # rename model components for easy input/output self._module_rename['Wall2022'] = 'Wall' self._module_rename['Patch2022'] = 'Patch' self._module_rename['Chamber2022'] = 'Chamber' self._module_rename['Valve2022'] = 'Valve' self._module_rename['TriSeg2022'] = 'TriSeg' self._module_rename['PressureFlowControl'] = 'PFC'
[docs] def build(self): # Circulation self.add_smart_component('ArtVen', build='SystemicCirculation') self.add_smart_component('ArtVen', build='PulmonaryCirculation') self.add_smart_component('Heart', patch_type='Patch2022') self.add_smart_component('Timings') self.add_smart_component('PressureFlowControl') # manually set papillary muscles self.set_component("Peri.RaRv.wPapMus", "Peri.TriSeg.wRv") self.set_component("Peri.LaLv.wPapMus", "Peri.TriSeg.wLv")
[docs] def set_reference(self): self['Chamber']['buckling'] = False self['Valve']['soft_closure'] = True self['Valve']['papillary_muscles'] = True self['Solver']['dt'] = 0.001 self['Solver']['dt_export'] = 0.002 self.set('Solver.order', 2) self.set('Model.t_cycle', 0.85) self.set('Model.PFC.fac', 0.5) self.set('Model.PFC.epsilon', 0.1) self.set('Model.PFC.fac_pfc', 1) self.set('Model.PFC.stable_threshold', 0.001) # Set parameters Circulation self['Tube0D']['A0'] = [0.00049828, 0.00049899, 0.00046929, 0.00050574] self['Tube0D']['A_wall'] = [1.13187792e-04, 3.72289316e-05, 7.27489286e-05, 4.31617949e-05] self['Tube0D']['k'] = [1.66666667, 2.33333333, 1.66666667, 2.33333333] self['Tube0D']['l'] = [0.4, 0.4, 0.19, 0.19] self['Tube0D']['p0'] = [12155.25602777, 297.44066943, 1912.6684696 , 580.51425824] self['ArtVen']['p0'] = [6299.86481149, 1000. ] self['ArtVen']['q0'] = [4.5e-05, 4.5e-05] self['ArtVen']['k'] = [1. , 1.88] # Set volume state variables # not needed to reset, only if initial model crashes if True: self.set('Model.SyArt.V', 2e-4) self.set('Model.PuArt.V', 1e-4) self.set('Model.SyVen.V', 4e-4) self.set('Model.PuVen.V', 2e-4) self.set('Model.Peri.TriSeg.V', 56e-6) self.set('Model.Peri.TriSeg.Y', 36e-3) self.set('Model.Peri.TriSeg.cLv.V', 150e-6) self.set('Model.Peri.TriSeg.cRv.V', 110e-6) self.set('Model.Peri.La.V', 25e-6) self.set('Model.Peri.Ra.V', 150e-6) # all wall parameters self['Patch']['l_se0'] = 0.04 self['Patch']['l_s_ref'] = 2.0 self['Patch']['l_s0'] = [1.79, 1.79, 1.8 , 1.8 , 1.8 ] self['Patch']['dl_s_pas'] = 0.6 self['Patch']['k1'] = 10 self['Patch']['dt'] = 0 self['Patch']['C_rest'] = 0 self['Patch']['l_si0'] = 1.51 self['Patch']['LDAD'] = [1.057, 1.057, 0.74 , 0.74 , 0.74 ] self['Patch']['ADO'] = [0.081, 0.081, 0.75 , 0.75 , 0.75 ] self['Patch']['LDCC'] = [4. , 4. , 3., 3., 3.] self['Patch']['v_max'] = 7. self['Patch']['v_max'][:2] = 14. self['Patch']['tr'] = [0.4 , 0.4 , 0.21, 0.21, 0.21] self['Patch']['td'] = [0.4 , 0.4 , 0.24, 0.24, 0.24] # wall specific self['Patch']['Sf_act'] = [100000., 100000., 120000., 120000., 120000.] self['Patch']['Am_ref'] = [0.00400721, 0.00311263, 0.00918281, 0.00518683, 0.01321999] self['Patch']['V_wall'] = [1.59935455e-05, 7.72140495e-06, 1.16441768e-04, 4.51241560e-05, 6.88196851e-05] self['Patch']['Sf_pas'] = [ 9.51064014, 10.3647024 , 424.3537027 , 417.74300178, 439.21574206] # Valves self['Valve']['adaptation_A_open_fac'] = [1. , 1.12, 1. , 1. , 1.12, 1. ] self['Valve']['A_open'] = [0.00050044, 0.00052598, 0.00046962, 0.00050745, 0.0005583 , 0.00049849] self['Valve']['A_leak'] = [2.64705882e-04, 2.64705882e-10, 2.64705882e-10, 2.64705882e-04, 2.64705882e-10, 2.64705882e-10] self['Valve']['l'] = 0.01626978 self['Valve']['rho_b'] = 1050 self['Valve']['papillary_muscles'] = True self['Valve']['papillary_muscles_slope'] = 100 self['Valve']['papillary_muscles_min'] = 0.1 self['Valve']['papillary_muscles_A_open_fac'] = 0.1 self['Valve']['soft_closure'] = True self['Bag']['k'] = 10 self['Bag']['V_ref'] = [0.00057937] self['Bag']['p_ref'] = 100 self.set('Model.Peri.TriSeg.Y', 0.035) self['Timings']['law_tau_av'] = 2 self['Timings']['c_tau_av0'] = 0.189 self['Timings']['c_tau_av1'] = -0.029 # Adaptation self['Patch']['adapt_gamma'] = 0.5 self.set('Solver.store_beats', 1) self['PFC']['stable_threshold'] = 1e-3 self['Patch']['SfPasMaxT'] = [3600., 3600., 4200., 4200., 4200.] self['Patch']['FacSfActT'] = [0.28, 0.28, 0.69, 0.69, 0.69] self['Patch']['SfPasActT'] = [2800., 2800., 6600., 6600., 6600.] self['Patch']['LsPasActT'] = [3. , 3. , 2.31, 2.31, 2.31] self.run(stable=True) return
[docs] def get_unittest_targets(self): """Hardcoded results after initializing and running 1 beat.""" return { 'LVEDV': 109.1, 'LVESV': 36.6, }
[docs] def get_unittest_results(self, model): """Real-time results after initializing and running 1 beat.""" LVEDV = np.max(model['Cavity']['V'][:, 'cLv'])*1e6 LVESV = np.min(model['Cavity']['V'][:, 'cLv'])*1e6 return { 'LVEDV': LVEDV, 'LVESV': LVESV, }
[docs] def plot(self, fig=None): # TODO self.plot_extended(fig)
[docs] def plot_extended(self, fig=None): if fig is None: fig = 1 if isinstance(fig, int): fig = plt.figure(fig, clear=True, figsize=(12, 8)) # Settings grid_size = [32, 32] def get_lim(module, signal, locs=slice(None, None, None)): signal = self[module][signal][:, locs] lim = np.array([np.min(signal), np.max(signal)]) lim += np.array([-1, 1]) * 0.1*np.diff(lim) return lim lim_V = get_lim('Cavity', 'V', ['cRv', 'Ra', 'La', 'cLv']) * 1e6 lim_V[0] = 0 lim_p = get_lim('Cavity', 'p', ['cRv', 'Ra', 'La', 'cLv']) / 133 lim_p[0] = np.min([lim_p[0], 0]) lim_Ls = get_lim('Patch', 'l_s') lim_Sf = get_lim('Patch', 'Sf') * 1e-3 lim_q = get_lim('Valve', 'q', ['LaLv', 'RaRv', 'LvSyArt', 'RaPuArt']) * 1e6 all_lim = [lim_V, lim_p, lim_Ls, lim_Sf, lim_q] if (np.any(np.isnan(all_lim)) or np.any(np.isinf(all_lim))): lim_V = [0, 200] lim_p = [0, 150] lim_Ls = [1.5, 2.0] lim_Sf = [0, 100] lim_q = [-1e-3, 1e-3] # Pressure Volume plot axPV = plt.subplot2grid(grid_size, (0, 17), rowspan=15, colspan=15, fig=fig) axPV.plot(self['Cavity']['V'][:, 'cLv']*1e6, self['Cavity']['p'][:, 'cLv']/133, c=colors['Lv'], ) axPV.plot(self['Cavity']['V'][:, 'cRv']*1e6, self['Cavity']['p'][:, 'cRv']/133, c=colors['Rv'], ) axPV.plot(self['Cavity']['V'][:, 'La']*1e6, self['Cavity']['p'][:, 'La']/133, c=colors['La'], ) axPV.plot(self['Cavity']['V'][:, 'Ra']*1e6, self['Cavity']['p'][:, 'Ra']/133, c=colors['Ra'], ) axPV.spines[['top', 'right']].set_visible(False) axPV.set_title('Pressure-Volume loop', weight='bold') axPV.set_xlabel('Volume [mL]') axPV.set_ylabel('Pressure [mmHg]') axPV.spines[['bottom', 'left']].set_position(('outward', 5)) ylabel_x_left = -0.25 ylabel_x_right = 1.25 # Volumes t = self['Solver']['t']*1e3 axVRv = plt.subplot2grid(grid_size, (0, 0), rowspan=8, colspan=6, fig=fig) axVRv.plot(t, self['Cavity']['V'][:, 'cRv']*1e6, c=colors['Rv'], ) axVRv.plot(t, self['Cavity']['V'][:, 'Ra']*1e6, c=colors['Ra'], ) axVRv.set_ylim(lim_V) axVRv.set_ylabel('Volume\n[mL]') axVRv.spines[['top', 'right']].set_visible(False) axVRv.set_title('Right Heart') # axVRv.set_xticks([]) axVRv.tick_params(axis='both', direction='in') axVRv.yaxis.set_label_coords(ylabel_x_left, 0.5) axVLv = plt.subplot2grid(grid_size, (0, 6), rowspan=8, colspan=6, fig=fig) axVLv.plot(t, self['Cavity']['V'][:, 'cLv']*1e6, c=colors['Lv'], ) axVLv.plot(t, self['Cavity']['V'][:, 'La']*1e6, c=colors['La'], ) axVLv.set_ylabel('Volume\n[mL]') axVLv.set_ylim(lim_V) axVLv.yaxis.set_ticks_position('right') axVLv.yaxis.set_label_position('right') axVLv.spines['right'].set_position(('outward', 0)) axVLv.spines[['top', 'left']].set_visible(False) axVLv.set_title('Left Heart') # axVLv.set_xticks([]) axVLv.tick_params(axis='both', direction='in') axVLv.yaxis.set_label_coords(ylabel_x_right, 0.5) # Pressures axpRv = plt.subplot2grid(grid_size, (8, 0), rowspan=8, colspan=6, fig=fig) axpRv.plot(t, self['Cavity']['p'][:, 'cRv']/133, c=colors['Rv'], ) axpRv.plot(t, self['Cavity']['p'][:, 'Ra']/133, c=colors['Ra'], ) axpRv.plot(t, self['Cavity']['p'][:, 'PuArt']/133, c=colors['PuArt'], ) axpRv.spines[['top', 'right']].set_visible(False) # axpRv.set_xticks([]) axpRv.tick_params(axis='both', direction='in') axpRv.set_ylim(lim_p) axpRv.set_ylabel('Pressure\n[mmHg]') axpRv.yaxis.set_label_coords(ylabel_x_left, 0.5) axpLv = plt.subplot2grid(grid_size, (8, 6), rowspan=8, colspan=6, fig=fig) axpLv.plot(t, self['Cavity']['p'][:, 'cLv']/133, c=colors['Lv'], ) axpLv.plot(t, self['Cavity']['p'][:, 'La']/133, c=colors['La'], ) axpLv.plot(t, self['Cavity']['p'][:, 'SyArt']/133, c=colors['SyArt'], ) axpLv.yaxis.set_ticks_position('right') axpLv.yaxis.set_label_position('right') axpLv.spines['right'].set_position(('outward', 0)) axpLv.spines[['top', 'left']].set_visible(False) # axpLv.set_xticks([]) axpLv.tick_params(axis='both', direction='in') axpLv.set_ylim(lim_p) axpLv.set_ylabel('Pressure\n[mmHg]') axpLv.yaxis.set_label_coords(ylabel_x_right, 0.5) # Valves ax = plt.subplot2grid(grid_size, (16, 0), rowspan=6, colspan=6, fig=fig) ax.plot(t, self['Valve']['q'][:, 'RaRv']*1e6, c=colors['RaRv'], ) ax.plot(t, self['Valve']['q'][:, 'RvPuArt']*1e6, c=colors['RvPuArt'], ) ax.spines[['top', 'right']].set_visible(False) ax.set_ylim(lim_q) # ax.set_xticks([]) ax.set_ylabel('Flow\n[mL/s]') ax.yaxis.set_label_coords(ylabel_x_left, 0.5) ax = plt.subplot2grid(grid_size, (16, 6), rowspan=6, colspan=6, fig=fig) ax.plot(t, self['Valve']['q'][:, 'LaLv']*1e6, c=colors['LaLv'], ) ax.plot(t, self['Valve']['q'][:, 'LvSyArt']*1e6, c=colors['LvSyArt'], ) ax.spines[['top', 'left']].set_visible(False) ax.set_ylim(lim_q) ax.yaxis.set_ticks_position('right') ax.yaxis.set_label_position('right') # ax.set_xticks([]) ax.set_ylabel('Flow\n[mL/s]') ax.yaxis.set_label_coords(ylabel_x_right, 0.5) # Stress ax = plt.subplot2grid(grid_size, (22, 0), rowspan=4, colspan=6, fig=fig) ax.plot(t, self['Patch']['Sf'][:, 'pRv0']*1e-3, c=colors['Rv'], ) ax.plot(t, self['Patch']['Sf'][:, 'pRa0']*1e-3, c=colors['Ra'], ) ax.spines[['top', 'right']].set_visible(False) # ax.set_xticks([]) ax.set_ylim(lim_Sf) ax.set_ylabel('Total\nstress [kPa]') ax.yaxis.set_label_coords(ylabel_x_left, 0.5) ax = plt.subplot2grid(grid_size, (22, 6), rowspan=4, colspan=6, fig=fig) ax.plot(t, self['Patch']['Sf'][:, 'pLv0']*1e-3, c=colors['Lv'], ) ax.plot(t, self['Patch']['Sf'][:, 'pSv0']*1e-3, c=colors['Sv'], ) ax.plot(t, self['Patch']['Sf'][:, 'pLa0']*1e-3, c=colors['La'], ) ax.spines[['top', 'left']].set_visible(False) ax.yaxis.set_ticks_position('right') ax.yaxis.set_label_position('right') # ax.set_xticks([]) ax.set_ylim(lim_Sf) ax.set_ylabel('Total\nstress [kPa]') ax.yaxis.set_label_coords(ylabel_x_right, 0.5) # Sarcomere Length ax = plt.subplot2grid(grid_size, (26, 0), rowspan=6, colspan=6, fig=fig) ax.plot(t, self['Patch']['l_s'][:, 'pRv0'], c=colors['Rv'], ) ax.plot(t, self['Patch']['l_s'][:, 'pRa0'], c=colors['Ra'], ) ax.spines[['top', 'right']].set_visible(False) ax.spines['bottom'].set_position(('outward', 5)) ax.set_ylim(lim_Ls) ax.set_ylabel('Sarcomere\nlength [$\mu$m]') ax.yaxis.set_label_coords(ylabel_x_left, 0.5) ax = plt.subplot2grid(grid_size, (26, 6), rowspan=6, colspan=6, fig=fig) ax.plot(t, self['Patch']['l_s'][:, 'pLv0'], c=colors['Lv'], ) ax.plot(t, self['Patch']['l_s'][:, 'pSv0'], c=colors['Sv'], ) ax.plot(t, self['Patch']['l_s'][:, 'pLa0'], c=colors['La'], ) ax.spines[['top', 'left']].set_visible(False) ax.spines['bottom'].set_position(('outward', 5)) ax.yaxis.set_ticks_position('right') ax.yaxis.set_label_position('right') ax.set_ylim(lim_Ls) ax.set_ylabel('Sarcomere\nlength [$\mu$m]') ax.yaxis.set_label_coords(ylabel_x_right, 0.5) # ax.set_xlabel('Time [ms]') # ax.xaxis.set_label_coords(0, -0.3) # Plot TriSeg titles = ['Pre-A', 'Onset QRS', 'Peak LV \n pressure', 'AV close'] idx = [0, np.argmax(np.diff(self['Patch']['C'][:, 'pLv0'])>0), np.argmax(self['Cavity']['p'][:, 'cLv']), len(t) - 1 - np.argmax( np.diff(self['Valve']['q'][:, 'LvSyArt'][::-1])>0) ] for i in range(4): ax = plt.subplot2grid(grid_size, (26, 16+4*i), rowspan=5, colspan=4, fig=fig) triseg2022(self, ax, idx[i], colors=[colors['Lv'], colors['Sv'], colors['Rv']]) ax.spines[['top', 'right', 'bottom', 'left']].set_visible(False) ax.set_xticks([]) ax.set_yticks([]) plt.xlabel(titles[i], fontsize=12) # Plot settings plt.subplots_adjust( top=0.96, bottom=0.05, left=0.075, right=0.98, hspace=5, wspace=0.5) plt.draw() # Stress strain ax_right_stress_strain = plt.subplot2grid(grid_size, (18, 17), rowspan=7, colspan=7, fig=fig) ax_left_stress_strain = plt.subplot2grid(grid_size, (18, 24), rowspan=7, colspan=7, fig=fig) ax_right_stress_strain.plot( self['Patch']['Ef'][:, 1], self['Patch']['Sf'][:, 1]*1e-3, c=colors['Ra'], ) ax_right_stress_strain.plot( self['Patch']['Ef'][:, 4], self['Patch']['Sf'][:, 4]*1e-3, c=colors['Rv'], ) ax_left_stress_strain.plot( self['Patch']['Ef'][:, 0], self['Patch']['Sf'][:, 0]*1e-3, c=colors['La'], ) ax_left_stress_strain.plot( self['Patch']['Ef'][:, 2], self['Patch']['Sf'][:, 2]*1e-3, c=colors['Lv'], ) ax_left_stress_strain.plot( self['Patch']['Ef'][:, 3], self['Patch']['Sf'][:, 3]*1e-3, c=colors['Sv'], ) ylim = [np.min(self['Patch']['Sf'])*1e-3, np.max(self['Patch']['Sf'])*1e-3] ylim_ptp = np.ptp(ylim)*0.025 ylim[0] -= ylim_ptp ylim[1] += ylim_ptp ax_right_stress_strain.set_ylim(ylim) ax_left_stress_strain.set_ylim(ylim) xlim = [np.min(self['Patch']['Ef']), np.max(self['Patch']['Ef'])] xlim_ptp = np.ptp(xlim)*0.025 xlim[0] -= xlim_ptp xlim[1] += xlim_ptp ax_right_stress_strain.set_xlim(xlim) ax_left_stress_strain.set_xlim(xlim) ax_right_stress_strain.spines[['left', 'bottom']].set_position(('outward', 5)) ax_left_stress_strain.spines[['right', 'bottom']].set_position(('outward', 5)) ax_right_stress_strain.spines[['top', 'right']].set_visible(False) ax_right_stress_strain.set_ylabel('[kPa]', rotation=0, va='bottom', ha='right') ax_right_stress_strain.yaxis.set_label_coords(0., 1.05) ax_right_stress_strain.set_xlabel('Strain [-]') ax_left_stress_strain.spines[['top', 'left']].set_visible(False) ax_left_stress_strain.yaxis.set_ticks_position('right') ax_left_stress_strain.yaxis.set_label_position('right') ax_left_stress_strain.set_ylabel('Stress\n[kPa]', rotation=0, va='bottom', ha='left') ax_left_stress_strain.yaxis.set_label_coords(1., 1.05) ax_left_stress_strain.set_xlabel('Strain [-]')
[docs] class VanOsta2023_2310(VanOsta2023):
[docs] def set_reference(self): self['Chamber']['buckling'] = False self['Valve']['soft_closure'] = True self['Valve']['papillary_muscles'] = True self['Solver']['dt'] = 0.001 self['Solver']['dt_export'] = 0.002 self.set('Solver.order', 2) self.set('Model.t_cycle', 0.85) self.set('Model.PFC.fac', 0.5) self.set('Model.PFC.epsilon', 0.1) self.set('Model.PFC.fac_pfc', 1) self.set('Model.PFC.stable_threshold', 0.001) # Set parameters Circulation self['Tube0D']['A0'] = [0.00049828, 0.00049899, 0.00046929, 0.00050574] self['Tube0D']['A_wall'] = [1.13187792e-04, 3.72289316e-05, 7.27489286e-05, 4.31617949e-05] self['Tube0D']['k'] = [1.66666667, 2.33333333, 1.66666667, 2.33333333] self['Tube0D']['l'] = [0.4, 0.4, 0.19, 0.19] self['Tube0D']['p0'] = [12155.25602777, 297.44066943, 1912.6684696 , 580.51425824] self['ArtVen']['p0'] = [6299.86481149, 1000. ] self['ArtVen']['q0'] = [4.5e-05, 4.5e-05] self['ArtVen']['k'] = [1. , 1.88] # Set volume state variables # not needed to reset, only if initial model crashes if True: self.set('Model.SyArt.V', 2e-4) self.set('Model.PuArt.V', 1e-4) self.set('Model.SyVen.V', 4e-4) self.set('Model.PuVen.V', 2e-4) self.set('Model.Peri.TriSeg.V', 56e-6) self.set('Model.Peri.TriSeg.Y', 36e-3) self.set('Model.Peri.TriSeg.cLv.V', 150e-6) self.set('Model.Peri.TriSeg.cRv.V', 110e-6) self.set('Model.Peri.La.V', 25e-6) self.set('Model.Peri.Ra.V', 150e-6) # all wall parameters self['Patch']['l_se0'] = 0.04 self['Patch']['l_s_ref'] = 2.0 self['Patch']['l_s0'] = [1.79, 1.79, 1.8 , 1.8 , 1.8 ] self['Patch']['dl_s_pas'] = 0.6 self['Patch']['k1'] = 10 self['Patch']['dt'] = 0 self['Patch']['C_rest'] = 0 self['Patch']['l_si0'] = 1.51 self['Patch']['LDAD'] = [1.057, 1.057, 0.74 , 0.74 , 0.74 ] self['Patch']['ADO'] = [0.081, 0.081, 0.75 , 0.75 , 0.75 ] self['Patch']['LDCC'] = [4. , 4. , 3., 3., 3.] self['Patch']['v_max'] = 7. self['Patch']['v_max'][:2] = 14. self['Patch']['tr'] = [0.4 , 0.4 , 0.21, 0.21, 0.21] self['Patch']['td'] = [0.4 , 0.4 , 0.24, 0.24, 0.24] # wall specific self['Patch']['Sf_act'] = [100000., 100000., 120000., 120000., 120000.] self['Patch']['Am_ref'] = [0.00400721, 0.00311263, 0.00918281, 0.00518683, 0.01321999] self['Patch']['V_wall'] = [1.59935455e-05, 7.72140495e-06, 1.16441768e-04, 4.51241560e-05, 6.88196851e-05] self['Patch']['Sf_pas'] = [ 9.51064014, 10.3647024 , 424.3537027 , 417.74300178, 439.21574206] # Valves self['Valve']['adaptation_A_open_fac'] = [1. , 1.12, 1. , 1. , 1.12, 1. ] self['Valve']['A_open'] = [0.00050044, 0.00052598, 0.00046962, 0.00050745, 0.0005583 , 0.00049849] self['Valve']['A_leak'] = [2.64705882e-04, 2.64705882e-10, 2.64705882e-10, 2.64705882e-04, 2.64705882e-10, 2.64705882e-10] self['Valve']['l'] = 0.01626978 self['Valve']['rho_b'] = 1050 self['Valve']['papillary_muscles'] = True self['Valve']['papillary_muscles_slope'] = 100 self['Valve']['papillary_muscles_min'] = 0.1 self['Valve']['papillary_muscles_A_open_fac'] = 0.1 self['Valve']['soft_closure'] = True self['Bag']['k'] = 10 self['Bag']['V_ref'] = [0.00057937] self['Bag']['p_ref'] = 100 self.set('Model.Peri.TriSeg.Y', 0.035) self['Timings']['law_tau_av'] = 2 self['Timings']['c_tau_av0'] = 0.22 self['Timings']['c_tau_av1'] = -0.03 # Adaptation self['Patch']['adapt_gamma'] = 0.5 self.set('Solver.store_beats', 1) self['PFC']['stable_threshold'] = 1e-3 self['Patch']['SfPasMaxT'] = [3600., 3600., 4200., 4200., 4200.] self['Patch']['FacSfActT'] = [0.28, 0.28, 0.69, 0.69, 0.69] self['Patch']['SfPasActT'] = [2800., 2800., 6600., 6600., 6600.] self['Patch']['LsPasActT'] = [3. , 3. , 2.31, 2.31, 2.31] self.run(stable=True) return
[docs] def get_unittest_targets(self): """Hardcoded results after initializing and running 1 beat.""" return { 'LVEDV': 121.75, 'LVESV': 48.0, }
[docs] class VanOsta2023_2306(VanOsta2023):
[docs] def set_reference(self): self['Chamber']['buckling'] = False self['Valve']['soft_closure'] = True self['Solver']['dt'] = 0.0005 self['Solver']['dt_export'] = self['Solver']['dt'] self.set('Model.t_cycle', 0.85) self.set('Model.PFC.fac', 0.5) self.set('Model.PFC.epsilon', 0.1) self.set('Model.PFC.fac_pfc', 1) self.set('Model.PFC.stable_threshold', 0.001) # Set parameters Circulation self['Tube0D']['A0'] = [ 0.00049833, 0.00050034, 0.0004684 , 0.00051849, ] self['Tube0D']['A_wall'] = [ 1.14408188e-04, 4.81082964e-05, 5.19472921e-05, 5.79933632e-05, ] self['Tube0D']['k'] = np.array([ 8., 10., 8., 10.]) / 3 - 1 self['Tube0D']['l'] = [0.4, 0.4, 0.2, 0.2] self['Tube0D']['p0'] = [ 12161.21763497, 112.09788908, 1899.95009955, 572.39790382, ] self['ArtVen']['p0'] = [6395.43973044, 500.] self['ArtVen']['q0'] = [4.5e-05, 4.5e-05] self['ArtVen']['k'] = [1, 2] # Set volume state variables # not needed to reset, only if initial model crashes if True: self.set('Model.SyArt.V', 2e-4) self.set('Model.PuArt.V', 1e-4) self.set('Model.SyVen.V', 4e-4) self.set('Model.PuVen.V', 2e-4) self.set('Model.Peri.TriSeg.V', 44e-6) self.set('Model.Peri.TriSeg.Y', 34.6e-3) self.set('Model.Peri.TriSeg.cLv.V', 150e-6) self.set('Model.Peri.TriSeg.cRv.V', 100e-6) self.set('Model.Peri.La.V', 100e-6) self.set('Model.Peri.Ra.V', 50e-6) # all wall parameters self['Patch']['l_se'] = 0.04 self['Patch']['l_s_ref'] = 2.0 self['Patch']['l_s0'] = 1.8 self['Patch']['dl_s_pas'] = 0.6 self['Patch']['k1'] = 10 self['Patch']['dt'] = 0 self['Patch']['C_rest'] = 0 self['Patch']['l_si0'] = 1.51 self['Patch']['LDAD'] = 1.057 self['Patch']['ADO'] = 0.65 self['Patch']['LDCC'] = 4. self['Patch']['v_max'] = 7. self['Patch']['v_max'][:2] = 14. self['Patch']['tr'] = 0.25 self['Patch']['td'] = 0.25 self['Patch']['tr'][:2] = 0.4 self['Patch']['td'][:2] = 0.4 # wall specific self['Patch']['Am_ref'] = [ 0.00706159, 0.00603949, 0.0093191 , 0.00507053, 0.01313792, ] self['Patch']['V_wall'] = [ 1.86518494e-05, 6.12511827e-06, 9.51121820e-05, 3.74835076e-05, 4.97478018e-05, ] self['Patch']['Sf_pas'] = np.array([ 51591.64007141, 52277.48834349, 22370.46712926, 22051.80366169, 23278.22158555, ]) * 0.0349 self['Patch']['Sf_act'] = [84e3, 84e3, 120e3, 120e3, 120e3] # Valves self['Valve']['adaptation_A_open_fac'] = [ 1., 1.5, 1., 1., 1.5, 1.] self['Valve']['A_open'] = [ 0.00050078, 0.0007021, 0.00046806, 0.00051776, 0.00074755, 0.00049837] self['Valve']['A_leak'] = [ 2.64705882e-04, 2.64705882e-10, 2.64705882e-10, 2.64705882e-04, 2.64705882e-10, 2.64705882e-10] self['Valve']['l'] = 0.01626978 self['Valve']['rho_b'] = 1050 self['Valve']['papillary_muscles'] = False self['Valve']['papillary_muscles_slope'] = 100 self['Valve']['papillary_muscles_min'] = 0.1 self['Valve']['papillary_muscles_A_open_fac'] = 0.1 self['Valve']['soft_closure'] = True self['Bag']['k'] = 10 self['Bag']['V_ref'] = 0.0005 self['Bag']['p_ref'] = 100 self.set('Model.Peri.TriSeg.Y', 0.035) self['Timings']['law_tau_av'] = 2 self['Timings']['c_tau_av0'] = 0.2 self['Timings']['c_tau_av1'] = -0.485*60e-3 # Adaptation self['Patch']['adapt_gamma'] = 0.75 self.run(stable=True)
[docs] def get_unittest_targets(self): """Hardcoded results after initializing and running 1 beat.""" return { 'LVEDV': 141.6, 'LVESV': 69.4, }
[docs] class VanOsta2023_2308(VanOsta2023):
[docs] def set_reference(self): self['Chamber']['buckling'] = False self['Valve']['soft_closure'] = True self['Valve']['papillary_muscles'] = True self['Solver']['dt'] = 0.001 self['Solver']['dt_export'] = 0.002 self.set('Solver.order', 2) self.set('Model.t_cycle', 0.85) self.set('Model.PFC.fac', 0.5) self.set('Model.PFC.epsilon', 0.1) self.set('Model.PFC.fac_pfc', 1) self.set('Model.PFC.stable_threshold', 0.001) # Set parameters Circulation self['Tube0D']['A0'] = [0.0004982 , 0.00049959, 0.00045184, 0.00051768] self['Tube0D']['A_wall'] = [1.13597208e-04, 3.79106863e-05, 8.91394588e-05, 4.26698697e-05] self['Tube0D']['k'] = [1.66666667, 2.33333333, 1. , 2.33333333] self['Tube0D']['l'] = [0.4, 0.4, 0.1, 0.1] self['Tube0D']['p0'] = [12154.79898845, 213.26733196, 1913.05480512, 600.72294959] self['ArtVen']['p0'] = [6345.26731406, 950. ] self['ArtVen']['q0'] = [4.5e-05, 4.5e-05] self['ArtVen']['k'] = [1. , 1.72] # Set volume state variables # not needed to reset, only if initial model crashes if True: self.set('Model.SyArt.V', 2e-4) self.set('Model.PuArt.V', 1e-4) self.set('Model.SyVen.V', 4e-4) self.set('Model.PuVen.V', 2e-4) self.set('Model.Peri.TriSeg.V', 56e-6) self.set('Model.Peri.TriSeg.Y', 36e-3) self.set('Model.Peri.TriSeg.cLv.V', 150e-6) self.set('Model.Peri.TriSeg.cRv.V', 110e-6) self.set('Model.Peri.La.V', 25e-6) self.set('Model.Peri.Ra.V', 150e-6) # all wall parameters self['Patch']['l_se'] = 0.04 self['Patch']['l_s_ref'] = 2.0 self['Patch']['l_s0'] = 1.8 self['Patch']['dl_s_pas'] = 0.6 self['Patch']['k1'] = 10 self['Patch']['dt'] = 0 self['Patch']['C_rest'] = 0 self['Patch']['l_si0'] = 1.51 self['Patch']['LDAD'] = [1.057, 1.057, 0.64 , 0.64 , 0.64 ] self['Patch']['ADO'] = [0.65, 0.65, 0.75, 0.75, 0.75] self['Patch']['LDCC'] = [4. , 4. , 3.2, 3.2, 3.2] self['Patch']['v_max'] = 7. self['Patch']['v_max'][:2] = 14. self['Patch']['tr'] = [0.4 , 0.4 , 0.24, 0.24, 0.24] self['Patch']['td'] = [0.4 , 0.4 , 0.23, 0.23, 0.23] # wall specific self['Patch']['Sf_act'] = [80e3, 80e3, 120e3, 120e3, 120e3] self['Patch']['Am_ref'] = [0.00458522, 0.00381765, 0.00806997, 0.00454307, 0.01176514] self['Patch']['V_wall'] = [2.75050615e-05, 1.25959326e-05, 8.80910385e-05, 3.46281364e-05, 5.16086110e-05] self['Patch']['Sf_pas'] = [ 16.51117993, 17.0639141 , 580.39235927, 569.67392472, 606.50514861] # Valves self['Valve']['adaptation_A_open_fac'] = [1. , 1.11, 1. , 1. , 1.11, 1. ] self['Valve']['A_open'] = [0.00050042, 0.00050203, 0.00045228, 0.00051764, 0.00055321, 0.00049838] self['Valve']['A_leak'] = [2.64705882e-04, 2.64705882e-10, 2.64705882e-10, 2.64705882e-04, 2.64705882e-10, 2.64705882e-10] self['Valve']['l'] = 0.01626978 self['Valve']['rho_b'] = 1050 self['Valve']['papillary_muscles'] = True self['Valve']['papillary_muscles_slope'] = 100 self['Valve']['papillary_muscles_min'] = 0.1 self['Valve']['papillary_muscles_A_open_fac'] = 0.1 self['Valve']['soft_closure'] = True self['Bag']['k'] = 10 self['Bag']['V_ref'] = [0.00051968] self['Bag']['p_ref'] = 100 self.set('Model.Peri.TriSeg.Y', 0.035) self['Timings']['law_tau_av'] = 2 self['Timings']['c_tau_av0'] = 0.172 self['Timings']['c_tau_av1'] = -0.485*60e-3 # Adaptation self['Patch']['adapt_gamma'] = 0.5 self.set('Solver.store_beats', 1) self['PressureFlowControl']['stable_threshold'] = 1e-3 self['Patch']['SfPasMaxT'] = [6400., 6400., 6600., 6600., 6600.] self['Patch']['FacSfActT'] = [0.44, 0.44, 0.61, 0.61, 0.61] self['Patch']['SfPasActT'] = [4800., 4800., 6600., 6600., 6600.] self['Patch']['LsPasActT'] = [3. , 3. , 2.23, 2.23, 2.23] self.run(stable=True) return
[docs] def get_unittest_targets(self): """Hardcoded results after initializing and running 1 beat.""" return { 'LVEDV': 119.7, 'LVESV': 47.2, }
[docs] class Walmsley2015(VanOsta2023):
[docs] def set_reference(self): # change model parameters here self['Chamber']['buckling'] = False self['Valve']['soft_closure'] = True self['Valve']['papillary_muscles'] = False self['Solver']['dt'] = 0.001 self['Solver']['dt_export'] = 0.002 self.set('Solver.order', 2) self.set('Model.t_cycle', 0.85) self.set('Model.PFC.fac', 0.5) self.set('Model.PFC.epsilon', 0.1) self.set('Model.PFC.fac_pfc', 1) self.set('Model.PFC.stable_threshold', 0.001) # Set parameters Circulation self['Tube0D']['A0'] = [4.9720e-04, 4.9830e-04, 4.6850e-04, 5.0910e-04] self['Tube0D']['A_wall'] = [1.1370e-04, 6.410e-05, 9.670e-05, 5.950e-05] self['Tube0D']['k'] = [1.66666667, 2.33333333, 1.66666667, 2.33333333] # self['Tube0D']['k'] = [8, 10, 8, 10] self['Tube0D']['l'] = [0.4, 0.4, 0.2, 0.2] self['Tube0D']['p0'] = [12164, 228, 2630 , 678] self['ArtVen']['p0'] = [6396, 1500. ] self['ArtVen']['q0'] = [4.5e-05, 4.5e-05] self['ArtVen']['k'] = [1. , 2] # Set volume state variables # not needed to reset, only if initial model crashes if True: self.set('Model.SyArt.V', 2e-4) self.set('Model.PuArt.V', 1e-4) self.set('Model.SyVen.V', 4e-4) self.set('Model.PuVen.V', 2e-4) self.set('Model.Peri.TriSeg.V', 56e-6) self.set('Model.Peri.TriSeg.Y', 36e-3) self.set('Model.Peri.TriSeg.cLv.V', 150e-6) self.set('Model.Peri.TriSeg.cRv.V', 110e-6) self.set('Model.Peri.La.V', 25e-6) self.set('Model.Peri.Ra.V', 150e-6) # all wall parameters self['Patch']['l_se0'] = 0.04 self['Patch']['l_s_ref'] = 2.0 self['Patch']['l_s0'] = [1.8, 1.8, 1.8 , 1.8 , 1.8 ] self['Patch']['dl_s_pas'] = 0.6 self['Patch']['k1'] = 10 self['Patch']['dt'] = 0 self['Patch']['C_rest'] = 0 self['Patch']['l_si0'] = 1.51 self['Patch']['LDAD'] = [1.057, 1.057, 0.74 , 0.74 , 0.74 ] self['Patch']['ADO'] = [0.081, 0.081, 0.75 , 0.75 , 0.75 ] self['Patch']['LDCC'] = [4. , 4. , 3., 3., 3.] self['Patch']['v_max'] = 7. self['Patch']['v_max'][:2] = 14. self['Patch']['tr'] = [0.4 , 0.4 , 0.25, 0.25, 0.25] self['Patch']['td'] = [0.4 , 0.4 , 0.25, 0.25, 0.25] # wall specific self['Patch']['Sf_act'] = [60000., 60000., 100000., 100000., 100000.] self['Patch']['Am_ref'] = [0.0071, 0.0058, 0.0099, 0.0052, 0.0135] self['Patch']['V_wall'] = [1.3377e-05, 5.4588e-06, 1.1382e-04, 3.8320e-05, 8.0093e-05] self['Patch']['Sf_pas'] = [ 2.8942e3, 3.6579e3 , 794.1495 , 790.6246, 801.1993] # Valves self['Valve']['adaptation_A_open_fac'] = [1. , 1.12, 1. , 1. , 1.12, 1. ] self['Valve']['A_open'] = [0.00049811, 0.00070281, 0.00046854, 0.00050903, 0.00074578 , 0.00049719] self['Valve']['A_leak'] = [2.6471e-04, 2.6471e-10, 2.6471e-10, 2.6471e-04, 2.6471e-10, 2.6471e-10] self['Valve']['l'] = 0.0163 self['Valve']['rho_b'] = 1050 self['Valve']['papillary_muscles'] = False self['Valve']['papillary_muscles_slope'] = 100 self['Valve']['papillary_muscles_min'] = 0.1 self['Valve']['papillary_muscles_A_open_fac'] = 0.1 self['Valve']['soft_closure'] = True self['Bag']['k'] = 10 self['Bag']['V_ref'] = [0.00072379] self['Bag']['p_ref'] = 100 self.set('Model.Peri.TriSeg.Y', 0.035) # self['Timings']['law_tauAv'] = 1 # self['Timings']['c_tauAv0'] = 0.22 # self['Timings']['c_tauAv1'] = -0.03 # Adaptation # self['Patch2022']['adapt_gamma'] = 0.5 self.set('Solver.store_beats', 1) self['PFC']['stable_threshold'] = 1e-3 # self['Patch']['SfPasMaxT'] = [3600., 3600., 4200., 4200., 4200.] # self['Patch']['FacSfActT'] = [0.28, 0.28, 0.69, 0.69, 0.69] # self['Patch']['SfPasActT'] = [2800., 2800., 6600., 6600., 6600.] # self['Patch']['LsPasActT'] = [3. , 3. , 2.31, 2.31, 2.31] self.run(stable=True)