Coverage for bim2sim/plugins/PluginOpenFOAM/bim2sim_openfoam/task/init_openfoam_setup.py: 0%

143 statements  

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

1import math 

2import pathlib 

3import shutil 

4from datetime import datetime 

5 

6import pandas as pd 

7 

8from bim2sim.plugins.PluginEnergyPlus.bim2sim_energyplus.utils import \ 

9 PostprocessingUtils 

10from bim2sim.plugins.PluginOpenFOAM.bim2sim_openfoam.openfoam_elements.openfoam_case import \ 

11 OpenFOAMCase 

12from bim2sim.plugins.PluginOpenFOAM.bim2sim_openfoam.utils.openfoam_utils import \ 

13 OpenFOAMUtils 

14from bim2sim.tasks.base import ITask 

15from butterfly import fvSolution, fvSchemes, controlDict, \ 

16 decomposeParDict, foamfile, turbulenceProperties, g 

17 

18 

19class InitializeOpenFOAMSetup(ITask): 

20 """This ITask initializes the OpenFOAM Setup. 

21 """ 

22 

23 reads = () 

24 touches = ('openfoam_case',) 

25 

26 single_use = False 

27 

28 def __init__(self, playground): 

29 super().__init__(playground) 

30 

31 def run(self): 

32 openfoam_case = OpenFOAMCase(playground=self.playground) 

33 self.create_directory(openfoam_case) 

34 # setup system 

35 self.create_fvSolution(openfoam_case) 

36 self.create_fvSchemes(openfoam_case) 

37 self.create_controlDict(openfoam_case, 

38 self.playground.sim_settings.total_iterations) 

39 self.create_decomposeParDict(openfoam_case) 

40 # setup constant 

41 self.create_g(openfoam_case) 

42 self.create_radiationProperties(openfoam_case) 

43 self.create_thermophysicalProperties(openfoam_case) 

44 self.create_turbulenceProperties(openfoam_case) 

45 self.create_jobscripts(openfoam_case, self.playground.sim_settings) 

46 self.read_ep_results(openfoam_case, 

47 date=self.playground.sim_settings.simulation_date, 

48 time=self.playground.sim_settings.simulation_time) 

49 return openfoam_case, 

50 

51 def create_directory(self, openfoam_case): 

52 openfoam_case.default_templates_dir = ( 

53 pathlib.Path(__file__).parent.parent / 'assets' / 'templates') 

54 openfoam_case.openfoam_dir = self.paths.export / 'OpenFOAM' 

55 openfoam_case.openfoam_dir.mkdir(exist_ok=True) 

56 openfoam_case.openfoam_systems_dir = (openfoam_case.openfoam_dir / 

57 'system') 

58 openfoam_case.openfoam_constant_dir = (openfoam_case.openfoam_dir / 

59 'constant') 

60 openfoam_case.openfoam_0_dir = openfoam_case.openfoam_dir / '0' 

61 openfoam_case.openfoam_systems_dir.mkdir(exist_ok=True) 

62 openfoam_case.openfoam_constant_dir.mkdir(exist_ok=True) 

63 openfoam_case.openfoam_0_dir.mkdir(exist_ok=True) 

64 openfoam_case.openfoam_triSurface_dir = ( 

65 openfoam_case.openfoam_constant_dir / 'triSurface') 

66 openfoam_case.openfoam_triSurface_dir.mkdir(exist_ok=True) 

67 

68 @staticmethod 

69 def create_fvSolution(openfoam_case): 

70 openfoam_case.fvSolution = fvSolution.FvSolution() 

71 if openfoam_case.transient_simulation: 

72 # todo: for Final values, fix $U, $... that are currently not 

73 # recognized (and not imported). Options: (1) add an extended 

74 # version of fvSolution that does not contain any $... assignments, 

75 # or (2) modify the foamFile parser (?) to handle $... assignments 

76 # self.fvSolution = self.fvSolution.from_file( 

77 # self.default_templates_dir / 'system' / 'transient' 

78 # / 'fvSolution') 

79 # implemented hotfix: copy file to temp dir. 

80 shutil.copy2(openfoam_case.default_templates_dir / 'system' / 

81 'transient' / 'fvSolution', 

82 openfoam_case.openfoam_systems_dir) 

83 # todo: currently, fvSolution cannot be accessed using butterfly 

84 openfoam_case.fvSolution = None 

85 else: 

86 openfoam_case.fvSolution = openfoam_case.fvSolution.from_file( 

87 openfoam_case.default_templates_dir / 'system' / 'steadyState' 

88 / 'fvSolution') 

89 openfoam_case.fvSolution.save(openfoam_case.openfoam_dir) 

90 

91 @staticmethod 

92 def create_fvSchemes(openfoam_case): 

93 openfoam_case.fvSchemes = fvSchemes.FvSchemes() 

94 if openfoam_case.transient_simulation: 

95 openfoam_case.fvSchemes = openfoam_case.fvSchemes.from_file( 

96 openfoam_case.default_templates_dir / 

97 'system' / 'transient' / 

98 'fvSchemes') 

99 else: 

100 openfoam_case.fvSchemes = openfoam_case.fvSchemes.from_file( 

101 openfoam_case.default_templates_dir / 

102 'system' / 

103 'steadyState' / 

104 'fvSchemes') 

105 openfoam_case.fvSchemes.save(openfoam_case.openfoam_dir) 

106 

107 @staticmethod 

108 def create_controlDict(openfoam_case, total_iterations): 

109 openfoam_case.controlDict = controlDict.ControlDict() 

110 if openfoam_case.transient_simulation: 

111 openfoam_case.controlDict = openfoam_case.controlDict.from_file( 

112 openfoam_case.default_templates_dir / 'system' / 'transient' / 

113 'controlDict') 

114 else: 

115 openfoam_case.controlDict = openfoam_case.controlDict.from_file( 

116 openfoam_case.default_templates_dir / 'system' / 'steadyState' / 

117 'controlDict') 

118 openfoam_case.controlDict.save(openfoam_case.openfoam_dir) 

119 openfoam_case.controlDict.endTime = total_iterations 

120 

121 @staticmethod 

122 def create_decomposeParDict(openfoam_case): 

123 openfoam_case.decomposeParDict = decomposeParDict.DecomposeParDict() 

124 if openfoam_case.transient_simulation: 

125 openfoam_case.decomposeParDict = ( 

126 openfoam_case.decomposeParDict.from_file( 

127 openfoam_case.default_templates_dir / 'system' / 

128 'transient' / 'decomposeParDict')) 

129 else: 

130 openfoam_case.decomposeParDict = ( 

131 openfoam_case.decomposeParDict.from_file( 

132 openfoam_case.default_templates_dir / 'system' / 

133 'steadyState' / 'decomposeParDict')) 

134 prev_procs = openfoam_case.decomposeParDict.get_value_by_parameter( 

135 'numberOfSubdomains') 

136 if prev_procs != openfoam_case.n_procs: 

137 hc1 = openfoam_case.decomposeParDict.get_value_by_parameter( 

138 'hierarchicalCoeffs') 

139 distrib = OpenFOAMUtils.split_into_three_factors( 

140 openfoam_case.n_procs) 

141 openfoam_case.decomposeParDict.set_value_by_parameter( 

142 'numberOfSubdomains', str(openfoam_case.n_procs)) 

143 distrib = '(' + str(distrib[0]) + ' ' + str(distrib[1]) + ' ' + \ 

144 str(distrib[2]) + ')' 

145 hc1['n'] = distrib 

146 openfoam_case.decomposeParDict.set_value_by_parameter( 

147 'hierarchicalCoeffs', hc1) 

148 openfoam_case.decomposeParDict.save(openfoam_case.openfoam_dir) 

149 

150 @staticmethod 

151 def create_g(openfoam_case): 

152 openfoam_case.g = g.G() 

153 openfoam_case.g = openfoam_case.g.from_file( 

154 openfoam_case.default_templates_dir / 'constant' / 'g') 

155 openfoam_case.g.save(openfoam_case.openfoam_dir) 

156 

157 @staticmethod 

158 def create_radiationProperties(openfoam_case): 

159 # todo: create radiationProperties module? 

160 if openfoam_case.radiation_model == 'fvDOM': 

161 thispath = (openfoam_case.default_templates_dir / 'constant' / 

162 'radiation' / 'fvDOM' / 

163 'radiationProperties') 

164 else: # P1 or preconditioned fvDOM or "noRadiation" 

165 thispath = (openfoam_case.default_templates_dir / 'constant' / 

166 'radiation' / 'P1' / 

167 'radiationProperties') 

168 posixpath = thispath.as_posix() 

169 

170 openfoam_case.radiationProperties = foamfile.FoamFile.from_file( 

171 posixpath) 

172 if openfoam_case.radiation_model == 'none': 

173 openfoam_case.radiationProperties.set_value_by_parameter( 

174 'radiationModel', 'none') 

175 openfoam_case.radiationProperties.set_value_by_parameter( 

176 'radiation', 'off') 

177 openfoam_case.radiationProperties.save(openfoam_case.openfoam_dir) 

178 

179 @staticmethod 

180 def create_thermophysicalProperties(openfoam_case): 

181 # todo: create thermophysicalProperties module? 

182 thispath = (openfoam_case.default_templates_dir / 'constant' / 

183 'thermophysicalProperties') 

184 posixpath = thispath.as_posix() 

185 

186 openfoam_case.thermophysicalProperties = foamfile.FoamFile.from_file( 

187 posixpath) 

188 openfoam_case.thermophysicalProperties.save(openfoam_case.openfoam_dir) 

189 

190 @staticmethod 

191 def create_turbulenceProperties(openfoam_case): 

192 openfoam_case.turbulenceProperties = ( 

193 turbulenceProperties.TurbulenceProperties()) 

194 openfoam_case.turbulenceProperties = ( 

195 openfoam_case.turbulenceProperties.from_file( 

196 openfoam_case.default_templates_dir / 'constant' / 

197 'turbulenceProperties')) 

198 openfoam_case.turbulenceProperties.save(openfoam_case.openfoam_dir) 

199 

200 @staticmethod 

201 def create_jobscripts(openfoam_case, simsettings): 

202 openfoam_case.openfoam_scripts_dir = openfoam_case.openfoam_dir 

203 openfoam_case.openfoam_scripts_dir.mkdir(exist_ok=True) 

204 script_files = ['fullRun.sh', 'runMeshing.sh', 'runSimulation.sh'] 

205 comp_acct = "" if not simsettings.cluster_compute_account else ( 

206 "#SBATCH --account=" + simsettings.cluster_compute_account) 

207 replacements = {"JOBNAME": simsettings.cluster_jobname, 

208 "STIME": simsettings.cluster_max_runtime_simulation, 

209 "MTIME": simsettings.cluster_max_runtime_meshing, 

210 "COMP_ACCOUNT": comp_acct, 

211 "NNODES": str(math.ceil( 

212 openfoam_case.n_procs/simsettings.cluster_cpu_per_node)), 

213 "NPROCS": str(openfoam_case.n_procs)} 

214 open(openfoam_case.openfoam_dir / 'paraview.foam', 'x') 

215 for script_file in script_files: 

216 src = openfoam_case.default_templates_dir / 'scripts' / script_file 

217 with open(src, 'r') as file: 

218 content = file.read() 

219 for key, value in replacements.items(): 

220 content = content.replace(key, value) 

221 dst = openfoam_case.openfoam_scripts_dir / script_file 

222 with open(dst, 'w') as file: 

223 file.write(content) 

224 

225 def read_ep_results(self, openfoam_case, year=1900, date='12/21', time=11): 

226 try: 

227 full_results_df = pd.read_csv( 

228 self.paths.export / 'EnergyPlus' / 'SimResults' / 

229 self.playground.project.name 

230 / 'eplusout.csv') 

231 full_results_df['Date/Time'] = full_results_df['Date/Time'].apply( 

232 PostprocessingUtils._string_to_datetime) 

233 full_results_df = full_results_df.set_index('Date/Time') 

234 target_date = datetime.strptime(f"{year}-{date} {time:02}", "%Y-%m/%d %H") 

235 if target_date in full_results_df.index: 

236 openfoam_case.timestep_df = full_results_df.loc[ 

237 f"{year}-{date} {time:02}:00:00"] 

238 else: 

239 self.logger.warning(f"The requested date: {year}-{date} {time:02} " 

240 f"is not available in the eplusout.csv file. " 

241 f"Calculating the closest available timestep " 

242 f"for the selected hour of the day.") 

243 target_day = pd.to_datetime(target_date).dayofyear 

244 dates = full_results_df.index 

245 filtered_dates = dates[dates.hour == time] 

246 delta = (filtered_dates.dayofyear - target_day) % 366 

247 min_delta = delta.min() 

248 new_date = filtered_dates[delta == min_delta] 

249 openfoam_case.timestep_df = full_results_df.loc[ 

250 new_date].squeeze(axis=0) 

251 self.logger.warning(f"The new date is set to {new_date}. This is " 

252 f"the timestep for the OpenFOAM simulation.") 

253 except FileNotFoundError: 

254 self.logger.warning("No sim_results found. Boundary conditions " 

255 "cannot be generated. ")