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

76 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2025-12-18 09:34 +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.plugins.PluginOpenFOAM.bim2sim_openfoam.utils.openfoam_utils import \ 

10 OpenFOAMUtils as of_utils 

11from bim2sim.utilities.types import BoundaryOrientation 

12 

13logger = logging.getLogger(__name__) 

14 

15 

16class StlBound(OpenFOAMBaseBoundaryFields, OpenFOAMBaseElement): 

17 def __init__(self, bound, radiation_model): 

18 super().__init__() 

19 self.radiation_model = radiation_model 

20 self.bound = bound 

21 self.guid = bound.guid 

22 self.bound_element_type = ( 

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

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

25 bound.top_bottom == 'TOP'): 

26 self.bound_element_type = 'Ceiling' 

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

28 # todo: test and remove? 

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

30 if bound.top_bottom == BoundaryOrientation.top: 

31 self.bound_element_type = 'Ceiling' 

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

33 '$', '___') 

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

35 bound.cfd_face = bound.bound_shape 

36 opening_shapes = [] 

37 if bound.opening_bounds: 

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

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

40 opening_shapes) 

41 self.temperature = 293.15 

42 self.heat_flux = 0 

43 self.power = 0 

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

45 self.set_default_refinement_level() 

46 self.set_patch_info_type() 

47 

48 def set_default_refinement_level(self): 

49 self.refinement_level = [2, 3] 

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

51 'InnerFloor', 'Floor', 'Roof', 

52 'GroundFloor', 'OuterDoor', 'Ceiling']: 

53 self.refinement_level = [2, 3] 

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

55 self.refinement_level = [2, 3] 

56 else: 

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

58 f"unknown") 

59 

60 def set_patch_info_type(self): 

61 # AirTerminal, SpaceHeater 

62 self.patch_info_type = 'wall' 

63 if self.bound_element_type == 'SpaceHeater': 

64 self.patch_info_type = 'wall' 

65 elif self.bound_element_type == 'AirTerminal': 

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

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

68 pass 

69 else: 

70 pass 

71 

72 def read_boundary_conditions(self, timestep_df, default_temp): 

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

74 if not self.bound.physical: 

75 self.heat_flux = 0 

76 self.power = 0 

77 self.temperature = default_temp - 273.15 

78 try: 

79 self.temperature = timestep_df[ 

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

81 except KeyError: 

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

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

84 self.heat_flux = 0 

85 self.power = 0 

86 self.temperature = default_temp - 273.15 

87 return 

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

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

90 'Conduction Heat Transfer ' 

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

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

93 'Conduction Heat Transfer ' 

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

95 'Hourly)')] 

96 self.heat_flux = prev_heat_flux 

97 else: 

98 self.heat_flux = (timestep_df[res_key + ( 

99 'Surface Window Net Heat Transfer ' 

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

101 self.bound_area) 

102 self.power = timestep_df[res_key + ( 

103 'Surface Window Net Heat Transfer ' 

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

105 

106 def set_boundary_conditions(self, no_heatloss=False): 

107 if self.radiation_model == 'none': 

108 qr = 'none' 

109 else: 

110 qr = 'qr' 

111 if no_heatloss: 

112 pass 

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

114 # else: # 

115 self.T = { 

116 'type': 'fixedValue', 

117 'value': f'uniform ' 

118 f'{of_utils.float_cutoff(self.temperature + 273.15)}' 

119 } 

120 else: 

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

122 'mode': 'power', 

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

124 'Q': f'uniform {of_utils.float_cutoff(self.power)}', 

125 'qrRelaxation': 0.003, 

126 'relaxation': 1.0, 

127 'kappaMethod': 'fluidThermo', 

128 'kappa': 'fluidThermo', 

129 'value': f'uniform ' 

130 f'{of_utils.float_cutoff(self.temperature + 273.15)}' 

131 }