Work with interactions

Spatial containment is captured by model.tree. Everything else — structural connections, MEP system flows, material associations, geometric dependencies — lives in model.graph, the interaction graph.

Importing existing relationships

When an IFC file is loaded, the front-end automatically translates IfcRel... instances into typed graph edges. Edge categories are grouped into three families:

Group

Categories

topology

connection, space_boundary, covering, interference, projection

structural

structural

mep

port_connection, port_element, flow_control, services, spatial_reference

Querying interactions

from compas_ifc.bim import BuildingInformationModel

model = BuildingInformationModel("data/Duplex_A_20110907.ifc")

# by category
connections = model.connections
boundaries = model.space_boundaries
interferences = model.interferences

# by group
structural = model.get_interactions_by_group("structural")
mep = model.get_interactions_by_group("mep")

# custom category
coverings = model.get_interactions_by_category("covering")

Each result is a list of graph edges; the underlying GenericElement objects are recovered via the graph’s node_element accessor.

Tracing connectivity

To follow a connectivity network — for example an MEP flow system or a chain of structurally connected members — trace_connections performs a breadth-first walk over the interaction graph from a starting element, following only edges that match a category (or a whole group), and returns the reachable elements:

start = model.get_elements_by_name("AHU-01")[0]

# all elements reachable through MEP flow edges, up to 5 hops away
downstream = model.trace_connections(
    start,
    category="mep",
    max_depth=5,
)
for element in downstream:
    print(element.name)

category accepts either a single relationship category (e.g. "connection") or a group name ("topology", "structural", "mep"); max_depth=None returns the whole connected component.

Computing connections from geometry

When the source IFC file does not declare the connections you need, the front-end can detect them from the geometry. compute_connections runs a vectorised broadphase (BVH + tight AABB filter) followed by face-level contact detection:

n = model.compute_connections(
    element_types=["IfcWall", "IfcWallStandardCase"],
    tolerance=1e-3,
    minimum_area=1e-2,
)
print(f"{n} new connection edges")

Computed contacts are added to the same interaction graph (with source="computed") and, by default, persisted as IfcRelConnectsElements instances in the underlying IFC file so they survive a save/reload.

Detecting clashes

compute_collisions performs ray-cast point-in-mesh detection for volumetric overlap. Penetrating points are stored on graph edges in the interference category:

n = model.compute_collisions(element_types=["IfcWall", "IfcSlab"])
print(f"{n} collisions")

model.show_collisions()  # interactive viewer