예제 #1
0
    def yield_test(self, pointset, total_strain, plastic_strain, stress,
                   modulus):
        # Locally-defined tolerances -- these should maybe be
        # parameters for the property itself.  When these
        # tolerances are met, the Newton-Raphson iterations are over.
        yield_tolerance = 1.E-06
        resid_tolerance = 1.E-06
        iteration_max = 100
        for (p, e, ep, sigma, cijkl) in zip(pointset, total_strain,
                                            plastic_strain, stress, modulus):
            yld = self.yield_func(sigma)
            print "Yield function gives ", yld
            if yld > 0.0:

                # "Initial guess" for plastic increment amounts.
                gamma = 0.0
                delta_ep = SymmMatrix(3)

                # Allocate "work" matrices.
                mtx = smallmatrix.SmallMatrix(7, 7)
                rhs = smallmatrix.SmallMatrix(7, 1)

                # Compute matrix r, measure norm.
                r_matrix = SymmMatrix(3)
                r_norm = 0.0
                dyld = self.d_yield_func(sigma)
                for kl in SymTensorIndex(0, 0):
                    klr = kl.row()
                    klc = kl.col()
                    r_matrix[klr,
                             klc] = delta_ep[klr, klc] - gamma * dyld[klr, klc]
                    r_norm += r_matrix[klr, klc]**2
                r_norm = math.sqrt(r_norm)
                #
                # Repeat until converged....
                iteration_count = 0
                # On entry to the loop, you must have a valid yield
                # function value yld, derivative dyld, and both
                # r_matrix and r_norm computed for the current stress,
                # and gamma and delta_ep must be valid.
                while ((math.fabs(yld)>yield_tolerance) or \
                       (r_norm > resid_tolerance)) and \
                       iteration_count<iteration_max:
                    iteration_count += 1
                    #
                    # RHS is easy.
                    for kl in SymTensorIndex(0, 0):
                        rhs[kl.integer(), 0] = -r_matrix[kl.row(), kl.col()]
                    rhs[6, 0] = -yld

                    mtx.clear()

                    #
                    # MTX is slightly more involved.
                    for kl in SymTensorIndex(0, 0):
                        klr = kl.row()
                        klc = kl.col()

                        mtx[kl.integer(), 6] = -dyld[klr, klc]

                        for mn in SymTensorIndex(0, 0):
                            mnr = mn.row()
                            mnc = mn.col()
                            #
                            if (klr == mnr) and (klc == mnc):
                                mtx[kl.integer(), mn.integer()] += 1.0

                            mtx[6, mn.integer()] -= (
                                dyld[klr, klc] *
                                cijkl[kl.integer(), mn.integer()])

                            if gamma != 0.0:
                                for op in SymTensorIndex(0, 0):
                                    opr = op.row()
                                    opc = op.col()
                                    #
                                    mtx[kl.integer(), mn.integer()] += (
                                        gamma * cijkl[op.integer(),
                                                      mn.integer()]*\
                                        self.d_d_yield_func(klr,klc, opr,opc,
                                                            sigma))

                    # Mtx is now built.  Whee.
                    rcode = mtx.solve(rhs)

                    if rcode != 0:
                        raise ErrUserError(
                            "Nonzero return code in matrix solver.")

                    # Increment gamma and delta_ep, then use them to
                    # recompute sigma, yld, dyld, r_matrix and r_norm.
                    # then go around again.
                    for kl in SymTensorIndex(0, 0):
                        kli = kl.integer()
                        klr = kl.row()
                        klc = kl.col()
                        delta_ep[klr, klc] += rhs[kli, 0]
                    gamma += rhs[6, 0]

                    # Modify stress according to the increment of
                    # delta_ep (*not* delta_ep itself!)
                    for kl in SymTensorIndex(0, 0):
                        for mn in SymTensorIndex(0, 0):
                            sigma[kl.integer()] -= cijkl[kl.integer(),
                                                         mn.integer()]*\
                                                         rhs[mn.integer(),0]

                    yld = self.yield_func(sigma)
                    dyld = self.d_yield_func(sigma)

                    r_norm = 0.0
                    for kl in SymTensorIndex(0, 0):
                        klr = kl.row()
                        klc = kl.col()
                        r_matrix[klr,klc]=delta_ep[klr,klc] -\
                                           gamma*dyld[klr,klc]
                        r_norm += r_matrix[klr, klc]**2
                    r_norm = math.sqrt(r_norm)

                # Exit the convergence while loop.
                if iteration_count == 1:
                    print "Exiting while loop after 1 iteration."
                else:
                    print "Exiting while loop after %d iterations." %\
                          iteration_count
                print "Yield, resid are ", yld, r_norm

                for ij in SymTensorIndex(0, 0):
                    ijr = ij.row()
                    ijc = ij.col()
                    ep[ijr, ijc] += delta_ep[ijr, ijc]

                print "Plastic strain modified."
예제 #2
0
    def _undisplaced_from_displaced_with_element(self, mesh, elem, pos):
        # Search master space for an x such that f(x)=pos, and return x.

        delta = 0.001  # Small compared to master space.
        if config.dimension() == 2:
            mtx = smallmatrix.SmallMatrix(2, 2)
            rhs = smallmatrix.SmallMatrix(2, 1)
            delta_x = mastercoord.MasterCoord(delta, 0.0)
            delta_y = mastercoord.MasterCoord(0.0, delta)
        elif config.dimension() == 3:
            mtx = smallmatrix.SmallMatrix(3, 3)
            rhs = smallmatrix.SmallMatrix(3, 1)
            delta_x = mastercoord.MasterCoord(delta, 0.0, 0.0)
            delta_y = mastercoord.MasterCoord(0.0, delta, 0.0)
            delta_z = mastercoord.MasterCoord(0.0, 0.0, delta)

        res = elem.center()

        done = False
        # Magic numbers.  The function can actually fail, because for
        # higher-order elements, the displacement mapping is
        # parabolic, and the range of the parabolic mapping might not
        # include the point pos, if it's too far away from the
        # element.  So, if we've gone for more than maxiters
        # iterations, raise an exception.
        tolerance = 1.0e-10
        maxiters = 50

        count = 0
        while not done:
            count += 1
            if count > maxiters:
                raise IterationMaxExceeded()

            fwd = self.where.evaluate(mesh, [elem], [[res]])[0]
            fwddx = self.where.evaluate(mesh, [elem], [[res + delta_x]])[0]
            fwddy = self.where.evaluate(mesh, [elem], [[res + delta_y]])[0]
            if config.dimension() == 3:
                fwddz = self.where.evaluate(mesh, [elem], [[res + delta_z]])[0]

            dfdx = (fwddx - fwd) / delta
            dfdy = (fwddy - fwd) / delta
            if config.dimension() == 3:
                dfdz = (fwddz - fwd) / delta
            diff = pos - fwd

            rhs.setitem(0, 0, diff[0])
            rhs.setitem(1, 0, diff[1])
            if config.dimension() == 3:
                rhs.setitem(2, 0, diff[2])

            mtx.setitem(0, 0, dfdx[0])
            mtx.setitem(0, 1, dfdy[0])
            mtx.setitem(1, 0, dfdx[1])
            mtx.setitem(1, 1, dfdy[1])
            if config.dimension() == 3:
                mtx.setitem(0, 2, dfdz[0])
                mtx.setitem(1, 2, dfdz[1])
                mtx.setitem(2, 0, dfdx[2])
                mtx.setitem(2, 1, dfdy[2])
                mtx.setitem(2, 2, dfdz[2])

            ## TODO OPT: For a 2x2 matrix, is it faster to write out
            ## the solution, rather than using a general purpose
            ## routine?
            r = mtx.solve(rhs)

            if config.dimension() == 2:
                resid = (rhs[0, 0]**2 + rhs[1, 0]**2)
                res = mastercoord.MasterCoord(res[0] + rhs[0, 0],
                                              res[1] + rhs[1, 0])
            elif config.dimension() == 3:
                resid = (rhs[0, 0]**2 + rhs[1, 0]**2 + rhs[2, 0]**2)
                res = mastercoord.MasterCoord(res[0] + rhs[0, 0],
                                              res[1] + rhs[1, 0],
                                              res[2] + rhs[2, 0])

            if resid < tolerance:
                done = True

        return res
예제 #3
0
    def undisplaced(self, mesh, elem, pos):  # 2D only
        # Search master space for an x such that f(x)=pos, and return
        # the real space location of x. 'pos' is a position in real
        # space.

        delta = 0.001  # Small compared to master space.
        if config.dimension() == 2:
            mtx = smallmatrix.SmallMatrix(2, 2)
            rhs = smallmatrix.SmallMatrix(2, 1)
            delta_x = mastercoord.MasterCoord(delta, 0.0)
            delta_y = mastercoord.MasterCoord(0.0, delta)
        elif config.dimension() == 3:
            mtx = smallmatrix.SmallMatrix(3, 3)
            rhs = smallmatrix.SmallMatrix(3, 1)
            delta_x = mastercoord.MasterCoord(delta, 0.0, 0.0)
            delta_y = mastercoord.MasterCoord(0.0, delta, 0.0)
            delta_z = mastercoord.MasterCoord(0.0, 0.0, delta)

        res = elem.center()  # master space position

        done = False
        # Magic numbers.  The function can actually fail, because for
        # higher-order elements, the displacement mapping is
        # parabolic, and the range of the parabolic mapping might not
        # include the point pos, if it's too far away from the
        # element.  So, if we've gone for more than maxiters
        # iterations, raise an exception.
        tolerance = 1.0e-10
        maxiters = 50

        count = 0
        while not done:
            count += 1
            if count > maxiters:
                raise ooferror2.ErrConvergenceFailure("Displacement inversion",
                                                      maxiters)

            fwd = self._displaced(mesh, elem, masterpos=res)
            fwddx = self._displaced(mesh, elem, masterpos=res + delta_x)
            fwddy = self._displaced(mesh, elem, masterpos=res + delta_y)
            dfdx = (fwddx - fwd) / delta
            dfdy = (fwddy - fwd) / delta
            if config.dimension() == 3:
                fwddz = self._displaced(mesh, elem, masterpos=res + delta_z)
                dfdz = (fwddz - fwd) / delta

            diff = pos - fwd

            rhs.setitem(0, 0, diff[0])
            rhs.setitem(1, 0, diff[1])
            if config.dimension() == 3:
                rhs.setitem(2, 0, diff[2])

            mtx.setitem(0, 0, dfdx[0])
            mtx.setitem(0, 1, dfdy[0])
            mtx.setitem(1, 0, dfdx[1])
            mtx.setitem(1, 1, dfdy[1])
            if config.dimension() == 3:
                mtx.setitem(0, 2, dfdz[0])
                mtx.setitem(1, 2, dfdz[1])
                mtx.setitem(2, 0, dfdx[2])
                mtx.setitem(2, 1, dfdy[2])
                mtx.setitem(2, 2, dfdz[2])

            ## TODO OPT: For a 2x2 matrix, is it faster to write out the
            ## solution, rather than using a general purpose routine?
            r = mtx.solve(rhs)

            if config.dimension() == 2:
                resid = (rhs[0, 0]**2 + rhs[1, 0]**2)
                res = mastercoord.MasterCoord(res[0] + rhs[0, 0],
                                              res[1] + rhs[1, 0])
            elif config.dimension() == 3:
                resid = (rhs[0, 0]**2 + rhs[1, 0]**2 + rhs[2, 0]**2)
                res = mastercoord.MasterCoord(res[0] + rhs[0, 0],
                                              res[1] + rhs[1, 0],
                                              res[2] + rhs[2, 0])

            if resid < tolerance:
                done = True

        return elem.from_master(res)