• BDNS-plus
  • Volumes & Levels
  • Tags
  • Customisations
  • Serialisation
  • Revit
  • Examples
  • Notes

Compare BDNS Abbreviations vs ifc4x3 classes

Code
import pandas as pd
import pathlib
from bsdd import Client
from bdns_plus.abbreviations import get_bdns_asset_abbreviations, get_asset_abbreviations_enum, get_asset_abbreviations
from itables import show
import pandas as pd
import re


IFC4X3_URI = "https://identifier.buildingsmart.org/uri/buildingsmart/ifc/4.3"

def ifc_strip_enum(ifc_class):
    return re.sub(r"([A-Z0-9_]+_?)$", "", ifc_class) 

def ifc_class_is_enum(ifc_class):
    if ifc_strip_enum(ifc_class) == ifc_class:
        return False
    else:
        return True

def get_ifc_classes(client):
    def get_batch(i):
        return client.get_classes(
            IFC4X3_URI,
            use_nested_classes=False,
            class_type="Class",
            offset=i[0],
            limit=i[1],
        )["classes"]

    ifc_classes = {}
    for i in [(0, 1000), (1000, 2000)]:  # 1418 classes in total. 1000 max request limit
        ifc_classes = ifc_classes | {x["code"]: x for x in get_batch(i)}
    return ifc_classes


client = Client()
ifc_classes = get_ifc_classes(client)
ifc_classes_core = {k:v for k, v in ifc_classes.items() if not ifc_class_is_enum(k)}
bdns_abbreviations = get_bdns_asset_abbreviations()

map_bdns_ifc = {x[1]: x[-2] for x in bdns_abbreviations[1:]}
ifc_in_bdns = set([x[-2] for x in bdns_abbreviations[1:]])

map_ifc_bdns = {}
for ifc in ifc_in_bdns:
    map_ifc_bdns[ifc] = [k for k, v in map_bdns_ifc.items() if v == ifc]
    
core_map_ifc_bdns  = {k:v for k,v in map_ifc_bdns.items() if not ifc_class_is_enum(k)}

_map_ifc_bdns = {k: [str(v)] for k, v in map_ifc_bdns.items()}
df_ifc_map_bdns = pd.DataFrame.from_dict(_map_ifc_bdns).T.reset_index().rename(columns={"index":"ifc4_3", 0:"bdns_abbreviation"})
# show(df_ifc_map_bdns)

Quantifying the task of adding at least 1no bdns abbreviation for every core IFC4x3 class

Code
print(f"len(ifc_classes)       = {len(ifc_classes)} ")
print(f"len(ifc_classes_core)  = {len(ifc_classes_core)}  (i.e. without the enum, e.g. IfcValve)")
print(f"len(core_map_ifc_bdns) = {len(core_map_ifc_bdns)}   (i.e. number of core Ifc classes with at least 1no mapping to an abbreviation)")

IfcClass’s that only have enums in BDNS, not the core class

Code
ifc_missing_core = sorted([x for x in list(set([ifc_strip_enum(x) for x in ifc_in_bdns])) if x not in core_map_ifc_bdns])
bdns_data = [x + [ifc_strip_enum(x[4])] for x in bdns_abbreviations[1:]] # add ifc core col
print(f"len(ifc_missing_core) = {len(ifc_missing_core)}")
print(f"-----")
for k, v in {x: [f"{b[4]} - {b[0]} - {b[1]}" for b in bdns_data if x == b[6]] for x in ifc_missing_core}.items():
    print(k)
    for _ in v:
        print(f"   {_}")
Code
def add_descriptions(abbreviations):
    map_abbreviation_description = get_asset_abbreviations()
    return [f"{x} - {map_abbreviation_description[x]}" for x in abbreviations]

core_map_ifc_bdns_descriptions = {k: add_descriptions(v) for k, v in core_map_ifc_bdns.items()}
core_map_ifc_bdns_one_to_one = {k:v[0] for k, v in core_map_ifc_bdns.items() if len(v) == 1}

# br = """
# """
br = "<br>"

updates = {'IfcDamper': 'DMP',
 'IfcCableSegment': 'CA',
 'IfcController': 'CNTRL',
 'IfcCompressor': 'CMP',
 'IfcLightFixture': 'LT',
 'IfcChiller': 'CH',
 'IfcWindow': 'WD',
 'IfcOutlet': 'OUT',
 'IfcTransformer': 'TXMR',
 'IfcPump': 'PMP',
 'IfcFlowMeter': 'MTR',
 'IfcSpaceHeater': 'HTR',
 'IfcFan': 'FAN',
 'IfcFilter': 'FLT',
 'IfcAirTerminal': 'AT'}

core_map_ifc_bdns_descriptions_str = {k: [br.join(v)] for k,v in core_map_ifc_bdns_descriptions.items()}
df = pd.DataFrame.from_dict(core_map_ifc_bdns_descriptions_str).T.reset_index().rename(columns={"index":"ifc_class", 0: "bdns_options"})
df["bdns_core"] = df.ifc_class.map(core_map_ifc_bdns_one_to_one)
df["bdns_suggested_updates"] = df.ifc_class.map(updates)
# df.to_csv("map.csv")
df.fillna("").style