ifc-commit/docs/ifcfile.md
2026-03-24 16:11:15 +01:00

4.1 KiB

ifcopenshell.file

An ifcopenshell.file is the in-memory representation of a parsed IFC file. It is the central object in every ifcbus operation — all reading, querying, modifying, and writing go through it.


Opening a file

import ifcopenshell

model = ifcopenshell.open("input.ifc")
# model is an ifcopenshell.file object

ifcopenshell.open() parses the STEP-encoded .ifc file and loads all entities into memory. The result is a live, mutable object graph.


What it contains

An IFC file is a flat list of entity instances, each identified by a sequential integer id (#1, #2, …). Entities reference each other by id, forming a directed graph.

#1  = IfcOrganization(...)
#2  = IfcApplication(#1, ...)
#33 = IfcOwnerHistory(#32, #2, ...)
#514 = IfcSpace('0BTBFw6f90Nfh9rP1dlXrr', #33, 'A101', ...)

The ifcopenshell.file object holds:

  • All entity instances (the flat list above)
  • Schema — e.g. IFC2X3, IFC4
  • Header — file metadata (author, application, description, timestamp)

Key methods

Querying

# By entity id (integer)
el = model.by_id(514)

# By GlobalId (GUID string)
el = model.by_guid("0BTBFw6f90Nfh9rP1dlXrr")

# All instances of a type (includes subtypes)
walls = model.by_type("IfcWall")         # returns list
spaces = model.by_type("IfcSpace")

# Iterate over every entity in the file
for entity in model:
    print(entity.id(), entity.is_a())

Relationships

# All entities that reference this element (inverse links)
refs = model.get_inverse(el)   # returns set of entity instances

# All entities reachable from this element (deep graph traversal)
graph = model.traverse(el)     # returns list, breadth-first

Modifying

# Create a new entity
org = model.create_entity("IfcOrganization", Name="ACME")

# Remove an entity and clean up its relationships
model.remove(el)

# Higher-level removal (cleans containment, placements, etc.)
import ifcopenshell.api
ifcopenshell.api.run("root.remove_product", model, product=el)

Writing

# Write back to a file
model.write("output.ifc")

# Or via ifcpatch (used when the result comes from a recipe)
import ifcpatch
ifcpatch.write(result, "output.ifc")

Schema and header

print(model.schema)                          # "IFC2X3" or "IFC4"
print(model.header.file_description)        # ViewDefinition, ...
print(model.header.file_name.name)          # original filename

Entity instances

Each element returned by the methods above is an entity instance (ifcopenshell.entity_instance). Its attributes are accessed as properties:

wall = model.by_type("IfcWall")[0]

wall.GlobalId        # GUID string
wall.Name            # element name
wall.is_a()          # "IfcWall" — runtime type string
wall.id()            # integer entity id (file-local, unstable across extractions)
wall.get_info()      # dict of all attribute name → value

Entity ids are not stable — the same physical element will have a different id after extraction or merging. Always use GlobalId or Name to identify elements across files.


Relationship to ifcpatch

ifcpatch.execute() takes an ifcopenshell.file as input and returns a new one as output. The input is never modified in place. ifcpatch.write() is a thin wrapper around model.write() with some post-processing.

result = ifcpatch.execute({
    "input": "input.ifc",
    "file":  model,          # ← ifcopenshell.file
    "recipe": "ExtractElements",
    "arguments": ["IfcWall"],
})
# result is a new ifcopenshell.file
ifcpatch.write(result, "output.ifc")

Memory model

The entire file is loaded into memory as a C++ object graph (via a Python binding). This means:

  • Operations are fast (no re-parsing on each query).
  • Large files consume significant RAM.
  • The object is not thread-safe — do not share across threads.
  • Passing the object to MergeProjects as a file path string (instead of the object itself) triggers a segfault in the current version — always pass the live object.