| name | ifcos-syntax-elements |
| description | Use when querying, traversing, or extracting data from IFC elements -- by_type, by_id, by_guid, inverse references, or property extraction. Prevents the common mistake of manually traversing relationships instead of using the universal property extraction pattern (IsDefinedBy -> HasProperties). Covers get_info(), is_a(), GUID utilities, and attribute access patterns. Keywords: by_type, by_id, by_guid, get_info, is_a, inverse, IsDefinedBy, HasProperties, IFC query, element traversal, property extraction, find all walls, get element by GlobalId, list elements.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires IfcOpenShell Python library. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
IfcOpenShell Element Traversal and Querying
Quick Reference
Decision Tree: Finding Elements
Need to find IFC elements?
├── Know the IFC class? (IfcWall, IfcDoor, etc.)
│ └── model.by_type("IfcWall")
│ ├── Need subtypes included? → include_subtypes=True (DEFAULT)
│ └── Need exact type only? → include_subtypes=False
│
├── Know the STEP ID? (#123 in .ifc file)
│ └── model.by_id(123)
│ └── WARNING: STEP IDs are NOT persistent across re-exports
│
├── Know the GlobalId? (22-char IFC GUID)
│ └── model.by_guid("2O2Fr$t4X7Zf8NOew3FLOH")
│ └── GlobalId is ONLY on IfcRoot-derived entities
│
├── Need complex filtering? (by property, container, material)
│ └── ifcopenshell.util.selector.filter_elements(model, query)
│
└── Need ALL entities in the file?
└── for entity in model: ...
Decision Tree: Reading Element Data
Need data from an element?
├── Single attribute? → element.Name, element.GlobalId, etc.
│
├── All attributes as dict? → element.get_info()
│ ├── Need referenced entities expanded? → get_info(recursive=True)
│ │ └── WARNING: EXPENSIVE on large models — avoid in loops
│ └── Need only primitive values? → get_info(scalar_only=True)
│
├── Type checking?
│ ├── Get type name → element.is_a() # returns "IfcWall"
│ └── Check inheritance → element.is_a("IfcElement") # returns True/False
│
├── Property sets?
│ ├── RECOMMENDED → ifcopenshell.util.element.get_psets(element)
│ └── Manual pattern → element.IsDefinedBy traversal (see below)
│
├── Spatial container? → ifcopenshell.util.element.get_container(element)
├── Element type? → ifcopenshell.util.element.get_type(element)
├── Material? → ifcopenshell.util.element.get_material(element)
└── STEP ID? → element.id()
Critical Warnings
- ALWAYS use
model.by_type() for type-based queries — it is internally cached after the first call per type.
- ALWAYS use
ifcopenshell.guid.new() to generate GlobalIds. NEVER construct GUID strings manually.
- ALWAYS use
ifcopenshell.util.element.get_psets() for property extraction in production code. Use the manual IsDefinedBy traversal only when you need fine-grained control.
- NEVER use STEP IDs (
entity.id()) as persistent identifiers. They change when files are re-exported. Use GlobalId for cross-session identification.
- NEVER call
get_info(recursive=True) in a loop over many elements — it recursively expands all references and is extremely expensive.
- NEVER assume an entity has a
GlobalId. Only IfcRoot-derived entities (IfcWall, IfcProject, etc.) have GlobalIds. Low-level entities (IfcCartesianPoint, IfcDirection) do NOT.
- ALWAYS handle
None values when accessing optional attributes. Many IFC attributes are optional and return None.
- ALWAYS check
prop.NominalValue is not None before accessing .wrappedValue in the property extraction pattern.
Essential Patterns
Pattern 1: Query Elements by IFC Class
import ifcopenshell
model = ifcopenshell.open("model.ifc")
walls = model.by_type("IfcWall")
walls_exact = model.by_type("IfcWall", include_subtypes=False)
storeys = model.by_type("IfcBuildingStorey")
spaces = model.by_type("IfcSpace")
doors = model.by_type("IfcDoor")
windows = model.by_type("IfcWindow")
slabs = model.by_type("IfcSlab")
columns = model.by_type("IfcColumn")
beams = model.by_type("IfcBeam")
Pattern 2: Query by ID and GUID
import ifcopenshell
import ifcopenshell.guid
model = ifcopenshell.open("model.ifc")
entity = model.by_id(123)
entity = model.by_guid("2O2Fr$t4X7Zf8NOew3FLOH")
new_guid = ifcopenshell.guid.new()
standard_uuid = ifcopenshell.guid.expand(new_guid)
ifc_guid = ifcopenshell.guid.compress(standard_uuid)
Pattern 3: Entity Attribute Access and Type Checking
wall = model.by_type("IfcWall")[0]
print(wall.Name)
print(wall.GlobalId)
print(wall.Description)
wall.is_a()
wall.is_a("IfcWall")
wall.is_a("IfcElement")
wall.is_a("IfcRoot")
wall.is_a("IfcSlab")
wall.id()
info = wall.get_info()
Pattern 4: Inverse References
wall = model.by_type("IfcWall")[0]
inverse = model.get_inverse(wall)
for rel in model.get_inverse(wall):
if rel.is_a("IfcRelContainedInSpatialStructure"):
print(f"Wall is in: {rel.RelatingStructure.Name}")
for rel in model.get_inverse(wall):
if rel.is_a("IfcRelDefinesByProperties"):
pset = rel.RelatingPropertyDefinition
if pset.is_a("IfcPropertySet"):
print(f"PSet: {pset.Name}")
for rel in model.get_inverse(wall):
if rel.is_a("IfcRelDefinesByType"):
print(f"Type: {rel.RelatingType.Name}")
Pattern 5: Universal IFC Property Extraction
This is the fundamental pattern for extracting properties from ANY IFC element. It traverses: IsDefinedBy → IfcRelDefinesByProperties → IfcPropertySet → HasProperties → wrappedValue.
def extract_properties(element):
"""Extract all property sets and their values from an IFC element."""
result = {}
for rel in element.IsDefinedBy:
if rel.is_a("IfcRelDefinesByProperties"):
pset = rel.RelatingPropertyDefinition
if pset.is_a("IfcPropertySet"):
props = {}
for prop in pset.HasProperties:
if prop.is_a("IfcPropertySingleValue") and prop.NominalValue:
props[prop.Name] = prop.NominalValue.wrappedValue
result[pset.Name] = props
return result
wall = model.by_type("IfcWall")[0]
all_props = extract_properties(wall)
for pset_name, props in all_props.items():
print(f"\n{pset_name}:")
for name, value in props.items():
print(f" {name}: {value}")
Pattern 6: Recommended: Use util.element Helpers
import ifcopenshell.util.element
wall = model.by_type("IfcWall")[0]
psets = ifcopenshell.util.element.get_psets(wall)
psets_and_qsets = ifcopenshell.util.element.get_psets(wall, psets_only=False)
qsets = ifcopenshell.util.element.get_psets(wall, qtos_only=True)
wall_type = ifcopenshell.util.element.get_type(wall)
container = ifcopenshell.util.element.get_container(wall)
material = ifcopenshell.util.element.get_material(wall)
materials = ifcopenshell.util.element.get_materials(wall)
parent = ifcopenshell.util.element.get_aggregate(wall)
building = model.by_type("IfcBuilding")[0]
children = ifcopenshell.util.element.get_decomposition(building)
Common Operations
Iterating Over All Entities
for entity in model:
pass
total = len(model)
from collections import Counter
type_counts = Counter(entity.is_a() for entity in model)
for ifc_type, count in type_counts.most_common(20):
print(f" {ifc_type}: {count}")
Finding Openings in a Wall
def get_openings(model, wall):
"""Get opening elements that void a wall."""
openings = []
for rel in model.get_inverse(wall):
if rel.is_a("IfcRelVoidsElement"):
openings.append(rel.RelatedOpeningElement)
return openings
CSS-like Element Selection
import ifcopenshell.util.selector
walls = ifcopenshell.util.selector.filter_elements(model, "IfcWall")
ext_walls = ifcopenshell.util.selector.filter_elements(
model, 'IfcWall, /Pset_WallCommon/.IsExternal = True')
ground_elements = ifcopenshell.util.selector.filter_elements(
model, 'IfcBuildingElement, container="Ground Floor"')
Error Handling for Lookups
try:
entity = model.by_id(999999)
except RuntimeError:
print("Entity not found")
try:
entity = model.by_guid("nonexistent_guid_12345")
except RuntimeError:
print("Entity not found")
walls = model.by_type("IfcWall")
Version Notes
Schema-Specific Entity Names
| Concept | IFC2X3 | IFC4 | IFC4X3 |
|---|
| Building elements parent | IfcBuildingElement | IfcBuildingElement | IfcBuiltElement |
| Spatial elements parent | IfcSpatialStructureElement | IfcSpatialElement | IfcSpatialElement |
| Wall subtype | IfcWallStandardCase | IfcWall (subtype removed) | IfcWall |
| Facility types | N/A | N/A | IfcBridge, IfcRoad, IfcRailway, IfcMarineFacility |
Query API Compatibility
The query methods (by_type, by_id, by_guid, get_inverse, get_info, is_a) are schema-agnostic — they work identically across IFC2X3, IFC4, and IFC4X3. Only the entity class names passed to these methods differ per schema.
GUID Module
ifcopenshell.guid is schema-independent. The same GUID format (22-character base64) is used across all IFC versions.
| Function | Purpose |
|---|
ifcopenshell.guid.new() | Generate a new IFC GlobalId |
ifcopenshell.guid.expand(ifc_guid) | Convert IFC GUID → standard UUID string |
ifcopenshell.guid.compress(uuid_str) | Convert UUID string → 22-char IFC GUID |
Reference Links