Coverage for bim2sim/plugins/PluginEnergyPlus/bim2sim_energyplus/task/ep_ifc_validation.py: 0%

127 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-03-12 17:09 +0000

1import json 

2 

3from bim2sim.tasks.base import ITask 

4 

5 

6class IfcValidation(ITask): 

7 """ 

8 Validate IFC file, focussing on energy modeling (use of space boundaries). 

9 

10 See run method for further details. 

11 """ 

12 

13 reads = ('ifc_files', ) 

14 

15 def __init__(self, playground): 

16 super().__init__(playground) 

17 self.error_summary = {} 

18 self.bounds = [] 

19 self.id_list = [] 

20 

21 def run(self, ifc_files): 

22 """ 

23 IFC file validation for EnergyPlus. No longer maintained. 

24 

25 This function holds an IFC file validation for EnergyPlus, but is no 

26 longer used. This task is replaced by the CheckIFC class in the 

27 common task section. For building performance simulation workflows 

28 like EnergyPlus, the common CheckIfc class executes the BEPS specific 

29 CheckIfcBPS methods. 

30 

31 Args: 

32 ifc_files: input ifc files. 

33 """ 

34 self.bounds = [] 

35 self.id_list = [] 

36 for ifc in ifc_files: 

37 

38 self.bounds.extend(ifc.by_type('IfcRelSpaceBoundary')) 

39 self.id_list.extend([e.GlobalId for e in ifc.by_type("IfcRoot")]) 

40 

41 self._check_space_boundaries() 

42 self._write_errors_to_json() 

43 self._evaluate_checks() 

44 

45 def _check_space_boundaries(self): 

46 """ Perform space boundary validation and add errors to error summary.""" 

47 self.logger.info("Check syntax of IfcRelSpaceBoundary") 

48 for bound in self.bounds: 

49 sbv = SpaceBoundaryValidation(bound, self.id_list) 

50 if len(sbv.error) > 0: 

51 self.error_summary.update({bound.GlobalId: sbv.error}) 

52 

53 def _write_errors_to_json(self): 

54 """write error summary to json file for export.""" 

55 with open(str(self.paths.root) + "/export/" + 'ifc_SB_error_summary.json', 'w+') as fp: 

56 json.dump(self.error_summary, fp, indent="\t") 

57 self.logger.info("All tests done!") 

58 

59 def _evaluate_checks(self): 

60 """Add error summary to logging.""" 

61 if len(self.error_summary) == 0: 

62 self.logger.info( 

63 "All %d IfcRelSpaceBoundary entities PASSED the syntax validation process." % len(self.bounds)) 

64 else: 

65 self.logger.warning("%d out of %d IfcRelSpaceBoundary entities FAILED the syntax validation process. \n" 

66 "Occuring sets of errors: %s \n" 

67 "See ifc_SB_error_summary.json for further information on the errors." 

68 % (len(self.error_summary), 

69 len(self.bounds), 

70 set(tuple(s) for s in [vals for key, vals in self.error_summary.items()]))) 

71 

72 

73class SpaceBoundaryValidation: 

74 """ 

75 Validate IFC Space Boundaries for use in EnergyPlus 

76 """ 

77 def __init__(self, bound, id_list): 

78 self.error = [] 

79 self.bound = bound 

80 self.id_list = id_list 

81 self._validate_space_boundaries() 

82 

83 def _validate_space_boundaries(self): 

84 self._apply_validation_function(self._check_unique(), 'GlobalId') 

85 self._apply_validation_function(self._check_level(), '2ndLevel') 

86 self._apply_validation_function(self._check_description(), 'Description') 

87 self._apply_validation_function(self._check_rel_space(), 'RelatingSpace') 

88 self._apply_validation_function(self._check_rel_building_elem(), 'RelatedBuildingElement') 

89 self._apply_validation_function(self._check_conn_geom(), 'ConnectionGeometry') 

90 self._apply_validation_function(self._check_phys_virt_bound(), 'PhysicalOrVirtualBoundary') 

91 self._apply_validation_function(self._check_int_ext_bound(), 'InternalOrExternalBoundary') 

92 self._apply_validation_function(self._check_on_relating_elem(), 'SurfaceOnRelatingElement') 

93 self._apply_validation_function(self._check_on_related_elem(), 'SurfaceOnRelatedElement') 

94 self._apply_validation_function(self._check_basis_surface(), 'BasisSurface') 

95 self._apply_validation_function(self._check_inner_boundaries(), 'InnerBoundaries') 

96 if hasattr(self.bound.ConnectionGeometry.SurfaceOnRelatingElement.OuterBoundary, 'Segments'): 

97 self._apply_validation_function(self._check_outer_boundary_composite(), 'OuterBoundaryCompositeCurve') 

98 self._apply_validation_function(self._check_segments(), 'Segments') 

99 self._apply_validation_function(self._check_segments_poly(), 'SegmentsPolyline') 

100 self._apply_validation_function(self._check_segments_poly_coord(), 'SegmentsPolylineCoordinates') 

101 else: 

102 self._apply_validation_function(self._check_outer_boundary_poly(), 'OuterBoundaryPolyline') 

103 self._apply_validation_function(self._check_outer_boundary_poly_coord(), 'OuterBoundaryPolylineCoordinates') 

104 self._apply_validation_function(self._check_plane_position(), 'Position') 

105 self._apply_validation_function(self._check_location(), 'Location') 

106 self._apply_validation_function(self._check_axis(), 'Axis') 

107 self._apply_validation_function(self._check_refdirection(), 'RefDirection') 

108 self._apply_validation_function(self._check_location_coord(), 'LocationCoordinates') 

109 self._apply_validation_function(self._check_axis_dir_ratios(), 'AxisDirectionRatios') 

110 self._apply_validation_function(self._check_refdirection_dir_ratios(), 'RefDirectionDirectionRatios') 

111 

112 def _apply_validation_function(self, fct, err_name): 

113 if not fct: 

114 self.error.append(err_name) 

115 

116 def _check_unique(self): 

117 return self.id_list.count(self.bound.GlobalId) == 1 

118 

119 def _check_level(self): 

120 return self.bound.Name == "2ndLevel" 

121 

122 def _check_description(self): 

123 return self.bound.Description in {'2a', '2b'} 

124 

125 def _check_rel_space(self): 

126 return any( 

127 [self.bound.RelatingSpace.is_a('IfcSpace') or self.bound.RelatingSpace.is_a('IfcExternalSpatialElement')]) 

128 

129 def _check_rel_building_elem(self): 

130 if self.bound.RelatedBuildingElement is not None: 

131 return self.bound.RelatedBuildingElement.is_a('IfcBuildingElement') 

132 

133 def _check_conn_geom(self): 

134 return self.bound.ConnectionGeometry.is_a('IfcConnectionSurfaceGeometry') 

135 

136 def _check_phys_virt_bound(self): 

137 return self.bound.PhysicalOrVirtualBoundary.upper() in {'PHYSICAL', 'VIRTUAL'} 

138 

139 def _check_int_ext_bound(self): 

140 return self.bound.InternalOrExternalBoundary.upper() in {'INTERNAL', 

141 'EXTERNAL', 

142 'EXTERNAL_EARTH', 

143 'EXTERNAL_FIRE', 

144 'EXTERNAL_WATER' 

145 } 

146 

147 def _check_on_relating_elem(self): 

148 return self.bound.ConnectionGeometry.SurfaceOnRelatingElement.is_a('IfcCurveBoundedPlane') 

149 

150 def _check_on_related_elem(self): 

151 return self.bound.ConnectionGeometry.SurfaceOnRelatedElement is None 

152 

153 def _check_basis_surface(self): 

154 return self.bound.ConnectionGeometry.SurfaceOnRelatingElement.BasisSurface.is_a('IfcPlane') 

155 

156 def _check_outer_boundary_composite(self): 

157 return self.bound.ConnectionGeometry.SurfaceOnRelatingElement.OuterBoundary.is_a('IfcCompositeCurve') 

158 

159 def _check_outer_boundary_poly(self): 

160 return self._check_poly_points(self.bound.ConnectionGeometry.SurfaceOnRelatingElement.OuterBoundary) 

161 

162 def _check_outer_boundary_poly_coord(self): 

163 return all(self.bound.ConnectionGeometry.SurfaceOnRelatingElement.OuterBoundary) 

164 

165 def _check_inner_boundaries(self): 

166 return (self.bound.ConnectionGeometry.SurfaceOnRelatingElement.InnerBoundaries is None) or \ 

167 (i.is_a('IfcCompositeCurve') 

168 for i in self.bound.ConnectionGeometry.SurfaceOnRelatingElement.InnerBoundaries) 

169 

170 def _check_segments(self): 

171 return (s.is_a('IfcPolyline') 

172 for s in self.bound.ConnectionGeometry.SurfaceOnRelatingElement.OuterBoundary.Segments) 

173 

174 def _check_segments_poly(self): 

175 return all(self._check_poly_points(s.ParentCurve) 

176 for s in self.bound.ConnectionGeometry.SurfaceOnRelatingElement.OuterBoundary.Segments) 

177 

178 def _check_segments_poly_coord(self): 

179 return all(self._check_poly_points_coord(s.ParentCurve) 

180 for s in self.bound.ConnectionGeometry.SurfaceOnRelatingElement.OuterBoundary.Segments) 

181 

182 def _check_plane_position(self): 

183 return self.bound.ConnectionGeometry.SurfaceOnRelatingElement.BasisSurface.Position.is_a('IfcAxis2Placement3D') 

184 

185 def _check_poly_points(self, polyline): 

186 return polyline.is_a('IfcPolyline') 

187 

188 def _check_location(self): 

189 return self.bound.ConnectionGeometry.SurfaceOnRelatingElement.BasisSurface.Position.Location.is_a( 

190 'IfcCartesianPoint') 

191 

192 def _check_axis(self): 

193 return self.bound.ConnectionGeometry.SurfaceOnRelatingElement.BasisSurface.Position.Axis.is_a('IfcDirection') 

194 

195 def _check_refdirection(self): 

196 return self.bound.ConnectionGeometry.SurfaceOnRelatingElement.BasisSurface.Position.RefDirection.is_a( 

197 'IfcDirection') 

198 

199 def _check_coords(self, points): 

200 return points.is_a('IfcCartesianPoint') and 1 <= len(points.Coordinates) <= 4 

201 

202 def _check_dir_ratios(self, dir_ratios): 

203 return 2 <= len(dir_ratios.DirectionRatios) <= 3 

204 

205 def _check_poly_points_coord(self, polyline): 

206 return all(self._check_coords(p) for p in polyline.Points) 

207 

208 def _check_location_coord(self): 

209 return self._check_coords(self.bound.ConnectionGeometry.SurfaceOnRelatingElement.BasisSurface.Position.Location) 

210 

211 def _check_axis_dir_ratios(self): 

212 return self._check_dir_ratios(self.bound.ConnectionGeometry.SurfaceOnRelatingElement.BasisSurface.Position.Axis) 

213 

214 def _check_refdirection_dir_ratios(self): 

215 return self._check_dir_ratios( 

216 self.bound.ConnectionGeometry.SurfaceOnRelatingElement.BasisSurface.Position.RefDirection)