Coverage for bim2sim/elements/mapping/units.py: 62%

53 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-10-01 10:24 +0000

1"""Module contains the unit registry for all params 

2 

3To handle different unit definitions in IFC files and get accurate values when 

4exporting later to simulation models, we use pint to maintain and check correct 

5unit definitions throughout the whole bim2sim chain. To get the correct units 

6when loading the IFC we convert IFC units to pint units. 

7""" 

8 

9from pint import UnitRegistry, set_application_registry 

10 

11# to avoid temperature problems 

12ureg = UnitRegistry(autoconvert_offset_to_baseunit=True) 

13set_application_registry(ureg) 

14ureg.define('watthour = watt * hour = Wh') 

15ureg.define('percent = 0.01*count = %') 

16ureg.define('EUR = currency') 

17ureg.define('USD = currency') 

18ureg.define('GBP = currency') 

19 

20# TODO:multiple ifc files 

21# ifc units are up2date to ifc 4.3 

22ifc_pint_unitmap = { 

23 'AMPERE': 'ampere', 

24 'BECQUEREL': 'becquerel', 

25 'CANDELA': 'candela', 

26 'COULOMB': 'coulomb', 

27 'CUBIC_METRE': 'cubic metre', 

28 'DEGREE_CELSIUS': 'degree_Celsius', 

29 'FARAD': 'farad', 

30 'GRAM': 'gram', 

31 'GRAY': 'gray', 

32 'HENRY': 'henry', 

33 'HERTZ': 'hertz', 

34 'JOULE': 'joule', 

35 'KELVIN': 'kelvin', 

36 'LUMEN': 'lumen', 

37 'LUX': 'lux', 

38 'METRE': 'metre', 

39 'MOLE': 'mole', 

40 'NEWTON': 'newton', 

41 'OHM': 'ohm', 

42 'PASCAL': 'pascal', 

43 'RADIAN': 'radian', 

44 'SECOND': 'second', 

45 'SIEMENS': 'siemens', 

46 'SIEVERT': 'sievert', 

47 'SQUARE_METRE': 'square metre', 

48 'STERADIAN': 'steradian', 

49 'TESLA': 'tesla', 

50 'VOLT': 'volt', 

51 'WATT': 'watt', 

52 'WEBER': 'weber', 

53} 

54 

55 

56def parse_ifc(unit_entity): 

57 """""" 

58 unit_type = unit_entity.is_a() 

59 if unit_type == 'IfcDerivedUnit': 

60 unit = ureg.dimensionless 

61 for element in unit_entity.Elements: 

62 prefix_string = \ 

63 element.Unit.Prefix.lower() if element.Unit.Prefix else '' 

64 unit_part = ureg.parse_units('{}{}'.format(prefix_string, 

65 ifc_pint_unitmap[ 

66 element.Unit.Name])) 

67 if element.Unit.Dimensions: 

68 unit_part = unit_part ** element.Dimensions 

69 unit = unit * unit_part ** element.Exponent 

70 return unit 

71 elif unit_type == 'IfcSIUnit': 

72 prefix_string = unit_entity.Prefix.lower() if unit_entity.Prefix else '' 

73 unit = ureg.parse_units( 

74 '{}{}'.format(prefix_string, ifc_pint_unitmap[unit_entity.Name])) 

75 return unit 

76 elif unit_type in [ 

77 'IfcConversionBasedUnit', 

78 'IfcConversionBasedUnitWithOffset' 

79 ]: 

80 # we use pint conversions instead IFC ones (ignoring ConversionOffset & 

81 # ConversionFactor) 

82 unit_component = unit_entity.ConversionFactor.UnitComponent 

83 prefix_string = unit_component.Prefix.lower() if \ 

84 unit_component.Prefix else '' 

85 unit = ureg.parse_units( 

86 '{}{}'.format(prefix_string, ifc_pint_unitmap[unit_component.Name])) 

87 if unit_component.Dimensions: 

88 unit = unit ** unit_component.Dimensions 

89 return unit 

90 elif unit_type == 'IfcMonetaryUnit': 

91 currency = unit_entity.Currency 

92 try: 

93 unit = ureg.parse_units(currency) 

94 except: 

95 unit = ureg.dimensionless 

96 return unit 

97 elif unit_type == 'IfcDerivedUnitElement': 

98 unit = ureg.dimensionless 

99 prefix_string = \ 

100 unit_type.Unit.Prefix.lower() if unit_type.Unit.Prefix else '' 

101 unit_part = ureg.parse_units('{}{}'.format(prefix_string, 

102 ifc_pint_unitmap[ 

103 unit_type.Unit.Name])) 

104 if unit_type.Unit.Dimensions: 

105 unit_part = unit_part ** unit_type.Dimensions 

106 unit = unit * unit_part ** unit_type.Exponent 

107 return unit 

108 elif unit_type == 'IfcMeasureWithUnit': 

109 unit_component = unit_entity.UnitComponent 

110 unit = ureg.parse_units(ifc_pint_unitmap[unit_component.Name]) 

111 if unit_component.Dimensions: 

112 unit = unit ** unit_component.Dimensions 

113 return unit 

114 else: 

115 raise NotImplementedError(f"Found {unit_type} and can't convert it to" 

116 f"Pint unit in Python.") 

117 # TODO: IfcDimensionalExponents,IfcContextDependentUnit