How to input list of Constraint to compas_fd.constraints.Constraint

Hi,

thanks to the elaborate example on compas_fd from this thread Importing compas_fd to rhino8 ScriptEditor - #17 by tomvanmele

I am setting up a quick variation, I want to formfind a membrane over a series of arches, set up geometry image below

I am trying to set multiple Constraint in compas_fd.constraints.Constraint ( the series of arches). from the docs I see that Constraint only takes 1 object ? I am struggling to add a list of Constraint. I’m iterating through a list of contraint and on visualizing, the mesh is not updated

#imports
#imports
from compas.datastructures import Mesh
from compas.geometry import Point, Vector, Line, NurbsCurve
from compas.geometry import Sphere, Cylinder
from compas.scene import Scene
from compas.colors import Color

from compas_fd.solvers import fd_constrained_numpy
from compas_fd.constraints import Constraint

#mesh 
mesh = Mesh.from_meshgrid(dx=40,dy=7, nx=40,ny=7)

# vertices, edges
vertices = mesh.vertices_attributes("xyz")
edges = list(mesh.edges())

# anchors/supports
supports = list(mesh.vertices_where(vertex_degree=2))
edge_vertices_0 = list(mesh.vertices_where(y=0,z=0))
edge_vertices_1 = list(mesh.vertices_where(y=7,z=0))
supports += edge_vertices_0 [5::6]
supports += edge_vertices_1 [5::6]

pts = [mesh.vertex_coordinates(ind) for ind in supports]

# loads
loads = [[0, 0, 0] for _ in range(mesh.number_of_vertices())]

# force densities
q = []
for edge in edges:
    if mesh.is_edge_on_boundary(edge):
        q.append(30)
    else:
        q.append(1.0)

# constraints
arches = []
v0 = [mesh.vertex_coordinates(ind) for ind in edge_vertices_0 [5::6]]
v1 = [mesh.vertex_coordinates(ind) for ind in edge_vertices_1 [5::6]]

for i,j in zip(v0,v1):
    pt0 = Point(i[0],i[1],i[2])
    pt1 = Point(j[0],j[1],j[2])
    line = Line(pt0,pt1)
    mid_point = line.midpoint
    move = Point(mid_point[0],mid_point[1],mid_point[2]+3)
    arch = NurbsCurve.from_points([i, [move[0],move[1],move[2]], j], degree=2)
    arches.append(arch)

arch_constraint = []
for arch in arches:
    constraint = Constraint(arch)
    arch_constraint.append(constraint)


constraints = [None] * mesh.number_of_vertices()
print(len(constraints))
constrained = []
for arch in arch_constraint:
    for vertex in mesh.vertices():
        if vertex in supports:
            continue
        constraints[vertex] = arch
        constrained.append(vertex)

print(len(constraints))

result = fd_constrained_numpy(
    vertices=vertices,
    fixed=list(set(supports + constrained)),
    edges=edges,
    forcedensities=q,
    loads=loads,
    constraints=constraints,
)


for vertex, attr in mesh.vertices(data=True):
    attr["x"] = result.vertices[vertex, 0]
    attr["y"] = result.vertices[vertex, 1]
    attr["z"] = result.vertices[vertex, 2]

print(mesh)


scene = Scene()
scene.clear()
scene.add(mesh, disjoint=True)

for pt in pts:
    scene.add(Point(pt[0],pt[1],pt[2]), layer="00_compas_fd_mesh_00::supports")

for arch in arches:
    scene.add(arch, layer="00_compas_fd_mesh_00::arches")

for vertex in supports:
    scene.add(mesh.vertex_point(vertex), color=Color.red())

for vertex in supports:
    point = mesh.vertex_point(vertex)
    vector = Vector(*result.residuals[vertex]) * -0.5
    line = Line.from_point_and_vector(point, vector)
    scene.add(line, color=Color.green())

# for index, edge in enumerate(mesh.edges()):
#     if mesh.is_edge_on_boundary(edge):
#         line = mesh.edge_line(edge)
#         radius = 0.005 * result.forces[index]
#         pipe = Cylinder.from_line_and_radius(line, radius)
#         scene.add(pipe, color=Color.red())

scene.draw()

result below

I have a feeling I got something fundamentally wrong. Any suggestion would help
Thanks in advance!

you have not updated the assignment of vertices to constraints. you are basically assigning all vertices to the last constraint in the list. you have to assign the vertex loops corresponding to the individual constraints to those constraints.

1 Like