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

203 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2025-12-18 09:34 +0000

1from collections import OrderedDict 

2 

3import stl 

4from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut 

5from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox 

6from OCC.Core.StlAPI import StlAPI_Writer 

7from OCC.Core.TopOpeBRep import TopOpeBRep_ShapeIntersector 

8from OCC.Core.gp import gp_Pnt 

9from stl import mesh 

10 

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

12 OpenFOAMUtils as of_utils 

13from bim2sim.tasks.base import ITask 

14from bim2sim.utilities.common_functions import filter_elements 

15from bim2sim.utilities.pyocc_tools import PyOCCTools 

16from butterfly import (blockMeshDict, snappyHexMeshDict, foamfile, 

17 surfaceFeatureExtractDict) 

18 

19 

20class CreateOpenFOAMMeshing(ITask): 

21 """This ITask initializes the OpenFOAM Meshing. 

22 """ 

23 

24 reads = ('openfoam_case', 'openfoam_elements') 

25 touches = ('openfoam_case', 'openfoam_elements') 

26 

27 def __init__(self, playground): 

28 super().__init__(playground) 

29 

30 def run(self, openfoam_case, openfoam_elements): 

31 # create blockMesh based on surface geometry 

32 self.create_blockMesh(openfoam_case) 

33 # create snappyHexMesh based on surface types 

34 self.create_snappyHexMesh(openfoam_case, openfoam_elements) 

35 self.update_snappyHexMesh_heating(openfoam_case, openfoam_elements) 

36 self.add_topoSetDict_for_heating(openfoam_case, openfoam_elements) 

37 if self.playground.sim_settings.add_air_volume_evaluation: 

38 self.modify_topoSet_for_evaluation(openfoam_case, openfoam_elements) 

39 self.update_blockMeshDict_air(openfoam_case, openfoam_elements) 

40 self.update_snappyHexMesh_air(openfoam_case, openfoam_elements) 

41 self.update_snappyHexMesh_furniture(openfoam_case, openfoam_elements) 

42 self.update_snappyHexMesh_people(openfoam_case, openfoam_elements) 

43 self.update_snappyHexMesh_mesh_controls(openfoam_case) 

44 if self.playground.sim_settings.mesh_feature_snapping: 

45 self.create_surfaceFeatureExtract(openfoam_case) 

46 

47 return openfoam_case, openfoam_elements 

48 

49 def create_blockMesh(self, openfoam_case, resize_factor=0.1, shape=None): 

50 mesh_size = self.playground.sim_settings.mesh_size 

51 if not shape: 

52 shape = openfoam_case.current_zone.space_shape 

53 (min_pt, max_pt) = PyOCCTools.simple_bounding_box(shape) 

54 scaled_min_pt = [] 

55 scaled_max_pt = [] 

56 len_xyz = [] 

57 for p1, p2 in zip(min_pt, max_pt): 

58 p1 -= resize_factor 

59 p2 += resize_factor 

60 len_xyz.append(p2 - p1) 

61 scaled_min_pt.append(p1) 

62 scaled_max_pt.append(p2) 

63 

64 # calculate number of cells per xyz direction 

65 n_div_xyz = (round(len_xyz[0] / mesh_size), 

66 round(len_xyz[1] / mesh_size), 

67 round(len_xyz[2] / mesh_size)) 

68 scaled_min_pt = [of_utils.float_cutoff(i) for i in scaled_min_pt] 

69 scaled_max_pt = [of_utils.float_cutoff(i) for i in scaled_max_pt] 

70 openfoam_case.blockMeshDict = blockMeshDict.BlockMeshDict.from_min_max( 

71 scaled_min_pt, scaled_max_pt, n_div_xyz=n_div_xyz) 

72 openfoam_case.blockMeshDict.save(openfoam_case.openfoam_dir) 

73 

74 @staticmethod 

75 def create_surfaceFeatureExtract(openfoam_case): 

76 """Initialize surfaceFeatureExtractDict""" 

77 level = 0 

78 features_string = "(" 

79 openfoam_case.surfaceFeatureExtract = ( 

80 surfaceFeatureExtractDict.SurfaceFeatureExtractDict()) 

81 for stl_file in openfoam_case.snappyHexMeshDict.stl_file_names: 

82 openfoam_case.surfaceFeatureExtract.update_values( 

83 surfaceFeatureExtractDict.SurfaceFeatureExtractDict.from_stl_file( 

84 stl_file + '.stl').values) 

85 features_string += (f'{{file "{stl_file}.eMesh";' 

86 f'level {level};}}') 

87 features_string += ")" 

88 openfoam_case.snappyHexMeshDict.features = features_string 

89 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

90 openfoam_case.surfaceFeatureExtract.save(openfoam_case.openfoam_dir) 

91 

92 def create_snappyHexMesh(self, openfoam_case, openfoam_elements, ): 

93 stl_name = "space_" + openfoam_case.current_zone.guid 

94 region_names = [] 

95 regions = {} 

96 mesh_objects = mesh.Mesh.from_multi_file( 

97 openfoam_case.openfoam_triSurface_dir / 

98 str(stl_name + '.stl'), 

99 mode=stl.Mode.ASCII) 

100 for obj in mesh_objects: 

101 region_names.append(str(obj.name, encoding='utf-8')) 

102 for name in region_names: 

103 regions.update({name: {'name': name}}) 

104 openfoam_case.snappyHexMeshDict = snappyHexMeshDict.SnappyHexMeshDict() 

105 openfoam_case.snappyHexMeshDict.add_stl_geometry( 

106 str("space_" + openfoam_case.current_zone.guid), regions) 

107 

108 # self.snappyHexMesh.values['geometry']['regions'].update(regions) 

109 location_in_mesh = ( 

110 str('(' + 

111 str( 

112 openfoam_case.current_zone.space_center.Coord()[ 

113 0]) + ' ' + 

114 str( 

115 openfoam_case.current_zone.space_center.Coord()[ 

116 1]) + ' ' + 

117 str( 

118 openfoam_case.current_zone.space_center.Coord()[ 

119 2]) + ')' 

120 )) 

121 openfoam_case.snappyHexMeshDict.values['castellatedMeshControls'][ 

122 'locationInMesh'] = location_in_mesh 

123 self.set_refinementSurfaces(openfoam_case, openfoam_elements, 

124 region_names) 

125 openfoam_case.snappyHexMeshDict.values['castellatedMeshControls'][ 

126 'refinementSurfaces'].update(openfoam_case.refinementSurfaces) 

127 

128 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

129 

130 @staticmethod 

131 def set_refinementSurfaces(openfoam_case, openfoam_elements, 

132 region_names, 

133 default_refinement_level=[1, 2]): 

134 (stl_bounds, heaters, air_terminals, 

135 furniture, people) = of_utils.split_openfoam_elements( 

136 openfoam_elements) 

137 stl_name = "space_" + openfoam_case.current_zone.guid 

138 

139 refinementSurface_regions = {} 

140 

141 for obj in stl_bounds: 

142 refinementSurface_regions.update( 

143 {obj.solid_name: 

144 { 

145 'level': '({} {})'.format( 

146 int(obj.refinement_level[0]), 

147 int(obj.refinement_level[1])), 

148 'patchInfo': 

149 {'type': obj.patch_info_type}}}) 

150 

151 openfoam_case.refinementSurfaces = {stl_name: 

152 { 

153 'level': '({} {})'.format( 

154 int(default_refinement_level[0]), 

155 int(default_refinement_level[ 

156 1])), 

157 'regions': refinementSurface_regions 

158 }} 

159 

160 # todo: different approach for air terminals (partially patchInfo 

161 # wall, partially inlet / outlet. 

162 

163 def update_snappyHexMesh_heating(self, openfoam_case, openfoam_elements): 

164 heaters = filter_elements(openfoam_elements, 'Heater') 

165 for heater in heaters: 

166 openfoam_case.snappyHexMeshDict.values['geometry'].update( 

167 { 

168 heater.heater_surface.stl_name: 

169 { 

170 'type': 'triSurfaceMesh', 

171 'name': heater.heater_surface.solid_name, 

172 'regions': 

173 {heater.heater_surface.solid_name: 

174 { 

175 'name': heater.heater_surface.solid_name 

176 } 

177 } 

178 }, 

179 heater.porous_media.solid_name: 

180 { 

181 'type': 'searchableBox', 

182 'min': f"({heater.porous_media.bbox_min_max[0][0]} " 

183 f"{heater.porous_media.bbox_min_max[0][1]} " 

184 f"{heater.porous_media.bbox_min_max[0][2]})", 

185 'max': f"({heater.porous_media.bbox_min_max[1][0]} " 

186 f"{heater.porous_media.bbox_min_max[1][1]} " 

187 f"{heater.porous_media.bbox_min_max[1][2]})", 

188 }, 

189 } 

190 ) 

191 openfoam_case.snappyHexMeshDict.values['castellatedMeshControls'][ 

192 'refinementSurfaces'].update( 

193 { 

194 heater.heater_surface.solid_name: 

195 { 

196 'level': '(1 2)', 

197 'regions': 

198 { 

199 heater.heater_surface.solid_name: 

200 { 

201 'level': 

202 f"({heater.heater_surface.refinement_level[0]} " 

203 f"{heater.heater_surface.refinement_level[1]})", 

204 'patchInfo': 

205 { 

206 'type': 

207 heater.heater_surface.patch_info_type 

208 } 

209 } 

210 } 

211 } 

212 }, 

213 ) 

214 openfoam_case.snappyHexMeshDict.values['castellatedMeshControls'][ 

215 'refinementRegions'].update( 

216 { 

217 heater.porous_media.solid_name: 

218 { 

219 'mode': 'inside', 

220 'levels': 

221 f'((' 

222 f'0 ' 

223 f'{heater.porous_media.refinement_level[1]}))' 

224 }, 

225 heater.heater_surface.solid_name: 

226 {'mode': 'distance', 

227 'levels': f"((0.05 {heater.heater_surface.refinement_level[1]}) " 

228 f"(0.15 {heater.heater_surface.refinement_level[1] - 1}))" 

229 }, 

230 } 

231 ) 

232 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

233 

234 @staticmethod 

235 def add_topoSetDict_for_heating(openfoam_case, openfoam_elements): 

236 heaters = filter_elements(openfoam_elements, 'Heater') 

237 openfoam_case.topoSetDict = foamfile.FoamFile( 

238 name='topoSetDict', cls='dictionary', location='system', 

239 default_values=OrderedDict() 

240 ) 

241 openfoam_case.topoSetDict.values.update( 

242 {'actions (': '//'}) 

243 for h in heaters: 

244 openfoam_case.topoSetDict.values.update( 

245 {f'//{h.solid_name}': { 

246 'name': h.porous_media.solid_name, 

247 'action': 'new', 

248 'type': 'cellSet', 

249 'source': 'surfaceToCell', 

250 'sourceInfo': 

251 { 

252 'file': fr'"constant/triSurface/' 

253 fr'{h.porous_media.stl_name}"', 

254 'useSurfaceOrientation': 'true', 

255 'outsidePoints': '((0 0 0))', 

256 'includeCut': 'false', 

257 'includeInside': 'true', 

258 'includeOutside': 'false', 

259 'nearDistance': '-1', 

260 'curvature': '0', 

261 } 

262 }, 

263 } 

264 ) 

265 openfoam_case.topoSetDict.values.update({');': '//'}) # required to 

266 # close 

267 # the 

268 # round bracket. Replace by better option if you find any. 

269 

270 openfoam_case.topoSetDict.save(openfoam_case.openfoam_dir) 

271 

272 @staticmethod 

273 def modify_topoSet_for_evaluation(openfoam_case, openfoam_elements): 

274 furniture = filter_elements(openfoam_elements, 'Furniture') 

275 people = filter_elements(openfoam_elements, 'People') 

276 heaters = filter_elements(openfoam_elements, 'Heater') 

277 airterminals = filter_elements(openfoam_elements, 'AirTerminal') 

278 cut_shapes = [] 

279 for furn in furniture: 

280 cut_shapes.append( 

281 PyOCCTools.unify_shape(PyOCCTools.make_solid_from_shape( 

282 PyOCCTools, PyOCCTools.simple_bounding_box_shape([ 

283 furn.tri_geom])))) 

284 for heater in heaters: 

285 cut_shapes.append( 

286 PyOCCTools.unify_shape(PyOCCTools.make_solid_from_shape( 

287 PyOCCTools, 

288 PyOCCTools.scale_shape(heater.porous_media.tri_geom, 1.1)))) 

289 for person in people: 

290 cut_shapes.append( 

291 PyOCCTools.unify_shape(PyOCCTools.make_solid_from_shape( 

292 PyOCCTools, PyOCCTools.simple_bounding_box_shape( 

293 [person.scaled_surface])))) 

294 for air in airterminals: 

295 cut_shapes.append( 

296 PyOCCTools.unify_shape(PyOCCTools.make_solid_from_shape( 

297 PyOCCTools, PyOCCTools.scale_shape(air.bbox_min_max_shape, 

298 1.1)))) 

299 space_solid_shrinked = (PyOCCTools.make_solid_from_shape( 

300 PyOCCTools, PyOCCTools.scale_shape( 

301 openfoam_case.current_zone.space_shape, 0.9))) 

302 shape = space_solid_shrinked 

303 for cut_shape in cut_shapes: 

304 ins = TopOpeBRep_ShapeIntersector() 

305 ins.InitIntersection(cut_shape, shape) 

306 if ins.MoreIntersection(): 

307 shape = BRepAlgoAPI_Cut(shape, cut_shape).Shape() 

308 shape = PyOCCTools.make_solid_from_shape(PyOCCTools, shape) 

309 tri_eval_shape = PyOCCTools.triangulate_bound_shape(shape) 

310 stl_writer = StlAPI_Writer() 

311 stl_writer.SetASCIIMode(True) 

312 stl_writer.Write(tri_eval_shape, 

313 str(openfoam_case.openfoam_triSurface_dir / 

314 'evaluate_air_volume.stl')) 

315 openfoam_case.topoSetDict.values.pop(');') # required to 

316 

317 for person in people: 

318 tri_eval_shape = PyOCCTools.triangulate_bound_shape( 

319 person.scaled_surface) 

320 stl_writer = StlAPI_Writer() 

321 stl_writer.SetASCIIMode(True) 

322 stl_writer.Write(tri_eval_shape, 

323 str(openfoam_case.openfoam_triSurface_dir / 

324 f"evaluate_{person.solid_name}.stl")) 

325 openfoam_case.topoSetDict.values.update( 

326 {f'//evaluate_{person.solid_name}': { 

327 'name': f"evaluate_{person.solid_name}", 

328 'action': 'new', 

329 'type': 'cellSet', 

330 'source': 'surfaceToCell', 

331 'sourceInfo': 

332 { 

333 'file': fr'"constant/triSurface/' 

334 fr'evaluate_{person.solid_name}.stl"', 

335 'useSurfaceOrientation': 'false', 

336 'outsidePoints': 

337 f'((' 

338 f'{openfoam_case.current_zone.space_center.X()} ' 

339 f'{openfoam_case.current_zone.space_center.Y()} ' 

340 f'{openfoam_case.current_zone.space_center.Z()}' 

341 f' ))', 

342 'includeCut': 'true', 

343 'includeInside': 'false', 

344 'includeOutside': 'false', 

345 'nearDistance': '-1', 

346 'curvature': '0', 

347 } 

348 }, 

349 } 

350 ) 

351 openfoam_case.topoSetDict.values.update( 

352 {f'//evaluate air volume': { 

353 'name': 'evaluate_air_volume', 

354 'action': 'new', 

355 'type': 'cellSet', 

356 'source': 'surfaceToCell', 

357 'sourceInfo': 

358 { 

359 'file': fr'"constant/triSurface/' 

360 fr'evaluate_air_volume.stl"', 

361 'useSurfaceOrientation': 'true', 

362 'outsidePoints': '((0 0 0))', 

363 'includeCut': 'false', 

364 'includeInside': 'true', 

365 'includeOutside': 'false', 

366 'nearDistance': '-1', 

367 'curvature': '0', 

368 } 

369 }, 

370 } 

371 ) 

372 openfoam_case.topoSetDict.values.update({');': '//'}) # required to 

373 # close 

374 # the 

375 # round bracket. Replace by better option if you find any. 

376 

377 openfoam_case.topoSetDict.save(openfoam_case.openfoam_dir) 

378 

379 # update controlDict for evaluation 

380 for person in people: 

381 for operation in ['average', 'min', 'max']: 

382 evaluate_dict = { 

383 f"{person.solid_name}_{operation}": { 

384 'type': 'volFieldValue', 

385 'libs': '(fieldFunctionObjects)', 

386 'log': 'true', 

387 'writeFields': 'false', 

388 'enabled': 'true', 

389 'writeControl': 'timeStep', 

390 'writeInterval': '1', 

391 'regionType': 'cellZone', 

392 'name': f"evaluate_{person.solid_name}", 

393 'operation': operation, 

394 'fields': '( T U PMV PPD )' 

395 }} 

396 openfoam_case.controlDict.values['functions'].update( 

397 evaluate_dict) 

398 for operation in ['average', 'min', 'max']: 

399 evaluate_dict = { 

400 f"evaluate_air_volume_{operation}": { 

401 'type': 'volFieldValue', 

402 'libs': '(fieldFunctionObjects)', 

403 'log': 'true', 

404 'writeFields': 'false', 

405 'enabled': 'true', 

406 'writeControl': 'timeStep', 

407 'writeInterval': '1', 

408 'regionType': 'cellZone', 

409 'name': f"evaluate_air_volume", 

410 'operation': operation, 

411 'fields': '( T U PMV PPD )' 

412 }} 

413 openfoam_case.controlDict.values['functions'].update( 

414 evaluate_dict) 

415 

416 openfoam_case.controlDict.save(openfoam_case.openfoam_dir) 

417 

418 def update_blockMeshDict_air(self, openfoam_case, openfoam_elements): 

419 air_terminals = filter_elements(openfoam_elements, 'AirTerminal') 

420 new_min_max = PyOCCTools.simple_bounding_box([ 

421 openfoam_case.current_zone.space_shape, 

422 *[inlet_outlet.bbox_min_max_shape 

423 for inlet_outlet in 

424 air_terminals]]) 

425 new_blockmesh_box = BRepPrimAPI_MakeBox( 

426 gp_Pnt(*new_min_max[0]), 

427 gp_Pnt(*new_min_max[1])).Shape() 

428 

429 self.create_blockMesh(openfoam_case, shape=new_blockmesh_box) 

430 

431 def update_snappyHexMesh_air(self, openfoam_case, openfoam_elements): 

432 air_terminals = filter_elements(openfoam_elements, 'AirTerminal') 

433 for air_terminal in air_terminals: 

434 for name in [air_terminal.diffuser.solid_name, 

435 air_terminal.source_sink.solid_name, 

436 air_terminal.box.solid_name]: 

437 if not name: 

438 continue 

439 openfoam_case.snappyHexMeshDict.values['geometry'].update( 

440 { 

441 name + '.stl': 

442 { 

443 'type': 'triSurfaceMesh', 

444 'name': name, 

445 'regions': 

446 {name: 

447 { 

448 'name': name 

449 } 

450 } 

451 } 

452 } 

453 ) 

454 openfoam_case.snappyHexMeshDict.values['geometry'].update({ 

455 air_terminal.air_type + '_refinement_small': 

456 { 

457 'type': 'searchableBox', 

458 'min': f"({air_terminal.refinement_zone_small[0][0]} " 

459 f"{air_terminal.refinement_zone_small[0][1]} " 

460 f"{air_terminal.refinement_zone_small[0][2]})", 

461 'max': f"({air_terminal.refinement_zone_small[1][0]} " 

462 f"{air_terminal.refinement_zone_small[1][1]} " 

463 f"{air_terminal.refinement_zone_small[1][2]})", 

464 }, 

465 air_terminal.air_type + '_refinement_large': 

466 { 

467 'type': 'searchableBox', 

468 'min': f"({air_terminal.refinement_zone_large[0][0]} " 

469 f"{air_terminal.refinement_zone_large[0][1]} " 

470 f"{air_terminal.refinement_zone_large[0][2]})", 

471 'max': f"({air_terminal.refinement_zone_large[1][0]} " 

472 f"{air_terminal.refinement_zone_large[1][1]} " 

473 f"{air_terminal.refinement_zone_large[1][2]})", 

474 } 

475 } 

476 ) 

477 if air_terminal.diffuser.solid_name: 

478 openfoam_case.snappyHexMeshDict.values[ 

479 'castellatedMeshControls'][ 

480 'refinementSurfaces'].update( 

481 {air_terminal.diffuser.solid_name: 

482 {'level': 

483 f"({air_terminal.diffuser.refinement_level[0]}" 

484 f" {air_terminal.diffuser.refinement_level[1]})", 

485 'regions': 

486 {air_terminal.diffuser.solid_name: 

487 {'level': 

488 f"({air_terminal.diffuser.refinement_level[0]}" 

489 f" {air_terminal.diffuser.refinement_level[1]})", 

490 'patchInfo': { 

491 'type': 

492 air_terminal.diffuser.patch_info_type}}}} 

493 }, 

494 ) 

495 openfoam_case.snappyHexMeshDict.values['castellatedMeshControls'][ 

496 'refinementSurfaces'].update( 

497 {air_terminal.source_sink.solid_name: 

498 {'level': '(1 2)', 'regions': 

499 {air_terminal.source_sink.solid_name: { 

500 'level': f"({air_terminal.source_sink.refinement_level[0]}" 

501 f" {air_terminal.source_sink.refinement_level[1]})", 

502 'patchInfo': { 

503 'type': air_terminal.air_type}}}} 

504 }, 

505 ) 

506 openfoam_case.snappyHexMeshDict.values['castellatedMeshControls'][ 

507 'refinementSurfaces'].update( 

508 {air_terminal.box.solid_name: 

509 {'level': '(1 2)', 

510 'regions': { 

511 air_terminal.box.solid_name: { 

512 'level': f"({air_terminal.box.refinement_level[0]}" 

513 f" {air_terminal.box.refinement_level[1]})", 

514 'patchInfo': { 

515 'type': 

516 air_terminal.box.patch_info_type}}}} 

517 }, 

518 ) 

519 openfoam_case.snappyHexMeshDict.values['castellatedMeshControls'][ 

520 'refinementRegions'].update( 

521 {air_terminal.source_sink.solid_name: 

522 {'mode': 'distance', 

523 'levels': f"((0.03 " 

524 f"{air_terminal.source_sink.refinement_level[1]}) " 

525 f"(0.08 " 

526 f"{air_terminal.source_sink.refinement_level[1] - 1}))"}, 

527 air_terminal.diffuser.solid_name: 

528 {'mode': 'distance', 

529 'levels': f"((0.03 " 

530 f"{air_terminal.diffuser.refinement_level[1]}) " 

531 f"(0.08 " 

532 f"{air_terminal.diffuser.refinement_level[1] - 1}))"}, 

533 } 

534 ) 

535 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

536 

537 def update_snappyHexMesh_furniture(self, openfoam_case, openfoam_elements): 

538 furnitures = filter_elements(openfoam_elements, 'Furniture') 

539 for furniture in furnitures: 

540 openfoam_case.snappyHexMeshDict.values['geometry'].update( 

541 { 

542 furniture.stl_name: 

543 { 

544 'type': 'triSurfaceMesh', 

545 'name': furniture.solid_name, 

546 'regions': 

547 {furniture.solid_name: 

548 { 

549 'name': furniture.solid_name 

550 } 

551 } 

552 }, 

553 # furniture.solid_name + '_refinement_small': 

554 # { 

555 # 'type': 'searchableBox', 

556 # 'min': f"({furniture.refinement_zone_small[0][0]} " 

557 # f"{furniture.refinement_zone_small[0][1]} " 

558 # f"{furniture.refinement_zone_small[0][2]})", 

559 # 'max': f"({furniture.refinement_zone_small[1][0]} " 

560 # f"{furniture.refinement_zone_small[1][1]} " 

561 # f"{furniture.refinement_zone_small[1][2]})", 

562 # }, 

563 # furniture.solid_name + '_refinement_large': 

564 # { 

565 # 'type': 'searchableBox', 

566 # 'min': f"({furniture.refinement_zone_large[0][0]} " 

567 # f"{furniture.refinement_zone_large[0][1]} " 

568 # f"{furniture.refinement_zone_large[0][2]})", 

569 # 'max': f"({furniture.refinement_zone_large[1][0]} " 

570 # f"{furniture.refinement_zone_large[1][1]} " 

571 # f"{furniture.refinement_zone_large[1][2]})", 

572 # } 

573 } 

574 ) 

575 openfoam_case.snappyHexMeshDict.values['castellatedMeshControls'][ 

576 'refinementSurfaces'].update( 

577 { 

578 furniture.solid_name: 

579 { 

580 'level': '(1 2)', 

581 'regions': 

582 { 

583 furniture.solid_name: 

584 { 

585 'level': 

586 f"({furniture.refinement_level[0]} " 

587 f"{furniture.refinement_level[1]})", 

588 'patchInfo': 

589 { 

590 'type': 

591 furniture.patch_info_type 

592 } 

593 } 

594 } 

595 } 

596 }, 

597 ) 

598 openfoam_case.snappyHexMeshDict.values['castellatedMeshControls'][ 

599 'refinementRegions'].update( 

600 { 

601 furniture.solid_name: 

602 {'mode': 'distance', 

603 'levels': f"((0.03 {furniture.refinement_level[1]})" 

604 f"(0.06 {furniture.refinement_level[1] - 1}))" 

605 } 

606 }, 

607 ) 

608 # openfoam_case.snappyHexMeshDict.values['castellatedMeshControls'][ 

609 # 'refinementRegions'].update( 

610 # { 

611 # furniture.solid_name + '_refinement_small': 

612 # { 

613 # 'mode': 'inside', 

614 # 'levels': 

615 # f'(({furniture.refinement_zone_level_small[0]} ' 

616 # f'{furniture.refinement_zone_level_small[1]}))', 

617 # 'regions': 

618 # {furniture.stl_name: 

619 # {'mode': 'outside'}}, 

620 # } 

621 # } 

622 # ) 

623 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

624 

625 def update_snappyHexMesh_people(self, openfoam_case, openfoam_elements): 

626 people = filter_elements(openfoam_elements, 'People') 

627 for person in people: 

628 for body_part in person.body_parts_dict.values(): 

629 openfoam_case.snappyHexMeshDict.values['geometry'].update( 

630 { 

631 body_part.stl_name: 

632 { 

633 'type': 'triSurfaceMesh', 

634 'name': body_part.solid_name, 

635 'regions': 

636 {body_part.solid_name: 

637 { 

638 'name': body_part.solid_name 

639 } 

640 } 

641 }, 

642 }) 

643 

644 openfoam_case.snappyHexMeshDict.values[ 

645 'castellatedMeshControls'][ 

646 'refinementSurfaces'].update( 

647 { 

648 body_part.solid_name: 

649 { 

650 'level': '(1 2)', 

651 'regions': 

652 { 

653 body_part.solid_name: 

654 { 

655 'level': 

656 f"(" 

657 f"{person.refinement_level[0]} " 

658 f"{person.refinement_level[1]})", 

659 'patchInfo': 

660 { 

661 'type': 

662 body_part.patch_info_type 

663 } 

664 } 

665 } 

666 } 

667 }, 

668 ) 

669 openfoam_case.snappyHexMeshDict.values[ 

670 'castellatedMeshControls'][ 

671 'refinementRegions'].update( 

672 { 

673 body_part.solid_name: 

674 {'mode': 'distance', 

675 'levels': f"((0.05 {person.refinement_level[1]})" 

676 f"(0.1 {person.refinement_level[1] - 1}))" 

677 }, 

678 } 

679 ) 

680 

681 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

682 

683 def update_snappyHexMesh_mesh_controls(self, openfoam_case): 

684 openfoam_case.snappyHexMeshDict.values[ 

685 'castellatedMeshControls'].update({'maxLocalCells': 1000000}) 

686 openfoam_case.snappyHexMeshDict.values[ 

687 'castellatedMeshControls'].update({ 

688 'maxGlobalCells': 

689 self.playground.sim_settings.mesh_max_global_cells}) 

690 openfoam_case.snappyHexMeshDict.values[ 

691 'meshQualityControls'].update({'maxBoundarySkewness': 20}) 

692 openfoam_case.snappyHexMeshDict.values[ 

693 'meshQualityControls'].update({'maxInternalSkewness': 3}) 

694 openfoam_case.snappyHexMeshDict.values[ 

695 'castellatedMeshControls'].update({'resolveFeatureAngle': 60}) 

696 openfoam_case.snappyHexMeshDict.values[ 

697 'castellatedMeshControls'].update({'minRefinementCells': 5}) 

698 openfoam_case.snappyHexMeshDict.values[ 

699 'castellatedMeshControls'].update({'gapMode': 'mixed'}) 

700 openfoam_case.snappyHexMeshDict.values[ 

701 'castellatedMeshControls'].update({'gapLevel': '(3 0 7)'}) 

702 openfoam_case.snappyHexMeshDict.values[ 

703 'snapControls'].update({'nSolveIter': 50}) 

704 openfoam_case.snappyHexMeshDict.values[ 

705 'snapControls'].update({'nRelaxIter': 15}) 

706 openfoam_case.snappyHexMeshDict.values[ 

707 'snapControls'].update({'tolerance': 5.0}) 

708 openfoam_case.snappyHexMeshDict.values[ 

709 'snapControls'].update({'multiRegionFeatureSnap': 'false'}) 

710 openfoam_case.snappyHexMeshDict.values[ 

711 'snapControls'].update({'implicitFeatureSnap': 'true'}) 

712 openfoam_case.snappyHexMeshDict.values[ 

713 'snapControls'].update({'explicitFeatureSnap': 'false'}) 

714 if self.playground.sim_settings.mesh_feature_snapping: 

715 openfoam_case.snappyHexMeshDict.values[ 

716 'snapControls'].update({'explicitFeatureSnap': 'true'}) 

717 openfoam_case.snappyHexMeshDict.values[ 

718 'snapControls'].update({'implicitFeatureSnap': 'false'}) 

719 openfoam_case.snappyHexMeshDict.values[ 

720 'snapControls'].update( 

721 {'extractFeaturesRefineLevel': 'true'}) 

722 

723 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir)