ifcos-syntax-fileio

Installation
SKILL.md

IfcOpenShell File I/O Operations

Quick Reference

Decision Tree: Opening vs Creating IFC Files

Need an IFC model?
├── Existing file on disk?
│   └── YES → ifcopenshell.open("path/to/file.ifc")
│       ├── Large file (100MB+)? → use should_stream=True
│       └── Non-standard extension? → use format=".ifc"
└── NO → Create new file
    ├── Need header metadata, timestamps, MVD? (production use)
    │   └── YES → ifcopenshell.api.project.create_file(version="IFC4")
    └── Need bare-minimum empty file? (testing, prototyping)
        └── ifcopenshell.file(schema="IFC4")

Decision Tree: Writing Output

Need to output IFC data?
├── Write to disk?
│   ├── Standard .ifc → model.write("output.ifc")
│   ├── XML format → model.write("output.ifcXML")
│   ├── Compressed → model.write("output.ifc", zipped=True)
│   └── ZIP archive → model.write("output.ifcZIP")
└── Get as string? → model.to_string()

Critical Warnings

  • ALWAYS specify schema= explicitly when calling ifcopenshell.file(). The default is "IFC4" but relying on implicit defaults is error-prone.
  • ALWAYS check model.schema after opening a file before using schema-specific entities.
  • NEVER use ifcopenshell.file() for production IFC creation. Use ifcopenshell.api.project.create_file() instead — it sets up header metadata, timestamps, and MVD automatically.
  • NEVER call model.remove() without understanding that references to the removed entity become null. Use ifcopenshell.api.run("root.remove_product", ...) for safe removal of products.
  • ALWAYS wrap undo-able operations in begin_transaction() / end_transaction() pairs. NEVER leave a transaction open.
  • NEVER call undo() or redo() while a transaction is active.

Essential Patterns

Pattern 1: Open an Existing IFC File

# IfcOpenShell — all schema versions
import ifcopenshell

model = ifcopenshell.open("/path/to/model.ifc")
print(model.schema)  # "IFC2X3", "IFC4", or "IFC4X3"
print(f"Entities: {len(model)}")

Pattern 2: Create a New IFC File (Production)

# IfcOpenShell — IFC4 (change version= for IFC2X3 or IFC4X3)
import ifcopenshell
import ifcopenshell.api

model = ifcopenshell.api.run("project.create_file", version="IFC4")
project = ifcopenshell.api.run("root.create_entity", model,
    ifc_class="IfcProject", name="My Project")
ifcopenshell.api.run("unit.assign_unit", model)
context = ifcopenshell.api.run("context.add_context", model,
    context_type="Model", context_identifier="Body",
    target_view="MODEL_VIEW")

Pattern 3: Create a New IFC File (Bare Minimum)

# IfcOpenShell — IFC4 (specify schema= for other versions)
import ifcopenshell

model = ifcopenshell.file(schema="IFC4")
# WARNING: This file has NO header, NO project, NO units.
# ALWAYS add at minimum: IfcProject, units, and a geometric context.

Pattern 4: Write IFC to Disk

# IfcOpenShell — all schema versions
model.write("/path/to/output.ifc")

# Write as compressed ZIP
model.write("/path/to/output.ifc", zipped=True)

# Write as XML format
model.write("/path/to/output.ifcXML")

Pattern 5: Serialize IFC to String

# IfcOpenShell — all schema versions
ifc_string = model.to_string()

Pattern 6: Transaction Management (Undo/Redo)

# IfcOpenShell — all schema versions
model.begin_transaction()

wall = model.create_entity("IfcWall",
    GlobalId=ifcopenshell.guid.new(), Name="Test Wall")

model.end_transaction()

# Undo the transaction
model.undo()

# Redo the transaction
model.redo()

Pattern 7: Transfer Entity Between Files

# IfcOpenShell — all schema versions
source = ifcopenshell.open("source.ifc")
target = ifcopenshell.file(schema=source.schema)

wall = source.by_type("IfcWall")[0]
target.add(wall)  # Recursively adds wall and all referenced entities
target.write("target.ifc")

Pattern 8: Remove Entity from File

# IfcOpenShell — all schema versions
wall = model.by_type("IfcWall")[0]
model.remove(wall)
# WARNING: All attributes referencing this entity become null ($).
# Aggregate references (lists/sets) are cleaned up automatically.

Common Operations

Opening Files

# IfcOpenShell — all schema versions
import ifcopenshell

# Standard file open
model = ifcopenshell.open("building.ifc")

# Open ZIP-compressed IFC
model = ifcopenshell.open("building.ifcZIP")

# Open XML-format IFC
model = ifcopenshell.open("building.ifcXML")

# Force format when extension is non-standard
model = ifcopenshell.open("building.dat", format=".ifc")

# Streaming mode for large files (100MB+)
# WARNING: Only supports sequential iteration, NOT random access
model = ifcopenshell.open("huge_model.ifc", should_stream=True)
for entity in model:
    if entity.is_a("IfcWall"):
        print(entity.Name)

Creating Files

# IfcOpenShell — IFC4 (change version/schema for other versions)
import ifcopenshell
import ifcopenshell.api

# RECOMMENDED: Production file with proper header
model = ifcopenshell.api.run("project.create_file", version="IFC4")

# Alternative: Bare empty file (testing only)
model = ifcopenshell.file(schema="IFC4")

# IFC2X3 file
model_legacy = ifcopenshell.file(schema="IFC2X3")

# IFC4X3 file (infrastructure projects)
model_infra = ifcopenshell.file(schema="IFC4X3")

# Specific schema sub-version
model_specific = ifcopenshell.file(schema_version=(4, 0, 2, 1))  # IFC4 ADD2 TC1

Writing Files

# IfcOpenShell — all schema versions
# Standard STEP format
model.write("output.ifc")

# XML serialization
model.write("output.ifcXML")

# ZIP-compressed STEP
model.write("output.ifcZIP")

# STEP with additional ZIP compression
model.write("output.ifc", zipped=True)

# ZIP-compressed XML
model.write("output.ifcXML", format=".ifcXML", zipped=True)

# Serialize to string (no file written)
ifc_text = model.to_string()

Adding and Removing Entities

# IfcOpenShell — all schema versions
import ifcopenshell

# Add entity from another file (copies entity + all dependencies)
source = ifcopenshell.open("source.ifc")
target = ifcopenshell.file(schema=source.schema)
wall = source.by_type("IfcWall")[0]
target.add(wall)

# Remove entity from file
model.remove(wall)

Transaction Management

# IfcOpenShell — all schema versions

# Basic transaction
model.begin_transaction()
wall = model.create_entity("IfcWall",
    GlobalId=ifcopenshell.guid.new(), Name="New Wall")
model.end_transaction()

# Undo last transaction
model.undo()

# Redo undone transaction
model.redo()

# Discard transaction without recording
model.begin_transaction()
# ... experimental changes ...
model.discard_transaction()

# Set maximum undo history size (default: 64)
model.set_history_size(128)

Error Handling

# IfcOpenShell — all schema versions
import ifcopenshell

try:
    model = ifcopenshell.open("model.ifc")
except FileNotFoundError:
    print("File not found")
except ifcopenshell.Error:
    print("Invalid or corrupt IFC file")

Accessing File Metadata

# IfcOpenShell — all schema versions
model = ifcopenshell.open("model.ifc")

# Schema information
print(model.schema)             # "IFC2X3", "IFC4", or "IFC4X3"
print(model.schema_identifier)  # e.g., "IFC4_ADD2"
print(model.schema_version)     # e.g., (4, 0, 2, 1)

# Header information
print(model.header.file_description)
print(model.header.file_name)
print(model.header.file_schema)

# Entity count
print(len(model))

Version Notes

Schema Parameter Differences

Method Parameter Values
ifcopenshell.file() schema= "IFC2X3", "IFC4", "IFC4X3"
ifcopenshell.api.project.create_file() version= "IFC2X3", "IFC4", "IFC4X3"

ALWAYS use the correct parameter name: schema= for file(), version= for create_file().

ifcopenshell.file() vs ifcopenshell.api.project.create_file()

Feature ifcopenshell.file() api.project.create_file()
Header metadata Empty/minimal Pre-populated (timestamp, app info)
Preprocessor Not set Set to "IfcOpenShell"
MVD Not set DesignTransferView default
Timestamp Not set Current timestamp
Use case Testing, prototyping Production IFC creation

Reference Links

Related skills

More from openaec-foundation/computational-design-day-delft-march-2026

Installs
1
GitHub Stars
1
First Seen
Mar 24, 2026