Coverage for bim2sim/plugins/PluginOpenFOAM/bim2sim_openfoam/openfoam_elements/stlbound.py: 0%

75 statements  

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

1import logging 

2 

3from bim2sim.elements.base_elements import Element 

4from bim2sim.plugins.PluginOpenFOAM.bim2sim_openfoam.openfoam_elements.openfoam_base_boundary_conditions import \ 

5 OpenFOAMBaseBoundaryFields 

6from bim2sim.plugins.PluginOpenFOAM.bim2sim_openfoam.openfoam_elements.openfoam_base_element import \ 

7 OpenFOAMBaseElement 

8from bim2sim.utilities.pyocc_tools import PyOCCTools 

9from bim2sim.utilities.types import BoundaryOrientation 

10 

11logger = logging.getLogger(__name__) 

12 

13 

14class StlBound(OpenFOAMBaseBoundaryFields, OpenFOAMBaseElement): 

15 def __init__(self, bound, radiation_model): 

16 super().__init__() 

17 self.radiation_model = radiation_model 

18 self.bound = bound 

19 self.guid = bound.guid 

20 self.bound_element_type = ( 

21 bound.bound_element.__class__.__name__.replace('Disaggregated', '')) 

22 if (self.bound_element_type in ['Floor', 'InnerFloor'] and 

23 bound.top_bottom == 'TOP'): 

24 self.bound_element_type = 'Ceiling' 

25 # hotfix for incorrectly assigned floors and roofs in bim2sim elements 

26 # todo: test and remove? 

27 if self.bound_element_type in ['InnerFloor']: 

28 if bound.top_bottom == BoundaryOrientation.top: 

29 self.bound_element_type = 'Ceiling' 

30 self.solid_name = self.bound_element_type + '_' + bound.guid.replace( 

31 '$', '___') 

32 if not hasattr(bound, 'cfd_face'): 

33 bound.cfd_face = bound.bound_shape 

34 opening_shapes = [] 

35 if bound.opening_bounds: 

36 opening_shapes = [s.bound_shape for s in bound.opening_bounds] 

37 self.tri_geom = PyOCCTools.triangulate_bound_shape(bound.cfd_face, 

38 opening_shapes) 

39 self.temperature = 293.15 

40 self.heat_flux = 0 

41 self.power = 0 

42 self.bound_area = PyOCCTools.get_shape_area(self.tri_geom) 

43 self.set_default_refinement_level() 

44 self.set_patch_info_type() 

45 

46 def set_default_refinement_level(self): 

47 self.refinement_level = [2, 3] 

48 if self.bound_element_type in ['OuterWall', 'Window', 'Door', 

49 'InnerFloor', 'Floor', 'Roof', 

50 'GroundFloor', 'OuterDoor', 'Ceiling']: 

51 self.refinement_level = [2, 3] 

52 elif self.bound_element_type in ['InnerWall', 'Wall', 'InnerDoor']: 

53 self.refinement_level = [2, 3] 

54 else: 

55 logger.warning(f"{self.bound_element_type} bound_element_type is " 

56 f"unknown") 

57 

58 def set_patch_info_type(self): 

59 # AirTerminal, SpaceHeater 

60 self.patch_info_type = 'wall' 

61 if self.bound_element_type == 'SpaceHeater': 

62 self.patch_info_type = 'wall' 

63 elif self.bound_element_type == 'AirTerminal': 

64 # todo: implement distinction for inlet (Zuluft) and outlet ( 

65 # Abluft), for the surface itself and the surrounding boxes. 

66 pass 

67 else: 

68 pass 

69 

70 def read_boundary_conditions(self, timestep_df, default_temp): 

71 res_key = self.guid.upper() + ':' 

72 if not self.bound.physical: 

73 self.heat_flux = 0 

74 self.power = 0 

75 self.temperature = default_temp - 273.15 

76 try: 

77 self.temperature = timestep_df[ 

78 res_key + 'Surface Inside Face Temperature [C](Hourly)'] 

79 except KeyError: 

80 logger.warning(f"the boundary with guid %s does not provide a " 

81 f"surface inside face temperature and is set to adiabatic.", self.guid) 

82 self.heat_flux = 0 

83 self.power = 0 

84 self.temperature = default_temp - 273.15 

85 return 

86 if not self.bound_element_type == 'Window': 

87 self.power = timestep_df[res_key + ('Surface Inside Face ' 

88 'Conduction Heat Transfer ' 

89 'Rate [W](Hourly)')] 

90 prev_heat_flux = timestep_df[res_key + ('Surface Inside Face ' 

91 'Conduction Heat Transfer ' 

92 'Rate per Area [W/m2](' 

93 'Hourly)')] 

94 self.heat_flux = prev_heat_flux 

95 else: 

96 self.heat_flux = (timestep_df[res_key + ( 

97 'Surface Window Net Heat Transfer ' 

98 'Rate [W](Hourly)')] / 

99 self.bound_area) 

100 self.power = timestep_df[res_key + ( 

101 'Surface Window Net Heat Transfer ' 

102 'Rate [W](Hourly)')] 

103 

104 def set_boundary_conditions(self, no_heatloss=False): 

105 if self.radiation_model == 'none': 

106 qr = 'none' 

107 else: 

108 qr = 'qr' 

109 if no_heatloss: 

110 pass 

111 elif any(i for i in ["INNER", "FLOOR"] if i in self.solid_name.upper()): 

112 # else: # 

113 self.T = { 

114 'type': 'fixedValue', 

115 'value': f'uniform {self.temperature + 273.15}' 

116 } 

117 else: 

118 self.T = {'type': 'externalWallHeatFluxTemperature', 

119 'mode': 'power', 

120 'qr': f"{qr}", 

121 'Q': f'uniform {self.power}', 

122 'qrRelaxation': 0.003, 

123 'relaxation': 1.0, 

124 'kappaMethod': 'fluidThermo', 

125 'kappa': 'fluidThermo', 

126 'value': f'uniform {self.temperature + 273.15}' 

127 }