bim-classification-ai
Classify BIM elements using AI and standard classification systems. Map elements to UniFormat, MasterFormat, OmniClass, and CWICR codes.
What this skill does
# BIM Classification AI
## Business Case
### Problem Statement
BIM models often lack proper classification:
- Elements without classification codes
- Inconsistent naming conventions
- Manual classification is tedious
- Difficult to map to cost databases
### Solution
AI-powered classification system that analyzes BIM element properties and suggests appropriate classification codes from multiple standards.
### Business Value
- **Automation** - Reduce manual classification effort
- **Consistency** - Standardized classification across projects
- **Integration** - Enable cost estimation and QTO
- **Quality** - Improved data quality in BIM models
## Technical Implementation
```python
import pandas as pd
from typing import Dict, Any, List, Optional, Tuple
from dataclasses import dataclass, field
from enum import Enum
import re
class ClassificationSystem(Enum):
"""Classification standards."""
UNIFORMAT = "uniformat"
MASTERFORMAT = "masterformat"
OMNICLASS = "omniclass"
UNICLASS = "uniclass"
CWICR = "cwicr"
@dataclass
class ClassificationCode:
"""Classification code with metadata."""
code: str
title: str
system: ClassificationSystem
level: int
parent_code: Optional[str] = None
keywords: List[str] = field(default_factory=list)
@dataclass
class ClassificationResult:
"""Result of classification attempt."""
element_id: str
element_name: str
element_category: str
suggested_codes: List[Tuple[ClassificationCode, float]] # (code, confidence)
selected_code: Optional[ClassificationCode] = None
manual_override: bool = False
class ClassificationDatabase:
"""Classification codes database."""
def __init__(self):
self.codes: Dict[ClassificationSystem, List[ClassificationCode]] = {
system: [] for system in ClassificationSystem
}
self._load_standard_codes()
def _load_standard_codes(self):
"""Load standard classification codes."""
# UniFormat II codes
uniformat_codes = [
("A", "Substructure", 1, None, ["foundation", "basement", "excavation"]),
("A10", "Foundations", 2, "A", ["footing", "pile", "foundation"]),
("A1010", "Standard Foundations", 3, "A10", ["spread footing", "strip footing"]),
("A1020", "Special Foundations", 3, "A10", ["pile", "caisson", "mat foundation"]),
("B", "Shell", 1, None, ["superstructure", "exterior", "roof"]),
("B10", "Superstructure", 2, "B", ["floor", "roof", "structure"]),
("B1010", "Floor Construction", 3, "B10", ["slab", "deck", "floor"]),
("B1020", "Roof Construction", 3, "B10", ["roof", "deck", "truss"]),
("B20", "Exterior Enclosure", 2, "B", ["wall", "window", "door"]),
("B2010", "Exterior Walls", 3, "B20", ["curtain wall", "masonry", "cladding"]),
("B2020", "Exterior Windows", 3, "B20", ["window", "glazing", "storefront"]),
("B30", "Roofing", 2, "B", ["roof", "membrane", "insulation"]),
("C", "Interiors", 1, None, ["partition", "ceiling", "floor finish"]),
("C10", "Interior Construction", 2, "C", ["partition", "door", "glazing"]),
("C20", "Stairs", 2, "C", ["stair", "railing", "ladder"]),
("C30", "Interior Finishes", 2, "C", ["finish", "paint", "flooring"]),
("D", "Services", 1, None, ["mechanical", "electrical", "plumbing"]),
("D10", "Conveying", 2, "D", ["elevator", "escalator", "lift"]),
("D20", "Plumbing", 2, "D", ["pipe", "fixture", "drain"]),
("D30", "HVAC", 2, "D", ["duct", "hvac", "air handling"]),
("D40", "Fire Protection", 2, "D", ["sprinkler", "fire", "suppression"]),
("D50", "Electrical", 2, "D", ["electrical", "power", "lighting"]),
]
for code, title, level, parent, keywords in uniformat_codes:
self.codes[ClassificationSystem.UNIFORMAT].append(
ClassificationCode(code, title, ClassificationSystem.UNIFORMAT, level, parent, keywords)
)
# MasterFormat codes (simplified)
masterformat_codes = [
("03", "Concrete", 1, None, ["concrete", "formwork", "reinforcing"]),
("03 30 00", "Cast-in-Place Concrete", 2, "03", ["concrete", "pour", "slab"]),
("03 41 00", "Precast Structural Concrete", 2, "03", ["precast", "concrete", "panel"]),
("04", "Masonry", 1, None, ["brick", "block", "stone"]),
("05", "Metals", 1, None, ["steel", "metal", "aluminum"]),
("05 12 00", "Structural Steel Framing", 2, "05", ["beam", "column", "steel"]),
("06", "Wood, Plastics, Composites", 1, None, ["wood", "timber", "lumber"]),
("07", "Thermal and Moisture Protection", 1, None, ["insulation", "roofing", "waterproofing"]),
("08", "Openings", 1, None, ["door", "window", "glazing"]),
("09", "Finishes", 1, None, ["drywall", "paint", "flooring"]),
("21", "Fire Suppression", 1, None, ["sprinkler", "fire", "suppression"]),
("22", "Plumbing", 1, None, ["pipe", "fixture", "plumbing"]),
("23", "HVAC", 1, None, ["hvac", "duct", "mechanical"]),
("26", "Electrical", 1, None, ["electrical", "power", "lighting"]),
]
for code, title, level, parent, keywords in masterformat_codes:
self.codes[ClassificationSystem.MASTERFORMAT].append(
ClassificationCode(code, title, ClassificationSystem.MASTERFORMAT, level, parent, keywords)
)
def search(self, query: str, system: ClassificationSystem = None) -> List[ClassificationCode]:
"""Search classification codes by keyword."""
results = []
query_lower = query.lower()
systems = [system] if system else list(ClassificationSystem)
for sys in systems:
for code in self.codes.get(sys, []):
# Check title
if query_lower in code.title.lower():
results.append(code)
continue
# Check keywords
if any(query_lower in kw.lower() for kw in code.keywords):
results.append(code)
return results
class BIMClassificationAI:
"""AI-powered BIM element classification."""
def __init__(self, classification_db: ClassificationDatabase = None):
self.db = classification_db or ClassificationDatabase()
self.category_mappings = self._load_category_mappings()
self.results: List[ClassificationResult] = []
def _load_category_mappings(self) -> Dict[str, List[str]]:
"""Load Revit/IFC category to classification mappings."""
return {
# Structural
"Structural Columns": ["B10", "05 12 00", "column", "structural"],
"Structural Framing": ["B10", "05 12 00", "beam", "framing"],
"Structural Foundations": ["A10", "03 30 00", "foundation", "footing"],
"Floors": ["B1010", "03 30 00", "floor", "slab"],
# Architectural
"Walls": ["B20", "04", "wall", "partition"],
"Curtain Walls": ["B2010", "08 44 00", "curtain wall", "glazing"],
"Windows": ["B2020", "08 50 00", "window", "glazing"],
"Doors": ["C10", "08 10 00", "door", "opening"],
"Roofs": ["B30", "07 50 00", "roof", "roofing"],
"Ceilings": ["C30", "09 51 00", "ceiling", "finish"],
"Stairs": ["C20", "05 51 00", "stair", "railing"],
# MEP
"Ducts": ["D30", "23 31 00", "duct", "hvac"],
"Pipes": ["D20", "22 11 00", "pipe", "plumbing"],
"Electrical Equipment": ["D50", "26 20 00", "electrical", "panel"],
"Lighting Fixtures": ["D50", "26 51 00", "light", "fixture"],
"Sprinklers": ["D40", "21 13 00", "sprinkler", "fire protection"],
"Mechanical Equipment": ["D30Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.