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]
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
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
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
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])