예제 #1
0
def vertical_from_q(form,
                    scale=1.0,
                    density=1.0,
                    kmax=100,
                    tol=1e-3,
                    display=True):
    """Compute vertical equilibrium from the force densities of the independent edges.

    Parameters
    ----------
    form : FormDiagram
        The form diagram
    scale : float
        The scale of the horizontal forces.
        Default is ``1.0``.
    density : float, optional
        The density for computation of the self-weight of the thrust network.
        Set this to 0.0 to ignore self-weight and only consider specified point loads.
        Default is ``1.0``.
    kmax : int, optional
        The maximum number of iterations for computing vertical equilibrium.
        Default is ``100``.
    tol : float
        The stopping criterion.
        Default is ``0.001``.
    display : bool
        Display information about the current iteration.
        Default is ``True``.

    """
    k_i = form.key_index()
    uv_i = form.uv_index()
    vcount = form.number_of_vertices()
    anchors = list(form.anchors())
    fixed = list(form.fixed())
    fixed = set(anchors + fixed)
    fixed = [k_i[key] for key in fixed]
    edges = [(k_i[u], k_i[v]) for u, v in form.edges_where({'is_edge': True})]
    free = list(set(range(vcount)) - set(fixed))
    xyz = array(form.get_vertices_attributes('xyz'), dtype=float64)
    thick = array(form.get_vertices_attribute('t'), dtype=float64).reshape(
        (-1, 1))
    p = array(form.get_vertices_attributes(('px', 'py', 'pz')), dtype=float64)
    q = [
        attr.get('q', 1.0)
        for u, v, attr in form.edges_where({'is_edge': True}, True)
    ]
    q = array(q, dtype=float64).reshape((-1, 1))
    C = connectivity_matrix(edges, 'csr')
    # --------------------------------------------------------------------------
    # original data
    # --------------------------------------------------------------------------
    p0 = array(p, copy=True)
    q0 = array(q, copy=True)
    # --------------------------------------------------------------------------
    # load updater
    # --------------------------------------------------------------------------
    update_loads = LoadUpdater(form, p0, thickness=thick, density=density)
    # --------------------------------------------------------------------------
    # update forcedensity based on given q[ind]
    # --------------------------------------------------------------------------
    q = scale * q0
    Q = diags([q.ravel()], [0])
    # --------------------------------------------------------------------------
    # compute vertical
    # --------------------------------------------------------------------------
    update_z(xyz,
             Q,
             C,
             p,
             free,
             fixed,
             update_loads,
             tol=tol,
             kmax=kmax,
             display=display)
    # --------------------------------------------------------------------------
    # update
    # --------------------------------------------------------------------------
    l = normrow(C.dot(xyz))
    f = q * l
    r = C.transpose().dot(Q).dot(C).dot(xyz) - p
    sw = p - p0
    # --------------------------------------------------------------------------
    # form
    # --------------------------------------------------------------------------
    for key, attr in form.vertices(True):
        index = k_i[key]
        attr['z'] = xyz[index, 2]
        attr['rx'] = r[index, 0]
        attr['ry'] = r[index, 1]
        attr['rz'] = r[index, 2]
        attr['sw'] = sw[index, 2]
    for u, v, attr in form.edges_where({'is_edge': True}, True):
        index = uv_i[(u, v)]
        attr['f'] = f[index, 0]
        attr['l'] = l[index, 0]
예제 #2
0
def vertical_from_bbox(form,
                       factor=5.0,
                       kmax=100,
                       tol=1e-3,
                       density=1.0,
                       display=True):
    # --------------------------------------------------------------------------
    # FormDiagram
    # --------------------------------------------------------------------------
    k_i = form.key_index()
    uv_i = form.uv_index()
    vcount = len(form.vertex)
    anchors = list(form.anchors())
    fixed = list(form.fixed())
    fixed = set(anchors + fixed)
    fixed = [k_i[key] for key in fixed]
    free = list(set(range(vcount)) - set(fixed))
    edges = [(k_i[u], k_i[v]) for u, v in form.edges_where({'is_edge': True})]
    xyz = array(form.get_vertices_attributes('xyz'), dtype=float64)
    thick = array(form.get_vertices_attribute('t'), dtype=float64).reshape(
        (-1, 1))
    p = array(form.get_vertices_attributes(('px', 'py', 'pz')), dtype=float64)
    q = [
        attr.get('q', 1.0)
        for u, v, attr in form.edges_where({'is_edge': True}, True)
    ]
    q = array(q, dtype=float64).reshape((-1, 1))
    C = connectivity_matrix(edges, 'csr')
    Ci = C[:, free]
    Cf = C[:, fixed]
    Cit = Ci.transpose()
    Ct = C.transpose()
    # --------------------------------------------------------------------------
    # original data
    # --------------------------------------------------------------------------
    p0 = array(p, copy=True)
    q0 = array(q, copy=True)
    # --------------------------------------------------------------------------
    # load updater
    # --------------------------------------------------------------------------
    update_loads = LoadUpdater(form, p0, thickness=thick, density=density)
    # --------------------------------------------------------------------------
    # scale
    # --------------------------------------------------------------------------
    (xmin, ymin, zmin), (xmax, ymax, zmax) = form.bbox()
    d = ((xmax - xmin)**2 + (ymax - ymin)**2)**0.5
    scale = d / factor
    # --------------------------------------------------------------------------
    # vertical
    # --------------------------------------------------------------------------
    q = scale * q0
    Q = diags([q.ravel()], [0])
    update_z(xyz,
             Q,
             C,
             p,
             free,
             fixed,
             update_loads,
             tol=tol,
             kmax=kmax,
             display=display)
    # --------------------------------------------------------------------------
    # update
    # --------------------------------------------------------------------------
    l = normrow(C.dot(xyz))
    f = q * l
    r = Ct.dot(Q).dot(C).dot(xyz) - p
    sw = p - p0
    # --------------------------------------------------------------------------
    # form
    # --------------------------------------------------------------------------
    for key, attr in form.vertices(True):
        index = k_i[key]
        attr['z'] = xyz[index, 2]
        attr['rx'] = r[index, 0]
        attr['ry'] = r[index, 1]
        attr['rz'] = r[index, 2]
        attr['sw'] = sw[index, 2]
    for u, v, attr in form.edges_where({'is_edge': True}, True):
        index = uv_i[(u, v)]
        attr['f'] = f[index, 0]
        attr['l'] = l[index, 0]

    return scale
예제 #3
0
def ForceDensitySolver(formData,
                       flt_TtlSWLd,
                       bool_LdsRdistrByTrib=True,
                       iMax_LdsRedistr=5):
    _formDiag = FormDiagram.from_data(formData)

    _dctMap__Ind_to_VKey = _formDiag.IndexToVKey(bool_ExclExt=False)
    _dctMap__VKey_to_Ind = _formDiag.VKeyToIndex(bool_ExclExt=False)

    _vKeysL_Vertices = _formDiag.VertexKeys(bool_ExclExt=False)
    _coordsL_Vertices = _formDiag.RetrieveCoordinates(_vKeysL_Vertices)
    _eKeysL_Edges = _formDiag.EdgeKeys(bool_ExclExt=False, bool_Ind=False)
    _eIndKeysL_Edges = _formDiag.EdgeKeys(bool_ExclExt=False, bool_Ind=True)
    _vIndKeysL_Anchs = [
        _dctMap__VKey_to_Ind[_vKey] for _vKey in list(_formDiag.anchors())
    ]
    _fltsL_Q = _formDiag.get_edges_attribute('q', 1.0)

    _vecsL_ApldLds = _formDiag.get_vertices_attributes(['px', 'py', 'pz'])
    _vecsA_TtlLds = array(_vecsL_ApldLds, dtype=float64)
    _vecsA_ApldLds = array(_vecsL_ApldLds, dtype=float64)
    _LdUpdtr = LoadUpdater(_formDiag,
                           _vecsA_ApldLds,
                           thickness=1.0,
                           density=flt_TtlSWLd)

    _coordsL_Vertices_0 = deepcopy(_coordsL_Vertices)
    _fltsL_Q_0 = _fltsL_Q
    _iMax = 10

    _cDctStructSolvOprDta = {'res': {'all': {}}}
    _i = 0
    while _i < _iMax:

        ##Update Loads
        _coordsAr_Vertices_0 = array(_coordsL_Vertices_0, dtype=float64)
        _LdUpdtr(_vecsA_TtlLds, _coordsAr_Vertices_0)
        _vecsL_TtlLds = _vecsA_TtlLds.tolist()

        _coordsL_Vertices_1, _fltsL_Q_1, _fltsL_EdgeForces, _fltsL_EdgeLgths, _flt_ResidForces = fd_numpy(
            _coordsL_Vertices_0, _eIndKeysL_Edges, _vIndKeysL_Anchs,
            _fltsL_Q_0, _vecsL_TtlLds)

        UpdateFormDiagramVertices(_formDiag, _coordsL_Vertices_1,
                                  _dctMap__Ind_to_VKey)

        _cDctFDRes = {
            'lds': _vecsL_TtlLds,
            'coords': _coordsL_Vertices_1,
            'q': _fltsL_Q_1,
            'f': _fltsL_EdgeForces,
            'lgths': _fltsL_EdgeLgths,
            'fResid': _flt_ResidForces
        }
        _cDctFDRes_Prtl = {
            _kV: [_v[0] for _v in _lA]
            for _kV, _lA in _cDctFDRes.items() if _kV not in ['lds', 'coords']
        }
        _cDctFDRes.update(_cDctFDRes_Prtl)  ##Remove the listed values
        _cDctStructSolvOprDta['res']['all'][int(_i)] = _cDctFDRes

        if bool_LdsRdistrByTrib == False:
            break
        elif _i >= iMax_LdsRedistr - 1:
            break

        _coordsL_Vertices_0 = _coordsL_Vertices_1
        _i += 1

    _i_FnlIter = max(list(_cDctStructSolvOprDta['res']['all'].keys()))
    _formDiag.SetEdgesAttributeWithValues(
        str_AttrNm='f',
        dtaL_AttrVals=_cDctStructSolvOprDta['res']['all'][_i_FnlIter]['f'],
        eKeysL=_eKeysL_Edges)
    _formDiag.SetEdgesAttributeWithValues(
        str_AttrNm='q',
        dtaL_AttrVals=_cDctStructSolvOprDta['res']['all'][_i_FnlIter]['q'],
        eKeysL=_eKeysL_Edges)
    _formDiag.SetEdgesAttributeWithValues(
        str_AttrNm='l',
        dtaL_AttrVals=_cDctStructSolvOprDta['res']['all'][_i_FnlIter]['lgths'],
        eKeysL=_eKeysL_Edges)
    _formDiag.SetVerticesAttributesWithValues(
        strsL_AttrsNms=['px', 'py', 'pz'],
        dtaLL_AttrsVals=_cDctStructSolvOprDta['res']['all'][_i_FnlIter]['lds'],
        vKeysL=_vKeysL_Vertices)
    _formDiag.SetVerticesAttributeWithValues(
        str_AttrNm='fR',
        dtaL_AttrVals=_cDctStructSolvOprDta['res']['all'][_i_FnlIter]
        ['fResid'],
        vKeysL=_vKeysL_Vertices)

    _formData = _formDiag.to_data()
    return _formData, _cDctStructSolvOprDta
예제 #4
0
def vertical_from_zmax(form,
                       zmax,
                       kmax=100,
                       xtol=1e-2,
                       rtol=1e-3,
                       density=1.0,
                       display=True):
    """For the given form and force diagram, compute the scale of the force
    diagram for which the highest point of the thrust network is equal to a
    specified value.

    Parameters
    ----------
    form : compas_tna.diagrams.formdiagram.FormDiagram
        The form diagram
    force : compas_tna.diagrams.forcediagram.ForceDiagram
        The corresponding force diagram.
    zmax : float
        The maximum height of the thrust network (the default is None, which
        implies that the maximum height will be equal to a quarter of the diagonal
        of the bounding box of the form diagram).
    kmax : int
        The maximum number of iterations for computing vertical equilibrium
        (the default is 100).
    tol : float
        The stopping criterion.
    density : float
        The density for computation of the self-weight of the thrust network
        (the default is 1.0). Set this to 0.0 to ignore self-weight and only
        consider specified point loads.
    display : bool
        If True, information about the current iteration will be displayed.

    """
    xtol2 = xtol**2
    # --------------------------------------------------------------------------
    # FormDiagram
    # --------------------------------------------------------------------------
    k_i = form.key_index()
    uv_i = form.uv_index()
    vcount = len(form.vertex)
    anchors = list(form.anchors())
    fixed = list(form.fixed())
    fixed = set(anchors + fixed)
    fixed = [k_i[key] for key in fixed]
    free = list(set(range(vcount)) - set(fixed))
    edges = [(k_i[u], k_i[v]) for u, v in form.edges_where({'is_edge': True})]
    xyz = array(form.get_vertices_attributes('xyz'), dtype=float64)
    thick = array(form.get_vertices_attribute('t'), dtype=float64).reshape(
        (-1, 1))
    p = array(form.get_vertices_attributes(('px', 'py', 'pz')), dtype=float64)
    q = [
        attr.get('q', 1.0)
        for u, v, attr in form.edges_where({'is_edge': True}, True)
    ]
    q = array(q, dtype=float64).reshape((-1, 1))
    C = connectivity_matrix(edges, 'csr')
    Ci = C[:, free]
    Cf = C[:, fixed]
    Cit = Ci.transpose()
    Ct = C.transpose()
    # --------------------------------------------------------------------------
    # original data
    # --------------------------------------------------------------------------
    p0 = array(p, copy=True)
    q0 = array(q, copy=True)
    # --------------------------------------------------------------------------
    # load updater
    # --------------------------------------------------------------------------
    update_loads = LoadUpdater(form, p0, thickness=thick, density=density)
    # --------------------------------------------------------------------------
    # scale to zmax
    # note that zmax should not exceed scale * diagonal
    # --------------------------------------------------------------------------
    scale = 1.0

    for k in range(kmax):
        if display:
            print(k)

        update_loads(p, xyz)

        q = scale * q0
        Q = diags([q.ravel()], [0])
        A = Cit.dot(Q).dot(Ci)
        b = p[free, 2] - Cit.dot(Q).dot(Cf).dot(xyz[fixed, 2])
        xyz[free, 2] = spsolve(A, b)
        z = max(xyz[free, 2])
        res2 = (z - zmax)**2

        if res2 < xtol2:
            break

        scale = scale * (z / zmax)
    # --------------------------------------------------------------------------
    # vertical
    # --------------------------------------------------------------------------
    q = scale * q0
    Q = diags([q.ravel()], [0])

    res = update_z(xyz,
                   Q,
                   C,
                   p,
                   free,
                   fixed,
                   update_loads,
                   tol=rtol,
                   kmax=kmax,
                   display=display)
    # --------------------------------------------------------------------------
    # update
    # --------------------------------------------------------------------------
    l = normrow(C.dot(xyz))
    f = q * l
    r = Ct.dot(Q).dot(C).dot(xyz) - p
    sw = p - p0
    # --------------------------------------------------------------------------
    # form
    # --------------------------------------------------------------------------
    for key, attr in form.vertices(True):
        index = k_i[key]
        attr['z'] = xyz[index, 2]
        attr['rx'] = r[index, 0]
        attr['ry'] = r[index, 1]
        attr['rz'] = r[index, 2]
        attr['sw'] = sw[index, 2]
    for u, v, attr in form.edges_where({'is_edge': True}, True):
        index = uv_i[(u, v)]
        attr['f'] = f[index, 0]
        attr['l'] = l[index, 0]

    return scale
예제 #5
0
def vertical_from_q(form,
                    scale=1.0,
                    density=1.0,
                    kmax=100,
                    tol=1e-3,
                    display=False):
    r"""Compute vertical equilibrium from the force densities of the independent edges.

    Parameters
    ----------
    form : FormDiagram
        The form diagram
    scale : float
        The scale of the horizontal forces.
        Default is ``1.0``.
    density : float, optional
        The density for computation of the self-weight of the thrust network.
        Set this to 0.0 to ignore self-weight and only consider specified point loads.
        Default is ``1.0``.
    kmax : int, optional
        The maximum number of iterations for computing vertical equilibrium.
        Default is ``100``.
    tol : float
        The stopping criterion.
        Default is ``0.001``.
    display : bool
        Display information about the current iteration.
        Default is ``False``.

    Notes
    -----
    The force densities stored in the Form Diagram are the ratios of lengths of corresponding edges in the Form and Force Diagram.
    This means they are not yet scaled with the scale of the horizontal forces.
    The horizontal forces stored in the diagram are scaled.

    .. math::

        q_i &= scale * \frac{l_{i, force}}{l_{i, form}} \\
            &= \frac{h_{i, form}}{l_{i, form}} \\
            &= \frac{f_{i, thrust}}{l_{i, thrust}}

    """
    k_i = form.key_index()
    uv_i = form.uv_index()

    vcount = form.number_of_vertices()
    anchors = list(form.anchors())
    fixed = [k_i[key] for key in anchors]
    free = list(set(range(vcount)) - set(fixed))
    xyz = array(form.vertices_attributes('xyz'), dtype=float64)
    thick = array(form.vertices_attribute('t'), dtype=float64).reshape((-1, 1))
    p = array(form.vertices_attributes(('px', 'py', 'pz')), dtype=float64)

    edges = list(form.edges_where({'_is_edge': True}))
    q = array(form.edges_attribute('q', keys=edges), dtype=float64).reshape(
        (-1, 1))
    edges = [(k_i[u], k_i[v]) for u, v in edges]

    C = connectivity_matrix(edges, 'csr')
    # --------------------------------------------------------------------------
    # original data
    # --------------------------------------------------------------------------
    p0 = array(p, copy=True)
    q0 = array(q, copy=True)
    # --------------------------------------------------------------------------
    # load updater
    # --------------------------------------------------------------------------
    update_loads = LoadUpdater(form, p0, thickness=thick, density=density)
    # --------------------------------------------------------------------------
    # update forcedensity based on given q[ind]
    # --------------------------------------------------------------------------
    q = scale * q0
    Q = diags([q.ravel()], [0])
    # --------------------------------------------------------------------------
    # compute vertical
    # --------------------------------------------------------------------------
    update_z(xyz,
             Q,
             C,
             p,
             free,
             fixed,
             update_loads,
             tol=tol,
             kmax=kmax,
             display=display)
    # --------------------------------------------------------------------------
    # update
    # --------------------------------------------------------------------------
    f = q * normrow(C.dot(xyz))
    r = C.transpose().dot(Q).dot(C).dot(xyz) - p
    # --------------------------------------------------------------------------
    # form
    # --------------------------------------------------------------------------
    for vertex in form.vertices():
        index = k_i[vertex]
        form.vertex_attribute(vertex, 'z', xyz[index, 2])
        form.vertex_attributes(vertex, ['_rx', '_ry', '_rz'], r[index])

    for edge in form.edges_where({'_is_edge': True}):
        index = uv_i[edge]
        form.edge_attribute(edge, '_f', f[index, 0])