# Ifc Impl Property Extraction

> Use when reading property sets, quantities, or effective attribute values out of an IFC model and the extracted values look wrong, incomplete, empty, or missing. Prevents reading only occurrence property sets while ignoring inherited type defaults, using IsDefinedBy to reach the type in IFC4 and IFC4.3, treating an IfcElementQuantity as an IfcPropertySet, and forgetting to expand an IfcPropertySetDefinitionSet bundled inside one relationship. Covers the IsDefinedBy / IsTypedBy traversal, the type vs occurrence override resolution algorithm, reading IfcElementQuantity, resolving a property value unit, IfcPropertySetDefinitionSet expansion, standard Pset_ vs custom property sets, and the IFC2x3 vs IFC4 inverse-attribute split. Keywords: property extraction, read property set, IfcRelDefinesByProperties, IsDefinedBy, IsTypedBy, HasPropertySets, IfcElementQuantity, IfcPropertySet, type vs occurrence override, Pset_WallCommon, quantity takeoff, NominalValue, resolve unit, "property is missing", "value is empty", "w

- Skill: `impertio-studio/ifc-impl-property-extraction` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add impertio-studio/ifc-impl-property-extraction`
- Raw SKILL.md: https://api.skillmd.com/api/skills/impertio-studio/ifc-impl-property-extraction/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: MIT
- Author: Impertio-Studio (https://skillmd.com/u/impertio-studio)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/impertio-studio/ifc-impl-property-extraction

---


# 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.

