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
BuiltInCategory enum.
- 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 --- text
StorageType.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 / DocumentSaved
Application.ViewActivated
Application.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
TransactionManager instead of raw Transaction.
- Use
DocumentManager.Instance.CurrentDBDocument instead of __revit__.
- Inputs come from
IN[0], IN[1], ...; output goes to OUT.
Performance Considerations
Dynamo becomes slow when:
- Graphs exceed 200-300 nodes.
- Lists contain 10,000+ items with geometry preview on.
- Multiple levels of
List.Map or List@Level create 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
Passthrough node 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 classes in Revit maps categories to IFC entities.
- Property set mapping: custom
.txt mapping 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
IndependentTag at room location point.
- Door tags: iterate doors, place tag at door midpoint with leader if needed.
- Dimension strings: create
Dimension objects 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
ViewSchedule of 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.Geometry in loops --- geometry extraction is expensive. Cache results.
- Use
ElementId sets for fast lookups instead of element lists.
- Turn off warning suppression wisely ---
FailureHandlingOptions can skip dialog boxes during batch operations.
User Input Patterns
from pyrevit import forms
# Simple alert
forms.alert("Operation complete.",
…(truncated)
1---2name: bim-scripting3description: 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 design4---56# BIM Scripting78Comprehensive reference for automating Building Information Modeling workflows9through scripting, API access, and interoperability platforms. This skill covers10the full spectrum of BIM automation --- from visual programming with Dynamo11through deep Revit API scripting, pyRevit extension development, IFC/openBIM12data exchange, model checking, automated documentation, and cross-platform13interoperability via Speckle, BHoM, and Rhino.Inside.Revit.1415---1617## 1. BIM Automation Philosophy1819### Why Script BIM2021BIM models are databases disguised as 3D geometry. Every wall, door, room, and22duct segment carries structured data --- type, dimensions, material, cost code,23fire rating, acoustic class, phase, workset, design option. Manual manipulation24of that data does not scale. A 200-unit residential project may contain 40,000+25elements, each with 30--80 parameters. Changing a naming convention, verifying26parameter completeness, or exporting coordinated drawing sets by hand is not27just slow --- it is error-prone and unrepeatable.2829Scripting BIM means treating the model as a programmable data source:3031- **Read** element properties at scale (audit, validate, report).32- **Write** parameter values in batch (standards enforcement, data enrichment).33- **Create** elements procedurally (repetitive layouts, adaptive placement).34- **Transform** geometry computationally (facade panelization, structural optimization).35- **Export** deliverables automatically (sheets to PDF, models to IFC, data to dashboards).3637### Manual vs. Automated BIM Workflows3839| Workflow | Manual Approach | Automated Approach | Time Savings |40|---|---|---|---|41| Parameter QA | Open each element, check value | Script scans all elements, flags violations | 95% |42| Sheet creation | Place views, adjust crops, add tags one by one | Script generates sheets from template rules | 90% |43| Clash detection | Visual inspection in section views | Navisworks / script-based interference check | 85% |44| Export to IFC | File > Export > IFC, configure, repeat per model | Batch script exports all linked models with preset mappings | 80% |45| Room finish schedule | Manual schedule, manual formatting | API-generated schedule with conditional formatting | 75% |46| Design option comparison | Duplicate views, switch options, compare | Script generates comparison report with metrics | 90% |47| Naming convention enforcement | Manual review of browser tree | FilteredElementCollector + regex validation | 98% |4849### ROI of BIM Automation5051The return on investment for BIM scripting follows a clear pattern:52531. **First script** --- 2-8 hours to develop, saves 1-4 hours per use. Break-even after 2-3 uses.542. **Script library** (20-50 tools) --- 200-500 hours to develop, saves 10-30 hours per project. Break-even within 1-2 projects.553. **Custom application** --- 500-2000 hours to develop, saves 50-200 hours per project. Break-even within 3-5 projects.564. **Enterprise platform** --- 2000-10,000 hours to develop, transforms entire practice workflow.5758### The Automation Spectrum5960```61Level 1: Visual Programming (Dynamo, Grasshopper)62 - Lowest barrier to entry63 - Best for designers who think visually64 - Limited scalability and version control65 - Good for: one-off design explorations, parameter mapping, geometry generation6667Level 2: Scripting (Python in Dynamo, pyRevit, RevitPythonShell)68 - Moderate barrier to entry69 - Full API access with Python convenience70 - Version-controllable, shareable71 - Good for: batch operations, custom tools, data workflows7273Level 3: Custom Tools (C# add-ins, pyRevit extensions)74 - Higher barrier to entry75 - Compiled performance, custom UI, ribbon integration76 - Deployable to teams77 - Good for: production tools, firm-wide standards enforcement7879Level 4: Full Applications (standalone apps, web dashboards, microservices)80 - Highest barrier to entry81 - Complete control over UX and data pipeline82 - Cloud-scalable, multi-user83 - Good for: enterprise BIM management, cross-project analytics84```8586### When to Automate vs. When to Model Manually8788Automate when:89- The task repeats across projects or phases.90- The task involves more than 50 elements.91- Consistency and auditability are critical (QA/QC, code compliance).92- The output feeds downstream processes (cost, energy, structural analysis).93- Human error risk is high (naming, classification, spatial containment).9495Model manually when:96- The task is a one-time creative act (early concept massing).97- Judgment and spatial intuition outweigh procedural logic.98- The element count is small and the rules are ambiguous.99- The cost of developing automation exceeds the cost of manual work.100101### BIM Maturity Levels and Automation102103| BIM Level | Description | Automation Role |104|---|---|---|105| Level 0 | 2D CAD, no BIM | CAD scripting (AutoLISP, VBA) for drawing automation |106| Level 1 | 3D modeling, 2D documentation | Basic Dynamo scripts, parameter management |107| Level 2 | Federated models, structured data exchange | IFC workflows, clash detection, model checking |108| Level 3 | Integrated single model, full lifecycle data | API-driven analytics, real-time dashboards, AI-assisted QA |109| Level 4 (emerging) | Digital twin, IoT-connected, predictive | Continuous model sync, ML-driven optimization, autonomous agents |110111---112113## 2. Revit API Fundamentals114115### Architecture116117The Revit API is a .NET framework (C# or VB.NET natively, Python via IronPython118or CPython with RevitPythonShell/pyRevit). The object hierarchy:119120```121UIApplication122 └── Application (Revit application-level settings, version info)123 └── Document (the .rvt file; model database)124 ├── Elements (everything in the model)125 ├── Views (plans, sections, 3D views, schedules)126 ├── Phases (existing, new construction, demolition)127 ├── DesignOptions (option sets and options)128 ├── Worksets (worksharing partitions)129 └── Settings (project units, line styles, fill patterns)130```131132### Element Types133134Every object in a Revit model inherits from `Element`. Key subclasses:135136| Class | Description | Example |137|---|---|---|138| `FamilyInstance` | Placed instance of a loadable family | Door, window, furniture, fixture |139| `Wall` | System family: wall element | Basic Wall, Curtain Wall, Stacked Wall |140| `Floor` | System family: floor slab | Generic Floor, composite assemblies |141| `Roof` | System family: roof element | Basic Roof, extrusion roof |142| `Ceiling` | System family: ceiling element | Compound ceiling, basic ceiling |143| `FamilyInstance` (structural) | Columns, beams, braces | Steel W-shapes, concrete columns |144| `Room` | Spatial element for architectural spaces | Bounded by room-bounding elements |145| `Area` | Spatial element for area plans | Gross area, rentable area |146| `View` | Any view in the model | `ViewPlan`, `ViewSection`, `View3D`, `ViewSheet` |147| `ViewSheet` | A sheet for documentation | Contains viewport placements |148| `ViewSchedule` | A schedule/quantity takeoff | Tabular data extraction |149| `Group` | Grouped elements | Model groups, detail groups |150| `Level` | Datum: horizontal reference plane | Defines story heights |151| `Grid` | Datum: vertical reference plane | Structural grid lines |152| `ReferencePlane` | Construction plane | Alignment references |153154### Categories, Families, Types, Instances155156This four-level hierarchy is central to Revit:157158```159Category (e.g., Doors)160 └── Family (e.g., Single-Flush)161 └── Type (e.g., 36" x 84")162 └── Instance (placed door #1, #2, #3...)163```164165- **Category**: broad classification (Walls, Doors, Floors, Furniture). Each has a `BuiltInCategory` enum.166- **Family**: a parametric definition (.rfa file for loadable families; system families are built-in).167- **Type**: a named set of parameter values within a family (dimensions, materials).168- **Instance**: a placed occurrence with instance-specific parameters (location, room, mark).169170### Parameters171172Parameters store all non-geometric data on elements.173174| Parameter Kind | Scope | Definition | Access |175|---|---|---|---|176| Built-in | Hardcoded by Revit | Predefined (e.g., `WALL_BASE_OFFSET`) | `element.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET)` |177| Project | One project file | Defined in Project Parameters dialog | `element.LookupParameter("MyParam")` |178| Shared | Across projects/families | Defined in Shared Parameters file (.txt) | `element.get_Parameter(guid)` or by name |179| Family | Inside .rfa family | Defined in Family Editor | Exposed as type or instance parameter |180| Global | Project-wide value | Not element-bound; referenced by formulas | `GlobalParametersManager` |181182Parameter storage types:183- `StorageType.String` --- text184- `StorageType.Integer` --- integers and YesNo (0/1)185- `StorageType.Double` --- real numbers (always in internal units)186- `StorageType.ElementId` --- reference to another element (material, type, level)187188### Transactions189190Every model modification must occur inside a `Transaction`. Without it, the API191throws an `InvalidOperationException`.192193```python194# Python (pyRevit / RevitPythonShell)195from Autodesk.Revit.DB import Transaction196197doc = __revit__.ActiveUIDocument.Document198t = Transaction(doc, "Batch Update Parameters")199t.Start()200201try:202 # ... modify elements ...203 t.Commit()204except Exception as e:205 t.RollBack()206 print("Error: {}".format(e))207```208209Transaction types:210- **Transaction** --- standard single transaction (most common).211- **TransactionGroup** --- wraps multiple transactions; can assimilate (merge into one undo) or roll back all.212- **SubTransaction** --- nested within a Transaction; can roll back independently without aborting the parent.213214### FilteredElementCollector215216The primary mechanism for querying elements in a Revit model. It operates as a217builder pattern with filters:218219```python220from Autodesk.Revit.DB import (221 FilteredElementCollector, BuiltInCategory,222 ElementCategoryFilter, ElementClassFilter223)224225# All walls in the model226walls = FilteredElementCollector(doc) \227 .OfCategory(BuiltInCategory.OST_Walls) \228 .WhereElementIsNotElementType() \229 .ToElements()230231# All door types (not instances)232door_types = FilteredElementCollector(doc) \233 .OfCategory(BuiltInCategory.OST_Doors) \234 .WhereElementIsElementType() \235 .ToElements()236237# All family instances of a specific class238instances = FilteredElementCollector(doc) \239 .OfClass(FamilyInstance) \240 .ToElements()241242# Elements in a specific view243view_elements = FilteredElementCollector(doc, view.Id) \244 .OfCategory(BuiltInCategory.OST_Walls) \245 .ToElements()246```247248### Geometry Access249250Extracting geometry from Revit elements:251252```253Element254 └── get_Geometry(Options)255 └── GeometryElement (iterable)256 ├── Solid257 │ ├── Faces (FaceArray)258 │ │ └── Face → Surface, UV domain, normal259 │ └── Edges (EdgeArray)260 │ └── Edge → Curve261 ├── GeometryInstance (for family instances)262 │ └── GetInstanceGeometry() → GeometryElement263 ├── Curve (for line-based elements)264 ├── Point265 └── PolyLine266```267268### Units269270Revit internal units are **always**:271- Length: **feet**272- Angle: **radians**273- Area: **square feet**274- Volume: **cubic feet**275276Use `UnitUtils.ConvertFromInternalUnits()` and `UnitUtils.ConvertToInternalUnits()`277for conversion. In Revit 2022+, use `UnitTypeId` instead of `DisplayUnitType`.278279### Events280281The Revit API provides application and document-level events:282- `Application.DocumentOpened` / `DocumentClosing` / `DocumentSaved`283- `Application.ViewActivated`284- `Application.DialogBoxShowing` (intercept and auto-dismiss dialogs)285- `Document.DocumentChanged` (react to element modifications)286- `UIApplication.Idling` (periodic background processing)287288### External Commands, Applications, Events289290| Type | Purpose | Lifecycle |291|---|---|---|292| `IExternalCommand` | Single button click action | Runs once per invocation |293| `IExternalApplication` | Ribbon tab/panel setup, startup logic | Runs at Revit startup/shutdown |294| `IExternalDBApplication` | DB-level (no UI) startup logic | For services, updaters |295| `IExternalEventHandler` | Thread-safe model modification from external threads | Raised via `ExternalEvent` |296297### C# vs. Python for Revit API298299| Criterion | C# | Python (IronPython/CPython) |300|---|---|---|301| Performance | Compiled; fastest | Interpreted; slower for large loops |302| Debugging | Full Visual Studio debugger | Print statements, limited debugger |303| Deployment | DLL add-in; requires compilation | Script file; instant edit-run cycle |304| Learning curve | Steeper (typed language, project setup) | Gentler (dynamic typing, REPL) |305| API coverage | 100% | 100% (same .NET API via clr) |306| Ecosystem | NuGet packages, .NET libraries | Python packages (limited in IronPython) |307| UI creation | WPF, WinForms with full designer | WPF possible but harder; rpw simplifies |308| Best for | Production add-ins, enterprise tools | Rapid prototyping, small utilities, pyRevit |309310---311312## 3. Dynamo for Revit313314### Core Advantages315316Dynamo is a visual programming environment integrated with Revit (ships with317Revit since 2017). Key strengths:318319- **Visual dataflow** --- nodes connected by wires; intuitive for non-programmers.320- **Live Revit connection** --- read/write model elements in real time.321- **Geometry preview** --- 3D preview of computational geometry before committing to Revit.322- **Extensibility** --- custom nodes in Python, C#, or DesignScript; package manager ecosystem.323324### Revit-Specific Nodes325326Dynamo provides dedicated Revit node categories:327328- **Selection**: Select Model Element, Select Elements by Category, All Elements of Category329- **Create**: Wall.ByCurveAndHeight, Floor.ByOutlineTypeAndLevel, FamilyInstance.ByPoint330- **Modify**: Element.SetParameterByName, Element.MoveByVector, Element.OverrideColorInView331- **Query**: Element.GetParameterValueByName, Element.BoundingBox, Room.Boundaries332333### Dynamo Player334335Dynamo Player exposes Dynamo scripts as simple button-click tools for end users336who do not need to understand the graph. Configure inputs as user-facing337prompts. Best practice: design scripts specifically for Player with clear input338labels and minimal required interaction.339340### Geometry Kernels341342Dynamo uses **two separate geometry engines**:3433441. **DesignScript / ASM (Autodesk Shape Manager)** --- Dynamo's native geometry kernel.345 Creates Points, Curves, Surfaces, Solids in Dynamo's 3D preview.3462. **Revit geometry** --- the actual BIM model geometry.347348These are **not interchangeable**. A Dynamo `Surface` is not a Revit `Face`.349Converting between them requires explicit nodes:350- `Surface.ByPatch` (Dynamo) vs. `FaceWall.Create` (Revit)351- `Curve.ByPoints` (Dynamo) vs. `ModelCurve.ByCurve` (Revit)352353### Common Revit Workflows in Dynamo3543551. **Room-based floor finish placement** --- query room boundaries, offset curves, create floor elements by outline.3562. **Adaptive component placement** --- distribute families along curves or surfaces with parameter-driven spacing.3573. **Parameter read/write** --- bulk read element parameters to Excel, modify, write back.3584. **View creation** --- generate scope boxes, create dependent views per scope box, apply view templates.3595. **Sheet setup** --- create sheets from list, place viewports at coordinates, populate titleblock parameters.3606. **Keynote management** --- read keynote table, validate against model, update keynote parameters.3617. **Area analysis** --- extract room areas, calculate ratios (net-to-gross, circulation percentage), color-code by metric.362363### Essential Packages364365| Package | Author | Key Capabilities |366|---|---|---|367| Clockwork | Andreas Dieckmann | 500+ utility nodes; view manipulation, element filtering, string operations |368| Rhythm | John Pierson | Revit-focused; sheet management, view manipulation, element creation |369| archi-lab | Konrad Sobon | View/sheet automation, element selection, Revit API wrappers |370| spring nodes | Dimitar Venkov | Geometry, mesh processing, FEM analysis integration |371| BimorphNodes | Bimorph | Geometry, CAD import, mesh to solid conversion |372| Genius Loci | Alban de Chasteigner | Site tools, topography, Revit element manipulation |373| Data-Shapes | Mostafa El Ayoubi | Custom UI nodes (forms, dropdowns, file pickers) |374| Orchid | Erik Falck Jorgensen | Document management, family loading, workset operations |375| LunchBox | Nathan Miller | Paneling, geometric patterns, data management |376377### Python Scripting in Dynamo378379Python nodes in Dynamo provide full Revit API access:380381```python382import clr383clr.AddReference('RevitAPI')384clr.AddReference('RevitServices')385386from Autodesk.Revit.DB import *387from RevitServices.Persistence import DocumentManager388from RevitServices.Transactions import TransactionManager389390doc = DocumentManager.Instance.CurrentDBDocument391392# Start transaction393TransactionManager.Instance.EnsureInTransaction(doc)394395# ... API operations ...396397TransactionManager.Instance.TransactionTaskDone()398```399400Key differences from standalone pyRevit scripts:401- Use `TransactionManager` instead of raw `Transaction`.402- Use `DocumentManager.Instance.CurrentDBDocument` instead of `__revit__`.403- Inputs come from `IN[0], IN[1], ...`; output goes to `OUT`.404405### Performance Considerations406407Dynamo becomes slow when:408- Graphs exceed 200-300 nodes.409- Lists contain 10,000+ items with geometry preview on.410- Multiple levels of `List.Map` or `List@Level` create combinatorial explosions.411412Alternatives when Dynamo is too slow:413- Move heavy logic into a single Python node (avoids inter-node marshalling).414- Use pyRevit for batch operations without geometry preview overhead.415- Use compiled C# add-in for maximum performance.416- Use Dynamo's `Passthrough` node to sequence operations and avoid unnecessary recalculation.417418---419420## 4. pyRevit Framework421422### Architecture423424pyRevit is a rapid application development framework for Revit. It creates425ribbon UI elements from a folder structure:426427```428MyExtension.extension/429 ├── MyTab.tab/430 │ ├── MyPanel.panel/431 │ │ ├── MyButton.pushbutton/432 │ │ │ ├── script.py (IronPython script)433 │ │ │ ├── icon.png (16x16, 24x24, or 32x32)434 │ │ │ └── bundle.yaml (tooltip, author, help URL)435 │ │ ├── MySplitButton.splitbutton/436 │ │ │ ├── Option1.pushbutton/437 │ │ │ └── Option2.pushbutton/438 │ │ └── MyPullDown.pulldown/439 │ │ ├── Item1.pushbutton/440 │ │ └── Item2.pushbutton/441 │ └── AnotherPanel.panel/442 └── lib/ (shared Python modules)443 └── my_utils.py444```445446### Script Types447448- **IronPython (.py)** --- default; runs in Revit's IronPython engine. Access to .NET via `clr`.449- **CPython (.py with `#! python3`)** --- runs in CPython 3.x. Access to pip packages (pandas, numpy). Cannot access UI elements directly.450- **C# (.cs)** --- compiled at runtime. Full performance and type safety.451452### pyRevit CLI453454```bash455# Install pyRevit456pyrevit install457458# Clone an extension from GitHub459pyrevit extend ui MyExtension https://github.com/user/repo.git460461# List installed extensions462pyrevit extensions list463464# Attach to a Revit version465pyrevit attach 2024 latest466467# Enable/disable extensions468pyrevit extensions enable MyExtension469pyrevit extensions disable MyExtension470471# Clear caches472pyrevit caches clear --all473```474475### Built-in Tools Reference476477pyRevit ships with dozens of production-ready tools:478479- **Select** --- select all instances of a type, select by parameter value, select linked elements.480- **Match** --- match type properties, match graphic overrides between elements.481- **Keynotes** --- keynote manager with live editing and project keynote file management.482- **Sheets** --- batch create sheets, renumber sheets, print sheet sets.483- **Views** --- batch create views, set view templates, manage scope boxes.484- **Project** --- project parameter manager, shared parameter loader.485- **Toggles** --- quick toggles for halftone, crop regions, annotations.486487### Creating Custom Extensions488489Minimum viable pyRevit button:490491```python492# script.py493"""Tooltip text shown on hover."""494495__title__ = "My Button"496__author__ = "Your Name"497498from pyrevit import revit, DB, forms499500doc = revit.doc501502# Get all rooms503rooms = DB.FilteredElementCollector(doc) \504 .OfCategory(DB.BuiltInCategory.OST_Rooms) \505 .WhereElementIsNotElementType() \506 .ToElements()507508# Filter rooms with no number509unnamed = [r for r in rooms if not r.get_Parameter(510 DB.BuiltInParameter.ROOM_NUMBER).AsString()]511512if unnamed:513 forms.alert("{} rooms have no number assigned.".format(len(unnamed)))514else:515 forms.alert("All rooms are numbered.", title="QA Check Passed")516```517518### Transaction Handling in pyRevit519520pyRevit provides a context manager for transactions:521522```python523from pyrevit import revit, DB524525with revit.Transaction("Update Room Names"):526 for room in rooms:527 param = room.get_Parameter(DB.BuiltInParameter.ROOM_NAME)528 current = param.AsString()529 param.Set(current.upper())530```531532### RevitPythonShell533534An interactive Python REPL inside Revit. Useful for:535- Exploring the API interactively (inspect elements, test queries).536- Quick one-off operations without creating a full pyRevit script.537- Debugging: inspect element properties, test FilteredElementCollector queries.538539### Template Scripts540541**Batch parameter update:**542```python543from pyrevit import revit, DB, forms544545doc = revit.doc546walls = DB.FilteredElementCollector(doc) \547 .OfCategory(DB.BuiltInCategory.OST_Walls) \548 .WhereElementIsNotElementType() \549 .ToElements()550551with revit.Transaction("Set Wall Comments"):552 for wall in walls:553 wall.LookupParameter("Comments").Set("Reviewed")554```555556**View creation from room list:**557```python558from pyrevit import revit, DB559560doc = revit.doc561rooms = DB.FilteredElementCollector(doc) \562 .OfCategory(DB.BuiltInCategory.OST_Rooms) \563 .WhereElementIsNotElementType() \564 .ToElements()565566level = rooms[0].Level567vft = doc.GetDefaultElementTypeId(DB.ElementTypeGroup.ViewTypeFloorPlan)568569with revit.Transaction("Create Room Views"):570 for room in rooms:571 name = room.get_Parameter(DB.BuiltInParameter.ROOM_NAME).AsString()572 view = DB.ViewPlan.Create(doc, vft, level.Id)573 view.Name = "Room - {}".format(name)574```575576### Deployment577578- **Shared extension path**: configure in pyRevit settings to point to a network share.579 All team members load extensions from the same location.580- **Version control**: store extensions in Git. Use CI/CD to deploy to the shared path.581- **pyRevit CLI** can install extensions from Git repositories directly.582583### pyRevit Hooks584585pyRevit supports event hooks via specially named scripts:586587- `doc-changed-[hookid].py` --- fires when the document changes.588- `doc-opened-[hookid].py` --- fires when a document is opened.589- `doc-saved-[hookid].py` --- fires after a document is saved.590- `app-init-[hookid].py` --- fires when Revit starts (before any document).591592Hooks live in a `hooks/` folder within the extension.593594---595596## 5. IFC & openBIM597598### IFC Schema Overview599600IFC (Industry Foundation Classes) is an ISO-standard (ISO 16739) open data601schema for BIM data exchange. Major versions:602603| Version | Status | Key Additions |604|---|---|---|605| IFC2x3 | Legacy, widely supported | Most common in practice; 650+ entities |606| IFC4 | Current standard (ISO 16739-1:2018) | Improved geometry, new MEP entities, 4D/5D support |607| IFC4.3 | Released 2024 | Infrastructure: roads, bridges, rail, tunnels, ports |608609### Key IFC Entities610611```612IfcProject613 └── IfcSite614 └── IfcBuilding615 └── IfcBuildingStorey616 ├── IfcWall / IfcWallStandardCase617 ├── IfcSlab618 ├── IfcBeam619 ├── IfcColumn620 ├── IfcDoor621 ├── IfcWindow622 ├── IfcSpace (equivalent of Revit Room)623 ├── IfcCurtainWall624 ├── IfcStair / IfcStairFlight625 ├── IfcRamp / IfcRampFlight626 ├── IfcRailing627 ├── IfcRoof628 ├── IfcCovering (finishes, ceilings)629 ├── IfcFurnishingElement630 └── IfcDistributionElement (MEP)631 ├── IfcFlowSegment (pipes, ducts)632 ├── IfcFlowTerminal (fixtures, diffusers)633 └── IfcFlowFitting (elbows, tees)634```635636### Property Sets and Quantity Sets637638IFC data is carried in standardized property sets (Psets) and quantity sets (Qtos):639640- **Pset_WallCommon**: Reference, Status, IsExternal, ThermalTransmittance, FireRating, AcousticRating641- **Pset_SlabCommon**: Reference, Status, IsExternal, LoadBearing, AcousticRating642- **Pset_DoorCommon**: Reference, FireRating, IsExternal, SecurityRating, HandicapAccessible643- **Pset_SpaceCommon**: Reference, IsExternal, GrossPlannedArea, NetPlannedArea, PubliclyAccessible644- **Qto_WallBaseQuantities**: Length, Width, Height, GrossVolume, NetVolume, GrossSideArea, NetSideArea645- **Qto_SlabBaseQuantities**: Width, Length, Depth, Perimeter, GrossArea, NetArea, GrossVolume, NetVolume646647### IFC Export Settings in Revit648649Critical export configuration:650- **IFC version**: IFC2x3 Coordination View 2.0 (most compatible) or IFC4 Reference View.651- **Export mapping table**: `IFC export classes` in Revit maps categories to IFC entities.652- **Property set mapping**: custom `.txt` mapping file for project-specific Psets.653- **Phase**: export only the relevant phase.654- **Base point**: shared coordinates for model federation.655- **Element selection**: current view vs. entire model.656657### MVD (Model View Definition)658659MVDs define subsets of the IFC schema for specific use cases:660661| MVD | Purpose | Use Case |662|---|---|---|663| Coordination View 2.0 | Geometry + basic properties | Multi-discipline coordination |664| Design Transfer View | Rich geometry + full properties | Model handover between authoring tools |665| Reference View | Lightweight reference geometry | Lightweight context for coordination |666| Quantity Takeoff View | Properties + quantities | Cost estimation data exchange |667668### BCF (BIM Collaboration Format)669670BCF (ISO 21597) is a structured format for communicating issues in BIM:671- **BCF XML**: file-based (.bcfzip). Contains viewpoints (camera position, component visibility), comments, and issue metadata.672- **BCF API**: REST API for real-time issue sync between platforms.673- **Workflow**: reviewer opens federated model, creates BCF issue with snapshot, assigns to responsible party, tracks resolution.674675### IFC Tools676677| Tool | Language | Capabilities |678|---|---|---|679| IfcOpenShell | Python/C++ | Read/write/validate IFC; geometry processing; most mature open-source |680| IFC.js | JavaScript | Web-based IFC viewer/parser; WebGL rendering |681| xBIM | C# (.NET) | Read/write IFC; geometry meshing; WPF viewer |682| BIMserver | Java | Model server; IFC storage; version control; plugin architecture |683| Solibri | Desktop app | Model checking; clash detection; rule-based validation |684| BIMcollab | Web/Desktop | BCF management; cloud collaboration; issue tracking |685| BlenderBIM | Python | Full IFC authoring in Blender; IfcOpenShell-based |686687### openBIM Coordination Workflow688689```690Architect (Revit) ──export IFC──> Coordination Platform691Structural (Tekla) ──export IFC──> (Solibri, BIMcollab,692MEP (Revit MEP) ──export IFC──> Navisworks, or custom)693 │694 Federated Model695 │696 ┌─────────────┼─────────────┐697 Clash Detection QA/QC 4D Planning698 │ │ │699 BCF Issues Validation Schedule Link700 │ Report │701 ──BCF──> Author fixes ──re-export──>702```703704---705706## 6. Model Checking & Validation707708### Rule-Based Checking709710Model checking verifies that a BIM model meets predefined rules. Categories:7117121. **Data completeness** --- required parameters are filled.7132. **Naming conventions** --- element names follow organizational standards.7143. **Spatial containment** --- elements are properly hosted on levels/rooms.7154. **Classification compliance** --- elements have correct Uniclass/OmniClass codes.7165. **Geometric validity** --- no zero-thickness walls, no overlapping elements.7176. **Design standards** --- minimum room sizes, maximum corridor lengths, accessibility clearances.718719### Clash Detection Types720721| Type | Description | Tolerance | Example |722|---|---|---|---|723| Hard clash | Physical intersection of elements | 0 mm | Duct passing through beam |724| Soft clash (clearance) | Insufficient clearance | Variable (50-300 mm typical) | Pipe too close to electrical cable tray |725| Workflow clash (4D) | Time-based conflict | Schedule overlap | Two trades occupying same zone simultaneously |726| Duplicate | Same element modeled twice | Position tolerance | Two identical walls overlapping |727728### Navisworks Clash Detection Setup7297301. **Append** all models (Revit NWC, IFC, DWG).7312. **Create selection sets** by discipline (Arch, Struct, MEP), system, or zone.7323. **Configure clash tests**: set A vs. set B, tolerance, clash type.7334. **Apply rules**: ignore clashes between connected elements, within same system, or by specific parameter match.7345. **Group results** by grid intersection, level, or element type.7356. **Generate report**: HTML, XML, or BCF for distribution.736737### Custom Model Checking with Revit API738739```python740from pyrevit import revit, DB, forms, output741742doc = revit.doc743out = output.get_output()744745# Check: All rooms must have a number and name746rooms = DB.FilteredElementCollector(doc) \747 .OfCategory(DB.BuiltInCategory.OST_Rooms) \748 .WhereElementIsNotElementType() \749 .ToElements()750751issues = []752for room in rooms:753 number = room.get_Parameter(DB.BuiltInParameter.ROOM_NUMBER).AsString()754 name = room.get_Parameter(DB.BuiltInParameter.ROOM_NAME).AsString()755 area = room.get_Parameter(DB.BuiltInParameter.ROOM_AREA).AsDouble()756757 if not number:758 issues.append(("Room {} has no number".format(room.Id), room.Id))759 if not name:760 issues.append(("Room {} has no name".format(room.Id), room.Id))761 if area == 0:762 issues.append(("Room {} is not bounded (0 area)".format(room.Id), room.Id))763764out.print_md("## Room QA Report")765out.print_md("**Total rooms**: {}".format(len(rooms)))766out.print_md("**Issues found**: {}".format(len(issues)))767for msg, eid in issues:768 out.print_md("- {} [Click to select](revit://select?eid={})".format(msg, eid))769```770771### LOD/LOI Verification772773BIM Execution Plans specify required Level of Development (LOD) and Level of774Information (LOI) at each project stage. Automated verification:775776- **LOD 100**: massing volumes present; check that IfcBuildingElementProxy exists.777- **LOD 200**: approximate geometry; check that elements have correct category but allow generic types.778- **LOD 300**: precise geometry; verify element dimensions match design intent; all parameters from EIR filled.779- **LOD 350**: coordination geometry; verify connections between disciplines; MEP clearances maintained.780- **LOD 400**: fabrication-ready; verify manufacturer data, part numbers, installation instructions.781782### IFC Validation with IfcOpenShell783784```python785import ifcopenshell786import ifcopenshell.validate787788model = ifcopenshell.open("model.ifc")789790# Schema validation791logger = ifcopenshell.validate.json_logger()792ifcopenshell.validate.validate(model, logger)793794for error in logger.statements:795 print(error)796797# Custom validation: all walls must have Pset_WallCommon798for wall in model.by_type("IfcWall"):799 psets = ifcopenshell.util.element.get_psets(wall)800 if "Pset_WallCommon" not in psets:801 print(f"Wall #{wall.id()} missing Pset_WallCommon")802```803804---805806## 7. Automated Documentation807808### View Creation Automation809810Programmatic view generation eliminates the tedious manual setup of project811views. Common patterns:812813- **Floor plans per level** --- create architectural, structural, MEP, and fire safety plans for every level.814- **Dependent views per scope box** --- subdivide large floor plates into manageable sheets.815- **Sections at every grid intersection** --- structural section cuts for detailing.816- **Enlarged plans per room** --- interior elevations and enlarged plans keyed to room boundaries.817- **3D views per zone** --- isometric views for coordination reviews.818819### Sheet Layout Automation820821```python822from pyrevit import revit, DB823824doc = revit.doc825826# Get titleblock type827tb_type = DB.FilteredElementCollector(doc) \828 .OfCategory(DB.BuiltInCategory.OST_TitleBlocks) \829 .WhereElementIsElementType() \830 .FirstElement()831832# Get all floor plan views833views = DB.FilteredElementCollector(doc) \834 .OfClass(DB.ViewPlan) \835 .WhereElementIsNotElementType() \836 .ToElements()837838with revit.Transaction("Create Sheets"):839 for i, view in enumerate(views):840 if view.IsTemplate or view.Name.startswith("{"):841 continue842 # Create sheet843 sheet = DB.ViewSheet.Create(doc, tb_type.Id)844 sheet.SheetNumber = "A{:03d}".format(i + 1)845 sheet.Name = view.Name846847 # Place viewport at center of sheet848 center = DB.XYZ(1.375, 0.875, 0) # center of A1 sheet in feet849 DB.Viewport.Create(doc, sheet.Id, view.Id, center)850```851852### Tag and Annotation Automation853854- **Room tags**: iterate rooms, place `IndependentTag` at room location point.855- **Door tags**: iterate doors, place tag at door midpoint with leader if needed.856- **Dimension strings**: create `Dimension` objects along gridlines or wall faces.857- **Keynotes**: assign keynote values to elements, place keynote tags in views.858859### Export Automation860861```python862from pyrevit import revit, DB863864doc = revit.doc865866# Batch PDF export (Revit 2022+)867sheets = DB.FilteredElementCollector(doc) \868 .OfClass(DB.ViewSheet) \869 .ToElements()870871pdf_options = DB.PDFExportOptions()872pdf_options.FileName = "ExportedSheets"873pdf_options.Combine = False # separate PDF per sheet874pdf_options.PaperFormat = DB.ExportPaperFormat.Default875pdf_options.ZoomType = DB.ZoomType.FitToPage876877sheet_ids = [s.Id for s in sheets if s.CanBePrinted]878doc.Export("C:/Output/", sheet_ids, pdf_options)879```880881### Drawing List Management882883Automate the drawing list schedule:884- Ensure all sheets have correct sheet number, name, revision, status.885- Generate a `ViewSchedule` of sheets via API with required fields.886- Export drawing list to Excel for transmittals.887- Validate sheet numbering against organizational standard (e.g., `A-101`, `S-201`, `M-301`).888889---890891## 8. BIM Interoperability Platforms892893### Speckle894895Speckle is an open-source data platform for AEC that treats 3D model data as896versionable, streamable, and queryable:897898- **Connectors**: Revit, Rhino, Grasshopper, Blender, AutoCAD, Civil3D, Unity, Unreal, Excel, Power BI, QGIS.899- **Streams**: persistent data channels. Push model data to a stream; any connected app can receive it.900- **Commits**: every push creates a versioned commit. Full history, branching, diffing.901- **Web viewer**: browser-based 3D viewer with filtering, measurement, section cuts.902- **GraphQL API**: programmatic access to all data. Query elements, filter by properties.903- **Speckle Automate**: serverless functions triggered on new commits. Use for automated QA/QC, data enrichment, notifications.904905**When to use Speckle**: cross-platform model sharing, design review with non-BIM906stakeholders, automated data pipelines, custom dashboards from model data.907908### BHoM (Buildings and Habitats object Model)909910BHoM is an open-source collaborative computational framework for the built911environment:912913- **Object model**: unified .NET object definitions for structural, environmental, architectural, and planning objects.914- **Adapters**: bidirectional data exchange with analysis software:915 - Structural: Robot, GSA, ETABS, SAP2000, Lusas916 - Environmental: IES, EnergyPlus, Ladybug917 - BIM: Revit, IFC918 - Geometry: Rhino, Grasshopper919- **Engine**: computational methods that operate on BHoM objects (structural analysis queries, environmental calculations, geometry operations).920- **UI**: Grasshopper components and Excel plugin for accessible interaction.921922**When to use BHoM**: multi-software structural analysis workflows, computational923design pipelines that span multiple analysis tools, when you need a unified924object model across disciplines.925926### Rhino.Inside.Revit927928Rhino.Inside.Revit runs the full Rhino and Grasshopper environment inside the929Revit process, enabling:930931- **Grasshopper → Revit**: create Revit elements (walls, floors, roofs, adaptive components) from Grasshopper geometry.932- **Revit → Grasshopper**: query Revit elements, extract geometry, read parameters.933- **Bidirectional live link**: changes in Grasshopper update Revit elements; changes in Revit reflect in Grasshopper.934- **Rhino geometry in Revit views**: use Rhino's superior NURBS engine for complex geometry, bake to Revit as DirectShape or native elements.935936Use cases:937- Complex facade panelization designed in GH, built as Revit curtain panels.938- Parametric roof geometry from GH, exported as Revit roof-by-face.939- Site grading and landscape computed in GH, placed as Revit topography.940- Structural optimization in GH (Karamba3D), results pushed to Revit structural model.941942### Comparison Table943944| Feature | Speckle | BHoM | Rhino.Inside.Revit |945|---|---|---|---|946| Primary use | Data exchange & versioning | Computational workflows | Geometry & design |947| Architecture | Cloud-based streams | .NET object model + adapters | In-process (runs inside Revit) |948| Revit support | Connector (push/pull) | Adapter (read/write) | Full bidirectional live link |949| Rhino/GH support | Connector | GH components | Native (Rhino is the engine) |950| Analysis tools | Via Automate | Native adapters (Robot, GSA, etc.) | Via GH plugins (Karamba, Ladybug) |951| Open source | Yes (Apache 2.0) | Yes (LGPL 3.0) | Yes (MIT) |952| Best for | Cross-platform data flow | Multi-tool analysis pipelines | Complex geometry in Revit |953954---955956## 9. BIM Scripting Best Practices957958### Error Handling and Logging959960```python961from pyrevit import revit, DB, forms962import traceback963964doc = revit.doc965errors = []966success_count = 0967968with revit.Transaction("Batch Operation"):969 for element in elements:970 try:971 # operation that might fail972 param = element.LookupParameter("Target Param")973 if param and not param.IsReadOnly:974 param.Set(new_value)975 success_count += 1976 else:977 errors.append("Element {}: parameter not found or read-only".format(element.Id))978 except Exception as e:979 errors.append("Element {}: {}".format(element.Id, str(e)))980981# Report results982msg = "Processed: {}\nErrors: {}".format(success_count, len(errors))983if errors:984 msg += "\n\n" + "\n".join(errors[:20]) # limit error display985forms.alert(msg, title="Operation Complete")986```987988### Performance Best Practices9899901. **Minimize FilteredElementCollector calls** --- collect once, filter in Python.9912. **Use quick filters** (OfClass, OfCategory) before slow filters (WherePasses with parameter filter).9923. **Disable regeneration** when not needed: `doc.Regenerate()` only when required.9934. **Batch element creation** --- create elements in a single transaction, not one transaction per element.9945. **Avoid `Element.Geometry` in loops** --- geometry extraction is expensive. Cache results.9956. **Use `ElementId` sets** for fast lookups instead of element lists.9967. **Turn off warning suppression wisely** --- `FailureHandlingOptions` can skip dialog boxes during batch operations.997998### User Input Patterns9991000```python1001from pyrevit import forms10021003# Simple alert1004forms.alert("Operation complete.", 10051006…(truncated)