SuperAPI AI Directory

ifc-syntax-express

General & other

View repository

Updated 10-15 22:18

About this skill

IFC Syntax : The EXPRESS Schema Language

Every IFC schema (IFC2x3, IFC4, IFC4.3) is written entirely in EXPRESS, the data modeling language standardized as ISO 10303-11:2004. EXPRESS is declarative : it describes what a valid population of data looks like, never behaviour or algorithms. This skill teaches how to read an EXPRESS declaration and how it maps to a serialized IFC instance. The EXPRESS schema is the single source of truth : the STEP physical file, ifcXML, and ifcJSON are all derived encodings of the same EXPRESS model.

Quick Reference

The three attribute kinds : the most important table

Kind Stored? Serialized in the STEP file? What it is
Explicit Yes Yes : a positional value An independently stored value, supplied in the file
DERIVE No No : slot holds * A value computed by an expression (:=)
INVERSE No No : occupies no slot at all A navigable back-reference, reconstructed by the reader

ALWAYS count only explicit attributes (across the full inheritance chain) when reading or writing a STEP instance. NEVER give a DERIVE or INVERSE attribute a value.

EXPRESS construct cheat-sheet

Construct Declares Example
TYPE name = base; END_TYPE; A defined type (a named, optionally constrained base type) TYPE IfcLengthMeasure = REAL; END_TYPE;
TYPE name = ENUMERATION OF (...); END_TYPE; A fixed list of named values IfcWallTypeEnum
TYPE name = SELECT (...); END_TYPE; A type union (one-of alternatives) IfcUnit
ENTITY name ... END_ENTITY; An entity type with attributes and inheritance IfcWall
RULE name FOR (...); ... END_RULE; A schema-level population constraint global rules
FUNCTION name(...) : T; ... END_FUNCTION; A computation used by DERIVE / WHERE IfcBaseAxis

STEP physical file markers (the EXPRESS-to-file mapping)

Marker in the file EXPRESS meaning
#42=IFCWALL(...) An instance ; keyword upper-case, #id file-local
$ An unset OPTIONAL explicit attribute
* A DERIVE (or re-declared) attribute slot ; computed, not stored
(absent) An INVERSE attribute : no slot exists in the parentheses
.STANDARD. .T. .F. .U. An enumeration, BOOLEAN, or LOGICAL value (dotted)
IFCLENGTHMEASURE(2.5) A SELECT-of-defined-type value (wrapped in the type name)
#84 A SELECT-of-entity value (a bare reference, no wrapper)
(0.,0.,0.) Any aggregate (LIST / SET / ARRAY / BAG : the wire syntax is the same)

The four aggregations

Aggregation Ordered Duplicates Bounds Notes
LIST [lo:hi] OF T Yes Allowed (unless OF UNIQUE) Optional, default [0:?] Indexable
SET [lo:hi] OF T No Never Optional Set semantics
ARRAY [lo:hi] OF T Yes Allowed (unless UNIQUE) Mandatory Only one that allows OPTIONAL holes
BAG [lo:hi] OF T No Allowed Optional Unordered multiset

? as the high bound means unbounded. LIST OF UNIQUE differs from SET only in that it is ordered.

The three equality tokens (NEVER confuse these)

  • = : value equality (deep, structural comparison).
  • :=: : instance equality (identity : same #id).
  • := : assignment ; used ONLY to give a DERIVE attribute its expression. It is not a comparison operator.

Decision Trees

Which attribute kind is this, and does it go in the file?

Where is the attribute declared in the ENTITY body?
|
+-- In the main attribute block (before DERIVE/INVERSE/WHERE)
|   --> EXPLICIT attribute. Serialized as a positional value.
|       If marked OPTIONAL and unset --> written as $
|
+-- Under the DERIVE keyword (has := and an expression)
|   --> DERIVE attribute. NEVER serialized as a value ; slot is *
|
+-- Under the INVERSE keyword (has a FOR clause)
    --> INVERSE attribute. NEVER serialized ; no slot exists at all.

Which TYPE construct is this?

TYPE name = ... END_TYPE;  what follows the "=" ?
|
+-- A base type / another defined type (REAL, INTEGER, IfcLengthMeasure, ...)
|   --> Defined type. A named alias, optionally narrowed by a WHERE rule.
|
+-- ENUMERATION OF (V1, V2, ..., USERDEFINED, NOTDEFINED)
|   --> Enumeration. A fixed list of dotted values.
|
+-- SELECT (A, B, C)
    --> Select (type union). An attribute typed by it holds ONE of A, B, C.
        This is NOT inheritance : the alternatives need not share a supertype.

ONEOF vs ANDOR (subtype constraint)

SUPERTYPE OF (...)  contains which operator?
|
+-- ONEOF (A, B, C)  --> a concrete instance is EXACTLY ONE of A, B, or C.
|                        Mutually exclusive. The overwhelmingly common IFC case.
|
+-- A ANDOR B        --> an instance may be A alone, B alone, OR A and B together.
                         Multiple inheritance. IFC uses ANDOR rarely.

Can I instantiate this entity?

Does the ENTITY declaration say ABSTRACT SUPERTYPE?
|
+-- YES --> NEVER instantiate it. IfcRoot, IfcProduct, IfcElement,
|           IfcObjectDefinition exist only as supertypes. No #id=IFCELEMENT(...).
|
+-- NO  --> It is concrete and instantiable (IfcWall, IfcDoor, IfcCartesianPoint).
            A concrete entity may still be a SUPERTYPE OF other entities.

Patterns

Pattern : Read an ENTITY declaration top to bottom

An ENTITY ... END_ENTITY; block has a fixed order of sections :

ENTITY IfcRoot
 ABSTRACT SUPERTYPE OF (ONEOF
    (IfcObjectDefinition, IfcPropertyDefinition, IfcRelationship));
    GlobalId : IfcGloballyUniqueId;
    OwnerHistory : OPTIONAL IfcOwnerHistory;
    Name : OPTIONAL IfcLabel;
    Description : OPTIONAL IfcText;
 UNIQUE
    UR1 : GlobalId;
END_ENTITY;

ALWAYS read in this order :

  1. ABSTRACT (if present) : the entity cannot be instantiated.
  2. SUPERTYPE OF (...) : its direct subtypes, with ONEOF or ANDOR.
  3. SUBTYPE OF (...) : its direct supertype(s). Absent on a root entity.
  4. The explicit attribute block : independently stored values, in declared order.
  5. DERIVE (if present) : computed attributes.
  6. INVERSE (if present) : back-references.
  7. WHERE (if present) : per-instance rules.
  8. UNIQUE (if present) : per-population uniqueness rules.

A subtype inherits every attribute of every supertype. A serialized IfcWall (chain IfcRoot to IfcObjectDefinition to IfcObject to IfcProduct to IfcElement to IfcBuiltElement to IfcWall) carries every explicit attribute of all seven levels, in supertype-first order.

IfcBuiltElement is the IFC4.3 name. In IFC2x3 and IFC4 the equivalent supertype is IfcBuildingElement ; IFC4.3 renamed IfcBuildingElement to IfcBuiltElement. See ifc-core-entity-hierarchy.

Pattern : Treat the three attribute kinds correctly

ALWAYS check which keyword block an attribute sits under before reasoning about a file.

  • Explicit attributes are the only ones that appear as positional values. The number of values inside the parentheses MUST equal the count of explicit attributes across the full inheritance chain.
  • DERIVE attributes (introduced with := and an expression, for example IfcDirection.Dim := HIINDEX(DirectionRatios);) are recomputed by every reader. Their positional slot holds *, never a value.
  • INVERSE attributes (which always have a FOR clause, for example IfcProduct.ReferencedBy : SET [0:?] OF IfcRelAssignsToProduct FOR RelatingProduct) occupy no slot at all. The reader rebuilds them by indexing forward #id references. This is the foundation of the IFC objectified-relationship pattern.

Pattern : Read the INVERSE FOR clause

ReferencedBy : SET [0:?] OF IfcRelAssignsToProduct FOR RelatingProduct reads : "the set of every IfcRelAssignsToProduct instance whose RelatingProduct explicit attribute points at this instance." The FOR names the explicit attribute on the other entity that this INVERSE mirrors. The cardinality (SET [0:?], SET [0:1], ...) constrains how many back-links may exist. See ifc-core-relationships.

Pattern : Apply the WHERE / UNIQUE / RULE scope correctly

The three constraint mechanisms differ in scope :

  • A WHERE rule constrains one instance. A named boolean expression that MUST evaluate TRUE for every instance. On a defined type, SELF is the value (IfcPositiveLengthMeasure.WR1 : SELF > 0.;) ; on an entity, SELF is the instance.
  • A UNIQUE rule constrains across the whole population of one entity type. IfcRoot.UR1 : GlobalId; forbids two IfcRoot instances from sharing a GlobalId. A UNIQUE rule may list several attributes for a compound key.
  • A global RULE constrains populations across entity types. It is declared at schema level, not on any entity, and can range over an entire population. An entity WHERE rule cannot see other instances ; a global RULE can.

NEVER read a WHERE rule, RULE, or function as application behaviour. They are constraints and computations, never algorithms with side effects.

Pattern : Read the SELF backslash supertype path

Inside a WHERE rule or DERIVE expression, SELF\Supertype.Attribute names an attribute inherited from a supertype. The backslash \ is the supertype-cast operator : it narrows the view of SELF to a named supertype.

DimIs3D : SELF\IfcCartesianTransformationOperator.Dim = 3; reads "this instance, viewed as its supertype IfcCartesianTransformationOperator, its Dim attribute." The qualifier is required because EXPRESS allows an attribute name to be re-declared in a subtype. ALWAYS expect SELF\... whenever a rule reaches up the inheritance chain.

Pattern : Read the built-in functions in WHERE rules

The functions that actually appear in IFC WHERE rules :

  • EXISTS(v) : TRUE if v is set. The standard guard for OPTIONAL attributes.
  • SIZEOF(agg) : element count of an aggregate.
  • TYPEOF(v) : the set of type-name strings of v ; used with IN, for example 'IFC4X3.IFCWALL' IN TYPEOF(x). The type-name string is schema-qualified, upper-case.
  • HIINDEX(agg) / LOINDEX(agg) : the actual high / low index of a populated aggregate. Distinct from HIBOUND / LOBOUND, which return the declared bounds.
  • QUERY(x <* agg | condition) : iterate-and-filter. <* binds x to each element ; returns the elements where the filter is TRUE. Almost always wrapped in SIZEOF(...).
  • NVL(v, default) : returns v if set, otherwise default.
  • USEDIN(v, 'Schema.Entity.Attribute') : the instances referencing v through that role. The functional counterpart of an INVERSE attribute.

See references/methods.md for the full ISO 10303-11 function library.

Pattern : Honour the USERDEFINED / NOTDEFINED enumeration convention

Every IFC predefined-type enumeration ends with USERDEFINED and NOTDEFINED. When an instance's PredefinedType is .USERDEFINED., the paired free-text attribute (usually ObjectType, inherited from IfcObject) MUST carry the actual type name. This pairing is enforced by a WHERE rule on the entity. ALWAYS set the paired attribute when using USERDEFINED. See ifc-syntax-data-types.

Reference Links

  • references/methods.md : the full EXPRESS construct reference : TYPE / ENUMERATION / SELECT / ENTITY grammar, the three attribute kinds, WHERE / UNIQUE / RULE, the four aggregations with BNF, the built-in function library, operators, and the complete EXPRESS-to-STEP mapping rules.
  • references/examples.md : verbatim, source-verified EXPRESS snippets from IFC4.3 and IFC4 entity pages, each explained, plus the matching STEP serialization.
  • references/anti-patterns.md : the twelve common EXPRESS misreadings, each with the reason it corrupts a file or a reading.

Official sources

Related skills

  • ifc-syntax-data-types : the IFC resource-layer value-type system built on EXPRESS defined types, selects, and enumerations.
  • ifc-core-data-model : the four-layer schema architecture written in EXPRESS.
  • ifc-syntax-step-physical-file : the STEP physical file (ISO 10303-21) encoding.
  • ifc-core-entity-hierarchy : the IFC inheritance lattice and the IfcBuildingElement to IfcBuiltElement rename.
  • ifc-core-relationships : the objectified-relationship pattern built on INVERSE.