From eba89c8e4b1d53ea377dacc80bd6bb7cf7437bb8 Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 16:56:48 -0500 Subject: [PATCH 01/12] chore(probes): a census of every BuiltInCategory's placed instances on every release, scored against Revit's Tags (#1261) (RE-319) --- .../examples/probe_re319_category_census.rs | 173 ++++++++++++++++++ tools/re/category_census_vs_ifc.py | 100 ++++++++++ 2 files changed, 273 insertions(+) create mode 100644 probes/examples/probe_re319_category_census.rs create mode 100644 tools/re/category_census_vs_ifc.py diff --git a/probes/examples/probe_re319_category_census.rs b/probes/examples/probe_re319_category_census.rs new file mode 100644 index 000000000..a17aaac52 --- /dev/null +++ b/probes/examples/probe_re319_category_census.rs @@ -0,0 +1,173 @@ +//! RE-319 probe: the placed instances of every `BuiltInCategory` a file's +//! partition records hold, recovered or not, on every release the exporter +//! reads (#1261). +//! +//! FACT (to be measured): on each release, the RE-21 instance rule (a +//! declared or enclosing ElementId, no container reference, the placed +//! kind) selects, in the categories of conduits (-2008132), conduit +//! fittings (-2008128), cable trays (-2008130), cable tray fittings +//! (-2008126) and gutters (-2001391), ElementIds that Revit's own export +//! holds as `Tag`, and no ElementId it does not. +//! +//! Reads a 2008 to 2023 file through `partition_element_records_2023:: +//! scan_records` and a 2024 to 2027 file through the product sweep with +//! every category the file's marker frames carry, so a category that is not +//! in `RECOVERED_CATEGORIES` shows too. Prints, per category, three lines +//! that `tools/re/category_census_vs_ifc.py` scores against an export: +//! +//! - `any `: every ElementId a decoded frame of the +//! category carries (symbols and container members included); +//! - `rule `: those that pass the instance rule; +//! - `category `: those with a 3D body, in the +//! export phase and not in a non-primary design option, which is what the +//! exporter writes. +//! +//! ```bash +//! cargo run --profile ci -p rvt-probes --example probe_re319_category_census -- model.rvt +//! ``` + +use rvt::RevitFile; +use rvt::research::partition_element_records::{self as per, PartitionElementRecord}; +use rvt::research::partition_element_records_2023 as per32; +use std::collections::{BTreeMap, BTreeSet}; + +fn i64_at(buf: &[u8], at: usize) -> Option { + let end = at.checked_add(8)?; + buf.get(at..end) + .map(|b| i64::from_le_bytes(b.try_into().expect("8 bytes"))) +} + +/// Every frame of the file's marker in the `BuiltInCategory` band, decoded +/// for any category: a 2024 to 2027 file's frames with a declared id or an +/// enclosing record's. +fn records_2024(rf: &mut RevitFile, release: u32) -> Vec { + let Some(marker) = per::file_bbox_marker(rf, release) else { + println!("the release gives no record marker"); + return Vec::new(); + }; + let Ok(table) = rvt::elem_table::parse_records(rf) else { + return Vec::new(); + }; + let declared = rvt::elem_table::declared_ids(&table); + let assigned = per::compute_second_prologue_ids(rf); + let none = BTreeMap::new(); + let mut out = Vec::new(); + for stream in rf.partition_stream_names() { + let Ok(inflated) = rf.inflated_partition(&stream) else { + continue; + }; + let buf = inflated.bytes(); + let mut categories: BTreeSet = BTreeSet::new(); + for hit in memchr::memmem::find_iter(buf, &marker) { + let Some(start) = hit.checked_sub(per::BBOX_MARKER_OFFSET) else { + continue; + }; + if let Some(category) = i64_at(buf, start + per::CATEGORY_OFFSET) { + if (per::BUILTIN_CATEGORY_MIN..=per::BUILTIN_CATEGORY_MAX).contains(&category) { + categories.insert(category); + } + } + } + let list: Vec = categories.into_iter().collect(); + for records in per::find_categories_records_assigned( + &stream, + buf, + &list, + &declared, + &marker, + assigned.get(&stream).unwrap_or(&none), + ) { + out.extend(records); + } + } + out +} + +fn name_of(category: i64) -> String { + per::builtin_category_name(category) + .map(|name| name.replace(' ', "_")) + .unwrap_or_else(|| "unnamed".to_string()) +} + +fn print_ids(kind: &str, category: i64, ids: &BTreeSet) { + let list: Vec = ids.iter().map(u32::to_string).collect(); + println!( + "{kind} {category} {} {} {}", + name_of(category), + ids.len(), + list.join(",") + ); +} + +fn main() -> Result<(), Box> { + let path = std::env::args() + .skip(1) + .find(|arg| !arg.starts_with("--")) + .ok_or("usage: probe_re319_category_census ")?; + let mut rf = RevitFile::open(&path)?; + let saved = rf.basic_file_info()?.version; + let release = rf.layout_release()?; + println!("release saved {saved} layout {release}"); + let records: Vec = if per32::is_32bit_release(release) { + per32::scan_records(&mut rf, release) + } else if per::supports_revit_version(release) { + records_2024(&mut rf, release) + } else { + println!("a release whose records are not read: nothing to measure"); + return Ok(()); + }; + let filtered = per32::applies_export_filters(release) || per::supports_revit_version(release); + let (phases, options) = if filtered { + (Some(rf.phase_filter()), Some(rf.design_options())) + } else { + (None, None) + }; + println!("records {}", records.len()); + + let mut any: BTreeMap> = BTreeMap::new(); + let mut rule: BTreeMap> = BTreeMap::new(); + let mut selected: BTreeMap> = BTreeMap::new(); + let mut leftout = (0usize, 0usize, 0usize); + for record in &records { + let category = record.builtin_category; + any.entry(category).or_default().insert(record.element_id); + if !record.is_exported_instance() { + continue; + } + rule.entry(category).or_default().insert(record.element_id); + if !record.has_volume() { + leftout.0 += 1; + continue; + } + if options.as_ref().is_some_and(|o| o.excludes(record)) { + leftout.1 += 1; + continue; + } + if phases.as_ref().is_some_and(|p| p.excludes(record)) { + leftout.2 += 1; + continue; + } + selected + .entry(category) + .or_default() + .insert(record.element_id); + } + println!( + "placed instances left out: {} without volume, {} by design option, {} by phase", + leftout.0, leftout.1, leftout.2 + ); + for category in any.keys() { + print_ids("any", *category, &any[category]); + print_ids( + "rule", + *category, + rule.get(category).unwrap_or(&BTreeSet::new()), + ); + print_ids( + "category", + *category, + selected.get(category).unwrap_or(&BTreeSet::new()), + ); + } + Ok(()) +} diff --git a/tools/re/category_census_vs_ifc.py b/tools/re/category_census_vs_ifc.py new file mode 100644 index 000000000..c992108ae --- /dev/null +++ b/tools/re/category_census_vs_ifc.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +"""Score the placed instances of every BuiltInCategory against a Revit IFC export's Tags (RE-319). + +Reads the `any`, `rule` and `category` lines that +`probes/examples/probe_re319_category_census.rs` prints, one ` ` +each per category, and compares the ElementIds with the numeric `Tag` of every element of +the export, openings and virtual elements left out. For each category it prints the +ElementIds of any decoded frame, of the placed instances (the RE-21 rule) and of the +instances rvt-rs's exporter writes (a 3D body, in the export phase, in a primary design +option), how many of each the export holds, and the IFC classes they land on. Then the +export's elements that no written instance covers, by class and by the category whose +frames hold their id. + +Usage: + + python3 tools/re/category_census_vs_ifc.py [--list] + +`--list` is what Measure passes to a probe's scorer; it also lists the first ElementIds of each +category that the export lacks. +""" + +import collections +import sys + +import ifcopenshell + + +def parse(path): + """kind -> category id -> (name, set of ElementIds).""" + found = {"any": {}, "rule": {}, "category": {}} + for line in open(path): + kind = line.split(" ", 1)[0] + if kind not in found: + continue + _, category, name, _count, ids = line.rstrip("\n").split(" ", 4) + found[kind][int(category)] = (name, {int(i) for i in ids.split(",") if i}) + return found + + +def main(argv): + listing = "--list" in argv + argv = [arg for arg in argv if arg != "--list"] + if len(argv) != 3: + print(__doc__, file=sys.stderr) + return 2 + found = parse(argv[1]) + tags = {} + # The file stays bound while its instances are in use: IfcOpenShell 0.9 + # frees a file its instances outlive (#773). + model = ifcopenshell.open(argv[2]) + for element in model.by_type("IfcElement"): + if element.is_a("IfcOpeningElement") or element.is_a("IfcVirtualElement"): + continue + tag = getattr(element, "Tag", None) + if tag and tag.isdigit(): + tags[int(tag)] = element.is_a() + print(f"export schema {model.schema}; elements with a numeric Tag: {len(tags)}") + written = set() + for _, (_, ids) in found["category"].items(): + written |= ids + print( + f"written instances {len(written)}; in the export {len(written & set(tags))}, " + f"not in it {len(written - set(tags))}, export elements not written {len(set(tags) - written)}" + ) + print("category | name | any | rule (in export) | written (in export, not in export) | export classes of the written") + for category in sorted(found["any"], reverse=True): + name, any_ids = found["any"][category] + _, rule_ids = found["rule"].get(category, (name, set())) + _, wrote = found["category"].get(category, (name, set())) + classes = collections.Counter(tags[i] for i in wrote if i in tags) + shown = ", ".join(f"{cls} {n}" for cls, n in sorted(classes.items())) + print( + f"{category} | {name} | {len(any_ids)} | {len(rule_ids)} ({len(rule_ids & set(tags))}) | " + f"{len(wrote)} ({len(wrote & set(tags))}, {len(wrote - set(tags))}) | {shown}" + ) + if listing and wrote - set(tags): + print(" not in the export:", ",".join(str(i) for i in sorted(wrote - set(tags))[:20])) + missed = collections.defaultdict(collections.Counter) + for tag, cls in tags.items(): + if tag in written: + continue + holders = [name for _, (name, ids) in found["any"].items() if tag in ids] + rule_holders = [name for _, (name, ids) in found["rule"].items() if tag in ids] + if rule_holders: + where = "rule:" + "/".join(sorted(set(rule_holders))) + elif holders: + where = "frame:" + "/".join(sorted(set(holders))) + else: + where = "no frame" + missed[cls][where] += 1 + print("export elements not written, by IFC class and where rvt-rs holds their id:") + for cls in sorted(missed): + total = sum(missed[cls].values()) + parts = ", ".join(f"{where} {n}" for where, n in sorted(missed[cls].items())) + print(f" {cls}: {total} ({parts})") + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv)) From 5ed66c5879868cc7e35723706c54e28c3afd7f0b Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 17:19:15 -0500 Subject: [PATCH 02/12] chore(tools): the category census scorer names the category Revit's export gives each instance set (#1261) (RE-319) --- tools/re/category_census_vs_ifc.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/re/category_census_vs_ifc.py b/tools/re/category_census_vs_ifc.py index c992108ae..f54446940 100644 --- a/tools/re/category_census_vs_ifc.py +++ b/tools/re/category_census_vs_ifc.py @@ -23,6 +23,7 @@ import sys import ifcopenshell +import ifcopenshell.util.element def parse(path): @@ -37,6 +38,12 @@ def parse(path): return found +def category_name(element): + """The category an export gives an element (`Other.Category`), or "-".""" + value = ifcopenshell.util.element.get_psets(element).get("Other", {}).get("Category") + return str(value) if value else "-" + + def main(argv): listing = "--list" in argv argv = [arg for arg in argv if arg != "--list"] @@ -45,6 +52,7 @@ def main(argv): return 2 found = parse(argv[1]) tags = {} + elements = {} # The file stays bound while its instances are in use: IfcOpenShell 0.9 # frees a file its instances outlive (#773). model = ifcopenshell.open(argv[2]) @@ -54,6 +62,7 @@ def main(argv): tag = getattr(element, "Tag", None) if tag and tag.isdigit(): tags[int(tag)] = element.is_a() + elements[int(tag)] = element print(f"export schema {model.schema}; elements with a numeric Tag: {len(tags)}") written = set() for _, (_, ids) in found["category"].items(): @@ -62,13 +71,17 @@ def main(argv): f"written instances {len(written)}; in the export {len(written & set(tags))}, " f"not in it {len(written - set(tags))}, export elements not written {len(set(tags) - written)}" ) - print("category | name | any | rule (in export) | written (in export, not in export) | export classes of the written") + print("category | name | any | rule (in export) | written (in export, not in export) | export classes of the written, categories of the instances") for category in sorted(found["any"], reverse=True): name, any_ids = found["any"][category] _, rule_ids = found["rule"].get(category, (name, set())) _, wrote = found["category"].get(category, (name, set())) classes = collections.Counter(tags[i] for i in wrote if i in tags) shown = ", ".join(f"{cls} {n}" for cls, n in sorted(classes.items())) + names = collections.Counter( + category_name(elements[i]) for i in rule_ids if i in tags + ) + shown += "".join(f" | category {name!r} {n}" for name, n in sorted(names.items())) print( f"{category} | {name} | {len(any_ids)} | {len(rule_ids)} ({len(rule_ids & set(tags))}) | " f"{len(wrote)} ({len(wrote & set(tags))}, {len(wrote - set(tags))}) | {shown}" From 9ade4f78e78207ab972898f90bb93e4813fad6d7 Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 17:24:15 -0500 Subject: [PATCH 03/12] feat(elements): conduits, conduit fittings and gutters from their element records (#1261) (RE-319) --- src/bin/rvt_ifc.rs | 3 ++ src/ifc/category_map.rs | 23 ++++++++++++++ src/ifc/step_writer.rs | 4 +-- src/research/partition_element_records.rs | 37 +++++++++++++++++++++-- viewer/src/main.ts | 3 ++ 5 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/bin/rvt_ifc.rs b/src/bin/rvt_ifc.rs index 8ae6eed3c..cdd7c9db5 100644 --- a/src/bin/rvt_ifc.rs +++ b/src/bin/rvt_ifc.rs @@ -975,6 +975,8 @@ fn ifc_type_display(upper: &str) -> String { "IfcAlarm", "IfcBeam", "IfcBuildingElementProxy", + "IfcCableCarrierFitting", + "IfcCableCarrierSegment", "IfcColumn", "IfcCovering", "IfcCurtainWall", @@ -983,6 +985,7 @@ fn ifc_type_display(upper: &str) -> String { "IfcDuctSegment", "IfcElectricAppliance", "IfcFlowController", + "IfcFlowSegment", "IfcFooting", "IfcFurniture", "IfcLightFixture", diff --git a/src/ifc/category_map.rs b/src/ifc/category_map.rs index b68121b5e..1a559a307 100644 --- a/src/ifc/category_map.rs +++ b/src/ifc/category_map.rs @@ -350,6 +350,29 @@ pub const MAPPINGS: &[Mapping] = &[ ifc_type: "IFCPIPEFITTING", predefined_type: None, }, + // RE-319: conduits and their fittings, as the IFC4 subtypes of the + // `IfcFlowSegment` and `IfcFlowFitting` Revit's IFC2X3 export of BIM-Speed + // Vitoria `ALD26 Before` writes for all 102 and 74 (revit-ifc's + // `IFCCompatibilityType` writes both in IFC2X3 as those supertypes). No + // IFC4 export of a conduit is measured, so the `PredefinedType` stays + // unset. A gutter keeps Revit's own `IfcFlowSegment`, a concrete IFC4 + // entity too: revit-ifc names no IFC4 entity for the gutter category + // (its category table is Revit's own, not in the source). + Mapping { + revit_class: "Conduit", + ifc_type: "IFCCABLECARRIERSEGMENT", + predefined_type: None, + }, + Mapping { + revit_class: "ConduitFitting", + ifc_type: "IFCCABLECARRIERFITTING", + predefined_type: None, + }, + Mapping { + revit_class: "Gutter", + ifc_type: "IFCFLOWSEGMENT", + predefined_type: None, + }, // Massing / abstract. Mapping { revit_class: "Mass", diff --git a/src/ifc/step_writer.rs b/src/ifc/step_writer.rs index 622935f3f..9ae430b56 100644 --- a/src/ifc/step_writer.rs +++ b/src/ifc/step_writer.rs @@ -106,7 +106,7 @@ pub fn write_step_to( #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum ElementTail { /// `Tag` only — the entity declares no `PredefinedType` - /// (`IfcFurnishingElement`, `IfcFlowController`). Arity 8. + /// (`IfcFurnishingElement`, `IfcFlowController`, `IfcFlowSegment`). Arity 8. Tag, /// `Tag, PredefinedType` — the shape almost every /// `IfcBuildingElement` subtype takes. Arity 9. @@ -142,7 +142,7 @@ enum ElementTail { /// subtype in IFC4. fn element_tail_for(ifc_upper: &str) -> ElementTail { match ifc_upper { - "IFCFURNISHINGELEMENT" | "IFCFLOWCONTROLLER" => ElementTail::Tag, + "IFCFURNISHINGELEMENT" | "IFCFLOWCONTROLLER" | "IFCFLOWSEGMENT" => ElementTail::Tag, "IFCDOOR" | "IFCWINDOW" => ElementTail::Opening, "IFCSPACE" => ElementTail::Space, "IFCREINFORCINGBAR" => ElementTail::ReinforcingBar, diff --git a/src/research/partition_element_records.rs b/src/research/partition_element_records.rs index e08b5ad21..43dfd855e 100644 --- a/src/research/partition_element_records.rs +++ b/src/research/partition_element_records.rs @@ -290,6 +290,28 @@ pub const OST_PIPE_CURVES: i64 = -2_008_044; /// Autodesk `BuiltInCategory.OST_PipeFitting`. pub const OST_PIPE_FITTING: i64 = -2_008_049; +// RE-319: conduits, conduit fittings and gutters, measured on the one file +// with a Revit export that holds them (BIM-Speed Vitoria `ALD26 Before`, +// Revit 2018): every instance the RE-21 rule selects is a `Tag` of Revit's +// own export, as `IfcFlowSegment` or `IfcFlowFitting`, and none is missing. +// The centerline categories that sit beside every conduit and fitting +// (`OST_ConduitCenterLine` -2008139, `OST_ConduitFittingCenterLine` +// -2008141, and for pipes `OST_PipeCurvesCenterLine` -2008045 and +// `OST_PipeFittingCenterLine` -2008072) are never recovered: none is in +// Revit's export, and revit-ifc's `ElementFilteringUtil` lists the conduit +// ones among the categories it leaves out. Cable trays and cable tray +// fittings (`OST_CableTray` -2008130, `OST_CableTrayFitting` -2008126) are +// not recovered either: no file with a Revit export holds an instance of +// either, so nothing shows that Revit's export writes them. + +/// Autodesk `BuiltInCategory.OST_Conduit` — conduits. +pub const OST_CONDUITS: i64 = -2_008_132; +/// Autodesk `BuiltInCategory.OST_ConduitFitting`. +pub const OST_CONDUIT_FITTING: i64 = -2_008_128; +/// Autodesk `BuiltInCategory.OST_Gutter` — gutters. Revit's IFC2X3 export +/// writes them as `IfcFlowSegment`. +pub const OST_GUTTER: i64 = -2_001_391; + // RE-36: structural categories. Nearly every frame of these uses the // second prologue, so their instances export through RE-34's inferred // ElementIds; the oracle is the VIM export of the same sample @@ -388,7 +410,12 @@ pub const OST_EDGE_SLAB: i64 = -2_001_392; /// RE-39 adds stairs with their runs, landings and stringers, and roofs. /// RE-40 adds slab edges, once elements in non-primary design options are /// left out: all 59 exported on Snowdon Towers are Revit's. -pub const PRODUCT_RECORD_CATEGORIES: [(i64, &str); 39] = [ +/// +/// RE-319 adds conduits, conduit fittings and gutters: on BIM-Speed Vitoria +/// `ALD26 Before` (Revit 2018) all 102, 74 and 2 instances the rule selects +/// are `Tag`s of Revit's own export, written there as `IfcFlowSegment`, +/// `IfcFlowFitting` and `IfcFlowSegment`. +pub const PRODUCT_RECORD_CATEGORIES: [(i64, &str); 42] = [ (OST_FURNITURE, "Furniture"), (OST_CASEWORK, "Casework"), (OST_PLUMBING_FIXTURES, "PlumbingFixture"), @@ -402,6 +429,9 @@ pub const PRODUCT_RECORD_CATEGORIES: [(i64, &str); 39] = [ (OST_DUCT_FITTING, "DuctFitting"), (OST_PIPE_CURVES, "Pipe"), (OST_PIPE_FITTING, "PipeFitting"), + (OST_CONDUITS, "Conduit"), + (OST_CONDUIT_FITTING, "ConduitFitting"), + (OST_GUTTER, "Gutter"), (OST_STRUCTURAL_FRAMING, "StructuralFraming"), (OST_STRUCTURAL_COLUMNS, "StructuralColumn"), (OST_STRUCTURAL_FOUNDATION, "StructuralFoundation"), @@ -1385,7 +1415,7 @@ pub(crate) fn find_subslice(haystack: &[u8], needle: &[u8]) -> Option { /// The categories the exporter recovers instances of, with the class name /// each is decoded as: the architectural core plus /// [`PRODUCT_RECORD_CATEGORIES`]. -pub const RECOVERED_CATEGORIES: [(i64, &str); 46] = [ +pub const RECOVERED_CATEGORIES: [(i64, &str); 49] = [ (OST_WALLS, "Wall"), (OST_DOORS, "Door"), (OST_WINDOWS, "Window"), @@ -1406,6 +1436,9 @@ pub const RECOVERED_CATEGORIES: [(i64, &str); 46] = [ (OST_DUCT_FITTING, "DuctFitting"), (OST_PIPE_CURVES, "Pipe"), (OST_PIPE_FITTING, "PipeFitting"), + (OST_CONDUITS, "Conduit"), + (OST_CONDUIT_FITTING, "ConduitFitting"), + (OST_GUTTER, "Gutter"), (OST_STRUCTURAL_FRAMING, "StructuralFraming"), (OST_STRUCTURAL_COLUMNS, "StructuralColumn"), (OST_STRUCTURAL_FOUNDATION, "StructuralFoundation"), diff --git a/viewer/src/main.ts b/viewer/src/main.ts index df89fe968..01c5f63d0 100644 --- a/viewer/src/main.ts +++ b/viewer/src/main.ts @@ -1494,6 +1494,8 @@ const IFC_ENTITY_NAMES = [ 'IfcBuilding', 'IfcBuildingElementProxy', 'IfcBuildingStorey', + 'IfcCableCarrierFitting', + 'IfcCableCarrierSegment', 'IfcColumn', 'IfcCovering', 'IfcCurtainWall', @@ -1502,6 +1504,7 @@ const IFC_ENTITY_NAMES = [ 'IfcDuctSegment', 'IfcElectricAppliance', 'IfcFlowController', + 'IfcFlowSegment', 'IfcFlowTerminal', 'IfcFooting', 'IfcFurnishingElement', From 37838a94d36099bddc1c8d55e5e77c6ee3a9f233 Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 17:32:25 -0500 Subject: [PATCH 04/12] feat(elements): a gutter is placed on the Level its base elevation gives (#1261) (RE-319) --- src/research/partition_schema_mvp/fields.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/research/partition_schema_mvp/fields.rs b/src/research/partition_schema_mvp/fields.rs index 5015c0e0b..ba776acff 100644 --- a/src/research/partition_schema_mvp/fields.rs +++ b/src/research/partition_schema_mvp/fields.rs @@ -1040,6 +1040,8 @@ pub const FRAMING_TOP_LEVEL_SOURCE: &str = "structural_framing_top_level"; /// light fixture, wall sweep, generic model, hardscape element and stair is /// on the Level [`crate::element_record_level_refs::elevation_band_level`] /// gives, while plumbing fixtures follow the Level object they name instead. +/// A gutter is placed the same way (RE-319): both of `ALD26 Before`'s, whose +/// records name no Level, are on the storey of Revit's export. pub const ELEVATION_PLACED_CLASSES: &[&str] = &[ "SlabEdge", "LightingFixture", @@ -1047,4 +1049,5 @@ pub const ELEVATION_PLACED_CLASSES: &[&str] = &[ "GenericModel", "Hardscape", "Stair", + "Gutter", ]; From 1c71bda0ea103cf398f82261ae1c4a392d8cc127 Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 17:41:43 -0500 Subject: [PATCH 05/12] fix(ifc): a conduit, conduit fitting or gutter gets no Level parameter that no export measures (#1261) (RE-319) --- src/ifc/export_content.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ifc/export_content.rs b/src/ifc/export_content.rs index 77489f8bf..867ec1d53 100644 --- a/src/ifc/export_content.rs +++ b/src/ifc/export_content.rs @@ -1665,6 +1665,16 @@ fn wall_geometry_from_decoded(decoded: &DecodedElement) -> Option Option { use crate::partition_level_parameters as lp; + // RE-319: the names Revit gives a conduit's, conduit fitting's or + // gutter's Level parameter are measured on no export (the one export that + // holds them is Revit 2018's IFC2X3, which writes no `Constraints` set on + // them), so none is written. + if matches!( + ifc_type, + "IFCCABLECARRIERSEGMENT" | "IFCCABLECARRIERFITTING" | "IFCFLOWSEGMENT" + ) { + return None; + } let text = |wanted: &str| { decoded.fields.iter().find_map(|(name, value)| match value { InstanceField::String(v) if name == wanted => Some(v.clone()), From dc2806f95f7c3b18600a79bb2c9569aa8c9e4513 Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 17:45:59 -0500 Subject: [PATCH 06/12] docs(elements): RE-319 report, the changelog fragment and the public status for conduits, conduit fittings and gutters (#1261) (RE-319) --- changelog.d/added/1261-conduits-gutters.md | 23 +++++ docs/evidence.md | 3 +- docs/release-1.0-criteria.md | 2 +- docs/status.md | 9 +- docs/support-matrix.json | 9 ++ docs/supported-profile.md | 3 +- ...E-319-conduits-conduit-fittings-gutters.md | 98 +++++++++++++++++++ 7 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 changelog.d/added/1261-conduits-gutters.md create mode 100644 reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md diff --git a/changelog.d/added/1261-conduits-gutters.md b/changelog.d/added/1261-conduits-gutters.md new file mode 100644 index 000000000..e421f0949 --- /dev/null +++ b/changelog.d/added/1261-conduits-gutters.md @@ -0,0 +1,23 @@ +- **Conduits, conduit fittings and gutters are exported from their element + records, on every release the exporter reads.** `OST_Conduit`, + `OST_ConduitFitting` and `OST_Gutter` join the recovered categories under + the unchanged RE-21 instance rule, with the record's box as the body and the + Level its record names (a gutter's by its elevation). Against Revit's own + IFC2X3 export of BIM-Speed's Vitoria `ALD26 Before` (Revit 2018), the one + file with an export that holds any of them, all 102 conduits, 74 conduit + fittings and 2 gutters the rule selects are elements of Revit's by `Tag` and + none is outside it: 1,314 of its 1,321 elements are now written (1,136 + before), 1,305 of them in Revit's class or IFC4's for its IFC2X3 one + (conduits as `IfcCableCarrierSegment`, their fittings as + `IfcCableCarrierFitting`, gutters as Revit's `IfcFlowSegment`, no + `PredefinedType`), and 1,251 on Revit's storey (1,073 before), with every + validation finding at 0 and the properties Revit does not write unchanged at + 20. The 7 still missing are 4 panel walls and 3 assemblies. Cable trays and + cable tray fittings are not recovered, since no file with a Revit export + holds one, and neither are the conduit centerline categories Revit's export + leaves out. Autodesk's MEP samples of 2015 to 2027 (19 or 20 conduits and 14 + conduit fittings on `rme_advanced` and `rme_basic`) and Snowdon Towers + Electrical (530 conduits and 322 fittings) now export them too, counted and + not scored: no Revit export of those files exists. See + [RE-319](reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md) + (#1261). diff --git a/docs/evidence.md b/docs/evidence.md index 1f7578c88..c5b399111 100644 --- a/docs/evidence.md +++ b/docs/evidence.md @@ -17,7 +17,7 @@ The recovery figures in this README compare rvt-rs's export with Revit's own IFC | Revit 2027 projects | yes; 325 fields of the 2027 schema carry a flag whose meaning is not measured (RE-264) | **experimental (since 0.6.0):** typed IFC entities from each element's record, with the constants the file's schema gives (RE-179); on Autodesk's five 2027 sample projects the same ElementIds and classes as their 2026 copies (20,818 of 20,818), with **no Revit 2027 export measured** | as on 2026 | as on 2026: storeys, rooms (their outline as on 2025, RE-314), doors and windows in their hosts, family and type names, layer sets, wall joins and mullion materials read the same as the 2026 copies; 79 corner mullions are not put in a curtain wall | | Revit 2023 projects | yes | typed IFC entities (since 0.4.0) from each element's record (RE-81): on two 2023 projects every element of Revit's export (modelo_bim, 37 of 37) or all but the 8 window trims nested in windows (Exemplo_data, 37 of 45), none outside it | the element's bounding box, walls cut back by the walls they join (Exemplo_data 17 of 17 and modelo_bim 4 of 4 as Revit's, RE-120), beams stopped at the faces of the columns they frame into (modelo_bim 8 of 8, RE-122); rooms their outline (RE-102) | ElementId, category, each door's and window's host wall (30 of 30 as Revit's, RE-85), and the storeys of Revit's own Levels with each element on the one its record names, a beam on the one at its top (Exemplo_data 37 of 37 and modelo_bim 37 of 37 in Revit's storey, RE-107, RE-119), each family instance's family and type name (50 of 50 as Revit names them, RE-109), each wall's, floor's and roof's type and system family (24 of 24 with Revit's type, RE-111, RE-112), family instances' materials (44 of 45 as Revit's, RE-113), and layer sets, named by their own or their category's material (RE-114, RE-115): Exemplo_data 36 of 37 and modelo_bim 31 of 37 elements with Revit's materials, and materials with Revit's shading colours (20 of 21, none different, RE-116); no layered or angled joins or IFC export overrides, and the diagnostics say so; on 2016 to 2023, elements in a non-primary design option or outside the export phase are left out since RE-315 | | Revit 2019 to 2022 projects | yes | **experimental (since 0.6.0):** typed IFC entities from each element's record, which 2019 to 2022 frame as 2023 does, read with the tags each release's schema gives (RE-180); on Autodesk's 2019 to 2022 sample projects every ElementId shared with the 2023 copy has the class it has there (`rac_basic`, `rst_basic` and `rac_advanced` of each release), with **no Revit export of a 2019 to 2022 file measured** | as on 2023 | as on 2023: storeys, doors and windows in their hosts, family and type names, layer sets and materials read as the 2023 copies do, with a few type names and type materials different (RE-180 §6) | -| Revit 2015 to 2018 projects | yes on 2016 to 2018; on 2015, partial: they open on Autodesk's sample projects, and previews and PartAtom are not measured | **experimental (since 0.6.0):** typed IFC entities from each element's record, which 2015 to 2018 frame as 2019 does, read with the tags each release's schema gives (RE-181); on Autodesk's 2016, 2017 and 2018 sample projects every ElementId shared with the 2019 copy has the class it has there (`rac_basic`, `rst_basic` and `rac_advanced` of each release), and on five of its six 2015 sample projects (the sixth is another model), with **Revit's own export measured on one 2015 project and one 2018 project**: BIMcollab's structural example (RE-198, a public download, not redistributable) has all 241 of Revit's elements by ElementId, each in Revit's class or IFC4's for its IFC2X3 one, 3 air terminals Revit's export leaves out (#879), 16 footings on no storey and none of its elements' GlobalIds Revit's (#878); BIM-Speed's Vitoria `ALD26 Before` (2018, CC BY 4.0), most of whose frames carry no ElementId of their own and sit in their element's record (RE-315), has 1,136 of Revit's 1,321 elements by ElementId, 1,127 of them in Revit's class or IFC4's for its IFC2X3 one (9 curtain walls are written as walls), none written that Revit's export leaves out, 1,073 on Revit's storey, and 7 storeys, as many as Revit's; the 185 missing are 178 conduits, conduit fittings and gutters, whose categories are not recovered, 4 panel walls and 3 assemblies, and its held-out sibling writes 1,336 elements and spaces against Revit's 1,520, counts only, none of its elements one that Revit's export lacks (198 were, until the export phase and design options were applied, which the counts cannot tell apart); 2014's element records are read as 2015's are, measured on one local 2014 file only (RE-259, the row below) | as on 2019 | as on 2019: storeys, doors and windows in their hosts, family and type names, layer sets and materials read as the 2019 copies do, but where the files' own bytes differ (RE-181 §6) | +| Revit 2015 to 2018 projects | yes on 2016 to 2018; on 2015, partial: they open on Autodesk's sample projects, and previews and PartAtom are not measured | **experimental (since 0.6.0):** typed IFC entities from each element's record, which 2015 to 2018 frame as 2019 does, read with the tags each release's schema gives (RE-181); on Autodesk's 2016, 2017 and 2018 sample projects every ElementId shared with the 2019 copy has the class it has there (`rac_basic`, `rst_basic` and `rac_advanced` of each release), and on five of its six 2015 sample projects (the sixth is another model), with **Revit's own export measured on one 2015 project and one 2018 project**: BIMcollab's structural example (RE-198, a public download, not redistributable) has all 241 of Revit's elements by ElementId, each in Revit's class or IFC4's for its IFC2X3 one, 3 air terminals Revit's export leaves out (#879), 16 footings on no storey and none of its elements' GlobalIds Revit's (#878); BIM-Speed's Vitoria `ALD26 Before` (2018, CC BY 4.0), most of whose frames carry no ElementId of their own and sit in their element's record (RE-315), has 1,314 of Revit's 1,321 elements by ElementId (1,136 before its 102 conduits, 74 conduit fittings and 2 gutters were recovered, RE-319), 1,305 of them in Revit's class or IFC4's for its IFC2X3 one (9 curtain walls are written as walls), none written that Revit's export leaves out, 1,251 on Revit's storey, and 7 storeys, as many as Revit's; the 7 missing are 4 panel walls and 3 assemblies, and its held-out sibling writes @@HELD@@ elements and spaces against Revit's 1,520, counts only, none of its elements one that Revit's export lacks (198 were, until the export phase and design options were applied, which the counts cannot tell apart); 2014's element records are read as 2015's are, measured on one local 2014 file only (RE-259, the row below) | as on 2019 | as on 2019: storeys, doors and windows in their hosts, family and type names, layer sets and materials read as the 2019 copies do, but where the files' own bytes differ (RE-181 §6) | | Revit 2011 to 2014 projects | yes: 2011 to 2013 open since RE-259, whose schemas have no GUID lists; measured on local closed-source files only, outside the 1.0 range (2015 to 2027) | **experimental:** typed IFC entities from each element's record, which 2011 to 2014 frame as 2015 does, read with the tags each release's schema gives (RE-259); on a local copy of Autodesk's 2013 `rac_advanced` sample every ElementId shared with its 2015 copy has the class it has there and 62,071 of 62,153 fields agree, with **no Revit export of a file before 2015 measured** and no same-model pair for 2011, 2012 or 2014 | as on 2015 | as on 2015: storeys, doors and windows in their hosts, family and type names, layer sets and materials read as the 2015 copy does, but where the files' own bytes differ (RE-259 §7) | | Revit 2008 to 2010 projects | yes: they open and report their release, which 2008 and 2009 take from their build date (RE-259); measured on local closed-source files only, outside the 1.0 range (2015 to 2027) | **experimental:** typed IFC entities from each element's record, which 2009 and 2010 frame as 2011 does and 2008 4 bytes shorter (RE-260); on one local 2009 project 8 doors and their wall, on one 2008 project one generic model, with **no Revit export and no same-model copy of any 2008 to 2010 file measured** | as on 2015 | storeys with their names and elevations (RE-260, also on 2011 and 2012), materials named and coloured; type names, layer sets and hosts as on 2015 but not measured | | Families (`.rfa`) | yes | family metadata, OmniClass, previews; no family geometry | none | a family's types and type parameters as its `PartAtom` stream lists them (`rvt-info`, `PartAtom::family_types`) | @@ -72,6 +72,7 @@ On Revit 2024 and 2025 project files, rvt-rs reads each element from its partiti | Railings, curtain panels, mullions | `IfcRailing`, `IfcPlate`, `IfcMember` | Snowdon Towers 131 railings, every mullion | | Furniture, casework, plumbing, lighting, equipment | `IfcFurniture`, `IfcSanitaryTerminal`, `IfcLightFixture`, `IfcElectricAppliance`, proxies | RE1 models and Snowdon Towers, every one Revit exports | | Ducts, pipes, fittings, air terminals | `IfcDuctSegment`, `IfcPipeSegment` drawn as its cylinder where its ends are proven (RE-131), their fittings, `IfcAirTerminal` | RE1 Mechanical and Plumbing, every one; all 69 pipes are Revit's cylinder, its radius, axis ends and length to 0.00001 ft, and so are the BIM4LCA office's 12 (Revit 2024) | +| Conduits, conduit fittings, gutters | `IfcCableCarrierSegment`, `IfcCableCarrierFitting`, `IfcFlowSegment` (gutters), each drawn as its record's box, no `PredefinedType` (RE-319) | BIM-Speed Vitoria `ALD26 Before` (Revit 2018, IFC2X3 export), the one file with an export that holds any: all 102 conduits, 74 fittings and 2 gutters the instance rule selects are elements of Revit's export by `Tag`, none outside it, all 178 on the storey of Revit's (the 2 gutters by their elevation); the boxes of 102 of the 104 conduits and gutters within 0.01 ft of Revit's. Autodesk's `rme_basic` and `rme_advanced` of 2015 to 2027 and Snowdon Towers Electrical export them too, counted and not scored (no Revit export). Cable trays and cable tray fittings are not exported: no export holds one | | Electrical and mechanical devices and equipment | `IfcAlarm` (fire alarm devices), `IfcElectricAppliance` (data devices), proxies (switches, sensors, receptacles, junction boxes, panels, mechanical equipment) | RE1 Electrical and Mechanical, every one Revit exports and nothing else; the symbols nested in switches and receptacles left out, as Revit leaves them out (RE-79) | | Structural framing, columns, foundations | `IfcBeam` along its location line, `IfcColumn`, `IfcFooting` | Snowdon structural sample: all 1,078 in the category its VIM export gives them; 923 of 942 beams run along their line, with Revit's own section on 613 of the 839 a later edition kept unchanged, and on 179 more less the top a floor join cuts (RE-49); 377 steel beams and 40 steel columns are their type's I section, Revit's own on all 271 beams and 24 columns the VIM scores (RE-103, RE-104) | | Site elements, generic models, slab edges, elevators, ramps | proxies, `IfcTransportElement`, `IfcRamp` | Snowdon Towers, every one Revit exports | diff --git a/docs/release-1.0-criteria.md b/docs/release-1.0-criteria.md index fe3f010b4..ff9f336e4 100644 --- a/docs/release-1.0-criteria.md +++ b/docs/release-1.0-criteria.md @@ -37,7 +37,7 @@ only in a pull request that links the new evidence. | | Requirement | Bar | Measured now | Status | |---|---|---|---|---| | W1 | A new user installs it | Every channel (crates.io, the PyPI wheels, the CLI archives, the container image, the viewer) is checked from what was published, as [Post-publish install verification](../RELEASE.md#post-publish-install-verification) describes | All five checked from what was published for v0.12.0 ([`install.md`](install.md)); `cargo install` from crates.io itself was not run, only on the tagged source in the publish workflow | **passed** for 0.12.0, but for that install; repeated at the 1.0 tag | -| W2 | Every release from 2015 to 2027 is supported | No release in that range is experimental. Each has at least one project with Revit's own IFC export of that release that meets W4, W6 and W7 | 2024 has exact element sets against a same-release export (Core Interior, RE-21). 2025's same-release evidence is puzzbobb's Revit 2025 models (22 with a Revit export, all exact by ElementId, Measure only) and `teste_export_2025` (a Revit 25.4 export, local only); RE1's exports are by Revit 26.2, a cross-release pair (RE-32). 2023 has 37 of 37 and 37 of 45, the other 8 being window trims nested in families (RE-81). 2026 has 113 of 115 on one project (RE-124). 2015 has one: BIMcollab's structural example against Revit 2015's own export, all 241 of its elements by ElementId, in Revit's class or IFC4's for its IFC2X3 one, plus 3 it leaves out ([RE-198](../reports/element-framing/RE-198-revit-2015-bimcollab-export.md), [#879](https://github.com/DrunkOnJava/rvt-rs/issues/879)). 2018 has one, used up for W5: Vitoria's `ALD26 Before` against Revit's own IFC2X3 export, 1,136 of its 1,321 elements by ElementId, 1,127 of them in Revit's class or IFC4's (9 curtain walls come out as walls), none written that the export leaves out, 185 missing, so it does not meet W4 (RE-315). 2016, 2017, 2019 to 2022 and 2027 have no same-release export, and are measured only against the same models saved by a neighbouring release (RE-179 to RE-181, [#421](https://github.com/DrunkOnJava/rvt-rs/issues/421)); the native readers on 2015 to 2022 are [#1158](https://github.com/DrunkOnJava/rvt-rs/issues/1158), and geometry and properties beyond each element's box on 2015 to 2023, 2026 and 2027 are [#1190](https://github.com/DrunkOnJava/rvt-rs/issues/1190) | **failed** | +| W2 | Every release from 2015 to 2027 is supported | No release in that range is experimental. Each has at least one project with Revit's own IFC export of that release that meets W4, W6 and W7 | 2024 has exact element sets against a same-release export (Core Interior, RE-21). 2025's same-release evidence is puzzbobb's Revit 2025 models (22 with a Revit export, all exact by ElementId, Measure only) and `teste_export_2025` (a Revit 25.4 export, local only); RE1's exports are by Revit 26.2, a cross-release pair (RE-32). 2023 has 37 of 37 and 37 of 45, the other 8 being window trims nested in families (RE-81). 2026 has 113 of 115 on one project (RE-124). 2015 has one: BIMcollab's structural example against Revit 2015's own export, all 241 of its elements by ElementId, in Revit's class or IFC4's for its IFC2X3 one, plus 3 it leaves out ([RE-198](../reports/element-framing/RE-198-revit-2015-bimcollab-export.md), [#879](https://github.com/DrunkOnJava/rvt-rs/issues/879)). 2018 has one, used up for W5: Vitoria's `ALD26 Before` against Revit's own IFC2X3 export, 1,314 of its 1,321 elements by ElementId (1,136 before conduits, conduit fittings and gutters were recovered), 1,305 of them in Revit's class or IFC4's (9 curtain walls come out as walls), none written that the export leaves out, 7 missing (4 curtain-panel walls and 3 assemblies), so it does not meet W4 (RE-315, RE-319). 2016, 2017, 2019 to 2022 and 2027 have no same-release export, and are measured only against the same models saved by a neighbouring release (RE-179 to RE-181, [#421](https://github.com/DrunkOnJava/rvt-rs/issues/421)); the native readers on 2015 to 2022 are [#1158](https://github.com/DrunkOnJava/rvt-rs/issues/1158), and geometry and properties beyond each element's box on 2015 to 2023, 2026 and 2027 are [#1190](https://github.com/DrunkOnJava/rvt-rs/issues/1190) | **failed** | | W3 | Family and template files are read like projects | A family (`.rfa`) or template (`.rte`, `.rft`) of every supported release yields its types, parameters and geometry, measured against Revit's export of the family placed in a project | Metadata, previews, schema and OmniClass, and a family's types and type parameters as its `PartAtom` stream lists them, Revit's text at save rather than the family's records, and not compared with an export of the family placed in a project ([supported profile](supported-profile.md#by-input)) ([#1189](https://github.com/DrunkOnJava/rvt-rs/issues/1189)) | **failed** | | W4 | Correct elements on the models the decoder was developed on | On every reference model, the elements written and their IFC classes equal Revit's export of that model in every category: none missing, none extra | Core Interior (2024): exact in its six instance categories (RE-21, run in CI). RE1 (2025): Architecture 84, Electrical 49 and Mechanical 74 exact by ElementId; Plumbing writes one element Revit's export leaves out, a water closet tank (442378, pinned in `tests/element_records_2025.rs`). puzzbobb's Revit 2025 models: all 22 with an export exact. BIM4LCA office (2024): all 12,974 as built; at building permit one column Revit's export leaves out (1927742), and on both files one fixture in another class (3095244) ([#792](https://github.com/DrunkOnJava/rvt-rs/issues/792)) (Measure run 40927543524, 2026-10-29). Snowdon Towers (2024, local only): 5,945 of 5,968 in Revit's export; the other 23 are curtain panels with no resolved type ([#309](https://github.com/DrunkOnJava/rvt-rs/issues/309)), and the 6 slabs in the Legends phase of [#328](https://github.com/DrunkOnJava/rvt-rs/issues/328) are no longer written (RE-184; Measure run 40930512289: `IfcSlab` 224 to 218, the only change on any CI model; [evidence page](evidence.md#what-rvt-rs-reads-from-real-projects)) | **failed** | | W5 | Correct on models it was not developed on ([#408](https://github.com/DrunkOnJava/rvt-rs/issues/408)) | At least two projects of every supported release, each with Revit's own IFC export of that release, whose first measurement, made before any fix is made for them, meets W4, W6 and W7. A pair whose first measurement does not is used up for W5: it stays in Measure as a held-out regression check, counts only and never developed on, and its counts may be quoted in reports (the maintainer, 2026-11-03). Since no model meets W6 and W7 yet, any pair measured now would be used up, so a fresh pair is pinned sealed: no Measure run fetches it until the final 1.0 check, made once when W4, W6 and W7 pass on the reference models. The results are published as measured | Held-out measurements so far: Snowdon Towers Plumbing, HVAC and Electrical (2024). It scored against a VIM of the 2027 edition rather than Revit's IFC export of these files: all 10,385 exported elements in the expected category, storeys and GlobalIds equal, every body a box ([report](../reports/validation/held-out-snowdon-mep-2026-09-27.md)). The first held-out project with Revit's own export of its release was BIMcollab's Revit 2015 structural example (RE-198), measured before any fix; RE-208 and RE-220 have since used it, so it no longer counts toward this bar, and neither do the holdout pack's models (`research/holdout-models.tsv`), whose first measurements were not recorded against W4, W6 and W7. Since 2026-11-03 Measure also holds out six projects with their release's own export (`research/holdout-archive-models.tsv`, [#1261](https://github.com/DrunkOnJava/rvt-rs/issues/1261)), measured once before any fix, counts only: Vitoria's two Revit 2018 saves export no element against Revit's 1,394 and 1,520, so `ALD26 Before` is spent to find why and `ALD26 Project` stays held out; Frigento (2020) has 151 of 151 elements paired by Tag, Gdynia (2021) 199 of 203, Warmond (2021) 710 of 710, and BIM Whale's `AdvancedProject` (2021) 1,698 of 1,714 with none of its 8 spaces, which are Revit Areas (held out, after being measured in full once). All six fail W4 at that first measurement, so they are used up for W5 and stay as regression checks: both Vitoria saves miss every element, Gdynia misses 4 and BIM Whale 16, its 8 Areas among them, and Frigento writes 22 elements and Warmond 6 spaces that Revit's export leaves out (run 41658225355). No model meets this bar today, and every release needs fresh pairs. BIMcollab's example fails W4: 3 elements written that Revit's export leaves out, and 16 footings on no storey, whose saved Level is unset ([#879](https://github.com/DrunkOnJava/rvt-rs/issues/879), RE-281). It also fails on identity: the project's, site's, building's and five storeys' GlobalIds are Revit's, from the values the file stores ([RE-220](../reports/element-framing/RE-220-stored-global-ids.md)), but none of its 241 elements' ([#878](https://github.com/DrunkOnJava/rvt-rs/issues/878)) | **failed** | diff --git a/docs/status.md b/docs/status.md index 4ace3d10f..1ae8e536b 100644 --- a/docs/status.md +++ b/docs/status.md @@ -81,8 +81,13 @@ exports their elements, measured against the same sample projects saved by Revit 2019 (for 2015 to 2018, RE-181), 2023 (for 2019 to 2022, RE-180) and 2026 (for 2027, RE-179) rather than against a Revit export of them, except two projects against Revit's own export of their release: BIMcollab's 2015 -structural example (RE-198) and Vitoria's 2018 `ALD26 Before` (RE-315); 2015's -`rst_basic` is another model than its 2019 copy, so it is not measured. On +structural example (RE-198) and Vitoria's 2018 `ALD26 Before` (RE-315, RE-319); +2015's `rst_basic` is another model than its 2019 copy, so it is not measured. +Conduits, conduit fittings and gutters export on every release the exporter +reads and are measured against Revit's own export on `ALD26 Before` only (all +178 it holds are Revit's elements, RE-319); Autodesk's MEP samples and Snowdon +Towers Electrical export them too, counted and not scored, and cable trays do +not export, since no Revit export holds one. On projects saved by Revit 2011 to 2014, experimentally and outside the 1.0 range (2015 to 2027), it exports their elements too, measured on a local copy of Autodesk's 2013 `rac_advanced` sample against its 2015 copy, and files of diff --git a/docs/support-matrix.json b/docs/support-matrix.json index dcdb8ac40..cbc592e93 100644 --- a/docs/support-matrix.json +++ b/docs/support-matrix.json @@ -242,6 +242,15 @@ "notes": "Six BuiltInCategory values (OST_LightingDevices, OST_FireAlarmDevices, OST_DataDevices, OST_ElectricalFixtures, OST_ElectricalEquipment, OST_MechanicalEquipment) decode under the RE-21 instance rule. A shared nested device (the symbol a switch or receptacle nests) is a record of its own in its parent's category; the two list each other among their references and the nested one has the larger ElementId, and Revit's export leaves it out, so rvt-rs does too (21 of 21 on RE1 Electrical). RE1 Electrical then exports exactly Revit's elements: 12 lighting fixtures, 2 data devices, 5 fire alarm devices and 30 devices and panels, none outside its export; RE1 Mechanical adds its AHU. Entities are the IFC4 subtype of what Revit's IFC2x3 export writes: IfcAlarm (IfcAlarmType), IfcElectricAppliance (IfcElectricApplianceType), proxies. Measured on the RE1 models only; Core Interior and Snowdon Towers hold none of these categories and are unchanged. Bodies are the record bounding box. Revit 2024 and 2025 only.", "user_impact": "MEP models export their switches, receptacles, sensors, alarms, panels and equipment, each an element Revit's own export also holds." }, + { + "id": "element-records-conduits-gutters", + "area": "elements", + "name": "Conduits, conduit fittings and gutters from partition element records (RE-319)", + "status": "experimental", + "evidence": "partition_element_records::PRODUCT_RECORD_CATEGORIES and RECOVERED_CATEGORIES (OST_CONDUITS, OST_CONDUIT_FITTING, OST_GUTTER); probes/examples/probe_re319_category_census.rs; tools/re/category_census_vs_ifc.py; reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md", + "notes": "Three BuiltInCategory values (OST_Conduit, OST_ConduitFitting, OST_Gutter) decode under the unchanged RE-21 instance rule on every release the exporter reads. Measured against Revit's own export on one file, BIM-Speed's Vitoria ALD26 Before (Revit 2018, IFC2X3, CC BY 4.0): all 102 conduits, 74 conduit fittings and 2 gutters the rule selects are Tags of Revit's export and none is outside it, so 1,314 of its 1,321 elements are written (1,136 before), 1,305 of them in Revit's class or IFC4's for its IFC2X3 one, 1,251 on Revit's storey (1,073 before), with no validation finding and the values Revit does not write unchanged at 20; the 7 missing are 4 panel walls and 3 assemblies. Entities: IfcCableCarrierSegment and IfcCableCarrierFitting, the IFC4 subtypes of the IfcFlowSegment and IfcFlowFitting Revit's IFC2X3 export writes, and IfcFlowSegment for gutters; no IFC4 export of any of the three exists in the development set, so PredefinedType is left unset. Bodies are the record bounding box: the 102 conduit and gutter boxes within 0.01 ft of Revit's world box are 102 of 104 (the scorer does not say which two). Not measured: any release but 2018 against an export; Autodesk's rme_basic and rme_advanced samples of 2015 to 2027 (19 or 20 conduits, 14 fittings) and Snowdon Towers Electrical (530 conduits, 322 fittings) export them too, counted and not scored since no Revit export of them exists. Cable trays and cable tray fittings (OST_CableTray, OST_CableTrayFitting) are not recovered: no file with a Revit export holds an instance of either. The conduit and conduit fitting centerline categories (OST_ConduitCenterLine, OST_ConduitFittingCenterLine), which revit-ifc leaves out of the export, are never recovered. Conduit and gutter names are not read on Revit 2018 (Name differs, as for pipes), and no Constraints Level parameter is written for the three classes.", + "user_impact": "Projects with conduits, conduit fittings or roof gutters export them as IFC elements with their Revit ElementIds and storeys, drawn as their record's box; on the one Revit 2018 project with a Revit export every one is an element Revit also exports. Cable trays are not exported." + }, { "id": "element-records-revit-2023", "area": "elements", diff --git a/docs/supported-profile.md b/docs/supported-profile.md index c8981612c..0150cf3af 100644 --- a/docs/supported-profile.md +++ b/docs/supported-profile.md @@ -43,7 +43,7 @@ apart: | Revit 2023 project | yes | yes, measured on two 2023 projects against Revit's IFC4 exports (RE-81); components nested in doors and windows are left out | the element's bounding box; rooms their outline (RE-102) | ElementId, category, door and window host walls (RE-85), Levels as storeys with each element on the one its record names (RE-107), and family instances' family and type names (RE-109) | | Revit 2027 project | partial: opens on Autodesk's sample projects; previews and PartAtom not measured | experimental (since 0.6.0): the same ElementIds and classes as the 2026 copies of Autodesk's five sample projects (RE-179); no Revit 2027 export is measured | as on 2026 | as on 2026 | | Revit 2019 to 2022 project | yes | experimental (since 0.6.0): 2023's records and readers with each release's schema tags; every ElementId shared with the 2023 copies of Autodesk's sample projects keeps its class, and the `rac_basic`, `rst_basic` and 2021 and 2022 `rac_advanced` exports have the 2023 copies' building elements, class for class (RE-180); no Revit export of a 2019 to 2022 file is measured | as on 2023 | as on 2023 | -| Revit 2015 to 2018 project | yes on 2016 to 2018; 2015 partial: opens on Autodesk's sample projects; previews and PartAtom not measured | experimental (since 0.6.0): 2019's records and readers with each release's schema tags; every ElementId shared with the 2019 copies of Autodesk's 2016 to 2018 sample projects keeps its class, and their exports have the 2019 copies' building elements, class for class; on five of the six 2015 samples every shared ElementId keeps its class, and the sixth, `rst_basic`, is another model (RE-181); Revit's own export is measured on one 2015 project (RE-198) and one 2018 project, Vitoria's `ALD26 Before`, where 1,136 of its 1,321 elements are written by ElementId, 1,127 of them in Revit's class or IFC4's (9 curtain walls come out as walls), none that the export leaves out, 1,073 on Revit's storey (RE-315) | as on 2019 | as on 2019 | +| Revit 2015 to 2018 project | yes on 2016 to 2018; 2015 partial: opens on Autodesk's sample projects; previews and PartAtom not measured | experimental (since 0.6.0): 2019's records and readers with each release's schema tags; every ElementId shared with the 2019 copies of Autodesk's 2016 to 2018 sample projects keeps its class, and their exports have the 2019 copies' building elements, class for class; on five of the six 2015 samples every shared ElementId keeps its class, and the sixth, `rst_basic`, is another model (RE-181); Revit's own export is measured on one 2015 project (RE-198) and one 2018 project, Vitoria's `ALD26 Before`, where 1,314 of its 1,321 elements are written by ElementId (1,136 before conduits, conduit fittings and gutters, RE-319), 1,305 of them in Revit's class or IFC4's (9 curtain walls come out as walls), none that the export leaves out, 1,251 on Revit's storey (RE-315) | as on 2019 | as on 2019 | | Revit 2011 to 2014 project | yes, on local closed-source files only, outside the 1.0 range (2015 to 2027); 2011 to 2013 open since RE-259 | experimental: 2015's records and readers with each release's schema tags; on a local copy of Autodesk's 2013 `rac_advanced` sample every ElementId shared with its 2015 copy keeps its class, and its export has the 2015 copy's building elements, class for class, but for a re-divided curtain wall (RE-259); no Revit export of a file before 2015 is measured | as on 2015 | as on 2015 | | Revit 2008 to 2010 project | yes, on local closed-source files only, outside the 1.0 range (2015 to 2027) (RE-259) | experimental: 2011's records and readers with each release's schema tags, 2008's envelope 4 bytes shorter (RE-260); checked only for consistency within each file, with no Revit export and no same-model copy | as on 2015 | storeys and named materials | | Family (`.rfa`) | yes | family metadata and OmniClass only | none | a family's types and type parameters as its `PartAtom` stream lists them: Revit's text at save, not read from the family's own records | @@ -109,6 +109,7 @@ counts reported on 2026-11-02 and 2026-11-03 on 0.12.0): | Beams | along their location line with their section; a steel beam whose type stores an I section as that I (RE-103) | 923 of 942 Snowdon structural beams on their line; 377 drawn as their I, Revit's own shape and place on all 271 its VIM export scores; channels and angles are not drawn yet (#94) | | Steel columns | a structural column whose type stores an I section as that I, turned to the column's own X axis (RE-104); a column whose type is a square hollow section as it, rounded corners and all, from its family's parameters (RE-221) | all 40 of Snowdon's steel columns; Revit's own shape and turn on all 24 its VIM export scores. Revit's own body on all 79 hollow-section columns of the BIM4LCA office as built and 55 at building permit; rectangular and turned tubes and other sections keep their box. Every I-section member carries its I as an `IfcMaterialProfileSet` of its type's material (RE-105) | | Pipes | a cylinder along its two ends with its outside radius, where the ends and the record box prove one (RE-131) | all 69 pipes on RE1 Mechanical and Plumbing (Revit 2025) and the BIM4LCA office's 12 (Revit 2024), Revit's own radius, ends and length to 0.00001 ft; sloped pipes are not measured, ducts and fittings keep their box | +| Conduits, conduit fittings, gutters | the element's record box (RE-319); no cable tray or cable tray fitting is exported | Vitoria's `ALD26 Before` (Revit 2018) only, the one file with a Revit export that holds any: all 102 conduits, 74 fittings and 2 gutters are Revit's elements by `Tag` on Revit's storey, the boxes of 102 of the 104 conduits and gutters within 0.01 ft of Revit's; Autodesk's MEP samples (2015 to 2027) and Snowdon Towers Electrical export them too, counted and not scored | | Stairs | aggregates of flights, landings and supports, each stair's and flight's `PredefinedType` from its runs and landings; straight flights as their steps, monolithic ones included; riserless flights as their treads, spiral ones as their sector-shaped treads; a monolithic landing as its slab, and a landing that is one tread as that tread | Snowdon Towers 33 of 38 drawn flights equal to Revit's; on the BIM4LCA office (Revit 2024) all 35 flights have Revit's volume, its 34 straight ones and its spiral one, its 21 monolithic landings Revit's top and outline, and its tread landing Revit's body; on puzzbobb's Revit 2025 stair models every flight of models 13 to 16 has Revit's volume (RE-214, RE-217). A monolithic landing's underside is drawn flat where Revit's follows a flight's soffit, 100.4% to 104.7% of Revit's volume, and its `BodySource` says so; monolithic spiral runs and riserless runs with a nosing keep their box (#357) | | Curtain walls | aggregates of panels and mullions placed by their grids; a mullion or panel turned or tilted off the model's axes as the box along its own axes (RE-106) | every Snowdon panel and mullion relation Revit's; 1,019 turned or tilted mullions and panels with Revit's extents along their axes | | Doors, windows, openings | the element's box, turned with the instance where it is turned (RE-87); its opening is as deep as the host wall | host is Revit's on 138 of 138 (Core Interior) and 192 of 194 (Snowdon; the other 2 in another wall Revit cuts, RE-85), and on Revit 2024 and 2025 the wall its native record names, Revit's on all 463 of the BIM4LCA office's as built (RE-245); on Revit 2024 and 2025 the opening is the outline the symbol that draws it cuts, through the instance's transform: 138 of 138 on Core Interior and 4 of 4 on RE1 within 0.001 ft of Revit's (RE-215, #227; Measure run 40927543524); a window whose type stores Width, Height and Default Sill Height takes Revit's opening exactly (56 of 68 on Snowdon, RE-93), and a door whose body is its type's Rough Height tall its rough opening (57 of 126, RE-94); any other door whose type stores Width and Height carries them as its overall size (137 of 137 on Core Interior and RE1, RE-187; Measure run 40927543524); on Revit 2024 and 2025 a door's or window's overall size is the outline the symbol that draws it cuts, Revit's on every one with such an outline (138 of 138 on Core Interior, 4 of 5 on RE1, RE-215); a door or window whose symbol cuts no outline takes its own extents as its overall size, Revit's on all 269 windows and 266 of 269 doors of the BIM4LCA office (RE-218); otherwise not Revit's opening profile (#227, RE-83) | diff --git a/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md b/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md new file mode 100644 index 000000000..0889677a9 --- /dev/null +++ b/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md @@ -0,0 +1,98 @@ +# RE-319: conduits, conduit fittings and gutters are Revit's own elements by `Tag` (measured on Revit 2018) and are recovered; cable trays and the centerline categories are not + +**Date:** 2026-11-03 +**Issues:** #1261 (a Revit 2018 project exports no element; RE-315 §9 left 178 conduits, conduit fittings and gutters as "the next category census"); follows RE-33 (the category census), RE-21 (the instance rule), RE-79 (nested MEP components), RE-131 (pipe cylinders), RE-315 (the 32-bit second prologue) +**Artefacts:** BIM-Speed's Vitoria `ALD26 Before.rvt` (Revit 2018, sha256 `d3e5b04631e67265927be98352021ed6290b33ae67d39b1b6727fd76f014ff6f`) and Revit's own IFC2X3 export of it (`a42c6f3b0c9b7575d4c37c675155ff53c02571ca81357a87023f9da5fbf45181`), CC BY 4.0, TU Berlin DepositOnce, doi:10.14279/depositonce-16441, spent for W5 (RE-315) and measured in full with `-f holdout=true`; RE1 Electrical (`9875e765c9f47893808c47b845a8379b8777b92510e3e0284f763cb457c9630b`, IFC `c7002a10c8e10ab2fca64ff61dcf38db04da652924f65ce53c2064827dfa9e16`), Mechanical (`d559720177aa0ec435133f804e7c45d60da2deb9d5585bb3d55f4830139c014b`, IFC `9e56cf7246ce86ef73646dd588a1efb8a4756e5e102b30e28b3b58577a454db0`) and Plumbing (`03689df2aa426031a216e65051b9f19d3265d6fe96884dd47373b17435f9e54c`, IFC `294490b222632509779910345f27a4eeda3645956138a593298c241495f7b8b6`), Revit 2025, MIT, IFC2X3 exports; Core Interior (`c805df445d613b408e37337765572021265e3f5dfdc7d1fa53b22ba1600b8014`); the BIM4LCA office and its terrain variants, puzzbobb's 23 Revit 2025 models and Autodesk's sample projects of 2015 to 2027 (hashes in `research/bim4lca-measure.tsv`, `research/r2025-models.tsv` and `research/autodesk-sample-projects.tsv`); by counts only, the held-out `ALD26 Project`. +**Probe:** `probes/examples/probe_re319_category_census.rs`, scored by `tools/re/category_census_vs_ifc.py`. +**Status:** positive on Revit 2018's `ALD26 Before` against Revit's own export, the only file with an export that holds any of these categories; no other release's export is measured for them. Cable trays and cable tray fittings are **not recovered** (not measured: no file with a Revit export holds an instance). The centerline categories are never recovered. + +## 1. The census + +`probes/examples/probe_re319_category_census.rs` reads every file through the exporter's own record reader (the 2008 to 2023 `scan_records`, or the 2024 to 2027 product sweep over every category the file's marker frames carry, so a category outside `RECOVERED_CATEGORIES` shows too) and prints, per category, the ElementIds of any decoded frame, of the placed instances the RE-21 rule selects (no container reference, the placed-instance kind) and of those the exporter writes (a 3D body, in the export phase, outside a non-primary design option). `category_census_vs_ifc.py` scores each set against the `Tag`s of Revit's export. Measure run 41726416015 (`-f holdout=true -f samples=true -f nordic=true -f r2025=true -f bimcollab=true -f models="spent-* core-interior einhoven re1-* nordic-office-* r2025-* bimcollab-*"`, head `eba89c8e`). + +Per category, frames with a decoded id / RE-21 instances / written (3D body, phase, option) / of those in Revit's export by `Tag`: + +| file | conduits -2008132 | conduit fittings -2008128 | gutters -2001391 | cable trays -2008130 | cable tray fittings -2008126 | +|---|---|---|---|---|---| +| Vitoria `ALD26 Before` (2018, IFC2X3 export) | 102 / 102 / 102 / **102** | 135 / 74 / 74 / **74** | 2 / 2 / 2 / **2** | none | 5 / 0 / 0 / nothing to score | +| RE1 Electrical, Mechanical, Plumbing (2025); Core Interior (2024); the four BIM4LCA office files (2024); the 29 R2025 models; Einhoven (2023); every `rac` and `rst` sample | none of the five | none | none | none | none | +| Autodesk `rme_advanced` 2015, 2019, 2024 to 2027 (no export) | 19 / 19 / 19 | 32 to 34 / 14 / 14 | none | 17 / 17 / 17 | 48 to 50 / 14 / 14 | +| Autodesk `rme_basic` 2015, 2019, 2024 to 2027 (no export) | 20 / 20 / 20 | 32 to 34 / 14 / 14 | none | none | 14 / 0 / 0 | +| Snowdon Towers Electrical 2024 (no export) | 530 / 530 / 530 | 338 / 322 / 322 | none | none | 24 / 0 / 0 | +| Snowdon Towers HVAC 2024 and Plumbing 2024 (no export) | none | 6 and 15 / 0 / 0 | none | none | 7 and 24 / 0 / 0 | + +RE1 Electrical, which a first reading would take for the file with conduits and trays, has none in its records, and its export holds 14 `IfcFlowTerminal` and no flow segment. The same ElementIds are in every release of `rme_advanced` and `rme_basic` (2015 to 2027), which no export of those samples checks. + +On `ALD26 Before` the census agrees with RE-315 §9: every conduit, conduit fitting and gutter the rule selects is a `Tag` of Revit's export (178 of 178), in `IfcFlowSegment` (102 conduits, 2 gutters) or `IfcFlowFitting` (74 fittings), and none the rule selects is outside the export. The 61 other conduit fitting frames fail the rule (a container reference, or the type symbol's kind). The categories one step beside each, `-2008139` (102 frames) and `-2008141` (74), match the conduits and their fittings one for one, and are in Revit's export as nothing: they are `OST_ConduitCenterLine` and `OST_ConduitFittingCenterLine`, which revit-ifc's `ElementFilteringUtil` lists among the categories it leaves out of the export (cited, not copied), as `-2008045` and `-2008072` (`OST_PipeCurvesCenterLine`, `OST_PipeFittingCenterLine`) are for the 140 pipes and 128 fittings already written. All 444 of the centerline frames the rule selects there (102, 74, 140 and 128) are "not in the export" in the scorer's table, so none is recovered. The ids are Autodesk's published `BuiltInCategory` values: `OST_Conduit` -2008132, `OST_ConduitFitting` -2008128, `OST_CableTray` -2008130, `OST_CableTrayFitting` -2008126, `OST_Gutter` -2001391, `OST_ConduitCenterLine` -2008139, `OST_ConduitFittingCenterLine` -2008141. + +## 2. What is recovered, and what is not + +- **Conduits, conduit fittings, gutters:** recovered, under the unchanged RE-21 rule, with the record's box as the body, on every release the exporter reads (2008 to 2027; the rule and the record layout are those of every other category). Measured against Revit's export on 2018 only. +- **Cable trays and cable tray fittings:** not recovered. No file in the development set that has a Revit export holds an instance of either (the cable tray fittings the rule selects, 14 on each `rme` sample, are on files with no export, and on Vitoria 5 frames fail the rule), so nothing shows that Revit's export writes them, or in which class, or which it leaves out. They stay counted as unattributed frames where the file's layout counts them, and "not measured" here. +- **The centerline categories:** never recovered (above). + +## 3. The class + +Revit's IFC2X3 export of `ALD26 Before` writes conduits and gutters as `IfcFlowSegment` and conduit fittings as `IfcFlowFitting`. rvt-rs writes IFC4. What revit-ifc says (Autodesk's open-source exporter, CLEANROOM source 5: read for what the export writes, cited by file and class, no code taken): + +- `Source/Revit.IFC.Common/Utility/IFCCompatibilityType.cs`, the dictionary `SuperTypeCompatibility`, says which IFC4 subtypes Revit writes as their supertype before IFC4: `IfcCableCarrierSegment`, `IfcCableSegment`, `IfcDuctSegment` and `IfcPipeSegment` as `IfcFlowSegment`; `IfcCableCarrierFitting`, `IfcCableFitting`, `IfcDuctFitting`, `IfcJunctionBox` and `IfcPipeFitting` as `IfcFlowFitting`. It is the IFC4-to-IFC2X3 direction, and it picks no subtype for a category. +- `Source/Revit.IFC.Export/Exporter/FamilyInstanceExporter.cs`, `CanHaveSystemDefinition`, tests the types `IfcCableSegmentType`, `IfcCableCarrierSegmentType`, `IfcCableFittingType` and `IfcCableCarrierFittingType` against `OST_CableTrayFitting` and `OST_ConduitFitting`: a conduit fitting is exported as one of the cable types, which in IFC4 is the cable carrier fitting the compatibility table writes as `IfcFlowFitting`. +- `Source/Revit.IFC.Export/Toolkit/IFC4Enums.cs`: `IFCCableCarrierSegmentType` has `CONDUITSEGMENT`, `IFCPipeSegmentType` has `GUTTER`. +- The category-to-class table that decides the class of each category is Revit's own (`IFCCategoryTemplate`, `ExporterCacheManager.CategoryMappingTemplate`) and is not in revit-ifc's source, so **no source names the IFC4 class of `OST_Conduit`, `OST_ConduitFitting` or `OST_Gutter`**, and no IFC4 export in the development set holds one. + +What is written, then: conduits as `IfcCableCarrierSegment` and their fittings as `IfcCableCarrierFitting`, the IFC4 subtypes of the `IfcFlowSegment` and `IfcFlowFitting` Revit writes (as pipes are `IfcPipeSegment` and `IfcPipeFitting` for the same two), with the cable carrier types chosen from IFC4's own enumerations and revit-ifc's cable fitting handling; **gutters as `IfcFlowSegment`, Revit's own class**, since revit-ifc gives no IFC4 entity for the category (`IfcPipeSegment` has a `GUTTER` type in IFC4, but no source ties Revit's gutter to it). `PredefinedType` stays unset on all three: no IFC4 export shows Revit's value, and the writer never invents an enumerator it did not decode. `IfcFlowSegment` is concrete in IFC4 and declares no `PredefinedType`, so it is written with its eight attributes (`step_writer::ElementTail::Tag`). No type object is written for the three (`IfcCableCarrierSegmentType` and the others are not in `type_entity_for`): a conduit fitting's type name is read and Revit's `Reference` property is written for it, as for every typed element, and 74 of 74 equal Revit's. + +## 4. Bodies + +Boxes, with their `BodySource`, as every other category. RE-131's cylinder is not applied: `attach_pipe_axes` reads a pipe's two ends and radius from its connector entries for the class `Pipe` on Revit 2024 and 2025 only (`partition_pipe_axes::PIPE_AXIS_SUPPORTED_REVIT_VERSIONS`), `ALD26 Before`'s own pipes are boxes, and no file with a conduit and a Revit export is 2024 or 2025, so nothing shows that a conduit's entries read the same way or what Revit's cylinder is. On Revit's export the written conduit boxes are the right ones: of the 104 conduits and gutters the scorer pairs by `Tag`, 102 have a world box within 0.01 ft of Revit's (`duct_bodies_vs_ifc`, worst 3.0 ft; the scorer does not say which two), and Revit's own body fills a median 0.374 of a conduit's box, 0.309 of a conduit fitting's and 0.003 of a gutter's (`box_bodies_vs_ifc`): a conduit is a thin cylinder in its box, a gutter a profile along a roof edge, so the shape is not decoded and `rvt-ifc` counts them with the other bodies that are their record's box. + +## 5. Storey + +Conduits and their fittings sit on the Level their record's list names, as the other MEP categories (RE-107): all 176 on Revit's storey (the 21 elements on another storey are the 14 columns, 4 pipe segments and 3 pipe fittings of RE-315 §7, unchanged). A gutter's record names no Level; Revit's export puts both on `P5`. `Gutter` is in `ELEVATION_PLACED_CLASSES` (RE-68, the classes Revit places by elevation: slab edges, wall sweeps, light fixtures, generic models), and both land on `P5`. That is two elements on one file; the band is the same fail-closed band the other classes use. + +## 6. Result on `ALD26 Before` + +Run 41730511780 (main's side `c28ff053`, head `9ade4f78`, every scorer, no model but the spent pair) and run 41731699676 (head `37838a94`, with the gutters' elevation), measured again at the final head in the unfiltered run of §8. + +| `ALD26 Before` | main | head | Revit's export | +|---|---:|---:|---:| +| elements paired by `Tag` | 1,136 | **1,314** | 1,321 | +| written that Revit's export lacks | 0 | **0** | | +| in Revit's class or IFC4's for its IFC2X3 one | 1,127 | **1,305** | | +| storeys | 7 | 7 | 7 | +| elements on Revit's storey | 1,073 | **1,251** | | +| elements on another storey, on none | 21, 16 | 21, 16 | | + +By Revit's class: 1,314 of 1,321 written. The same class: beams 1, building element proxies 43, columns 114, doors 68, members 206, plates 67, railings 14, roofs 8, slabs 9, stairs 6, stair flights 6, walls (`IfcWall`) 12, windows 70, and now **2 gutters (`IfcFlowSegment`)** (626). In IFC4's class for Revit's IFC2X3 one: 128 `IfcFlowFitting` as `IfcPipeFitting`, 140 `IfcFlowSegment` as `IfcPipeSegment`, 235 `IfcWallStandardCase` as `IfcWall`, and now **74 `IfcFlowFitting` as `IfcCableCarrierFitting` and 102 `IfcFlowSegment` as `IfcCableCarrierSegment`** (679). Another class: 9 `IfcCurtainWall` as `IfcWall` (unchanged). **Missing, 7** (185 before): 4 `IfcWallStandardCase` (the curtain-panel walls of RE-315 §5) and 3 `IfcElementAssembly` (not instances). `IfcFlowSegment` absent 0 (104), `IfcFlowFitting` absent 0 (74). + +The scorers that move (`compare-scorer-diff`, run 41730511780): + +- `class_sets_vs_ifc`: the two rows above; `IfcSpace` extras 73 as before (spaces are paired by GlobalId, which are not Revit's, #878). No extra element. +- `storeys_vs_ifc`: 1,314 elements, 16 on no storey (the 9 proxies, 6 railings and 1 flight of before); 1,251 on Revit's storey, 26 where Revit contains it in an `IfcSpace`, 21 on another, 9 and 7 on none; the 21 are the same 14 columns, 4 pipe segments and 3 pipe fittings as before, none of them a conduit. +- `box_bodies_vs_ifc`: record-box bodies 880 to 1,058 (+102 conduits, +74 fittings, +2 gutters). +- `duct_bodies_vs_ifc`: 0 to 104 flow segments written with a body, 102 of 104 within 0.01 ft of Revit's world box. +- `names_vs_ifc`: 74 conduit fittings equal in name and ObjectType (`M_Codo de tubo - Aluminio:Estándar:`, Revit's own); 102 conduits and 2 gutters differ, as the 140 pipes do (`Conduit-` and `Gutter-` where Revit's is `Tubo con uniones:Tubo:` and `Canalón:Canalón:`: the system family's name is Revit's, in the file's language, and the type name is not read for a system type on Revit 2018). +- `type_objects_vs_ifc`: 74 more typed in ours, every TypeName equal to Revit's (592 to 666); 104 more untyped (the conduits and gutters). +- `psets_vs_ifc`: Revit's values on the objects written 4,961 to 5,317; equal 2,383 to 2,457 (the 74 fittings' `Pset_EnvironmentalImpactIndicators.Reference`); **different 0 to 0; values Revit does not write 20 to 20**; missing 2,578 to 2,860, 282 more, of which `Pset_DistributionFlowElementCommon.Reference` on the 178 (a set Revit writes on these three classes and not on the pipes, and that the Reference allow-list of #1120 does not name, so it is left out) and `Pset_EnvironmentalImpactIndicators.Reference` on the 104 conduits and gutters (no type name read). +- `global_ids_vs_ifc`: none of the elements' GlobalIds is Revit's (#878), as before. +- `schema.txt`: arity, validation, EXPRESS rules and property sets 0 findings; sets 1,668 to 1,742. + +No other scorer moves on this file (`ports_vs_ifc`, `pipe_bodies_vs_ifc`, `qtos_vs_ifc`, `predefined_types_vs_ifc`: unchanged). + +## 7. Other files + + + +## 8. Reproduce + + + +## 9. What stays missing, and what is not measured + +- 4 curtain-panel walls and 3 element assemblies of `ALD26 Before` (RE-315 §9). +- Cable trays and cable tray fittings (above), on every file. +- The class of a conduit, conduit fitting or gutter in an IFC4 export of Revit: no such export holds one. The IFC4 classes are the subtypes of Revit's IFC2X3 ones (conduits and fittings) and Revit's own class (gutters). +- Conduits' and gutters' names, and their `Reference`: Revit 2018 writes `Tubo con uniones:Tubo:`; the system type's name is not read there. +- A conduit's or fitting's `Constraints` Level parameter: `rvt-ifc` writes none for the three classes, since no export measures its name (Revit's own for a pipe segment is `Reference Level`, for a fitting `Level`). +- Ports and connections of conduit fittings: not written (`is_distribution_element` does not name `IfcCableCarrierFitting`), and the 2008 to 2023 path reads no joins at all. +- Conduit and gutter bodies are boxes. From 6c316177c938e696f0ab0d975c4d354144a0d4ee Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 17:48:09 -0500 Subject: [PATCH 07/12] docs(elements): RE-319 says which exports hold none of the categories and what the census's written column is (#1261) (RE-319) --- .../element-framing/RE-319-conduits-conduit-fittings-gutters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md b/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md index 0889677a9..464acb9f3 100644 --- a/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md +++ b/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md @@ -21,7 +21,7 @@ Per category, frames with a decoded id / RE-21 instances / written (3D body, pha | Snowdon Towers Electrical 2024 (no export) | 530 / 530 / 530 | 338 / 322 / 322 | none | none | 24 / 0 / 0 | | Snowdon Towers HVAC 2024 and Plumbing 2024 (no export) | none | 6 and 15 / 0 / 0 | none | none | 7 and 24 / 0 / 0 | -RE1 Electrical, which a first reading would take for the file with conduits and trays, has none in its records, and its export holds 14 `IfcFlowTerminal` and no flow segment. The same ElementIds are in every release of `rme_advanced` and `rme_basic` (2015 to 2027), which no export of those samples checks. +RE1 Electrical, which a first reading would take for the file with conduits and trays, has none in its records, and its export holds 14 `IfcFlowTerminal` and no flow segment. On each export of the second row (RE1, Core Interior, the BIM4LCA files and the R2025 models) every element with a `Tag` is among the instances the probe selects ("export elements not written 0"), and none is in these categories, so none of those exports holds a conduit, conduit fitting, gutter, cable tray or cable tray fitting. The probe's "written" column is the rule, a 3D body, the phase and the design option, not every filter the exporter applies (empty curtain panels, components nested in doors and windows), so its "not in the export" counts on a category the exporter filters further are not the exporter's; for the three categories here the exporter's own output equals it (§6). The same ElementIds are in every release of `rme_advanced` and `rme_basic` (2015 to 2027), which no export of those samples checks. On `ALD26 Before` the census agrees with RE-315 §9: every conduit, conduit fitting and gutter the rule selects is a `Tag` of Revit's export (178 of 178), in `IfcFlowSegment` (102 conduits, 2 gutters) or `IfcFlowFitting` (74 fittings), and none the rule selects is outside the export. The 61 other conduit fitting frames fail the rule (a container reference, or the type symbol's kind). The categories one step beside each, `-2008139` (102 frames) and `-2008141` (74), match the conduits and their fittings one for one, and are in Revit's export as nothing: they are `OST_ConduitCenterLine` and `OST_ConduitFittingCenterLine`, which revit-ifc's `ElementFilteringUtil` lists among the categories it leaves out of the export (cited, not copied), as `-2008045` and `-2008072` (`OST_PipeCurvesCenterLine`, `OST_PipeFittingCenterLine`) are for the 140 pipes and 128 fittings already written. All 444 of the centerline frames the rule selects there (102, 74, 140 and 128) are "not in the export" in the scorer's table, so none is recovered. The ids are Autodesk's published `BuiltInCategory` values: `OST_Conduit` -2008132, `OST_ConduitFitting` -2008128, `OST_CableTray` -2008130, `OST_CableTrayFitting` -2008126, `OST_Gutter` -2001391, `OST_ConduitCenterLine` -2008139, `OST_ConduitFittingCenterLine` -2008141. From 3a81189c6dde0783004c41d3d2e4daf27930e1e8 Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 18:34:15 -0500 Subject: [PATCH 08/12] chore(tools): the category census scorer names the type object Revit's export gives each instance set (#1261) (RE-319) --- tools/re/category_census_vs_ifc.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/re/category_census_vs_ifc.py b/tools/re/category_census_vs_ifc.py index f54446940..419cc0f2b 100644 --- a/tools/re/category_census_vs_ifc.py +++ b/tools/re/category_census_vs_ifc.py @@ -44,6 +44,14 @@ def category_name(element): return str(value) if value else "-" +def type_entity(element): + """The entity and PredefinedType of an element's type object in the export, or "-".""" + type_object = ifcopenshell.util.element.get_type(element) + if type_object is None: + return "-" + return f"{type_object.is_a()}/{getattr(type_object, 'PredefinedType', None) or '-'}" + + def main(argv): listing = "--list" in argv argv = [arg for arg in argv if arg != "--list"] @@ -82,6 +90,8 @@ def main(argv): category_name(elements[i]) for i in rule_ids if i in tags ) shown += "".join(f" | category {name!r} {n}" for name, n in sorted(names.items())) + kinds = collections.Counter(type_entity(elements[i]) for i in rule_ids if i in tags) + shown += "".join(f" | type object {kind} {n}" for kind, n in sorted(kinds.items())) print( f"{category} | {name} | {len(any_ids)} | {len(rule_ids)} ({len(rule_ids & set(tags))}) | " f"{len(wrote)} ({len(wrote & set(tags))}, {len(wrote - set(tags))}) | {shown}" From 753d85a2b2513a17268d76949c25b9214da077f3 Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 18:39:56 -0500 Subject: [PATCH 09/12] feat(ifc): a gutter is an IfcPipeSegment, the entity Revit's export types it by (#1261) (RE-319) --- src/bin/rvt_ifc.rs | 1 - src/ifc/category_map.rs | 19 ++++++++++--------- src/ifc/export_content.rs | 5 +++-- src/ifc/step_writer.rs | 4 ++-- viewer/src/main.ts | 1 - 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/bin/rvt_ifc.rs b/src/bin/rvt_ifc.rs index cdd7c9db5..4ad235471 100644 --- a/src/bin/rvt_ifc.rs +++ b/src/bin/rvt_ifc.rs @@ -985,7 +985,6 @@ fn ifc_type_display(upper: &str) -> String { "IfcDuctSegment", "IfcElectricAppliance", "IfcFlowController", - "IfcFlowSegment", "IfcFooting", "IfcFurniture", "IfcLightFixture", diff --git a/src/ifc/category_map.rs b/src/ifc/category_map.rs index 1a559a307..e281b1de3 100644 --- a/src/ifc/category_map.rs +++ b/src/ifc/category_map.rs @@ -350,14 +350,15 @@ pub const MAPPINGS: &[Mapping] = &[ ifc_type: "IFCPIPEFITTING", predefined_type: None, }, - // RE-319: conduits and their fittings, as the IFC4 subtypes of the - // `IfcFlowSegment` and `IfcFlowFitting` Revit's IFC2X3 export of BIM-Speed - // Vitoria `ALD26 Before` writes for all 102 and 74 (revit-ifc's - // `IFCCompatibilityType` writes both in IFC2X3 as those supertypes). No - // IFC4 export of a conduit is measured, so the `PredefinedType` stays - // unset. A gutter keeps Revit's own `IfcFlowSegment`, a concrete IFC4 - // entity too: revit-ifc names no IFC4 entity for the gutter category - // (its category table is Revit's own, not in the source). + // RE-319: conduits, their fittings and gutters, as the IFC4 subtypes of + // the `IfcFlowSegment` and `IfcFlowFitting` Revit's IFC2X3 export of + // BIM-Speed Vitoria `ALD26 Before` writes for all 102, 74 and 2 (revit-ifc's + // `IFCCompatibilityType` writes the subtypes in IFC2X3 as those + // supertypes). The same export types them by the IFC4 entities these are: + // `IfcCableCarrierSegmentType` (102 of 102), `IfcCableCarrierFittingType` + // (74 of 74) and `IfcPipeSegmentType` with `PredefinedType` `GUTTER` (2 of + // 2). No IFC4 export of one is measured, so the occurrence's + // `PredefinedType` stays unset, as a pipe's does. Mapping { revit_class: "Conduit", ifc_type: "IFCCABLECARRIERSEGMENT", @@ -370,7 +371,7 @@ pub const MAPPINGS: &[Mapping] = &[ }, Mapping { revit_class: "Gutter", - ifc_type: "IFCFLOWSEGMENT", + ifc_type: "IFCPIPESEGMENT", predefined_type: None, }, // Massing / abstract. diff --git a/src/ifc/export_content.rs b/src/ifc/export_content.rs index 74e65319b..1991e4e8c 100644 --- a/src/ifc/export_content.rs +++ b/src/ifc/export_content.rs @@ -1671,8 +1671,9 @@ fn level_parameter_property_set(decoded: &DecodedElement, ifc_type: &str) -> Opt // them), so none is written. if matches!( ifc_type, - "IFCCABLECARRIERSEGMENT" | "IFCCABLECARRIERFITTING" | "IFCFLOWSEGMENT" - ) { + "IFCCABLECARRIERSEGMENT" | "IFCCABLECARRIERFITTING" + ) || decoded.class == "Gutter" + { return None; } let text = |wanted: &str| { diff --git a/src/ifc/step_writer.rs b/src/ifc/step_writer.rs index e7ad266b0..db51eda95 100644 --- a/src/ifc/step_writer.rs +++ b/src/ifc/step_writer.rs @@ -106,7 +106,7 @@ pub fn write_step_to( #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum ElementTail { /// `Tag` only — the entity declares no `PredefinedType` - /// (`IfcFurnishingElement`, `IfcFlowController`, `IfcFlowSegment`). Arity 8. + /// (`IfcFurnishingElement`, `IfcFlowController`). Arity 8. Tag, /// `Tag, PredefinedType` — the shape almost every /// `IfcBuildingElement` subtype takes. Arity 9. @@ -142,7 +142,7 @@ enum ElementTail { /// subtype in IFC4. fn element_tail_for(ifc_upper: &str) -> ElementTail { match ifc_upper { - "IFCFURNISHINGELEMENT" | "IFCFLOWCONTROLLER" | "IFCFLOWSEGMENT" => ElementTail::Tag, + "IFCFURNISHINGELEMENT" | "IFCFLOWCONTROLLER" => ElementTail::Tag, "IFCDOOR" | "IFCWINDOW" => ElementTail::Opening, "IFCSPACE" => ElementTail::Space, "IFCREINFORCINGBAR" => ElementTail::ReinforcingBar, diff --git a/viewer/src/main.ts b/viewer/src/main.ts index 01c5f63d0..97ef48a6a 100644 --- a/viewer/src/main.ts +++ b/viewer/src/main.ts @@ -1504,7 +1504,6 @@ const IFC_ENTITY_NAMES = [ 'IfcDuctSegment', 'IfcElectricAppliance', 'IfcFlowController', - 'IfcFlowSegment', 'IfcFlowTerminal', 'IfcFooting', 'IfcFurnishingElement', From ca84f56ecf006e4c01b1b9c7e8bcb4f4f05f1125 Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 18:40:55 -0500 Subject: [PATCH 10/12] docs(elements): RE-319 cites Revit's type objects for the classes and records the held-out Project's counts (#1261) (RE-319) --- changelog.d/added/1261-conduits-gutters.md | 21 ++++---- docs/evidence.md | 6 +-- docs/reference-models.md | 2 +- docs/support-matrix.json | 2 +- ...E-319-conduits-conduit-fittings-gutters.md | 49 ++++++++++++++----- 5 files changed, 53 insertions(+), 27 deletions(-) diff --git a/changelog.d/added/1261-conduits-gutters.md b/changelog.d/added/1261-conduits-gutters.md index e421f0949..566ccebbd 100644 --- a/changelog.d/added/1261-conduits-gutters.md +++ b/changelog.d/added/1261-conduits-gutters.md @@ -9,15 +9,16 @@ none is outside it: 1,314 of its 1,321 elements are now written (1,136 before), 1,305 of them in Revit's class or IFC4's for its IFC2X3 one (conduits as `IfcCableCarrierSegment`, their fittings as - `IfcCableCarrierFitting`, gutters as Revit's `IfcFlowSegment`, no - `PredefinedType`), and 1,251 on Revit's storey (1,073 before), with every - validation finding at 0 and the properties Revit does not write unchanged at - 20. The 7 still missing are 4 panel walls and 3 assemblies. Cable trays and - cable tray fittings are not recovered, since no file with a Revit export - holds one, and neither are the conduit centerline categories Revit's export - leaves out. Autodesk's MEP samples of 2015 to 2027 (19 or 20 conduits and 14 - conduit fittings on `rme_advanced` and `rme_basic`) and Snowdon Towers - Electrical (530 conduits and 322 fittings) now export them too, counted and - not scored: no Revit export of those files exists. See + `IfcCableCarrierFitting`, gutters as `IfcPipeSegment`, the entities Revit's + own type objects name, with no `PredefinedType`), and 1,251 on Revit's + storey (1,073 before), with every validation finding at 0 and the + properties Revit does not write unchanged at 20. The 7 still missing are 4 + panel walls and 3 assemblies. Cable trays and cable tray fittings are not + recovered, since no file with a Revit export holds one, and neither are the + conduit centerline categories Revit's export leaves out. Autodesk's MEP + samples of 2015 to 2027 (19 or 20 conduits and 14 conduit fittings on + `rme_advanced` and `rme_basic`) and Snowdon Towers Electrical (530 conduits + and 322 fittings) now export them too, counted and not scored: no Revit + export of those files exists. See [RE-319](reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md) (#1261). diff --git a/docs/evidence.md b/docs/evidence.md index c5b399111..906c4b590 100644 --- a/docs/evidence.md +++ b/docs/evidence.md @@ -17,7 +17,7 @@ The recovery figures in this README compare rvt-rs's export with Revit's own IFC | Revit 2027 projects | yes; 325 fields of the 2027 schema carry a flag whose meaning is not measured (RE-264) | **experimental (since 0.6.0):** typed IFC entities from each element's record, with the constants the file's schema gives (RE-179); on Autodesk's five 2027 sample projects the same ElementIds and classes as their 2026 copies (20,818 of 20,818), with **no Revit 2027 export measured** | as on 2026 | as on 2026: storeys, rooms (their outline as on 2025, RE-314), doors and windows in their hosts, family and type names, layer sets, wall joins and mullion materials read the same as the 2026 copies; 79 corner mullions are not put in a curtain wall | | Revit 2023 projects | yes | typed IFC entities (since 0.4.0) from each element's record (RE-81): on two 2023 projects every element of Revit's export (modelo_bim, 37 of 37) or all but the 8 window trims nested in windows (Exemplo_data, 37 of 45), none outside it | the element's bounding box, walls cut back by the walls they join (Exemplo_data 17 of 17 and modelo_bim 4 of 4 as Revit's, RE-120), beams stopped at the faces of the columns they frame into (modelo_bim 8 of 8, RE-122); rooms their outline (RE-102) | ElementId, category, each door's and window's host wall (30 of 30 as Revit's, RE-85), and the storeys of Revit's own Levels with each element on the one its record names, a beam on the one at its top (Exemplo_data 37 of 37 and modelo_bim 37 of 37 in Revit's storey, RE-107, RE-119), each family instance's family and type name (50 of 50 as Revit names them, RE-109), each wall's, floor's and roof's type and system family (24 of 24 with Revit's type, RE-111, RE-112), family instances' materials (44 of 45 as Revit's, RE-113), and layer sets, named by their own or their category's material (RE-114, RE-115): Exemplo_data 36 of 37 and modelo_bim 31 of 37 elements with Revit's materials, and materials with Revit's shading colours (20 of 21, none different, RE-116); no layered or angled joins or IFC export overrides, and the diagnostics say so; on 2016 to 2023, elements in a non-primary design option or outside the export phase are left out since RE-315 | | Revit 2019 to 2022 projects | yes | **experimental (since 0.6.0):** typed IFC entities from each element's record, which 2019 to 2022 frame as 2023 does, read with the tags each release's schema gives (RE-180); on Autodesk's 2019 to 2022 sample projects every ElementId shared with the 2023 copy has the class it has there (`rac_basic`, `rst_basic` and `rac_advanced` of each release), with **no Revit export of a 2019 to 2022 file measured** | as on 2023 | as on 2023: storeys, doors and windows in their hosts, family and type names, layer sets and materials read as the 2023 copies do, with a few type names and type materials different (RE-180 §6) | -| Revit 2015 to 2018 projects | yes on 2016 to 2018; on 2015, partial: they open on Autodesk's sample projects, and previews and PartAtom are not measured | **experimental (since 0.6.0):** typed IFC entities from each element's record, which 2015 to 2018 frame as 2019 does, read with the tags each release's schema gives (RE-181); on Autodesk's 2016, 2017 and 2018 sample projects every ElementId shared with the 2019 copy has the class it has there (`rac_basic`, `rst_basic` and `rac_advanced` of each release), and on five of its six 2015 sample projects (the sixth is another model), with **Revit's own export measured on one 2015 project and one 2018 project**: BIMcollab's structural example (RE-198, a public download, not redistributable) has all 241 of Revit's elements by ElementId, each in Revit's class or IFC4's for its IFC2X3 one, 3 air terminals Revit's export leaves out (#879), 16 footings on no storey and none of its elements' GlobalIds Revit's (#878); BIM-Speed's Vitoria `ALD26 Before` (2018, CC BY 4.0), most of whose frames carry no ElementId of their own and sit in their element's record (RE-315), has 1,314 of Revit's 1,321 elements by ElementId (1,136 before its 102 conduits, 74 conduit fittings and 2 gutters were recovered, RE-319), 1,305 of them in Revit's class or IFC4's for its IFC2X3 one (9 curtain walls are written as walls), none written that Revit's export leaves out, 1,251 on Revit's storey, and 7 storeys, as many as Revit's; the 7 missing are 4 panel walls and 3 assemblies, and its held-out sibling writes @@HELD@@ elements and spaces against Revit's 1,520, counts only, none of its elements one that Revit's export lacks (198 were, until the export phase and design options were applied, which the counts cannot tell apart); 2014's element records are read as 2015's are, measured on one local 2014 file only (RE-259, the row below) | as on 2019 | as on 2019: storeys, doors and windows in their hosts, family and type names, layer sets and materials read as the 2019 copies do, but where the files' own bytes differ (RE-181 §6) | +| Revit 2015 to 2018 projects | yes on 2016 to 2018; on 2015, partial: they open on Autodesk's sample projects, and previews and PartAtom are not measured | **experimental (since 0.6.0):** typed IFC entities from each element's record, which 2015 to 2018 frame as 2019 does, read with the tags each release's schema gives (RE-181); on Autodesk's 2016, 2017 and 2018 sample projects every ElementId shared with the 2019 copy has the class it has there (`rac_basic`, `rst_basic` and `rac_advanced` of each release), and on five of its six 2015 sample projects (the sixth is another model), with **Revit's own export measured on one 2015 project and one 2018 project**: BIMcollab's structural example (RE-198, a public download, not redistributable) has all 241 of Revit's elements by ElementId, each in Revit's class or IFC4's for its IFC2X3 one, 3 air terminals Revit's export leaves out (#879), 16 footings on no storey and none of its elements' GlobalIds Revit's (#878); BIM-Speed's Vitoria `ALD26 Before` (2018, CC BY 4.0), most of whose frames carry no ElementId of their own and sit in their element's record (RE-315), has 1,314 of Revit's 1,321 elements by ElementId (1,136 before its 102 conduits, 74 conduit fittings and 2 gutters were recovered, RE-319), 1,305 of them in Revit's class or IFC4's for its IFC2X3 one (9 curtain walls are written as walls), none written that Revit's export leaves out, 1,251 on Revit's storey, and 7 storeys, as many as Revit's; the 7 missing are 4 panel walls and 3 assemblies, and its held-out sibling writes 1,514 elements and spaces against Revit's 1,520, counts only, none of its elements one that Revit's export lacks (198 were, until the export phase and design options were applied, which the counts cannot tell apart); 2014's element records are read as 2015's are, measured on one local 2014 file only (RE-259, the row below) | as on 2019 | as on 2019: storeys, doors and windows in their hosts, family and type names, layer sets and materials read as the 2019 copies do, but where the files' own bytes differ (RE-181 §6) | | Revit 2011 to 2014 projects | yes: 2011 to 2013 open since RE-259, whose schemas have no GUID lists; measured on local closed-source files only, outside the 1.0 range (2015 to 2027) | **experimental:** typed IFC entities from each element's record, which 2011 to 2014 frame as 2015 does, read with the tags each release's schema gives (RE-259); on a local copy of Autodesk's 2013 `rac_advanced` sample every ElementId shared with its 2015 copy has the class it has there and 62,071 of 62,153 fields agree, with **no Revit export of a file before 2015 measured** and no same-model pair for 2011, 2012 or 2014 | as on 2015 | as on 2015: storeys, doors and windows in their hosts, family and type names, layer sets and materials read as the 2015 copy does, but where the files' own bytes differ (RE-259 §7) | | Revit 2008 to 2010 projects | yes: they open and report their release, which 2008 and 2009 take from their build date (RE-259); measured on local closed-source files only, outside the 1.0 range (2015 to 2027) | **experimental:** typed IFC entities from each element's record, which 2009 and 2010 frame as 2011 does and 2008 4 bytes shorter (RE-260); on one local 2009 project 8 doors and their wall, on one 2008 project one generic model, with **no Revit export and no same-model copy of any 2008 to 2010 file measured** | as on 2015 | storeys with their names and elevations (RE-260, also on 2011 and 2012), materials named and coloured; type names, layer sets and hosts as on 2015 but not measured | | Families (`.rfa`) | yes | family metadata, OmniClass, previews; no family geometry | none | a family's types and type parameters as its `PartAtom` stream lists them (`rvt-info`, `PartAtom::family_types`) | @@ -72,7 +72,7 @@ On Revit 2024 and 2025 project files, rvt-rs reads each element from its partiti | Railings, curtain panels, mullions | `IfcRailing`, `IfcPlate`, `IfcMember` | Snowdon Towers 131 railings, every mullion | | Furniture, casework, plumbing, lighting, equipment | `IfcFurniture`, `IfcSanitaryTerminal`, `IfcLightFixture`, `IfcElectricAppliance`, proxies | RE1 models and Snowdon Towers, every one Revit exports | | Ducts, pipes, fittings, air terminals | `IfcDuctSegment`, `IfcPipeSegment` drawn as its cylinder where its ends are proven (RE-131), their fittings, `IfcAirTerminal` | RE1 Mechanical and Plumbing, every one; all 69 pipes are Revit's cylinder, its radius, axis ends and length to 0.00001 ft, and so are the BIM4LCA office's 12 (Revit 2024) | -| Conduits, conduit fittings, gutters | `IfcCableCarrierSegment`, `IfcCableCarrierFitting`, `IfcFlowSegment` (gutters), each drawn as its record's box, no `PredefinedType` (RE-319) | BIM-Speed Vitoria `ALD26 Before` (Revit 2018, IFC2X3 export), the one file with an export that holds any: all 102 conduits, 74 fittings and 2 gutters the instance rule selects are elements of Revit's export by `Tag`, none outside it, all 178 on the storey of Revit's (the 2 gutters by their elevation); the boxes of 102 of the 104 conduits and gutters within 0.01 ft of Revit's. Autodesk's `rme_basic` and `rme_advanced` of 2015 to 2027 and Snowdon Towers Electrical export them too, counted and not scored (no Revit export). Cable trays and cable tray fittings are not exported: no export holds one | +| Conduits, conduit fittings, gutters | `IfcCableCarrierSegment`, `IfcCableCarrierFitting`, `IfcPipeSegment` (gutters), each drawn as its record's box, no `PredefinedType` (RE-319) | BIM-Speed Vitoria `ALD26 Before` (Revit 2018, IFC2X3 export), the one file with an export that holds any: all 102 conduits, 74 fittings and 2 gutters the instance rule selects are elements of Revit's export by `Tag`, none outside it, all 178 on the storey of Revit's (the 2 gutters by their elevation); the boxes of 102 of the 104 conduits and gutters within 0.01 ft of Revit's. Autodesk's `rme_basic` and `rme_advanced` of 2015 to 2027 and Snowdon Towers Electrical export them too, counted and not scored (no Revit export). Cable trays and cable tray fittings are not exported: no export holds one | | Electrical and mechanical devices and equipment | `IfcAlarm` (fire alarm devices), `IfcElectricAppliance` (data devices), proxies (switches, sensors, receptacles, junction boxes, panels, mechanical equipment) | RE1 Electrical and Mechanical, every one Revit exports and nothing else; the symbols nested in switches and receptacles left out, as Revit leaves them out (RE-79) | | Structural framing, columns, foundations | `IfcBeam` along its location line, `IfcColumn`, `IfcFooting` | Snowdon structural sample: all 1,078 in the category its VIM export gives them; 923 of 942 beams run along their line, with Revit's own section on 613 of the 839 a later edition kept unchanged, and on 179 more less the top a floor join cuts (RE-49); 377 steel beams and 40 steel columns are their type's I section, Revit's own on all 271 beams and 24 columns the VIM scores (RE-103, RE-104) | | Site elements, generic models, slab edges, elevators, ramps | proxies, `IfcTransportElement`, `IfcRamp` | Snowdon Towers, every one Revit exports | @@ -104,7 +104,7 @@ Across Autodesk's Snowdon Towers architectural sample (Revit 2024), rvt-rs expor Core Interior and the RE1 models are licensed test files and run in CI. The BIM4LCA office and puzzbobb's Revit 2025 models are fetched by Measure. Snowdon Towers, the 255ribeiro projects, the 2026 house and BIMcollab's 2015 example have no licence to redistribute and are measured locally (BIMcollab's and the holdout pack's summary counts leave Measure's runner), so those figures cannot be re-run by others. By ElementId the exports equal Revit's on Core Interior (970), RE1 Architecture (84), Electrical (49) and Mechanical (74), the 22 R2025 models with an export and the office as built (12,974); RE1 Plumbing writes a water closet tank (442378) and the office at building permit a column (1927742, #792) that Revit's export leaves out, and one office fixture (3095244) is in another IFC class than Revit's (#792) (Measure run 40927543524). Parts Revit's exporter splits one element into under one ElementId (a roof or slab, #323) count once. -All of the above were used to develop the decoder. Three models that were not, Autodesk's Snowdon Towers Plumbing, HVAC and Electrical samples (2024), were measured once as they are against the VIM export of the sample: every exported element the VIM holds is in the expected category (10,385), every VIM instance both hold is exported, and all storeys and GlobalIds agree ([held-out report](../reports/validation/held-out-snowdon-mep-2026-09-27.md), #408). Their bodies are bounding boxes. Six Revit 2018 to 2021 projects with their release's own export were added to Measure on 2026-11-03. On that first measurement both Revit 2018 saves of one building exported no element, and the 2020 and 2021 projects 151 of 151, 199 of 203, 710 of 710 and 1,698 of 1,714 of the elements Revit exports, by Tag (#1261). None met W4, W6 and W7 then, so under W5 all six are used up: they stay in Measure as held-out regression checks, counts only, and are never developed on. One of the 2018 saves, `ALD26 Before`, was spent to find the cause and is now a development file: since RE-315 it writes 1,136 of Revit's 1,321 elements and all 73 of its spaces, and its held-out sibling `ALD26 Project` writes 1,336 elements and spaces against Revit's 1,520, with none that Revit's export lacks ([reference models](reference-models.md)). +All of the above were used to develop the decoder. Three models that were not, Autodesk's Snowdon Towers Plumbing, HVAC and Electrical samples (2024), were measured once as they are against the VIM export of the sample: every exported element the VIM holds is in the expected category (10,385), every VIM instance both hold is exported, and all storeys and GlobalIds agree ([held-out report](../reports/validation/held-out-snowdon-mep-2026-09-27.md), #408). Their bodies are bounding boxes. Six Revit 2018 to 2021 projects with their release's own export were added to Measure on 2026-11-03. On that first measurement both Revit 2018 saves of one building exported no element, and the 2020 and 2021 projects 151 of 151, 199 of 203, 710 of 710 and 1,698 of 1,714 of the elements Revit exports, by Tag (#1261). None met W4, W6 and W7 then, so under W5 all six are used up: they stay in Measure as held-out regression checks, counts only, and are never developed on. One of the 2018 saves, `ALD26 Before`, was spent to find the cause and is now a development file: since RE-315 and RE-319 it writes 1,314 of Revit's 1,321 elements and all 73 of its spaces, and its held-out sibling `ALD26 Project` writes 1,514 elements and spaces against Revit's 1,520, with none that Revit's export lacks ([reference models](reference-models.md)). ## What does not work yet diff --git a/docs/reference-models.md b/docs/reference-models.md index 71a454328..d7c68fcd5 100644 --- a/docs/reference-models.md +++ b/docs/reference-models.md @@ -34,7 +34,7 @@ lists the local-only files with their source and hash, and never fetches them. | 255ribeiro Projeto1, `teste_export_2025` | 2025 | none declared, local only | IFC4X3 CoordinationView; IFC4 DesignTransferView 1.0, Revit 25.4 (PTB) | metric projects; IFC export overrides; files saved in `PTB` (RE-123) | | 255ribeiro `Exemplo_data`, `modelo_bim` | 2023 | none declared, local only | IFC4 ReferenceView 1.2, Revit 23.1 (`Exemplo_data`); IFC4 DesignTransferView 1.0, Revit 26.2 PTB (`modelo_bim`, exported from the 2023 file by a later Revit) | Revit 2023 element records (RE-81 to RE-122): 37 of 37 and 37 of 45 elements, storeys, types, layers, materials, wall joins, beams; files saved in `PTB` | | BIMcollab example, structural model (`02_BIMcollab_Example_STR`) | 2015 | none stated, local only; BIMcollab's public example project (`research/bimcollab-models.tsv`, fetched by Measure with `-f bimcollab=true`, STE1200's pointer) | IFC2X3 CoordinationView 2.0, Revit Architecture 2015, 2014-10-08, rewritten by Solibri's IFC Optimizer; the model was renamed after it | held out when measured (RE-198); RE-208 and RE-220 have since used it, so it no longer counts as held out: all 241 exported elements by ElementId, in Revit's class or IFC4's for its IFC2X3 one, 3 more written, GlobalIds not in the file (#878, RE-208), 16 footings on no storey (#879); wall faces and layer sets as Revit's | -| BIM-Speed Vitoria (`ALD26 Before`, `ALD26 Project`), Frigento, Gdynia, Warmond | 2018, 2018, 2020, 2021, 2021 | CC BY 4.0 (TU Berlin DepositOnce, doi:10.14279/depositonce-16441); fetched by Measure with `-f holdout=true` (`research/holdout-archive-models.tsv`) | each release's own export: IFC2X3 CoordinationView 2.0 (Vitoria, Gdynia), IFC4 DesignTransferView (Frigento), IFC4 passed through BIMServer.center's preprocessor (Warmond); the IFC2X3 exports and Warmond's are counted apart and never remove a value | **held out** (Griffin, 2026-11-03): measured before any fix, counts only; the first same-release pairs for 2018, 2020 and 2021 (#408, #1261). Before any fix (run 41658225355): both Vitoria saves export no element against Revit's 1,394 and 1,520. Every Autodesk 2018 sample exports its elements, so `ALD26 Before` is spent to find why (measured in full as `spent-bimspeed-vitoria-before-2018`) and `ALD26 Project` stays held out as the check. After RE-315 (frames with no ElementId of their own take their record's, run 41707934595): `ALD26 Before` writes 1,136 of Revit's 1,321 elements by Tag, 1,127 of them in Revit's class or IFC4's, with none that Revit's export lacks, on 7 storeys; `ALD26 Project` first wrote 1,534 elements and spaces against Revit's 1,520, counts only, 198 of them elements Revit's export does not hold, and writes 1,336 (1,263 elements and 73 spaces) with none, since the export phase and design options are applied to Revit 2016 to 2023 (the counts cannot tell which of the two removed them); Frigento, Gdynia and Warmond export byte for byte as before. Before any fix, Frigento 151 of 151 elements paired by Tag, Gdynia 199 of 203 (18 of 19 spaces), Warmond 710 of 710 (179 of 179 spaces); an element is counted as found by its Tag, whatever its class | +| BIM-Speed Vitoria (`ALD26 Before`, `ALD26 Project`), Frigento, Gdynia, Warmond | 2018, 2018, 2020, 2021, 2021 | CC BY 4.0 (TU Berlin DepositOnce, doi:10.14279/depositonce-16441); fetched by Measure with `-f holdout=true` (`research/holdout-archive-models.tsv`) | each release's own export: IFC2X3 CoordinationView 2.0 (Vitoria, Gdynia), IFC4 DesignTransferView (Frigento), IFC4 passed through BIMServer.center's preprocessor (Warmond); the IFC2X3 exports and Warmond's are counted apart and never remove a value | **held out** (Griffin, 2026-11-03): measured before any fix, counts only; the first same-release pairs for 2018, 2020 and 2021 (#408, #1261). Before any fix (run 41658225355): both Vitoria saves export no element against Revit's 1,394 and 1,520. Every Autodesk 2018 sample exports its elements, so `ALD26 Before` is spent to find why (measured in full as `spent-bimspeed-vitoria-before-2018`) and `ALD26 Project` stays held out as the check. After RE-315 (frames with no ElementId of their own take their record's, run 41707934595): `ALD26 Before` writes 1,136 of Revit's 1,321 elements by Tag, 1,127 of them in Revit's class or IFC4's, with none that Revit's export lacks, on 7 storeys; `ALD26 Project` first wrote 1,534 elements and spaces against Revit's 1,520, counts only, 198 of them elements Revit's export does not hold, and writes 1,336 (1,263 elements and 73 spaces) with none, since the export phase and design options are applied to Revit 2016 to 2023 (the counts cannot tell which of the two removed them); Frigento, Gdynia and Warmond export byte for byte as before. After RE-319 (conduits, conduit fittings and gutters, run 41733219416): `ALD26 Before` writes 1,314 of Revit's 1,321 elements by Tag, 1,305 of them in Revit's class or IFC4's, with none that Revit's export lacks, 1,251 on Revit's storey; `ALD26 Project` writes 1,514 elements and spaces (1,441 elements and 73 spaces) against Revit's 1,520, counts only, none that Revit's export lacks, 1,433 of the 1,441 elements in Revit's class or IFC4's and 1,359 on Revit's storey; the other held-out pairs export byte for byte as before. Before any fix, Frigento 151 of 151 elements paired by Tag, Gdynia 199 of 203 (18 of 19 spaces), Warmond 710 of 710 (179 of 179 spaces); an element is counted as found by its Tag, whatever its class | | BIM Whale `AdvancedProject` | 2021 | the IFC from andrewisen/bim-whale-ifc-samples (MIT); the `.rvt` from the Dropbox link its README gives, under the README's "feel free to use these files however you like"; fetched by Measure with `-f holdout=true` | IFC2X3 CoordinationView 2.0, exporter 21.1.10.26, counted apart | **held out** (Griffin, 2026-11-03): before any fix it had 1,698 of 1,714 elements paired by Tag (456 of them in another class than Revit's: 407 `IfcFurniture` for `IfcFurnishingElement`, 49 `IfcSanitaryTerminal` for `IfcFlowTerminal`) and none of its 8 spaces. Those spaces are Revit Areas of a 'Rentable' scheme, not rooms; rvt-rs reads Areas on Revit 2024 only. It was briefly spent on 2026-11-03 to look for the cause and restored. While spent it was measured in full in four runs (41661841411, 41668542833, 41671242397 and 41672953553, their artifacts deleted), and the RE-315 work read its record chain and frame counts beside Vitoria's; no rule or constant came from it (#1261, #1286) | ## Candidates, not yet measured here diff --git a/docs/support-matrix.json b/docs/support-matrix.json index cbc592e93..d1043b1f2 100644 --- a/docs/support-matrix.json +++ b/docs/support-matrix.json @@ -248,7 +248,7 @@ "name": "Conduits, conduit fittings and gutters from partition element records (RE-319)", "status": "experimental", "evidence": "partition_element_records::PRODUCT_RECORD_CATEGORIES and RECOVERED_CATEGORIES (OST_CONDUITS, OST_CONDUIT_FITTING, OST_GUTTER); probes/examples/probe_re319_category_census.rs; tools/re/category_census_vs_ifc.py; reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md", - "notes": "Three BuiltInCategory values (OST_Conduit, OST_ConduitFitting, OST_Gutter) decode under the unchanged RE-21 instance rule on every release the exporter reads. Measured against Revit's own export on one file, BIM-Speed's Vitoria ALD26 Before (Revit 2018, IFC2X3, CC BY 4.0): all 102 conduits, 74 conduit fittings and 2 gutters the rule selects are Tags of Revit's export and none is outside it, so 1,314 of its 1,321 elements are written (1,136 before), 1,305 of them in Revit's class or IFC4's for its IFC2X3 one, 1,251 on Revit's storey (1,073 before), with no validation finding and the values Revit does not write unchanged at 20; the 7 missing are 4 panel walls and 3 assemblies. Entities: IfcCableCarrierSegment and IfcCableCarrierFitting, the IFC4 subtypes of the IfcFlowSegment and IfcFlowFitting Revit's IFC2X3 export writes, and IfcFlowSegment for gutters; no IFC4 export of any of the three exists in the development set, so PredefinedType is left unset. Bodies are the record bounding box: the 102 conduit and gutter boxes within 0.01 ft of Revit's world box are 102 of 104 (the scorer does not say which two). Not measured: any release but 2018 against an export; Autodesk's rme_basic and rme_advanced samples of 2015 to 2027 (19 or 20 conduits, 14 fittings) and Snowdon Towers Electrical (530 conduits, 322 fittings) export them too, counted and not scored since no Revit export of them exists. Cable trays and cable tray fittings (OST_CableTray, OST_CableTrayFitting) are not recovered: no file with a Revit export holds an instance of either. The conduit and conduit fitting centerline categories (OST_ConduitCenterLine, OST_ConduitFittingCenterLine), which revit-ifc leaves out of the export, are never recovered. Conduit and gutter names are not read on Revit 2018 (Name differs, as for pipes), and no Constraints Level parameter is written for the three classes.", + "notes": "Three BuiltInCategory values (OST_Conduit, OST_ConduitFitting, OST_Gutter) decode under the unchanged RE-21 instance rule on every release the exporter reads. Measured against Revit's own export on one file, BIM-Speed's Vitoria ALD26 Before (Revit 2018, IFC2X3, CC BY 4.0): all 102 conduits, 74 conduit fittings and 2 gutters the rule selects are Tags of Revit's export and none is outside it, so 1,314 of its 1,321 elements are written (1,136 before), 1,305 of them in Revit's class or IFC4's for its IFC2X3 one, 1,251 on Revit's storey (1,073 before), with no validation finding and the values Revit does not write unchanged at 20; the 7 missing are 4 panel walls and 3 assemblies. Entities: IfcCableCarrierSegment, IfcCableCarrierFitting and IfcPipeSegment (gutters), the IFC4 subtypes of the IfcFlowSegment and IfcFlowFitting Revit's IFC2X3 export writes, which its type objects name (IfcCableCarrierSegmentType 102 of 102, IfcCableCarrierFittingType 74 of 74, IfcPipeSegmentType 2 of 2); no IFC4 export of any of the three exists in the development set, so PredefinedType is left unset. Bodies are the record bounding box: the 102 conduit and gutter boxes within 0.01 ft of Revit's world box are 102 of 104 (the scorer does not say which two). Not measured: any release but 2018 against an export; Autodesk's rme_basic and rme_advanced samples of 2015 to 2027 (19 or 20 conduits, 14 fittings) and Snowdon Towers Electrical (530 conduits, 322 fittings) export them too, counted and not scored since no Revit export of them exists. Cable trays and cable tray fittings (OST_CableTray, OST_CableTrayFitting) are not recovered: no file with a Revit export holds an instance of either. The conduit and conduit fitting centerline categories (OST_ConduitCenterLine, OST_ConduitFittingCenterLine), which revit-ifc leaves out of the export, are never recovered. Conduit and gutter names are not read on Revit 2018 (Name differs, as for pipes), and no Constraints Level parameter is written for the three classes.", "user_impact": "Projects with conduits, conduit fittings or roof gutters export them as IFC elements with their Revit ElementIds and storeys, drawn as their record's box; on the one Revit 2018 project with a Revit export every one is an element Revit also exports. Cable trays are not exported." }, { diff --git a/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md b/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md index 464acb9f3..91457859f 100644 --- a/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md +++ b/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md @@ -15,7 +15,7 @@ Per category, frames with a decoded id / RE-21 instances / written (3D body, pha | file | conduits -2008132 | conduit fittings -2008128 | gutters -2001391 | cable trays -2008130 | cable tray fittings -2008126 | |---|---|---|---|---|---| | Vitoria `ALD26 Before` (2018, IFC2X3 export) | 102 / 102 / 102 / **102** | 135 / 74 / 74 / **74** | 2 / 2 / 2 / **2** | none | 5 / 0 / 0 / nothing to score | -| RE1 Electrical, Mechanical, Plumbing (2025); Core Interior (2024); the four BIM4LCA office files (2024); the 29 R2025 models; Einhoven (2023); every `rac` and `rst` sample | none of the five | none | none | none | none | +| RE1 Electrical, Mechanical, Plumbing (2025); Core Interior (2024); the four BIM4LCA office files (2024); the 24 R2025 models; Einhoven (2023); every `rac` and `rst` sample | none of the five | none | none | none | none | | Autodesk `rme_advanced` 2015, 2019, 2024 to 2027 (no export) | 19 / 19 / 19 | 32 to 34 / 14 / 14 | none | 17 / 17 / 17 | 48 to 50 / 14 / 14 | | Autodesk `rme_basic` 2015, 2019, 2024 to 2027 (no export) | 20 / 20 / 20 | 32 to 34 / 14 / 14 | none | none | 14 / 0 / 0 | | Snowdon Towers Electrical 2024 (no export) | 530 / 530 / 530 | 338 / 322 / 322 | none | none | 24 / 0 / 0 | @@ -33,14 +33,18 @@ On `ALD26 Before` the census agrees with RE-315 §9: every conduit, conduit fitt ## 3. The class -Revit's IFC2X3 export of `ALD26 Before` writes conduits and gutters as `IfcFlowSegment` and conduit fittings as `IfcFlowFitting`. rvt-rs writes IFC4. What revit-ifc says (Autodesk's open-source exporter, CLEANROOM source 5: read for what the export writes, cited by file and class, no code taken): +Revit's IFC2X3 export of `ALD26 Before` writes conduits and gutters as `IfcFlowSegment` and conduit fittings as `IfcFlowFitting`. rvt-rs writes IFC4. -- `Source/Revit.IFC.Common/Utility/IFCCompatibilityType.cs`, the dictionary `SuperTypeCompatibility`, says which IFC4 subtypes Revit writes as their supertype before IFC4: `IfcCableCarrierSegment`, `IfcCableSegment`, `IfcDuctSegment` and `IfcPipeSegment` as `IfcFlowSegment`; `IfcCableCarrierFitting`, `IfcCableFitting`, `IfcDuctFitting`, `IfcJunctionBox` and `IfcPipeFitting` as `IfcFlowFitting`. It is the IFC4-to-IFC2X3 direction, and it picks no subtype for a category. -- `Source/Revit.IFC.Export/Exporter/FamilyInstanceExporter.cs`, `CanHaveSystemDefinition`, tests the types `IfcCableSegmentType`, `IfcCableCarrierSegmentType`, `IfcCableFittingType` and `IfcCableCarrierFittingType` against `OST_CableTrayFitting` and `OST_ConduitFitting`: a conduit fitting is exported as one of the cable types, which in IFC4 is the cable carrier fitting the compatibility table writes as `IfcFlowFitting`. +**Revit's own type objects** name the IFC4 entity. The same export types each element by a type object, and `class_sets_vs_ifc` and `category_census_vs_ifc` read it (runs 41730511780 and 41740219735): the 102 conduits by `IfcCableCarrierSegmentType` (`PredefinedType` `NOTDEFINED`), the 74 conduit fittings by `IfcCableCarrierFittingType` (`NOTDEFINED`) and the 2 gutters by `IfcPipeSegmentType` with `PredefinedType` `GUTTER`; its 140 pipes by `IfcPipeSegmentType` (`NOTDEFINED`) and 128 pipe fittings by `IfcPipeFittingType`, which rvt-rs already writes as `IfcPipeSegment` and `IfcPipeFitting`. So the IFC4 entities are `IfcCableCarrierSegment`, `IfcCableCarrierFitting` and `IfcPipeSegment`, each a subtype of the `IfcFlowSegment` or `IfcFlowFitting` Revit writes for the occurrence. + +What revit-ifc says (Autodesk's open-source exporter, CLEANROOM source 5: read for what the export writes, cited by file and class, no code taken): + +- `Source/Revit.IFC.Common/Utility/IFCCompatibilityType.cs`, the dictionary `SuperTypeCompatibility`, says which IFC4 subtypes Revit writes as their supertype before IFC4: `IfcCableCarrierSegment`, `IfcCableSegment`, `IfcDuctSegment` and `IfcPipeSegment` as `IfcFlowSegment`; `IfcCableCarrierFitting`, `IfcCableFitting`, `IfcDuctFitting`, `IfcJunctionBox` and `IfcPipeFitting` as `IfcFlowFitting`. It is the IFC4-to-IFC2X3 direction, and it picks no subtype for a category; it is why the occurrences are `IfcFlowSegment` and `IfcFlowFitting` in this export. +- `Source/Revit.IFC.Export/Exporter/FamilyInstanceExporter.cs`, `CanHaveSystemDefinition`, tests the types `IfcCableSegmentType`, `IfcCableCarrierSegmentType`, `IfcCableFittingType` and `IfcCableCarrierFittingType` against `OST_CableTrayFitting` and `OST_ConduitFitting`: a conduit fitting is exported as one of the cable types. - `Source/Revit.IFC.Export/Toolkit/IFC4Enums.cs`: `IFCCableCarrierSegmentType` has `CONDUITSEGMENT`, `IFCPipeSegmentType` has `GUTTER`. -- The category-to-class table that decides the class of each category is Revit's own (`IFCCategoryTemplate`, `ExporterCacheManager.CategoryMappingTemplate`) and is not in revit-ifc's source, so **no source names the IFC4 class of `OST_Conduit`, `OST_ConduitFitting` or `OST_Gutter`**, and no IFC4 export in the development set holds one. +- The category-to-class table that decides the class of each category is Revit's own (`IFCCategoryTemplate`, `ExporterCacheManager.CategoryMappingTemplate`) and is not in revit-ifc's source, so **revit-ifc names the IFC4 class of none of `OST_Conduit`, `OST_ConduitFitting` and `OST_Gutter`**. The class of the gutter, `IfcPipeSegment`, therefore rests on the type objects of Revit's own export (2 of 2) and on IFC4's `GUTTER`, not on revit-ifc. -What is written, then: conduits as `IfcCableCarrierSegment` and their fittings as `IfcCableCarrierFitting`, the IFC4 subtypes of the `IfcFlowSegment` and `IfcFlowFitting` Revit writes (as pipes are `IfcPipeSegment` and `IfcPipeFitting` for the same two), with the cable carrier types chosen from IFC4's own enumerations and revit-ifc's cable fitting handling; **gutters as `IfcFlowSegment`, Revit's own class**, since revit-ifc gives no IFC4 entity for the category (`IfcPipeSegment` has a `GUTTER` type in IFC4, but no source ties Revit's gutter to it). `PredefinedType` stays unset on all three: no IFC4 export shows Revit's value, and the writer never invents an enumerator it did not decode. `IfcFlowSegment` is concrete in IFC4 and declares no `PredefinedType`, so it is written with its eight attributes (`step_writer::ElementTail::Tag`). No type object is written for the three (`IfcCableCarrierSegmentType` and the others are not in `type_entity_for`): a conduit fitting's type name is read and Revit's `Reference` property is written for it, as for every typed element, and 74 of 74 equal Revit's. +What is written: conduits as `IfcCableCarrierSegment`, their fittings as `IfcCableCarrierFitting` and gutters as `IfcPipeSegment` (as pipes are `IfcPipeSegment` and `IfcPipeFitting` for the same two IFC2X3 classes). `PredefinedType` stays unset on all three, as a pipe's does: no IFC4 export shows Revit's value on an occurrence, and the writer never invents an enumerator it did not decode. Revit's type objects carry `GUTTER` for the gutters (2 of 2) and `NOTDEFINED` for the conduits and fittings, so writing `.GUTTER.` on a gutter is measured on its type object only; it is left for a decision. No type object is written for the three: a conduit fitting's type name is read and Revit's `Reference` property is written for it, as for every typed element, and 74 of 74 equal Revit's. ## 4. Bodies @@ -63,7 +67,7 @@ Run 41730511780 (main's side `c28ff053`, head `9ade4f78`, every scorer, no model | elements on Revit's storey | 1,073 | **1,251** | | | elements on another storey, on none | 21, 16 | 21, 16 | | -By Revit's class: 1,314 of 1,321 written. The same class: beams 1, building element proxies 43, columns 114, doors 68, members 206, plates 67, railings 14, roofs 8, slabs 9, stairs 6, stair flights 6, walls (`IfcWall`) 12, windows 70, and now **2 gutters (`IfcFlowSegment`)** (626). In IFC4's class for Revit's IFC2X3 one: 128 `IfcFlowFitting` as `IfcPipeFitting`, 140 `IfcFlowSegment` as `IfcPipeSegment`, 235 `IfcWallStandardCase` as `IfcWall`, and now **74 `IfcFlowFitting` as `IfcCableCarrierFitting` and 102 `IfcFlowSegment` as `IfcCableCarrierSegment`** (679). Another class: 9 `IfcCurtainWall` as `IfcWall` (unchanged). **Missing, 7** (185 before): 4 `IfcWallStandardCase` (the curtain-panel walls of RE-315 §5) and 3 `IfcElementAssembly` (not instances). `IfcFlowSegment` absent 0 (104), `IfcFlowFitting` absent 0 (74). +By Revit's class: 1,314 of 1,321 written. The same class: beams 1, building element proxies 43, columns 114, doors 68, members 206, plates 67, railings 14, roofs 8, slabs 9, stairs 6, stair flights 6, walls (`IfcWall`) 12, windows 70 (624). In IFC4's class for Revit's IFC2X3 one: 128 `IfcFlowFitting` as `IfcPipeFitting`, 140 `IfcFlowSegment` as `IfcPipeSegment`, 235 `IfcWallStandardCase` as `IfcWall`, and now **74 `IfcFlowFitting` as `IfcCableCarrierFitting`, 102 `IfcFlowSegment` as `IfcCableCarrierSegment` and 2 `IfcFlowSegment` as `IfcPipeSegment`** (681). Another class: 9 `IfcCurtainWall` as `IfcWall` (unchanged). **Missing, 7** (185 before): 4 `IfcWallStandardCase` (the curtain-panel walls of RE-315 §5) and 3 `IfcElementAssembly` (not instances). `IfcFlowSegment` absent 0 (104), `IfcFlowFitting` absent 0 (74). The scorers that move (`compare-scorer-diff`, run 41730511780): @@ -72,26 +76,47 @@ The scorers that move (`compare-scorer-diff`, run 41730511780): - `box_bodies_vs_ifc`: record-box bodies 880 to 1,058 (+102 conduits, +74 fittings, +2 gutters). - `duct_bodies_vs_ifc`: 0 to 104 flow segments written with a body, 102 of 104 within 0.01 ft of Revit's world box. - `names_vs_ifc`: 74 conduit fittings equal in name and ObjectType (`M_Codo de tubo - Aluminio:Estándar:`, Revit's own); 102 conduits and 2 gutters differ, as the 140 pipes do (`Conduit-` and `Gutter-` where Revit's is `Tubo con uniones:Tubo:` and `Canalón:Canalón:`: the system family's name is Revit's, in the file's language, and the type name is not read for a system type on Revit 2018). -- `type_objects_vs_ifc`: 74 more typed in ours, every TypeName equal to Revit's (592 to 666); 104 more untyped (the conduits and gutters). +- `type_objects_vs_ifc`: Revit's types on the elements written 1,102 to 1,280; none of the 178 has a type object of ours (flow segments untyped 140 to 244, flow fittings 0 to 74); the TypeName carried on the occurrence is Revit's for 666 of 1,280 (592 before, the 74 conduit fittings added). - `psets_vs_ifc`: Revit's values on the objects written 4,961 to 5,317; equal 2,383 to 2,457 (the 74 fittings' `Pset_EnvironmentalImpactIndicators.Reference`); **different 0 to 0; values Revit does not write 20 to 20**; missing 2,578 to 2,860, 282 more, of which `Pset_DistributionFlowElementCommon.Reference` on the 178 (a set Revit writes on these three classes and not on the pipes, and that the Reference allow-list of #1120 does not name, so it is left out) and `Pset_EnvironmentalImpactIndicators.Reference` on the 104 conduits and gutters (no type name read). - `global_ids_vs_ifc`: none of the elements' GlobalIds is Revit's (#878), as before. - `schema.txt`: arity, validation, EXPRESS rules and property sets 0 findings; sets 1,668 to 1,742. No other scorer moves on this file (`ports_vs_ifc`, `pipe_bodies_vs_ifc`, `qtos_vs_ifc`, `predefined_types_vs_ifc`: unchanged). -## 7. Other files +## 7. Other files, and the held-out Project + +Run 41733219416 (`-f holdout=true -f samples=true -f nordic=true -f r2025=true -f bimcollab=true`, no model filter, every scorer; main's side `782fff64`, head `4e9e3ef1`, the merge of main into the code of this report; the commits after it change documents and the census scorer only): 112 models exported on both sides, **97 byte for byte main's IFC and 15 moved**. The 15 are the models that hold the three categories where the rule selects an instance, and in each the only change is the conduits, conduit fittings and gutters written: - +| model | change | +|---|---| +| Vitoria `ALD26 Before` (spent) | +102 conduits, +74 conduit fittings, +2 gutters (§6) | +| `ALD26 Project` (held out) | counts only, below | +| Autodesk `rme_advanced` 2015, 2019, 2024, 2025, 2026, 2027 | +19 conduits, +14 conduit fittings each (swept solids +33 on 2024) | +| Autodesk `rme_basic` 2015, 2019, 2024, 2025, 2026, 2027 | +20 conduits, +14 conduit fittings each (+34 on 2024) | +| Snowdon Towers Electrical 2024 | +530 conduits, +322 conduit fittings (+852 swept solids) | + +Those samples have no Revit export: they are counted, not scored; their schema checks have 0 findings (the 2024 `rme` files' validation is skipped over 30 MB, as before). Unchanged, byte for byte: Core Interior, Einhoven, RE1 Architecture, Electrical, Mechanical and Plumbing, the four BIM4LCA files, the 24 R2025 models, BIMcollab's 2015 example, the other 17 held-out pairs (Frigento, Gdynia, Warmond, BIM Whale and the rest, whose `counts.txt` are main's line for line), and 45 samples, among them Snowdon Towers Architectural, Structural, HVAC and Plumbing (the last two hold conduit fittings and cable tray fittings that fail the rule). No other scorer output moves on any model. + +**Held out, counts only** (`ALD26 Project`, Revit's 1,520 elements and spaces: 1,447 elements and 73 spaces): main wrote 1,336 (1,263 elements and 73 spaces); the head writes **1,514 (1,441 elements and 73 spaces)**. `IfcFlowSegment` absent 104 to 0 and `IfcFlowFitting` absent 74 to 0, the two classes where any change should show; no element written that Revit's export lacks (the extra column is `IfcSpace` 73 as before, spaces paired by GlobalId); 1,433 of the 1,441 elements in Revit's class or IFC4's (the other 8 are curtain walls written as walls); 1,359 of 1,441 on Revit's storey (1,181 of 1,263), 14 on none and 21 on another, as before; the 6 elements missing are 3 `IfcElementAssembly` and 3 `IfcWallStandardCase`. Properties: Revit's values on the objects written 5,784 to 6,140, equal 2,919 to 2,993, **different 0 to 0, values Revit does not write 18 to 18**. The file was not opened. ## 8. Reproduce - +```bash +# the census, on every development file (the samples run the probe alone) +gh workflow run measure.yml --ref main -f ref=3a81189c6dde0783004c41d3d2e4daf27930e1e8 -f base=none -f holdout=true -f samples=true -f nordic=true -f r2025=true -f bimcollab=true -f models="spent-* core-interior einhoven re1-* nordic-office-* r2025-* bimcollab-*" -f scorers=none -f probe=probe_re319_category_census -f probe_scorer=category_census_vs_ifc +# Vitoria Before, every scorer, against main, with the IFC kept +gh workflow run measure.yml --ref main -f ref=4e9e3ef10e3c47ce6d807761774f4921a199dc4a -f base=main -f holdout=true -f models="spent-*" -f keep_ifc=true +# the final head: every model, every scorer, every held-out pair (counts only) +gh workflow run measure.yml --ref main -f ref=4e9e3ef10e3c47ce6d807761774f4921a199dc4a -f base=main -f holdout=true -f samples=true -f nordic=true -f r2025=true -f bimcollab=true +``` + +Runs: census 41726416015 (head `eba89c8e`); the categories' names and types in Revit's export 41729789378 and 41740219735; `ALD26 Before` against main 41730511780 (head `9ade4f78`, before the gutters' elevation and the Level parameter) and 41731699676 (head `37838a94`, with the 2024 samples); the final run 41733219416. The census scorer is in `tools/re` at `3a81189c`; the scorer for the final run is the one of the head. ## 9. What stays missing, and what is not measured - 4 curtain-panel walls and 3 element assemblies of `ALD26 Before` (RE-315 §9). - Cable trays and cable tray fittings (above), on every file. -- The class of a conduit, conduit fitting or gutter in an IFC4 export of Revit: no such export holds one. The IFC4 classes are the subtypes of Revit's IFC2X3 ones (conduits and fittings) and Revit's own class (gutters). +- The class and `PredefinedType` of a conduit, conduit fitting or gutter occurrence in an IFC4 export of Revit: no such export holds one. The IFC4 classes follow the type objects of Revit's IFC2X3 export of `ALD26 Before`; the gutters' `GUTTER` is on their type objects only (2 of 2). - Conduits' and gutters' names, and their `Reference`: Revit 2018 writes `Tubo con uniones:Tubo:`; the system type's name is not read there. - A conduit's or fitting's `Constraints` Level parameter: `rvt-ifc` writes none for the three classes, since no export measures its name (Revit's own for a pipe segment is `Reference Level`, for a fitting `Level`). - Ports and connections of conduit fittings: not written (`is_distribution_element` does not name `IfcCableCarrierFitting`), and the 2008 to 2023 path reads no joins at all. From 8f159a062980c467f09635a8c11a0d142a63fccc Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 19:31:26 -0500 Subject: [PATCH 11/12] docs(elements): RE-319 reports the final run on the final head, with gutters as IfcPipeSegment (#1261) (RE-319) --- docs/reference-models.md | 2 +- .../RE-319-conduits-conduit-fittings-gutters.md | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/reference-models.md b/docs/reference-models.md index d7c68fcd5..1d378cc17 100644 --- a/docs/reference-models.md +++ b/docs/reference-models.md @@ -34,7 +34,7 @@ lists the local-only files with their source and hash, and never fetches them. | 255ribeiro Projeto1, `teste_export_2025` | 2025 | none declared, local only | IFC4X3 CoordinationView; IFC4 DesignTransferView 1.0, Revit 25.4 (PTB) | metric projects; IFC export overrides; files saved in `PTB` (RE-123) | | 255ribeiro `Exemplo_data`, `modelo_bim` | 2023 | none declared, local only | IFC4 ReferenceView 1.2, Revit 23.1 (`Exemplo_data`); IFC4 DesignTransferView 1.0, Revit 26.2 PTB (`modelo_bim`, exported from the 2023 file by a later Revit) | Revit 2023 element records (RE-81 to RE-122): 37 of 37 and 37 of 45 elements, storeys, types, layers, materials, wall joins, beams; files saved in `PTB` | | BIMcollab example, structural model (`02_BIMcollab_Example_STR`) | 2015 | none stated, local only; BIMcollab's public example project (`research/bimcollab-models.tsv`, fetched by Measure with `-f bimcollab=true`, STE1200's pointer) | IFC2X3 CoordinationView 2.0, Revit Architecture 2015, 2014-10-08, rewritten by Solibri's IFC Optimizer; the model was renamed after it | held out when measured (RE-198); RE-208 and RE-220 have since used it, so it no longer counts as held out: all 241 exported elements by ElementId, in Revit's class or IFC4's for its IFC2X3 one, 3 more written, GlobalIds not in the file (#878, RE-208), 16 footings on no storey (#879); wall faces and layer sets as Revit's | -| BIM-Speed Vitoria (`ALD26 Before`, `ALD26 Project`), Frigento, Gdynia, Warmond | 2018, 2018, 2020, 2021, 2021 | CC BY 4.0 (TU Berlin DepositOnce, doi:10.14279/depositonce-16441); fetched by Measure with `-f holdout=true` (`research/holdout-archive-models.tsv`) | each release's own export: IFC2X3 CoordinationView 2.0 (Vitoria, Gdynia), IFC4 DesignTransferView (Frigento), IFC4 passed through BIMServer.center's preprocessor (Warmond); the IFC2X3 exports and Warmond's are counted apart and never remove a value | **held out** (Griffin, 2026-11-03): measured before any fix, counts only; the first same-release pairs for 2018, 2020 and 2021 (#408, #1261). Before any fix (run 41658225355): both Vitoria saves export no element against Revit's 1,394 and 1,520. Every Autodesk 2018 sample exports its elements, so `ALD26 Before` is spent to find why (measured in full as `spent-bimspeed-vitoria-before-2018`) and `ALD26 Project` stays held out as the check. After RE-315 (frames with no ElementId of their own take their record's, run 41707934595): `ALD26 Before` writes 1,136 of Revit's 1,321 elements by Tag, 1,127 of them in Revit's class or IFC4's, with none that Revit's export lacks, on 7 storeys; `ALD26 Project` first wrote 1,534 elements and spaces against Revit's 1,520, counts only, 198 of them elements Revit's export does not hold, and writes 1,336 (1,263 elements and 73 spaces) with none, since the export phase and design options are applied to Revit 2016 to 2023 (the counts cannot tell which of the two removed them); Frigento, Gdynia and Warmond export byte for byte as before. After RE-319 (conduits, conduit fittings and gutters, run 41733219416): `ALD26 Before` writes 1,314 of Revit's 1,321 elements by Tag, 1,305 of them in Revit's class or IFC4's, with none that Revit's export lacks, 1,251 on Revit's storey; `ALD26 Project` writes 1,514 elements and spaces (1,441 elements and 73 spaces) against Revit's 1,520, counts only, none that Revit's export lacks, 1,433 of the 1,441 elements in Revit's class or IFC4's and 1,359 on Revit's storey; the other held-out pairs export byte for byte as before. Before any fix, Frigento 151 of 151 elements paired by Tag, Gdynia 199 of 203 (18 of 19 spaces), Warmond 710 of 710 (179 of 179 spaces); an element is counted as found by its Tag, whatever its class | +| BIM-Speed Vitoria (`ALD26 Before`, `ALD26 Project`), Frigento, Gdynia, Warmond | 2018, 2018, 2020, 2021, 2021 | CC BY 4.0 (TU Berlin DepositOnce, doi:10.14279/depositonce-16441); fetched by Measure with `-f holdout=true` (`research/holdout-archive-models.tsv`) | each release's own export: IFC2X3 CoordinationView 2.0 (Vitoria, Gdynia), IFC4 DesignTransferView (Frigento), IFC4 passed through BIMServer.center's preprocessor (Warmond); the IFC2X3 exports and Warmond's are counted apart and never remove a value | **held out** (Griffin, 2026-11-03): measured before any fix, counts only; the first same-release pairs for 2018, 2020 and 2021 (#408, #1261). Before any fix (run 41658225355): both Vitoria saves export no element against Revit's 1,394 and 1,520. Every Autodesk 2018 sample exports its elements, so `ALD26 Before` is spent to find why (measured in full as `spent-bimspeed-vitoria-before-2018`) and `ALD26 Project` stays held out as the check. After RE-315 (frames with no ElementId of their own take their record's, run 41707934595): `ALD26 Before` writes 1,136 of Revit's 1,321 elements by Tag, 1,127 of them in Revit's class or IFC4's, with none that Revit's export lacks, on 7 storeys; `ALD26 Project` first wrote 1,534 elements and spaces against Revit's 1,520, counts only, 198 of them elements Revit's export does not hold, and writes 1,336 (1,263 elements and 73 spaces) with none, since the export phase and design options are applied to Revit 2016 to 2023 (the counts cannot tell which of the two removed them); Frigento, Gdynia and Warmond export byte for byte as before. After RE-319 (conduits, conduit fittings and gutters, run 41741114199): `ALD26 Before` writes 1,314 of Revit's 1,321 elements by Tag, 1,305 of them in Revit's class or IFC4's, with none that Revit's export lacks, 1,251 on Revit's storey; `ALD26 Project` writes 1,514 elements and spaces (1,441 elements and 73 spaces) against Revit's 1,520, counts only, none that Revit's export lacks, 1,433 of the 1,441 elements in Revit's class or IFC4's and 1,359 on Revit's storey; the other held-out pairs export byte for byte as before. Before any fix, Frigento 151 of 151 elements paired by Tag, Gdynia 199 of 203 (18 of 19 spaces), Warmond 710 of 710 (179 of 179 spaces); an element is counted as found by its Tag, whatever its class | | BIM Whale `AdvancedProject` | 2021 | the IFC from andrewisen/bim-whale-ifc-samples (MIT); the `.rvt` from the Dropbox link its README gives, under the README's "feel free to use these files however you like"; fetched by Measure with `-f holdout=true` | IFC2X3 CoordinationView 2.0, exporter 21.1.10.26, counted apart | **held out** (Griffin, 2026-11-03): before any fix it had 1,698 of 1,714 elements paired by Tag (456 of them in another class than Revit's: 407 `IfcFurniture` for `IfcFurnishingElement`, 49 `IfcSanitaryTerminal` for `IfcFlowTerminal`) and none of its 8 spaces. Those spaces are Revit Areas of a 'Rentable' scheme, not rooms; rvt-rs reads Areas on Revit 2024 only. It was briefly spent on 2026-11-03 to look for the cause and restored. While spent it was measured in full in four runs (41661841411, 41668542833, 41671242397 and 41672953553, their artifacts deleted), and the RE-315 work read its record chain and frame counts beside Vitoria's; no rule or constant came from it (#1261, #1286) | ## Candidates, not yet measured here diff --git a/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md b/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md index 91457859f..1cc5c1a12 100644 --- a/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md +++ b/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md @@ -2,7 +2,7 @@ **Date:** 2026-11-03 **Issues:** #1261 (a Revit 2018 project exports no element; RE-315 §9 left 178 conduits, conduit fittings and gutters as "the next category census"); follows RE-33 (the category census), RE-21 (the instance rule), RE-79 (nested MEP components), RE-131 (pipe cylinders), RE-315 (the 32-bit second prologue) -**Artefacts:** BIM-Speed's Vitoria `ALD26 Before.rvt` (Revit 2018, sha256 `d3e5b04631e67265927be98352021ed6290b33ae67d39b1b6727fd76f014ff6f`) and Revit's own IFC2X3 export of it (`a42c6f3b0c9b7575d4c37c675155ff53c02571ca81357a87023f9da5fbf45181`), CC BY 4.0, TU Berlin DepositOnce, doi:10.14279/depositonce-16441, spent for W5 (RE-315) and measured in full with `-f holdout=true`; RE1 Electrical (`9875e765c9f47893808c47b845a8379b8777b92510e3e0284f763cb457c9630b`, IFC `c7002a10c8e10ab2fca64ff61dcf38db04da652924f65ce53c2064827dfa9e16`), Mechanical (`d559720177aa0ec435133f804e7c45d60da2deb9d5585bb3d55f4830139c014b`, IFC `9e56cf7246ce86ef73646dd588a1efb8a4756e5e102b30e28b3b58577a454db0`) and Plumbing (`03689df2aa426031a216e65051b9f19d3265d6fe96884dd47373b17435f9e54c`, IFC `294490b222632509779910345f27a4eeda3645956138a593298c241495f7b8b6`), Revit 2025, MIT, IFC2X3 exports; Core Interior (`c805df445d613b408e37337765572021265e3f5dfdc7d1fa53b22ba1600b8014`); the BIM4LCA office and its terrain variants, puzzbobb's 23 Revit 2025 models and Autodesk's sample projects of 2015 to 2027 (hashes in `research/bim4lca-measure.tsv`, `research/r2025-models.tsv` and `research/autodesk-sample-projects.tsv`); by counts only, the held-out `ALD26 Project`. +**Artefacts:** BIM-Speed's Vitoria `ALD26 Before.rvt` (Revit 2018, sha256 `d3e5b04631e67265927be98352021ed6290b33ae67d39b1b6727fd76f014ff6f`) and Revit's own IFC2X3 export of it (`a42c6f3b0c9b7575d4c37c675155ff53c02571ca81357a87023f9da5fbf45181`), CC BY 4.0, TU Berlin DepositOnce, doi:10.14279/depositonce-16441, spent for W5 (RE-315) and measured in full with `-f holdout=true`; RE1 Electrical (`9875e765c9f47893808c47b845a8379b8777b92510e3e0284f763cb457c9630b`, IFC `c7002a10c8e10ab2fca64ff61dcf38db04da652924f65ce53c2064827dfa9e16`), Mechanical (`d559720177aa0ec435133f804e7c45d60da2deb9d5585bb3d55f4830139c014b`, IFC `9e56cf7246ce86ef73646dd588a1efb8a4756e5e102b30e28b3b58577a454db0`) and Plumbing (`03689df2aa426031a216e65051b9f19d3265d6fe96884dd47373b17435f9e54c`, IFC `294490b222632509779910345f27a4eeda3645956138a593298c241495f7b8b6`), Revit 2025, MIT, IFC2X3 exports; Core Interior (`c805df445d613b408e37337765572021265e3f5dfdc7d1fa53b22ba1600b8014`); the BIM4LCA office and its terrain variants, puzzbobb's 24 Revit 2025 models and Autodesk's sample projects of 2015 to 2027 (hashes in `research/bim4lca-measure.tsv`, `research/r2025-models.tsv` and `research/autodesk-sample-projects.tsv`); by counts only, the held-out `ALD26 Project`. **Probe:** `probes/examples/probe_re319_category_census.rs`, scored by `tools/re/category_census_vs_ifc.py`. **Status:** positive on Revit 2018's `ALD26 Before` against Revit's own export, the only file with an export that holds any of these categories; no other release's export is measured for them. Cable trays and cable tray fittings are **not recovered** (not measured: no file with a Revit export holds an instance). The centerline categories are never recovered. @@ -56,7 +56,7 @@ Conduits and their fittings sit on the Level their record's list names, as the o ## 6. Result on `ALD26 Before` -Run 41730511780 (main's side `c28ff053`, head `9ade4f78`, every scorer, no model but the spent pair) and run 41731699676 (head `37838a94`, with the gutters' elevation), measured again at the final head in the unfiltered run of §8. +Run 41730511780 (main's side `c28ff053`, head `9ade4f78`, every scorer, no model but the spent pair) and run 41731699676 (head `37838a94`, with the gutters' elevation) measured the code before the gutters became `IfcPipeSegment`; every figure below was measured again at the final head, `46da221f`, in the unfiltered run of §7 (41741114199), and is the same. | `ALD26 Before` | main | head | Revit's export | |---|---:|---:|---:| @@ -69,9 +69,9 @@ Run 41730511780 (main's side `c28ff053`, head `9ade4f78`, every scorer, no model By Revit's class: 1,314 of 1,321 written. The same class: beams 1, building element proxies 43, columns 114, doors 68, members 206, plates 67, railings 14, roofs 8, slabs 9, stairs 6, stair flights 6, walls (`IfcWall`) 12, windows 70 (624). In IFC4's class for Revit's IFC2X3 one: 128 `IfcFlowFitting` as `IfcPipeFitting`, 140 `IfcFlowSegment` as `IfcPipeSegment`, 235 `IfcWallStandardCase` as `IfcWall`, and now **74 `IfcFlowFitting` as `IfcCableCarrierFitting`, 102 `IfcFlowSegment` as `IfcCableCarrierSegment` and 2 `IfcFlowSegment` as `IfcPipeSegment`** (681). Another class: 9 `IfcCurtainWall` as `IfcWall` (unchanged). **Missing, 7** (185 before): 4 `IfcWallStandardCase` (the curtain-panel walls of RE-315 §5) and 3 `IfcElementAssembly` (not instances). `IfcFlowSegment` absent 0 (104), `IfcFlowFitting` absent 0 (74). -The scorers that move (`compare-scorer-diff`, run 41730511780): +The scorers that move (`compare-scorer-diff` of run 41741114199, the same list as run 41730511780's): -- `class_sets_vs_ifc`: the two rows above; `IfcSpace` extras 73 as before (spaces are paired by GlobalId, which are not Revit's, #878). No extra element. +- `class_sets_vs_ifc`: `IfcFlowFitting` 202: 128 `IfcPipeFitting`, 74 `IfcCableCarrierFitting`, absent 74 to 0; `IfcFlowSegment` 244: 140 `IfcPipeSegment`, 102 `IfcCableCarrierSegment`, 2 `IfcPipeSegment` (the gutters, whose Revit type object is `IfcPipeSegmentType` `GUTTER`), absent 104 to 0; `IfcSpace` extras 73 as before (spaces are paired by GlobalId, which are not Revit's, #878). No extra element. - `storeys_vs_ifc`: 1,314 elements, 16 on no storey (the 9 proxies, 6 railings and 1 flight of before); 1,251 on Revit's storey, 26 where Revit contains it in an `IfcSpace`, 21 on another, 9 and 7 on none; the 21 are the same 14 columns, 4 pipe segments and 3 pipe fittings as before, none of them a conduit. - `box_bodies_vs_ifc`: record-box bodies 880 to 1,058 (+102 conduits, +74 fittings, +2 gutters). - `duct_bodies_vs_ifc`: 0 to 104 flow segments written with a body, 102 of 104 within 0.01 ft of Revit's world box. @@ -85,7 +85,7 @@ No other scorer moves on this file (`ports_vs_ifc`, `pipe_bodies_vs_ifc`, `qtos_ ## 7. Other files, and the held-out Project -Run 41733219416 (`-f holdout=true -f samples=true -f nordic=true -f r2025=true -f bimcollab=true`, no model filter, every scorer; main's side `782fff64`, head `4e9e3ef1`, the merge of main into the code of this report; the commits after it change documents and the census scorer only): 112 models exported on both sides, **97 byte for byte main's IFC and 15 moved**. The 15 are the models that hold the three categories where the rule selects an instance, and in each the only change is the conduits, conduit fittings and gutters written: +Run 41741114199 (`-f holdout=true -f samples=true -f nordic=true -f r2025=true -f bimcollab=true`, no model filter, every scorer; main's side `4ad28023`, head `46da221f`, the merge of main into the code of this report; the commits after it change documents only): 112 models exported on both sides, **97 byte for byte main's IFC and 15 moved**. The 15 are the models that hold the three categories where the rule selects an instance, and in each the only change is the conduits, conduit fittings and gutters written: | model | change | |---|---| @@ -105,12 +105,12 @@ Those samples have no Revit export: they are counted, not scored; their schema c # the census, on every development file (the samples run the probe alone) gh workflow run measure.yml --ref main -f ref=3a81189c6dde0783004c41d3d2e4daf27930e1e8 -f base=none -f holdout=true -f samples=true -f nordic=true -f r2025=true -f bimcollab=true -f models="spent-* core-interior einhoven re1-* nordic-office-* r2025-* bimcollab-*" -f scorers=none -f probe=probe_re319_category_census -f probe_scorer=category_census_vs_ifc # Vitoria Before, every scorer, against main, with the IFC kept -gh workflow run measure.yml --ref main -f ref=4e9e3ef10e3c47ce6d807761774f4921a199dc4a -f base=main -f holdout=true -f models="spent-*" -f keep_ifc=true +gh workflow run measure.yml --ref main -f ref=46da221fc89f259d7dd535e06e8f49a7ac0286a3 -f base=main -f holdout=true -f models="spent-*" -f keep_ifc=true # the final head: every model, every scorer, every held-out pair (counts only) -gh workflow run measure.yml --ref main -f ref=4e9e3ef10e3c47ce6d807761774f4921a199dc4a -f base=main -f holdout=true -f samples=true -f nordic=true -f r2025=true -f bimcollab=true +gh workflow run measure.yml --ref main -f ref=46da221fc89f259d7dd535e06e8f49a7ac0286a3 -f base=main -f holdout=true -f samples=true -f nordic=true -f r2025=true -f bimcollab=true ``` -Runs: census 41726416015 (head `eba89c8e`); the categories' names and types in Revit's export 41729789378 and 41740219735; `ALD26 Before` against main 41730511780 (head `9ade4f78`, before the gutters' elevation and the Level parameter) and 41731699676 (head `37838a94`, with the 2024 samples); the final run 41733219416. The census scorer is in `tools/re` at `3a81189c`; the scorer for the final run is the one of the head. +Runs: census 41726416015 (head `eba89c8e`); the categories' names and types in Revit's export 41729789378 and 41740219735; `ALD26 Before` against main 41730511780 (head `9ade4f78`, before the gutters' elevation and the Level parameter) and 41731699676 (head `37838a94`, with the 2024 samples); the final run 41741114199 on `46da221f`. An earlier unfiltered run, 41733219416 on `4e9e3ef1`, wrote the gutters as `IfcFlowSegment` before the type objects of Revit's export (run 41740219735) showed `IfcPipeSegmentType`; it moved the same 15 models and is superseded. The census scorer is in `tools/re` at `3a81189c`; the scorer for the final run is the one of the head. ## 9. What stays missing, and what is not measured From c223c470beac8a8f522a872cbc399654ea9a940d Mon Sep 17 00:00:00 2001 From: Griffin Long <151978260+DrunkOnJava@users.noreply.github.com> Date: Tue, 3 Nov 2026 19:54:37 -0500 Subject: [PATCH 12/12] docs(elements): the support matrix counts ALD26 Before with RE-319's conduits, and RE-319 corrects its missing-value arithmetic and states the type objects, bodies, Snowdon and systems it leaves unmeasured (#1261) (RE-319) --- docs/support-matrix.json | 4 ++-- .../RE-319-conduits-conduit-fittings-gutters.md | 7 +++++-- src/ifc/export_content.rs | 6 +++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/support-matrix.json b/docs/support-matrix.json index 25f8d81f8..2a8db428f 100644 --- a/docs/support-matrix.json +++ b/docs/support-matrix.json @@ -176,7 +176,7 @@ "name": "Revit 2015 to 2018 partition element records, read in the 32-bit layout of Revit 2019 to 2023, with storeys, hosts, type names, layer sets and materials", "status": "experimental", "evidence": "partition_element_records_2023::REVIT_32BIT_RELEASES and schema_tags; partition_level_records::LEVEL_PLACEMENT_KIND_2015; partition_compound_structure::wall_orientation_has_word; partition_materials::pattern_slots_32; partition_names::find_element_data_names_32; probes/examples/probe_re181_revit_2015_2018.rs; reports/element-framing/RE-181-revit-2015-2018-element-records.md; reports/element-framing/RE-198-revit-2015-bimcollab-export.md; probes/examples/probe_re315_32bit_record_chain.rs; reports/element-framing/RE-315-32bit-second-prologue-records.md", - "notes": "Revit 2015 to 2018 frame their element records as 2019 does (RE-180): on Autodesk's 2016 to 2018 sample projects every record marker but 4 to 109 per file (as many as on the 2019 copy, but 15 on 2016 rst_basic) has a declared u32 ElementId 52 bytes before it, and so do all but 4 to 6 per file of Autodesk's six 2015 sample projects (pinned by #801) and 0 to 68 per file of three of its 2015 templates; 2014 is not read, since the one 2014 file measured is not documented. Each release takes its own tags of the five schema classes RE-180 lists. Three layouts differ from 2019's: a Level record's placement kind is 0xffffef6f, a wall's flip follows its location line with no word between (as on 2019 and 2020), and a material's shading frame holds two pattern slots, not four. On 2015 to 2018 a type's element-data name is looked for in its own data only and a one-unit entry is passed over. Revit's own export is measured on one 2015 project, BIMcollab's structural example (RE-198, a public download): all 241 of its elements by ElementId, in Revit's class or IFC4's for its IFC2X3 one, 3 written that the export leaves out (#879), and none of its elements' GlobalIds Revit's (#878). Revit's own export is measured on one 2018 project, Vitoria's ALD26 Before (RE-315, CC BY 4.0, spent to find why it exported nothing): 1,136 of Revit's 1,321 elements by ElementId, 1,127 of them in Revit's class or IFC4's (9 curtain walls are written as walls), none written that the export leaves out, 185 missing; for 2016, 2017 and the other 2018 projects there is no Revit export and the oracle is the same model saved by Revit 2019. On rac_basic, rst_basic and rac_advanced of 2016 to 2018 every ElementId shared with the 2019 copy has its class; 2018 rac_basic and rac_advanced agree on every field, and the other differences are in the files' own bytes (boxes, reference lists, 2016's shading colours, 2016 rst_basic's renamed families). On five of the six 2015 sample projects every ElementId shared with the 2019 copy has its class; the sixth, rst_basic, shares no ElementId with it (another model), and the differing fields (type materials from RE-82's scan, renamed families, curtain-wall member boxes) are counted in RE-181 §6, not explained. Not read, as on 2019 to 2023: layered joins, IFC export overrides, parameters. Design options and the export phase are applied on 2016 to 2018 and not on 2015 (RE-315). Design options are read as on 2024 with u32 ids, on the eight saves of Autodesk's rst_basic_sample_project of 2016 to 2023 only: 1 set, 4 frames in a non-primary option, a Mass that Revit does not export, so the exported IFC does not change and no Revit export of these files is measured. The phase is read as RE-281 reads it for 2015 to 2023; no Autodesk sample has an element outside it, so the only evidence that applying it is right on a 32-bit file is the held-out Vitoria Project's counts (198 elements Revit's export lacks, then none), which cannot tell the phase from the design options. A frame with no declared ElementId of its own (the second prologue) takes the id of the declared record around it when it is a placed instance and its reference list names that id (RE-315): on Vitoria's Revit 2018 `ALD26 Before`, which wrote no element before, 1,136 of Revit's 1,321 elements by ElementId, 1,127 of them in Revit's class or IFC4's, none written that its IFC2X3 export leaves out, 1,073 on Revit's storey and 7 storeys, as many as Revit's; the 185 missing are conduits, conduit fittings and gutters in categories not yet recovered (178), 4 panel walls and 3 assemblies.", + "notes": "Revit 2015 to 2018 frame their element records as 2019 does (RE-180): on Autodesk's 2016 to 2018 sample projects every record marker but 4 to 109 per file (as many as on the 2019 copy, but 15 on 2016 rst_basic) has a declared u32 ElementId 52 bytes before it, and so do all but 4 to 6 per file of Autodesk's six 2015 sample projects (pinned by #801) and 0 to 68 per file of three of its 2015 templates; 2014 is not read, since the one 2014 file measured is not documented. Each release takes its own tags of the five schema classes RE-180 lists. Three layouts differ from 2019's: a Level record's placement kind is 0xffffef6f, a wall's flip follows its location line with no word between (as on 2019 and 2020), and a material's shading frame holds two pattern slots, not four. On 2015 to 2018 a type's element-data name is looked for in its own data only and a one-unit entry is passed over. Revit's own export is measured on one 2015 project, BIMcollab's structural example (RE-198, a public download): all 241 of its elements by ElementId, in Revit's class or IFC4's for its IFC2X3 one, 3 written that the export leaves out (#879), and none of its elements' GlobalIds Revit's (#878). Revit's own export is measured on one 2018 project, Vitoria's ALD26 Before (RE-315, CC BY 4.0, spent to find why it exported nothing): 1,314 of Revit's 1,321 elements by ElementId, 1,305 of them in Revit's class or IFC4's (9 curtain walls are written as walls), none written that the export leaves out, 7 missing (4 curtain-panel walls and 3 element assemblies; the conduits, conduit fittings and gutters are recovered since RE-319); for 2016, 2017 and the other 2018 projects there is no Revit export and the oracle is the same model saved by Revit 2019. On rac_basic, rst_basic and rac_advanced of 2016 to 2018 every ElementId shared with the 2019 copy has its class; 2018 rac_basic and rac_advanced agree on every field, and the other differences are in the files' own bytes (boxes, reference lists, 2016's shading colours, 2016 rst_basic's renamed families). On five of the six 2015 sample projects every ElementId shared with the 2019 copy has its class; the sixth, rst_basic, shares no ElementId with it (another model), and the differing fields (type materials from RE-82's scan, renamed families, curtain-wall member boxes) are counted in RE-181 §6, not explained. Not read, as on 2019 to 2023: layered joins, IFC export overrides, parameters. Design options and the export phase are applied on 2016 to 2018 and not on 2015 (RE-315). Design options are read as on 2024 with u32 ids, on the eight saves of Autodesk's rst_basic_sample_project of 2016 to 2023 only: 1 set, 4 frames in a non-primary option, a Mass that Revit does not export, so the exported IFC does not change and no Revit export of these files is measured. The phase is read as RE-281 reads it for 2015 to 2023; no Autodesk sample has an element outside it, so the only evidence that applying it is right on a 32-bit file is the held-out Vitoria Project's counts (198 elements Revit's export lacks, then none), which cannot tell the phase from the design options. A frame with no declared ElementId of its own (the second prologue) takes the id of the declared record around it when it is a placed instance and its reference list names that id (RE-315): on Vitoria's Revit 2018 `ALD26 Before`, which wrote no element before, 1,136 of Revit's 1,321 elements by ElementId, 1,127 of them in Revit's class or IFC4's, none written that its IFC2X3 export leaves out, 1,073 on Revit's storey and 7 storeys, as many as Revit's; the 185 missing are conduits, conduit fittings and gutters in categories not yet recovered (178), 4 panel walls and 3 assemblies.", "user_impact": "Revit 2015 to 2018 projects export typed elements under Revit's ElementIds, on Revit's storeys, with doors and windows in their walls and named types and layer sets; checked against the same models saved by Revit 2019, and for one 2015 project (RE-198) and one 2018 project (RE-315) against Revit's own export of their release." }, { @@ -203,7 +203,7 @@ "name": "ElementIds for second-prologue partition element records, read from the enclosing partition record", "status": "partial", "evidence": "partition_element_records::partition_record_chain / assign_second_prologue_ids / RevitFile::second_prologue_ids; tests/partition_record_chain.rs (every first-prologue frame starts a record of its own id on Core Interior and the RE1 models); tests/element_records_2025.rs; probes/examples/probe_re35_record_wrapper.rs; reports/element-framing/RE-35-partition-record-wrapper.md; reports/element-framing/RE-43-invalid-element-id.md", - "notes": "Every Partitions/* stream opens with a chain of records, one per element: u64 ElementId, u32 size, u16 prologue constant (release constant + 28), u16 count, the body, and a 16-byte trailer that repeats the size (RE-35). A first-prologue frame starts its record; a second-prologue frame (RE-30) sits inside its element's record, so its ElementId is the record's, read rather than inferred. All 30,432 first-prologue frames across nine 2024 and 2025 files start a record of their own id, and the chains hold every declared id on Core Interior and the RE1 models. Records after the chain belong to loaded families' own documents and never export. Against Revit's own exports: RE1 Architecture, Mechanical and Plumbing reach 100% of every recovered entity; Snowdon Towers Architectural exports 6,045 elements, 5,945 in Revit's export (a frame holding u32::MAX, the invalid ElementId, also takes its record's id, RE-43), with every wall, column, door, window, curtain wall and panel, railing, ceiling, furniture item, fixture and generic model of Revit's export attributed once RE-41 declares the ElemTable's second id. The rest are real elements Revit's export leaves out (#309); the 18 in non-primary design options are left out as Revit leaves them out (RE-40). Floors, building pads and ceilings get their ids too. It replaces RE-34's reference-order inference, which gave a door its type's id on a Revit 2025 file outside its hold-outs. Placed instances with no 3D volume are left out, as Revit leaves them out. Revit 2024 and 2025; on Revit 2008 to 2023, whose ElementId is a u32 in a 12-byte record header, the same idea is RE-315 (RE-35's chain walk stops at the first record whose trailer flag word is neither 0 nor 0x01000000, which these files have), measured against Revit's own export on one Revit 2018 project only, ALD26 Before: 1,136 of Revit's 1,321 elements by ElementId, 1,127 of them in Revit's class or IFC4's, and all 7 of its Levels; no other release of that layout is measured for it.", + "notes": "Every Partitions/* stream opens with a chain of records, one per element: u64 ElementId, u32 size, u16 prologue constant (release constant + 28), u16 count, the body, and a 16-byte trailer that repeats the size (RE-35). A first-prologue frame starts its record; a second-prologue frame (RE-30) sits inside its element's record, so its ElementId is the record's, read rather than inferred. All 30,432 first-prologue frames across nine 2024 and 2025 files start a record of their own id, and the chains hold every declared id on Core Interior and the RE1 models. Records after the chain belong to loaded families' own documents and never export. Against Revit's own exports: RE1 Architecture, Mechanical and Plumbing reach 100% of every recovered entity; Snowdon Towers Architectural exports 6,045 elements, 5,945 in Revit's export (a frame holding u32::MAX, the invalid ElementId, also takes its record's id, RE-43), with every wall, column, door, window, curtain wall and panel, railing, ceiling, furniture item, fixture and generic model of Revit's export attributed once RE-41 declares the ElemTable's second id. The rest are real elements Revit's export leaves out (#309); the 18 in non-primary design options are left out as Revit leaves them out (RE-40). Floors, building pads and ceilings get their ids too. It replaces RE-34's reference-order inference, which gave a door its type's id on a Revit 2025 file outside its hold-outs. Placed instances with no 3D volume are left out, as Revit leaves them out. Revit 2024 and 2025; on Revit 2008 to 2023, whose ElementId is a u32 in a 12-byte record header, the same idea is RE-315 (RE-35's chain walk stops at the first record whose trailer flag word is neither 0 nor 0x01000000, which these files have), measured against Revit's own export on one Revit 2018 project only, ALD26 Before: 1,314 of Revit's 1,321 elements by ElementId with RE-319's conduits, conduit fittings and gutters, 1,305 of them in Revit's class or IFC4's, and all 7 of its Levels; no other release of that layout is measured for it.", "user_impact": "Files whose element records mostly lack an ElementId at their start (Autodesk's Snowdon Towers samples, the RE1 models, projects saved incrementally) export their walls, doors, windows, floors, ceilings, columns, curtain-wall parts, railings, furniture, fixtures, ducts and pipes under the ElementIds Revit itself uses; the diagnostics count what is still left out." }, { diff --git a/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md b/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md index 1cc5c1a12..d02ea143e 100644 --- a/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md +++ b/reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md @@ -77,7 +77,7 @@ The scorers that move (`compare-scorer-diff` of run 41741114199, the same list a - `duct_bodies_vs_ifc`: 0 to 104 flow segments written with a body, 102 of 104 within 0.01 ft of Revit's world box. - `names_vs_ifc`: 74 conduit fittings equal in name and ObjectType (`M_Codo de tubo - Aluminio:Estándar:`, Revit's own); 102 conduits and 2 gutters differ, as the 140 pipes do (`Conduit-` and `Gutter-` where Revit's is `Tubo con uniones:Tubo:` and `Canalón:Canalón:`: the system family's name is Revit's, in the file's language, and the type name is not read for a system type on Revit 2018). - `type_objects_vs_ifc`: Revit's types on the elements written 1,102 to 1,280; none of the 178 has a type object of ours (flow segments untyped 140 to 244, flow fittings 0 to 74); the TypeName carried on the occurrence is Revit's for 666 of 1,280 (592 before, the 74 conduit fittings added). -- `psets_vs_ifc`: Revit's values on the objects written 4,961 to 5,317; equal 2,383 to 2,457 (the 74 fittings' `Pset_EnvironmentalImpactIndicators.Reference`); **different 0 to 0; values Revit does not write 20 to 20**; missing 2,578 to 2,860, 282 more, of which `Pset_DistributionFlowElementCommon.Reference` on the 178 (a set Revit writes on these three classes and not on the pipes, and that the Reference allow-list of #1120 does not name, so it is left out) and `Pset_EnvironmentalImpactIndicators.Reference` on the 104 conduits and gutters (no type name read). +- `psets_vs_ifc`: Revit's values on the objects written 4,961 to 5,317; equal 2,383 to 2,457 (the 74 fittings' `Pset_EnvironmentalImpactIndicators.Reference`); **different 0 to 0; values Revit does not write 20 to 20**; missing 2,578 to 2,860, 282 more, of which `Pset_DistributionFlowElementCommon.Reference` on the 176 conduits and fittings (a set Revit writes on those two classes and not on the pipes, and that the Reference allow-list of #1120 does not name, so it is left out) `Pset_EnvironmentalImpactIndicators.Reference` on the 104 conduits and gutters (no type name read), and `Pset_PipeSegmentTypeCommon.Reference` on the 2 gutters: 176 + 104 + 2 = 282. - `global_ids_vs_ifc`: none of the elements' GlobalIds is Revit's (#878), as before. - `schema.txt`: arity, validation, EXPRESS rules and property sets 0 findings; sets 1,668 to 1,742. @@ -120,4 +120,7 @@ Runs: census 41726416015 (head `eba89c8e`); the categories' names and types in R - Conduits' and gutters' names, and their `Reference`: Revit 2018 writes `Tubo con uniones:Tubo:`; the system type's name is not read there. - A conduit's or fitting's `Constraints` Level parameter: `rvt-ifc` writes none for the three classes, since no export measures its name (Revit's own for a pipe segment is `Reference Level`, for a fitting `Level`). - Ports and connections of conduit fittings: not written (`is_distribution_element` does not name `IfcCableCarrierFitting`), and the 2008 to 2023 path reads no joins at all. -- Conduit and gutter bodies are boxes. +- Conduit and gutter bodies are boxes (on Autodesk's 2024 and later `rme` samples 8 of the 33 new bodies each are turned boxes, RE-87). 102 of the 104 conduit and gutter boxes on `ALD26 Before` are within 0.01 ft of Revit's body; the other two are not attributed, and may be the two gutters. +- Type objects: Revit types all 178 (`IfcCableCarrierSegmentType`, `IfcCableCarrierFittingType`, `IfcPipeSegmentType` with `GUTTER`); rvt-rs writes no type object for them. A gutter, written as `IfcPipeSegment`, would be typed with `NOTDEFINED` if it ever carried a type name; none does on the files measured. +- Snowdon Towers Electrical's 530 conduits and 322 fittings are counted, not scored: it has no Revit IFC export here (its VIM export, #408, is held out). +- Systems: the 2024 and later path's MEP system membership is not class-gated, so a conduit may join a system there; that is not measured. diff --git a/src/ifc/export_content.rs b/src/ifc/export_content.rs index c5f800801..d67c5b280 100644 --- a/src/ifc/export_content.rs +++ b/src/ifc/export_content.rs @@ -1666,9 +1666,9 @@ fn wall_geometry_from_decoded(decoded: &DecodedElement) -> Option Option { use crate::partition_level_parameters as lp; // RE-319: the names Revit gives a conduit's, conduit fitting's or - // gutter's Level parameter are measured on no export (the one export that - // holds them is Revit 2018's IFC2X3, which writes no `Constraints` set on - // them), so none is written. + // gutter's Level parameter are not measured: the one export that holds + // them, Revit 2018's IFC2X3, writes no Revit parameter-group set on any + // element. So none is written. if matches!( ifc_type, "IFCCABLECARRIERSEGMENT" | "IFCCABLECARRIERFITTING"