| name | ifc-impl-property-extraction |
| description | 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", "wrong value", "Pset not found", "quantities not showing", how do I read properties from an IFC file, what property set does an element have, where are the values stored.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires IFC IFC2x3, IFC4, IFC4.3. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
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
- Read
FILE_SCHEMA from the STEP header to fix the version branch.
- Index every
IfcRelDefinesByProperties and IfcRelDefinesByType to rebuild the
IsDefinedBy / IsTypedBy inverses (ifc-impl-reading-parsing).
- For the target element :
resolveType (Pattern 2).
- Collect type sets from
typeObject.HasPropertySets, occurrence sets from
IsDefinedBy, expanding each RelatingPropertyDefinition (Pattern 4).
- Split retrieved sets into property sets and quantity sets by entity type.
- Merge property sets type-first then occurrence-second (Pattern 1).
- 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.