示例#1
0
def run_pm4sand_et(sl,
                   csr,
                   esig_v0=101.0e3,
                   static_bias=0.0,
                   n_lim=100,
                   k0=0.5,
                   strain_limit=0.03,
                   strain_inc=5.0e-6,
                   etype='implicit'):

    nu_init = k0 / (1 + k0)
    damp = 0.02
    omega0 = 0.2
    omega1 = 20.0
    a1 = 2. * damp / (omega0 + omega1)
    a0 = a1 * omega0 * omega1

    # Initialise OpenSees instance
    osi = o3.OpenSeesInstance(ndm=2, ndf=3, state=3)

    # Establish nodes
    h_ele = 1.
    bl_node = o3.node.Node(osi, 0, 0)
    br_node = o3.node.Node(osi, h_ele, 0)
    tr_node = o3.node.Node(osi, h_ele, h_ele)
    tl_node = o3.node.Node(osi, 0, h_ele)
    all_nodes = [bl_node, br_node, tr_node, tl_node]

    # Fix bottom node
    o3.Fix3DOF(osi, bl_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)
    o3.Fix3DOF(osi, br_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)
    o3.Fix3DOF(osi, tr_node, o3.cc.FREE, o3.cc.FREE, o3.cc.FIXED)
    o3.Fix3DOF(osi, tl_node, o3.cc.FREE, o3.cc.FREE, o3.cc.FIXED)
    # Set out-of-plane DOFs to be slaved
    o3.EqualDOF(osi, tr_node, tl_node, [o3.cc.X, o3.cc.Y])

    # Define material
    pm4sand = o3.nd_material.PM4Sand(osi,
                                     sl.relative_density,
                                     sl.g0_mod,
                                     sl.h_po,
                                     sl.unit_sat_mass,
                                     101.3,
                                     nu=nu_init)

    # Note water bulk modulus is irrelevant since constant volume test - so as soil skeleton contracts
    # the bulk modulus of the soil skeleton controls the change in effective stress
    water_bulk_mod = 2.2e6
    ele = o3.element.SSPquadUP(osi,
                               all_nodes,
                               pm4sand,
                               1.0,
                               water_bulk_mod,
                               1.,
                               sl.permeability,
                               sl.permeability,
                               sl.e_curr,
                               alpha=1.0e-5,
                               b1=0.0,
                               b2=0.0)

    o3.constraints.Transformation(osi)
    o3.test_check.NormDispIncr(osi, tol=1.0e-6, max_iter=35, p_flag=0)
    o3.numberer.RCM(osi)
    omegas = np.array(o3.get_eigen(osi, n=1))**0.5
    periods = 2 * np.pi / omegas
    periods = [0.001]
    if etype == 'implicit':
        o3.algorithm.Newton(osi)
        o3.system.FullGeneral(osi)
        o3.integrator.Newmark(osi, gamma=5. / 6, beta=4. / 9)
        dt = 0.01
    else:
        o3.algorithm.Linear(osi, factor_once=True)
        o3.system.FullGeneral(osi)
        if etype == 'newmark_explicit':
            o3.integrator.NewmarkExplicit(osi, gamma=0.5)
            explicit_dt = periods[0] / np.pi / 8
        elif etype == 'central_difference':
            o3.integrator.CentralDifference(osi)
            explicit_dt = periods[0] / np.pi / 16  # 0.5 is a factor of safety
        elif etype == 'hht_explicit':
            o3.integrator.HHTExplicit(osi, alpha=0.5)
            explicit_dt = periods[0] / np.pi / 8
        elif etype == 'explicit_difference':
            o3.integrator.ExplicitDifference(osi)
            explicit_dt = periods[0] / np.pi / 4
        else:
            raise ValueError(etype)
        print('explicit_dt: ', explicit_dt)
        dt = explicit_dt
    o3.analysis.Transient(osi)
    freqs = [0.5, 10]
    xi = 0.1
    use_modal_damping = 0
    if use_modal_damping:
        omega_1 = 2 * np.pi * freqs[0]
        omega_2 = 2 * np.pi * freqs[1]
        a0 = 2 * xi * omega_1 * omega_2 / (omega_1 + omega_2)
        a1 = 2 * xi / (omega_1 + omega_2)
        o3.rayleigh.Rayleigh(osi, a0, 0, a1, 0)
    else:
        o3.ModalDamping(osi, [xi])

    o3.update_material_stage(osi, pm4sand, stage=0)
    # print('here1: ', o3.get_ele_response(osi, ele, 'stress'), esig_v0, csr)

    all_stresses_cache = o3.recorder.ElementToArrayCache(osi,
                                                         ele,
                                                         arg_vals=['stress'])
    all_strains_cache = o3.recorder.ElementToArrayCache(osi,
                                                        ele,
                                                        arg_vals=['strain'])
    nodes_cache = o3.recorder.NodesToArrayCache(osi,
                                                all_nodes,
                                                dofs=[1, 2, 3],
                                                res_type='disp')
    o3.recorder.NodesToFile(osi,
                            'node_disp.txt',
                            all_nodes,
                            dofs=[1, 2, 3],
                            res_type='disp')

    # Add static vertical pressure and stress bias
    ttime = 30
    time_series = o3.time_series.Path(osi,
                                      time=[0, ttime, 1e10],
                                      values=[0, 1, 1])
    o3.pattern.Plain(osi, time_series)
    o3.Load(osi, tl_node, [0, -esig_v0 / 2, 0])
    o3.Load(osi, tr_node, [0, -esig_v0 / 2, 0])

    o3.analyze(osi, num_inc=int(ttime / dt) + 10, dt=dt)

    ts2 = o3.time_series.Path(osi,
                              time=[ttime, 80000, 1e10],
                              values=[1., 1., 1.],
                              factor=1)
    o3.pattern.Plain(osi, ts2, fact=1.)
    y_vert = o3.get_node_disp(osi, tr_node, o3.cc.Y)
    o3.SP(osi, tl_node, dof=o3.cc.Y, dof_values=[y_vert])
    o3.SP(osi, tr_node, dof=o3.cc.Y, dof_values=[y_vert])

    # Close the drainage valves
    for node in all_nodes:
        o3.remove_sp(osi, node, dof=3)
    o3.analyze(osi, int(5 / dt), dt=dt)
    print('here3: ', o3.get_ele_response(osi, ele, 'stress'), esig_v0, csr)

    o3.update_material_stage(osi, pm4sand, stage=1)
    o3.set_parameter(osi, value=0, eles=[ele], args=['FirstCall', pm4sand.tag])
    o3.analyze(osi, int(5 / dt), dt=dt)
    o3.set_parameter(osi,
                     value=sl.poissons_ratio,
                     eles=[ele],
                     args=['poissonRatio', pm4sand.tag])

    o3.extensions.to_py_file(osi)

    n_cyc = 0.0
    target_strain = 1.1 * strain_limit
    target_disp = target_strain * h_ele
    limit_reached = 0
    export = 1
    while n_cyc < n_lim:
        print('n_cyc: ', n_cyc)
        h_disp = o3.get_node_disp(osi, tr_node, o3.cc.X)
        curr_time = o3.get_time(osi)
        steps = target_strain / strain_inc
        ts0 = o3.time_series.Path(osi,
                                  time=[curr_time, curr_time + steps, 1e10],
                                  values=[h_disp, target_disp, target_disp],
                                  factor=1)
        pat0 = o3.pattern.Plain(osi, ts0)
        o3.SP(osi, tr_node, dof=o3.cc.X, dof_values=[1.0])
        curr_stress = o3.get_ele_response(osi, ele, 'stress')[2]
        if math.isnan(curr_stress):
            raise ValueError

        if export:
            o3.extensions.to_py_file(osi)
            export = 0
        while curr_stress < (csr - static_bias) * esig_v0:
            o3.analyze(osi, int(0.1 / dt), dt=dt)
            curr_stress = o3.get_ele_response(osi, ele, 'stress')[2]
            h_disp = o3.get_node_disp(osi, tr_node, o3.cc.X)
            print(h_disp, target_disp)
            if h_disp >= target_disp:
                print('STRAIN LIMIT REACHED - on load')
                limit_reached = 1
                break
        if limit_reached:
            break
        n_cyc += 0.25
        print('load reversal, n_cyc: ', n_cyc)
        curr_time = o3.get_time(osi)
        o3.remove_load_pattern(osi, pat0)
        o3.remove(osi, ts0)
        o3.remove_sp(osi, tr_node, dof=o3.cc.X)
        # Reverse cycle
        steps = (h_disp + target_disp) / (strain_inc * h_ele)
        ts0 = o3.time_series.Path(osi,
                                  time=[curr_time, curr_time + steps, 1e10],
                                  values=[h_disp, -target_disp, -target_disp],
                                  factor=1)
        pat0 = o3.pattern.Plain(osi, ts0)
        o3.SP(osi, tr_node, dof=o3.cc.X, dof_values=[1.0])
        i = 0
        while curr_stress > -(csr + static_bias) * esig_v0:
            o3.analyze(osi, int(0.1 / dt), dt=dt)
            curr_stress = o3.get_ele_response(osi, ele, 'stress')[2]
            h_disp = o3.get_node_disp(osi, tr_node, o3.cc.X)

            if -h_disp >= target_disp:
                print('STRAIN LIMIT REACHED - on reverse')
                limit_reached = 1
                break
            i += 1
            if i > steps:
                break
        if limit_reached:
            break
        n_cyc += 0.5
        print('reload, n_cyc: ', n_cyc)
        curr_time = o3.get_time(osi)
        o3.remove_load_pattern(osi, pat0)
        o3.remove(osi, ts0)
        o3.remove_sp(osi, tr_node, dof=o3.cc.X)
        # reload cycle
        steps = (-h_disp + target_disp) / (strain_inc * h_ele)
        ts0 = o3.time_series.Path(osi,
                                  time=[curr_time, curr_time + steps, 1e10],
                                  values=[h_disp, target_disp, target_disp],
                                  factor=1)
        pat0 = o3.pattern.Plain(osi, ts0)
        o3.SP(osi, tr_node, dof=o3.cc.X, dof_values=[1.0])
        while curr_stress < static_bias * esig_v0:
            o3.analyze(osi, int(0.1 / dt), dt=dt)
            curr_stress = o3.get_ele_response(osi, ele, 'stress')[2]
            h_disp = o3.get_node_disp(osi, tr_node, o3.cc.X)

            if h_disp >= target_disp:
                print('STRAIN LIMIT REACHED - on reload')
                limit_reached = 1
                break
        if limit_reached:
            break
        o3.remove_load_pattern(osi, pat0)
        o3.remove(osi, ts0)
        o3.remove_sp(osi, tr_node, dof=o3.cc.X)
        n_cyc += 0.25

    o3.wipe(osi)
    all_stresses = all_stresses_cache.collect()
    all_strains = all_strains_cache.collect()
    disps = nodes_cache.collect()
    stress = all_stresses[:, 2]
    strain = all_strains[:, 2]
    ppt = all_stresses[:, 1]

    return stress, strain, ppt, disps

    pass
def get_response(bd, dtype):
    """
    Compute the response of a nonlinear lollipop on a foundation with linear/nonlinear soil
    Units are N, m, s

    :param bd:
        SDOF building object
    :param asig:
        Acceleration signal object
    :return:
    """
    osi = o3.OpenSeesInstance(ndm=2, state=3)

    # Establish nodes
    top_ss_node = o3.node.Node(osi, 0, bd.h_eff)
    bot_ss_node = o3.node.Node(osi, 0, 0)

    # Fix bottom node
    o3.Fix3DOF(osi, bot_ss_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)

    # nodal mass (weight / g):
    o3.Mass(osi, top_ss_node, bd.mass_eff, 0.0, 0)

    # Define a column element with a plastic hinge at base
    transf = o3.geom_transf.Linear2D(osi, [])  # can change for P-delta effects
    area = 1.0
    e_mod = 200.0e9
    iz = bd.k_eff * bd.h_eff**3 / (3 * e_mod)
    ele_nodes = [bot_ss_node, top_ss_node]

    # Superstructure element
    vert_ele = o3.element.ElasticBeamColumn2D(osi,
                                              ele_nodes,
                                              area=area,
                                              e_mod=e_mod,
                                              iz=iz,
                                              transf=transf)

    # define superstructure damping using rotational spring approach from Millen et al. (2017) to avoid double damping
    if dtype == 'rot_link':
        k_rot = bd.k_eff * (2.0 / 3)**2 * bd.h_eff**2
        ss_rot_link_mat = o3.uniaxial_material.Elastic(osi, k_rot)
        sfi_link_ele = o3.element.TwoNodeLink(osi, [bot_ss_node, top_ss_node],
                                              mats=[ss_rot_link_mat],
                                              dir=[o3.cc.DOF2D_ROTZ],
                                              shear_dist=[0.1],
                                              p_delta_vals=[0., 0.])
        print(sfi_link_ele.parameters)
    elif dtype == 'horz_link':
        cxx = bd.xi * 2 * np.sqrt(bd.mass_eff * bd.k_eff)
        cxx *= 0.01
        ss_rot_link_mat = o3.uniaxial_material.Viscous(osi, cxx, alpha=1.)
        sfi_link_ele = o3.element.TwoNodeLink(osi, [bot_ss_node, top_ss_node],
                                              mats=[ss_rot_link_mat],
                                              dirs=[o3.cc.X])
    else:
        omega = 2 * np.pi / bd.t_fixed
        beta_k = 2 * bd.xi / omega
        o3.rayleigh.Rayleigh(osi, 0, 0, beta_k_init=beta_k, beta_k_comm=0.0)

    # Define the input motion for the dynamic analysis
    # acc_series = o3.time_series.Path(osi, dt=asig.dt, values=-asig.values)  # should be negative
    # o3.pattern.UniformExcitation(osi, dir=o3.cc.X, accel_series=acc_series)
    # print('loaded gm')
    # o3.wipe_analysis(osi)
    ts2 = o3.time_series.Path(osi,
                              time=[0, 100, 1e10],
                              values=[0., 1., 1.],
                              factor=1)
    o3.pattern.Plain(osi, ts2, fact=1.)
    o3.SP(osi, top_ss_node, dof=o3.cc.X, dof_values=[0.2])

    o3.algorithm.Newton(osi)
    o3.system.SparseGeneral(osi)
    o3.numberer.RCM(osi)
    o3.constraints.Transformation(osi)
    o3.integrator.Newmark(osi, 0.5, 0.25)
    o3.analysis.Transient(osi)

    o3.test_check.NormDispIncr(osi, tol=1.0e-6, max_iter=10)
    analysis_time = 80
    analysis_dt = 0.01

    # define outputs of analysis
    od = {
        "time":
        o3.recorder.TimeToArrayCache(osi),
        "rel_deck_disp":
        o3.recorder.NodeToArrayCache(osi, top_ss_node, [o3.cc.DOF2D_X],
                                     'disp'),
        "deck_force":
        o3.recorder.NodeToArrayCache(osi, top_ss_node, [o3.cc.DOF2D_X],
                                     'reaction'),
        "deck_rot":
        o3.recorder.NodeToArrayCache(osi, top_ss_node, [o3.cc.DOF2D_ROTZ],
                                     'disp'),
        "chord_rots":
        o3.recorder.ElementToArrayCache(osi,
                                        vert_ele,
                                        arg_vals=['chordRotation']),
        "col_forces":
        o3.recorder.ElementToArrayCache(osi, vert_ele, arg_vals=[
            'basicForce'
        ]),  # note that 'force' provides global force (includes link)
    }
    if dtype in ['rot_link', 'horz_link']:
        od['link_force'] = o3.recorder.ElementToArrayCache(osi,
                                                           sfi_link_ele,
                                                           arg_vals=['force'])

    o3.analyze(osi, int(analysis_time / analysis_dt), analysis_dt)

    o3.wipe(osi)

    for item in od:
        od[item] = od[item].collect()
    od['col_shear'] = -(od['col_forces'][:, 2] -
                        od['col_forces'][:, 1]) / bd.h_eff
    od['col_moment'] = od['col_forces'][:, 1]
    od['col_moment_end'] = od['col_forces'][:, 2]
    od['hinge_rotation'] = od['chord_rots'][:, 1]
    del od['col_forces']
    del od['chord_rots']

    return od
def run_ts_custom_strain(mat, esig_v0, strains, osi=None, nu_dyn=None, target_d_inc=0.00001, k0=None, etype='newmark_explicit',
                         handle='silent', verbose=0, opyfile=None, dss=False, plain_strain=True, min_n=10, nl=True):
    # if dss:
    #     raise ValueError('dss option is not working')
    damp = 0.05
    omega0 = 0.2
    omega1 = 20.0
    a1 = 2. * damp / (omega0 + omega1)
    a0 = a1 * omega0 * omega1
    if osi is None:
        osi = o3.OpenSeesInstance(ndm=2, ndf=2)
        mat.build(osi)

    # Establish nodes
    h_ele = 1.
    nodes = [
        o3.node.Node(osi, 0.0, 0.0),
        o3.node.Node(osi, h_ele, 0.0),
        o3.node.Node(osi, h_ele, h_ele),
        o3.node.Node(osi, 0.0, h_ele)
    ]

    # Fix bottom node
    o3.Fix2DOF(osi, nodes[0], o3.cc.FIXED, o3.cc.FIXED)
    if k0 is None:
        o3.Fix2DOF(osi, nodes[1], o3.cc.FIXED, o3.cc.FIXED)
        # Set out-of-plane DOFs to be slaved
        o3.EqualDOF(osi, nodes[2], nodes[3], [o3.cc.X, o3.cc.Y])
    else:  # control k0 with node forces
        o3.Fix2DOF(osi, nodes[1], o3.cc.FIXED, o3.cc.FREE)

    if plain_strain:
        oop = 'PlaneStrain'
    else:
        oop = 'PlaneStress'

    ele = o3.element.SSPquad(osi, nodes, mat, oop, 1, 0.0, 0.0)

    angular_freqs = np.array(o3.get_eigen(osi, solver='fullGenLapack', n=2)) ** 0.5
    print('angular_freqs: ', angular_freqs)
    periods = 2 * np.pi / angular_freqs
    xi = 0.03
    o3.ModalDamping(osi, [xi, xi])

    print('periods: ', periods)
    o3.constraints.Transformation(osi)
    o3.test_check.NormDispIncr(osi, tol=1.0e-6, max_iter=35, p_flag=0)
    o3.numberer.RCM(osi)
    if etype == 'implicit':
        o3.algorithm.Newton(osi)
        o3.system.FullGeneral(osi)
        o3.integrator.Newmark(osi, gamma=0.5, beta=0.25)
        dt = 0.01
    else:
        o3.algorithm.Linear(osi, factor_once=True)
        o3.system.FullGeneral(osi)
        if etype == 'newmark_explicit':
            o3.integrator.NewmarkExplicit(osi, gamma=0.5)
            explicit_dt = periods[0] / np.pi / 8
        elif etype == 'central_difference':
            o3.integrator.CentralDifference(osi)
            explicit_dt = periods[0] / np.pi / 16  # 0.5 is a factor of safety
        elif etype == 'hht_explicit':
            o3.integrator.HHTExplicit(osi, alpha=0.5)
            explicit_dt = periods[0] / np.pi / 8
        elif etype == 'explicit_difference':
            o3.integrator.ExplicitDifference(osi)
            explicit_dt = periods[0] / np.pi / 4
        else:
            raise ValueError(etype)
        print('explicit_dt: ', explicit_dt)
        dt = explicit_dt
    o3.analysis.Transient(osi)

    o3.update_material_stage(osi, mat, stage=0)

    # dt = 0.00001
    tload = 60
    n_steps = tload / dt
    # Add static vertical pressure and stress bias
    time_series = o3.time_series.Path(osi, time=[0, tload, 1e10], values=[0, 1, 1])
    o3.pattern.Plain(osi, time_series)
    # ts0 = o3.time_series.Linear(osi, factor=1)
    # o3.pattern.Plain(osi, ts0)

    if k0:
        o3.Load(osi, nodes[2], [-esig_v0 / 2, -esig_v0 / 2])
        o3.Load(osi, nodes[3], [esig_v0 / 2, -esig_v0 / 2])
        o3.Load(osi, nodes[1], [-esig_v0 / 2, 0])
        # node 0 is fixed
    else:
        o3.Load(osi, nodes[2], [0, -esig_v0 / 2])
        o3.Load(osi, nodes[3], [0, -esig_v0 / 2])

    print('Apply init stress to elastic element')
    o3.analyze(osi, num_inc=n_steps, dt=dt)
    stresses = o3.get_ele_response(osi, ele, 'stress')
    print('init_stress0: ', stresses)
    o3.load_constant(osi, tload)

    if hasattr(mat, 'update_to_nonlinear') and nl:
        print('set to nonlinear')
        mat.update_to_nonlinear()
        o3.analyze(osi, 10000, dt=dt)
    # if not nl:
    #     mat.update_to_linear()
    if nu_dyn is not None:
        mat.set_nu(nu_dyn, eles=[ele])
        o3.analyze(osi, 10000, dt=dt)

    # o3.extensions.to_py_file(osi)
    stresses = o3.get_ele_response(osi, ele, 'stress')
    print('init_stress1: ', stresses)

    # Prepare for reading results
    exit_code = None
    stresses = o3.get_ele_response(osi, ele, 'stress')
    if dss:
        o3.gen_reactions(osi)
        force0 = o3.get_node_reaction(osi, nodes[2], o3.cc.DOF2D_X)
        force1 = o3.get_node_reaction(osi, nodes[3], o3.cc.DOF2D_X)
        # force2 = o3.get_node_reaction(osi, nodes[0], o3.cc.DOF2D_X)
        stress = [force1 + force0]
        strain = [o3.get_node_disp(osi, nodes[2], dof=o3.cc.DOF2D_X)]
        sxy_ind = None
        gxy_ind = None
        # iforce0 = o3.get_node_reaction(osi, nodes[0], o3.cc.DOF2D_X)
        # iforce1 = o3.get_node_reaction(osi, nodes[1], o3.cc.DOF2D_X)
        # iforce2 = o3.get_node_reaction(osi, nodes[2], o3.cc.DOF2D_X)
        # iforce3 = o3.get_node_reaction(osi, nodes[3], o3.cc.DOF2D_X)
        # print(iforce0, iforce1, iforce2, iforce3, stresses[2])
    else:
        ro = o3.recorder.load_recorder_options()
        import pandas as pd
        df = pd.read_csv(ro)
        mat_type = ele.mat.type
        dfe = df[(df['mat'] == mat_type) & (df['form'] == oop)]
        df_sxy = dfe[dfe['recorder'] == 'stress']
        outs = df_sxy['outs'].iloc[0].split('-')
        sxy_ind = outs.index('sxy')

        df_gxy = dfe[dfe['recorder'] == 'strain']
        outs = df_gxy['outs'].iloc[0].split('-')
        gxy_ind = outs.index('gxy')
        stress = [stresses[sxy_ind]]
        cur_strains = o3.get_ele_response(osi, ele, 'strain')
        strain = [cur_strains[gxy_ind]]

    time_series = o3.time_series.Path(osi, time=[0, tload, 1e10], values=[0, 1, 1])
    o3.pattern.Plain(osi, time_series)
    disps = list(np.array(strains) * 1)
    d_per_dt = 0.01
    diff_disps = np.diff(disps, prepend=0)
    time_incs = np.abs(diff_disps) / d_per_dt
    approx_n_steps = time_incs / dt
    time_incs = np.where(approx_n_steps < 800, 800 * dt, time_incs)
    approx_n_steps = time_incs / dt
    assert min(approx_n_steps) >= 8, approx_n_steps
    curr_time = o3.get_time(osi)
    times = list(np.cumsum(time_incs) + curr_time)
    disps.append(disps[-1])
    times.append(1e10)

    disps = list(disps)
    n_steps_p2 = int((times[-2] - curr_time) / dt) + 10

    print('n_steps: ', n_steps_p2)
    times.insert(0, curr_time)
    disps.insert(0, 0.0)

    init_disp = o3.get_node_disp(osi, nodes[2], dof=o3.cc.X)

    disps = list(np.array(disps) + init_disp)
    ts0 = o3.time_series.Path(osi, time=times, values=disps, factor=1)
    pat0 = o3.pattern.Plain(osi, ts0)
    o3.SP(osi, nodes[2], dof=o3.cc.X, dof_values=[1])
    o3.SP(osi, nodes[3], dof=o3.cc.X, dof_values=[1])
    print('init_disp: ', init_disp)
    print('path -times: ', times)
    print('path -values: ', disps)

    v_eff = [stresses[1]]
    h_eff = [stresses[0]]
    time = [o3.get_time(osi)]
    for i in range(int(n_steps_p2 / 200)):
        print(i / (n_steps_p2 / 200))
        fail = o3.analyze(osi, 200, dt=dt)
        o3.gen_reactions(osi)

        stresses = o3.get_ele_response(osi, ele, 'stress')
        v_eff.append(stresses[1])
        h_eff.append(stresses[0])
        if dss:
            o3.gen_reactions(osi)
            force0 = o3.get_node_reaction(osi, nodes[2], o3.cc.DOF2D_X)
            force1 = o3.get_node_reaction(osi, nodes[3], o3.cc.DOF2D_X)
            stress.append(force1 + force0)
            strain.append(o3.get_node_disp(osi, nodes[2], dof=o3.cc.DOF2D_X))
        else:
            stress.append(stresses[sxy_ind])
            cur_strains = o3.get_ele_response(osi, ele, 'strain')
            strain.append(cur_strains[gxy_ind])
        time.append(o3.get_time(osi))

        if fail:
            break

    return np.array(stress), np.array(strain)-init_disp, np.array(v_eff), np.array(h_eff), np.array(time), exit_code
示例#4
0
def run_mz_triaxial():
    """
    This function runs an o3seespy equivalent of the ManzariDafalias triaxial compression
    example from https://opensees.berkeley.edu/wiki/index.php/Manzari_Dafalias_Material

    The intention is to demonstrate the compatibility between o3seespy and the Tcl version
    of OpenSees.
    """

    damp = 0.1
    omega0 = 0.0157
    omega1 = 64.123
    a1 = 2. * damp / (omega0 + omega1)
    a0 = a1 * omega0 * omega1

    # Initialise OpenSees instance
    osi = o3.OpenSeesInstance(ndm=3, ndf=4, state=3)

    # Establish nodes
    n_coords = [
        [1.0, 0.0, 0.0],
        [1.0, 1.0, 0.0],
        [0.0, 1.0, 0.0],
        [0.0, 0.0, 0.0],
        [1.0, 0.0, 1.0],
        [1.0, 1.0, 1.0],
        [0.0, 1.0, 1.0],
        [0.0, 0.0, 1.0]
    ]
    nm = []
    for nc in n_coords:
        nm.append(o3.node.Node(osi, *nc))

    o3.Fix4DOF(osi, nm[0], o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)
    o3.Fix4DOF(osi, nm[1], o3.cc.FREE, o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED)
    o3.Fix4DOF(osi, nm[2], o3.cc.FIXED, o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED)
    o3.Fix4DOF(osi, nm[3], o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED)
    o3.Fix4DOF(osi, nm[4], o3.cc.FREE, o3.cc.FIXED, o3.cc.FREE, o3.cc.FIXED)
    o3.Fix4DOF(osi, nm[5], o3.cc.FREE, o3.cc.FREE, o3.cc.FREE, o3.cc.FIXED)
    o3.Fix4DOF(osi, nm[6], o3.cc.FIXED, o3.cc.FREE, o3.cc.FREE, o3.cc.FIXED)
    o3.Fix4DOF(osi, nm[7], o3.cc.FIXED, o3.cc.FIXED, o3.cc.FREE, o3.cc.FIXED)

    # Define material
    p_conf = -300.0  # confinement stress
    dev_disp = -0.3  # deviatoric strain
    perm = 1.0e-10  # permeability
    e_curr = 0.8  # void ratio

    mzmod = o3.nd_material.ManzariDafalias(osi, g0=125, nu=0.05, e_init=0.8, m_c=1.25, c_c=0.712, lambda_c=0.019,
                                              e_0=0.934, ksi=0.7, p_atm=100, m_yield=0.01, h_0=7.05, c_h=0.968, n_b=1.1,
                                              a_0=0.704, n_d=3.5, z_max=4, c_z=600, den=1.42)

    water_bulk_mod = 2.2e6
    f_den = 1.0
    ele = o3.element.SSPbrickUP(osi, nm, mzmod, water_bulk_mod, f_den, perm,
                                perm, perm, void=e_curr, alpha=1.5e-9, b1=0.0, b2=0.0, b3=0.0)

    all_stresses_cache = o3.recorder.ElementToArrayCache(osi, ele, arg_vals=['stress'], fname='stresses_03.txt')
    all_strains_cache = o3.recorder.ElementToArrayCache(osi, ele, arg_vals=['strain'], fname='strains_03.txt')
    nodes_cache = o3.recorder.NodesToArrayCache(osi, nm, dofs=[1, 2, 3], res_type='disp')

    o3.constraints.Penalty(osi, 1.0e18, 1.0e18)
    o3.test_check.NormDispIncr(osi, tol=1.0e-5, max_iter=20, p_flag=0)
    o3.algorithm.Newton(osi)
    o3.numberer.RCM(osi)
    o3.system.BandGeneral(osi)
    o3.integrator.Newmark(osi, gamma=0.5, beta=0.25)
    o3.rayleigh.Rayleigh(osi, a0, 0.0, a1, 0.0)
    o3.analysis.Transient(osi)

    # Add static vertical pressure and stress bias
    p_node = p_conf / 4.0
    time_series = o3.time_series.Path(osi, time=[0, 10000, 1e10], values=[0, 1, 1])
    o3.pattern.Plain(osi, time_series)
    o3.Load(osi, nm[0], [p_node, 0, 0, 0])
    o3.Load(osi, nm[1], [p_node, p_node, 0, 0])
    o3.Load(osi, nm[2], [0, p_node, 0, 0])
    o3.Load(osi, nm[3], [0, 0, 0, 0])
    o3.Load(osi, nm[4], [p_node, 0, p_node, 0])
    o3.Load(osi, nm[5], [p_node, p_node, p_node, 0])
    o3.Load(osi, nm[6], [0, p_node, p_node, 0])
    o3.Load(osi, nm[7], [0, 0, p_node, 0])

    o3.analyze(osi, num_inc=100, dt=100)
    o3.analyze(osi, 50, 100)

    # Close the drainage valves
    for node in nm:
        o3.remove_sp(osi, node, dof=4)
    o3.analyze(osi, 50, dt=100)

    z_vert = o3.get_node_disp(osi, nm[4], o3.cc.DOF3D_Z)
    l_values = [1, 1 + dev_disp / z_vert, 1 + dev_disp / z_vert]
    ts2 = o3.time_series.Path(osi, time=[20000, 1020000, 10020000], values=l_values, factor=1)
    o3.pattern.Plain(osi, ts2, fact=1.)
    o3.SP(osi, nm[4], dof=o3.cc.DOF3D_Z, dof_values=[z_vert])
    o3.SP(osi, nm[5], dof=o3.cc.DOF3D_Z, dof_values=[z_vert])
    o3.SP(osi, nm[6], dof=o3.cc.DOF3D_Z, dof_values=[z_vert])
    o3.SP(osi, nm[7], dof=o3.cc.DOF3D_Z, dof_values=[z_vert])

    o3.extensions.to_py_file(osi)

    dt = 100
    num_step = 10000

    rem_step = num_step

    def sub_step_analyze(dt, sub_step):
        loc_success = 0
        if sub_step > 10:
            return -10
        for i in range(1, 3):
            print(f'try dt = {dt}')
            loc_success = o3.analyze(osi, 1, dt)
            if loc_success != 0:
                loc_success = sub_step_analyze(dt / 2., sub_step + 1)
                if success == -1:
                    print('Did not converge.')
                    return loc_success
            else:
                if i == 1:
                    print(f'Substep {sub_step}: Left side converged with dt = {dt}')
                else:
                    print(f'Substep {sub_step}: Right side converged with dt = {dt}')
        return loc_success

    print('Start analysis')
    start_t = time.process_time()
    success = 0
    while success != -10:
        sub_step = 0
        success = o3.analyze(osi, rem_step, dt)
        if success == 0:
            print('Analysis Finished')
            break
        else:
            cur_time = o3.get_time(osi)
            print(f'Analysis failed at {cur_time} . Try substepping.')
            success = sub_step_analyze(dt / 2, sub_step + 1)
            cur_step = int((cur_time - 20000) / dt + 1)
            rem_step = int(num_step - cur_step)
            print(f'Current step: {cur_step}, Remaining steps: {rem_step}')

    end_t = time.process_time()
    print(f'loading analysis execution time: {end_t - start_t:.2f} seconds.')

    o3.wipe(osi)
    all_stresses = all_stresses_cache.collect()
    all_strains = all_strains_cache.collect()
    disps = nodes_cache.collect()

    return all_stresses, all_strains, disps

    pass