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

52 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-12 17:09 +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('percent = 0.01*count = %') 

15ureg.define('EUR = currency') 

16ureg.define('USD = currency') 

17ureg.define('GBP = currency') 

18 

19# TODO:multiple ifc files 

20# ifc units are up2date to ifc 4.3 

21ifc_pint_unitmap = { 

22 'AMPERE': 'ampere', 

23 'BECQUEREL': 'becquerel', 

24 'CANDELA': 'candela', 

25 'COULOMB': 'coulomb', 

26 'CUBIC_METRE': 'cubic metre', 

27 'DEGREE_CELSIUS': 'degree_Celsius', 

28 'FARAD': 'farad', 

29 'GRAM': 'gram', 

30 'GRAY': 'gray', 

31 'HENRY': 'henry', 

32 'HERTZ': 'hertz', 

33 'JOULE': 'joule', 

34 'KELVIN': 'kelvin', 

35 'LUMEN': 'lumen', 

36 'LUX': 'lux', 

37 'METRE': 'metre', 

38 'MOLE': 'mole', 

39 'NEWTON': 'newton', 

40 'OHM': 'ohm', 

41 'PASCAL': 'pascal', 

42 'RADIAN': 'radian', 

43 'SECOND': 'second', 

44 'SIEMENS': 'siemens', 

45 'SIEVERT': 'sievert', 

46 'SQUARE_METRE': 'square metre', 

47 'STERADIAN': 'steradian', 

48 'TESLA': 'tesla', 

49 'VOLT': 'volt', 

50 'WATT': 'watt', 

51 'WEBER': 'weber', 

52} 

53 

54 

55def parse_ifc(unit_entity): 

56 """""" 

57 unit_type = unit_entity.is_a() 

58 if unit_type == 'IfcDerivedUnit': 

59 unit = ureg.dimensionless 

60 for element in unit_entity.Elements: 

61 prefix_string = \ 

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

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

64 ifc_pint_unitmap[ 

65 element.Unit.Name])) 

66 if element.Unit.Dimensions: 

67 unit_part = unit_part ** element.Dimensions 

68 unit = unit * unit_part ** element.Exponent 

69 return unit 

70 elif unit_type == 'IfcSIUnit': 

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

72 unit = ureg.parse_units( 

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

74 return unit 

75 elif unit_type in [ 

76 'IfcConversionBasedUnit', 

77 'IfcConversionBasedUnitWithOffset' 

78 ]: 

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

80 # ConversionFactor) 

81 unit_component = unit_entity.ConversionFactor.UnitComponent 

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

83 unit_component.Prefix else '' 

84 unit = ureg.parse_units( 

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

86 if unit_component.Dimensions: 

87 unit = unit ** unit_component.Dimensions 

88 return unit 

89 elif unit_type == 'IfcMonetaryUnit': 

90 currency = unit_entity.Currency 

91 try: 

92 unit = ureg.parse_units(currency) 

93 except: 

94 unit = ureg.dimensionless 

95 return unit 

96 elif unit_type == 'IfcDerivedUnitElement': 

97 unit = ureg.dimensionless 

98 prefix_string = \ 

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

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

101 ifc_pint_unitmap[ 

102 unit_type.Unit.Name])) 

103 if unit_type.Unit.Dimensions: 

104 unit_part = unit_part ** unit_type.Dimensions 

105 unit = unit * unit_part ** unit_type.Exponent 

106 return unit 

107 elif unit_type == 'IfcMeasureWithUnit': 

108 unit_component = unit_entity.UnitComponent 

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

110 if unit_component.Dimensions: 

111 unit = unit ** unit_component.Dimensions 

112 return unit 

113 else: 

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

115 f"Pint unit in Python.") 

116 # TODO: IfcDimensionalExponents,IfcContextDependentUnit