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

201 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-10-01 10:24 +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 openfoam_case.blockMeshDict = blockMeshDict.BlockMeshDict.from_min_max( 

69 scaled_min_pt, scaled_max_pt, n_div_xyz=n_div_xyz) 

70 openfoam_case.blockMeshDict.save(openfoam_case.openfoam_dir) 

71 

72 @staticmethod 

73 def create_surfaceFeatureExtract(openfoam_case): 

74 """Initialize surfaceFeatureExtractDict""" 

75 level = 0 

76 features_string = "(" 

77 openfoam_case.surfaceFeatureExtract = ( 

78 surfaceFeatureExtractDict.SurfaceFeatureExtractDict()) 

79 for stl_file in openfoam_case.snappyHexMeshDict.stl_file_names: 

80 openfoam_case.surfaceFeatureExtract.update_values( 

81 surfaceFeatureExtractDict.SurfaceFeatureExtractDict.from_stl_file( 

82 stl_file + '.stl').values) 

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

84 f'level {level};}}') 

85 features_string += ")" 

86 openfoam_case.snappyHexMeshDict.features = features_string 

87 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

88 openfoam_case.surfaceFeatureExtract.save(openfoam_case.openfoam_dir) 

89 

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

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

92 region_names = [] 

93 regions = {} 

94 mesh_objects = mesh.Mesh.from_multi_file( 

95 openfoam_case.openfoam_triSurface_dir / 

96 str(stl_name + '.stl'), 

97 mode=stl.Mode.ASCII) 

98 for obj in mesh_objects: 

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

100 for name in region_names: 

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

102 openfoam_case.snappyHexMeshDict = snappyHexMeshDict.SnappyHexMeshDict() 

103 openfoam_case.snappyHexMeshDict.add_stl_geometry( 

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

105 

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

107 location_in_mesh = ( 

108 str('(' + 

109 str( 

110 openfoam_case.current_zone.space_center.Coord()[ 

111 0]) + ' ' + 

112 str( 

113 openfoam_case.current_zone.space_center.Coord()[ 

114 1]) + ' ' + 

115 str( 

116 openfoam_case.current_zone.space_center.Coord()[ 

117 2]) + ')' 

118 )) 

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

120 'locationInMesh'] = location_in_mesh 

121 self.set_refinementSurfaces(openfoam_case, openfoam_elements, 

122 region_names) 

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

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

125 

126 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

127 

128 @staticmethod 

129 def set_refinementSurfaces(openfoam_case, openfoam_elements, 

130 region_names, 

131 default_refinement_level=[1, 2]): 

132 (stl_bounds, heaters, air_terminals, 

133 furniture, people) = of_utils.split_openfoam_elements( 

134 openfoam_elements) 

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

136 

137 refinementSurface_regions = {} 

138 

139 for obj in stl_bounds: 

140 refinementSurface_regions.update( 

141 {obj.solid_name: 

142 { 

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

144 int(obj.refinement_level[0]), 

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

146 'patchInfo': 

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

148 

149 openfoam_case.refinementSurfaces = {stl_name: 

150 { 

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

152 int(default_refinement_level[0]), 

153 int(default_refinement_level[ 

154 1])), 

155 'regions': refinementSurface_regions 

156 }} 

157 

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

159 # wall, partially inlet / outlet. 

160 

161 def update_snappyHexMesh_heating(self, openfoam_case, openfoam_elements): 

162 heaters = filter_elements(openfoam_elements, 'Heater') 

163 for heater in heaters: 

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

165 { 

166 heater.heater_surface.stl_name: 

167 { 

168 'type': 'triSurfaceMesh', 

169 'name': heater.heater_surface.solid_name, 

170 'regions': 

171 {heater.heater_surface.solid_name: 

172 { 

173 'name': heater.heater_surface.solid_name 

174 } 

175 } 

176 }, 

177 heater.porous_media.solid_name: 

178 { 

179 'type': 'searchableBox', 

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

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

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

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

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

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

186 }, 

187 } 

188 ) 

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

190 'refinementSurfaces'].update( 

191 { 

192 heater.heater_surface.solid_name: 

193 { 

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

195 'regions': 

196 { 

197 heater.heater_surface.solid_name: 

198 { 

199 'level': 

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

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

202 'patchInfo': 

203 { 

204 'type': 

205 heater.heater_surface.patch_info_type 

206 } 

207 } 

208 } 

209 } 

210 }, 

211 ) 

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

213 'refinementRegions'].update( 

214 { 

215 heater.porous_media.solid_name: 

216 { 

217 'mode': 'inside', 

218 'levels': 

219 f'((' 

220 f'0 ' 

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

222 }, 

223 heater.heater_surface.solid_name: 

224 {'mode': 'distance', 

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

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

227 }, 

228 } 

229 ) 

230 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

231 

232 @staticmethod 

233 def add_topoSetDict_for_heating(openfoam_case, openfoam_elements): 

234 heaters = filter_elements(openfoam_elements, 'Heater') 

235 openfoam_case.topoSetDict = foamfile.FoamFile( 

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

237 default_values=OrderedDict() 

238 ) 

239 openfoam_case.topoSetDict.values.update( 

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

241 for h in heaters: 

242 openfoam_case.topoSetDict.values.update( 

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

244 'name': h.porous_media.solid_name, 

245 'action': 'new', 

246 'type': 'cellSet', 

247 'source': 'surfaceToCell', 

248 'sourceInfo': 

249 { 

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

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

252 'useSurfaceOrientation': 'true', 

253 'outsidePoints': '((0 0 0))', 

254 'includeCut': 'false', 

255 'includeInside': 'true', 

256 'includeOutside': 'false', 

257 'nearDistance': '-1', 

258 'curvature': '0', 

259 } 

260 }, 

261 } 

262 ) 

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

264 # close 

265 # the 

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

267 

268 openfoam_case.topoSetDict.save(openfoam_case.openfoam_dir) 

269 

270 @staticmethod 

271 def modify_topoSet_for_evaluation(openfoam_case, openfoam_elements): 

272 furniture = filter_elements(openfoam_elements, 'Furniture') 

273 people = filter_elements(openfoam_elements, 'People') 

274 heaters = filter_elements(openfoam_elements, 'Heater') 

275 airterminals = filter_elements(openfoam_elements, 'AirTerminal') 

276 cut_shapes = [] 

277 for furn in furniture: 

278 cut_shapes.append( 

279 PyOCCTools.unify_shape(PyOCCTools.make_solid_from_shape( 

280 PyOCCTools, PyOCCTools.simple_bounding_box_shape([ 

281 furn.tri_geom])))) 

282 for heater in heaters: 

283 cut_shapes.append( 

284 PyOCCTools.unify_shape(PyOCCTools.make_solid_from_shape( 

285 PyOCCTools, 

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

287 for person in people: 

288 cut_shapes.append( 

289 PyOCCTools.unify_shape(PyOCCTools.make_solid_from_shape( 

290 PyOCCTools, PyOCCTools.simple_bounding_box_shape( 

291 [person.scaled_surface])))) 

292 for air in airterminals: 

293 cut_shapes.append( 

294 PyOCCTools.unify_shape(PyOCCTools.make_solid_from_shape( 

295 PyOCCTools, PyOCCTools.scale_shape(air.bbox_min_max_shape, 

296 1.1)))) 

297 space_solid_shrinked = (PyOCCTools.make_solid_from_shape( 

298 PyOCCTools, PyOCCTools.scale_shape( 

299 openfoam_case.current_zone.space_shape, 0.9))) 

300 shape = space_solid_shrinked 

301 for cut_shape in cut_shapes: 

302 ins = TopOpeBRep_ShapeIntersector() 

303 ins.InitIntersection(cut_shape, shape) 

304 if ins.MoreIntersection(): 

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

306 shape = PyOCCTools.make_solid_from_shape(PyOCCTools, shape) 

307 tri_eval_shape = PyOCCTools.triangulate_bound_shape(shape) 

308 stl_writer = StlAPI_Writer() 

309 stl_writer.SetASCIIMode(True) 

310 stl_writer.Write(tri_eval_shape, 

311 str(openfoam_case.openfoam_triSurface_dir / 

312 'evaluate_air_volume.stl')) 

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

314 

315 for person in people: 

316 tri_eval_shape = PyOCCTools.triangulate_bound_shape( 

317 person.scaled_surface) 

318 stl_writer = StlAPI_Writer() 

319 stl_writer.SetASCIIMode(True) 

320 stl_writer.Write(tri_eval_shape, 

321 str(openfoam_case.openfoam_triSurface_dir / 

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

323 openfoam_case.topoSetDict.values.update( 

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

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

326 'action': 'new', 

327 'type': 'cellSet', 

328 'source': 'surfaceToCell', 

329 'sourceInfo': 

330 { 

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

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

333 'useSurfaceOrientation': 'false', 

334 'outsidePoints': 

335 f'((' 

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

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

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

339 f' ))', 

340 'includeCut': 'true', 

341 'includeInside': 'false', 

342 'includeOutside': 'false', 

343 'nearDistance': '-1', 

344 'curvature': '0', 

345 } 

346 }, 

347 } 

348 ) 

349 openfoam_case.topoSetDict.values.update( 

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

351 'name': 'evaluate_air_volume', 

352 'action': 'new', 

353 'type': 'cellSet', 

354 'source': 'surfaceToCell', 

355 'sourceInfo': 

356 { 

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

358 fr'evaluate_air_volume.stl"', 

359 'useSurfaceOrientation': 'true', 

360 'outsidePoints': '((0 0 0))', 

361 'includeCut': 'false', 

362 'includeInside': 'true', 

363 'includeOutside': 'false', 

364 'nearDistance': '-1', 

365 'curvature': '0', 

366 } 

367 }, 

368 } 

369 ) 

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

371 # close 

372 # the 

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

374 

375 openfoam_case.topoSetDict.save(openfoam_case.openfoam_dir) 

376 

377 # update controlDict for evaluation 

378 for person in people: 

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

380 evaluate_dict = { 

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

382 'type': 'volFieldValue', 

383 'libs': '(fieldFunctionObjects)', 

384 'log': 'true', 

385 'writeFields': 'false', 

386 'enabled': 'true', 

387 'writeControl': 'timeStep', 

388 'writeInterval': '1', 

389 'regionType': 'cellZone', 

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

391 'operation': operation, 

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

393 }} 

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

395 evaluate_dict) 

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

397 evaluate_dict = { 

398 f"evaluate_air_volume_{operation}": { 

399 'type': 'volFieldValue', 

400 'libs': '(fieldFunctionObjects)', 

401 'log': 'true', 

402 'writeFields': 'false', 

403 'enabled': 'true', 

404 'writeControl': 'timeStep', 

405 'writeInterval': '1', 

406 'regionType': 'cellZone', 

407 'name': f"evaluate_air_volume", 

408 'operation': operation, 

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

410 }} 

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

412 evaluate_dict) 

413 

414 openfoam_case.controlDict.save(openfoam_case.openfoam_dir) 

415 

416 def update_blockMeshDict_air(self, openfoam_case, openfoam_elements): 

417 air_terminals = filter_elements(openfoam_elements, 'AirTerminal') 

418 new_min_max = PyOCCTools.simple_bounding_box([ 

419 openfoam_case.current_zone.space_shape, 

420 *[inlet_outlet.bbox_min_max_shape 

421 for inlet_outlet in 

422 air_terminals]]) 

423 new_blockmesh_box = BRepPrimAPI_MakeBox( 

424 gp_Pnt(*new_min_max[0]), 

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

426 

427 self.create_blockMesh(openfoam_case, shape=new_blockmesh_box) 

428 

429 def update_snappyHexMesh_air(self, openfoam_case, openfoam_elements): 

430 air_terminals = filter_elements(openfoam_elements, 'AirTerminal') 

431 for air_terminal in air_terminals: 

432 for name in [air_terminal.diffuser.solid_name, 

433 air_terminal.source_sink.solid_name, 

434 air_terminal.box.solid_name]: 

435 if not name: 

436 continue 

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

438 { 

439 name + '.stl': 

440 { 

441 'type': 'triSurfaceMesh', 

442 'name': name, 

443 'regions': 

444 {name: 

445 { 

446 'name': name 

447 } 

448 } 

449 } 

450 } 

451 ) 

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

453 air_terminal.air_type + '_refinement_small': 

454 { 

455 'type': 'searchableBox', 

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

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

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

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

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

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

462 }, 

463 air_terminal.air_type + '_refinement_large': 

464 { 

465 'type': 'searchableBox', 

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

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

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

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

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

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

472 } 

473 } 

474 ) 

475 if air_terminal.diffuser.solid_name: 

476 openfoam_case.snappyHexMeshDict.values[ 

477 'castellatedMeshControls'][ 

478 'refinementSurfaces'].update( 

479 {air_terminal.diffuser.solid_name: 

480 {'level': 

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

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

483 'regions': 

484 {air_terminal.diffuser.solid_name: 

485 {'level': 

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

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

488 'patchInfo': { 

489 'type': 

490 air_terminal.diffuser.patch_info_type}}}} 

491 }, 

492 ) 

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

494 'refinementSurfaces'].update( 

495 {air_terminal.source_sink.solid_name: 

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

497 {air_terminal.source_sink.solid_name: { 

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

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

500 'patchInfo': { 

501 'type': air_terminal.air_type}}}} 

502 }, 

503 ) 

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

505 'refinementSurfaces'].update( 

506 {air_terminal.box.solid_name: 

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

508 'regions': { 

509 air_terminal.box.solid_name: { 

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

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

512 'patchInfo': { 

513 'type': 

514 air_terminal.box.patch_info_type}}}} 

515 }, 

516 ) 

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

518 'refinementRegions'].update( 

519 {air_terminal.source_sink.solid_name: 

520 {'mode': 'distance', 

521 'levels': f"((0.03 " 

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

523 f"(0.08 " 

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

525 air_terminal.diffuser.solid_name: 

526 {'mode': 'distance', 

527 'levels': f"((0.03 " 

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

529 f"(0.08 " 

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

531 } 

532 ) 

533 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

534 

535 def update_snappyHexMesh_furniture(self, openfoam_case, openfoam_elements): 

536 furnitures = filter_elements(openfoam_elements, 'Furniture') 

537 for furniture in furnitures: 

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

539 { 

540 furniture.stl_name: 

541 { 

542 'type': 'triSurfaceMesh', 

543 'name': furniture.solid_name, 

544 'regions': 

545 {furniture.solid_name: 

546 { 

547 'name': furniture.solid_name 

548 } 

549 } 

550 }, 

551 # furniture.solid_name + '_refinement_small': 

552 # { 

553 # 'type': 'searchableBox', 

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

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

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

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

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

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

560 # }, 

561 # furniture.solid_name + '_refinement_large': 

562 # { 

563 # 'type': 'searchableBox', 

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

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

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

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

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

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

570 # } 

571 } 

572 ) 

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

574 'refinementSurfaces'].update( 

575 { 

576 furniture.solid_name: 

577 { 

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

579 'regions': 

580 { 

581 furniture.solid_name: 

582 { 

583 'level': 

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

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

586 'patchInfo': 

587 { 

588 'type': 

589 furniture.patch_info_type 

590 } 

591 } 

592 } 

593 } 

594 }, 

595 ) 

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

597 'refinementRegions'].update( 

598 { 

599 furniture.solid_name: 

600 {'mode': 'distance', 

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

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

603 } 

604 }, 

605 ) 

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

607 # 'refinementRegions'].update( 

608 # { 

609 # furniture.solid_name + '_refinement_small': 

610 # { 

611 # 'mode': 'inside', 

612 # 'levels': 

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

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

615 # 'regions': 

616 # {furniture.stl_name: 

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

618 # } 

619 # } 

620 # ) 

621 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

622 

623 def update_snappyHexMesh_people(self, openfoam_case, openfoam_elements): 

624 people = filter_elements(openfoam_elements, 'People') 

625 for person in people: 

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

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

628 { 

629 body_part.stl_name: 

630 { 

631 'type': 'triSurfaceMesh', 

632 'name': body_part.solid_name, 

633 'regions': 

634 {body_part.solid_name: 

635 { 

636 'name': body_part.solid_name 

637 } 

638 } 

639 }, 

640 }) 

641 

642 openfoam_case.snappyHexMeshDict.values[ 

643 'castellatedMeshControls'][ 

644 'refinementSurfaces'].update( 

645 { 

646 body_part.solid_name: 

647 { 

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

649 'regions': 

650 { 

651 body_part.solid_name: 

652 { 

653 'level': 

654 f"(" 

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

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

657 'patchInfo': 

658 { 

659 'type': 

660 body_part.patch_info_type 

661 } 

662 } 

663 } 

664 } 

665 }, 

666 ) 

667 openfoam_case.snappyHexMeshDict.values[ 

668 'castellatedMeshControls'][ 

669 'refinementRegions'].update( 

670 { 

671 body_part.solid_name: 

672 {'mode': 'distance', 

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

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

675 }, 

676 } 

677 ) 

678 

679 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir) 

680 

681 def update_snappyHexMesh_mesh_controls(self, openfoam_case): 

682 openfoam_case.snappyHexMeshDict.values[ 

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

684 openfoam_case.snappyHexMeshDict.values[ 

685 'castellatedMeshControls'].update({ 

686 'maxGlobalCells': 

687 self.playground.sim_settings.mesh_max_global_cells}) 

688 openfoam_case.snappyHexMeshDict.values[ 

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

690 openfoam_case.snappyHexMeshDict.values[ 

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

692 openfoam_case.snappyHexMeshDict.values[ 

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

694 openfoam_case.snappyHexMeshDict.values[ 

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

696 openfoam_case.snappyHexMeshDict.values[ 

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

698 openfoam_case.snappyHexMeshDict.values[ 

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

700 openfoam_case.snappyHexMeshDict.values[ 

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

702 openfoam_case.snappyHexMeshDict.values[ 

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

704 openfoam_case.snappyHexMeshDict.values[ 

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

706 openfoam_case.snappyHexMeshDict.values[ 

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

708 openfoam_case.snappyHexMeshDict.values[ 

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

710 openfoam_case.snappyHexMeshDict.values[ 

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

712 if self.playground.sim_settings.mesh_feature_snapping: 

713 openfoam_case.snappyHexMeshDict.values[ 

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

715 openfoam_case.snappyHexMeshDict.values[ 

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

717 openfoam_case.snappyHexMeshDict.values[ 

718 'snapControls'].update( 

719 {'extractFeaturesRefineLevel': 'true'}) 

720 

721 openfoam_case.snappyHexMeshDict.save(openfoam_case.openfoam_dir)