SuperAPI AI Directory

ifc-impl-property-extraction

General & other

View repository

Updated 10-15 22:18

About this skill

IFC Property Extraction

Read the effective property and quantity values of an IFC element. The hard part is not finding one IfcPropertySet ; it is resolving the type vs occurrence layering correctly and handling the IFC2x3 vs IFC4 inverse-attribute split.

This skill is read-side. For the write-side (attaching property sets) see ifc-impl-data-enrichment. For the entity definitions see ifc-syntax-property-sets and ifc-syntax-quantities.

Quick Reference

Goal Path Versions
Occurrence property sets occurrence.IsDefinedBy to IfcRelDefinesByProperties.RelatingPropertyDefinition all
Type of an occurrence (IFC4+) occurrence.IsTypedBy[0].RelatingType IFC4, IFC4.3
Type of an occurrence (IFC2x3) filter occurrence.IsDefinedBy for IfcRelDefinesByType, then .RelatingType IFC2x3
Type property sets typeObject.HasPropertySets (direct explicit attribute, no relationship hop) all
Properties in a set IfcPropertySet.HasProperties to IfcPropertySingleValue.NominalValue all
Quantities of an element IfcElementQuantity.Quantities to IfcQuantityArea.AreaValue etc. all
Standard set Name begins with Pset_ (properties) or Qto_ (quantities, IFC4+) all

Core facts

  • ALWAYS read BOTH the type-level sets AND the occurrence-level sets. Type sets are defaults ; occurrence sets override them. Reading one side only returns wrong values.
  • INVERSE attributes (IsDefinedBy, IsTypedBy, Types, ObjectTypeOf) are NOT stored in the STEP file. ALWAYS build them by scanning every IfcRelDefinesByProperties and IfcRelDefinesByType instance and grouping by RelatedObjects. See ifc-impl-reading-parsing.
  • IfcPropertySet and IfcElementQuantity share the same attachment relationship (IfcRelDefinesByProperties) and the same HasPropertySets slot. ALWAYS branch on the entity type after retrieval.
  • A property set Name is the lookup key for override resolution. NEVER override by list position or #id.

Decision Trees

Which traversal reaches the type

Target IFC version of the file (read FILE_SCHEMA in the header) ?
├─ IFC4 or IFC4.3
│   └─ occurrence.IsTypedBy : SET [0:1] OF IfcRelDefinesByType
│      └─ at most one ; .RelatingType is the IfcTypeObject (or NULL = untyped)
└─ IFC2x3
    └─ occurrence.IsDefinedBy : SET OF IfcRelDefines  (mixed)
       └─ filter members that are IfcRelDefinesByType ; .RelatingType is the type
          (IFC2x3 has NO IsTypedBy inverse ; the type relationship lives in IsDefinedBy)

Which inverse holds the occurrence property sets

Target IFC version ?
├─ IFC4 or IFC4.3
│   └─ occurrence.IsDefinedBy : SET [0:?] OF IfcRelDefinesByProperties  (properties only)
└─ IFC2x3
    └─ occurrence.IsDefinedBy : SET OF IfcRelDefines
       └─ keep ONLY the members that are IfcRelDefinesByProperties
          (drop the IfcRelDefinesByType members ; those are the type link)

Is a retrieved set a property set or a quantity set

entity is a subtype of IfcPropertySetDefinition. Which one ?
├─ IfcPropertySet          -> read .HasProperties (IfcProperty subtypes)
├─ IfcElementQuantity      -> read .Quantities    (IfcPhysicalQuantity subtypes)
└─ IfcPreDefinedPropertySet (e.g. IfcDoorPanelProperties, IFC2x3-style)
                           -> read its fixed named attributes, NOT HasProperties

Does the value carry a unit already

Reading IfcPropertySingleValue.NominalValue ?
├─ property.Unit is set         -> use property.Unit  (explicit local override)
└─ property.Unit is $ (unset)   -> the measure type of NominalValue implies the
                                   unit ; resolve it from IfcProject
                                   UnitsInContext (IfcUnitAssignment). See
                                   ifc-syntax-units.

Patterns

Pattern 1 : resolve the effective property sets of an element

The override rule (verified against the IFC4 ADD2 property-set template documentation) : when a property set with the same Name exists on both the type and the occurrence, and a property with the same Name exists in both, the occurrence property value wins. Type values are defaults.

function effectiveProperties(occurrence, schema):
    result = {}                       # psetName -> { propName -> property }

    # 1. TYPE LEVEL (defaults) - apply first
    typeObject = resolveType(occurrence, schema)
    if typeObject != NULL:
        for psd in (typeObject.HasPropertySets or []):
            mergeSet(result, psd)     # see Pattern 4 for expansion

    # 2. OCCURRENCE LEVEL (overrides) - apply second so it wins
    for rel in occurrence.IsDefinedBy:
        if not isInstance(rel, "IfcRelDefinesByProperties"):
            continue                  # IFC2x3 : skips IfcRelDefinesByType members
        for psd in expand(rel.RelatingPropertyDefinition):
            mergeSet(result, psd)

    return result

function mergeSet(result, psd):
    if not isInstance(psd, "IfcPropertySet"):
        return                        # IfcElementQuantity handled separately
    bucket = result.setdefault(psd.Name, {})
    for prop in psd.HasProperties:
        bucket[prop.Name] = prop      # later write (occurrence) overwrites earlier

ALWAYS apply the type level first and the occurrence level second so the second write overwrites on a Name collision. NEVER reverse the order.

Pattern 2 : resolve the type of an occurrence (version-split)

function resolveType(occurrence, schema):
    if schema in ("IFC4", "IFC4X3"):
        # IsTypedBy : SET [0:1] OF IfcRelDefinesByType
        if occurrence.IsTypedBy is not empty:
            return occurrence.IsTypedBy[0].RelatingType
        return NULL
    else:  # IFC2X3
        # no IsTypedBy ; the type link sits inside IsDefinedBy
        for rel in occurrence.IsDefinedBy:
            if isInstance(rel, "IfcRelDefinesByType"):
                return rel.RelatingType
        return NULL

IfcRelDefinesByType.RelatingType is the IfcTypeObject ; RelatedObjects are the occurrences. NEVER swap the direction. An element with no type relationship is valid : resolveType returns NULL and only occurrence sets apply.

Pattern 3 : read quantities (IfcElementQuantity)

IfcElementQuantity arrives through the SAME IfcRelDefinesByProperties / HasPropertySets channels as IfcPropertySet. Collect it the same way, then branch:

for psd in allRetrievedSets(occurrence):
    if isInstance(psd, "IfcElementQuantity"):
        for q in psd.Quantities:                 # SET [1:?] OF IfcPhysicalQuantity
            value = readQuantityValue(q)          # LengthValue / AreaValue / ...
            unit  = q.Unit or globalUnitFor(q)    # IfcPhysicalSimpleQuantity.Unit

Each IfcPhysicalSimpleQuantity subtype names its value attribute after its kind : IfcQuantityLength.LengthValue, IfcQuantityArea.AreaValue, IfcQuantityVolume.VolumeValue, IfcQuantityCount.CountValue, IfcQuantityWeight.WeightValue, IfcQuantityTime.TimeValue, IfcQuantityNumber.NumberValue (IFC4+). NEVER call .HasProperties on an IfcElementQuantity : that attribute does not exist on it.

Pattern 4 : expand IfcPropertySetDefinitionSet (IFC4+)

In IFC4 and IFC4.3, IfcRelDefinesByProperties.RelatingPropertyDefinition is the select IfcPropertySetDefinitionSelect, which is EITHER a single IfcPropertySetDefinition OR an IfcPropertySetDefinitionSet (a defined type : SET [1:?] OF IfcPropertySetDefinition). One relationship can therefore carry many sets at once.

function expand(relating):
    if isInstance(relating, "IfcPropertySetDefinitionSet"):
        return list(relating)              # the SET members
    return [relating]                      # a single IfcPropertySetDefinition

In IFC2x3 RelatingPropertyDefinition is always a single IfcPropertySetDefinition ; expand is a no-op there. NEVER assume one relationship equals one set in IFC4+.

Pattern 5 : resolve a property value unit

function resolveUnit(property, project):
    if property.Unit is set:
        return property.Unit               # explicit local override
    measureType = typeOf(property.NominalValue)   # e.g. IfcLengthMeasure
    unitEnum    = unitEnumFor(measureType)        # e.g. LENGTHUNIT
    for u in project.UnitsInContext.Units:
        if u.UnitType == unitEnum:
            return u                       # the project global unit
    return NULL                            # dimensionless or unresolved

A property never invents a unit. It either carries an explicit Unit, or its measure type maps to an IfcUnitEnum value resolved against the project IfcUnitAssignment. See ifc-syntax-units for the measure-to-unit table.

Pattern 6 : standard vs custom property sets

psetName.startsWith("Pset_")  ->  standard property set (documented template)
psetName.startsWith("Qto_")   ->  standard quantity set (IFC4+)
otherwise                     ->  custom / project-specific set

A custom set wrongly named with the reserved Pset_ or Qto_ prefix is an authoring anti-pattern, not a separate kind of set. ALWAYS read custom sets the same way as standard ones ; the prefix only signals whether a published template governs the contained property names and types. NEVER skip a set because it lacks the Pset_ prefix.

Worked Order of Operations

  1. Read FILE_SCHEMA from the STEP header to fix the version branch.
  2. Index every IfcRelDefinesByProperties and IfcRelDefinesByType to rebuild the IsDefinedBy / IsTypedBy inverses (ifc-impl-reading-parsing).
  3. For the target element : resolveType (Pattern 2).
  4. Collect type sets from typeObject.HasPropertySets, occurrence sets from IsDefinedBy, expanding each RelatingPropertyDefinition (Pattern 4).
  5. Split retrieved sets into property sets and quantity sets by entity type.
  6. Merge property sets type-first then occurrence-second (Pattern 1).
  7. For each value, resolve the unit (Pattern 5).

Reference Links

  • references/methods.md : exact attributes, cardinalities, version matrix, the measure-to-unit-enum table.
  • references/examples.md : worked STEP snippets and the full resolution walk-through.
  • references/anti-patterns.md : the failure modes and why each one is wrong.

Related skills

  • ifc-syntax-property-sets : IfcPropertySet, the IfcProperty value tree.
  • ifc-syntax-quantities : IfcElementQuantity, the seven quantity subtypes.
  • ifc-syntax-units : IfcUnitAssignment, measure-to-unit resolution.
  • ifc-impl-reading-parsing : rebuilding INVERSE attributes from a STEP file.
  • ifc-impl-data-enrichment : the write-side, attaching property sets.
  • ifc-errors-property-set-mistakes : WHERE-rule-backed property failures.

Verified sources

All entity names, attributes, and cardinalities verified 2026-05-20 via WebFetch against the buildingSMART specifications listed in SOURCES.md : IFC 4.3.2 spec, IFC4 ADD2 TC1 spec, IFC2x3 TC1 spec.