def main():
    
    basepath = str(Path(__file__).parent.absolute())
    
    model0d = 'syspul_veins' # syspul, syspul_veins, syspulcap, syspulcapcor_veins
    params_cap = 'var1' # var1, var2
    
    IO_PARAMS         = {'problem_type'          : 'flow0d', # solid, fluid, flow0d, solid_flow0d, fluid_flow0d
                         'write_results_every'   : 1,
                         'output_path'           : ''+basepath+'/tmp/0D/'+model0d+'',
                         'simname'               : 'test1'}

    SOLVER_PARAMS     = {'tol_res'               : 1.0e-6,
                         'tol_inc'               : 1.0e-7}

    TIME_PARAMS       = {'maxtime'               : 2*1.0,
                         'numstep'               : 2*100,
                         #'numstep_stop'          : 100,
                         'timint'                : 'ost', # ost
                         'theta_ost'             : 0.5,
                         'initial_conditions'    : init(model0d),
                         'periodic_checktype'    : 'pQvar'}
    
    MODEL_PARAMS      = {'modeltype'             : model0d,
                         'parameters'            : param(model0d,params_cap),
                         'chamber_models'        : {'lv' : {'type' : '0D_elast', 'activation_curve' : 2}, 'rv' : {'type' : '0D_elast', 'activation_curve' : 2}, 'la' : {'type' : '0D_elast', 'activation_curve' : 1}, 'ra' : {'type' : '0D_elast', 'activation_curve' : 1}}}
    

    # define your time curves here (syntax: tcX refers to curve X)
    class time_curves():
        
        def tc1(self, t): # atrial activation
            
            act_dur = 2.*param(model0d,params_cap)['t_ed']
            t0 = 0.
            
            if t >= t0 and t <= t0 + act_dur:
                return 0.5*(1.-np.cos(2.*np.pi*(t-t0)/act_dur))
            else:
                return 0.0

        def tc2(self, t): # ventricular activation
            
            act_dur = 1.8*(param(model0d,params_cap)['t_es'] - param(model0d,params_cap)['t_ed'])
            t0 = param(model0d,params_cap)['t_ed']
            
            if t >= t0 and t <= t0 + act_dur:
                return 0.5*(1.-np.cos(2.*np.pi*(t-t0)/act_dur))
            else:
                return 0.0


    # problem setup
    problem = ambit.Ambit(IO_PARAMS, TIME_PARAMS, SOLVER_PARAMS, constitutive_params=MODEL_PARAMS, time_curves=time_curves())
    
    # solve time-dependent problem
    problem.solve_problem()
예제 #2
0
def main():
    
    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS         = {'problem_type'          : 'solid',
                         'mesh_domain'           : ''+basepath+'/input/blockshex_domain.xdmf',
                         'mesh_boundary'         : ''+basepath+'/input/blockshex_boundary.xdmf',
                         'fiber_data'            : {'nodal' : [''+basepath+'/input/fib1_blockshex.txt',''+basepath+'/input/fib2_blockshex.txt']},
                         'write_results_every'   : 1,
                         'output_path'           : ''+basepath+'/tmp/',
                         'results_to_write'      : ['displacement','cauchystress','vonmises_cauchystress','pk1stress','pk2stress','glstrain','eastrain','jacobian','fiber1','fiber2'],
                         'simname'               : 'solid_mat_uniax_hex_2field'}

    SOLVER_PARAMS     = {'solve_type'            : 'direct', # direct, iterative
                         'tol_res'               : 1.0e-8,
                         'tol_inc'               : 1.0e-8,
                         'maxiter'               : 25,
                         'divergence_continue'   : None}

    TIME_PARAMS       = {'maxtime'               : 1.0,
                         'numstep'               : 1,
                         'timint'                : 'static'}
    
    FEM_PARAMS        = {'order_disp'            : 2, # hex27 elements
                         'order_pres'            : 1, # hex8 elements
                         'quad_degree'           : 4, # should yield 27 Gauss points
                         'incompressible_2field' : True} # True, False

    MATERIALS         = {'MAT1' : {'neohooke_dev'       : {'mu' : 10.}},
                         'MAT2' : {'mooneyrivlin_dev'   : {'c1' : 2.5, 'c2' : 2.5}},
                         'MAT3' : {'holzapfelogden_dev' : {'a_0' : 0.059, 'b_0' : 8.023, 'a_f' : 18.472, 'b_f' : 16.026, 'a_s' : 2.481, 'b_s' : 11.120, 'a_fs' : 0.216, 'b_fs' : 11.436, 'fiber_comp' : False}}}



    # analytical incompressible P_11 solutions for stretch in 1-direction (= x-direction):
    
    # constraint is lam_1 * lam_2 * lam_3 = 1
    # strain in 1-direction: lam := lam_1 ---> lam_2 = lam_3 = lam_q ---> lam_q = 1 / sqrt(lam)

    # I1 = lam_1^2 + lam_2^2 + lam_3^2 = lam^2 + 2/lam
    # I2 = lam_1^2 * lam_2^2 + lam_1^2 * lam_3^2 + lam_2^2 * lam_3^2 = 2 lam + 1/lam^2

    # NeoHooke
    def P_nh(lam):
        mu = MATERIALS['MAT1']['neohooke_dev']['mu']
        return mu*(lam-1./lam**2.)

    # Mooney Rivlin
    def P_mr(lam):
        c1, c2 = MATERIALS['MAT2']['mooneyrivlin_dev']['c1'], MATERIALS['MAT2']['mooneyrivlin_dev']['c2']
        return 2.*c1*(lam-1./(lam**2.)) + 2.*c2*(1.-1./(lam**3.))

    # Holzapfel-Ogden with fiber f0 in 1-direction, fiber s0 in 2-direction (I8 term cancels!)
    # no fiber compression, so cross-strains are equal (wouldn't be if s0 would constribute in compression!)
    def P_ho(lam):
        a_0, b_0 = MATERIALS['MAT3']['holzapfelogden_dev']['a_0'], MATERIALS['MAT3']['holzapfelogden_dev']['b_0']
        a_f, b_f = MATERIALS['MAT3']['holzapfelogden_dev']['a_f'], MATERIALS['MAT3']['holzapfelogden_dev']['b_f']
        a_s, b_s = MATERIALS['MAT3']['holzapfelogden_dev']['a_s'], MATERIALS['MAT3']['holzapfelogden_dev']['b_s']
        return a_0*(lam-1./lam**2.)*np.exp(b_0*(lam**2. + 2./lam - 3.)) + \
               a_f * 2.*lam*(lam**2.-1)*np.exp(b_f*(lam**2.-1.)**2.)


    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    class time_curves():
        
        def tc1(self, t):
            umax = 1.0
            return umax*t/TIME_PARAMS['maxtime']

        def tc2(self, t):
            umax = 1.0
            return umax*t/TIME_PARAMS['maxtime']
        
        def tc3(self, t):
            umax = 0.1
            return umax*t/TIME_PARAMS['maxtime']
        
        # PK1 stress that yields to a x-displacement of 1.0 for NH material
        def tc4(self, t):
            tmax = 17.5
            return tmax*t/TIME_PARAMS['maxtime']
        
        # PK1 stress that yields to a x-displacement of 1.0 for MR material
        def tc5(self, t):
            tmax = 13.125
            return tmax*t/TIME_PARAMS['maxtime']
        
        # PK1 stress that yields to a x-displacement of 0.1 for HO material
        def tc6(self, t):
            tmax = 17.32206451195601
            return tmax*t/TIME_PARAMS['maxtime']



    BC_DICT           = { 'dirichlet' : [{'id' : [1], 'dir' : 'x', 'val' : 0.},
                                         {'id' : [2], 'dir' : 'y', 'val' : 0.},
                                         {'id' : [3], 'dir' : 'z', 'val' : 0.},
                                         #{'id' : [4], 'dir' : 'x', 'curve' : [1]},
                                         {'id' : [7], 'dir' : 'x', 'val' : 0.},
                                         {'id' : [8], 'dir' : 'y', 'val' : 0.},
                                         {'id' : [9], 'dir' : 'z', 'val' : 0.},
                                         #{'id' : [10], 'dir' : 'x', 'curve' : [2]},
                                         {'id' : [13], 'dir' : 'x', 'val' : 0.},
                                         {'id' : [14], 'dir' : 'y', 'val' : 0.},
                                         {'id' : [15], 'dir' : 'z', 'val' : 0.}],
                                         #{'id' : [16], 'dir' : 'x', 'curve' : [3]}]}
                            'neumann' : [{'type' : 'pk1', 'id' : [4], 'dir' : 'xyz', 'curve' : [4,0,0]},
                                         {'type' : 'pk1', 'id' : [10], 'dir' : 'xyz', 'curve' : [5,0,0]},
                                         {'type' : 'pk1', 'id' : [16], 'dir' : 'xyz', 'curve' : [6,0,0]}] }


    # problem setup
    problem = ambit.Ambit(IO_PARAMS, TIME_PARAMS, SOLVER_PARAMS, FEM_PARAMS, MATERIALS, BC_DICT, time_curves=time_curves())
    
    # solve time-dependent problem
    problem.solve_problem()

    
    # --- results check
    tol = 1.0e-6

    check_node = []
    check_node.append(np.array([1.0, 1.0, 1.0]))
    check_node.append(np.array([1.0, 3.0, 1.0]))
    check_node.append(np.array([1.0, 5.0, 1.0]))

    u_corr = np.zeros(3*len(check_node))
    
    ## correct results
    u_corr[0] = 1.0 # x
    u_corr[1] = -2.9289321881345320E-01 # y
    u_corr[2] = -2.9289321881345320E-01 # z
    
    u_corr[3] = 1.0 # x
    u_corr[4] = -2.9289321881345320E-01 # y
    u_corr[5] = -2.9289321881345320E-01 # z
    
    u_corr[6] = 0.1 # x
    u_corr[7] = -4.6537410754407753E-02 # y
    u_corr[8] = -4.6537410754407753E-02 # z

    check1 = results_check.results_check_node(problem.mp.u, check_node, u_corr, problem.mp.V_u, problem.mp.comm, tol=tol, nm='u')
    success = results_check.success_check([check1], problem.mp.comm)
    
    return success
def main():

    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS = {
        'problem_type':
        'flow0d',  # solid, fluid, flow0d, solid_flow0d, fluid_flow0d
        'write_results_every': -999,
        'output_path': '' + basepath + '/tmp',
        'simname': 'test'
    }

    SOLVER_PARAMS = {'tol_res': 1.0e-8, 'tol_inc': 1.0e-8}

    TIME_PARAMS = {
        'maxtime': 10 * 1.0,
        'numstep': 10 * 100,
        'timint': 'ost',  # ost
        'theta_ost': 0.5,
        'initial_conditions': init(),
        'eps_periodic': 0.03,
        'periodic_checktype': 'pQvar'
    }

    MODEL_PARAMS = {
        'modeltype': 'syspulcap',
        'parameters': param(),
        'chamber_models': {
            'lv': {
                'type': '0D_elast',
                'activation_curve': 2
            },
            'rv': {
                'type': '0D_elast',
                'activation_curve': 2
            },
            'la': {
                'type': '0D_elast',
                'activation_curve': 1
            },
            'ra': {
                'type': '0D_elast',
                'activation_curve': 1
            }
        }
    }

    # define your time curves here (syntax: tcX refers to curve X)
    class time_curves():
        def tc1(self, t):  # atrial activation

            act_dur = 2. * param()['t_ed']
            t0 = 0.

            if t >= t0 and t <= t0 + act_dur:
                return 0.5 * (1. - np.cos(2. * np.pi * (t - t0) / act_dur))
            else:
                return 0.0

        def tc2(self, t):  # ventricular activation

            act_dur = 1.8 * (param()['t_es'] - param()['t_ed'])
            t0 = param()['t_ed']

            if t >= t0 and t <= t0 + act_dur:
                return 0.5 * (1. - np.cos(2. * np.pi * (t - t0) / act_dur))
            else:
                return 0.0

    # problem setup
    problem = ambit.Ambit(IO_PARAMS,
                          TIME_PARAMS,
                          SOLVER_PARAMS,
                          constitutive_params=MODEL_PARAMS,
                          time_curves=time_curves())

    # solve time-dependent problem
    problem.solve_problem()

    # --- results check
    tol = 1.0e-6

    s_corr = np.zeros(problem.mp.cardvasc0D.numdof)

    # correct results
    s_corr[0] = 2.9433926104934122E+04
    s_corr[1] = 7.0386144010472729E-01
    s_corr[2] = 4.2678334743198088E-01
    s_corr[3] = 6.7442751399979128E-01
    s_corr[4] = 7.8447355051941843E+00
    s_corr[5] = 4.6065595569000950E+04
    s_corr[6] = 7.5426962510972304E+00
    s_corr[7] = -1.1478898357265389E+04
    s_corr[8] = -1.0718237002034781E+04
    s_corr[9] = -8.4007390955961782E+03
    s_corr[10] = -5.7419312828933507E+03
    s_corr[11] = -1.9132875426215376E+03
    s_corr[12] = 2.1087309064812008E+00
    s_corr[13] = 1.9898868996888057E+04
    s_corr[14] = 2.0751857916695799E+00
    s_corr[15] = 1.7186285836733463E+04
    s_corr[16] = 2.0732040949606132E+00
    s_corr[17] = 1.3479806604615822E+04
    s_corr[18] = 2.0782222891608901E+00
    s_corr[19] = 9.2042331302840139E+03
    s_corr[20] = 2.0766705496498501E+00
    s_corr[21] = 3.0595541185596117E+03
    s_corr[22] = 1.7839813644519802E+00
    s_corr[23] = -4.6650427627891768E+04
    s_corr[24] = 3.4387975523172128E+04
    s_corr[25] = 5.3317892047428794E-01
    s_corr[26] = 8.9862420216417258E-02
    s_corr[27] = 4.9879094495111614E-01
    s_corr[28] = 1.8877949970498080E+00
    s_corr[29] = 1.2785936834889279E+04
    s_corr[30] = 1.7919004707881436E+00
    s_corr[31] = -8.4133350499779073E+04
    s_corr[32] = 1.6151509560740245E+00
    s_corr[33] = -5.9085660502758556E+03

    check1 = results_check.results_check_vec(problem.mp.s,
                                             s_corr,
                                             problem.mp.comm,
                                             tol=tol)
    success = results_check.success_check([check1], problem.mp.comm)

    return success
예제 #4
0
def main():

    basepath = str(Path(__file__).parent.absolute())

    # all possible input parameters

    IO_PARAMS = {
        'problem_type':
        'solid_flow0d',  # solid, fluid, flow0d, solid_flow0d, fluid_flow0d
        'mesh_domain': '' + basepath + '/input/heart3Dcoarse_domain.xdmf',
        'mesh_boundary': '' + basepath + '/input/heart3Dcoarse_boundary.xdmf',
        'write_results_every': -999,
        'output_path': '' + basepath + '/tmp/',
        'results_to_write':
        ['displacement', 'pressure'],  # see io_routines.py for what to write
        'simname': 'test'
    }  # how to name the output

    SOLVER_PARAMS_SOLID = {
        'solve_type': 'iterative',  # direct, iterative
        'tol_res': 1.0e-8,
        'tol_inc': 1.0e-8,
        'tol_lin': 1.0e-7,
        'print_liniter_every': 50,
        'divergence_continue':
        None,  # what to apply when Newton diverges: None, PTC ('ptc' can stay False)
        'ptc':
        False,  # if you want to use PTC straight away (independent of divergence_continue)
        'k_ptc_initial': 0.1
    }  # initial PTC value that adapts during nonlinear iteration

    SOLVER_PARAMS_FLOW0D = {'tol_res': 1.0e-6, 'tol_inc': 1.0e-6}

    TIME_PARAMS_SOLID = {
        'maxtime': 1.0,
        'numstep': 100,
        'numstep_stop': 1,
        'timint': 'ost',
        'theta_ost': 0.5
    }

    TIME_PARAMS_FLOW0D = {
        'timint': 'ost',
        'theta_ost': 0.5,
        'initial_conditions': init(),  # a dictionary
        'eps_periodic': 1.0e-3,  # cardiac cycle periodicity tolerance
        'periodic_checktype': None
    }  # None, 'allvar', 'pQvar'

    MODEL_PARAMS_FLOW0D = {
        'modeltype': 'syspulcap',
        'parameters': param(),
        'chamber_models': {
            'lv': {
                'type': '3D_solid'
            },
            'rv': {
                'type': '3D_solid'
            },
            'la': {
                'type': '0D_elast',
                'activation_curve': 1
            },
            'ra': {
                'type': '0D_elast',
                'activation_curve': 1
            }
        }
    }

    FEM_PARAMS = {
        'order_disp':
        2,  # order of displacement interpolation (solid mechanics)
        'order_pres':
        1,  # order of pressure interpolation (solid, fluid mechanics)
        'quad_degree': 5,  # quadrature degree
        'incompressible_2field': True
    }  # if we want to use a 2-field functional for pressure dofs (always applies for fluid mechanics, optional for solid)

    COUPLING_PARAMS = {
        'surface_ids': [
            [1], [2]
        ],  # for syspul* models: order is lv, rv, la, ra (has to be consistent with chamber_models dict)
        'surface_p_ids': [[1], [2]],
        'coupling_quantity': [
            'flux', 'flux'
        ],  # volume, flux, pressure (former need 'monolithic_direct', latter needs 'monolithic_lagrange' as coupling_type)
        'coupling_type': 'monolithic_direct'
    }  # monolithic_direct, monolithic_lagrange

    # see solid_material.py or fluid_material.py for material laws available (and their parameters)
    MATERIALS = {
        'MAT1': {
            'neohooke_dev': {
                'mu': 10.
            },
            'inertia': {
                'rho0': 1.0e-6
            },
            'rayleigh_damping': {
                'eta_m': 0.0,
                'eta_k': 0.0001
            }
        }
    }

    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    # some examples... up to 9 possible (tc1 until tc9 - feel free to implement more in timeintegration.py --> timecurves function if needed...)
    class time_curves():
        def tc1(self, t):  # atrial activation

            act_dur = 2. * param()['t_ed']
            t0 = 0.

            if t >= t0 and t <= t0 + act_dur:
                return 0.5 * (1. - np.cos(2. * np.pi * (t - t0) / act_dur))
            else:
                return 0.0

    BC_DICT = {
        'robin': [{
            'type': 'spring',
            'id': [3],
            'dir': 'normal',
            'stiff': 0.075
        }, {
            'type': 'dashpot',
            'id': [3],
            'dir': 'normal',
            'visc': 0.005
        }, {
            'type': 'spring',
            'id': [4],
            'dir': 'normal',
            'stiff': 2.5
        }, {
            'type': 'dashpot',
            'id': [4],
            'dir': 'normal',
            'visc': 0.0005
        }, {
            'type': 'spring',
            'id': [4],
            'dir': 'xyz',
            'stiff': 0.25
        }, {
            'type': 'dashpot',
            'id': [4],
            'dir': 'xyz',
            'visc': 0.0005
        }]
    }

    # problem setup
    problem = ambit.Ambit(IO_PARAMS, [TIME_PARAMS_SOLID, TIME_PARAMS_FLOW0D],
                          [SOLVER_PARAMS_SOLID, SOLVER_PARAMS_FLOW0D],
                          FEM_PARAMS, [MATERIALS, MODEL_PARAMS_FLOW0D],
                          BC_DICT,
                          time_curves=time_curves(),
                          coupling_params=COUPLING_PARAMS)

    # problem solve
    problem.solve_problem()

    # --- results check
    tol = 1.0e-6

    s_corr = np.zeros(problem.mp.pbf.cardvasc0D.numdof)

    # correct 0D results
    s_corr[0] = 1.5095864743040130E+06
    s_corr[1] = 1.2844204058649662E+00
    s_corr[2] = -2.2965082274795714E+00
    s_corr[3] = -2.2516606843904677E-01
    s_corr[4] = 1.2035047944220826E+01
    s_corr[5] = 7.9266376779754364E+03
    s_corr[6] = 1.0920576465746846E+01
    s_corr[7] = 4.8757248185773104E+04
    s_corr[8] = 4.5874998121783552E+04
    s_corr[9] = 3.5972406593836102E+04
    s_corr[10] = 2.4558826877860327E+04
    s_corr[11] = 8.1860969826562832E+03
    s_corr[12] = 2.2677989771675335E+00
    s_corr[13] = 8.3769499009227275E+02
    s_corr[14] = 2.2702566758390823E+00
    s_corr[15] = 9.5189334925959599E+02
    s_corr[16] = 2.2702868360248418E+00
    s_corr[17] = 7.5312458499319700E+02
    s_corr[18] = 2.2701207039868367E+00
    s_corr[19] = 5.0027868673701960E+02
    s_corr[20] = 2.2705227157170751E+00
    s_corr[21] = 1.7138025576859900E+02
    s_corr[22] = 2.2541277949292278E+00
    s_corr[23] = 2.0733856020336604E+05
    s_corr[24] = 9.9000307744360238E+04
    s_corr[25] = 2.7306345247149444E-01
    s_corr[26] = -4.3686268354670260E-01
    s_corr[27] = 1.7406314472713416E-01
    s_corr[28] = 2.4017163277669913E+00
    s_corr[29] = 1.1803816043509409E+04
    s_corr[30] = 2.3131877074406706E+00
    s_corr[31] = 2.0066530960234333E+05
    s_corr[32] = 1.6159475288856615E+00
    s_corr[33] = 3.9878128320907672E+04

    check1 = results_check.results_check_vec(problem.mp.pbf.s,
                                             s_corr,
                                             problem.mp.comm,
                                             tol=tol)
    success = results_check.success_check([check1], problem.mp.comm)

    return success
예제 #5
0
def main():

    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS = {
        'problem_type':
        'solid',  # solid, fluid, flow0d, solid_flow0d, fluid_flow0d
        'mesh_domain': '' + basepath + '/input/heart2D_domain.xdmf',
        'mesh_boundary': '' + basepath + '/input/heart2D_boundary.xdmf',
        'fiber_data': {
            'nodal': ['' + basepath + '/input/fib_fiber_coords_nodal_2D.txt']
        },
        'write_results_every': -999,
        'output_path': '' + basepath + '/tmp/',
        'results_to_write': ['displacement', 'pressure', 'fiberstretch'],
        'simname': 'solid_2Dheart_frankstarling'
    }

    SOLVER_PARAMS_SOLID = {
        'solve_type': 'direct',  # direct, iterative
        'tol_res': 1.0e-8,
        'tol_inc': 1.0e-8,
        'ptc': False
    }

    TIME_PARAMS_SOLID = {
        'maxtime': 1.0,
        'numstep': 10,
        'numstep_stop': 5,
        'timint': 'genalpha',
        'theta_ost': 1.0,
        'rho_inf_genalpha': 0.8
    }

    FEM_PARAMS = {
        'order_disp': 2,
        'order_pres': 1,
        'quad_degree': 5,
        'incompressible_2field': True
    }

    MATERIALS = {
        'MAT1': {
            'mooneyrivlin_dev': {
                'c1': 60.,
                'c2': -20.
            },
            'active_fiber': {
                'sigma0': 100.0,
                'alpha_max': 15.0,
                'alpha_min': -20.0,
                'activation_curve': 3,
                'frankstarling': True,
                'amp_min': 1.,
                'amp_max': 1.7,
                'lam_threslo': 1.01,
                'lam_maxlo': 1.15,
                'lam_threshi': 999.,
                'lam_maxhi': 9999.
            },
            'inertia': {
                'rho0': 1.0e-5
            },
            'rayleigh_damping': {
                'eta_m': 0.001,
                'eta_k': 0.0001
            }
        }
    }

    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    class time_curves():
        def tc1(self, t):
            pmax = -16.
            if t <= 0.2:
                return pmax * t / 0.2
            else:
                return pmax

        def tc2(self, t):
            pmax = -4.
            if t <= 0.2:
                return pmax * t / 0.2
            else:
                return pmax

        def tc3(self, t):

            K = 5.
            t_contr, t_relax = 0.2, 1000.

            alpha_max = MATERIALS['MAT1']['active_fiber']['alpha_max']
            alpha_min = MATERIALS['MAT1']['active_fiber']['alpha_min']

            c1 = t_contr + alpha_max / (K * (alpha_max - alpha_min))
            c2 = t_relax - alpha_max / (K * (alpha_max - alpha_min))

            # Diss Hirschvogel eq. 2.101
            return (K * (t - c1) + 1.) * (
                (K * (t - c1) + 1.) > 0.) - K * (t - c1) * (
                    (K * (t - c1)) > 0.) - K * (t - c2) * (
                        (K * (t - c2)) > 0.) + (K * (t - c2) - 1.) * (
                            (K * (t - c2) - 1.) > 0.)

    BC_DICT = {
        'dirichlet': [{
            'dir': '2dimZ',
            'val': 0.
        }],
        'neumann': [{
            'type': 'true',
            'id': [1],
            'dir': 'normal',
            'curve': 1
        }, {
            'type': 'true',
            'id': [2],
            'dir': 'normal',
            'curve': 2
        }],
        'robin': [{
            'type': 'spring',
            'id': [3],
            'dir': 'normal',
            'stiff': 0.075
        }]
    }

    # problem setup
    problem = ambit.Ambit(IO_PARAMS,
                          TIME_PARAMS_SOLID,
                          SOLVER_PARAMS_SOLID,
                          FEM_PARAMS,
                          MATERIALS,
                          BC_DICT,
                          time_curves=time_curves())

    # solve time-dependent problem
    problem.solve_problem()

    # --- results check
    tol = 1.0e-6

    check_node = []
    check_node.append(
        np.array(
            [-21.089852094479845, -26.26308841783208, 9.227760327944651e-16]))

    u_corr = np.zeros(3 * len(check_node))

    ## correct results
    u_corr[0] = 4.9439615617476127E+00  # x
    u_corr[1] = 2.4846265243158223E+00  # y
    u_corr[2] = 0.0  # z

    check1 = results_check.results_check_node(problem.mp.u,
                                              check_node,
                                              u_corr,
                                              problem.mp.V_u,
                                              problem.mp.comm,
                                              tol=tol,
                                              nm='u')
    success = results_check.success_check([check1], problem.mp.comm)

    return success
예제 #6
0
def main():

    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS = {
        'problem_type':
        'solid_flow0d',  # solid, fluid, flow0d, solid_flow0d, fluid_flow0d
        'mesh_domain': '' + basepath + '/input/chamber_domain.xdmf',
        'mesh_boundary': '' + basepath + '/input/chamber_boundary.xdmf',
        'write_results_every': -999,
        'output_path': '' + basepath + '/tmp/',
        'results_to_write': [''],
        'simname': 'test'
    }

    SOLVER_PARAMS_SOLID = {
        'solve_type': 'direct',  # direct, iterative
        'tol_res': 1.0e-8,
        'tol_inc': 1.0e-8
    }

    SOLVER_PARAMS_FLOW0D = {'tol_res': 1.0e-8, 'tol_inc': 1.0e-8}

    TIME_PARAMS_SOLID = {
        'maxtime': 1.0,
        'numstep': 20,
        'numstep_stop': 10,
        'timint': 'genalpha',  # genalpha, ost, static
        'theta_ost': 1.0,
        'rho_inf_genalpha': 0.8
    }

    TIME_PARAMS_FLOW0D = {
        'timint': 'ost',  # ost
        'theta_ost': 0.5,
        'initial_conditions': {
            'p_0': 0.0,
            'q_0': 0.0,
            's_0': 0.0
        }
    }

    MODEL_PARAMS_FLOW0D = {
        'modeltype': '4elwindkesselLsZ',
        'parameters': {
            'R': 1.0e3,
            'C': 0.0,
            'Z': 10.0,
            'L': 5.0,
            'p_ref': 0.0
        }
    }

    FEM_PARAMS = {
        'order_disp': 1,
        'order_pres': 1,
        'quad_degree': 1,
        'incompressible_2field': False
    }  # True, False

    COUPLING_PARAMS = {
        'surface_ids': [[3]],
        'coupling_quantity': 'volume',
        'coupling_type': 'monolithic_direct'
    }

    MATERIALS = {
        'MAT1': {
            'neohooke_dev': {
                'mu': 100.
            },
            'ogden_vol': {
                'kappa': 100. / (1. - 2. * 0.49)
            },
            'inertia': {
                'rho0': 1.0e-6
            }
        }
    }

    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    class time_curves():
        def tc1(self, t):
            pmax = -10.
            return pmax * t / TIME_PARAMS_SOLID['maxtime']

    BC_DICT = {
        'dirichlet': [{
            'id': [1],
            'dir': 'x',
            'val': 0.
        }, {
            'id': [3],
            'dir': 'y',
            'val': 0.
        }, {
            'id': [3],
            'dir': 'z',
            'val': 0.
        }],
        'neumann': [{
            'type': 'true',
            'id': [2],
            'dir': 'normal',
            'curve': 1
        }]
    }

    # problem setup
    problem = ambit.Ambit(IO_PARAMS, [TIME_PARAMS_SOLID, TIME_PARAMS_FLOW0D],
                          [SOLVER_PARAMS_SOLID, SOLVER_PARAMS_FLOW0D],
                          FEM_PARAMS, [MATERIALS, MODEL_PARAMS_FLOW0D],
                          BC_DICT,
                          time_curves=time_curves(),
                          coupling_params=COUPLING_PARAMS)

    # solve time-dependent problem
    problem.solve_problem()

    # --- results check
    tol = 1.0e-7

    s_corr = np.zeros(problem.mp.pbf.cardvasc0D.numdof)

    # correct 0D results
    s_corr[0] = 9.2733644380642666E+00
    s_corr[1] = -9.1004836216937203E-03
    s_corr[2] = -1.6375196030721982E-02

    check1 = results_check.results_check_vec(problem.mp.pbf.s,
                                             s_corr,
                                             problem.mp.comm,
                                             tol=tol)
    success = results_check.success_check([check1], problem.mp.comm)

    return success
def main():

    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS = {
        'problem_type':
        'flow0d',  # solid, fluid, flow0d, solid_flow0d, fluid_flow0d
        'write_results_every': -999,
        'output_path': '' + basepath + '/tmp/',
        'simname': 'test'
    }

    SOLVER_PARAMS = {
        'solve_type': 'direct',  # direct
        'tol_res': 1.0e-8,
        'tol_inc': 1.0e-8
    }

    TIME_PARAMS = {
        'maxtime': 1.0,
        'numstep': 100,
        'numstep_stop': 100,
        'timint': 'ost',  # ost
        'theta_ost': 0.5,
        'initial_conditions': init()
    }

    MODEL_PARAMS = {
        'modeltype': '4elwindkesselLsZ',
        'parameters': param(),
        'excitation_curve': 1
    }

    # define your time curves here (syntax: tcX refers to curve X)
    class time_curves():
        def tc1(self, t):
            return 0.5 * (1. - np.cos(2. * np.pi * (t) / 0.1)) + 1.0

    # problem setup
    problem = ambit.Ambit(IO_PARAMS,
                          TIME_PARAMS,
                          SOLVER_PARAMS,
                          constitutive_params=MODEL_PARAMS,
                          time_curves=time_curves())

    # solve time-dependent problem
    problem.solve_problem()

    # --- results check
    tol = 1.0e-7

    s_corr = np.zeros(problem.mp.cardvasc0D.numdof)

    # correct results
    s_corr[0] = 1.0608252198133588E+00
    s_corr[1] = 0.0
    s_corr[2] = 0.0

    check1 = results_check.results_check_vec(problem.mp.s,
                                             s_corr,
                                             problem.mp.comm,
                                             tol=tol)
    success = results_check.success_check([check1], problem.mp.comm)

    return success
def main():

    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS = {
        'problem_type': 'solid',
        'mesh_domain': '' + basepath + '/input/lv_domain.xdmf',
        'mesh_boundary': '' + basepath + '/input/lv_boundary.xdmf',
        'write_results_every': -999,
        'output_path': '' + basepath + '/tmp/',
        'results_to_write': ['displacement', 'theta'],
        'simname': 'solid_growth_prescribed_iso_lv'
    }

    FEM_PARAMS = {
        'order_disp': 1,
        'order_pres': 1,
        'quad_degree': 1,
        'incompressible_2field': True
    }

    SOLVER_PARAMS_SOLID = {
        'solve_type': 'direct',  # direct, iterative
        'tol_res': 1.0e-8,
        'tol_inc': 1.0e-8
    }

    TIME_PARAMS_SOLID = {'maxtime': 1.0, 'numstep': 10, 'timint': 'static'}

    MATERIALS = {
        'MAT1': {
            'neohooke_dev': {
                'mu': 100.
            },
            'growth': {
                'growth_dir': 'isotropic',
                'growth_trig': 'prescribed',
                'prescribed_curve': 1
            }
        }
    }

    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    class time_curves():
        def tc1(self, t):
            thetamax = 2.0
            gr = thetamax - 1.
            return 1.0 + gr * t / TIME_PARAMS_SOLID['maxtime']

    BC_DICT = {'dirichlet': [{'id': [2], 'dir': 'all', 'val': 0.}]}

    # problem setup
    problem = ambit.Ambit(IO_PARAMS,
                          TIME_PARAMS_SOLID,
                          SOLVER_PARAMS_SOLID,
                          FEM_PARAMS,
                          MATERIALS,
                          BC_DICT,
                          time_curves=time_curves())

    # solve time-dependent problem
    problem.solve_problem()

    # --- results check
    tol = 1.0e-6

    check_node = []
    check_node.append(
        np.array([3.475149154663086, -3.17646312713623, -74.3183364868164]))

    u_corr, p_corr = np.zeros(3 * len(check_node)), np.zeros(len(check_node))

    ## correct results (apex node)
    u_corr[0] = -9.3743445617845182E+00  # x
    u_corr[1] = 1.0877463102123736E+01  # y
    u_corr[2] = -1.0954897338860498E+02  # z

    p_corr[0] = -9.3006817518134621E+00

    check1 = results_check.results_check_node(problem.mp.u,
                                              check_node,
                                              u_corr,
                                              problem.mp.V_u,
                                              problem.mp.comm,
                                              tol=tol,
                                              nm='u')
    check2 = results_check.results_check_node(problem.mp.p,
                                              check_node,
                                              p_corr,
                                              problem.mp.V_p,
                                              problem.mp.comm,
                                              tol=tol,
                                              nm='p')

    success = results_check.success_check([check1, check2], problem.mp.comm)

    return success
예제 #9
0
def main():

    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS = {
        'problem_type':
        'solid',
        'mesh_domain':
        '' + basepath + '/input/block_domain.xdmf',
        'mesh_boundary':
        '' + basepath + '/input/block_boundary.xdmf',
        'write_results_every':
        -999,
        'output_path':
        '' + basepath + '/tmp/',
        'results_to_write': [
            'displacement', 'pressure', 'theta', 'trmandelstress',
            'trmandelstress_e'
        ],
        'simname':
        'test_solid_growth_volstressmandel'
    }

    SOLVER_PARAMS = {
        'solve_type': 'direct',
        'tol_res': 1.0e-8,
        'tol_inc': 1.0e-8
    }

    TIME_PARAMS = {'maxtime': 1.0, 'numstep': 5, 'timint': 'static'}

    FEM_PARAMS = {
        'order_disp': 1,
        'quad_degree': 1,
        'incompressible_2field': False
    }

    MATERIALS = {
        'MAT1': {
            'neohooke_dev': {
                'mu': 10.
            },
            'ogden_vol': {
                'kappa': 10. / (1. - 2. * 0.49)
            },
            'growth': {
                'growth_dir':
                'isotropic',  # isotropic, fiber, crossfiber, radial
                'growth_trig':
                'volstress',  # fibstretch, volstress, prescribed
                'growth_thres': -25.0,
                'thetamax': 3.0,
                'thetamin': 1.0,
                'tau_gr': 20.0,
                'gamma_gr': 2.0,
                'tau_gr_rev': 10000.0,
                'gamma_gr_rev': 2.0
            }
        }
    }

    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    class time_curves():
        def tc1(self, t):
            pmax = -10.
            return pmax * t / TIME_PARAMS['maxtime']

    BC_DICT = {
        'dirichlet': [{
            'id': [1],
            'dir': 'x',
            'val': 0.
        }, {
            'id': [2],
            'dir': 'y',
            'val': 0.
        }, {
            'id': [3],
            'dir': 'z',
            'val': 0.
        }],
        # hydrostatic Neumann on all faces
        'neumann': [{
            'type': 'true',
            'id': [1, 2, 3, 4, 5, 6],
            'dir': 'normal',
            'curve': 1
        }]
    }

    # problem setup
    problem = ambit.Ambit(IO_PARAMS,
                          TIME_PARAMS,
                          SOLVER_PARAMS,
                          FEM_PARAMS,
                          MATERIALS,
                          BC_DICT,
                          time_curves=time_curves())

    # solve time-dependent problem
    problem.solve_problem()

    # --- results check
    tol = 1.0e-6

    check_node = []
    check_node.append(
        np.array([1.00000000e+00, 1.00000000e+00, 1.00000000e+00]))

    u_corr = np.zeros(3 * len(check_node))

    ## correct results
    u_corr[0] = 1.7091249480527462E-01  # x
    u_corr[1] = 1.7091249480527512E-01  # y
    u_corr[2] = 1.7091249480527512E-01  # z

    check1 = results_check.results_check_node(problem.mp.u,
                                              check_node,
                                              u_corr,
                                              problem.mp.V_u,
                                              problem.mp.comm,
                                              tol=tol,
                                              nm='u')
    success = results_check.success_check([check1], problem.mp.comm)

    return success
def main():
    
    basepath = str(Path(__file__).parent.absolute())

    # reads in restart step from the command line
    try: restart_step = int(sys.argv[1])
    except: restart_step = 0

    IO_PARAMS            = {'problem_type'          : 'solid_flow0d', # solid, fluid, flow0d, solid_flow0d, fluid_flow0d
                            'mesh_domain'           : ''+basepath+'/input/heart2D_domain.xdmf',
                            'mesh_boundary'         : ''+basepath+'/input/heart2D_boundary.xdmf',
                            'fiber_data'            : {'nodal' : [''+basepath+'/input/fib_fiber_coords_nodal_2D.txt',''+basepath+'/input/fib_sheet_coords_nodal_2D.txt']},
                            'write_results_every'   : 1,
                            'output_path'           : ''+basepath+'/tmp/',
                            'results_to_write'      : ['displacement'],
                            'simname'               : 'solid_flow0d_2Dheart',
                            'write_restart_every'   : 1,
                            'restart_step'          : restart_step}

    SOLVER_PARAMS_SOLID  = {'solve_type'            : 'direct', # direct, iterative
                            'tol_res'               : 1.0e-8,
                            'tol_inc'               : 1.0e-8}
    
    SOLVER_PARAMS_FLOW0D = {'tol_res'               : 1.0e-6,
                            'tol_inc'               : 1.0e-6}

    TIME_PARAMS_SOLID    = {'maxtime'               : 1.0,
                            'numstep'               : 500,
                            'numstep_stop'          : 5,
                            'timint'                : 'genalpha', # genalpha, ost, static
                            'theta_ost'             : 1.0,
                            'rho_inf_genalpha'      : 0.8}
    
    TIME_PARAMS_FLOW0D   = {'timint'                : 'ost', # ost
                            'theta_ost'             : 0.5,
                            'initial_conditions'    : init()}

    MODEL_PARAMS_FLOW0D  = {'modeltype'             : 'syspul',
                            'parameters'            : param(),
                            'chamber_models'        : {'lv' : {'type' : '3D_fem', 'interfaces' : 1}, 'rv' : {'type' : '3D_fem', 'interfaces' : 1}, 'la' : {'type' : '0D_elast', 'activation_curve' : 2}, 'ra' : {'type' : '0D_elast', 'activation_curve' : 2}}}

    FEM_PARAMS           = {'order_disp'            : 1,
                            'order_pres'            : 1,
                            'quad_degree'           : 1,
                            'incompressible_2field' : False,
                            'prestress_initial'     : True}
    
    COUPLING_PARAMS      = {'surface_ids'           : [[1],[2]],
                            'cq_factor'             : [80.,80.],
                            'coupling_quantity'     : 'volume',
                            'coupling_type'         : 'monolithic_direct'}

    MATERIALS            = {'MAT1' : {'holzapfelogden_dev'    : {'a_0' : 0.059, 'b_0' : 8.023, 'a_f' : 18.472, 'b_f' : 16.026, 'a_s' : 2.481, 'b_s' : 11.120, 'a_fs' : 0.216, 'b_fs' : 11.436},
                                      'sussmanbathe_vol'      : {'kappa' : 1.0e3},
                                      'active_fiber'          : {'sigma0' : 50.0, 'alpha_max' : 15.0, 'alpha_min' : -20.0, 'activation_curve' : 1},
                                      'inertia'               : {'rho0' : 1.0e-6}}}



    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    class time_curves():
        
        def tc1(self, t):
            
            K = 5.
            t_contr, t_relax = 0.0, 0.53
            
            alpha_max = MATERIALS['MAT1']['active_fiber']['alpha_max']
            alpha_min = MATERIALS['MAT1']['active_fiber']['alpha_min']
            
            c1 = t_contr + alpha_max/(K*(alpha_max-alpha_min))
            c2 = t_relax - alpha_max/(K*(alpha_max-alpha_min))
            
            # Diss Hirschvogel eq. 2.101
            return (K*(t-c1)+1.)*((K*(t-c1)+1.)>0.) - K*(t-c1)*((K*(t-c1))>0.) - K*(t-c2)*((K*(t-c2))>0.) + (K*(t-c2)-1.)*((K*(t-c2)-1.)>0.)

        def tc2(self, t): # atrial activation
            
            act_dur = 2.*param()['t_ed']
            t0 = 0.
            
            if t >= t0 and t <= t0 + act_dur:
                return 0.5*(1.-np.cos(2.*np.pi*(t-t0)/act_dur))
            else:
                return 0.0


    BC_DICT              = { 'dirichlet' : [{'dir' : '2dimZ', 'val' : 0.}],
                            'robin' : [{'type' : 'spring', 'id' : [3], 'dir' : 'normal', 'stiff' : 0.075},
                                       {'type' : 'dashpot', 'id' : [3], 'dir' : 'normal', 'visc' : 0.005}] }

    # problem setup
    problem = ambit.Ambit(IO_PARAMS, [TIME_PARAMS_SOLID, TIME_PARAMS_FLOW0D], [SOLVER_PARAMS_SOLID, SOLVER_PARAMS_FLOW0D], FEM_PARAMS, [MATERIALS, MODEL_PARAMS_FLOW0D], BC_DICT, time_curves=time_curves(), coupling_params=COUPLING_PARAMS)
    
    # solve time-dependent problem
    problem.solve_problem()


    # --- results check
    tol = 1.0e-6
        
    s_corr = np.zeros(problem.mp.pbf.cardvasc0D.numdof)

    # correct 0D results
    s_corr[0]    = -2.0114350666760171E-02
    s_corr[1]    = 3.9868184096752618E-01
    s_corr[2]    = -1.0274818383992834E+00
    s_corr[3]    = 5.9982534828086920E-01
    s_corr[4]    = 1.0874643732273704E+01
    s_corr[5]    = 7.1802465982943570E+04
    s_corr[6]    = 2.2872622295989982E+00
    s_corr[7]    = 8.4716159930435591E+04
    s_corr[8]    = -1.2619948195877369E-02
    s_corr[9]    = 2.5407439126854764E-01
    s_corr[10]    = -1.8318777040206888E-01
    s_corr[11]    = 3.8027387249972561E-01
    s_corr[12]    = 2.2121515765204145E+00
    s_corr[13]    = 3.5710868582746974E+04
    s_corr[14]    = 1.6764885477792106E+00
    s_corr[15]    = 8.5187113787445720E+04

    check1 = results_check.results_check_vec(problem.mp.pbf.s, s_corr, problem.mp.comm, tol=tol)
    success = results_check.success_check([check1], problem.mp.comm)
    
    return success
def main():

    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS = {
        'problem_type':
        'solid_flow0d_multiscale_gandr',
        'mesh_domain':
        '' + basepath + '/input/heart3Dcoarse_domain.xdmf',
        'mesh_boundary':
        '' + basepath + '/input/heart3Dcoarse_boundary.xdmf',
        'fiber_data': {
            'nodal': [
                '' + basepath + '/input/fib_fiber_coords_nodal_3Dcoarse.txt',
                '' + basepath + '/input/fib_sheet_coords_nodal_3Dcoarse.txt'
            ]
        },
        'write_results_every':
        1,
        'output_path':
        '' + basepath + '/tmp',
        'results_to_write':
        ['displacement', 'theta', 'phi_remod', 'trmandelstress_e'],
        'simname':
        'multiscale_concentric_as'
    }

    SOLVER_PARAMS_SOLID = {
        'solve_type': 'direct',  # direct, iterative
        'tol_res': 1.0e-8,
        'tol_inc': 1.0e-8,
        'divergence_continue': 'PTC',
        'k_ptc_initial': 10.0,
        'print_local_iter': False,
        'tol_res_local': 1.0e-10,
        'tol_inc_local': 1.0e-10
    }

    SOLVER_PARAMS_FLOW0D = {'tol_res': 1.0e-6, 'tol_inc': 1.0e-6}

    TIME_PARAMS_SOLID_SMALL = {
        'maxtime': 1.0 * 100,
        'numstep': 50 * 100,
        'timint': 'genalpha',
        'theta_ost': 1.0,
        'rho_inf_genalpha': 0.8
    }

    TIME_PARAMS_SOLID_LARGE = {
        'maxtime': 2592000.0,  # 1 month: 30*24*60*60 s
        'numstep': 1000,
        'timint': 'static'
    }

    TIME_PARAMS_FLOW0D = {
        'timint': 'ost',  # ost
        'theta_ost': 0.5,
        'eps_periodic': 999,
        'periodic_checktype': 'pQvar',
        'initial_file':
        '' + basepath + '/input/initial_syspulcap_multiscale.txt'
    }

    MODEL_PARAMS_FLOW0D = {
        'modeltype': 'syspulcap',
        'parameters': param(),
        'chamber_models': {
            'lv': {
                'type': '3D_fem',
                'interfaces': 1
            },
            'rv': {
                'type': '3D_fem',
                'interfaces': 1
            },
            'la': {
                'type': '0D_elast',
                'activation_curve': 2
            },
            'ra': {
                'type': '0D_elast',
                'activation_curve': 2
            }
        },
        'perturb_type': ['as', 50.],
        'perturb_after_cylce': 1
    }

    FEM_PARAMS = {
        'order_disp': 1,
        'order_pres': 1,
        'quad_degree': 1,
        'incompressible_2field': False,
        'prestress_initial': True,
        'lin_remodeling_full': False
    }

    COUPLING_PARAMS = {
        'surface_ids': [[1], [2]],
        'coupling_quantity': 'volume',
        'coupling_type': 'monolithic_direct'
    }

    MULTISCALE_GR_PARAMS = {
        'gandr_trigger_phase': 'end_systole',  # end_diastole, end_systole
        'numcycles': 10,
        'tol_small':
        0.08,  # cycle error tolerance: overrides eps_periodic from TIME_PARAMS_FLOW0D
        'tol_large': 5.0e-3,  # growth rate tolerance [mm^3/s]
        'tol_outer': 3.0e-3,
        'write_checkpoints': True,
        'restart_cycle': 0,
        'restart_from_small': False
    }

    MATERIALS = {
        'MAT1': {
            'guccione_dev': {
                'c_0': 1.662,
                'b_f': 14.31,
                'b_t': 4.49,
                'b_fs': 10.
            },
            'sussmanbathe_vol': {
                'kappa': 1.0e3
            },
            'active_fiber': {
                'sigma0': 150.,
                'alpha_max': 10.0,
                'alpha_min': -30.0,
                'activation_curve': 1,
                'frankstarling': True,
                'amp_min': 1.,
                'amp_max': 1.5,
                'lam_threslo': 1.01,
                'lam_maxlo': 1.15,
                'lam_threshi': 999.,
                'lam_maxhi': 9999.
            },
            'inertia': {
                'rho0': 1.0e-6
            },
            'growth': {
                'growth_dir': 'crossfiber',
                'growth_trig': 'volstress',
                'trigger_reduction': 0.99,
                'growth_thres': 1.05,
                'thres_tol': 1.0e-3,
                'thetamax': 3.0,
                'thetamin': 1.0,
                'tau_gr': 32.0e4,
                'gamma_gr': 2.0,
                'tau_gr_rev': 64.0e4,
                'gamma_gr_rev': 2.0,
                'remodeling_mat': {
                    'guccione_dev': {
                        'c_0': 10 * 1.662,
                        'b_f': 14.31,
                        'b_t': 4.49,
                        'b_fs': 10.
                    },
                    'sussmanbathe_vol': {
                        'kappa': 1.0e3
                    },
                    'active_fiber': {
                        'sigma0': 150.,
                        'alpha_max': 10.0,
                        'alpha_min': -30.0,
                        'activation_curve': 1,
                        'frankstarling': True,
                        'amp_min': 1.,
                        'amp_max': 1.5,
                        'lam_threslo': 1.01,
                        'lam_maxlo': 1.15,
                        'lam_threshi': 999.,
                        'lam_maxhi': 9999.
                    }
                }
            }
        }
    }

    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    class time_curves():
        def tc1(self, t):

            K = 5.
            t_contr, t_relax = 0.2, 0.53

            alpha_max = MATERIALS['MAT1']['active_fiber']['alpha_max']
            alpha_min = MATERIALS['MAT1']['active_fiber']['alpha_min']

            c1 = t_contr + alpha_max / (K * (alpha_max - alpha_min))
            c2 = t_relax - alpha_max / (K * (alpha_max - alpha_min))

            # Diss Hirschvogel eq. 2.101
            return (K * (t - c1) + 1.) * (
                (K * (t - c1) + 1.) > 0.) - K * (t - c1) * (
                    (K * (t - c1)) > 0.) - K * (t - c2) * (
                        (K * (t - c2)) > 0.) + (K * (t - c2) - 1.) * (
                            (K * (t - c2) - 1.) > 0.)

        def tc2(self, t):  # atrial activation

            act_dur = 2. * param()['t_ed']
            t0 = 0.

            if t >= t0 and t <= t0 + act_dur:
                return 0.5 * (1. - np.cos(2. * np.pi * (t - t0) / act_dur))
            else:
                return 0.0

    BC_DICT = {
        'robin': [
            {
                'type': 'spring',
                'id': [3],
                'dir': 'normal',
                'stiff': 0.075
            },
            {
                'type': 'dashpot',
                'id': [3],
                'dir': 'normal',
                'visc': 0.005
            },
            {
                'type': 'spring',
                'id': [4],
                'dir': 'normal',
                'stiff': 10.0
            },  # 2.5, 1.25
            {
                'type': 'dashpot',
                'id': [4],
                'dir': 'normal',
                'visc': 0.0005
            },
            {
                'type': 'spring',
                'id': [4],
                'dir': 'xyz',
                'stiff': 0.25
            },
            {
                'type': 'dashpot',
                'id': [4],
                'dir': 'xyz',
                'visc': 0.0005
            }
        ]
    }

    # problem setup
    problem = ambit.Ambit(
        IO_PARAMS,
        [TIME_PARAMS_SOLID_SMALL, TIME_PARAMS_SOLID_LARGE, TIME_PARAMS_FLOW0D],
        [SOLVER_PARAMS_SOLID, SOLVER_PARAMS_FLOW0D],
        FEM_PARAMS, [MATERIALS, MODEL_PARAMS_FLOW0D],
        BC_DICT,
        time_curves=time_curves(),
        coupling_params=COUPLING_PARAMS,
        multiscale_params=MULTISCALE_GR_PARAMS)

    # solve time-dependent problem
    problem.solve_problem()

    # --- results check
    tol = 1.0e-6

    s_corr = np.zeros(problem.mp.pbf.cardvasc0D.numdof)

    # correct 0D results
    s_corr[0] = 1.5095864743040130E+06
    s_corr[1] = 1.2844204058649662E+00
    s_corr[2] = -2.2965082274795714E+00
    s_corr[3] = -2.2516606843904677E-01
    s_corr[4] = 1.2035047944220826E+01
    s_corr[5] = 7.9266376779754364E+03
    s_corr[6] = 1.0920576465746846E+01
    s_corr[7] = 4.8757248185773104E+04
    s_corr[8] = 4.5874998121783552E+04
    s_corr[9] = 3.5972406593836102E+04
    s_corr[10] = 2.4558826877860327E+04
    s_corr[11] = 8.1860969826562832E+03
    s_corr[12] = 2.2677989771675335E+00
    s_corr[13] = 8.3769499009227275E+02
    s_corr[14] = 2.2702566758390823E+00
    s_corr[15] = 9.5189334925959599E+02
    s_corr[16] = 2.2702868360248418E+00
    s_corr[17] = 7.5312458499319700E+02
    s_corr[18] = 2.2701207039868367E+00
    s_corr[19] = 5.0027868673701960E+02
    s_corr[20] = 2.2705227157170751E+00
    s_corr[21] = 1.7138025576859900E+02
    s_corr[22] = 2.2541277949292278E+00
    s_corr[23] = 2.0733856020336604E+05
    s_corr[24] = 9.9000307744360238E+04
    s_corr[25] = 2.7306345247149444E-01
    s_corr[26] = -4.3686268354670260E-01
    s_corr[27] = 1.7406314472713416E-01
    s_corr[28] = 2.4017163277669913E+00
    s_corr[29] = 1.1803816043509409E+04
    s_corr[30] = 2.3131877074406706E+00
    s_corr[31] = 2.0066530960234333E+05
    s_corr[32] = 1.6159475288856615E+00
    s_corr[33] = 3.9878128320907672E+04

    check1 = results_check.results_check_vec(problem.mp.pbf.s,
                                             s_corr,
                                             problem.mp.comm,
                                             tol=tol)
    success = results_check.success_check([check1], problem.mp.comm)

    return success
예제 #12
0
def main():

    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS = {
        'problem_type':
        'flow0d',  # solid, fluid, flow0d, solid_flow0d, fluid_flow0d
        'write_results_every': -999,
        'output_path': '' + basepath + '/tmp',
        'simname': 'test'
    }

    SOLVER_PARAMS = {'tol_res': 1.0e-8, 'tol_inc': 1.0e-8}

    TIME_PARAMS = {
        'maxtime': 10 * 1.0,
        'numstep': 10 * 100,
        'timint': 'ost',  # ost
        'theta_ost': 0.5,
        'initial_conditions': init(),
        'eps_periodic': 0.03,
        'periodic_checktype': 'pQvar'
    }

    MODEL_PARAMS = {
        'modeltype': 'syspul',
        'parameters': param(),
        'chamber_models': {
            'lv': {
                'type': '0D_elast',
                'activation_curve': 2
            },
            'rv': {
                'type': '0D_elast',
                'activation_curve': 2
            },
            'la': {
                'type': '0D_elast',
                'activation_curve': 1
            },
            'ra': {
                'type': '0D_elast',
                'activation_curve': 1
            }
        }
    }

    # define your time curves here (syntax: tcX refers to curve X)
    class time_curves():
        def tc1(self, t):  # atrial activation

            act_dur = 2. * param()['t_ed']
            t0 = 0.

            if t >= t0 and t <= t0 + act_dur:
                return 0.5 * (1. - np.cos(2. * np.pi * (t - t0) / act_dur))
            else:
                return 0.0

        def tc2(self, t):  # ventricular activation

            act_dur = 1.8 * (param()['t_es'] - param()['t_ed'])
            t0 = param()['t_ed']

            if t >= t0 and t <= t0 + act_dur:
                return 0.5 * (1. - np.cos(2. * np.pi * (t - t0) / act_dur))
            else:
                return 0.0

    # problem setup
    problem = ambit.Ambit(IO_PARAMS,
                          TIME_PARAMS,
                          SOLVER_PARAMS,
                          constitutive_params=MODEL_PARAMS,
                          time_curves=time_curves())

    # solve time-dependent problem
    problem.solve_problem()

    # --- results check
    tol = 1.0e-6

    s_corr = np.zeros(problem.mp.cardvasc0D.numdof)

    # correct results
    s_corr[0] = 2.7156831671111686E+04
    s_corr[1] = 6.5014832315152615E-01
    s_corr[2] = 2.3863884814303105E-01
    s_corr[3] = 6.2299149148041377E-01
    s_corr[4] = 7.3204325568836603E+00
    s_corr[5] = 4.4855244723865435E+04
    s_corr[6] = 1.9666233818994407E+00
    s_corr[7] = -2.3737219188883661E+04
    s_corr[8] = 3.2279121521802968E+04
    s_corr[9] = 4.9648390872022957E-01
    s_corr[10] = 1.6997499381247427E-01
    s_corr[11] = 4.6420478719842723E-01
    s_corr[12] = 1.8990559860434069E+00
    s_corr[13] = -8.1705347914691476E+04
    s_corr[14] = 1.4965782216339247E+00
    s_corr[15] = -1.0232540549572852E+04

    check1 = results_check.results_check_vec(problem.mp.s,
                                             s_corr,
                                             problem.mp.comm,
                                             tol=tol)
    success = results_check.success_check([check1], problem.mp.comm)

    return success
def main():
    
    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS         = {'problem_type'          : 'flow0d',
                         'write_results_every'   : -999,
                         'output_path'           : ''+basepath+'/tmp/',
                         'simname'               : 'test'}

    SOLVER_PARAMS     = {'tol_res'               : 1.0e-7,
                         'tol_inc'               : 1.0e-7}

    TIME_PARAMS       = {'maxtime'               : 5.0,
                         'numstep'               : 500,
                         'timint'                : 'ost',
                         'theta_ost'             : 1.0,
                         'initial_conditions'    : init(),
                         'eps_periodic'          : 0.05,
                         'periodic_checktype'    : 'pvar'}
    
    MODEL_PARAMS      = {'modeltype'             : 'syspulcaprespir',
                         'parameters'            : param(),
                         'chamber_models'        : {'lv' : {'type' : '0D_elast_prescr', 'elastance_curve' : 1}, 'rv' : {'type' : '0D_elast_prescr', 'elastance_curve' : 2}, 'la' : {'type' : '0D_elast_prescr', 'elastance_curve' : 3}, 'ra' : {'type' : '0D_elast_prescr', 'elastance_curve' : 4}}}
    

    # define your time curves here (syntax: tcX refers to curve X)
    class time_curves():

        def tc1(self, t):
            
            elastinterp = np.loadtxt(''+str(basepath)+'/input/elastances_lv.txt', skiprows=0)

            equidist_time_array = np.zeros(len(elastinterp))
            for i in range(len(equidist_time_array)):
                equidist_time_array[i] = (i+1)/len(equidist_time_array)
                
            return np.interp(t, equidist_time_array, elastinterp)

        def tc2(self, t):
            
            elastinterp = np.loadtxt(''+str(basepath)+'/input/elastances_rv.txt', skiprows=0)

            equidist_time_array = np.zeros(len(elastinterp))
            for i in range(len(equidist_time_array)):
                equidist_time_array[i] = (i+1)/len(equidist_time_array)
                
            return np.interp(t, equidist_time_array, elastinterp)

        def tc3(self, t):
            
            elastinterp = np.loadtxt(''+str(basepath)+'/input/elastances_la.txt', skiprows=0)

            equidist_time_array = np.zeros(len(elastinterp))
            for i in range(len(equidist_time_array)):
                equidist_time_array[i] = (i+1)/len(equidist_time_array)
                
            return np.interp(t, equidist_time_array, elastinterp)

        def tc4(self, t):
            
            elastinterp = np.loadtxt(''+str(basepath)+'/input/elastances_ra.txt', skiprows=0)

            equidist_time_array = np.zeros(len(elastinterp))
            for i in range(len(equidist_time_array)):
                equidist_time_array[i] = (i+1)/len(equidist_time_array)
                
            return np.interp(t, equidist_time_array, elastinterp)


    # problem setup
    problem = ambit.Ambit(IO_PARAMS, TIME_PARAMS, SOLVER_PARAMS, constitutive_params=MODEL_PARAMS, time_curves=time_curves())
    
    # solve time-dependent problem
    problem.solve_problem()


    # --- results check
    tol = 1.0e-6

    s_corr = np.zeros(problem.mp.cardvasc0D.numdof)

    ## correct results - from former testcase (5 cycles with each 1.0 s, theta = 1.0)
    ## currently CANNOT be reproduced with the prescribed elastance model here (even though we're not too far off...)
    ## TODO: Check why this is the case!
    #s_corr[0] = 7.71781462654294883e+04
    #s_corr[1] = 4.82455285374715770e-01
    #s_corr[2] = -9.32089188108091160e-01
    #s_corr[3] = 4.05277139109286311e-01
    #s_corr[4] = 9.72616902019019669e+00
    #s_corr[5] = 5.83726080022352398e+04
    #s_corr[6] = 9.32931790589786658e+00
    #s_corr[7] = 1.83084886403833043e+04
    #s_corr[8] = 1.72154627598280422e+04
    #s_corr[9] = 1.35034073594659403e+04
    #s_corr[10] = 9.21242124362669529e+03
    #s_corr[11] = 3.07080126056907102e+03
    #s_corr[12] = 2.41090621846982422e+00
    #s_corr[13] = 2.27052534769887789e+04
    #s_corr[14] = 2.41613895635923948e+00
    #s_corr[15] = 2.21779080874570500e+04
    #s_corr[16] = 2.41406095622704475e+00
    #s_corr[17] = 1.74172480658872846e+04
    #s_corr[18] = 2.41889648262861146e+00
    #s_corr[19] = 1.18412162444708483e+04
    #s_corr[20] = 2.41890958116365296e+00
    #s_corr[21] = 3.95711134217977497e+03
    #s_corr[22] = 2.04035648172536721e+00
    #s_corr[23] = 9.42308665820743918e+04
    #s_corr[24] = 7.15400334964196954e+04
    #s_corr[25] = 2.31123843349538866e-01
    #s_corr[26] = -2.39084978137291376e-01
    #s_corr[27] = 1.59583809853119180e-01
    #s_corr[28] = 2.55043359122603297e+00
    #s_corr[29] = 2.05678359828922803e+04
    #s_corr[30] = 2.39617482135434079e+00
    #s_corr[31] = 3.90560782940216595e+04
    #s_corr[32] = 2.10325423414917845e+00
    #s_corr[33] = 1.08053263251630851e+05
    #s_corr[34] = 4.77138986718484014e+06
    #s_corr[35] = 2.66700289957665256e+05
    #s_corr[36] = 9.99650347866085411e+01
    #s_corr[37] = 3.27022324023728411e-02
    #s_corr[38] = 1.48960517556904676e-01
    #s_corr[39] = 1.67086022107776043e+04
    #s_corr[40] = 1.66918635646860639e+04
    #s_corr[41] = 1.30961635410208564e+04
    #s_corr[42] = 8.89244395770556184e+03
    #s_corr[43] = 2.98353472804512467e+03
    #s_corr[44] = 1.59148286724528916e+01
    #s_corr[45] = 5.05719330574661186e+00
    #s_corr[46] = 1.59054445599070569e+01
    #s_corr[47] = 5.05719330574661186e+00
    #s_corr[48] = 1.58961192182105986e+01
    #s_corr[49] = 5.06015201758573507e+00
    #s_corr[50] = 3.46365073559847225e+00
    #s_corr[51] = 1.34592586031045460e+01
    #s_corr[52] = 4.11463113554487236e+00
    #s_corr[53] = 1.20061143012695695e+01
    #s_corr[54] = 4.12264630043372993e+00
    #s_corr[55] = 1.19870456277740534e+01
    #s_corr[56] = 4.12650550117093129e+00
    #s_corr[57] = 1.19774295132249193e+01
    #s_corr[58] = 4.13959751959834321e+00
    #s_corr[59] = 1.19526966777885217e+01
    #s_corr[60] = 8.15516536353003829e+00
    #s_corr[61] = 6.85478506275626120e+00
    #s_corr[62] = 4.42228745397937040e+00
    #s_corr[63] = 1.11168107086389227e+01
    #s_corr[64] = 4.87983353032786340e+01
    #s_corr[65] = 1.47121161937896550e+00
    #s_corr[66] = 7.33259028428000548e+00
    #s_corr[67] = 7.35917863339734968e+00
    #s_corr[68] = 6.40038489593068594e+00
    #s_corr[69] = 8.09752757832401571e+00
    #s_corr[70] = 8.15548041504590238e+00
    #s_corr[71] = 6.85197645062970562e+00
    #s_corr[72] = 4.42194570246950125e+00
    #s_corr[73] = 1.11159168023280195e+01
    #s_corr[74] = 4.87944514855986995e+01
    #s_corr[75] = 1.46148783974661067e+00
    #s_corr[76] = 7.33353820491393904e+00
    #s_corr[77] = 7.35448022540421764e+00
    #s_corr[78] = 6.40121826107596270e+00
    #s_corr[79] = 8.09305239721075331e+00
    #s_corr[80] = 1.59169639733867108e+01
    #s_corr[81] = 5.05686647907035258e+00
    
    # "new" "correct" results after 1 cycle
    s_corr[0] = 7.8772984062558084E+04
    s_corr[1] = 4.8659486302195032E-01
    s_corr[2] = -9.3610058358450243E-01
    s_corr[3] = 4.0782187895939220E-01
    s_corr[4] = 9.7688277148044182E+00
    s_corr[5] = 5.8808488437678505E+04
    s_corr[6] = 9.3690308416361692E+00
    s_corr[7] = 1.8467820872202938E+04
    s_corr[8] = 1.7334898156421506E+04
    s_corr[9] = 1.3597017271886743E+04
    s_corr[10] = 9.2764846741601486E+03
    s_corr[11] = 3.0920607948138941E+03
    s_corr[12] = 2.3904106904481224E+00
    s_corr[13] = 2.1963539583972666E+04
    s_corr[14] = 2.4078904587582968E+00
    s_corr[15] = 2.2186303961320122E+04
    s_corr[16] = 2.4058351324957048E+00
    s_corr[17] = 1.7424935125746462E+04
    s_corr[18] = 2.4105541578551586E+00
    s_corr[19] = 1.1842731275571505E+04
    s_corr[20] = 2.4107809114187750E+00
    s_corr[21] = 3.9598510095865377E+03
    s_corr[22] = 2.0319657244376885E+00
    s_corr[23] = 9.3711973674203065E+04
    s_corr[24] = 7.0539636117053349E+04
    s_corr[25] = 2.3269582989298973E-01
    s_corr[26] = -2.4254777064876870E-01
    s_corr[27] = 1.6215619377593637E-01
    s_corr[28] = 2.5876339002636235E+00
    s_corr[29] = 2.1024862315696508E+04
    s_corr[30] = 2.4299474328958999E+00
    s_corr[31] = 3.9854755419966961E+04
    s_corr[32] = 2.1310367672461474E+00
    s_corr[33] = 1.0962946028161315E+05
    s_corr[34] = 4.9359151070363959E+06
    s_corr[35] = 1.2176999298415647E+06
    s_corr[36] = 9.9835478479934423E+01
    s_corr[37] = 1.1874877807660576E-02
    s_corr[38] = 1.8905022661610985E-01
    s_corr[39] = 1.6856052226168646E+04
    s_corr[40] = 1.6807410235902895E+04
    s_corr[41] = 1.3186748889259841E+04
    s_corr[42] = 8.9541309449532910E+03
    s_corr[43] = 3.0041461413938432E+03
    s_corr[44] = 1.5868870030490044E+01
    s_corr[45] = 5.0645312522587602E+00
    s_corr[46] = 1.5853909749529379E+01
    s_corr[47] = 5.0669389175553903E+00
    s_corr[48] = 1.5849765885394156E+01
    s_corr[49] = 5.0676025646993645E+00
    s_corr[50] = 1.6195682913639453E+00
    s_corr[51] = 1.7179751665615537E+01
    s_corr[52] = 3.8185082152968373E+00
    s_corr[53] = 1.2477049172174398E+01
    s_corr[54] = 3.9607746097186181E+00
    s_corr[55] = 1.2246871673462810E+01
    s_corr[56] = 4.0976635194540458E+00
    s_corr[57] = 1.2021904244523247E+01
    s_corr[58] = 4.1363317713754935E+00
    s_corr[59] = 1.1959313574705780E+01
    s_corr[60] = 8.1560564804157494E+00
    s_corr[61] = 6.8543786891326901E+00
    s_corr[62] = 4.4220064405023898E+00
    s_corr[63] = 1.1117637256132248E+01
    s_corr[64] = 4.8799048063729643E+01
    s_corr[65] = 1.4670011536083674E+00
    s_corr[66] = 7.3334628304288074E+00
    s_corr[67] = 7.3581916462645314E+00
    s_corr[68] = 6.4011225251472208E+00
    s_corr[69] = 8.0967303185253847E+00
    s_corr[70] = 8.1554715871500623E+00
    s_corr[71] = 6.8518898508557946E+00
    s_corr[72] = 4.4219094292144900E+00
    s_corr[73] = 1.1115847759264300E+01
    s_corr[74] = 4.8793936123173694E+01
    s_corr[75] = 1.4608640562779471E+00
    s_corr[76] = 7.3335746032859470E+00
    s_corr[77] = 7.3541764115858905E+00
    s_corr[78] = 6.4012488006615680E+00
    s_corr[79] = 8.0927561433097157E+00
    s_corr[80] = 1.5885890375194892E+01
    s_corr[81] = 5.0617824505327755E+00
    
    check1 = results_check.results_check_vec(problem.mp.s, s_corr, problem.mp.comm, tol=tol)
    success = results_check.success_check([check1], problem.mp.comm)
    
    return success
def main():

    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS = {
        'problem_type':
        'solid',
        'mesh_domain':
        '' + basepath + '/input/blockhex_domain.xdmf',
        'mesh_boundary':
        '' + basepath + '/input/blockhex_boundary.xdmf',
        'fiber_data': {
            'nodal': [
                '' + basepath + '/input/fib1_blockhex.txt',
                '' + basepath + '/input/fib2_blockhex.txt'
            ]
        },
        'write_results_every':
        -999,
        'output_path':
        '' + basepath + '/tmp/',
        'results_to_write': [
            'displacement', 'theta', 'fiberstretch', 'fiberstretch_e',
            'phi_remod'
        ],
        'simname':
        'solid_growthremodeling_fiberstretch'
    }

    SOLVER_PARAMS_SOLID = {
        'solve_type': 'direct',
        'tol_res': 1.0e-8,
        'tol_inc': 1.0e-8
    }

    TIME_PARAMS_SOLID = {'maxtime': 1.0, 'numstep': 20, 'timint': 'static'}

    FEM_PARAMS = {
        'order_disp': 1,
        'order_pres': 1,
        'quad_degree': 3,
        'incompressible_2field': False
    }

    MATERIALS = {
        'MAT1': {
            'neohooke_dev': {
                'mu': 10.
            },
            'ogden_vol': {
                'kappa': 10. / (1. - 2. * 0.49)
            },
            'growth': {
                'growth_dir':
                'isotropic',  # isotropic, fiber, crossfiber, radial
                'growth_trig':
                'fibstretch',  # fibstretch, volstress, prescribed
                'growth_thres': 1.15,
                'thetamax': 3.0,
                'thetamin': 1.0,
                'tau_gr': 1.0,
                'gamma_gr': 1.72,
                'tau_gr_rev': 10000.0,
                'gamma_gr_rev': 1.0,
                'remodeling_mat': {
                    'neohooke_dev': {
                        'mu': 3.
                    },
                    'ogden_vol': {
                        'kappa': 3. / (1. - 2. * 0.49)
                    }
                }
            }
        }
    }

    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    class time_curves():
        def tc1(self, t):
            pmax = 10.0
            return pmax * t / TIME_PARAMS_SOLID['maxtime']

    BC_DICT = {
        'dirichlet': [{
            'id': [1],
            'dir': 'x',
            'val': 0.
        }, {
            'id': [2],
            'dir': 'y',
            'val': 0.
        }, {
            'id': [3],
            'dir': 'z',
            'val': 0.
        }],
        'neumann': [{
            'type': 'pk1',
            'id': [4],
            'dir': 'xyz',
            'curve': [1, 0, 0]
        }]
    }

    # problem setup
    problem = ambit.Ambit(IO_PARAMS,
                          TIME_PARAMS_SOLID,
                          SOLVER_PARAMS_SOLID,
                          FEM_PARAMS,
                          MATERIALS,
                          BC_DICT,
                          time_curves=time_curves())

    # solve time-dependent problem
    problem.solve_problem()

    # --- results check
    tol = 1.0e-6

    check_node = []
    check_node.append(np.array([1.0, 1.0, 1.0]))

    u_corr = np.zeros(3 * len(check_node))

    ## correct results
    u_corr[0] = 1.0812823521095760E+00  # x
    u_corr[1] = -1.4360291810029382E-01  # y
    u_corr[2] = -1.4360291810029457E-01  # z

    check1 = results_check.results_check_node(problem.mp.u,
                                              check_node,
                                              u_corr,
                                              problem.mp.V_u,
                                              problem.mp.comm,
                                              tol=tol,
                                              nm='u')
    success = results_check.success_check([check1], problem.mp.comm)

    return success
예제 #15
0
def main():
    
    basepath = str(Path(__file__).parent.absolute())

    # all possible input parameters

    IO_PARAMS            = {'problem_type'          : 'solid_flow0d', # solid, fluid, flow0d, solid_flow0d, fluid_flow0d, solid_flow0d_multiscale_gandr, solid_constraint
                            'mesh_domain'           : ''+basepath+'/input/blocks_domain.xdmf', # domain mesh file
                            'mesh_boundary'         : ''+basepath+'/input/blocks_boundary.xdmf', # boundary mesh file
                            'meshfile_type'         : 'ASCII', # OPTIONAL: type of encoding of your mesh file (ASCII or HDF5) (default: 'ASCII')
                            'fiber_data'            : {'nodal' : [''+basepath+'/file1.txt',''+basepath+'/file2.txt']}, # OPTIONAL: only for anisotropic solid materials - nodal: fiber input data is stored at node coordinates, elemental: fiber input data is stored at element center
                            'write_results_every'   : 1, # frequency for results output (negative value for no output, 1 for every time step, etc.)
                            'write_results_every_0D': 1, # OPTIONAL: for flow0d results (default: write_results_every)
                            'write_restart_every'   : 1, # OPTIONAL: if restart info should be written (default: -1)
                            'output_path'           : ''+basepath+'/tmp/', # where results are written to
                            'output_path_0D'        : ''+basepath+'/tmp/', # OPTIONAL: different output path for flow0d results (default: output_path)
                            'results_to_write'      : ['displacement','velocity','pressure','cauchystress'], # see io_routines.py for what to write
                            'simname'               : 'my_simulation_name', # how to name the output (attention: there is no warning, results will be overwritten if existent)
                            'restart_step'          : 0} # OPTIONAL: at which time step to restart a former simulation (that crashed and shoud be resumed or whatever) (default: 0)

    # for solid*, fluid* problem types
    SOLVER_PARAMS_SOLID  = {'solve_type'            : 'direct', # direct, iterative
                            'tol_res'               : 1.0e-8, # residual tolerance for nonlinear solver
                            'tol_inc'               : 1.0e-8, # increment tolerance for nonlinear solver
                            'divergence_continue'   : None, # OPTIONAL: what to apply when Newton diverges: None, 'PTC' ('ptc' can stay False) (default: None)
                            'ptc'                   : False, # OPTIONAL: if you want to use PTC straight away (independent of divergence_continue) (default: False)
                            'k_ptc_initial'         : 0.1, # OPTIONAL: initial PTC value that adapts during nonlinear iteration (default: 0.1)
                            'ptc_randadapt_range'   : [0.85, 1.35], # OPTIONAL: in what range to randomly adapt PTC parameter if divergence continues to occur (default: [0.85, 1.35]) (only if divergence_continue is set to 'PTC')
                            # iterative linear solver settings (only apply for solve_type 'iterative')
                            'tol_lin'               : 1.0e-6, # OPTIONAL: linear solver tolerance (default: 1.0e-8)
                            'max_liniter'           : 1200, # OPTIONAL: maximum number of linear iterations (default: 1200)
                            'print_liniter_every'   : 50, # OPTIONAL: how often to print linear iterations (default: 50)
                            'adapt_linsolv_tol'     : False, # OPTIONAL: True, False - adapt linear tolerance throughout nonlinear iterations (default: False)
                            'adapt_factor'          : 0.1, # OPTIONAL: adaptation factor for adapt_linsolv_tol (the larger, the more adaptation) (default: 0.1)
                            # for local Newton (only for inelastic nonlinear materials at Gauss points, i.e. deformation-dependent growth)
                            'print_local_iter'      : False, # OPTIONAL: if we want to print iterations of local Newton (default: False)
                            'tol_res_local'         : 1.0e-10, # OPTIONAL: local Newton residual inf-norm tolerance (default: 1.0e-10)
                            'tol_inc_local'         : 1.0e-10} # OPTIONAL: local Newton increment inf-norm tolerance (default: 1.0e-10)
    
    # for flow0d, solid_flow0d, or fluid_flow0d problem types
    SOLVER_PARAMS_FLOW0D = {'tol_res'               : 1.0e-6, # residual tolerance for nonlinear solver
                            'tol_inc'               : 1.0e-6} # increment tolerance for nonlinear solver

    # for solid*, fluid* problem types
    TIME_PARAMS_SOLID    = {'maxtime'               : 1.0, # maximum simulation time
                            'numstep'               : 500, # number of steps over maxtime (maxtime/numstep governs the time step size)
                            'numstep_stop'          : 5, # OPTIONAL: if we want the simulation to stop earlier (default: numstep)
                            'timint'                : 'genalpha', # time-integration algorithm: genalpha, ost, static
                            'theta_ost'             : 1.0, # One-Step-Theta (ost) time integration factor 
                            'rho_inf_genalpha'      : 0.8} # spectral radius of Generalized-alpha (genalpha) time-integration (governs all other parameters alpha_m, alpha_f, beta, gamma)
    
    # for flow0d, solid_flow0d, or fluid_flow0d problem types
    TIME_PARAMS_FLOW0D   = {'timint'                : 'ost', # time-integration algorithm: ost
                            'theta_ost'             : 0.5, # One-Step-Theta time integration factor 
                            'initial_conditions'    : init(), # initial condition dictionary (here defined as function, see below)
                            'initial_file'          : None, # OPTIONAL: if we want to read initial conditions from a file (overwrites above specified dict)
                            'eps_periodic'          : 1.0e-3, # OPTIONAL: cardiac cycle periodicity tolerance (default: 1.0e-20)
                            'periodic_checktype'    : None} # OPTIONAL: None, 'allvar', 'pQvar' (default: None)

    # for flow0d, solid_flow0d, or fluid_flow0d problem types
    MODEL_PARAMS_FLOW0D  = {'modeltype'             : 'syspul', # 2elwindkessel, 4elwindkesselLsZ, 4elwindkesselLpZ, syspul, syspul_veins, syspulcap, syspulcapcor_veins
                            'parameters'            : param(), # parameter dictionary (here defined as function, see below)
                            'chamber_models'        : {'lv' : {'type' : '3D_solid'}, 'rv' : {'type' : '3D_fluid', 'num_inflows' : 1, , 'num_outflows' : 1}, 'la' : {'type' : '0D_elast', 'activation_curve' : 5}, 'ra' : {'type' : '0D_prescr', 'prescribed_curve' : 5}}, # only for syspul* models - 3D_solid, 3D_fluid: chamber is 3D solid or fluid mechanics model, 0D_elast: chamber is 0D elastance model, 0D_prescr: volume/flux is prescribed over time, prescr_elast: chamber is 0D elastance model with prescribed elastance over time
                            'prescribed_variables'  : {'q_vin_l' : 1}, # OPTIONAL: in case we want to prescribe values: variable name, and time curve number (define below)
                            'perturb_type'          : None, # OPTIONAL: ['mr',1.0e-6], ['ms',25.], ['ar',5.0e-6], ['as',50.], ['mi',0.,4] (default: None)
                            'perturb_after_cylce'   : 1, # OPTIONAL: after which cycle to induce the perturbation / disease / cardiovascular state change... (default: -1)
                            'valvelaws'             : {'av' : ['pwlin_pres',0], 'mv' : ['pwlin_pres',0], 'pv' : ['pwlin_pres',0], 'tv' : ['pwlin_pres',0]}} # OPTIONAL: valve laws for aortic (av), mitral (mv), pulmonary (pv), and tricuspid valve (tv) (pwlin_pres: piecewise-linear pressure-governed, pwlin_time: piecewise-linear time-governed, smooth_pres_momentum: , smooth p-q relationship, smooth_pres_resistance: smooth resistance pressure-governed with number being amount of smoothness) (default: {'av' : ['pwlin_pres',0], 'mv' : ['pwlin_pres',0], 'pv' : ['pwlin_pres',0], 'tv' : ['pwlin_pres',0]})

    # for solid*, fluid* problem types
    FEM_PARAMS           = {'order_disp'            : 1, # order of displacement interpolation (solid mechanics)
                            'order_vel'             : 1, # order of velocity interpolation (fluid mechanics)
                            'order_pres'            : 1, # order of pressure interpolation (solid, fluid mechanics)
                            'quad_degree'           : 1, # quadrature degree q (number of integration points: n(q) = ((q+2)//2)**dim) --> can be 1 for linear tets, should be >= 3 for linear hexes, should be >= 5 for quadratic tets/hexes
                            'incompressible_2field' : False, # if we want to use a 2-field functional for pressure dofs (always applies for fluid, optional for solid mechanics)
                            'prestress_initial'     : False} # OPTIONAL: if we want to use MULF prestressing (Gee et al. 2010) prior to solving a dynamic/other kind of solid or solid-coupled problem (experimental, not thoroughly tested!) (default: False)
    
    # for solid_flow0d or fluid_flow0d problem type
    COUPLING_PARAMS      = {'surface_ids'           : [[1],[2]], # coupling surfaces (for syspul* models: order is lv, rv, la, ra - has to be consistent with chamber_models dict)
                            'surface_p_ids'         : [[1],[2]], # OPTIONAL: if pressure should be applied to different surface than that from which the volume/flux is measured from... (default: surface_ids)
                            'cq_factor'             : [1.,1.], # OPTIONAL: if we want to scale the 3D volume or flux (e.g. for 2D solid models) (default: [1.] * number of surfaces)
                            'coupling_quantity'     : 'volume', # volume, flux, pressure (former need 'monolithic_direct', latter needs 'monolithic_lagrange' as coupling_type)
                            'coupling_type'         : 'monolithic_direct'} # monolithic_direct, monolithic_lagrange (ask MH for the difference... or try to find out in the code... :))

    # for solid_constraint problem type
    CONSTRAINT_PARAMS    = {'surface_ids'           : [[1],[2]], # coupling surfaces for volume or flux constraint (for syspul* models: order is lv, rv, la, ra)
                            'surface_p_ids'         : [[1],[2]], # OPTIONAL: if pressure should be applied to different surface than that from which the volume/flux is measured from... (default: surface_ids) (for syspul* models: order is lv, rv, la, ra)
                            'constraint_quantity'   : ['volume','volume'], # volume, flux, pressure (for syspul* models: order is lv, rv, la, ra) (default: volume) 
                            'prescribed_curve'      : [5,6]} # time curves that set the volumes/fluxes that shall be met

    # for solid_flow0d_multiscale_gandr problem type
    MULTISCALE_GR_PARAMS = {'gandr_trigger_phase'   : 'end_diastole', # end_diastole, end_systole
                            'numcycles'             : 10, # max. number of multiscale cycles (one cycle means one small scale succeeded by a large scale run)
                            'tol_small'             : 1.0e-3, # cycle error tolerance: overrides eps_periodic from TIME_PARAMS_FLOW0D
                            'tol_large'             : 1.0e-4, # growth rate tolerance
                            'tol_outer'             : 1.0e-3, # tolerance for volume increase during one growth cycle - stop sim if equal to or below this value
                            'write_checkpoints'     : False, # OPTIONAL: to write checkpoints after each small or large scale run to restart from there (default: False)
                            'restart_cycle'         : 0, # OPTIONAL: at which multiscale cycle to restart (default: 0)
                            'restart_from_small'    : False} # OPTIONAL: if the multiscale sim should be restarted from a previous small scale run (small scale of restart_cycle needs to be computed already) (default: False)
                            
                            # - MATn has to correspond to subdomain id n (set by the flags in Attribute section of *_domain.xdmf file - so if you have x mats, you need ids ranging from 1,...,x)
                            # - one MAT can be decomposed into submats, see examples below (additive stress contributions)
                            # - for solid: if you use a deviatoric (_dev) mat, you should also use EITHER a volumetric (_vol) mat, too, OR set incompressible_2field in FEM_PARAMS to 'True' and then only use a _dev mat and MUST NOT use a _vol mat! (if incompressible_2field is 'True', then all materials have to be treated perfectly incompressible currently)
                            # - for fluid: incompressible_2field is always on, and you only can define a Newtonian fluid ('newtonian') with dynamic viscosity 'eta'
                            # - for dynamics, you need to specify a mat called 'inertia' and set the density ('rho0' in solid, 'rho' in fluid dynamics)
                            # - material can also be inelastic and growth ('growth')
                            # - see solid_material.py or fluid_material.py for material laws available (and their parameters), and feel free to implement/add new strain energy functions or laws fairly quickly
    MATERIALS            = {'MAT1' : {'holzapfelogden_dev' : {'a_0' : 0.059, 'b_0' : 8.023, 'a_f' : 18.472, 'b_f' : 16.026, 'a_s' : 2.481, 'b_s' : 11.120, 'a_fs' : 0.216, 'b_fs' : 11.436, 'fiber_comp' : False},
                                      'sussmanbathe_vol'   : {'kappa' : 1.0e3},
                                      'active_fiber'       : {'sigma0' : 50.0, 'alpha_max' : 15.0, 'alpha_min' : -20.0, 'activation_curve' : 4, 'frankstarling' : True, 'amp_min' : 1., 'amp_max' : 1.7, 'lam_threslo' : 1.01, 'lam_maxlo' : 1.15, 'lam_threshi' : 999., 'lam_maxhi' : 9999.},
                                      'inertia'            : {'rho0' : 1.0e-6},
                                      'rayleigh_damping'   : {'eta_m' : 0.0, 'eta_k' : 0.0001}},
                            'MAT2' : {'neohooke_dev'       : {'mu' : 10.},
                                      'ogden_vol'          : {'kappa' : 10./(1.-2.*0.49)},
                                      'inertia'            : {'rho0' : 1.0e-6},
                                      'growth'             : {'growth_dir' : 'isotropic', # isotropic, fiber, crossfiber, radial
                                                              'growth_trig' : 'volstress', # fibstretch, volstress, prescribed
                                                              'growth_thres' : 1.01, # critial value above which growth happens (i.e. a critial stretch, stress or whatever depending on the growth trigger)
                                                              'thres_tol' : 1.0e-4, # tolerance for threshold (makes sense in multiscale approach, where threshold is set element-wise)
                                                              'trigger_reduction' : 1, # reduction factor for trigger ]0,1]
                                                              'thetamax' : 1.5, # maximum growth stretch
                                                              'thetamin' : 1.0, # minimum growth stretch
                                                              'tau_gr' : 1.0, # growth time constant
                                                              'gamma_gr' : 2.0, # growth nonlinearity
                                                              'tau_gr_rev' : 1000.0, # reverse growth time constant
                                                              'gamma_gr_rev' : 2.0, # reverse growth nonlinearity
                                                              'remodeling_mat' : {'neohooke_dev' : {'mu' : 3.}, # remodeling material
                                                                                  'ogden_vol'    : {'kappa' : 3./(1.-2.*0.49)}}}}}



    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    # some examples... up to 9 possible (tc1 until tc9 - feel free to implement more in timeintegration.py --> timecurves function if needed...)
    class time_curves():
        
        def tc1(self, t):
            return 3.*t
        
        def tc2(self, t):
            return -5000.0*np.sin(2.*np.pi*t/TIME_PARAMS_SOLID['maxtime'])

        def tc3(self, t): # can be a constant but formally needs t as input
            return 5.

        def tc4(self, t): # for active stress activation
            
            K = 5.
            t_contr, t_relax = 0.2, 0.53
            
            alpha_max = MATERIALS['MAT1']['active_fiber']['alpha_max']
            alpha_min = MATERIALS['MAT1']['active_fiber']['alpha_min']
            
            c1 = t_contr + alpha_max/(K*(alpha_max-alpha_min))
            c2 = t_relax - alpha_max/(K*(alpha_max-alpha_min))
            
            # Diss Hirschvogel eq. 2.101
            return (K*(t-c1)+1.)*((K*(t-c1)+1.)>0.) - K*(t-c1)*((K*(t-c1))>0.) - K*(t-c2)*((K*(t-c2))>0.) + (K*(t-c2)-1.)*((K*(t-c2)-1.)>0.)

        def tc5(self, t): # 0D elastance activation function
            
            act_dur = 0.4
            t0 = 0.
            
            if t >= t0 and t <= t0 + act_dur:
                y = 0.5*(1.-np.cos(2.*np.pi*(t-t0)/act_dur))
            else:
                y = 0.0

        #...

    # bc syntax examples
    BC_DICT              = { 'dirichlet' : [{'id' : [1], 'dir' : 'all', 'val' : 0.}, # either curve or val
                                            {'id' : [2,4,5], 'dir' : 'y', 'val' : 0.}, # either curve or val
                                            {'id' : [3], 'dir' : 'z', 'curve' : 1}], # either curve or val
                            # Neumann can be - pk1 with dir xyz (then use 'curve' : [xcurve-num, ycurve-num, zcurve-num] with 0 meaning zero),
                            #                - pk1 with dir normal (then use 'curve' : curve-num with 0 meaning zero)
                            #                - true with dir normal (then use 'curve' : curve-num with 0 meaning zero) = follower load in current normal direction
                            'neumann'    : [{'type' : 'pk1', 'id' : [3], 'dir' : 'xyz', 'curve' : [1,0,0]},
                                            {'type' : 'pk1', 'id' : [2], 'dir' : 'normal', 'curve' : 1},
                                            {'type' : 'true', 'id' : [2], 'dir' : 'normal', 'curve' : 1}],
                            # Robib BC can be either spring or dashpot, both either in xyz or normal direction
                            'robin'      : [{'type' : 'spring', 'id' : [3], 'dir' : 'normal', 'stiff' : 0.075},
                                            {'type' : 'dashpot', 'id' : [3], 'dir' : 'xyz', 'visc' : 0.005}] }

    # problem setup - exemplary for 3D-0D coupling of solid (fluid) to flow0d
    problem = ambit.Ambit(IO_PARAMS, [TIME_PARAMS_SOLID, TIME_PARAMS_FLOW0D], [SOLVER_PARAMS_SOLID, SOLVER_PARAMS_FLOW0D], FEM_PARAMS, [MATERIALS, MODEL_PARAMS_FLOW0D], BC_DICT, time_curves=time_curves(), coupling_params=COUPLING_PARAMS, multiscale_params=MULTISCALE_GR_PARAMS)
    
    # problem setup for solid (fluid) only: just pass parameters related to solid (fluid) instead of lists, so:
    #problem = ambit.Ambit(IO_PARAMS, TIME_PARAMS_SOLID, SOLVER_PARAMS_SOLID, FEM_PARAMS, MATERIALS, BC_DICT, time_curves=time_curves())

    # problem solve
    problem.solve_problem()
def main():
    
    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS            = {'problem_type'          : 'solid_flow0d_multiscale_gandr',
                            'mesh_domain'           : ''+basepath+'/input/heart3Dcoarse_domain.xdmf',
                            'mesh_boundary'         : ''+basepath+'/input/heart3Dcoarse_boundary.xdmf',
                            'fiber_data'            : {'nodal' : [''+basepath+'/input/fib_fiber_coords_nodal_3Dcoarse.txt',''+basepath+'/input/fib_sheet_coords_nodal_3Dcoarse.txt']},
                            'write_results_every'   : 1,
                            'output_path'           : ''+basepath+'/tmp',
                            'results_to_write'      : ['displacement','theta','phi_remod','fiberstretch_e'],
                            'simname'               : 'multiscale_eccentric_mr'}

    SOLVER_PARAMS_SOLID  = {'solve_type'            : 'direct', # direct, iterative
                            'tol_res'               : 1.0e-8,
                            'tol_inc'               : 1.0e-8,
                            'divergence_continue'   : 'PTC',
                            'k_ptc_initial'         : 10.0,
                            'print_local_iter'      : False,
                            'tol_res_local'         : 1.0e-10,
                            'tol_inc_local'         : 1.0e-10}
    
    SOLVER_PARAMS_FLOW0D = {'tol_res'               : 1.0e-6,
                            'tol_inc'               : 1.0e-6}

    TIME_PARAMS_SOLID_SMALL = {'maxtime'            : 1.0*100,
                            'numstep'               : 50*100,
                            'timint'                : 'genalpha',
                            'theta_ost'             : 1.0,
                            'rho_inf_genalpha'      : 0.8}

    TIME_PARAMS_SOLID_LARGE = {'maxtime'            : 2592000.0, # 1 month: 30*24*60*60 s
                            'numstep'               : 1000,
                            'timint'                : 'static'}

    TIME_PARAMS_FLOW0D   = {'timint'                : 'ost', # ost
                            'theta_ost'             : 0.5,
                            'eps_periodic'          : 999,
                            'periodic_checktype'    : 'pQvar',
                            'initial_file'          : ''+basepath+'/input/initial_syspulcap_multiscale.txt'}

    MODEL_PARAMS_FLOW0D  = {'modeltype'             : 'syspulcap',
                            'parameters'            : param(),
                            'chamber_models'        : {'lv' : {'type' : '3D_solid'}, 'rv' : {'type' : '3D_solid'}, 'la' : {'type' : '0D_elast', 'activation_curve' : 2}, 'ra' : {'type' : '0D_elast', 'activation_curve' : 2}},
                            'perturb_type'          : ['mr',1.0e-6],
                            'perturb_after_cylce'   : 1}

    FEM_PARAMS           = {'order_disp'            : 1,
                            'order_pres'            : 1,
                            'quad_degree'           : 1,
                            'incompressible_2field' : False,
                            'prestress_initial'     : True,
                            'lin_remodeling_full'   : False}
    
    COUPLING_PARAMS      = {'surface_ids'           : [[1],[2]],
                            'coupling_quantity'     : ['volume','volume'],
                            'coupling_type'         : 'monolithic_direct'}
    
    MULTISCALE_GR_PARAMS = {'gandr_trigger_phase'   : 'end_diastole', # end_diastole, end_systole
                            'numcycles'             : 10,
                            'tol_small'             : 0.08, # cycle error tolerance: overrides eps_periodic from TIME_PARAMS_FLOW0D
                            'tol_large'             : 5.0e-3, # growth rate tolerance [mm^3/s]
                            'tol_outer'             : 3.0e-3,
                            'write_checkpoints'     : True,
                            'restart_cycle'         : 0,
                            'restart_from_small'    : False}

    MATERIALS            = {'MAT1' : {'guccione_dev'     : {'c_0' : 1.662, 'b_f' : 14.31, 'b_t' : 4.49, 'b_fs' : 10.},
                                      'sussmanbathe_vol' : {'kappa' : 1.0e3},
                                      'active_fiber'     : {'sigma0' : 150., 'alpha_max' : 10.0, 'alpha_min' : -30.0, 'activation_curve' : 1, 'frankstarling' : True, 'amp_min' : 1., 'amp_max' : 1.5, 'lam_threslo' : 1.01, 'lam_maxlo' : 1.15, 'lam_threshi' : 999., 'lam_maxhi' : 9999.},
                                      'inertia'          : {'rho0' : 1.0e-6},
                                      'growth'           : {'growth_dir' : 'fiber',
                                                            'growth_trig' : 'fibstretch',
                                                            'trigger_reduction' : 0.99,
                                                            'growth_thres' : 1.05,
                                                            'thres_tol' : 1.0e-3,
                                                            'thetamax' : 3.0,
                                                            'thetamin' : 1.0,
                                                            'tau_gr' : 2.0e4,
                                                            'gamma_gr' : 2.0,
                                                            'tau_gr_rev' : 4.0e4,
                                                            'gamma_gr_rev' : 2.0,
                                                            'remodeling_mat' : {'guccione_dev'     : {'c_0' : 1.662, 'b_f' : 14.31, 'b_t' : 4.49, 'b_fs' : 10.},
                                                                                'sussmanbathe_vol' : {'kappa' : 1.0e3}}}}}



    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    class time_curves():
        
        def tc1(self, t):
            
            K = 5.
            t_contr, t_relax = 0.2, 0.53
            
            alpha_max = MATERIALS['MAT1']['active_fiber']['alpha_max']
            alpha_min = MATERIALS['MAT1']['active_fiber']['alpha_min']
            
            c1 = t_contr + alpha_max/(K*(alpha_max-alpha_min))
            c2 = t_relax - alpha_max/(K*(alpha_max-alpha_min))
            
            # Diss Hirschvogel eq. 2.101
            return (K*(t-c1)+1.)*((K*(t-c1)+1.)>0.) - K*(t-c1)*((K*(t-c1))>0.) - K*(t-c2)*((K*(t-c2))>0.) + (K*(t-c2)-1.)*((K*(t-c2)-1.)>0.)

        def tc2(self, t): # atrial activation
            
            act_dur = 2.*param()['t_ed']
            t0 = 0.
            
            if t >= t0 and t <= t0 + act_dur:
                return 0.5*(1.-np.cos(2.*np.pi*(t-t0)/act_dur))
            else:
                return 0.0


    BC_DICT              = { 'robin' : [{'type' : 'spring',  'id' : [3], 'dir' : 'normal', 'stiff' : 0.075},
                                        {'type' : 'dashpot', 'id' : [3], 'dir' : 'normal', 'visc'  : 0.005},
                                        {'type' : 'spring',  'id' : [4], 'dir' : 'normal', 'stiff' : 10.0}, # 2.5, 1.25
                                        {'type' : 'dashpot', 'id' : [4], 'dir' : 'normal', 'visc'  : 0.0005},
                                        {'type' : 'spring',  'id' : [4], 'dir' : 'xyz', 'stiff' : 0.25},
                                        {'type' : 'dashpot', 'id' : [4], 'dir' : 'xyz', 'visc'  : 0.0005}] }

    # problem setup
    problem = ambit.Ambit(IO_PARAMS, [TIME_PARAMS_SOLID_SMALL, TIME_PARAMS_SOLID_LARGE, TIME_PARAMS_FLOW0D], [SOLVER_PARAMS_SOLID, SOLVER_PARAMS_FLOW0D], FEM_PARAMS, [MATERIALS, MODEL_PARAMS_FLOW0D], BC_DICT, time_curves=time_curves(), coupling_params=COUPLING_PARAMS, multiscale_params=MULTISCALE_GR_PARAMS)
    
    # solve time-dependent problem
    problem.solve_problem()


    # --- results check
    tol = 1.0e-6
        
    s_corr = np.zeros(problem.mp.pbsmall.pbf.cardvasc0D.numdof)

    # correct 0D results
    s_corr[0]    = 9.8218127134072438E+03
    s_corr[1]    = 1.6830389591312851E+00
    s_corr[2]    = 6.9122581694220819E-01
    s_corr[3]    = 1.6732171464178778E+00
    s_corr[4]    = 6.1991003628749271E+00
    s_corr[5]    = 3.4679811145201791E+04
    s_corr[6]    = 5.9629754596187894E+00
    s_corr[7]    = -1.5127985585647235E+04
    s_corr[8]    = -1.4071745452471156E+04
    s_corr[9]    = -1.1030984515776136E+04
    s_corr[10]    = -7.5370923441673440E+03
    s_corr[11]    = -2.5111069127516153E+03
    s_corr[12]    = 1.9079271968625631E+00
    s_corr[13]    = 1.8611601990631785E+04
    s_corr[14]    = 1.8421266816160995E+00
    s_corr[15]    = 1.4042777929688003E+04
    s_corr[16]    = 1.8404635461013050E+00
    s_corr[17]    = 1.1012196762017255E+04
    s_corr[18]    = 1.8450877129650409E+00
    s_corr[19]    = 7.5357188622862641E+03
    s_corr[20]    = 1.8422585559378539E+00
    s_corr[21]    = 2.4886342151947470E+03
    s_corr[22]    = 1.6041858523754655E+00
    s_corr[23]    = -5.3410330934638907E+04
    s_corr[24]    = 1.4955139915285741E+04
    s_corr[25]    = 4.8317355188752570E-01
    s_corr[26]    = -4.2450391200662768E-02
    s_corr[27]    = 4.6821841197224007E-01
    s_corr[28]    = 3.1803505880679763E+00
    s_corr[29]    = 1.4570153064883158E+04
    s_corr[30]    = 3.0710744400813530E+00
    s_corr[31]    = -8.0065756622318950E+04
    s_corr[32]    = 2.8638179712861844E+00
    s_corr[33]    = 1.2057400362096410E+04

    check1 = results_check.results_check_vec(problem.mp.pbsmall.pbf.s, s_corr, problem.mp.comm, tol=tol)
    success = results_check.success_check([check1], problem.mp.comm)
    
    return success
def main():

    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS = {
        'problem_type':
        'solid',  # solid, fluid, flow0d, solid_flow0d, fluid_flow0d
        'mesh_domain': '' + basepath + '/input/block2_domain.xdmf',
        'mesh_boundary': '' + basepath + '/input/block2_boundary.xdmf',
        'write_results_every': -999,
        'output_path': '' + basepath + '/tmp/',
        'results_to_write': [''],
        'simname': 'solid_robin_static_prestress'
    }

    SOLVER_PARAMS = {
        'solve_type': 'direct',  # direct, iterative
        'tol_res': 1.0e-8,
        'tol_inc': 1.0e-8
    }

    TIME_PARAMS = {'maxtime': 1.0, 'numstep': 1, 'timint': 'static'}

    FEM_PARAMS = {
        'order_disp': 1,
        'order_pres': 1,
        'quad_degree': 1,
        'incompressible_2field': False,
        'prestress_initial': True
    }

    MATERIALS = {'MAT1': {'stvenantkirchhoff': {'Emod': 1000., 'nu': 0.3}}}

    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    class time_curves():
        def tc1(self, t):
            return 3.

    BC_DICT = {
        'dirichlet': [{
            'id': [1, 2, 3],
            'dir': 'z',
            'val': 0.
        }],
        'neumann': [{
            'type': 'pk1',
            'id': [3],
            'dir': 'xyz',
            'curve': [1, 0, 0]
        }],
        'robin': [{
            'type': 'spring',
            'id': [1, 2],
            'dir': 'normal',
            'stiff': 5.0
        }]
    }

    # problem setup
    problem = ambit.Ambit(IO_PARAMS,
                          TIME_PARAMS,
                          SOLVER_PARAMS,
                          FEM_PARAMS,
                          MATERIALS,
                          BC_DICT,
                          time_curves=time_curves())

    # solve time-dependent problem
    problem.solve_problem()

    # --- results check
    tol = 1.0e-6

    check_node = []
    check_node.append(
        np.array([
            -1.0000000000000000e+00, -1.0000000000000000e+00,
            1.0000000000000000e+01
        ]))

    u_corr = np.zeros(3 * len(check_node))

    ## correct results
    u_corr[0] = 0.0  # x
    u_corr[1] = 0.0  # y
    u_corr[2] = 0.0  # z

    check1 = results_check.results_check_node(problem.mp.u,
                                              check_node,
                                              u_corr,
                                              problem.mp.V_u,
                                              problem.mp.comm,
                                              tol=tol,
                                              nm='u')
    success = results_check.success_check([check1], problem.mp.comm)

    return success
def main():

    basepath = str(Path(__file__).parent.absolute())

    IO_PARAMS = {
        'problem_type':
        'solid_constraint',  # solid, fluid, flow0d, solid_flow0d, fluid_flow0d
        'mesh_domain': '' + basepath + '/input/chamber_domain.xdmf',
        'mesh_boundary': '' + basepath + '/input/chamber_boundary.xdmf',
        'write_results_every': -999,
        'output_path': '' + basepath + '/tmp/',
        'results_to_write': ['displacement', 'pressure'],
        'simname': 'solid_constraint_volume_chamber'
    }

    SOLVER_PARAMS_SOLID = {
        'solve_type': 'direct',  # direct, iterative
        'tol_res': 1.0e-8,
        'tol_inc': 1.0e-8
    }

    SOLVER_PARAMS_CONSTR = {'tol_res': 1.0e-8, 'tol_inc': 1.0e-8}

    TIME_PARAMS_SOLID = {
        'maxtime': 1.0,
        'numstep': 10,
        'numstep_stop': 5,
        'timint': 'ost',
        'theta_ost': 1.0
    }

    FEM_PARAMS = {
        'order_disp': 1,
        'order_pres': 1,
        'quad_degree': 1,
        'incompressible_2field': True
    }  # True, False

    CONSTRAINT_PARAMS = {
        'surface_ids': [[3]],
        'constraint_quantity': 'volume',
        'prescribed_curve': [1]
    }

    MATERIALS = {
        'MAT1': {
            'neohooke_dev': {
                'mu': 100.
            },
            'inertia': {
                'rho0': 1.0e-6
            }
        }
    }

    # define your load curves here (syntax: tcX refers to curve X, to be used in BC_DICT key 'curve' : [X,0,0], or 'curve' : X)
    class time_curves():
        def tc1(self, t):
            vini = 1.
            vmax = 2.0
            return (vmax - vini) * t / TIME_PARAMS_SOLID['maxtime'] + vini

    BC_DICT = {
        'dirichlet': [{
            'id': [1],
            'dir': 'x',
            'val': 0.
        }, {
            'id': [3],
            'dir': 'y',
            'val': 0.
        }, {
            'id': [3],
            'dir': 'z',
            'val': 0.
        }]
    }

    # problem setup
    problem = ambit.Ambit(IO_PARAMS,
                          TIME_PARAMS_SOLID,
                          [SOLVER_PARAMS_SOLID, SOLVER_PARAMS_CONSTR],
                          FEM_PARAMS,
                          MATERIALS,
                          BC_DICT,
                          time_curves=time_curves(),
                          coupling_params=CONSTRAINT_PARAMS)

    # solve time-dependent problem
    problem.solve_problem()

    # --- results check
    tol = 1.0e-6

    check_node = []
    check_node.append(np.array([1.5, 0.75, 0.75]))

    u_corr = np.zeros(3 * len(check_node))

    ## correct results
    u_corr[0] = 7.1440094913591246E-01  # x
    u_corr[1] = -1.1768897247463314E-02  # y
    u_corr[2] = 4.5878411920493023E-03  # z

    check1 = results_check.results_check_node(problem.mp.pbs.u,
                                              check_node,
                                              u_corr,
                                              problem.mp.pbs.V_u,
                                              problem.mp.comm,
                                              tol=tol,
                                              nm='u')
    success = results_check.success_check([check1], problem.mp.comm)

    return success