SuperAPI AI Directory

ifc-core-relationships

General & other

View repository

Updated 10-15 22:18

About this skill

IFC Relationships

IFC does not connect objects with plain pointer attributes. Every connection between objects is a separate, identifiable entity: an IfcRelationship. This is the objectified relationship pattern. This skill covers why IFC objectifies relationships, the six relationship families, the Relating versus Related direction convention, the concrete IfcRel* entities, and how to traverse them.

Verified against the IFC 4.3.2 specification (ISO 16739-1:2024) with IFC4 and IFC2x3 deltas noted inline. Applies to IFC2x3, IFC4, IFC4.3.

Quick Reference

The objectified relationship pattern

IfcRelationship is a direct subtype of IfcRoot, so every relationship instance carries its own GlobalId, OwnerHistory, Name, and Description. A relationship is a node in the model, not an attribute on the connected objects.

Consequences that drive every rule in this skill:

  • A relationship can carry its own data: connection geometry, priorities, boundary type. That data lives ON the relationship, not on the objects.
  • A relationship is added or removed WITHOUT editing the connected objects. ALWAYS edit the relationship instance, NEVER the participants.
  • A relationship is itself identifiable and versionable through its GlobalId.
  • The cost is indirection: to reach a wall's property sets you follow the wall's IsDefinedBy INVERSE to IfcRelDefinesByProperties instances, then read RelatingPropertyDefinition. NEVER expect a direct attribute.

The six relationship families

IfcRelationship is abstract with exactly six direct subtypes (verified). NEVER instantiate IfcRelationship or any abstract family supertype.

Family Purpose Concrete entities used most
IfcRelAssigns Cross-domain assignment of objects to a group, process, resource, control, actor, or product IfcRelAssignsToGroup
IfcRelAssociates Associate external information with objects IfcRelAssociatesMaterial, IfcRelAssociatesClassification
IfcRelConnects Connectivity, containment, fills, space boundaries IfcRelContainedInSpatialStructure, IfcRelConnectsElements, IfcRelFillsElement
IfcRelDeclares Declare objects or types into an IfcContext (project or library) IfcRelDeclares
IfcRelDecomposes Whole and part decomposition, plus feature subtraction IfcRelAggregates, IfcRelNests, IfcRelVoidsElement
IfcRelDefines Assign a type or a property set to objects IfcRelDefinesByType, IfcRelDefinesByProperties

The Relating versus Related convention

Every relationship has one Relating... role and one Related... role. The direction is part of the semantics. A backwards relationship is a structurally valid but meaningless model.

  • The Relating... side is the single anchor: the whole, the type, the spatial container, the property set, the opening.
  • The Related... side is the dependent participant. In one-to-many relationships it is an aggregate (SET or LIST, cardinality 1..n).

ALWAYS read the entity attribute documentation to know which object goes on which side. NEVER guess the direction.

Key IfcRel* reference table

All entities and attribute types below are verified against the IFC4.3 specification. Full positional signatures are in references/methods.md.

Entity Supertype Relating side Related side
IfcRelAggregates IfcRelDecomposes RelatingObject: IfcObjectDefinition (the whole) RelatedObjects: SET [1:?] OF IfcObjectDefinition (the parts)
IfcRelNests IfcRelDecomposes RelatingObject: IfcObjectDefinition (the whole) RelatedObjects: LIST [1:?] OF IfcObjectDefinition (ordered parts)
IfcRelContainedInSpatialStructure IfcRelConnects RelatingStructure: IfcSpatialElement RelatedElements: SET [1:?] OF IfcProduct
IfcRelReferencedInSpatialStructure IfcRelConnects RelatingStructure: IfcSpatialElement RelatedElements: SET [1:?] OF IfcSpatialReferenceSelect
IfcRelDefinesByProperties IfcRelDefines RelatingPropertyDefinition: IfcPropertySetDefinitionSelect RelatedObjects: SET [1:?] OF IfcObjectDefinition
IfcRelDefinesByType IfcRelDefines RelatingType: IfcTypeObject RelatedObjects: SET [1:?] OF IfcObject
IfcRelAssociatesMaterial IfcRelAssociates RelatingMaterial: IfcMaterialSelect RelatedObjects: SET [1:?] OF IfcDefinitionSelect
IfcRelAssociatesClassification IfcRelAssociates RelatingClassification: IfcClassificationSelect RelatedObjects: SET [1:?] OF IfcDefinitionSelect
IfcRelConnectsElements IfcRelConnects RelatingElement: IfcElement RelatedElement: IfcElement
IfcRelConnectsPathElements IfcRelConnectsElements inherits RelatingElement inherits RelatedElement
IfcRelVoidsElement IfcRelDecomposes RelatingBuildingElement: IfcElement RelatedOpeningElement: IfcFeatureElementSubtraction
IfcRelFillsElement IfcRelConnects RelatingOpeningElement: IfcOpeningElement RelatedBuildingElement: IfcElement
IfcRelSpaceBoundary IfcRelConnects RelatingSpace: IfcSpaceBoundarySelect RelatedBuildingElement: IfcElement

Note the reversed anchor between IfcRelVoidsElement and IfcRelFillsElement: see the door-in-wall pattern below.

Decision Trees

Which relationship do I use?

What am I trying to express?
|
+- A whole made of parts, order does NOT matter
|    -> IfcRelAggregates  (spatial tree, element assemblies)
|
+- A whole made of parts, order DOES matter
|    -> IfcRelNests  (ordered ports, ordered cost items, ordered tasks)
|
+- Place a physical element into a spatial level (storey, space)
|    -> IfcRelContainedInSpatialStructure
|
+- Reference an element from a second spatial structure
|    -> IfcRelReferencedInSpatialStructure
|
+- Attach a property set or quantity set to objects
|    -> IfcRelDefinesByProperties
|
+- Link occurrences to their shared type object
|    -> IfcRelDefinesByType
|
+- Assign a material to elements or element types
|    -> IfcRelAssociatesMaterial
|
+- Assign a classification reference (Uniclass, OmniClass)
|    -> IfcRelAssociatesClassification
|
+- Connect two elements physically or logically
|    -> IfcRelConnectsElements  (or IfcRelConnectsPathElements for wall joins)
|
+- Cut an opening into an element
|    -> IfcRelVoidsElement
|
+- Fill an opening with a door or window
|    -> IfcRelFillsElement
|
+- Define the surfaces that bound a space
|    -> IfcRelSpaceBoundary (or its 1stLevel / 2ndLevel subtypes)
|
+- Group objects across domains (a system, a zone, a schedule)
     -> IfcRelAssignsToGroup

Aggregate or nest?

Does the order of the parts carry meaning?
|
+- No  -> IfcRelAggregates : RelatedObjects is a SET, order is irrelevant.
|         The spatial tree (Project, Site, Building, Storey) ALWAYS uses
|         IfcRelAggregates.
|
+- Yes -> IfcRelNests : RelatedObjects is a LIST, position is meaningful.
          Use for ordered distribution ports, ordered cost items, ordered
          subtasks.

NEVER use IfcRelNests for the spatial tree. NEVER use IfcRelAggregates when the consumer depends on part order.

Containment or aggregation for the spatial tree?

What are the two objects?
|
+- Both are spatial elements (Site inside Project, Storey inside Building)
|    -> IfcRelAggregates : spatial element decomposes spatial element.
|
+- A physical element placed into a spatial element (a wall in a storey)
|    -> IfcRelContainedInSpatialStructure : NEVER IfcRelAggregates.
|
+- A physical element that also belongs to a second structure
     -> add IfcRelReferencedInSpatialStructure for the secondary link.
        The single primary containment stays IfcRelContainedInSpatialStructure.

A physical element ALWAYS sits in exactly ONE IfcRelContainedInSpatialStructure (the WR31 rule on that entity enforces at-most-once). Extra spatial links ALWAYS go through IfcRelReferencedInSpatialStructure. See ifc-core-spatial-structure.

Patterns

Every snippet uses STEP physical file syntax. $ marks an unset optional attribute. Attribute order is the EXPRESS declared order. Full verified signatures are in references/methods.md; runnable instances are in references/examples.md.

Pattern: aggregate parts into a whole

IfcRelAggregates has 6 positional attributes: the 4 from IfcRoot, then RelatingObject (the whole), then RelatedObjects (the SET of parts).

#30=IFCRELAGGREGATES(
  '1Hkj5pQ9X8x9bq0d6FZ7yA',  /* GlobalId        */
  #5,                        /* OwnerHistory    */
  $,                         /* Name            */
  $,                         /* Description     */
  #10,                       /* RelatingObject : IfcBuilding (the whole) */
  (#11,#12)                  /* RelatedObjects : the IfcBuildingStorey parts */
);

ALWAYS put the whole on RelatingObject and the parts on RelatedObjects. A reversed instance describes a storey aggregating a building.

Pattern: contain elements in a spatial structure

IfcRelContainedInSpatialStructure places physical elements into one spatial level. RelatedElements comes BEFORE RelatingStructure in the declared order.

#40=IFCRELCONTAINEDINSPATIALSTRUCTURE(
  '2k7sB$Qe9X8x9bq0d6FZ7y',  /* GlobalId        */
  #5,                        /* OwnerHistory    */
  'Storey contents',         /* Name            */
  $,                         /* Description     */
  (#21,#22),                 /* RelatedElements : the IfcWall occurrences */
  #11                        /* RelatingStructure : the IfcBuildingStorey */
);

Each physical element appears in RelatedElements of exactly one such relationship. NEVER list the same element in two IfcRelContainedInSpatialStructure instances.

Pattern: attach a property set

IfcRelDefinesByProperties links an IfcPropertySet or IfcElementQuantity to objects. RelatedObjects precedes RelatingPropertyDefinition.

#50=IFCRELDEFINESBYPROPERTIES(
  '3mNp7rTf0Y9y0cr1e7GA8z',  /* GlobalId                    */
  #5,                        /* OwnerHistory                */
  $,                         /* Name                        */
  $,                         /* Description                 */
  (#21,#22),                 /* RelatedObjects : the elements */
  #48                        /* RelatingPropertyDefinition : the IfcPropertySet */
);

One relationship can serve many objects (N-to-N). See ifc-syntax-property-sets for building the IfcPropertySet itself.

Pattern: link occurrences to a type

IfcRelDefinesByType is 1-to-N: one type, many occurrences.

#52=IFCRELDEFINESBYTYPE(
  '4pQr9sUg1Z0z1ds2f8HB9$',  /* GlobalId                  */
  #5,                        /* OwnerHistory              */
  $, $,                      /* Name, Description         */
  (#21,#22),                 /* RelatedObjects : IfcWall occurrences */
  #20                        /* RelatingType : the IfcWallType */
);

NEVER place a type object in RelatedObjects: that slot accepts IfcObject occurrences only. See ifc-core-entity-hierarchy for the type model.

Pattern: associate a material

IfcRelAssociatesMaterial inherits RelatedObjects from IfcRelAssociates and adds RelatingMaterial as the last attribute.

#54=IFCRELASSOCIATESMATERIAL(
  '5qRs0tVh2$1$2et3g9IC0_',  /* GlobalId                    */
  #5,                        /* OwnerHistory                */
  $, $,                      /* Name, Description           */
  (#21,#22),                 /* RelatedObjects : the elements */
  #53                        /* RelatingMaterial : IfcMaterial or IfcMaterialLayerSet... */
);

RelatingMaterial accepts the IfcMaterialSelect choices: IfcMaterial, IfcMaterialLayerSet, IfcMaterialLayerSetUsage, IfcMaterialProfileSet, IfcMaterialProfileSetUsage, IfcMaterialConstituentSet, IfcMaterialList. See ifc-syntax-materials.

Pattern: the door-in-wall void then fill

The canonical opening pattern uses two relationships, in this order:

  1. IfcRelVoidsElement subtracts an IfcOpeningElement from the wall.
  2. IfcRelFillsElement places the IfcDoor into that opening.
/* step 1 : the wall voids the opening */
#60=IFCRELVOIDSELEMENT(
  '6rSt1uWi3_2_3fu4h0JD1A',  /* GlobalId               */
  #5, $, $,                  /* OwnerHistory, Name, Description */
  #21,                       /* RelatingBuildingElement : the IfcWall */
  #58                        /* RelatedOpeningElement : the IfcOpeningElement */
);
/* step 2 : the opening is filled by the door */
#62=IFCRELFILLSELEMENT(
  '7sTu2vXj4A3A4gv5i1KE2B',  /* GlobalId               */
  #5, $, $,                  /* OwnerHistory, Name, Description */
  #58,                       /* RelatingOpeningElement : the IfcOpeningElement */
  #59                        /* RelatedBuildingElement : the IfcDoor */
);

The anchor reverses between the two relationships. The wall is the Relating side of IfcRelVoidsElement; the SAME opening (#58) is the Relating side of IfcRelFillsElement. ALWAYS create the void first, then the fill. NEVER point IfcRelFillsElement straight from wall to door: the door fills the opening, not the wall.

Version note: IfcRelVoidsElement is a subtype of IfcRelDecomposes in IFC4 and IFC4.3. In IFC2x3 it sat under the connectivity branch. The attribute names and order are stable across all three versions.

Pattern: traverse through INVERSE attributes

Objects do not store relationships as forward attributes. They expose INVERSE attributes that the parser populates by scanning relationship instances. To find what defines an object, follow its inverses:

From object INVERSE attribute Reaches
IfcObject IsDefinedBy IfcRelDefinesByProperties, IfcRelDefinesByType
IfcObjectDefinition IsDecomposedBy IfcRelAggregates where this is the whole
IfcObjectDefinition Decomposes IfcRelAggregates where this is a part
IfcObjectDefinition HasAssociations IfcRelAssociatesMaterial, IfcRelAssociatesClassification
IfcElement ContainedInStructure IfcRelContainedInSpatialStructure
IfcElement HasOpenings IfcRelVoidsElement
IfcOpeningElement HasFillings IfcRelFillsElement

To read a wall's property sets: take wall.IsDefinedBy, keep the IfcRelDefinesByProperties instances, then read each RelatingPropertyDefinition. NEVER look for a direct PropertySets attribute on the wall: it does not exist.

Anti-Patterns

Full detail with the failure mechanism is in references/anti-patterns.md. The five that matter most:

  • Reversing Relating and Related. The model parses but states the wrong fact (a storey aggregating a building, a part owning the whole).
  • Using IfcRelAggregates to place a physical element into a storey. Containment of physical elements ALWAYS uses IfcRelContainedInSpatialStructure.
  • Listing one element in two IfcRelContainedInSpatialStructure instances. Violates WR31; the element belongs to the spatial tree once only.
  • Pointing IfcRelFillsElement from the wall to the door directly, skipping the IfcOpeningElement. The door has nothing to fill.
  • Treating a relationship as a pointer and editing the participants to "connect" them. Connections ALWAYS exist only as IfcRel* instances.

Reference Links

This skill

  • references/methods.md: full positional attribute signatures for every IfcRel* entity in this skill, with supertypes and version notes.
  • references/examples.md: verified STEP physical file instances.
  • references/anti-patterns.md: failure modes and their root causes.

Related skills

  • ifc-core-entity-hierarchy: IfcRoot and the object inheritance tree that relationships connect.
  • ifc-core-spatial-structure: IfcProject, the spatial tree, the containment versus reference rule.
  • ifc-syntax-property-sets: building the IfcPropertySet attached via IfcRelDefinesByProperties.
  • ifc-syntax-building-elements: the concrete elements that participate as Relating and Related objects.

Official sources