Install
$ agentstack add skill-impertio-studio-blender-bonsai-ifcopenshell-sverchok-claude-skill-package-ifcos-errors-performance Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Dangerous shell/eval execution.
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
IfcOpenShell Performance Optimization
Quick Reference
Decision Tree: Geometry Processing Strategy
Processing IFC geometry?
├── Single element (interactive/debug)?
│ └── ifcopenshell.geom.create_shape(settings, element)
│
├── Multiple elements (10+)?
│ └── ALWAYS use ifcopenshell.geom.iterator
│ ├── Need all elements? → iterator(settings, model, cpu_count())
│ └── Need specific types? → iterator(settings, model, cpu_count(), include=filtered)
│
└── No geometry needed (data extraction only)?
└── Skip geometry entirely — use by_type() + get_psets()
Decision Tree: Large File Strategy
File size?
├── 2 GB (very large)
├── Needs full model? → 32+ GB RAM required
├── Needs subset? → Extract IDs first, process in chunks
└── Geometry? → Process by type in sequence, gc.collect() between types
Critical Warnings
- ALWAYS use
ifcopenshell.geom.iteratorfor batch geometry processing (10+ elements). NEVER callcreate_shape()in a loop for bulk operations — iterator is 5-10x faster. - ALWAYS pass
multiprocessing.cpu_count()to the iterator for optimal parallelism. Reduce thread count only on memory-constrained systems. - ALWAYS cache
by_type()results when accessing the same type multiple times. The call is fast (O(1) internal index), but repeated calls add overhead in tight loops. - ALWAYS batch spatial containment and type assignments. Pass a list of products to a single API call instead of calling per-element.
- NEVER store all geometry shapes in memory simultaneously. Process each shape and discard immediately.
- NEVER use
get_info(recursive=True)on large files — it materializes the entire entity graph into Python dicts. - NEVER open the same large file multiple times. Open once and pass the
modelreference. - ALWAYS call
gc.collect()after releasing large models or between geometry processing batches.
Essential Patterns
Pattern 1: Geometry Iterator (Batch Processing)
# IfcOpenShell v0.8+: all schema versions
import ifcopenshell
import ifcopenshell.geom
import multiprocessing
model = ifcopenshell.open("model.ifc")
settings = ifcopenshell.geom.settings()
iterator = ifcopenshell.geom.iterator(
settings, model, multiprocessing.cpu_count()
)
if iterator.initialize():
while True:
shape = iterator.get()
element = model.by_id(shape.id)
verts = shape.geometry.verts # Flat: [x1,y1,z1, x2,y2,z2, ...]
faces = shape.geometry.faces # Flat: [i1,i2,i3, ...]
# Process immediately, do NOT accumulate shapes
if not iterator.next():
break
Pattern 2: Filtered Geometry Processing
# IfcOpenShell v0.8+: all schema versions
import ifcopenshell
import ifcopenshell.geom
import multiprocessing
model = ifcopenshell.open("large_model.ifc")
settings = ifcopenshell.geom.settings()
# Process only walls: reduces memory and time
walls = model.by_type("IfcWall")
iterator = ifcopenshell.geom.iterator(
settings, model, multiprocessing.cpu_count(),
include=walls
)
if iterator.initialize():
while True:
shape = iterator.get()
# Process shape...
if not iterator.next():
break
Pattern 3: Efficient Property Extraction (No Geometry)
# IfcOpenShell v0.8+: all schema versions
import ifcopenshell
import ifcopenshell.util.element
model = ifcopenshell.open("large_model.ifc")
# Build pset index ONCE from relationship entities
pset_rels = model.by_type("IfcRelDefinesByProperties")
pset_map = {}
for rel in pset_rels:
for obj in rel.RelatedObjects:
if obj.id() not in pset_map:
pset_map[obj.id()] = []
pset_map[obj.id()].append(rel.RelatingPropertyDefinition)
# Now O(1) lookup per element instead of traversing relationships each time
Pattern 4: Batch API Operations
# IfcOpenShell v0.8+: all schema versions
import ifcopenshell
import ifcopenshell.api
model = ifcopenshell.open("model.ifc")
storey = model.by_type("IfcBuildingStorey")[0]
walls = list(model.by_type("IfcWall"))
# CORRECT: Single API call for all elements
ifcopenshell.api.run("spatial.assign_container", model,
relating_structure=storey, products=walls)
# Creates ONE IfcRelContainedInSpatialStructure for all walls
# CORRECT: Batch type assignment
wall_type = model.by_type("IfcWallType")[0]
ifcopenshell.api.run("type.assign_type", model,
related_objects=walls, relating_type=wall_type)
Pattern 5: Memory Management for Large Files
# IfcOpenShell v0.8+: all schema versions
import ifcopenshell
import ifcopenshell.util.element
import gc
def extract_wall_data(filepath):
"""Extract wall data from large file, then release model."""
model = ifcopenshell.open(filepath)
data = []
for wall in model.by_type("IfcWall"):
psets = ifcopenshell.util.element.get_psets(wall)
data.append({
"guid": wall.GlobalId,
"name": wall.Name,
"properties": psets
})
# Release model and force garbage collection
del model
gc.collect()
return data # Work with plain Python dicts from here
Pattern 6: Sequential Type Processing for Very Large Files
# IfcOpenShell v0.8+: all schema versions
import ifcopenshell
import ifcopenshell.geom
import gc
model = ifcopenshell.open("huge_model.ifc")
element_types = ["IfcWall", "IfcSlab", "IfcColumn", "IfcBeam"]
for etype in element_types:
elements = model.by_type(etype)
if not elements:
continue
settings = ifcopenshell.geom.settings()
iterator = ifcopenshell.geom.iterator(
settings, model, 4, include=elements
)
if iterator.initialize():
while True:
shape = iterator.get()
# Process and store results immediately
if not iterator.next():
break
# Force GC between types to control peak memory
gc.collect()
Performance Reference Tables
File Size vs Resource Usage
| File Size | Approx Elements | RAM Usage | Load Time | Notes | |-----------|----------------|-----------|-----------|-------| | 2 GB | > 500,000 | 16+ GB | 60s+ | Process by type, subprocess isolation |
Geometry Iterator vs create_shape()
| Aspect | create_shape() | geom.iterator | |--------|-----------------|-----------------| | Use case | Single element, interactive | Batch processing, export | | Multi-threading | No | Yes (OpenMP, multi-core) | | Geometry caching | No | Yes (reuses identical geometry) | | Error handling | Exception per element | Skips failed elements automatically | | Speed (1000 elements) | ~60s (sequential) | ~8s (8 cores) | | Memory per call | Lower overhead | Better amortized for many elements |
Geometry Settings for Performance
| Setting | Effect | Performance Impact | |---------|--------|-------------------| | disable-opening-subtractions | Skips boolean CSG operations | Major speedup, less accurate geometry | | use-world-coords | Applies global transforms | Slight overhead, but avoids manual transform | | weld-vertices | Merges duplicate vertices | Smaller output, slight processing cost | | apply-default-materials | Adds material data | Required for glTF, adds overhead | | dimensionality | Controls output complexity | CURVESSURFACESAND_SOLIDS is slowest |
Query Performance
| Method | Complexity | Notes | |--------|-----------|-------| | model.by_type("IfcWall") | O(1) | Uses internal class index | | model.by_id(42) | O(1) | Uses internal ID map | | model.by_guid("3Oe$...") | O(1) | Uses GUID index | | for e in model if e.is_a("IfcWall") | O(n) | NEVER use — iterates ALL entities | | ifcopenshell.util.element.get_psets(wall) | O(k) | Traverses k relationships per call | | ifcopenshell.util.selector.filter_elements(model, query) | O(n) | Full scan, but expressive queries |
Common Operations
Profiling IFC Operations
# IfcOpenShell v0.8+: all schema versions
import ifcopenshell
import time
model = ifcopenshell.open("model.ifc")
# Time file loading
start = time.perf_counter()
model = ifcopenshell.open("model.ifc")
load_time = time.perf_counter() - start
print(f"Load time: {load_time:.2f}s")
# Time by_type queries
start = time.perf_counter()
walls = model.by_type("IfcWall")
query_time = time.perf_counter() - start
print(f"by_type query: {query_time:.6f}s for {len(walls)} walls")
# Time geometry processing
import ifcopenshell.geom
import multiprocessing
settings = ifcopenshell.geom.settings()
start = time.perf_counter()
iterator = ifcopenshell.geom.iterator(
settings, model, multiprocessing.cpu_count()
)
count = 0
if iterator.initialize():
while True:
shape = iterator.get()
count += 1
if not iterator.next():
break
geom_time = time.perf_counter() - start
print(f"Geometry: {count} shapes in {geom_time:.2f}s "
f"({count/geom_time:.0f} shapes/sec)")
Controlling Thread Count for Memory
# IfcOpenShell v0.8+: all schema versions
import ifcopenshell
import ifcopenshell.geom
import multiprocessing
import os
model = ifcopenshell.open("large_model.ifc")
settings = ifcopenshell.geom.settings()
# Check available memory (Linux/macOS)
try:
import psutil
available_gb = psutil.virtual_memory().available / (1024**3)
except ImportError:
available_gb = 8 # Conservative fallback
# Scale threads to available memory
# Each thread can use 500MB-1GB for geometry processing
max_threads = multiprocessing.cpu_count()
safe_threads = min(max_threads, max(1, int(available_gb / 1.0)))
iterator = ifcopenshell.geom.iterator(
settings, model, safe_threads
)
Subprocess Isolation for Very Large Files
# IfcOpenShell v0.8+: all schema versions
import subprocess
import json
# Process geometry in a subprocess to guarantee memory cleanup
# Python's GC may not release all C++ allocated memory
result = subprocess.run(
["python", "-c", """
import ifcopenshell
import ifcopenshell.geom
import json
model = ifcopenshell.open("huge_model.ifc")
settings = ifcopenshell.geom.settings()
walls = model.by_type("IfcWall")
iterator = ifcopenshell.geom.iterator(settings, model, 4, include=walls)
data = []
if iterator.initialize():
while True:
shape = iterator.get()
element = model.by_id(shape.id)
data.append({"guid": element.GlobalId, "verts": len(shape.geometry.verts)})
if not iterator.next():
break
print(json.dumps(data))
"""],
capture_output=True, text=True
)
data = json.loads(result.stdout)
# Subprocess memory is fully reclaimed by OS on exit
Disabling Expensive Geometry Operations
# IfcOpenShell v0.8+: all schema versions
import ifcopenshell
import ifcopenshell.geom
model = ifcopenshell.open("model.ifc")
settings = ifcopenshell.geom.settings()
# Skip boolean operations (opening subtractions) for speed
# Doors/windows won't create holes in walls, but processing is much faster
settings.set("disable-opening-subtractions", True)
# Use world coordinates to avoid manual transform calculations
settings.set("use-world-coords", True)
Version Notes
Schema Sensitivity
This skill has low schema sensitivity. Performance patterns apply equally to IFC2X3, IFC4, and IFC4X3 files. The geometry iterator, caching strategies, and memory management techniques are schema-independent.
IfcOpenShell Version Notes
| Feature | Version | Notes | |---------|---------|-------| | geom.iterator | All versions | Core performance feature since early releases | | geom.settings() | All versions | String-based setting names in v0.8+ | | by_type() class index | All versions | O(1) lookup, always available | | include filter on iterator | v0.7+ | Filter elements before geometry processing | | Subprocess isolation | Any | Python-level pattern, not IfcOpenShell-specific |
Reference Links
- [Performance Method Signatures](references/methods.md) — Complete API signatures for geometry processing and querying
- [Working Performance Examples](references/examples.md) — End-to-end optimization examples for real scenarios
- [Performance Anti-Patterns](references/anti-patterns.md) — Common performance mistakes and how to avoid them
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Impertio-Studio
- Source: Impertio-Studio/Blender-Bonsai-ifcOpenshell-Sverchok-Claude-Skill-Package
- License: MIT
- Homepage: https://github.com/OpenAEC-Foundation
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.