Fast native IFC parsing, data extraction, and geometric analytics
Project description
ifcfast
Fast native IFC parsing, data extraction and geometric analytics. Python
on top, Rust underneath, no ifcopenshell.open() on the hot path.
Aimed at the "open an IFC, get the data out, run QTO / quality
queries" workflow. Tier-1 parse is byte-identical to ifcopenshell and
~20-27× faster on production files.
ifcfastwas extracted on 2026-05-13 from theEdvardGK/ifc-workbenchscratch repo. Seedocs/history/origin.mdfor the trail back and what was renamed.
What it gives you
| layer | format | typical latency on 200 MB IFC |
|---|---|---|
| Products (GUID, type, name, storey, parent, tag) | dict of parallel lists | tier-1 cold: 0.5–2 s |
| Property sets | long-format pandas.DataFrame |
137 ms |
| Element quantities | long-format pandas.DataFrame |
90 ms |
| Materials (incl. layer sets) | long-format pandas.DataFrame |
27 ms |
| Classifications | long-format pandas.DataFrame |
17 ms |
| All data layers (shared scan) | bundle | 1.3 s |
| Triangle meshes (extrusion / mapped / face sets / BREP) | OBJ / glTF / CSV | 2.6 s |
| Placement-vs-mesh drift report | pandas.DataFrame |
322 ms |
| Parquet cache (all of the above) | parquet | 65 ms hot reload |
End-to-end cold parse of a 200 MB IFC: under 5 s. Hot reload from cache: under 100 ms. Memory peak: under 1 GB resident (mmap-based).
Audited at 234,144 products across 5 authoring tools (Tekla,
Archicad, Revit IFC4, Revit IFC2X3, MagiCAD, BSProLib) with byte-level
parity vs ifcopenshell. See
docs/history/audit/.
Install
Needs Rust 1.95+ and Python 3.10+.
pip install maturin
maturin develop --release # builds the Rust extension, ~30 s first time
For production: maturin build --release produces a wheel.
Quick start
import ifcfast
m = ifcfast.open("model.ifc")
print(len(m), "products,", len(m.storeys), "storeys")
print(m.authoring_app, "→", m.schema)
walls = list(m.filter(entity="IfcWall"))
# Long-format data layers (pandas DataFrames, loaded lazily).
m.psets # 63k+ rows on a 200 MB Archicad file
m.quantities # author-supplied Qto_*BaseQuantities
m.materials # (guid, role, layer, name, thickness, category)
m.classifications # NS 3451 / Uniformat / OmniClass references
m.drift # placement-vs-mesh drift report
# Standard QTO query — external walls.
external_walls = m.psets[
(m.psets.pset_name == "Pset_WallCommon")
& (m.psets.prop_name == "IsExternal")
& (m.psets.value == "True")
].guid.unique()
# Quality gate — placement bugs.
suspect = m.drift[m.drift.drift_severity == "error"]
The same model can be re-opened cheaply — the second ifcfast.open(...)
returns from the parquet cache in tens of milliseconds.
CLI
ifcfast index model.ifc # tier-1 parse + counts
ifcfast extract model.ifc # extract data layers (writes cache)
ifcfast drift model.ifc --top 20 # placement / mesh drift report
ifcfast cache model.ifc # inspect cache for a file
The Rust binary ifcfast-mesh writes OBJ / glTF / CSV directly:
cargo build --release --bin ifcfast-mesh --no-default-features --features mesh
./target/release/ifcfast-mesh model.ifc model.glb
Cache
Parquet files live under ~/.cache/ifcfast/<cache_key>/, where
cache_key is sha256(file_size + first 4 MB + last 4 MB) truncated.
Any edit to the IFC invalidates the entry automatically.
Override with the IFCFAST_CACHE environment variable, e.g.
IFCFAST_CACHE=/srv/cache ifcfast extract model.ifc.
Disk footprint on a 200 MB Archicad IFC: 2.4 MB total zstd-compressed.
Data schemas
All extractors return long-format (one row per fact, no nested fields). Easy to join, easy to filter, easy to flatten to Excel.
Missing values: string columns use pandas StringDtype with nan
as the NULL sentinel (chosen for memory and pyarrow round-trip).
Cells corresponding to a STEP $ field hold float('nan'), not
Python None. Use .isna() to test, not == None or is None:
m.classifications[m.classifications.identification.isna()] # correct
m.classifications[m.classifications.identification == None] # always False
[r for r in m.classifications.itertuples() if r.identification is None] # always False
If you're cross-checking against ifcopenshell (which returns None),
normalise NaN→None on the comparison side.
psets
| column | type | description |
|---|---|---|
guid |
str | IfcProduct.GlobalId |
pset_name |
str | e.g. Pset_WallCommon |
prop_name |
str | e.g. IsExternal |
value |
str | None | booleans normalised to True / False / UNKNOWN |
value_type |
str | None | IfcBoolean, IfcText, IfcReal, … |
quantities
| column | type | description |
|---|---|---|
guid |
str | IfcProduct.GlobalId |
qto_name |
str | e.g. Qto_WallBaseQuantities |
quantity_name |
str | e.g. NetVolume, GrossArea, Length |
value |
str | None | numeric value as string |
quantity_type |
str | Area / Length / Volume / Count / Weight / Time |
unit_step_id |
int | None | usually None (project default applies) |
materials
| column | type | description |
|---|---|---|
guid |
str | IfcProduct.GlobalId |
role |
str | direct / list / layer / unknown |
layer_index |
int | 0-based for layered materials, -1 otherwise |
material_name |
str | None | material label |
layer_thickness_mm |
float | None | only set for role="layer" |
category |
str | None | IFC4 only |
classifications
| column | type | description |
|---|---|---|
guid |
str | IfcProduct.GlobalId |
system_name |
str | None | NS 3451, Uniformat II, OmniClass |
edition |
str | None | e.g. 2022 |
identification |
str | None | the actual code |
name |
str | None | human label |
location |
str | None | URI to spec (rarely populated) |
source |
str | None | publisher |
drift
| column | type | description |
|---|---|---|
guid, entity, source |
str | identification |
triangle_count, surface_area, volume_abs |
int / float | geometric stats |
placement_x/y/z |
float | what IfcLocalPlacement says |
centroid_x/y/z |
float | where the mesh AABB centre actually is |
drift_distance |
float | Euclidean distance, mm |
max_extent |
float | largest AABB dimension |
drift_ratio |
float | drift_distance / max_extent |
drift_severity |
str | ok / warn / error |
Severity rule: ok when drift_ratio ≤ 2.0 or drift_distance < 10 mm; error when drift_ratio > 10.0 and drift_distance > 10 mm.
A 100 m wall placed at one end has ratio 0.5 (legitimate). A 50 mm sensor 100 m from its placement has ratio 2000 (clear authoring bug).
Federated floor synthesis
Multi-discipline projects have the same physical floor named differently
by ARK / RIB / RIV / RIE authors. ifcfast.federated_floors clusters by
elevation across discipline models and applies a project-supplied YAML
rule.
# examples/projects/lbk-building-c.yaml
prefix: "C - "
overrides:
Plan U1: Hav
C - U1: Hav
idempotent_labels: [Hav]
apply_drop_leading_zero: true
The module is project-agnostic — project tables live in user config.
Architecture in two paragraphs
The Rust core (crates/core) does one byte-level pass over the IFC's
DATA section using a string-aware STEP tokenizer (memchr-accelerated).
That pass builds an EntityTable — a step_id → byte_range map of
every entity in the file. Each PyO3 entry point (index_ifc,
extract_psets, etc.) walks the table once, dispatching on entity type
and extracting only the fields that layer needs.
The Python cache (ifcfast.cache) writes each extractor's output as
zstd-compressed parquet, keyed by sha256(size + 4 MB head + 4 MB tail)
so any IFC edit invalidates automatically. Hot reads are pure
pandas / pyarrow — no Rust call needed. There is no ifcopenshell.open()
anywhere in the data path; ifcopenshell is an optional dev dep used
only for cross-checking parity in tests.
What it doesn't do
- Write or modify IFCs. Read-only by construction.
- Schema validation. Trusts the file's syntax. Use bsi-validator for conformance.
- Tessellate
IfcBooleanClippingResult(walls with openings render without cutouts — gross volume correct, net volume not). - NURBS / advanced BREP geometry. ~0.5% of elements in typical exports.
- Property variants beyond
IfcPropertySingleValue—IfcPropertyEnumeratedValue,IfcPropertyListValue,IfcPropertyBoundedValue,IfcComplexPropertyare skipped. Covers ~90% of psets seen on Revit / Archicad / Tekla / MagiCAD exports.
Layout
crates/core/ Rust extension (PyO3) — tokenizer, indexer, extractors, mesh
src/
lib.rs PyO3 entry points
lexer.rs STEP tokenizer
indexer.rs tier-1 product / storey index
entity_table.rs step_id → byte range lookup
extractors/ psets, quantities, materials, classifications
mesh/ extrusion, mapped, face sets, BREP, glTF writer
bin/ ifcfast-bench, ifcfast-mesh CLIs
python/ifcfast/ Public Python API
__init__.py ifcfast.open(), Model, header, classify
header.py STEP header reader (tier-0)
model.py Model class + native tier-1 driver
cache.py parquet cache for index + data layers
classify.py element-mode policy (count / measure / linear / skip)
federated_floors.py multi-discipline floor synthesiser
cli.py ifcfast CLI
docs/history/ origin doc + audit issues from ifc-workbench
examples/projects/ project YAMLs for federated_floors
tests/ pytest suite
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ifcfast-0.1.0a2.tar.gz.
File metadata
- Download URL: ifcfast-0.1.0a2.tar.gz
- Upload date:
- Size: 76.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
61bcb60f7ac54e96508d7e223157984d47feb419816460a38e133496f0905207
|
|
| MD5 |
bfca34ac5b648e1ac882daec28af03e3
|
|
| BLAKE2b-256 |
e80c2a2dfdfbd6b98885733439b98f21db06faeb67e14f7bcfdf85d69fccd2c3
|
Provenance
The following attestation bundles were made for ifcfast-0.1.0a2.tar.gz:
Publisher:
release.yml on EdvardGK/ifcfast
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ifcfast-0.1.0a2.tar.gz -
Subject digest:
61bcb60f7ac54e96508d7e223157984d47feb419816460a38e133496f0905207 - Sigstore transparency entry: 1538193501
- Sigstore integration time:
-
Permalink:
EdvardGK/ifcfast@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Branch / Tag:
refs/tags/v0.1.0a2 - Owner: https://github.com/EdvardGK
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Trigger Event:
push
-
Statement type:
File details
Details for the file ifcfast-0.1.0a2-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: ifcfast-0.1.0a2-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 335.4 kB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
17770f9c2b84997f3b33ccc1fb5d42a3a9c760e3036f9b09af7c61dc05da702e
|
|
| MD5 |
3f7cb5c00f2c88d322a3edde9a6d5e2e
|
|
| BLAKE2b-256 |
ff55cf11bfaa77fbcca7d5bc54d0a2422c6593d6926eba5e3a3eb579de1a69fc
|
Provenance
The following attestation bundles were made for ifcfast-0.1.0a2-cp310-abi3-win_amd64.whl:
Publisher:
release.yml on EdvardGK/ifcfast
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ifcfast-0.1.0a2-cp310-abi3-win_amd64.whl -
Subject digest:
17770f9c2b84997f3b33ccc1fb5d42a3a9c760e3036f9b09af7c61dc05da702e - Sigstore transparency entry: 1538193992
- Sigstore integration time:
-
Permalink:
EdvardGK/ifcfast@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Branch / Tag:
refs/tags/v0.1.0a2 - Owner: https://github.com/EdvardGK
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Trigger Event:
push
-
Statement type:
File details
Details for the file ifcfast-0.1.0a2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: ifcfast-0.1.0a2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 413.5 kB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9cd8682a6d876a82f06ea083c616a7c96ff17245e83a82f077a4e73940627110
|
|
| MD5 |
9e755e1215aeea26252e95b19434207a
|
|
| BLAKE2b-256 |
1ab0e93283ba5b90dc8ee6da603bd55d97d1ffdaa0484a3362acaa43b60854cc
|
Provenance
The following attestation bundles were made for ifcfast-0.1.0a2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on EdvardGK/ifcfast
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ifcfast-0.1.0a2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
9cd8682a6d876a82f06ea083c616a7c96ff17245e83a82f077a4e73940627110 - Sigstore transparency entry: 1538194542
- Sigstore integration time:
-
Permalink:
EdvardGK/ifcfast@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Branch / Tag:
refs/tags/v0.1.0a2 - Owner: https://github.com/EdvardGK
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Trigger Event:
push
-
Statement type:
File details
Details for the file ifcfast-0.1.0a2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: ifcfast-0.1.0a2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 392.4 kB
- Tags: CPython 3.10+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c9b29031505db56a6c029789b8e32365be71dd9a9ef407954454aa060c3599f
|
|
| MD5 |
0f3bdcdd112a98779f618a308bc4c032
|
|
| BLAKE2b-256 |
63b0e88c7d2237def0e83d83fe15bbce9669e91ffd8ac0ddf515207df0ea3da4
|
Provenance
The following attestation bundles were made for ifcfast-0.1.0a2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
release.yml on EdvardGK/ifcfast
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ifcfast-0.1.0a2-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
1c9b29031505db56a6c029789b8e32365be71dd9a9ef407954454aa060c3599f - Sigstore transparency entry: 1538193648
- Sigstore integration time:
-
Permalink:
EdvardGK/ifcfast@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Branch / Tag:
refs/tags/v0.1.0a2 - Owner: https://github.com/EdvardGK
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Trigger Event:
push
-
Statement type:
File details
Details for the file ifcfast-0.1.0a2-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: ifcfast-0.1.0a2-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 373.6 kB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9e8a6c0ec807013a8041012d2ab8e5a6f8afb7b3ffca884ae61ce0c73ec05c0f
|
|
| MD5 |
d0f4a267371cddc20b4232cbecd7216c
|
|
| BLAKE2b-256 |
d9350390cfda5f2bda60663ff7b186c2dad4f6c976e159a210acb58749acbb84
|
Provenance
The following attestation bundles were made for ifcfast-0.1.0a2-cp310-abi3-macosx_11_0_arm64.whl:
Publisher:
release.yml on EdvardGK/ifcfast
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ifcfast-0.1.0a2-cp310-abi3-macosx_11_0_arm64.whl -
Subject digest:
9e8a6c0ec807013a8041012d2ab8e5a6f8afb7b3ffca884ae61ce0c73ec05c0f - Sigstore transparency entry: 1538194259
- Sigstore integration time:
-
Permalink:
EdvardGK/ifcfast@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Branch / Tag:
refs/tags/v0.1.0a2 - Owner: https://github.com/EdvardGK
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Trigger Event:
push
-
Statement type:
File details
Details for the file ifcfast-0.1.0a2-cp310-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: ifcfast-0.1.0a2-cp310-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 390.5 kB
- Tags: CPython 3.10+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
73d766e67a1212b7725db4676305d5156fcf0e148cf0b127f667a406b7b885c6
|
|
| MD5 |
81da060cfb8f6a8910a09617a262ee74
|
|
| BLAKE2b-256 |
bae3394f08c49848d4a143f6630959521aaab313e9053245699f164dace56745
|
Provenance
The following attestation bundles were made for ifcfast-0.1.0a2-cp310-abi3-macosx_10_12_x86_64.whl:
Publisher:
release.yml on EdvardGK/ifcfast
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ifcfast-0.1.0a2-cp310-abi3-macosx_10_12_x86_64.whl -
Subject digest:
73d766e67a1212b7725db4676305d5156fcf0e148cf0b127f667a406b7b885c6 - Sigstore transparency entry: 1538193801
- Sigstore integration time:
-
Permalink:
EdvardGK/ifcfast@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Branch / Tag:
refs/tags/v0.1.0a2 - Owner: https://github.com/EdvardGK
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@cc54a407b6ba3663bbba9352eec1772771c57f7d -
Trigger Event:
push
-
Statement type: