[docs]defcompute_loadpath(form,force):"""Compute the internal work of a structure. Parameters ---------- form : FormDiagram The form diagram. force : ForceDiagram The force diagram. Returns ------- float The internal work done by the structure. """returncompute_internal_work(form,force)
[docs]defcompute_external_work(form,force):"""Compute the external work of a structure. The external work done by a structure is equal to the work done by the external forces. This is equal to the sum of the dot products of the force vectors and the vectors defined by the force application point and a fixed arbitrary point. Parameters ---------- form : FormDiagram The form diagram. force : ForceDiagram The force diagram. Returns ------- float The external work done by the structure. Examples -------- >>> """vertex_index=form.vertex_index()xy=array(form.xy(),dtype=float64)edges=[(vertex_index[u],vertex_index[v])foru,vinform.edges()]C=connectivity_matrix(edges,"csr")_vertex_index=force.vertex_index()_xy=force.xy()_edges=force.ordered_edges(form)_edges[:]=[(_vertex_index[u],_vertex_index[v])foru,vin_edges]_C=connectivity_matrix(_edges,"csr")leaves=set(form.leaves())external=[ifori,(u,v)inenumerate(form.edges())ifuinleavesorvinleaves]lengths=normrow(C.dot(xy))forces=normrow(_C.dot(_xy))returnlengths[external].T.dot(forces[external])[0,0]
[docs]defcompute_internal_work(form,force):"""Compute the work done by the internal forces of a structure. Parameters ---------- form : FormDiagram The form diagram. force : ForceDiagram The force diagram. Returns ------- float The internal work done by the structure. Examples -------- >>> """vertex_index=form.vertex_index()xy=array(form.xy(),dtype=float64)edges=[(vertex_index[u],vertex_index[v])foru,vinform.edges()]C=connectivity_matrix(edges,"csr")_vertex_index=force.vertex_index()_xy=force.xy()_edges=force.ordered_edges(form)_edges[:]=[(_vertex_index[u],_vertex_index[v])foru,vin_edges]_C=connectivity_matrix(_edges,"csr")leaves=set(form.leaves())internal=[ifori,(u,v)inenumerate(form.edges())ifunotinleavesandvnotinleaves]lengths=normrow(C.dot(xy))forces=normrow(_C.dot(_xy))returnlengths[internal].T.dot(forces[internal])[0,0]
[docs]defcompute_internal_work_tension(form,force):"""Compute the work done by the internal tensile forces of a structure. Parameters ---------- form : FormDiagram The form diagram. force : ForceDiagram The force diagram. Returns ------- float The internal work done by the tensile forces in a structure. Examples -------- >>> """vertex_index=form.vertex_index()xy=array(form.xy(),dtype=float64)edges=[(vertex_index[u],vertex_index[v])foru,vinform.edges()]C=connectivity_matrix(edges,"csr")q=array(form.q(),dtype=float64).reshape((-1,1))_vertex_index=force.vertex_index()_xy=force.xy()_edges=force.ordered_edges(form)_edges[:]=[(_vertex_index[u],_vertex_index[v])foru,vin_edges]_C=connectivity_matrix(_edges,"csr")leaves=set(form.leaves())internal=[ifori,(u,v)inenumerate(form.edges())ifunotinleavesandvnotinleaves]tension=[iforiininternalifq[i,0]>0]lengths=normrow(C.dot(xy))forces=normrow(_C.dot(_xy))returnlengths[tension].T.dot(forces[tension])[0,0]
[docs]defcompute_internal_work_compression(form,force):"""Compute the work done by the internal compressive forces of a structure. Parameters ---------- form : FormDiagram The form diagram. force : ForceDiagram The force diagram. Returns ------- float The internal work done by the compressive forces in a structure. Examples -------- >>> """vertex_index=form.vertex_index()xy=array(form.xy(),dtype=float64)edges=[(vertex_index[u],vertex_index[v])foru,vinform.edges()]C=connectivity_matrix(edges,"csr")q=array(form.q(),dtype=float64).reshape((-1,1))_vertex_index=force.vertex_index()_xy=force.xy()_edges=force.ordered_edges(form)_edges[:]=[(_vertex_index[u],_vertex_index[v])foru,vin_edges]_C=connectivity_matrix(_edges,"csr")leaves=set(form.leaves())internal=[ifori,(u,v)inenumerate(form.edges())ifunotinleavesandvnotinleaves]compression=[iforiininternalifq[i,0]<0]lengths=normrow(C.dot(xy))forces=normrow(_C.dot(_xy))returnlengths[compression].T.dot(forces[compression])[0,0]
[docs]defoptimise_loadpath(form,force,algo="COBYLA"):"""Optimise the loadpath using the parameters of the force domain. The parameters of the force domain are the coordinates of the vertices of the force diagram. Parameters ---------- form : FormDiagram The form diagram. force : ForceDiagram The force diagram. algo : {'COBYLA', L-BFGS-B', 'SLSQ', 'MMA', 'GMMA'}, optional The optimisation algorithm. Returns ------- form: :class:`FormDiagram` The optimised form diagram. force: :class:`ForceDiagram` The optimised force diagram. Notes ----- In many cases, the number of paramters of the force domain involved in generating new solutions in the form domain is smaller than when using the elements of the form diagram directly. For example, the loadpath of a bridge with a compression arch can be optimised using only the x-coordinates of the vertices of the force diagram corresponding to internal spaces formed by the segments of the arch, the corresponding deck elements, and the hangers connecting them. Any solution generated by these parameters will be in equilibrium and automatically have a horizontal bridge deck. Although the *BRG* algorithm is the preferred choice, since it is (should be) tailored to the problem of optimising loadpaths using the domain of the force diagram, it does not have a stable and/or efficient implementation. The main problem is the generation of the form diagram, based on a given force diagram. For example, when edge forces flip from tension to compression, and vice versa, parallelisation is no longer effective. """vertex_index=form.vertex_index()edge_index=form.edge_index()i_j={vertex_index[vertex]:[vertex_index[nbr]fornbrinform.vertex_neighbors(vertex)]forvertexinform.vertices()}ij_e={(vertex_index[u],vertex_index[v]):edge_index[u,v]foru,vinedge_index}ij_e.update({(vertex_index[v],vertex_index[u]):edge_index[u,v]foru,vinedge_index})xy=array(form.xy(),dtype=float64)edges=[(vertex_index[u],vertex_index[v])foru,vinform.edges()]C=connectivity_matrix(edges,"csr")leaves=[vertex_index[key]forkeyinform.leaves()]fixed=[vertex_index[key]forkeyinform.fixed()]free=list(set(range(form.number_of_vertices()))-set(fixed)-set(leaves))internal=[ifori,(u,v)inenumerate(form.edges())ifvertex_index[u]notinleavesandvertex_index[v]notinleaves]_vertex_index=force.vertex_index()_edge_index=force.edge_index(form)_edge_index.update({(v,u):_edge_index[u,v]foru,vin_edge_index})_xy=array(force.xy(),dtype=float64)_edges=force.ordered_edges(form)_edges[:]=[(_vertex_index[u],_vertex_index[v])foru,vin_edges]_C=connectivity_matrix(_edges,"csr")_free=[keyforkey,attrinforce.vertices(True)ifattr["is_param"]]_free=[_vertex_index[key]forkeyin_free]defobjfunc(_x):_xy[_free,0]=_xupdate_primal_from_dual(xy,_xy,free,leaves,i_j,ij_e,_C)length=normrow(C.dot(xy))force=normrow(_C.dot(_xy))lp=length[internal].T.dot(force[internal])[0,0]print(lp)returnlpx0=_xy[_free,0]result=minimize(objfunc,x0,method=algo,tol=1e-12,options={"maxiter":1000})# noqa: F841uv=C.dot(xy)_uv=_C.dot(_xy)angles=[angle_vectors_xy(a,b)fora,binzip(uv,_uv)]lengths=normrow(uv)forces=normrow(_uv)q=forces/lengthsforvertex,attrinform.vertices(True):index=vertex_index[vertex]attr["x"]=xy[index,0]attr["y"]=xy[index,1]foredge,attrinform.edges(True):index=edge_index[edge]attr["l"]=lengths[index,0]attr["a"]=angles[index]if(angles[index]-3.14159)**2<0.25*3.14159:attr["f"]=-forces[index,0]attr["q"]=-q[index,0]else:attr["f"]=forces[index,0]attr["q"]=q[index,0]forvertex,attrinforce.vertices(True):index=_vertex_index[vertex]attr["x"]=_xy[index,0]attr["y"]=_xy[index,1]foredge,attrinforce.edges(True):index=_edge_index[edge]attr["a"]=angles[index]attr["l"]=forces[index,0]returnform,force