Beispiel #1
0
def form_identify_dof(form):
    r"""Identify the DOF of a form diagram.

    Parameters
    ----------
    form : FormDiagram
        The form diagram.

    Returns
    -------
    k : int
        Dimension of the null space (nullity) of the equilibrium matrix.
        Number of independent states of self-stress.
    m : int
        Size of the left null space of the equilibrium matrix.
        Number of (infenitesimal) mechanisms.
    ind : list
        Indices of the independent edges.

    Notes
    -----
    The equilibrium matrix of the form diagram is

    .. math::

        \mathbf{E}
        =
        \begin{bmatrix}
        \mathbf{C}_{i}^{t}\mathbf{U} \\
        \mathbf{C}_{i}^{t}\mathbf{V}
        \end{bmatrix}


    If ``k == 0`` and ``m == 0``, the system described by the equilibrium matrix
    is statically determined.
    If ``k > 0`` and ``m == 0``, the system is statically indetermined with `k`
    idependent states of stress.
    If ``k == 0`` asnd ``m > 0``, the system is unstable, with `m` independent
    mechanisms.

    The dimension of a vector space (such as the null space) is the number of
    vectors of a basis of that vector space. A set of vectors forms a basis of a
    vector space if they are linearly independent vectors and every vector of the
    space is a linear combination of this set.

    Examples
    --------
    >>>
    """
    k_i = form.key_index()
    xy = form.vertices_attributes('xy')
    fixed = [k_i[key] for key in form.fixed()]
    free = list(set(range(len(form.vertex))) - set(fixed))
    edges = [(k_i[u], k_i[v]) for u, v in form.edges()]
    C = connectivity_matrix(edges)
    E = equilibrium_matrix(C, xy, free)
    k, m = dof(E)
    ind = nonpivots(rref(E))
    return k, m, [edges[i] for i in ind]
def form_identify_dof(form, **kwargs):
    algo = kwargs.get('algo') or 'sympy'
    k2i = form.key_index()
    xyz = form.vertices_attributes('xyz')
    fixed = [k2i[key] for key in form.anchors()]
    free = list(set(range(form.number_of_vertices())) - set(fixed))
    edges = [(k2i[u], k2i[v]) for u, v in form.edges_where({'_is_edge': True})]
    C = connectivity_matrix(edges)
    E = equilibrium_matrix(C, xyz, free)
    return nonpivots(rref(E, algo=algo))
Beispiel #3
0
def optimise_single(form,
                    solver='devo',
                    polish='slsqp',
                    qmin=1e-6,
                    qmax=5,
                    population=300,
                    generations=500,
                    printout=10,
                    tol=0.001,
                    plot=False,
                    frange=[],
                    indset=None,
                    tension=False,
                    planar=False):
    """ Finds the optimised load-path for a FormDiagram.

    Parameters
    ----------
    form : obj
        The FormDiagram.
    solver : str
        Differential Evolution 'devo' or Genetic Algorithm 'ga' evolutionary solver to use.
    polish : str
        'slsqp' polish or None.
    qmin : float
        Minimum qid value.
    qmax : float
        Maximum qid value.
    population : int
        Number of agents for the evolution solver.
    generations : int
        Number of generations for the evolution solver.
    printout : int
        Frequency of print output to the terminal.
    tol : float
        Tolerance on horizontal force balance.
    plot : bool
        Plot progress of the evolution.
    frange : list
        Minimum and maximum function value to plot.
    indset : list
        Independent set to use.
    tension : bool
        Allow tension edge force densities (experimental).
    planar : bool
        Only consider the x-y plane.

    Returns
    -------
    float
        Optimum load-path value.
    list
        Optimum qids

    """

    if printout:
        print('\n' + '-' * 50)
        print('Load-path optimisation started')
        print('-' * 50)

    # Mapping

    k_i = form.key_index()
    i_k = form.index_key()
    i_uv = form.index_uv()
    uv_i = form.uv_index()

    # Vertices and edges

    n = form.number_of_vertices()
    m = form.number_of_edges()
    fixed = [k_i[key] for key in form.fixed()]
    rol = [k_i[key] for key in form.vertices_where({'is_roller': True})]
    edges = [(k_i[u], k_i[v]) for u, v in form.edges()]
    sym = [uv_i[uv] for uv in form.edges_where({'is_symmetry': True})]
    free = list(set(range(n)) - set(fixed) - set(rol))

    # Co-ordinates and loads

    xyz = zeros((n, 3))
    x = zeros((n, 1))
    y = zeros((n, 1))
    z = zeros((n, 1))
    px = zeros((n, 1))
    py = zeros((n, 1))
    pz = zeros((n, 1))

    for key, vertex in form.vertex.items():
        i = k_i[key]
        xyz[i, :] = form.vertex_coordinates(key)
        x[i] = vertex.get('x')
        y[i] = vertex.get('y')
        px[i] = vertex.get('px', 0)
        py[i] = vertex.get('py', 0)
        pz[i] = vertex.get('pz', 0)

    xy = xyz[:, :2]
    px = px[free]
    py = py[free]
    pz = pz[free]

    # C and E matrices

    C = connectivity_matrix(edges, 'csr')
    Ci = C[:, free]
    Cf = C[:, fixed]
    Cit = Ci.transpose()
    E = equilibrium_matrix(C, xy, free, 'csr').toarray()
    uvw = C.dot(xyz)
    U = uvw[:, 0]
    V = uvw[:, 1]

    # Independent and dependent branches

    if indset:
        ind = []
        for u, v in form.edges():
            if geometric_key(form.edge_midpoint(u, v)[:2] + [0]) in indset:
                ind.append(uv_i[(u, v)])
    else:
        ind = nonpivots(sympy.Matrix(E).rref()[0].tolist())

    k = len(ind)
    dep = list(set(range(m)) - set(ind))

    for u, v in form.edges():
        form.set_edge_attribute((u, v), 'is_ind',
                                True if uv_i[(u, v)] in ind else False)

    if printout:
        _, s, _ = svd(E)
        print('Form diagram has {0} (RREF): {1} (SVD) independent branches '.
              format(len(ind), m - len(s)))

    # Set-up

    lh = normrow(C.dot(xy))**2
    Edinv = -csr_matrix(pinv(E[:, dep]))
    Ei = E[:, ind]
    p = vstack([px, py])
    q = array([attr['q'] for u, v, attr in form.edges(True)])[:, newaxis]
    bounds = [[qmin, qmax]] * k
    args = (q, ind, dep, Edinv, Ei, C, Ci, Cit, U, V, p, px, py, pz, tol, z,
            free, planar, lh, sym, tension)

    # Horizontal checks

    checked = True

    if tol == 0:
        for i in range(10**3):
            q[ind, 0] = rand(k) * qmax
            q[dep] = -Edinv.dot(p - Ei.dot(q[ind]))
            Rx = Cit.dot(U * q.ravel()) - px.ravel()
            Ry = Cit.dot(V * q.ravel()) - py.ravel()
            R = max(sqrt(Rx**2 + Ry**2))
            if R > tol:
                checked = False
                break

    if checked:

        # Solve

        if solver == 'devo':
            fopt, qopt = _diff_evo(_fint, bounds, population, generations,
                                   printout, plot, frange, args)

        if polish == 'slsqp':
            fopt_, qopt_ = _slsqp(_fint_, qopt, bounds, printout, _fieq, args)
            q1 = _zlq_from_qid(qopt_, args)[2]
            if fopt_ < fopt:
                if (min(q1) > -0.001 and not tension) or tension:
                    fopt, qopt = fopt_, qopt_

        z, _, q, q_ = _zlq_from_qid(qopt, args)

        # Unique key

        gkeys = []
        for i in ind:
            u, v = i_uv[i]
            gkeys.append(geometric_key(form.edge_midpoint(u, v)[:2] + [0]))
        form.attributes['indset'] = gkeys

        # Update FormDiagram

        for i in range(n):
            key = i_k[i]
            form.set_vertex_attribute(key=key, name='z', value=float(z[i]))

        for c, qi in enumerate(list(q_.ravel())):
            u, v = i_uv[c]
            form.set_edge_attribute((u, v), 'q', float(qi))

        # Relax

        q = array([attr['q'] for u, v, attr in form.edges(True)])
        Q = diags(q)
        CitQ = Cit.dot(Q)
        Di = CitQ.dot(Ci)
        Df = CitQ.dot(Cf)
        bx = px - Df.dot(x[fixed])
        by = py - Df.dot(y[fixed])
        # bz   = pz - Df.dot(z[fixed])
        x[free, 0] = spsolve(Di, bx)
        y[free, 0] = spsolve(Di, by)
        # z[free, 0] = spsolve(Di, bz)

        for i in range(n):
            form.set_vertex_attributes(
                key=i_k[i],
                names='xyz',
                values=[float(j) for j in [x[i], y[i], z[i]]])

        fopt = 0
        for u, v in form.edges():
            if form.get_edge_attribute((u, v), 'is_symmetry') is False:
                qi = form.get_edge_attribute((u, v), 'q')
                li = form.edge_length(u, v)
                fopt += abs(qi) * li**2

        form.attributes['loadpath'] = fopt

        if printout:
            print('\n' + '-' * 50)
            print('qid range : {0:.3f} : {1:.3f}'.format(min(qopt), max(qopt)))
            print('q range   : {0:.3f} : {1:.3f}'.format(min(q), max(q)))
            print('fopt      : {0:.3f}'.format(fopt))
            print('-' * 50 + '\n')

        return fopt, qopt

    else:

        if printout:
            print('Horizontal equillibrium checks failed')

        return None, None