Build your own model class

Todo

Explain how to create a custom model class

When the model is created, it must be parameterized properly. It is explained here how to create your own reference model state.

The model VanOsta2023 is build following this standard. This model is constructed by the following code.

  1"""
  2VanOsta2023 model.
  3
  4"""
  5
  6import circadapt
  7import circadapt.plot
  8from circadapt.model import Model
  9from circadapt.adapt import ModelAdapt
 10from circadapt.plot import triseg2022, mmode
 11import matplotlib.pyplot as plt
 12import numpy as np
 13
 14class VanOsta2023(Model, ModelAdapt):
 15    def __init__(self,
 16                 solver: str = None,
 17                 path_to_circadapt: str = None,
 18                 model_state: dict = None,
 19                 ):
 20        if solver is None:
 21            solver = 'backward_differential'
 22
 23        self._local_save_reference = True
 24
 25        ModelAdapt.__init__(self)
 26        Model.__init__(self,
 27                       solver,
 28                       path_to_circadapt=path_to_circadapt,
 29                       model_state=model_state,
 30                       )
 31
 32    def build(self):
 33        # Circulation
 34        self.add_smart_component('ArtVen', build='SystemicCirculation')
 35        self.add_smart_component('ArtVen', build='PulmonaryCirculation')
 36        self.add_smart_component('Heart', patch_type='Patch2022')
 37        self.add_smart_component('Timings')
 38        self.add_smart_component('PressureFlowControl')
 39
 40        # manually set papillary muscles
 41        self.set_component("Peri.RaRv.wPapMus", "Peri.TriSeg.wRv")
 42        self.set_component("Peri.LaLv.wPapMus", "Peri.TriSeg.wLv")
 43
 44    def set_reference(self):
 45        self['Chamber2022']['buckling'] = False
 46        self['Valve2022']['soft_closure'] = True
 47        self['Valve2022']['papillary_muscles'] = True
 48
 49        self['Solver']['dt'] = 0.001
 50        self['Solver']['dt_export'] = 0.002
 51        self.set('Solver.order',  2)
 52
 53        self.set('Model.t_cycle', 0.85)
 54
 55        self.set('Model.PFC.fac',  0.5)
 56        self.set('Model.PFC.epsilon', 0.1)
 57        self.set('Model.PFC.fac_pfc', 1)
 58        self.set('Model.PFC.stable_threshold', 0.001)
 59
 60        # Set parameters Circulation
 61        self['Tube0D']['A0'] = [0.0004982 , 0.00049959, 0.00045184, 0.00051768]
 62        self['Tube0D']['A_wall'] = [1.13597208e-04, 3.79106863e-05, 8.91394588e-05, 4.26698697e-05]
 63        self['Tube0D']['k'] = [1.66666667, 2.33333333, 1.        , 2.33333333]
 64        self['Tube0D']['l'] = [0.4, 0.4, 0.1, 0.1]
 65        self['Tube0D']['p0'] = [12154.79898845,   213.26733196,  1913.05480512,   600.72294959]
 66
 67        self['ArtVen']['p0'] = [6345.26731406,  950.        ]
 68        self['ArtVen']['q0'] = [4.5e-05, 4.5e-05]
 69        self['ArtVen']['k'] = [1.  , 1.72]
 70
 71        # Set volume state variables
 72        # not needed to reset, only if initial model crashes
 73        if True:
 74            self.set('Model.SyArt.V', 2e-4)
 75            self.set('Model.PuArt.V', 1e-4)
 76            self.set('Model.SyVen.V', 4e-4)
 77            self.set('Model.PuVen.V', 2e-4)
 78
 79            self.set('Model.Peri.TriSeg.V', 56e-6)
 80            self.set('Model.Peri.TriSeg.Y', 36e-3)
 81
 82            self.set('Model.Peri.TriSeg.cLv.V',  150e-6)
 83            self.set('Model.Peri.TriSeg.cRv.V',  110e-6)
 84            self.set('Model.Peri.La.V',  25e-6)
 85            self.set('Model.Peri.Ra.V',  150e-6)
 86
 87        # all wall parameters
 88        self['Patch2022']['l_se'] = 0.04
 89        self['Patch2022']['l_s_ref'] = 2.0
 90        self['Patch2022']['l_s0'] = 1.8
 91        self['Patch2022']['dl_s_pas'] = 0.6
 92        self['Patch2022']['k1'] = 10
 93        self['Patch2022']['dt'] = 0
 94        self['Patch2022']['C_rest'] = 0
 95        self['Patch2022']['l_si0'] = 1.51
 96        self['Patch2022']['LDAD'] = [1.057, 1.057, 0.64 , 0.64 , 0.64 ]
 97        self['Patch2022']['ADO'] = [0.65, 0.65, 0.75, 0.75, 0.75]
 98        self['Patch2022']['LDCC'] = [4. , 4. , 3.2, 3.2, 3.2]
 99        self['Patch2022']['v_max'] = 7.
100        self['Patch2022']['v_max'][:2] = 14.
101
102        self['Patch2022']['tr'] = [0.4 , 0.4 , 0.24, 0.24, 0.24]
103        self['Patch2022']['td'] = [0.4 , 0.4 , 0.23, 0.23, 0.23]
104
105        # wall specific
106        self['Patch2022']['Sf_act'] = [80e3, 80e3, 120e3, 120e3, 120e3]
107        self['Patch2022']['Am_ref'] = [0.00458522, 0.00381765, 0.00806997, 0.00454307, 0.01176514]
108        self['Patch2022']['V_wall'] = [2.75050615e-05, 1.25959326e-05, 8.80910385e-05, 3.46281364e-05,
109               5.16086110e-05]
110        self['Patch2022']['Sf_pas'] = [ 16.51117993,  17.0639141 , 580.39235927, 569.67392472,
111               606.50514861]
112
113        # Valves
114        self['Valve2022']['adaptation_A_open_fac'] = [1.  , 1.11, 1.  , 1.  , 1.11, 1.  ]
115        self['Valve2022']['A_open'] = [0.00050042, 0.00050203, 0.00045228, 0.00051764, 0.00055321,
116               0.00049838]
117        self['Valve2022']['A_leak'] = [2.64705882e-04, 2.64705882e-10, 2.64705882e-10, 2.64705882e-04,
118               2.64705882e-10, 2.64705882e-10]
119        self['Valve2022']['l'] = 0.01626978
120        self['Valve2022']['rho_b'] = 1050
121        self['Valve2022']['papillary_muscles'] = True
122        self['Valve2022']['papillary_muscles_slope'] = 100
123        self['Valve2022']['papillary_muscles_min'] = 0.1
124        self['Valve2022']['papillary_muscles_A_open_fac'] = 0.1
125        self['Valve2022']['soft_closure'] = True
126
127        self['Bag']['k'] = 10
128        self['Bag']['V_ref'] = [0.00051968]
129        self['Bag']['p_ref'] = 100
130
131        self.set('Model.Peri.TriSeg.Y', 0.035)
132
133        self['Timings']['law_tauAv'] = 2
134        self['Timings']['c_tauAv0'] = 0.172
135        self['Timings']['c_tauAv1'] = -0.485*60e-3
136
137        # Adaptation
138        self['Patch2022']['adapt_gamma'] = 0.5
139        self.set('Solver.store_beats', 1)
140
141        self['PressureFlowControl']['stable_threshold'] = 1e-3
142
143        self['Patch2022']['SfPasMaxT'] = [6400., 6400.,  6600.,  6600.,  6600.]
144        self['Patch2022']['FacSfActT'] = [0.44, 0.44, 0.61, 0.61, 0.61]
145        self['Patch2022']['SfPasActT'] = [4800., 4800., 6600., 6600., 6600.]
146        self['Patch2022']['LsPasActT'] = [3.  , 3.  , 2.23, 2.23, 2.23]
147
148        self.run(stable=True)
149
150        return
151
152
153        options = self.get_adapt_options()
154        self['General']['q0'] = options['exercise']['q0']
155        self['General']['t_cycle'] = options['exercise']['t_cycle']
156        self.run(stable=True)
157
158        reference_y = np.array([
159            self['Patch2022']['SfEcmMax'],
160            self['Patch2022']['SfActMax'],
161            self['Patch2022']['SfPasAct'],
162            self['Patch2022']['LsPasAct'],
163            ]).T
164
165        targets = np.array([
166            np.mean(reference_y[:2, :], axis=0),
167            np.mean(reference_y[2:, :], axis=0),
168            ])
169        targets[:, 1] /= self['Patch2022']['Sf_act'][:][[0, 2]]
170
171        # targets = np.array(
172        #     [[5.5e+05, 1.9e-01, 3.5e+03, 2.2e+00],
173        #      [6.0e+03, 4.9e-01, 4.0e+03, 2.3e+00],
174        #      ])
175
176        self['Patch2022']['SfPasMaxT'] = targets[[0, 0, 1, 1, 1], 0]
177        self['Patch2022']['FacSfActT'] = targets[[0, 0, 1, 1, 1], 1]
178        self['Patch2022']['SfPasActT'] = targets[[0, 0, 1, 1, 1], 2]
179        self['Patch2022']['LsPasActT'] = targets[[0, 0, 1, 1, 1], 3]
180
181        self['Patch2022']['adapt_gamma'] = 0.1
182        self.adapt(verbose=True)
183        self['Patch2022']['adapt_gamma'] = 0.5
184        self.adapt(verbose=True)
185
186        # Set adaptation constants
187        self.calculate_and_set_matrix(verbose=True)
188
189        # set resting state
190        self['General']['q0'] = options['rest']['q0']
191        self['General']['t_cycle'] = options['rest']['t_cycle']
192        self.run(stable=True)
193
194    def get_unittest_targets(self):
195        """Hardcoded results after initializing and running 1 beat."""
196        return {
197            'LVEDV': 119.7,
198            'LVESV':  47.2,
199            }
200
201    def get_unittest_results(self, model):
202        """Real-time results after initializing and running 1 beat."""
203        LVEDV = np.max(model['Cavity']['V'][:, 'cLv'])*1e6
204        LVESV = np.min(model['Cavity']['V'][:, 'cLv'])*1e6
205        return {
206            'LVEDV': LVEDV,
207            'LVESV': LVESV,
208            }
209
210    def plot(self, fig=None):
211        # TODO
212        self.plot_extended(fig)
213
214    def plot_extended(self, fig=None):
215        if fig is None:
216            fig = 1
217        if isinstance(fig, int):
218            fig = plt.figure(fig, clear=True, figsize=(12, 8))
219
220        # Settings
221        grid_size = [32, 32]
222
223        def get_lim(module, signal, locs=slice(None, None, None)):
224            signal = self[module][signal][:, locs]
225            lim = np.array([np.min(signal), np.max(signal)])
226            lim += np.array([-1, 1]) * 0.1*np.diff(lim)
227            return lim
228
229        lim_V = get_lim('Cavity', 'V', ['cRv', 'Ra', 'La', 'cLv']) * 1e6
230        lim_V[0] = 0
231        lim_p = get_lim('Cavity', 'p', ['cRv', 'Ra', 'La', 'cLv']) / 133
232        lim_p[0] = np.min([lim_p[0], 0])
233        lim_Ls = get_lim('Patch2022', 'l_s')
234        lim_Sf = get_lim('Patch2022', 'Sf') * 1e-3
235        lim_q = get_lim('Valve2022', 'q',
236                        ['LaLv', 'RaRv', 'LvSyArt', 'RaPuArt']) * 1e6
237
238        all_lim = [lim_V, lim_p, lim_Ls, lim_Sf, lim_q]
239        if (np.any(np.isnan(all_lim)) or np.any(np.isinf(all_lim))):
240            lim_V = [0, 200]
241            lim_p = [0, 150]
242            lim_Ls = [1.5, 2.0]
243            lim_Sf = [0, 100]
244            lim_q = [-1e-3, 1e-3]
245
246        # Pressure Volume plot
247        axPV = plt.subplot2grid(grid_size, (0, 17), rowspan=15, colspan=15, fig=fig)
248        axPV.plot(self['Cavity']['V'][:, 'cLv']*1e6, self['Cavity']['p'][:, 'cLv']/133)
249        axPV.plot(self['Cavity']['V'][:, 'cRv']*1e6, self['Cavity']['p'][:, 'cRv']/133)
250        axPV.plot(self['Cavity']['V'][:, 'La']*1e6, self['Cavity']['p'][:, 'La']/133)
251        axPV.plot(self['Cavity']['V'][:, 'Ra']*1e6, self['Cavity']['p'][:, 'Ra']/133)
252        axPV.spines[['top', 'right']].set_visible(False)
253        axPV.set_title('Pressure-Volume loop', weight='bold')
254        axPV.set_xlabel('Volume [mL]')
255        axPV.set_ylabel('Pressure [mmHg]')
256        axPV.spines[['bottom', 'left']].set_position(('outward', 5))
257
258        ylabel_x_left = -0.25
259        ylabel_x_right = 1.25
260
261        # Volumes
262        t = self['Solver']['t']*1e3
263        t -= t[0]
264
265        axVRv = plt.subplot2grid(grid_size, (0, 0), rowspan=8, colspan=6, fig=fig)
266        axVRv.plot(t, self['Cavity']['V'][:, 'cRv']*1e6)
267        axVRv.plot(t, self['Cavity']['V'][:, 'Ra']*1e6)
268        axVRv.set_ylim(lim_V)
269        axVRv.set_ylabel('Volume\n[mL]')
270        axVRv.spines[['top', 'right']].set_visible(False)
271        axVRv.set_title('Right Heart')
272        # axVRv.set_xticks([])
273        axVRv.tick_params(axis='both', direction='in')
274        axVRv.yaxis.set_label_coords(ylabel_x_left, 0.5)
275
276
277        axVLv = plt.subplot2grid(grid_size, (0, 6), rowspan=8, colspan=6, fig=fig)
278        axVLv.plot(t, self['Cavity']['V'][:, 'cLv']*1e6)
279        axVLv.plot(t, self['Cavity']['V'][:, 'La']*1e6)
280        axVLv.set_ylabel('Volume\n[mL]')
281        axVLv.set_ylim(lim_V)
282        axVLv.yaxis.set_ticks_position('right')
283        axVLv.yaxis.set_label_position('right')
284        axVLv.spines['right'].set_position(('outward', 0))
285        axVLv.spines[['top', 'left']].set_visible(False)
286        axVLv.set_title('Left Heart')
287        # axVLv.set_xticks([])
288        axVLv.tick_params(axis='both', direction='in')
289        axVLv.yaxis.set_label_coords(ylabel_x_right, 0.5)
290
291        # Pressures
292        axpRv = plt.subplot2grid(grid_size, (8, 0), rowspan=8, colspan=6, fig=fig)
293        axpRv.plot(t, self['Cavity']['p'][:, 'cRv']/133)
294        axpRv.plot(t, self['Cavity']['p'][:, 'Ra']/133)
295        axpRv.plot(t, self['Cavity']['p'][:, 'PuArt']/133)
296        axpRv.spines[['top', 'right']].set_visible(False)
297        # axpRv.set_xticks([])
298        axpRv.tick_params(axis='both', direction='in')
299        axpRv.set_ylim(lim_p)
300        axpRv.set_ylabel('Pressure\n[mmHg]')
301        axpRv.yaxis.set_label_coords(ylabel_x_left, 0.5)
302
303        axpLv = plt.subplot2grid(grid_size, (8, 6), rowspan=8, colspan=6, fig=fig)
304        axpLv.plot(t, self['Cavity']['p'][:, 'cLv']/133)
305        axpLv.plot(t, self['Cavity']['p'][:, 'La']/133)
306        axpLv.plot(t, self['Cavity']['p'][:, 'SyArt']/133)
307        axpLv.yaxis.set_ticks_position('right')
308        axpLv.yaxis.set_label_position('right')
309        axpLv.spines['right'].set_position(('outward', 0))
310        axpLv.spines[['top', 'left']].set_visible(False)
311        # axpLv.set_xticks([])
312        axpLv.tick_params(axis='both', direction='in')
313        axpLv.set_ylim(lim_p)
314        axpLv.set_ylabel('Pressure\n[mmHg]')
315        axpLv.yaxis.set_label_coords(ylabel_x_right, 0.5)
316
317        # Valves
318        ax = plt.subplot2grid(grid_size, (16, 0), rowspan=6, colspan=6, fig=fig)
319        ax.plot(t, self['Valve2022']['q'][:, 'RaRv']*1e6)
320        ax.plot(t, self['Valve2022']['q'][:, 'RvPuArt']*1e6)
321        ax.spines[['top', 'right']].set_visible(False)
322        ax.set_ylim(lim_q)
323        # ax.set_xticks([])
324        ax.set_ylabel('Flow\n[mL/s]')
325        ax.yaxis.set_label_coords(ylabel_x_left, 0.5)
326
327        ax = plt.subplot2grid(grid_size, (16, 6), rowspan=6, colspan=6, fig=fig)
328        ax.plot(t, self['Valve2022']['q'][:, 'LaLv']*1e6)
329        ax.plot(t, self['Valve2022']['q'][:, 'LvSyArt']*1e6)
330        ax.spines[['top', 'left']].set_visible(False)
331        ax.set_ylim(lim_q)
332        ax.yaxis.set_ticks_position('right')
333        ax.yaxis.set_label_position('right')
334        # ax.set_xticks([])
335        ax.set_ylabel('Flow\n[mL/s]')
336        ax.yaxis.set_label_coords(ylabel_x_right, 0.5)
337
338        # Stress
339        ax = plt.subplot2grid(grid_size, (22, 0), rowspan=4, colspan=6, fig=fig)
340        ax.plot(t, self['Patch2022']['Sf'][:, 'pRv0']*1e-3)
341        ax.plot(t, self['Patch2022']['Sf'][:, 'pRa0']*1e-3)
342        ax.spines[['top', 'right']].set_visible(False)
343        # ax.set_xticks([])
344        ax.set_ylim(lim_Sf)
345        ax.set_ylabel('Total\nstress [kPa]')
346        ax.yaxis.set_label_coords(ylabel_x_left, 0.5)
347
348        ax = plt.subplot2grid(grid_size, (22, 6), rowspan=4, colspan=6, fig=fig)
349        ax.plot(t, self['Patch2022']['Sf'][:, 'pLv0']*1e-3)
350        ax.plot(t, self['Patch2022']['Sf'][:, 'pSv0']*1e-3)
351        ax.plot(t, self['Patch2022']['Sf'][:, 'pLa0']*1e-3)
352        ax.spines[['top', 'left']].set_visible(False)
353        ax.yaxis.set_ticks_position('right')
354        ax.yaxis.set_label_position('right')
355        # ax.set_xticks([])
356        ax.set_ylim(lim_Sf)
357        ax.set_ylabel('Total\nstress [kPa]')
358        ax.yaxis.set_label_coords(ylabel_x_right, 0.5)
359
360        # Sarcomere Length
361        ax = plt.subplot2grid(grid_size, (26, 0), rowspan=6, colspan=6, fig=fig)
362        ax.plot(t, self['Patch2022']['l_s'][:, 'pRv0'])
363        ax.plot(t, self['Patch2022']['l_s'][:, 'pRa0'])
364        ax.spines[['top', 'right']].set_visible(False)
365        ax.spines['bottom'].set_position(('outward', 5))
366        ax.set_ylim(lim_Ls)
367        ax.set_ylabel('Sarcomere\nlength [$\mu$m]')
368        ax.yaxis.set_label_coords(ylabel_x_left, 0.5)
369
370        ax = plt.subplot2grid(grid_size, (26, 6), rowspan=6, colspan=6, fig=fig)
371        ax.plot(t, self['Patch2022']['l_s'][:, 'pLv0'])
372        ax.plot(t, self['Patch2022']['l_s'][:, 'pSv0'])
373        ax.plot(t, self['Patch2022']['l_s'][:, 'pLa0'])
374        ax.spines[['top', 'left']].set_visible(False)
375        ax.spines['bottom'].set_position(('outward', 5))
376        ax.yaxis.set_ticks_position('right')
377        ax.yaxis.set_label_position('right')
378        ax.set_ylim(lim_Ls)
379        ax.set_ylabel('Sarcomere\nlength [$\mu$m]')
380        ax.yaxis.set_label_coords(ylabel_x_right, 0.5)
381
382        # ax.set_xlabel('Time [ms]')
383        # ax.xaxis.set_label_coords(0, -0.3)
384
385
386        # Plot TriSeg
387        titles = ['Pre-A', 'Onset QRS', 'Peak LV \n pressure', 'AV close']
388        idx = [0,
389               np.argmax(np.diff(self['Patch2022']['C'][:, 'pLv0'])>0),
390               np.argmax(self['Cavity']['p'][:, 'cLv']),
391               len(t) - 1 - np.argmax(
392                   np.diff(self['Valve2022']['q'][:, 'LvSyArt'][::-1])>0)
393               ]
394
395        for i in range(4):
396            ax = plt.subplot2grid(grid_size, (26, 16+4*i),
397                                  rowspan=5, colspan=4, fig=fig)
398            triseg2022(self, ax, idx[i])
399            ax.spines[['top', 'right', 'bottom', 'left']].set_visible(False)
400            ax.set_xticks([])
401            ax.set_yticks([])
402            plt.xlabel(titles[i], fontsize=12)
403
404        # Plot settings
405        plt.subplots_adjust(
406            top=0.96,
407            bottom=0.05,
408            left=0.075,
409            right=0.98,
410            hspace=5,
411            wspace=0.5)
412        plt.draw()
413
414        # Plot MMode
415        ax_mmode = plt.subplot2grid(grid_size, (17, 17),
416                              rowspan=8, colspan=15, fig=fig)
417        circadapt.plot.triseg.mmode(self, ax_mmode)
418        ax_mmode.axhline(0, c='k', ls='--')
419        ax_mmode.spines[['top', 'right']].set_visible(False)
420
421        # Plot Y
422        # ax_mmode = plt.subplot2grid(grid_size, (17, 25),
423        #                       rowspan=8, colspan=7, fig=fig)
424        ax_mmode.plot(t, self['TriSeg2022']['Y']*1e3 * np.array([[1, -1]]), c='k')
425        ax_mmode.spines[['top', 'right']].set_visible(False)
426        plt.ylabel('MMode and Y [mm]')
427
428
429class VanOsta2023_2306(VanOsta2023):
430    def set_reference(self):
431        self['Chamber2022']['buckling'] = False
432        self['Valve2022']['soft_closure'] = True
433
434        self['Solver']['dt'] = 0.0005
435        self['Solver']['dt_export'] = self['Solver']['dt']
436
437        self.set('Model.t_cycle', 0.85)
438
439        self.set('Model.PFC.fac',  0.5)
440        self.set('Model.PFC.epsilon', 0.1)
441        self.set('Model.PFC.fac_pfc', 1)
442        self.set('Model.PFC.stable_threshold', 0.001)
443
444        # Set parameters Circulation
445        self['Tube0D']['A0'] = [
446            0.00049833,
447            0.00050034,
448            0.0004684 ,
449            0.00051849,
450            ]
451        self['Tube0D']['A_wall'] = [
452            1.14408188e-04,
453            4.81082964e-05,
454            5.19472921e-05,
455            5.79933632e-05,
456            ]
457        self['Tube0D']['k'] = np.array([ 8., 10.,  8., 10.]) / 3 - 1
458        self['Tube0D']['l'] = [0.4, 0.4, 0.2, 0.2]
459        self['Tube0D']['p0'] = [
460            12161.21763497,
461            112.09788908,
462            1899.95009955,
463            572.39790382,
464            ]
465
466        self['ArtVen']['p0'] = [6395.43973044,  500.]
467        self['ArtVen']['q0'] = [4.5e-05, 4.5e-05]
468        self['ArtVen']['k'] = [1, 2]
469
470        # Set volume state variables
471        # not needed to reset, only if initial model crashes
472        if True:
473            self.set('Model.SyArt.V', 2e-4)
474            self.set('Model.PuArt.V', 1e-4)
475            self.set('Model.SyVen.V', 4e-4)
476            self.set('Model.PuVen.V', 2e-4)
477
478            self.set('Model.Peri.TriSeg.V', 44e-6)
479            self.set('Model.Peri.TriSeg.Y', 34.6e-3)
480
481            self.set('Model.Peri.TriSeg.cLv.V',  150e-6)
482            self.set('Model.Peri.TriSeg.cRv.V',  100e-6)
483            self.set('Model.Peri.La.V',  100e-6)
484            self.set('Model.Peri.Ra.V',  50e-6)
485
486        # all wall parameters
487        self['Patch2022']['l_se'] = 0.04
488        self['Patch2022']['l_s_ref'] = 2.0
489        self['Patch2022']['l_s0'] = 1.8
490        self['Patch2022']['dl_s_pas'] = 0.6
491        self['Patch2022']['k1'] = 10
492        self['Patch2022']['dt'] = 0
493        self['Patch2022']['C_rest'] = 0
494        self['Patch2022']['l_si0'] = 1.51
495        self['Patch2022']['LDAD'] = 1.057
496        self['Patch2022']['ADO'] = 0.65
497        self['Patch2022']['LDCC'] = 4.
498        self['Patch2022']['v_max'] = 7.
499        self['Patch2022']['v_max'][:2] = 14.
500
501        self['Patch2022']['tr'] = 0.25
502        self['Patch2022']['td'] = 0.25
503        self['Patch2022']['tr'][:2] = 0.4
504        self['Patch2022']['td'][:2] = 0.4
505
506        # wall specific
507        self['Patch2022']['Am_ref'] = [
508            0.00706159,
509            0.00603949,
510            0.0093191 ,
511            0.00507053,
512            0.01313792,
513            ]
514        self['Patch2022']['V_wall'] = [
515            1.86518494e-05,
516            6.12511827e-06,
517            9.51121820e-05,
518            3.74835076e-05,
519            4.97478018e-05,
520            ]
521        self['Patch2022']['Sf_pas'] = np.array([
522            51591.64007141,
523            52277.48834349,
524            22370.46712926,
525            22051.80366169,
526            23278.22158555,
527            ]) * 0.0349
528        self['Patch2022']['Sf_act'] = [84e3, 84e3, 120e3, 120e3, 120e3]
529
530        # Valves
531        self['Valve2022']['adaptation_A_open_fac'] = [
532            1.,
533            1.5,
534            1.,
535            1.,
536            1.5,
537            1.]
538        self['Valve2022']['A_open'] = [
539            0.00050078,
540            0.0007021,
541            0.00046806,
542            0.00051776,
543            0.00074755,
544            0.00049837]
545        self['Valve2022']['A_leak'] = [
546            2.64705882e-04,
547            2.64705882e-10,
548            2.64705882e-10,
549            2.64705882e-04,
550            2.64705882e-10,
551            2.64705882e-10]
552        self['Valve2022']['l'] = 0.01626978
553        self['Valve2022']['rho_b'] = 1050
554        self['Valve2022']['papillary_muscles'] = False
555        self['Valve2022']['papillary_muscles_slope'] = 100
556        self['Valve2022']['papillary_muscles_min'] = 0.1
557        self['Valve2022']['papillary_muscles_A_open_fac'] = 0.1
558        self['Valve2022']['soft_closure'] = True
559
560        self['Bag']['k'] = 10
561        self['Bag']['V_ref'] = 0.0005
562        self['Bag']['p_ref'] = 100
563
564        self.set('Model.Peri.TriSeg.Y', 0.035)
565
566        self['Timings']['law_tauAv'] = 2
567        self['Timings']['c_tauAv0'] = 0.2
568        self['Timings']['c_tauAv1'] = -0.485*60e-3
569
570        # Adaptation
571        self['Patch2022']['adapt_gamma'] = 0.75
572
573        self.run(stable=True)
574
575    def get_unittest_targets(self):
576        """Hardcoded results after initializing and running 1 beat."""
577        return {
578            'LVEDV': 141.6,
579            'LVESV':  69.4,
580            }