Bim scripting
Skill marcinfinitesimal533/Claude-skills-for-Computational-Designers/skills/bim-scripting
Build Claude Code skills for computational design, parametric modeling, simulation, BIM scripting, and fabrication in AEC
npx -y skills add marcinfinitesimal533/Claude-skills-for-Computational-Designers --skill bim-scriptingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Revit API fundamentals, Dynamo for Revit, pyRevit framework, IFC schema and openBIM, model checking, automated documentation, clash detection, and BIM interoperability tools for AEC computational design
SKILL.md
43.0 KB, as published. Nobody here has run it
BIM Scripting
Comprehensive reference for automating Building Information Modeling workflows through scripting, API access, and interoperability platforms. This skill covers the full spectrum of BIM automation --- from visual programming with Dynamo through deep Revit API scripting, pyRevit extension development, IFC/openBIM data exchange, model checking, automated documentation, and cross-platform interoperability via Speckle, BHoM, and Rhino.Inside.Revit.
1. BIM Automation Philosophy
Why Script BIM
BIM models are databases disguised as 3D geometry. Every wall, door, room, and duct segment carries structured data --- type, dimensions, material, cost code, fire rating, acoustic class, phase, workset, design option. Manual manipulation of that data does not scale. A 200-unit residential project may contain 40,000+ elements, each with 30--80 parameters. Changing a naming convention, verifying parameter completeness, or exporting coordinated drawing sets by hand is not just slow --- it is error-prone and unrepeatable.
Scripting BIM means treating the model as a programmable data source:
- Read element properties at scale (audit, validate, report).
- Write parameter values in batch (standards enforcement, data enrichment).
- Create elements procedurally (repetitive layouts, adaptive placement).
- Transform geometry computationally (facade panelization, structural optimization).
- Export deliverables automatically (sheets to PDF, models to IFC, data to dashboards).
Manual vs. Automated BIM Workflows
| Workflow | Manual Approach | Automated Approach | Time Savings |
|---|---|---|---|
| Parameter QA | Open each element, check value | Script scans all elements, flags violations | 95% |
| Sheet creation | Place views, adjust crops, add tags one by one | Script generates sheets from template rules | 90% |
| Clash detection | Visual inspection in section views | Navisworks / script-based interference check | 85% |
| Export to IFC | File > Export > IFC, configure, repeat per model | Batch script exports all linked models with preset mappings | 80% |
| Room finish schedule | Manual schedule, manual formatting | API-generated schedule with conditional formatting | 75% |
| Design option comparison | Duplicate views, switch options, compare | Script generates comparison report with metrics | 90% |
| Naming convention enforcement | Manual review of browser tree | FilteredElementCollector + regex validation | 98% |
ROI of BIM Automation
The return on investment for BIM scripting follows a clear pattern:
- First script --- 2-8 hours to develop, saves 1-4 hours per use. Break-even after 2-3 uses.
- Script library (20-50 tools) --- 200-500 hours to develop, saves 10-30 hours per project. Break-even within 1-2 projects.
- Custom application --- 500-2000 hours to develop, saves 50-200 hours per project. Break-even within 3-5 projects.
- Enterprise platform --- 2000-10,000 hours to develop, transforms entire practice workflow.
The Automation Spectrum
Level 1: Visual Programming (Dynamo, Grasshopper)
- Lowest barrier to entry
- Best for designers who think visually
- Limited scalability and version control
- Good for: one-off design explorations, parameter mapping, geometry generation
Level 2: Scripting (Python in Dynamo, pyRevit, RevitPythonShell)
- Moderate barrier to entry
- Full API access with Python convenience
- Version-controllable, shareable
- Good for: batch operations, custom tools, data workflows
Level 3: Custom Tools (C# add-ins, pyRevit extensions)
- Higher barrier to entry
- Compiled performance, custom UI, ribbon integration
- Deployable to teams
- Good for: production tools, firm-wide standards enforcement
Level 4: Full Applications (standalone apps, web dashboards, microservices)
- Highest barrier to entry
- Complete control over UX and data pipeline
- Cloud-scalable, multi-user
- Good for: enterprise BIM management, cross-project analytics
When to Automate vs. When to Model Manually
Automate when:
- The task repeats across projects or phases.
- The task involves more than 50 elements.
- Consistency and auditability are critical (QA/QC, code compliance).
- The output feeds downstream processes (cost, energy, structural analysis).
- Human error risk is high (naming, classification, spatial containment).
Model manually when:
- The task is a one-time creative act (early concept massing).
- Judgment and spatial intuition outweigh procedural logic.
- The element count is small and the rules are ambiguous.
- The cost of developing automation exceeds the cost of manual work.
BIM Maturity Levels and Automation
| BIM Level | Description | Automation Role |
|---|---|---|
| Level 0 | 2D CAD, no BIM | CAD scripting (AutoLISP, VBA) for drawing automation |
| Level 1 | 3D modeling, 2D documentation | Basic Dynamo scripts, parameter management |
| Level 2 | Federated models, structured data exchange | IFC workflows, clash detection, model checking |
| Level 3 | Integrated single model, full lifecycle data | API-driven analytics, real-time dashboards, AI-assisted QA |
| Level 4 (emerging) | Digital twin, IoT-connected, predictive | Continuous model sync, ML-driven optimization, autonomous agents |
2. Revit API Fundamentals
Architecture
The Revit API is a .NET framework (C# or VB.NET natively, Python via IronPython or CPython with RevitPythonShell/pyRevit). The object hierarchy:
UIApplication
└── Application (Revit application-level settings, version info)
└── Document (the .rvt file; model database)
├── Elements (everything in the model)
├── Views (plans, sections, 3D views, schedules)
├── Phases (existing, new construction, demolition)
├── DesignOptions (option sets and options)
├── Worksets (worksharing partitions)
└── Settings (project units, line styles, fill patterns)
Element Types
Every object in a Revit model inherits from Element. Key subclasses:
| Class | Description | Example |
|---|---|---|
FamilyInstance | Placed instance of a loadable family | Door, window, furniture, fixture |
Wall | System family: wall element | Basic Wall, Curtain Wall, Stacked Wall |
Floor | System family: floor slab | Generic Floor, composite assemblies |
Roof | System family: roof element | Basic Roof, extrusion roof |
Ceiling | System family: ceiling element | Compound ceiling, basic ceiling |
FamilyInstance (structural) | Columns, beams, braces | Steel W-shapes, concrete columns |
Room | Spatial element for architectural spaces | Bounded by room-bounding elements |
Area | Spatial element for area plans | Gross area, rentable area |
View | Any view in the model | ViewPlan, ViewSection, View3D, ViewSheet |
ViewSheet | A sheet for documentation | Contains viewport placements |
ViewSchedule | A schedule/quantity takeoff | Tabular data extraction |
Group | Grouped elements | Model groups, detail groups |
Level | Datum: horizontal reference plane | Defines story heights |
Grid | Datum: vertical reference plane | Structural grid lines |
ReferencePlane | Construction plane | Alignment references |
Categories, Families, Types, Instances
This four-level hierarchy is central to Revit:
Category (e.g., Doors)
└── Family (e.g., Single-Flush)
└── Type (e.g., 36" x 84")
└── Instance (placed door #1, #2, #3...)
- Category: broad classification (Walls, Doors, Floors, Furniture). Each has a
BuiltInCategoryenum. - Family: a parametric definition (.rfa file for loadable families; system families are built-in).
- Type: a named set of parameter values within a family (dimensions, materials).
- Instance: a placed occurrence with instance-specific parameters (location, room, mark).
Parameters
Parameters store all non-geometric data on elements.
| Parameter Kind | Scope | Definition | Access |
|---|---|---|---|
| Built-in | Hardcoded by Revit | Predefined (e.g., WALL_BASE_OFFSET) | element.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET) |
| Project | One project file | Defined in Project Parameters dialog | element.LookupParameter("MyParam") |
| Shared | Across projects/families | Defined in Shared Parameters file (.txt) | element.get_Parameter(guid) or by name |
| Family | Inside .rfa family | Defined in Family Editor | Exposed as type or instance parameter |
| Global | Project-wide value | Not element-bound; referenced by formulas | GlobalParametersManager |
Parameter storage types:
StorageType.String--- textStorageType.Integer--- integers and YesNo (0/1)StorageType.Double--- real numbers (always in internal units)StorageType.ElementId--- reference to another element (material, type, level)
Transactions
Every model modification must occur inside a Transaction. Without it, the API
throws an InvalidOperationException.
# Python (pyRevit / RevitPythonShell)
from Autodesk.Revit.DB import Transaction
doc = __revit__.ActiveUIDocument.Document
t = Transaction(doc, "Batch Update Parameters")
t.Start()
try:
# ... modify elements ...
t.Commit()
except Exception as e:
t.RollBack()
print("Error: {}".format(e))
Transaction types:
- Transaction --- standard single transaction (most common).
- TransactionGroup --- wraps multiple transactions; can assimilate (merge into one undo) or roll back all.
- SubTransaction --- nested within a Transaction; can roll back independently without aborting the parent.
FilteredElementCollector
The primary mechanism for querying elements in a Revit model. It operates as a builder pattern with filters:
from Autodesk.Revit.DB import (
FilteredElementCollector, BuiltInCategory,
ElementCategoryFilter, ElementClassFilter
)
# All walls in the model
walls = FilteredElementCollector(doc) \
.OfCategory(BuiltInCategory.OST_Walls) \
.WhereElementIsNotElementType() \
.ToElements()
# All door types (not instances)
door_types = FilteredElementCollector(doc) \
.OfCategory(BuiltInCategory.OST_Doors) \
.WhereElementIsElementType() \
.ToElements()
# All family instances of a specific class
instances = FilteredElementCollector(doc) \
.OfClass(FamilyInstance) \
.ToElements()
# Elements in a specific view
view_elements = FilteredElementCollector(doc, view.Id) \
.OfCategory(BuiltInCategory.OST_Walls) \
.ToElements()
Geometry Access
Extracting geometry from Revit elements:
Element
└── get_Geometry(Options)
└── GeometryElement (iterable)
├── Solid
│ ├── Faces (FaceArray)
│ │ └── Face → Surface, UV domain, normal
│ └── Edges (EdgeArray)
│ └── Edge → Curve
├── GeometryInstance (for family instances)
│ └── GetInstanceGeometry() → GeometryElement
├── Curve (for line-based elements)
├── Point
└── PolyLine
Units
Revit internal units are always:
- Length: feet
- Angle: radians
- Area: square feet
- Volume: cubic feet
Use UnitUtils.ConvertFromInternalUnits() and UnitUtils.ConvertToInternalUnits()
for conversion. In Revit 2022+, use UnitTypeId instead of DisplayUnitType.
Events
The Revit API provides application and document-level events:
Application.DocumentOpened/DocumentClosing/DocumentSavedApplication.ViewActivatedApplication.DialogBoxShowing(intercept and auto-dismiss dialogs)Document.DocumentChanged(react to element modifications)UIApplication.Idling(periodic background processing)
External Commands, Applications, Events
| Type | Purpose | Lifecycle |
|---|---|---|
IExternalCommand | Single button click action | Runs once per invocation |
IExternalApplication | Ribbon tab/panel setup, startup logic | Runs at Revit startup/shutdown |
IExternalDBApplication | DB-level (no UI) startup logic | For services, updaters |
IExternalEventHandler | Thread-safe model modification from external threads | Raised via ExternalEvent |
C# vs. Python for Revit API
| Criterion | C# | Python (IronPython/CPython) |
|---|---|---|
| Performance | Compiled; fastest | Interpreted; slower for large loops |
| Debugging | Full Visual Studio debugger | Print statements, limited debugger |
| Deployment | DLL add-in; requires compilation | Script file; instant edit-run cycle |
| Learning curve | Steeper (typed language, project setup) | Gentler (dynamic typing, REPL) |
| API coverage | 100% | 100% (same .NET API via clr) |
| Ecosystem | NuGet packages, .NET libraries | Python packages (limited in IronPython) |
| UI creation | WPF, WinForms with full designer | WPF possible but harder; rpw simplifies |
| Best for | Production add-ins, enterprise tools | Rapid prototyping, small utilities, pyRevit |
3. Dynamo for Revit
Core Advantages
Dynamo is a visual programming environment integrated with Revit (ships with Revit since 2017). Key strengths:
- Visual dataflow --- nodes connected by wires; intuitive for non-programmers.
- Live Revit connection --- read/write model elements in real time.
- Geometry preview --- 3D preview of computational geometry before committing to Revit.
- Extensibility --- custom nodes in Python, C#, or DesignScript; package manager ecosystem.
Revit-Specific Nodes
Dynamo provides dedicated Revit node categories:
- Selection: Select Model Element, Select Elements by Category, All Elements of Category
- Create: Wall.ByCurveAndHeight, Floor.ByOutlineTypeAndLevel, FamilyInstance.ByPoint
- Modify: Element.SetParameterByName, Element.MoveByVector, Element.OverrideColorInView
- Query: Element.GetParameterValueByName, Element.BoundingBox, Room.Boundaries
Dynamo Player
Dynamo Player exposes Dynamo scripts as simple button-click tools for end users who do not need to understand the graph. Configure inputs as user-facing prompts. Best practice: design scripts specifically for Player with clear input labels and minimal required interaction.
Geometry Kernels
Dynamo uses two separate geometry engines:
- DesignScript / ASM (Autodesk Shape Manager) --- Dynamo's native geometry kernel. Creates Points, Curves, Surfaces, Solids in Dynamo's 3D preview.
- Revit geometry --- the actual BIM model geometry.
These are not interchangeable. A Dynamo Surface is not a Revit Face.
Converting between them requires explicit nodes:
Surface.ByPatch(Dynamo) vs.FaceWall.Create(Revit)Curve.ByPoints(Dynamo) vs.ModelCurve.ByCurve(Revit)
Common Revit Workflows in Dynamo
- Room-based floor finish placement --- query room boundaries, offset curves, create floor elements by outline.
- Adaptive component placement --- distribute families along curves or surfaces with parameter-driven spacing.
- Parameter read/write --- bulk read element parameters to Excel, modify, write back.
- View creation --- generate scope boxes, create dependent views per scope box, apply view templates.
- Sheet setup --- create sheets from list, place viewports at coordinates, populate titleblock parameters.
- Keynote management --- read keynote table, validate against model, update keynote parameters.
- Area analysis --- extract room areas, calculate ratios (net-to-gross, circulation percentage), color-code by metric.
Essential Packages
| Package | Author | Key Capabilities |
|---|---|---|
| Clockwork | Andreas Dieckmann | 500+ utility nodes; view manipulation, element filtering, string operations |
| Rhythm | John Pierson | Revit-focused; sheet management, view manipulation, element creation |
| archi-lab | Konrad Sobon | View/sheet automation, element selection, Revit API wrappers |
| spring nodes | Dimitar Venkov | Geometry, mesh processing, FEM analysis integration |
| BimorphNodes | Bimorph | Geometry, CAD import, mesh to solid conversion |
| Genius Loci | Alban de Chasteigner | Site tools, topography, Revit element manipulation |
| Data-Shapes | Mostafa El Ayoubi | Custom UI nodes (forms, dropdowns, file pickers) |
| Orchid | Erik Falck Jorgensen | Document management, family loading, workset operations |
| LunchBox | Nathan Miller | Paneling, geometric patterns, data management |
Python Scripting in Dynamo
Python nodes in Dynamo provide full Revit API access:
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')
from Autodesk.Revit.DB import *
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
# Start transaction
TransactionManager.Instance.EnsureInTransaction(doc)
# ... API operations ...
TransactionManager.Instance.TransactionTaskDone()
Key differences from standalone pyRevit scripts:
- Use
TransactionManagerinstead of rawTransaction. - Use
DocumentManager.Instance.CurrentDBDocumentinstead of__revit__. - Inputs come from
IN[0], IN[1], ...; output goes toOUT.
Performance Considerations
Dynamo becomes slow when:
- Graphs exceed 200-300 nodes.
- Lists contain 10,000+ items with geometry preview on.
- Multiple levels of
List.MaporList@Levelcreate combinatorial explosions.
Alternatives when Dynamo is too slow:
- Move heavy logic into a single Python node (avoids inter-node marshalling).
- Use pyRevit for batch operations without geometry preview overhead.
- Use compiled C# add-in for maximum performance.
- Use Dynamo's
Passthroughnode to sequence operations and avoid unnecessary recalculation.
4. pyRevit Framework
Architecture
pyRevit is a rapid application development framework for Revit. It creates ribbon UI elements from a folder structure:
MyExtension.extension/
├── MyTab.tab/
│ ├── MyPanel.panel/
│ │ ├── MyButton.pushbutton/
│ │ │ ├── script.py (IronPython script)
│ │ │ ├── icon.png (16x16, 24x24, or 32x32)
│ │ │ └── bundle.yaml (tooltip, author, help URL)
│ │ ├── MySplitButton.splitbutton/
│ │ │ ├── Option1.pushbutton/
│ │ │ └── Option2.pushbutton/
│ │ └── MyPullDown.pulldown/
│ │ ├── Item1.pushbutton/
│ │ └── Item2.pushbutton/
│ └── AnotherPanel.panel/
└── lib/ (shared Python modules)
└── my_utils.py
Script Types
- IronPython (.py) --- default; runs in Revit's IronPython engine. Access to .NET via
clr. - CPython (.py with
#! python3) --- runs in CPython 3.x. Access to pip packages (pandas, numpy). Cannot access UI elements directly. - C# (.cs) --- compiled at runtime. Full performance and type safety.
pyRevit CLI
# Install pyRevit
pyrevit install
# Clone an extension from GitHub
pyrevit extend ui MyExtension https://github.com/user/repo.git
# List installed extensions
pyrevit extensions list
# Attach to a Revit version
pyrevit attach 2024 latest
# Enable/disable extensions
pyrevit extensions enable MyExtension
pyrevit extensions disable MyExtension
# Clear caches
pyrevit caches clear --all
Built-in Tools Reference
pyRevit ships with dozens of production-ready tools:
- Select --- select all instances of a type, select by parameter value, select linked elements.
- Match --- match type properties, match graphic overrides between elements.
- Keynotes --- keynote manager with live editing and project keynote file management.
- Sheets --- batch create sheets, renumber sheets, print sheet sets.
- Views --- batch create views, set view templates, manage scope boxes.
- Project --- project parameter manager, shared parameter loader.
- Toggles --- quick toggles for halftone, crop regions, annotations.
Creating Custom Extensions
Minimum viable pyRevit button:
# script.py
"""Tooltip text shown on hover."""
__title__ = "My Button"
__author__ = "Your Name"
from pyrevit import revit, DB, forms
doc = revit.doc
# Get all rooms
rooms = DB.FilteredElementCollector(doc) \
.OfCategory(DB.BuiltInCategory.OST_Rooms) \
.WhereElementIsNotElementType() \
.ToElements()
# Filter rooms with no number
unnamed = [r for r in rooms if not r.get_Parameter(
DB.BuiltInParameter.ROOM_NUMBER).AsString()]
if unnamed:
forms.alert("{} rooms have no number assigned.".format(len(unnamed)))
else:
forms.alert("All rooms are numbered.", title="QA Check Passed")
Transaction Handling in pyRevit
pyRevit provides a context manager for transactions:
from pyrevit import revit, DB
with revit.Transaction("Update Room Names"):
for room in rooms:
param = room.get_Parameter(DB.BuiltInParameter.ROOM_NAME)
current = param.AsString()
param.Set(current.upper())
RevitPythonShell
An interactive Python REPL inside Revit. Useful for:
- Exploring the API interactively (inspect elements, test queries).
- Quick one-off operations without creating a full pyRevit script.
- Debugging: inspect element properties, test FilteredElementCollector queries.
Template Scripts
Batch parameter update:
from pyrevit import revit, DB, forms
doc = revit.doc
walls = DB.FilteredElementCollector(doc) \
.OfCategory(DB.BuiltInCategory.OST_Walls) \
.WhereElementIsNotElementType() \
.ToElements()
with revit.Transaction("Set Wall Comments"):
for wall in walls:
wall.LookupParameter("Comments").Set("Reviewed")
View creation from room list:
from pyrevit import revit, DB
doc = revit.doc
rooms = DB.FilteredElementCollector(doc) \
.OfCategory(DB.BuiltInCategory.OST_Rooms) \
.WhereElementIsNotElementType() \
.ToElements()
level = rooms[0].Level
vft = doc.GetDefaultElementTypeId(DB.ElementTypeGroup.ViewTypeFloorPlan)
with revit.Transaction("Create Room Views"):
for room in rooms:
name = room.get_Parameter(DB.BuiltInParameter.ROOM_NAME).AsString()
view = DB.ViewPlan.Create(doc, vft, level.Id)
view.Name = "Room - {}".format(name)
Deployment
- Shared extension path: configure in pyRevit settings to point to a network share. All team members load extensions from the same location.
- Version control: store extensions in Git. Use CI/CD to deploy to the shared path.
- pyRevit CLI can install extensions from Git repositories directly.
pyRevit Hooks
pyRevit supports event hooks via specially named scripts:
doc-changed-[hookid].py--- fires when the document changes.doc-opened-[hookid].py--- fires when a document is opened.doc-saved-[hookid].py--- fires after a document is saved.app-init-[hookid].py--- fires when Revit starts (before any document).
Hooks live in a hooks/ folder within the extension.
5. IFC & openBIM
IFC Schema Overview
IFC (Industry Foundation Classes) is an ISO-standard (ISO 16739) open data schema for BIM data exchange. Major versions:
| Version | Status | Key Additions |
|---|---|---|
| IFC2x3 | Legacy, widely supported | Most common in practice; 650+ entities |
| IFC4 | Current standard (ISO 16739-1:2018) | Improved geometry, new MEP entities, 4D/5D support |
| IFC4.3 | Released 2024 | Infrastructure: roads, bridges, rail, tunnels, ports |
Key IFC Entities
IfcProject
└── IfcSite
└── IfcBuilding
└── IfcBuildingStorey
├── IfcWall / IfcWallStandardCase
├── IfcSlab
├── IfcBeam
├── IfcColumn
├── IfcDoor
├── IfcWindow
├── IfcSpace (equivalent of Revit Room)
├── IfcCurtainWall
├── IfcStair / IfcStairFlight
├── IfcRamp / IfcRampFlight
├── IfcRailing
├── IfcRoof
├── IfcCovering (finishes, ceilings)
├── IfcFurnishingElement
└── IfcDistributionElement (MEP)
├── IfcFlowSegment (pipes, ducts)
├── IfcFlowTerminal (fixtures, diffusers)
└── IfcFlowFitting (elbows, tees)
Property Sets and Quantity Sets
IFC data is carried in standardized property sets (Psets) and quantity sets (Qtos):
- Pset_WallCommon: Reference, Status, IsExternal, ThermalTransmittance, FireRating, AcousticRating
- Pset_SlabCommon: Reference, Status, IsExternal, LoadBearing, AcousticRating
- Pset_DoorCommon: Reference, FireRating, IsExternal, SecurityRating, HandicapAccessible
- Pset_SpaceCommon: Reference, IsExternal, GrossPlannedArea, NetPlannedArea, PubliclyAccessible
- Qto_WallBaseQuantities: Length, Width, Height, GrossVolume, NetVolume, GrossSideArea, NetSideArea
- Qto_SlabBaseQuantities: Width, Length, Depth, Perimeter, GrossArea, NetArea, GrossVolume, NetVolume
IFC Export Settings in Revit
Critical export configuration:
- IFC version: IFC2x3 Coordination View 2.0 (most compatible) or IFC4 Reference View.
- Export mapping table:
IFC export classesin Revit maps categories to IFC entities. - Property set mapping: custom
.txtmapping file for project-specific Psets. - Phase: export only the relevant phase.
- Base point: shared coordinates for model federation.
- Element selection: current view vs. entire model.
MVD (Model View Definition)
MVDs define subsets of the IFC schema for specific use cases:
| MVD | Purpose | Use Case |
|---|---|---|
| Coordination View 2.0 | Geometry + basic properties | Multi-discipline coordination |
| Design Transfer View | Rich geometry + full properties | Model handover between authoring tools |
| Reference View | Lightweight reference geometry | Lightweight context for coordination |
| Quantity Takeoff View | Properties + quantities | Cost estimation data exchange |
BCF (BIM Collaboration Format)
BCF (ISO 21597) is a structured format for communicating issues in BIM:
- BCF XML: file-based (.bcfzip). Contains viewpoints (camera position, component visibility), comments, and issue metadata.
- BCF API: REST API for real-time issue sync between platforms.
- Workflow: reviewer opens federated model, creates BCF issue with snapshot, assigns to responsible party, tracks resolution.
IFC Tools
| Tool | Language | Capabilities |
|---|---|---|
| IfcOpenShell | Python/C++ | Read/write/validate IFC; geometry processing; most mature open-source |
| IFC.js | JavaScript | Web-based IFC viewer/parser; WebGL rendering |
| xBIM | C# (.NET) | Read/write IFC; geometry meshing; WPF viewer |
| BIMserver | Java | Model server; IFC storage; version control; plugin architecture |
| Solibri | Desktop app | Model checking; clash detection; rule-based validation |
| BIMcollab | Web/Desktop | BCF management; cloud collaboration; issue tracking |
| BlenderBIM | Python | Full IFC authoring in Blender; IfcOpenShell-based |
openBIM Coordination Workflow
Architect (Revit) ──export IFC──> Coordination Platform
Structural (Tekla) ──export IFC──> (Solibri, BIMcollab,
MEP (Revit MEP) ──export IFC──> Navisworks, or custom)
│
Federated Model
│
┌─────────────┼─────────────┐
Clash Detection QA/QC 4D Planning
│ │ │
BCF Issues Validation Schedule Link
│ Report │
──BCF──> Author fixes ──re-export──>
6. Model Checking & Validation
Rule-Based Checking
Model checking verifies that a BIM model meets predefined rules. Categories:
- Data completeness --- required parameters are filled.
- Naming conventions --- element names follow organizational standards.
- Spatial containment --- elements are properly hosted on levels/rooms.
- Classification compliance --- elements have correct Uniclass/OmniClass codes.
- Geometric validity --- no zero-thickness walls, no overlapping elements.
- Design standards --- minimum room sizes, maximum corridor lengths, accessibility clearances.
Clash Detection Types
| Type | Description | Tolerance | Example |
|---|---|---|---|
| Hard clash | Physical intersection of elements | 0 mm | Duct passing through beam |
| Soft clash (clearance) | Insufficient clearance | Variable (50-300 mm typical) | Pipe too close to electrical cable tray |
| Workflow clash (4D) | Time-based conflict | Schedule overlap | Two trades occupying same zone simultaneously |
| Duplicate | Same element modeled twice | Position tolerance | Two identical walls overlapping |
Navisworks Clash Detection Setup
- Append all models (Revit NWC, IFC, DWG).
- Create selection sets by discipline (Arch, Struct, MEP), system, or zone.
- Configure clash tests: set A vs. set B, tolerance, clash type.
- Apply rules: ignore clashes between connected elements, within same system, or by specific parameter match.
- Group results by grid intersection, level, or element type.
- Generate report: HTML, XML, or BCF for distribution.
Custom Model Checking with Revit API
from pyrevit import revit, DB, forms, output
doc = revit.doc
out = output.get_output()
# Check: All rooms must have a number and name
rooms = DB.FilteredElementCollector(doc) \
.OfCategory(DB.BuiltInCategory.OST_Rooms) \
.WhereElementIsNotElementType() \
.ToElements()
issues = []
for room in rooms:
number = room.get_Parameter(DB.BuiltInParameter.ROOM_NUMBER).AsString()
name = room.get_Parameter(DB.BuiltInParameter.ROOM_NAME).AsString()
area = room.get_Parameter(DB.BuiltInParameter.ROOM_AREA).AsDouble()
if not number:
issues.append(("Room {} has no number".format(room.Id), room.Id))
if not name:
issues.append(("Room {} has no name".format(room.Id), room.Id))
if area == 0:
issues.append(("Room {} is not bounded (0 area)".format(room.Id), room.Id))
out.print_md("## Room QA Report")
out.print_md("**Total rooms**: {}".format(len(rooms)))
out.print_md("**Issues found**: {}".format(len(issues)))
for msg, eid in issues:
out.print_md("- {} [Click to select](revit://select?eid={})".format(msg, eid))
LOD/LOI Verification
BIM Execution Plans specify required Level of Development (LOD) and Level of Information (LOI) at each project stage. Automated verification:
- LOD 100: massing volumes present; check that IfcBuildingElementProxy exists.
- LOD 200: approximate geometry; check that elements have correct category but allow generic types.
- LOD 300: precise geometry; verify element dimensions match design intent; all parameters from EIR filled.
- LOD 350: coordination geometry; verify connections between disciplines; MEP clearances maintained.
- LOD 400: fabrication-ready; verify manufacturer data, part numbers, installation instructions.
IFC Validation with IfcOpenShell
import ifcopenshell
import ifcopenshell.validate
model = ifcopenshell.open("model.ifc")
# Schema validation
logger = ifcopenshell.validate.json_logger()
ifcopenshell.validate.validate(model, logger)
for error in logger.statements:
print(error)
# Custom validation: all walls must have Pset_WallCommon
for wall in model.by_type("IfcWall"):
psets = ifcopenshell.util.element.get_psets(wall)
if "Pset_WallCommon" not in psets:
print(f"Wall #{wall.id()} missing Pset_WallCommon")
7. Automated Documentation
View Creation Automation
Programmatic view generation eliminates the tedious manual setup of project views. Common patterns:
- Floor plans per level --- create architectural, structural, MEP, and fire safety plans for every level.
- Dependent views per scope box --- subdivide large floor plates into manageable sheets.
- Sections at every grid intersection --- structural section cuts for detailing.
- Enlarged plans per room --- interior elevations and enlarged plans keyed to room boundaries.
- 3D views per zone --- isometric views for coordination reviews.
Sheet Layout Automation
from pyrevit import revit, DB
doc = revit.doc
# Get titleblock type
tb_type = DB.FilteredElementCollector(doc) \
.OfCategory(DB.BuiltInCategory.OST_TitleBlocks) \
.WhereElementIsElementType() \
.FirstElement()
# Get all floor plan views
views = DB.FilteredElementCollector(doc) \
.OfClass(DB.ViewPlan) \
.WhereElementIsNotElementType() \
.ToElements()
with revit.Transaction("Create Sheets"):
for i, view in enumerate(views):
if view.IsTemplate or view.Name.startswith("{"):
continue
# Create sheet
sheet = DB.ViewSheet.Create(doc, tb_type.Id)
sheet.SheetNumber = "A{:03d}".format(i + 1)
sheet.Name = view.Name
# Place viewport at center of sheet
center = DB.XYZ(1.375, 0.875, 0) # center of A1 sheet in feet
DB.Viewport.Create(doc, sheet.Id, view.Id, center)
Tag and Annotation Automation
- Room tags: iterate rooms, place
IndependentTagat room location point. - Door tags: iterate doors, place tag at door midpoint with leader if needed.
- Dimension strings: create
Dimensionobjects along gridlines or wall faces. - Keynotes: assign keynote values to elements, place keynote tags in views.
Export Automation
from pyrevit import revit, DB
doc = revit.doc
# Batch PDF export (Revit 2022+)
sheets = DB.FilteredElementCollector(doc) \
.OfClass(DB.ViewSheet) \
.ToElements()
pdf_options = DB.PDFExportOptions()
pdf_options.FileName = "ExportedSheets"
pdf_options.Combine = False # separate PDF per sheet
pdf_options.PaperFormat = DB.ExportPaperFormat.Default
pdf_options.ZoomType = DB.ZoomType.FitToPage
sheet_ids = [s.Id for s in sheets if s.CanBePrinted]
doc.Export("C:/Output/", sheet_ids, pdf_options)
Drawing List Management
Automate the drawing list schedule:
- Ensure all sheets have correct sheet number, name, revision, status.
- Generate a
ViewScheduleof sheets via API with required fields. - Export drawing list to Excel for transmittals.
- Validate sheet numbering against organizational standard (e.g.,
A-101,S-201,M-301).
8. BIM Interoperability Platforms
Speckle
Speckle is an open-source data platform for AEC that treats 3D model data as versionable, streamable, and queryable:
- Connectors: Revit, Rhino, Grasshopper, Blender, AutoCAD, Civil3D, Unity, Unreal, Excel, Power BI, QGIS.
- Streams: persistent data channels. Push model data to a stream; any connected app can receive it.
- Commits: every push creates a versioned commit. Full history, branching, diffing.
- Web viewer: browser-based 3D viewer with filtering, measurement, section cuts.
- GraphQL API: programmatic access to all data. Query elements, filter by properties.
- Speckle Automate: serverless functions triggered on new commits. Use for automated QA/QC, data enrichment, notifications.
When to use Speckle: cross-platform model sharing, design review with non-BIM stakeholders, automated data pipelines, custom dashboards from model data.
BHoM (Buildings and Habitats object Model)
BHoM is an open-source collaborative computational framework for the built environment:
- Object model: unified .NET object definitions for structural, environmental, architectural, and planning objects.
- Adapters: bidirectional data exchange with analysis software:
- Structural: Robot, GSA, ETABS, SAP2000, Lusas
- Environmental: IES, EnergyPlus, Ladybug
- BIM: Revit, IFC
- Geometry: Rhino, Grasshopper
- Engine: computational methods that operate on BHoM objects (structural analysis queries, environmental calculations, geometry operations).
- UI: Grasshopper components and Excel plugin for accessible interaction.
When to use BHoM: multi-software structural analysis workflows, computational design pipelines that span multiple analysis tools, when you need a unified object model across disciplines.
Rhino.Inside.Revit
Rhino.Inside.Revit runs the full Rhino and Grasshopper environment inside the Revit process, enabling:
- Grasshopper → Revit: create Revit elements (walls, floors, roofs, adaptive components) from Grasshopper geometry.
- Revit → Grasshopper: query Revit elements, extract geometry, read parameters.
- Bidirectional live link: changes in Grasshopper update Revit elements; changes in Revit reflect in Grasshopper.
- Rhino geometry in Revit views: use Rhino's superior NURBS engine for complex geometry, bake to Revit as DirectShape or native elements.
Use cases:
- Complex facade panelization designed in GH, built as Revit curtain panels.
- Parametric roof geometry from GH, exported as Revit roof-by-face.
- Site grading and landscape computed in GH, placed as Revit topography.
- Structural optimization in GH (Karamba3D), results pushed to Revit structural model.
Comparison Table
| Feature | Speckle | BHoM | Rhino.Inside.Revit |
|---|---|---|---|
| Primary use | Data exchange & versioning | Computational workflows | Geometry & design |
| Architecture | Cloud-based streams | .NET object model + adapters | In-process (runs inside Revit) |
| Revit support | Connector (push/pull) | Adapter (read/write) | Full bidirectional live link |
| Rhino/GH support | Connector | GH components | Native (Rhino is the engine) |
| Analysis tools | Via Automate | Native adapters (Robot, GSA, etc.) | Via GH plugins (Karamba, Ladybug) |
| Open source | Yes (Apache 2.0) | Yes (LGPL 3.0) | Yes (MIT) |
| Best for | Cross-platform data flow | Multi-tool analysis pipelines | Complex geometry in Revit |
9. BIM Scripting Best Practices
Error Handling and Logging
from pyrevit import revit, DB, forms
import traceback
doc = revit.doc
errors = []
success_count = 0
with revit.Transaction("Batch Operation"):
for element in elements:
try:
# operation that might fail
param = element.LookupParameter("Target Param")
if param and not param.IsReadOnly:
param.Set(new_value)
success_count += 1
else:
errors.append("Element {}: parameter not found or read-only".format(element.Id))
except Exception as e:
errors.append("Element {}: {}".format(element.Id, str(e)))
# Report results
msg = "Processed: {}\nErrors: {}".format(success_count, len(errors))
if errors:
msg += "\n\n" + "\n".join(errors[:20]) # limit error display
forms.alert(msg, title="Operation Complete")
Performance Best Practices
- Minimize FilteredElementCollector calls --- collect once, filter in Python.
- Use quick filters (OfClass, OfCategory) before slow filters (WherePasses with parameter filter).
- Disable regeneration when not needed:
doc.Regenerate()only when required. - Batch element creation --- create elements in a single transaction, not one transaction per element.
- Avoid
Element.Geometryin loops --- geometry extraction is expensive. Cache results. - Use
ElementIdsets for fast lookups instead of element lists. - Turn off warning suppression wisely ---
FailureHandlingOptionscan skip dialog boxes during batch operations.
User Input Patterns
from pyrevit import forms
# Simple alert
forms.alert("Operation complete.", title="Success")
# Yes/No prompt
if forms.alert("Continue with operation?", yes=True, no=True):
# proceed
pass
# Select from list
selected = forms.SelectFromList.show(
options,
title="Select Elements",
multiselect=True
)
# Text input
value = forms.ask_for_string(
prompt="Enter new parameter value:",
title="Parameter Update"
)
Transaction Management
| Pattern | Use Case | Undo Behavior |
|---|---|---|
| Single Transaction | Most operations | One undo step |
| TransactionGroup (assimilate) | Multi-step that should appear as one undo | One undo step |
| TransactionGroup (no assimilate) | Multi-step with individual undo | Multiple undo steps |
| SubTransaction | Tentative changes within a transaction | Roll back sub-changes without aborting main transaction |
Version Compatibility
Key API changes across Revit versions:
| Version | Notable API Changes |
|---|---|
| 2021 | ForgeTypeId begins replacing UnitType and DisplayUnitType |
| 2022 | UnitTypeId fully replaces DisplayUnitType; PDF export API added |
| 2023 | Toposolid replaces TopographySurface; analytical model API overhaul |
| 2024 | Document.GetUnusedElements() added; Element.IsHidden() improvements |
| 2025 | ParameterFilterElement improvements; enhanced schedule API |
Code Organization
my_extension.extension/
├── lib/
│ ├── __init__.py
│ ├── config.py (settings, constants)
│ ├── collectors.py (reusable FilteredElementCollector wrappers)
│ ├── param_utils.py (parameter read/write helpers)
│ ├── geom_utils.py (geometry extraction helpers)
│ ├── export_utils.py (PDF, DWG, IFC export wrappers)
│ └── report.py (HTML report generation)
├── MyTab.tab/
│ ├── QA.panel/
│ │ ├── CheckRooms.pushbutton/
│ │ ├── CheckNaming.pushbutton/
│ │ └── CheckParams.pushbutton/
│ ├── Export.panel/
│ │ ├── BatchPDF.pushbutton/
│ │ └── BatchIFC.pushbutton/
│ └── Data.panel/
│ ├── ParamWriter.pushbutton/
│ └── ExcelSync.pushbutton/
└── hooks/
└── doc-opened-[audit].py
Testing Strategies
- Test on a dedicated test model --- a small .rvt file with representative elements of every category.
- Log extensively during development --- use
print()or pyRevit's output module. - Test edge cases --- empty parameters, zero-area rooms, unplaced rooms, design options, phases, linked models.
- Version test --- verify scripts work across target Revit versions (2022, 2023, 2024, 2025).
- Performance test --- run scripts on the largest project model to identify bottlenecks.
- User acceptance test --- deploy to 2-3 users before firm-wide rollout; collect feedback.
- Regression test --- after Revit updates, re-run all scripts to verify continued functionality.