IFC Mapping Specification¶
Declarative mapping from IFC entity classes to the Pragmatic BIM Data Contract schema and the ingestion adapter database projection.
Files
| File | Role |
|---|---|
ifc_mapping.yaml |
Entrypoint: version, schema URI, imports list |
ifc_mapping.merged.yaml |
Generated single-file artifact for adapters (regenerate after edits) |
_conventions.yaml |
Global rules, metadata capture, field anchors |
_pset_fallbacks.yaml |
PropertySet lookup lists (default + Revit / ArchiCAD / Vectorworks) |
_relationships.yaml |
IFC rel class → relation_type |
_fragments.yaml |
Shared field, geometry, and attribute fragments |
_templates.yaml |
Shared entity templates (inherits) |
entities/architectural.yaml |
Walls, slabs, doors, spatial context, structure |
entities/hvac.yaml |
Ducts, pipes, equipment, systems |
../../scripts/merge_ifc_mapping.py |
Merge split sources → ifc_mapping.merged.yaml |
Split sources are the source of truth. Edit those, then regenerate the merged file.
This directory contains no adapter logic — only declarative YAML plus the merge helper script.
File layout and merge workflow¶
YAML anchors (&name / *name) do not work across files. Split sources are concatenated in imports order by the merge script so anchors resolve correctly.
ifc_mapping.yaml ← entrypoint (imports list)
_conventions.yaml ← conventions + metadata anchors
_pset_fallbacks.yaml ← tool-specific pset lists
_relationships.yaml
_fragments.yaml ← geometry / field fragments (uses pset anchors)
entities/architectural.yaml
entities/hvac.yaml ← entity blocks (indented under entities:)
_templates.yaml
│
▼ python scripts/merge_ifc_mapping.py
ifc_mapping.merged.yaml ← single file for adapters
After editing any split file:
python scripts/merge_ifc_mapping.py
CI check (merged file up to date):
python scripts/merge_ifc_mapping.py --check
Adapters can either load ifc_mapping.merged.yaml directly, or implement the same imports merge at runtime.
Where to edit what¶
| Change | File |
|---|---|
| New Revit / ArchiCAD / Vectorworks pset | _pset_fallbacks.yaml |
| New IFC class (architectural) | entities/architectural.yaml |
| New IFC class (HVAC) | entities/hvac.yaml |
| New relationship rule | _relationships.yaml |
| Metadata / GlobalId conventions | _conventions.yaml |
| Shared field or geometry pattern | _fragments.yaml or _templates.yaml |
Purpose¶
IFC exports vary by authoring tool and project. This mapping:
- Normalizes IFC instances to PBS entity types (
canonical_type) and module categories (content_kind). - Projects schema slots onto adapter columns (
name,code_or_number,storey,attributes). - Declares IFC relationship →
content_relations.relation_typemappings aligned with PBS schema slot names. - Assigns geometry roles for the
content_geometriestable.
Schema slots are defined in contract/ (LinkML YAML at folder root). This mapping must not introduce fields absent from those modules.
Database projection¶
The adapter writes three tables:
content¶
| Column | Source |
|---|---|
content_kind |
physical, virtual, or context (see below) |
canonical_type |
PBS LinkML class name, optionally with variant suffix (e.g. SeparatorSlab.floor) |
canonical_type_version |
Pinned schema release (currently v0.0.7 in ifc_mapping.yaml) |
name |
Entity.name |
code_or_number |
Primary identifier from classifications or PropertySet fallbacks |
storey |
parent_level resolution via spatial containment (GlobalId of IfcBuildingStorey) |
source_id |
IFC GlobalId — primary IFC ↔ contract link (see below) |
source_system |
Export origin (revit, archicad, vectorworks, or default ifc) |
attributes |
JSONB of PBS schema slots for the entity class, including ifc_global_id and metadata[] |
IFC ↔ contract identity (GlobalId)¶
IFC GlobalId is the stable crosswalk between the source model and PBS contract records:
| Location | Role |
|---|---|
content.source_id |
Primary lookup key on ingest and re-import |
attributes.ifc_global_id |
PBS Entity.ifc_global_id slot (same value) |
content_relations.source_content_id / target_content_id |
Relationship endpoints |
Re-imports, updates, and change detection match on GlobalId. The adapter should not generate a new contract id when GlobalId already exists for the same model scope.
Defined in ifc_mapping.yaml under conventions.ifc_contract_link.
content_relations¶
| Column | Source |
|---|---|
source_content_id |
Source element GlobalId |
target_content_id |
Target element GlobalId |
relation_type |
PBS relationship slot name (e.g. parent_level, separates_spaces) |
content_geometries¶
| Column | Source |
|---|---|
geometry_role |
body_3d, footprint_2d, axis, or point (GeometryRepresentationType) |
geometry_space |
IFC representation context or storey GlobalId |
geom |
Geometry payload (adapter-specific) |
content_kind and canonical_type¶
content_kind is the Entity type discriminator (see Entity.content_kind and ContentKind). IFC ingestion produces physical, virtual, context, and project (from IfcProject). Application pipelines create other entity kinds directly.
content_kind |
Entity branch | Examples |
|---|---|---|
physical |
Physical elements | SeparatorWall, ConnectionPhysical, Equipment |
virtual |
Virtual entities | Space, System, ConnectionVirtual, TimeRecord, CostRecord, Material |
context |
Spatial context | BuildingContext, LevelContext, ZoneContext, PerimeterContext |
project |
Business delivery scope | Project |
program |
Portfolio or capital program | Program |
product |
Commercial offering | Product |
deliverable |
Project outcome or handover | Deliverable |
requirement |
Requirements | PerformanceRequirement, SpatialRequirement, RegulatoryRequirement, BriefRequirement, DeliverableRequirement, ScheduleRequirement, CostRequirement, MaterialRequirement |
artifact |
Artifacts | Artifact |
contract |
Contracts | Contract |
decision |
Decisions | Decision |
task |
Tasks | Task |
process |
BPMN process instances | Process |
agent |
Agents | Person, Company, SoftwareAgent |
message |
Messages | Message |
Change records (PropertyChange, GeometryChange, etc.) are not entities and have no content_kind. Adapters or validation pipelines create them directly in a separate change store. Use the concrete change class together with change_type where applicable.
CostRecordRole (cost, price, estimate, actual) is application-created on CostRecord entities — not produced by IFC ingestion. Catalog cost and price records attach to Product.catalog_cost_records; project estimate and actual records use applies_to_entities.
Variant suffixes disambiguate IFC PredefinedType or transport role without inventing new PBS classes:
SeparatorSlab.floor,.roof,.baseslabConnectionPhysical.duct,.pipe,.network_otherBoundary.ceiling,.flooring,.cladding
YAML file structure¶
The entrypoint ifc_mapping.yaml declares version metadata and an imports list. Split modules compose the full mapping (see File layout and merge workflow above). Adapters typically load ifc_mapping.merged.yaml.
Merged structure:
mapping_version: "1.2.0"
schema_uri: https://schema.pragmaticbim.ch/
canonical_type_version: "v0.0.7"
conventions: ...
pset_fallbacks: ...
relationships: ...
fragments: ...
entities: ...
templates: ...
Entity block¶
Each entities.Ifc* entry defines:
| Key | Description |
|---|---|
content_kind |
Module category for the DB |
canonical_type |
PBS class (fixed or via predefined_type_map) |
inherits |
Merge fields from another entity or templates.* entry |
fields |
Top-level DB column lookups |
attributes |
PBS schema slots stored in JSONB |
geometry |
Primary and secondary geometry_role values |
relations |
IFC relationship classes that apply to this entity |
Field source types¶
| Source type | Adapter behavior |
|---|---|
ifc_attribute |
Read a direct IFC attribute |
ifc_attribute_fallback |
Try attributes in order; first non-empty wins |
ifc_pset_fallback |
Try PropertySet/property pairs in order; first match wins |
ifc_attribute_all |
All IFC entity attributes on the instance, minus excluded/promoted ones |
ifc_pset_all |
All PropertySet properties on the instance, minus those used elsewhere |
metadata_merge |
Combine multiple metadata capture rules into one metadata[] array |
ifc_classification |
Map IfcClassificationReference via IfcRelAssociatesClassification |
ifc_relation |
Resolve value through an IFC relationship |
ifc_attribute_heuristic |
Map attribute value through keyword rules with a default |
ifc_relation_heuristic |
Infer value from related entities (e.g. system discipline) |
vocabulary_lookup |
Map IFC PropertySet or attribute values through SKOS bridge TTL files and/or vocabulary prefLabels |
vocabulary_derived_classification |
Derive a Classification entry from a resolved enum/slot via a mapping bridge |
attribute_derivation |
Derive a typed attribute when unset (e.g. is_above_ground from parent_level.elevation) |
constant |
Fixed PBS enum or string value |
predefined_type_map |
Branch on IFC PredefinedType |
Fallback convention¶
Property lookups use ordered fallback lists. The adapter applies conventions.fallback_policy: first_match_wins.
Resolution order for code_or_number¶
- If
source_system_overrides[source_system]exists, try those PropertySet pairs first. - Then try the shared
fallbackslist (tool-agnostic IFC standard psets). - If still empty, use the first
classifications[].classification_codefromIfcRelAssociatesClassification.
Source system overrides¶
source_system |
Typical extra psets |
|---|---|
revit |
Pset_Revit_IdentityData.Mark, Pset_Revit_TypeIdentity.Type Mark |
archicad |
ARCHICAD_General.ID, ARCHICAD_General.Element ID |
vectorworks |
Vectorworks_General.Tag, Vectorworks_Data.RecordName |
Shared defaults (Pset_BuildingElementCommon.Reference, etc.) are always appended after tool-specific entries in the entity fallbacks list.
When extending: add new entries at the top of the relevant override list for a source system. Do not reorder existing entries — downstream projects may depend on current precedence.
Classifications¶
All mapped entities include a classifications field mapping. The adapter populates the PBS classifications[] slot (inlined Classification objects) from IfcRelAssociatesClassification:
| Classification slot | IFC source |
|---|---|
classification_scheme |
ReferencedSource.Name, fallback "ifc" |
classification_code |
Identification or ItemReference |
classification_label |
Name |
classification_uri |
Location |
classification_source |
ReferencedSource.SourceRoles |
This is especially important for entities with weak PBS typing (IfcBeam, IfcColumn, IfcStair, IfcRamp) where classification_code may also serve as code_or_number.
Metadata capture (IFC attributes and PropertySets)¶
All mapped entities populate attributes.metadata[] (PBS MetadataEntry). Two capture rules are merged (metadata_merge):
1. IFC entity attributes¶
Every IFC entity attribute on the instance is stored unless already promoted elsewhere:
| Excluded (promoted) | Destination |
|---|---|
GlobalId |
source_id, attributes.ifc_global_id |
Name, LongName, ObjectType |
content.name |
Description |
attributes.description |
| Attributes mapped to typed PBS slots | e.g. PredefinedType → separator_slab_type |
Key format: {IfcClass}.{AttributeName} — e.g. IfcWall.OverallHeight, IfcDoor.OverallHeight.
2. PropertySets¶
Every PropertySet property not used for code_or_number or typed attribute slots:
Key format: {Pset}.{Property} — e.g. Pset_WallCommon.FireRating.
Value serialization¶
metadata_value is stored as text (MetadataEntry.metadata_value). The adapter serializes IFC values (numbers, booleans, enums, object references) to strings. Object references may use GlobalId where resolvable.
Example attributes JSONB fragment:
{
"ifc_global_id": "3l$8vj$nL1Pu4$G9QjXjC",
"separator_wall_type": "unit_boundary",
"metadata": [
{ "metadata_key": "IfcWall.OverallHeight", "metadata_value": "3.0" },
{ "metadata_key": "Pset_WallCommon.FireRating", "metadata_value": "EI60" }
]
}
Relationship mappings¶
Global rules live under relationships in ifc_mapping.yaml. Each entity lists which IFC rel classes apply.
| IFC relationship | relation_type |
When |
|---|---|---|
IfcRelContainedInSpatialStructure |
parent_level |
RelatingStructure is IfcBuildingStorey |
| same | parent_space |
RelatingStructure is IfcSpace |
| same | parent_building |
RelatingStructure is IfcBuilding |
IfcRelAggregates |
parent_* |
Spatial hierarchy (site → building → storey) |
IfcRelAssignsToGroup |
group_members |
Assigned to IfcZone / IfcGroup |
IfcRelAssignsToSystem |
parent_system |
Element → system |
| same | contained_entities |
System → member elements |
IfcRelSpaceBoundary |
separates_spaces |
Wall/slab → space |
| same | bounded_by |
Covering → space |
IfcRelConnectsElements |
connects_physical_elements |
Structural joints, host connections |
IfcRelConnectsPathElements |
connects_physical_elements |
Duct/pipe run connectivity |
IfcRelFillsElement |
connects_physical_elements |
Door/window ↔ opening |
IfcRelServicesBuildings |
serves_spaces / serves_zones |
System service area |
IfcRelAssociatesClassification |
classifications |
Populates classifications slot |
Geometry roles¶
Uses GeometryRepresentationType values:
| Entity group | Primary | Secondary |
|---|---|---|
| Walls, slabs, roofs, curtain walls, stairs, ramps, equipment, doors, windows, fittings | body_3d |
footprint_2d |
| Duct/pipe segments | axis |
body_3d |
| Spaces | footprint_2d |
body_3d |
| Spatial contexts (site, building, storey, zone) | footprint_2d |
point |
Beams/columns (ConnectionVirtual) |
axis |
— |
Worked examples¶
IfcWall → SeparatorWall¶
# entities.IfcWall (abbreviated)
content_kind: physical
canonical_type: SeparatorWall
fields:
name: Name → LongName → ObjectType
code_or_number: Pset_WallCommon.Reference → … → Revit Mark
storey: IfcRelContainedInSpatialStructure → walk up to IfcBuildingStorey
attributes:
separator_wall_type: unit_boundary
ifc_global_id: GlobalId
geometry:
primary: body_3d
secondary: footprint_2d
metadata_examples:
- IfcWall.OverallHeight
- Pset_WallCommon.FireRating
relations:
- IfcRelContainedInSpatialStructure
- IfcRelSpaceBoundary
IfcDuctSegment → ConnectionPhysical¶
content_kind: physical
canonical_type: ConnectionPhysical.duct
attributes:
connection_physical_type: duct
connection_functional_types: [ventilation]
transport_medium: air
geometry:
primary: axis # centerline
secondary: body_3d
relations:
- IfcRelConnectsPathElements
- IfcRelAssignsToSystem
Connection functional types¶
ConnectionPhysical.connection_functional_types is a multivalued semantic assignment (SKOS vocabulary ConnectionFunctionalType). IFC ingestion sets a default where unambiguous; assign additional values when needed (for example glazed door → [access, visual]).
| Rule | Behavior |
|---|---|
| Multi-type | One connection may carry multiple functional types |
opening_other |
Physical enum stays ambiguous; assign access and/or visual at functional-type stage |
IfcPipeSegment |
Functional type inferred from IfcDistributionSystem.PredefinedType (heating, cooling, fresh_water, waste_water, special_media) |
IfcOpeningElement |
No default functional types — assign per case |
transport_medium |
Coarser bootstrap medium kept alongside functional types for ingestion |
Physical type (connection_physical_type) remains IFC-derived and single-valued. See classification/mapping/connection-functional-to-physical-type.mapping.ttl for compatible physical forms per functional type.
IfcSpace → Space (conditioning and above-ground)¶
Space carries optional design-state booleans as typed PBS slots (not requirements):
| PBS slot | IFC source | Notes |
|---|---|---|
is_heated |
Pset_SpaceCommon.IsHeated |
As-designed heating flag |
is_cooled |
Pset_SpaceCommon.IsAirConditioned |
As-designed cooling / AC flag |
is_above_ground |
— (no standard IFC pset) | Explicit override; see derivation below |
IfcBuildingStorey.Elevation maps to LevelContext.elevation (unit m). When is_above_ground is unset on a Space, adapters apply the attribute_derivation rule in conventions.space_above_ground_from_level:
if space.is_above_ground is null and parent_level.elevation is known:
is_above_ground := parent_level.elevation >= 0
Explicit is_above_ground on Space always wins over the derived value.
Prescriptive validation (application layer): when a brief requires a space to be heated, cooled, or above ground, create a PerformanceRequirement with requirement_property_key matching the Space slot name (is_heated, is_cooled, or is_above_ground), target_value_boolean: true, and link via applies_to_entities. Compare the Space slot (or derived is_above_ground) to the requirement target and record the outcome as MatchChange with match_status met, unmet, or unknown.
Example requirement entity:
content_kind: requirement
canonical_type: PerformanceRequirement
name: Office heating requirement
requirement_property_key: is_heated
target_value_boolean: true
applies_to_entities: [<Space id>]
Example match change when validation runs between revisions:
change_type: match
related_requirement: <PerformanceRequirement id>
affected_subject: <Space id>
match_status: met # or unmet / unknown
from_revision: ...
to_revision: ...
IfcSlab PredefinedType split¶
Per IfcSlabTypeEnum (IFC 4.3). CEILING is not a slab type — ceilings are IfcCovering with PredefinedType=CEILING.
IFC PredefinedType |
canonical_type |
attributes.separator_slab_type |
|---|---|---|
FLOOR, LANDING, PAVING, … |
SeparatorSlab.floor |
floor |
ROOF |
SeparatorSlab.roof |
roof |
BASESLAB, TRACKSLAB |
SeparatorSlab.baseslab |
baseslab |
USERDEFINED, NOTDEFINED |
SeparatorSlab.floor (default) |
floor |
IfcCovering PredefinedType split¶
Per IfcCoveringTypeEnum. Maps to PBS Boundary (schema exact mapping: ifcowl:IfcCovering).
IFC PredefinedType |
canonical_type |
attributes.boundary_type |
|---|---|---|
CEILING |
Boundary.ceiling |
ceiling |
FLOORING, SKIRTINGBOARD, TOPPING |
Boundary.flooring |
flooring |
ROOFING |
Boundary.roofing |
roofing |
CLADDING, INSULATION, … |
Boundary.cladding |
cladding |
IFC schema cross-check notes¶
Mappings are validated against IFC 4.3 entity and enumeration definitions (buildingSMART IFC 4.3 docs). Key corrections:
| Topic | IFC fact | Mapping rule |
|---|---|---|
| Ceiling | IfcCoveringTypeEnum.CEILING on IfcCovering; slabs are structural only |
IfcCovering → Boundary; not on IfcSlab |
| IfcRoof | Assembly container aggregating slabs/beams | PhysicalElement, not SeparatorSlab.roof |
| IfcSlab types | FLOOR, ROOF, BASESLAB, LANDING, + civil types — no CEILING |
Full enum in entities/architectural.yaml |
| Pipe segment type | IfcPipeSegmentTypeEnum: RIGIDSEGMENT, FLEXIBLESEGMENT, … — not GAS/STEAM |
transport_medium inferred from IfcDistributionSystem |
| System PredefinedType | IfcDistributionSystemEnum: DOMESTICHOTWATER, DOMESTICCOLDWATER, … |
Fixed invalid _ spellings; no SANITARY — use SEWAGE/WASTEWATER |
Known schema gaps¶
Documented limitations where IFC semantics exceed current PBS schema coverage:
| Gap | Mapping approach |
|---|---|
INSULATION, MEMBRANE, and other non-roof IfcCoveringTypeEnum values |
Map to nearest BoundaryType (cladding or flooring); insulation substance uses optional MAT-INS* or subsystem parent product |
No fitting enum on ConnectionPhysicalType |
IfcDuctFitting, IfcPipeFitting → network_other |
| No structural member class | IfcBeam, IfcColumn → ConnectionVirtual with connection_virtual_type: structural_joint |
| No stair/ramp class | IfcStair, IfcRamp → abstract PhysicalElement; enrich via classifications[] |
IfcCurtainWall |
Mapped to SeparatorWall (closest wall-based separator) |
IfcRoof |
Mapped to PhysicalElement (assembly container; roof faces are IfcSlab/IfcCovering parts) |
These are intentional pragmatic mappings pending schema extension.
Extending for a new source system¶
- Add a key under each relevant
source_system_overridesblock inpset_fallbacks(or per-entityfields.code_or_number). - Place tool-specific psets before shared IFC standard psets.
- Set
source_systemon ingest to match the override key (lowercase, e.g.solibriif adding QA tool exports). - Document the new overrides in this README.
Example:
source_system_overrides:
mytool:
- pset: MyTool_Identity
property: ElementCode
Adding a new IFC class¶
- Identify the nearest PBS class in
entity_physical_schema.yamlorentity_virtual_schema.yaml. - Add an
entities.IfcNewClassblock withcontent_kind,canonical_type, required type slots, and geometry. - Copy
fieldsandattributespatterns from a similar entity; only use slot names that exist on the target PBS class (plusEntitybase slots). - List applicable IFC relationships under
relations. - Add entity-specific pset fallbacks to
pset_fallbacksif standard lists are insufficient. - If the entity shares a template with others, add a
templates.*entry and reference it withinherits.
inherits and templates¶
Some entities declare inherits: IfcHvacEquipmentBase or inherits: IfcWall. The adapter merges the referenced templates.* or entities.* block before applying entity-specific overrides. Keys on the entity take precedence.
HVAC equipment sharing IfcHvacEquipmentBase: IfcPump, IfcFan, IfcCompressor, IfcBoiler, IfcChiller, IfcCoolingTower, IfcHeatExchanger.