ifcos-impl-creation
IFC Model Creation Workflows
Quick Reference
Decision Tree: Starting a New IFC Model
Creating a new IFC model?
├── Production model with proper header/metadata?
│ └── YES → model = ifcopenshell.api.run("project.create_file", version="IFC4")
│
└── Bare-minimum test file?
└── model = ifcopenshell.file(schema="IFC4")
└── WARNING: No header, no project, no units. Add these manually.
Decision Tree: Choosing IFC Schema Version
Which schema version?
├── Building/architecture project?
│ ├── Legacy compatibility needed? → IFC2X3
│ │ └── WARNING: OwnerHistory is REQUIRED on all rooted entities
│ └── Modern project? → IFC4
│
├── Infrastructure project (roads, bridges, tunnels)?
│ └── IFC4X3
│ └── Adds: IfcBridge, IfcRoad, IfcTunnel, IfcAlignment
│
└── Unsure? → Default to IFC4
Decision Tree: Element Creation Order
Building an IFC model from scratch?
Follow this EXACT order:
1. Create file → project.create_file
2. Create IfcProject → root.create_entity
3. Assign units → unit.assign_unit
4. Add contexts → context.add_context (Model + Body subcontext)
5. Create spatial hierarchy:
a. IfcSite → root.create_entity + aggregate.assign_object
b. IfcBuilding → root.create_entity + aggregate.assign_object
c. IfcBuildingStorey → root.create_entity + aggregate.assign_object
6. Create types (optional but recommended):
a. IfcWallType etc. → root.create_entity
b. Assign materials → material.add_material_set + material.assign_material
7. Create elements:
a. Create entity → root.create_entity
b. Add geometry → geometry.add_wall_representation (etc.)
c. Assign geometry → geometry.assign_representation
d. Set placement → geometry.edit_object_placement
e. Assign container → spatial.assign_container
f. Assign type → type.assign_type
8. Add properties → pset.add_pset + pset.edit_pset
9. Write file → model.write("output.ifc")
Critical Warnings
- ALWAYS use
ifcopenshell.api.run()for entity creation. NEVER usemodel.create_entity()directly — the API handles GlobalId generation, OwnerHistory, and validation automatically. - ALWAYS create the spatial hierarchy (Project → Site → Building → Storey) before creating physical elements. Elements without spatial containment are invisible in most BIM viewers.
- ALWAYS assign spatial containment via
spatial.assign_containerfor physical elements (walls, slabs, columns, doors). Without containment, elements float in the model with no spatial context. - ALWAYS set up geometric contexts (Model → Body subcontext) before creating geometry. Geometry without a context cannot be displayed.
- ALWAYS assign units via
unit.assign_unitimmediately after creating the project. Without units, all dimensions are ambiguous. - NEVER skip
geometry.edit_object_placementafter creating an element. Without a placement, the element has no position in 3D space. - NEVER create physical elements and types with mismatched IFC classes. An IfcWall occurrence MUST use IfcWallType, not IfcSlabType.
- IFC2X3 ONLY: OwnerHistory is REQUIRED on every rooted entity. The
root.create_entityAPI handles this automatically, but ONLY if an owner/user has been set viaowner.set_user. Callowner.set_userbefore creating any entities in IFC2X3.
Essential Patterns
Pattern 1: Complete IFC4 Model from Scratch
# IfcOpenShell — IFC4
import ifcopenshell
import ifcopenshell.api
# Step 1: Create file with proper header
model = ifcopenshell.api.run("project.create_file", version="IFC4")
# Step 2: Create project
project = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcProject", name="My Project")
# Step 3: Assign SI units (meters, radians)
ifcopenshell.api.run("unit.assign_unit", model)
# Step 4: Set up geometric context
model3d = ifcopenshell.api.run("context.add_context", model,
context_type="Model")
body = ifcopenshell.api.run("context.add_context", model,
context_type="Model", context_identifier="Body",
target_view="MODEL_VIEW", parent=model3d)
# Step 5: Create spatial hierarchy
site = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcSite", name="Default Site")
building = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcBuilding", name="Building A")
storey = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcBuildingStorey", name="Ground Floor")
ifcopenshell.api.run("aggregate.assign_object", model,
products=[site], relating_object=project)
ifcopenshell.api.run("aggregate.assign_object", model,
products=[building], relating_object=site)
ifcopenshell.api.run("aggregate.assign_object", model,
products=[storey], relating_object=building)
# Step 6: Create wall with geometry
wall = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcWall", name="Wall 001")
representation = ifcopenshell.api.run("geometry.add_wall_representation",
model, context=body, length=5.0, height=3.0, thickness=0.2)
ifcopenshell.api.run("geometry.assign_representation", model,
product=wall, representation=representation)
ifcopenshell.api.run("geometry.edit_object_placement", model, product=wall)
ifcopenshell.api.run("spatial.assign_container", model,
relating_structure=storey, products=[wall])
# Step 7: Add properties
pset = ifcopenshell.api.run("pset.add_pset", model,
product=wall, name="Pset_WallCommon")
ifcopenshell.api.run("pset.edit_pset", model, pset=pset, properties={
"IsExternal": True,
"LoadBearing": True,
"FireRating": "REI90"
})
# Step 8: Write
model.write("output.ifc")
Pattern 2: IFC2X3 Model with Required OwnerHistory
# IfcOpenShell — IFC2X3
import ifcopenshell
import ifcopenshell.api
# Create IFC2X3 file
model = ifcopenshell.api.run("project.create_file", version="IFC2X3")
# REQUIRED for IFC2X3: Set up owner BEFORE creating any entities
person = ifcopenshell.api.run("owner.add_person", model,
identification="jdoe", family_name="Doe", given_name="John")
org = ifcopenshell.api.run("owner.add_organisation", model,
identification="ACME", name="ACME Engineering")
user = ifcopenshell.api.run("owner.add_person_and_organisation", model,
person=person, organisation=org)
application = ifcopenshell.api.run("owner.add_application", model)
ifcopenshell.api.run("owner.set_user", model, user=user)
# Now create entities — OwnerHistory is automatically attached
project = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcProject", name="Legacy Project")
ifcopenshell.api.run("unit.assign_unit", model)
site = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcSite", name="Site")
building = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcBuilding", name="Building")
storey = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcBuildingStorey", name="Ground Floor")
ifcopenshell.api.run("aggregate.assign_object", model,
products=[site], relating_object=project)
ifcopenshell.api.run("aggregate.assign_object", model,
products=[building], relating_object=site)
ifcopenshell.api.run("aggregate.assign_object", model,
products=[storey], relating_object=building)
Pattern 3: Spatial Hierarchy with Multiple Storeys
# IfcOpenShell — IFC4
# After project, units, and contexts are set up:
site = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcSite", name="Main Site")
building = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcBuilding", name="Office Block")
# Create multiple storeys
basement = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcBuildingStorey", name="Basement")
ground = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcBuildingStorey", name="Ground Floor")
first = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcBuildingStorey", name="First Floor")
roof = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcBuildingStorey", name="Roof")
# Aggregate: Project → Site → Building → all storeys
ifcopenshell.api.run("aggregate.assign_object", model,
products=[site], relating_object=project)
ifcopenshell.api.run("aggregate.assign_object", model,
products=[building], relating_object=site)
ifcopenshell.api.run("aggregate.assign_object", model,
products=[basement, ground, first, roof], relating_object=building)
# Set storey elevations using object placement
import numpy as np
for storey_obj, elevation in [(basement, -3.0), (ground, 0.0),
(first, 3.5), (roof, 7.0)]:
matrix = np.eye(4)
matrix[2][3] = elevation # Z translation = elevation
ifcopenshell.api.run("geometry.edit_object_placement", model,
product=storey_obj, matrix=matrix)
Pattern 4: Creating Elements with Type Assignment
# IfcOpenShell — IFC4
# Create a wall type with material layers
wall_type = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcWallType", name="WT-200 External")
# Set up material layers for the type
layer_set = ifcopenshell.api.run("material.add_material_set", model,
name="WT-200", set_type="IfcMaterialLayerSet")
brick = ifcopenshell.api.run("material.add_material", model,
name="Brick", category="brick")
insulation = ifcopenshell.api.run("material.add_material", model,
name="Insulation", category="mineral wool")
plaster = ifcopenshell.api.run("material.add_material", model,
name="Gypsum Plaster", category="gypsum")
layer1 = ifcopenshell.api.run("material.add_layer", model,
layer_set=layer_set, material=brick)
ifcopenshell.api.run("material.edit_layer", model,
layer=layer1, attributes={"LayerThickness": 0.102})
layer2 = ifcopenshell.api.run("material.add_layer", model,
layer_set=layer_set, material=insulation)
ifcopenshell.api.run("material.edit_layer", model,
layer=layer2, attributes={"LayerThickness": 0.080})
layer3 = ifcopenshell.api.run("material.add_layer", model,
layer_set=layer_set, material=plaster)
ifcopenshell.api.run("material.edit_layer", model,
layer=layer3, attributes={"LayerThickness": 0.018})
ifcopenshell.api.run("material.assign_material", model,
products=[wall_type], type="IfcMaterialLayerSet", material=layer_set)
# Create wall occurrences and assign the type
wall1 = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcWall", name="Wall 001")
wall2 = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcWall", name="Wall 002")
ifcopenshell.api.run("type.assign_type", model,
related_objects=[wall1, wall2], relating_type=wall_type)
Pattern 5: Creating Openings (Doors and Windows)
# IfcOpenShell — IFC4
# Prerequisites: wall exists, body context exists, storey exists
# Create opening element
opening = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcOpeningElement", name="Door Opening")
opening_rep = ifcopenshell.api.run("geometry.add_wall_representation",
model, context=body, length=0.9, height=2.1, thickness=0.2)
ifcopenshell.api.run("geometry.assign_representation", model,
product=opening, representation=opening_rep)
ifcopenshell.api.run("geometry.edit_object_placement", model,
product=opening)
# Cut opening in wall (boolean subtraction)
ifcopenshell.api.run("void.add_opening", model,
opening=opening, element=wall)
# Create door and fill the opening
door = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDoor", name="Door 001")
ifcopenshell.api.run("void.add_filling", model,
opening=opening, element=door)
ifcopenshell.api.run("spatial.assign_container", model,
relating_structure=storey, products=[door])
Pattern 6: Property Sets and Quantity Sets
# IfcOpenShell — IFC4
# Add standard property set to wall
pset = ifcopenshell.api.run("pset.add_pset", model,
product=wall, name="Pset_WallCommon")
ifcopenshell.api.run("pset.edit_pset", model, pset=pset, properties={
"Reference": "WT-200",
"IsExternal": True,
"LoadBearing": True,
"FireRating": "REI60",
"ThermalTransmittance": 0.28
})
# Add quantity set
qto = ifcopenshell.api.run("pset.add_qto", model,
product=wall, name="Qto_WallBaseQuantities")
ifcopenshell.api.run("pset.edit_qto", model, qto=qto, properties={
"Length": 5.0,
"Height": 3.0,
"Width": 0.2,
"GrossSideArea": 15.0,
"NetSideArea": 13.11,
"GrossVolume": 3.0
})
# Custom property set (use project-specific prefix, NOT "Pset_")
custom_pset = ifcopenshell.api.run("pset.add_pset", model,
product=wall, name="ACME_WallData")
ifcopenshell.api.run("pset.edit_pset", model, pset=custom_pset, properties={
"CostCode": "STR-W-001",
"InstallDate": "2026-03-15",
"Inspector": "J. Doe"
})
Pattern 7: Slab and Column Creation
# IfcOpenShell — IFC4
# Slab with polyline footprint
slab = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcSlab", name="Floor Slab", predefined_type="FLOOR")
slab_rep = ifcopenshell.api.run("geometry.add_slab_representation", model,
context=body, depth=0.25,
polyline=[(0.0, 0.0), (10.0, 0.0), (10.0, 8.0), (0.0, 8.0)])
ifcopenshell.api.run("geometry.assign_representation", model,
product=slab, representation=slab_rep)
ifcopenshell.api.run("geometry.edit_object_placement", model, product=slab)
ifcopenshell.api.run("spatial.assign_container", model,
relating_structure=storey, products=[slab])
# Column with profile
column = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcColumn", name="Column C1")
profile = ifcopenshell.api.run("profile.add_parameterised_profile", model,
ifc_class="IfcRectangleProfileDef", XDim=0.3, YDim=0.3)
col_rep = ifcopenshell.api.run("geometry.add_profile_representation", model,
context=body, profile=profile, depth=3.0)
ifcopenshell.api.run("geometry.assign_representation", model,
product=column, representation=col_rep)
ifcopenshell.api.run("geometry.edit_object_placement", model, product=column)
ifcopenshell.api.run("spatial.assign_container", model,
relating_structure=storey, products=[column])
Version Notes
IFC2X3 vs IFC4+ Entity Differences
| Feature | IFC2X3 | IFC4 / IFC4X3 |
|---|---|---|
| OwnerHistory | REQUIRED on all rooted entities | OPTIONAL |
| IfcWallStandardCase | EXISTS (use for layered walls) | DEPRECATED (use IfcWall with PredefinedType) |
| IfcBuildingStorey | Only valid spatial container | IfcBuildingStorey + IfcSpace + IfcFacility |
| Property set types | IfcPropertySingleValue only | Adds IfcPropertyBoundedValue, IfcPropertyTableValue |
| Material sets | IfcMaterialList (legacy) | IfcMaterialConstituentSet (preferred) |
IFC4X3 Infrastructure Entities (Not Available in IFC2X3/IFC4)
IfcBridge,IfcBridgePartIfcRoad,IfcRoadPartIfcRailway,IfcRailwayPartIfcTunnel,IfcTunnelPartIfcAlignment,IfcLinearElementIfcFacility,IfcFacilityPart
Aggregation Hierarchy by Schema
| Schema | Standard Hierarchy |
|---|---|
| IFC2X3 | IfcProject → IfcSite → IfcBuilding → IfcBuildingStorey → IfcSpace |
| IFC4 | IfcProject → IfcSite → IfcBuilding → IfcBuildingStorey → IfcSpace |
| IFC4X3 | IfcProject → IfcSite → IfcFacility (or IfcBuilding/IfcBridge/IfcRoad) → IfcFacilityPart (or IfcBuildingStorey) → IfcSpace |
Type-to-Occurrence Mapping (Common Elements)
| Element Type | Occurrence Class | Notes |
|---|---|---|
| IfcWallType | IfcWall | IFC2X3: also IfcWallStandardCase |
| IfcSlabType | IfcSlab | Use predefined_type: FLOOR, ROOF, BASESLAB, LANDING |
| IfcColumnType | IfcColumn | |
| IfcBeamType | IfcBeam | |
| IfcDoorType | IfcDoor | IFC2X3: IfcDoorStyle (not IfcDoorType) |
| IfcWindowType | IfcWindow | IFC2X3: IfcWindowStyle (not IfcWindowType) |
| IfcCurtainWallType | IfcCurtainWall |
Common Operations
Set Up Geometric Contexts
# IfcOpenShell — IFC4
# Root context (REQUIRED before any subcontexts)
model3d = ifcopenshell.api.run("context.add_context", model,
context_type="Model")
# Body subcontext (REQUIRED for 3D solid geometry)
body = ifcopenshell.api.run("context.add_context", model,
context_type="Model", context_identifier="Body",
target_view="MODEL_VIEW", parent=model3d)
# Optional: Axis subcontext (for wall/beam centerlines)
axis = ifcopenshell.api.run("context.add_context", model,
context_type="Model", context_identifier="Axis",
target_view="GRAPH_VIEW", parent=model3d)
# Optional: Plan context (for 2D representations)
plan = ifcopenshell.api.run("context.add_context", model,
context_type="Plan")
plan_body = ifcopenshell.api.run("context.add_context", model,
context_type="Plan", context_identifier="Body",
target_view="PLAN_VIEW", parent=plan)
Position Elements with Transformation Matrix
# IfcOpenShell — IFC4
import numpy as np
# Place wall at specific X, Y, Z coordinates
matrix = np.eye(4)
matrix[0][3] = 5.0 # X offset = 5 meters
matrix[1][3] = 2.0 # Y offset = 2 meters
matrix[2][3] = 0.0 # Z offset = 0 meters (ground level)
ifcopenshell.api.run("geometry.edit_object_placement", model,
product=wall, matrix=matrix)
# Rotate element 90 degrees around Z axis
import math
angle = math.radians(90)
rotation_matrix = np.array([
[math.cos(angle), -math.sin(angle), 0, 0],
[math.sin(angle), math.cos(angle), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
])
ifcopenshell.api.run("geometry.edit_object_placement", model,
product=wall, matrix=rotation_matrix)
Shared Property Sets Across Multiple Elements
# IfcOpenShell — IFC4
# Create pset on first element
pset = ifcopenshell.api.run("pset.add_pset", model,
product=wall1, name="Pset_WallCommon")
ifcopenshell.api.run("pset.edit_pset", model, pset=pset, properties={
"IsExternal": True, "FireRating": "REI90"
})
# Share same pset with additional elements
ifcopenshell.api.run("pset.assign_pset", model,
products=[wall1, wall2, wall3], pset=pset)
Reference Links
- API Method Signatures — Complete signatures for all creation-related API methods
- Working Code Examples — End-to-end model creation examples
- Anti-Patterns — Common creation mistakes and how to avoid them
More from openaec-foundation/computational-design-day-delft-march-2026
blender-core-api
Guides Blender Python API usage including bpy module structure, RNA data access, context system, dependency graph, and operator invocation. Activates when writing bpy scripts, creating Blender addons, or accessing Blender data blocks programmatically.
1blender-syntax-panels
Defines Blender UI panel creation including bpy.types.Panel, draw() method, UILayout API (row/column/box/split), bl_space_type, bl_region_type, bl_category, sub-panels, draw_header, menus, and UIList. Activates when creating custom Blender panels, building addon interfaces, or working with UILayout elements.
1ifcos-syntax-api
Documents the ifcopenshell.api module system with all 30+ API modules, invocation patterns via api.run() and direct module calls, parameter conventions, and module categorization. Activates when creating IFC entities, modifying properties, managing spatial structure, or using any ifcopenshell.api function.
1bonsai-impl-bcf
Guides implementation of BIM Collaboration Format (BCF) workflows in Bonsai including creating BCF topics, adding viewpoints with camera snapshots, managing comments, importing/exporting BCF files (v2.1 and v3.0), and integrating BCF issue tracking with IFC element references. Activates when working with BCF files, BIM issue tracking, clash report management, or collaboration workflows in Bonsai.
1ifcos-impl-cost
Guides IFC cost management using ifcopenshell.api.cost including cost schedules, cost items, cost values, cost quantities, and 5D BIM workflows. Activates when implementing cost estimation in IFC models, creating cost schedules, or linking quantities to cost items.
1blender-syntax-modifiers
Covers Blender modifier stack API including adding/removing modifiers, applying modifiers via operators, evaluated mesh access via depsgraph, Geometry Nodes modifier input identifiers, and common AEC modifiers (Array, Boolean, Solidify). Activates when working with modifiers programmatically, applying modifiers to meshes, or accessing Geometry Nodes inputs.
1