Пример #1
0
def fe_solve(exo_io, runid, control, X, connect, elements, fixnodes,
             tractions, nforces, nproc=1):
    """ 2D and 3D Finite Element Code

    Currently configured to run either plane strain in 2D or general 3D but
    could easily be modified for plane stress or axisymmetry.

    Parameters
    ----------
    control : array_like, (i,)
        control[0] -> time integration scheme
        control[1] -> number of steps
        control[2] -> Newton tolerance
        control[3] -> maximum Newton iterations
        control[4] -> relax
        control[5] -> starting time
        control[6] -> termination time
        control[7] -> time step multiplier

    X : array like, (i, j,)
        Nodal coordinates
        X[i, j] -> jth coordinate of ith node for i=1...nnode, j=1...ncoord

    connect : array_like, (i, j,)
        Nodal connections
        connect[i, j] -> jth node on  on the ith element

    elements : array_like, (i,)
        Element class for each element

    fixnodes : array_like, (i, j,)
        List of prescribed displacements at nodes
            fixnodes[i, 0] -> Node number
            fixnodes[i, 1] -> Displacement component (x: 0, y: 1, or z: 2)
            fixnodes[i, 2] -> Value of the displacement

    tractions : array_like, (i, j,)
        List of element tractions
            tractions[i, 0] -> Element number
            tractions[i, 1] -> face number
            tractions[i, 2:] -> Components of traction as a function of time

    Returns
    -------
    retval : init
        0 on completion
        failure otherwise

    Notes
    -----
    Original code was adapted from [1].

    References
    ----------
    1. solidmechanics.org

    """
    # Local Variables
    # ---------------
    # du : array_like, (i,)
    #     Nodal displacements.
    #     Let wij be jth displacement component at ith node. Then du
    #     contains [w00, w01, w10, w11, ...] for 2D
    #     and [w00, w01, w02, w10, w11, w12, ...) for 3D

    # dw : array_like, (i,)
    #     Correction to nodal displacements.

    # K : array_like, (i, j,)
    #     Global stiffness matrix. Stored as
    #              [K_1111 K_1112 K_1121 K_1122...
    #               K_1211 K_1212 K_1221 K_1222...
    #               K_2111 K_2112 K_2121 K_2122...]
    #     for 2D problems and similarly for 3D problems

    # F : array_like, (i, )
    #     Force vector.
    #     Currently only includes contribution from tractions acting on
    #     element faces (body forces are neglected)
    # R : array_like, (i, )
    #     Volume contribution to residual
    # b : array_like (i, )
    #     RHS of equation system

    # number of processors
    nproc = np.amin([mp.cpu_count(), nproc, elements.size])

    # Set up timing and logging
    t0 = time.time()
    logger = Logger(runid)

    # Problem dimensions
    dim = elements[0].ndof
    nelems = elements.shape[0]
    nnode = X.shape[0]
    ndof = elements[0].ndof
    ncoord = elements[0].ncoord

    # Setup kinematic variables
    u = np.zeros((2, nnode * ndof))
    v = np.zeros((2, nnode * ndof))
    a = np.zeros((2, nnode * ndof))

    #  Simulation setup
    tint, nsteps, tol, maxit, relax, tstart, tterm, dtmult = control
    nsteps, maxit = int(nsteps), int(maxit)
    t = tstart
    dt = (tterm - tstart) / float(nsteps) * dtmult

    # Newmark parameters
    b = [.5, 0.]

    # Global mass, find only once
    M = global_mass(X, elements, connect, nproc)

    # Determine initial accelerations
    du = np.diff(u, axis=0)[0]
    K = global_stiffness(0., 1., X, elements, connect, du, nproc)
    findstiff = False
    F = global_traction(
        0., 1., X, elements, connect, tractions, nforces, du)
    apply_dirichlet_bcs(ndof, nnode, 0., fixnodes, u[0], du, 1., K, F, M)
    a[0] = np.linalg.solve(M, -np.dot(K, u[0]) + F)

    logger.write_intro("Explicit", runid, nsteps, tol, maxit, relax, tstart,
                       tterm, ndof, nelems, nnode))

    for step in range(nsteps):

        err1 = 1.
        t += dt

        logger.write(
            "Step {0:.5f}, Time: {1}, Time step: {2}".format(step + 1, t, dt))

        # --- Update the state of each element to end of step
        du = np.diff(u, axis=0)[0]
        update_element_states(dt, X, elements, connect, du)


        # --- Get global quantities
        K = global_stiffness(
            t, dt, X, elements, connect, du, nproc)
Пример #2
0
    def solve(self, nproc=1, disp=0):
        """ 2D and 3D Finite Element Code

        Currently configured to run either plane strain in 2D or general 3D but
        could easily be modified for plane stress or axisymmetry.

        """
        # Local Variables
        # ---------------
        # du : array_like, (i,)
        #     Nodal displacements.
        #     Let wij be jth displacement component at ith node. Then du
        #     contains [w00, w01, w10, w11, ...] for 2D
        #     and [w00, w01, w02, w10, w11, w12, ...) for 3D

        # dw : array_like, (i,)
        #     Correction to nodal displacements.

        # K : array_like, (i, j,)
        #     Global stiffness matrix. Stored as
        #              [K_1111 K_1112 K_1121 K_1122...
        #               K_1211 K_1212 K_1221 K_1222...
        #               K_2111 K_2112 K_2121 K_2122...]
        #     for 2D problems and similarly for 3D problems

        # F : array_like, (i, )
        #     Force vector.
        #     Currently only includes contribution from tractions acting on
        #     element faces (body forces are neglected)
        # R : array_like, (i, )
        #     Volume contribution to residual
        # b : array_like (i, )
        #     RHS of equation system
        runid = self.runid
        control = self.control_params()
        X = self.mesh.nodes()
        connect = self.mesh.connect()
        elements = self.mesh.elements()
        fixnodes = self.mesh.displacement_bcs()
        nforces = self.mesh.nodal_forces()
        tractions = self.mesh.traction_bcs()

        t0 = time.time()

        dim = elements[0].ndof
        nelems = elements.shape[0]
        nnode = X.shape[0]
        ndof = elements[0].ndof
        ncoord = elements[0].ncoord
        u = np.zeros((nnode * ndof))
        du = np.zeros((nnode * ndof))
        nodal_stresses = np.zeros((nnode, 6))
        # tjf: nodal_state will have to be adjusted for multi-material where
        # each node may be connected to elements of different material.
        # nodal_state = np.zeros((nnode, max(el.material.nxtra for el in elements)))

        nproc = 1.

        #  Simulation setup
        (tint, nsteps, tol, maxit, relax, tstart,
         tterm, dtmult, verbosity) = control

        nsteps, maxit = int(nsteps), int(maxit)
        t = tstart
        dt = (tterm - tstart) / float(nsteps) * dtmult
        global_data.set_var("TIME", t)
        global_data.set_var("TIME_STEP", dt)
        nodal_data.set_var("DISPL", u)

        findstiff = True

        logger.write_intro("Implicit", runid, nsteps, tol,
                            maxit, relax, tstart, tterm,
                            ndof, nelems, nnode, elements)

        logger.write(HEAD)

        for step in range(nsteps):

            loadfactor = float(step + 1) / float(nsteps)
            err1 = 1.
            t += dt

            # Newton-Raphson loop
            mult = 10 if step == 0 and ro.reducedint else 1
            for nit in range(mult * maxit):

                # --- Update the state of each element to end of Newton step
                update_element_states(t, dt, X, elements, connect, u, du)

                # --- Update nodal stresses
                for (inode, els) in enumerate(self.mesh._node_el_map):
                    sig = np.zeros(6)
                    # nx = elements[els[0]].material.nxtra
                    # xtra = np.zeros(nx)
                    acc_volume = 0.
                    for iel in els:
                        if iel == -1:
                            break
                        el = elements[iel]
                        vol = el._volume
                        sig += el.element_data(ave=True, item="STRESS") * vol
                        # xtra += el.element_data(ave=True, item="XTRA") * vol
                        acc_volume += vol
                    nodal_stresses[inode][:] = sig / acc_volume
                    # nodal_state[inode][0:nx] = xtra / acc_volume
                    continue

                # --- Get global quantities
                if findstiff:
                    gK = global_stiffness(t, dt, X, elements, connect, du, nproc)
                    findstiff = False
                K = np.array(gK)
                F = global_traction(t, dt, X, elements, connect,
                                    tractions, nforces, du)
                R = global_residual(t, dt, X, elements, connect, du)
                b = loadfactor * F - R

                apply_dirichlet_bcs(ndof, nnode, t, fixnodes, u, du,
                                    loadfactor, K, b)

                # --- Solve for the correction
                c, dw, info = linsolve(K, b)
                if info > 0:
                    logger.write("using least squares to solve system",
                                  beg="*** ")
                    dw = np.linalg.lstsq(K, b)[0]
                elif info < 0:
                    raise WasatchError(
                        "illegal value in %d-th argument of internal dposv" % -info)

                # --- update displacement increment
                du += relax * dw

                # --- Check convergence
                wnorm = np.dot(du, du)
                err1 = np.dot(dw, dw)
                if err1 > 1.E-10:
                    findstiff = True
                if wnorm != 0.:
                    err1 = np.sqrt(err1 / wnorm)
                err2 = np.sqrt(np.dot(b, b)) / float(ndof * nnode)

                logger.write_formatted(step+1, nit+1, loadfactor, t, dt,
                                       err1, err2, tol, fmt=ITER_FMT) 
                if err1 < tol:
                    break

                continue

            else:
                raise WasatchError("Problem did not converge")

            # Update the total displacecment
            u += du

            # Update the nodal coordinates
            x = np.zeros((nnode, ndof))
            for i in range(nnode):
                for j in range(ndof):
                    x[i, j] = X[i, j] + u[ndof * i + j]
                    continue
                continue

            # Advance the state of each element
            for element in elements:
                element.advance_state()

            global_data.set_var("TIME", t)
            global_data.set_var("TIME_STEP", dt)
            nodal_data.set_var("DISPL", u)

            self.io.write_data_to_db()

            continue

        self.io.finish()
        tf = time.time()

        logger.write("\n{0}: execution finished".format(self.runid))
        logger.write("{0}: total execution time: {1:8.6f}s".format(
                runid, tf - t0))

        retval = 0
        if disp:
            retval = {
                "DISPLACEMENT": u, "TIME": t, "DT": dt,
                "ELEMENT DATA": np.array([el.element_data() for el in elements]),
                "NODAL STRESSES": nodal_stresses,
                # "NODAL STATES": nodal_state,
                "NODAL COORDINATES": x}

        return retval
Пример #3
0
    def solve(self, nproc=1, disp=0):
        """ 2D and 3D Finite Element Code

        Currently configured to run either plane strain in 2D or general 3D but
        could easily be modified for plane stress or axisymmetry.

        """
        # Local Variables
        # ---------------
        # du : array_like, (i,)
        #     Nodal displacements.
        #     Let wij be jth displacement component at ith node. Then du
        #     contains [w00, w01, w10, w11, ...] for 2D
        #     and [w00, w01, w02, w10, w11, w12, ...) for 3D

        # dw : array_like, (i,)
        #     Correction to nodal displacements.

        # K : array_like, (i, j,)
        #     Global stiffness matrix. Stored as
        #              [K_1111 K_1112 K_1121 K_1122...
        #               K_1211 K_1212 K_1221 K_1222...
        #               K_2111 K_2112 K_2121 K_2122...]
        #     for 2D problems and similarly for 3D problems

        # F : array_like, (i, )
        #     Force vector.
        #     Currently only includes contribution from tractions acting on
        #     element faces (body forces are neglected)
        # R : array_like, (i, )
        #     Volume contribution to residual
        # b : array_like (i, )
        #     RHS of equation system
        runid = self.runid
        control = self.control_params()
        X = self.mesh.nodes()
        connect = self.mesh.connect()
        elements = self.mesh.elements()
        fixnodes = self.mesh.displacement_bcs()
        nforces = self.mesh.nodal_forces()
        tractions = self.mesh.traction_bcs()

        t0 = time.time()

        dim = elements[0].ndof
        nelems = elements.shape[0]
        nnode = X.shape[0]
        ndof = elements[0].ndof
        ncoord = elements[0].ncoord
        u = np.zeros((nnode * ndof))
        du = np.zeros((nnode * ndof))
        nodal_stresses = np.zeros((nnode, 6))
        # tjf: nodal_state will have to be adjusted for multi-material where
        # each node may be connected to elements of different material.
        # nodal_state = np.zeros((nnode, max(el.material.nxtra for el in elements)))

        nproc = 1.

        #  Simulation setup
        (tint, nsteps, tol, maxit, relax, tstart, tterm, dtmult,
         verbosity) = control

        nsteps, maxit = int(nsteps), int(maxit)
        t = tstart
        dt = (tterm - tstart) / float(nsteps) * dtmult
        global_data.set_var("TIME", t)
        global_data.set_var("TIME_STEP", dt)
        nodal_data.set_var("DISPL", u)

        findstiff = True

        logger.write_intro("Implicit", runid, nsteps, tol, maxit, relax,
                           tstart, tterm, ndof, nelems, nnode, elements)

        logger.write(HEAD)

        for step in range(nsteps):

            loadfactor = float(step + 1) / float(nsteps)
            err1 = 1.
            t += dt

            # Newton-Raphson loop
            mult = 10 if step == 0 and ro.reducedint else 1
            for nit in range(mult * maxit):

                # --- Update the state of each element to end of Newton step
                update_element_states(t, dt, X, elements, connect, u, du)

                # --- Update nodal stresses
                for (inode, els) in enumerate(self.mesh._node_el_map):
                    sig = np.zeros(6)
                    # nx = elements[els[0]].material.nxtra
                    # xtra = np.zeros(nx)
                    acc_volume = 0.
                    for iel in els:
                        if iel == -1:
                            break
                        el = elements[iel]
                        vol = el._volume
                        sig += el.element_data(ave=True, item="STRESS") * vol
                        # xtra += el.element_data(ave=True, item="XTRA") * vol
                        acc_volume += vol
                    nodal_stresses[inode][:] = sig / acc_volume
                    # nodal_state[inode][0:nx] = xtra / acc_volume
                    continue

                # --- Get global quantities
                if findstiff:
                    gK = global_stiffness(t, dt, X, elements, connect, du,
                                          nproc)
                    findstiff = False
                K = np.array(gK)
                F = global_traction(t, dt, X, elements, connect, tractions,
                                    nforces, du)
                R = global_residual(t, dt, X, elements, connect, du)
                b = loadfactor * F - R

                apply_dirichlet_bcs(ndof, nnode, t, fixnodes, u, du,
                                    loadfactor, K, b)

                # --- Solve for the correction
                c, dw, info = linsolve(K, b)
                if info > 0:
                    logger.write("using least squares to solve system",
                                 beg="*** ")
                    dw = np.linalg.lstsq(K, b)[0]
                elif info < 0:
                    raise WasatchError(
                        "illegal value in %d-th argument of internal dposv" %
                        -info)

                # --- update displacement increment
                du += relax * dw

                # --- Check convergence
                wnorm = np.dot(du, du)
                err1 = np.dot(dw, dw)
                if err1 > 1.E-10:
                    findstiff = True
                if wnorm != 0.:
                    err1 = np.sqrt(err1 / wnorm)
                err2 = np.sqrt(np.dot(b, b)) / float(ndof * nnode)

                logger.write_formatted(step + 1,
                                       nit + 1,
                                       loadfactor,
                                       t,
                                       dt,
                                       err1,
                                       err2,
                                       tol,
                                       fmt=ITER_FMT)
                if err1 < tol:
                    break

                continue

            else:
                raise WasatchError("Problem did not converge")

            # Update the total displacecment
            u += du

            # Update the nodal coordinates
            x = np.zeros((nnode, ndof))
            for i in range(nnode):
                for j in range(ndof):
                    x[i, j] = X[i, j] + u[ndof * i + j]
                    continue
                continue

            # Advance the state of each element
            for element in elements:
                element.advance_state()

            global_data.set_var("TIME", t)
            global_data.set_var("TIME_STEP", dt)
            nodal_data.set_var("DISPL", u)

            self.io.write_data_to_db()

            continue

        self.io.finish()
        tf = time.time()

        logger.write("\n{0}: execution finished".format(self.runid))
        logger.write("{0}: total execution time: {1:8.6f}s".format(
            runid, tf - t0))

        retval = 0
        if disp:
            retval = {
                "DISPLACEMENT": u,
                "TIME": t,
                "DT": dt,
                "ELEMENT DATA":
                np.array([el.element_data() for el in elements]),
                "NODAL STRESSES": nodal_stresses,
                # "NODAL STATES": nodal_state,
                "NODAL COORDINATES": x
            }

        return retval