SuperAPI AI Directory

ifcos-syntax-fileio

Writing & research

View repository

Updated 10-15 22:17

About this skill

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