Coverage for bim2sim/elements/mapping/condition.py: 57%

87 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2025-08-12 13:34 +0000

1"""Module for validating an element by a condition""" 

2import logging 

3 

4from bim2sim.elements.mapping.units import ureg 

5 

6 

7class Condition: 

8 """Class for validating an element by a condition""" 

9 

10 _logger = None 

11 

12 def __init__(self, name, critical_for_creation=True): 

13 self.name = name 

14 self.critical_for_creation = critical_for_creation 

15 

16 @property 

17 def logger(self): 

18 """logger instance""" 

19 if not Condition._logger: 

20 Condition._logger = logging.getLogger(__name__) 

21 return Condition._logger 

22 

23 def check(self, element, value): 

24 pass 

25 

26 

27class RangeCondition(Condition): 

28 """"Validate through a simple ValueRange 

29 

30 Args: 

31 key: attribute of the element to validate 

32 value_min: minimum allowed value 

33 value_max: maximum allowed value 

34 incl_edges: if True, the value_min and value_max are valid as well 

35 critical_for_creation: if True, the element will not be created if the validation fails 

36 Return: 

37 True if valid, False if not valid 

38 """ 

39 

40 def __init__(self, key: str, value_min, value_max, incl_edges: bool = False, 

41 critical_for_creation: bool = True): 

42 super().__init__(key, critical_for_creation) 

43 self.key = key 

44 self.valueMin = value_min 

45 self.valueMax = value_max 

46 self.incl_edges = incl_edges 

47 self.critical_for_creation = critical_for_creation 

48 

49 def check(self, element, value): 

50 if value is None: 

51 return False 

52 if not isinstance(value, (list, set)): 

53 value = [value] 

54 check_list = [] 

55 for v in value: 

56 if self.incl_edges: 

57 check_list.append(False if not v or v <= self.valueMin 

58 or v >= self.valueMax else True) 

59 else: 

60 check_list.append(False if not v or v < self.valueMin 

61 or v > self.valueMax else True) 

62 return all(check_list) 

63 

64 

65class ListCondition(Condition): 

66 """Validate if a list has elements, or a specific number of elements 

67 

68 Args: 

69 key: attribute of the element to validate 

70 values: list of allowed values 

71 critical_for_creation: if True, the element will not be created if the 

72 validation fails 

73 Return: 

74 True if valid, False if not valid 

75 """ 

76 

77 def __init__(self, key: str, list_length: int = None, 

78 critical_for_creation: bool = True): 

79 super().__init__(key, critical_for_creation) 

80 self.key = key 

81 self.listLength = list_length 

82 self.critical_for_creation = critical_for_creation 

83 

84 def check(self, element, value): 

85 if type(value) is not list: 

86 return False 

87 if self.listLength is None: 

88 return True if len(value) > 0 else False 

89 else: 

90 return True if len(value) == self.listLength else False 

91 

92 

93class ThicknessCondition(Condition): 

94 def __init__(self, key: str, 

95 threshold: ureg.Quantity = 0, 

96 critical_for_creation: bool = True): 

97 super().__init__(key, critical_for_creation) 

98 self.key = key 

99 self.threshold = threshold 

100 self.critical_for_creation = critical_for_creation 

101 

102 def check(self, element, value): 

103 if value is None: 

104 return False 

105 value_from_layers = sum(layer.thickness for layer in element.layers) 

106 if not value_from_layers: 

107 return False 

108 if not self.threshold: 

109 return True if value == value_from_layers else False 

110 discrepancy = abs(value - value_from_layers) / value 

111 return True if discrepancy <= self.threshold else False 

112 

113 

114class UValueCondition(Condition): 

115 def __init__(self, key: str, 

116 threshold: ureg.Quantity = 0, 

117 critical_for_creation: bool = True): 

118 super().__init__(key, critical_for_creation) 

119 self.key = key 

120 self.threshold = threshold 

121 self.critical_for_creation = critical_for_creation 

122 

123 def check(self, element, value): 

124 if value is None: 

125 return False 

126 value_from_layers = self.get_u_value_from_layers(element.layerset) 

127 if not value_from_layers: 

128 return False 

129 if not self.threshold: 

130 return True if value == value_from_layers else False 

131 discrepancy = abs(value - value_from_layers) / value 

132 return True if discrepancy <= self.threshold else False 

133 

134 @staticmethod 

135 def get_u_value_from_layers(layer_set): 

136 layers_r = 0 

137 for layer in layer_set.layers: 

138 if layer.thickness: 

139 if layer.material.thermal_conduc and \ 

140 layer.material.thermal_conduc > 0: 

141 layers_r += layer.thickness / layer.material.thermal_conduc 

142 

143 if layers_r > 0: 

144 return 1 / layers_r 

145 return None