"""
VanOsta2024 model.
This model is first used in Van Osta et al. under review
"""
from circadapt.model import Model
from circadapt.adapt import ModelAdapt
from circadapt.plot import triseg2022
import matplotlib.pyplot as plt
import numpy as np
# define colors for the plot function
colors = {
'Lv': np.array([213/255, 96/255, 98/255]),
'Sv': np.array([236/255, 195/255, 11/255]),
'Rv': np.array([6/255, 123/255, 194/255]),
'Ra': np.array([27/255, 231/255, 255/255]),
'La': np.array([250/255, 175/255, 150/255]),
'PuArt': np.array([5/255, 75/255, 125/255]),
'SyArt': np.array([150/255, 25/255, 25/255]),
'RaRv': np.array([0, 0, 0]),
'RvPuArt': np.array([0, 0, 0]),
'LaLv': np.array([0, 0, 0]),
'LvSyArt': np.array([0, 0, 0]),
}
colors['RaRv'] = colors['Ra'] #+ 0.5*colors['Rv']
colors['RvPuArt'] = colors['Rv'] #+ 0.5*colors['PuArt']
colors['LaLv'] = colors['La'] #+ 0.5*colors['Lv']
colors['LvSyArt'] = colors['Lv'] #+ 0.5*colors['SyArt']
colors['Sv'] = (0.5*colors['Lv'] + 0.5*colors['Rv'])**1.3
[docs]
class VanOsta2024(Model, ModelAdapt):
def __init__(self,
solver: str = None,
path_to_circadapt: str = None,
model_state: dict = None,
):
if solver is None:
solver = 'adams_moulton'
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['PressureFlowControl'] = 'PFC'
[docs]
def build(self):
pass
# Circulation
self.add_smart_component('ArtVen', build='SystemicCirculation')
self.add_smart_component('ArtVen', build='PulmonaryCirculation')
self.add_smart_component('Heart', patch_type='Patch', valve_type='Valve')
self.add_smart_component('Timings')
self.add_smart_component('PressureFlowControl')
self.set_component('PFC.circulation_volume_object', 'SyArt')
self.set_component('PFC.circulation_volume_object', 'SyVen')
self.set_component('PFC.circulation_volume_object', 'PuArt')
self.set_component('PFC.circulation_volume_object', 'PuVen')
self.set_component('PFC.circulation_volume_object', 'Peri.La')
self.set_component('PFC.circulation_volume_object', 'Peri.Ra')
self.set_component('PFC.circulation_volume_object', 'Peri.TriSeg.cLv')
self.set_component('PFC.circulation_volume_object', 'Peri.TriSeg.cRv')
# # 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'] = True
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['ArtVen']['p0'] = np.array([6306.25832487, 1000. ])
self['ArtVen']['q0'] = np.array([4.5e-05, 4.5e-05])
self['ArtVen']['k'] = np.array([1., 2.])
self['Tube0D']['l'] = np.array([0.4, 0.4, 0.2, 0.2])
self['Tube0D']['A_wall'] = np.array([1.12362733e-04, 6.57883944e-05, 9.45910889e-05, 8.22655361e-05])
self['Tube0D']['k'] = np.array([1.66666667, 2.33333333, 1.66666667, 2.33333333])
self['Tube0D']['p0'] = np.array([12162.50457811, 287.7083132 , 2132.51755623, 830.54673184])
self['Tube0D']['A0'] = np.array([0.0004983 , 0.00049909, 0.00047138, 0.00050803])
self['Tube0D']['target_wall_stress'] = np.array([500000., 500000., 500000., 500000.])
self['Tube0D']['target_mean_flow'] = np.array([0.17, 0.17, 0.17, 0.17])
self['Bag']['k'] = np.array([10.])
self['Bag']['p_ref'] = np.array([1000.])
self['Bag']['V_ref'] = np.array([0.00054267])
self['Patch']['Am_ref'] = np.array([0.00425687, 0.00401573, 0.00966859, 0.00289936, 0.01084227])
self['Patch']['V_wall'] = np.array([4.46069398e-06, 2.14548521e-06, 7.35720515e-05, 1.88904978e-05, 3.67720116e-05,])
self['Patch']['v_max'] = np.array([14., 14., 7., 7., 7.])
self['Patch']['l_se0'] = np.array([0.04, 0.04, 0.04, 0.04, 0.04])
self['Patch']['l_s0'] = np.array([1.8, 1.8, 1.8, 1.8, 1.8])
self['Patch']['l_s_ref'] = np.array([2., 2., 2., 2., 2.])
self['Patch']['dl_s_pas'] = np.array([0.6, 0.6, 0.6, 0.6, 0.6])
self['Patch']['Sf_pas'] = np.array([2248.53598 , 2684.76100348, 731.24545453, 729.06063771, 749.47694522,])
self['Patch']['tr'] = np.array([0.4 , 0.4 , 0.25, 0.25, 0.25])
self['Patch']['td'] = np.array([0.4 , 0.4 , 0.25, 0.25, 0.25])
self['Patch']['time_act'] = np.array([0.15 , 0.15 , 0.425, 0.425, 0.425])
self['Patch']['Sf_act'] = np.array([ 84000., 84000., 120000., 120000., 120000.])
self['Patch']['fac_Sf_tit'] = np.array([0.01, 0.01, 0.01, 0.01, 0.01])
self['Patch']['k1'] = np.array([10., 10., 10., 10., 10.])
self['Patch']['dt'] = np.array([0., 0., 0., 0., 0.])
self['Patch']['C_rest'] = np.array([0., 0., 0., 0., 0.])
self['Patch']['l_si0'] = np.array([1.51, 1.51, 1.51, 1.51, 1.51])
self['Patch']['LDAD'] = np.array([1.057, 1.057, 1.057, 1.057, 1.057])
self['Patch']['ADO'] = np.array([0.65, 0.65, 0.65, 0.65, 0.65])
self['Patch']['LDCC'] = np.array([4., 4., 4., 4., 4.])
self['Patch']['SfPasMaxT'] = np.array([320000., 320000., 16000., 16000., 16000.])
self['Patch']['SfPasActT'] = np.array([40000., 40000., 20000., 20000., 20000.])
self['Patch']['FacSfActT'] = np.array([0.8, 0.8, 1. , 1. , 1. ])
self['Patch']['LsPasActT'] = np.array([2.42, 2.42, 2.42, 2.42, 2.42])
self['Patch']['adapt_gamma'] = np.array([0.5, 0.5, 0.5, 0.5, 0.5])
self['Patch']['transmat00'] = np.array([-0.5751, -0.5751, -0.5751, -0.5751, -0.5751])
self['Patch']['transmat01'] = np.array([-0.7851, -0.7851, -0.7851, -0.7851, -0.7851])
self['Patch']['transmat02'] = np.array([0.6063, 0.6063, 0.6063, 0.6063, 0.6063])
self['Patch']['transmat03'] = np.array([-0.5565, -0.5565, -0.5565, -0.5565, -0.5565])
self['Patch']['transmat10'] = np.array([-0.1279, -0.1279, -0.1279, -0.1279, -0.1279])
self['Patch']['transmat11'] = np.array([0.0999, 0.0999, 0.0999, 0.0999, 0.0999])
self['Patch']['transmat12'] = np.array([0.2066, 0.2066, 0.2066, 0.2066, 0.2066])
self['Patch']['transmat13'] = np.array([-1.8441, -1.8441, -1.8441, -1.8441, -1.8441])
self['Patch']['transmat20'] = np.array([-0.1865, -0.1865, -0.1865, -0.1865, -0.1865])
self['Patch']['transmat21'] = np.array([-0.201, -0.201, -0.201, -0.201, -0.201])
self['Patch']['transmat22'] = np.array([1.3195, 1.3195, 1.3195, 1.3195, 1.3195])
self['Patch']['transmat23'] = np.array([-11.8745, -11.8745, -11.8745, -11.8745, -11.8745])
self['Valve']['adaptation_A_open_fac'] = np.array([1., 1., 1., 1., 1., 1.])
self['Valve']['A_open'] = np.array([0.00049916, 0.00047155, 0.00047155, 0.00050805, 0.00049835,
0.00049835])
self['Valve']['A_leak'] = np.array([0.00049916, 1.e-09, 1.e-09, 0.00050805, 1.e-09, 1.e-09])
self['Valve']['l'] = np.array([0.01260512, 0.01225144, 0.01225144, 0.01271679, 0.01259479,
0.01259479])
self['Valve']['L_fac_prox'] = np.array([0.75, 0.75, 0.75, 0.75, 0.75, 0.75])
self['Valve']['L_fac_dist'] = np.array([0.75, 0.75, 0.75, 0.75, 0.75, 0.75])
self['Valve']['L_fac_valve'] = np.array([1.5, 1.5, 1.5, 1.5, 1.5, 1.5])
self['Valve']['rho_b'] = np.array([1050., 1050., 1050., 1050., 1050., 1050.])
self['Valve']['papillary_muscles'] = np.array([False, False, False, False, False, False])
self['Valve']['papillary_muscles_slope'] = np.array([100., 100., 100., 100., 100., 100.])
self['Valve']['papillary_muscles_min'] = np.array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
self['Valve']['papillary_muscles_A_open_fac'] = np.array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1])
self['Valve']['soft_closure'] = np.array([ True, True, True, True, True, True])
self['Valve']['fraction_A_open_Aext'] = np.array([0.9, 0.9, 0.9, 0.9, 0.9, 0.9])
self['Timings']['time_fac'] = np.array([1.])
self['Timings']['tau_av'] = np.array([0.150025])
self['Timings']['dtau_av'] = np.array([0.])
self['Timings']['law_tau_av'] = np.array([1])
self['Timings']['law_Ra2La'] = np.array([1])
self['Timings']['law_ta'] = np.array([1])
self['Timings']['law_tv'] = np.array([1])
self['Timings']['c_tau_av0'] = np.array([0.])
self['Timings']['c_tau_av1'] = np.array([0.1765])
self['Timings']['c_ta_rest'] = np.array([0.])
self['Timings']['c_ta_tcycle'] = np.array([0.17647059])
self['Timings']['c_tv_rest'] = np.array([0.1])
self['Timings']['c_tv_tcycle'] = np.array([0.4])
self['PFC']['p0'] = np.array([12200.])
self['PFC']['q0'] = np.array([8.5e-05])
self['PFC']['stable_threshold'] = np.array([0.0001])
self['PFC']['is_active'] = np.array([ True])
self['PFC']['fac'] = np.array([1.])
self['PFC']['fac_pfc'] = np.array([1.])
self['PFC']['epsilon'] = np.array([0.4])
self['TriSeg']['tau'] = np.array([2.])
self['TriSeg']['ratio_septal_LV_Am'] = np.array([0.3])
self['TriSeg']['max_number_of_iterations'] = np.array([100.])
self['TriSeg']['thresh_F'] = np.array([0.001])
self['TriSeg']['thresh_dV'] = np.array([1.e-09])
self['TriSeg']['thresh_dY'] = np.array([1.e-06])
self.run(stable=True)
# self.adapt()
# set target volume
self['PFC']['target_volume'] = self['PFC']['circulation_volume']
return
[docs]
def get_unittest_targets(self):
"""Hardcoded results after initializing and running 1 beat."""
return {
'LVEDV': 120.5,
'LVESV': 48.3,
}
[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 len(self['Solver']['t'])==0:
raise RuntimeError('Can not plot the model, as no data is available. Did you simulate the model?')
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', weight='bold')
# 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', weight='bold')
# 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, sharex=axVRv)
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, sharex=axVLv)
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, sharex=axVRv)
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, sharex=axVLv)
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, sharex=axVRv)
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, sharex=axVLv)
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, sharex=axVRv)
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, sharex=axVLv)
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'][:, 'pRa0'],
self['Patch']['Sf'][:, 'pRa0']*1e-3,
c=colors['Ra'],
)
ax_right_stress_strain.plot(
self['Patch']['Ef'][:, 'pRv0'],
self['Patch']['Sf'][:, 'pRv0']*1e-3,
c=colors['Rv'],
)
ax_left_stress_strain.plot(
self['Patch']['Ef'][:, 'pLa0'],
self['Patch']['Sf'][:, 'pLa0']*1e-3,
c=colors['La'],
)
ax_left_stress_strain.plot(
self['Patch']['Ef'][:, 'pLv0'],
self['Patch']['Sf'][:, 'pLv0']*1e-3,
c=colors['Lv'],
)
ax_left_stress_strain.plot(
self['Patch']['Ef'][:, 'pSv0'],
self['Patch']['Sf'][:, 'pSv0']*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 [-]')