Repository navigation
fix: obstruction masks and cell-centred slice planes - #145
Merged
Merged
Conversation
Verified on an FDS 6.11.1 case: FDS writes a placeholder (the ambient temperature) into the cells inside an obstruction and into the nodes inside it, while the nodes on its faces get values of the gas next to it, unless there is no gas beyond the face (the obstruction continues into the neighbouring mesh, or the face lies on the outside of the domain). - Masks now block exactly those cells and nodes. Cell-centred masks blocked one cell too many on every axis; node masks blocked the lower face nodes, which hold gas values, and missed the inner node at the upper face. Meshes know which of their faces lie on the outside of the domain (Mesh.exterior_faces). - SubSlice keeps the node indices from the .smv file. A cell-centred plane SLCC ... k k holds the cell below node k; its coordinates, its mask and to_global use that cell instead of picking one of the two cells next to node k by float rounding. - to_global(return_coordinates=True) returns the cell centres for cell-centred slices instead of node positions. - The slices example gets a cell-centred slice to show the masked wall (the wall is one cell thick, so the node-based slice has no node inside it); the known-issue note is removed and the slices, Plot3D and Smoke3D notebooks are run again. This changes the results of masked=True for slices, Plot3D and Smoke3D. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The review found that FDS writes the placeholder into a node whenever all cells of its mesh around it are solid (CORNER_VALUE in dump.f90, and Smokeview blanks nodes the same way), not per obstruction: - Masks are now built from the union of the solid cells of all obstructions in a mesh; a node is blocked if all of the mesh's cells around it are solid. This covers obstructions sharing a face, ending at the edge of the mesh (also with gas beyond in the neighbouring mesh), at the outside of the domain, and holes. Mesh.exterior_faces, the bounding box test and the pass over all mesh pairs are gone. - All parts of an obstruction in a mesh are masked (Obstruction.get_subobstructions), not only the first. - get_2d_slice_from_3d updates the node indices of the cut slice and cuts slices defined with XB at their own index instead of the mesh's. The test case gets a third mesh that adjoins only part of a face and obstructions for each of these cases; the mask matches the placeholder values of FDS 6.11.1 on every slice and mesh. The notebooks are run again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- get_obstruction_mask maps the visible times of an obstruction to indices once instead of searching all times for each of them (was quadratic in the number of time steps), and pads the cells outside the mesh with np.pad. - get_2d_slice_from_3d: cutting a cell-centred slice at a node takes the cell above it, as FDS does for e.g. PBZ (was decided by float rounding), and the cut subslice gets a 2D dimension. - get_obstruction_mask_slice's docstring points to the rules. - Tests: the stored/fresh case handling and the cache-free loading are shared in tests/fds_cases.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
masked=True keeps its original meaning, where the obstructions are, with the bugs of #132 fixed: cells inside an obstruction (not one more), and nodes inside it and on both of its faces (not shifted towards the lower corner). Obstructions without thickness still mask one row, so thin walls stay visible. mask="placeholders" (to_global of slices, Plot3D and Smoke3D; Mesh.get_obstruction_mask(mode=...)) instead hides only the values FDS did not compute but filled with the ambient value, so the gas values on the faces of an obstruction are kept. The tests check the obstruction mask against the obstruction coordinates in the .smv file and the placeholder mask against FDS's output; the tests with fake obstructions keep their expectations from master. The slices example shows the masked wall again with a node-based slice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Compared by hand with Smokeview on the slice PBZ=0.7 of the test case: 199 of 200 areas agreed. The one difference was the part of an obstruction that ends at a mesh boundary, which FDS writes into the neighbouring mesh without thickness: the cell-centred mask blocked the cell after it, although no cell lies inside it and Smokeview does not blank it. Obstructions without thickness now block no cells, but still the nodes on them, so thin walls stay visible in node-based data. The Smokeview reading is a test now; all 200 areas agree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The slice PBY=0.8 read off by hand in Smokeview, where the plane lies on faces of obstructions, crosses one across the mesh boundary and one with a hole: all 200 areas agree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cell-centred slice PBZ=0.4 read off by hand in Smokeview, checked through to_global(masked=True): all 200 cells agree (master: 181). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The local mask arrays in to_global of slices, Plot3D and Smoke3D are renamed, so the new parameter mask is no longer rebound. - Both mask modes walk the obstruction parts through one helper, Mesh._obstruction_parts. - The docstring of get_obstruction_mask says where the default mask and Smokeview's blanking differ (node-based data), and Smoke3D's docstring lists mask with the other parameters. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #132.
What
masked=Truemeansmasked=Truekeeps its original meaning: it hides where the obstructions are, now without the errors described in #132. A new option,mask="placeholders", hides only the values FDS did not compute but filled with the ambient value, and keeps the gas values FDS writes on the faces of an obstruction:The option exists for slices, Plot3D and Smoke3D (
to_global,Smoke3D.to_physical) and asMesh.get_obstruction_mask(..., mode=...)/get_obstruction_mask_slice(..., mode=...).Fixed
x1 … x2on every axis (one too many)x1 … x2-1inside the obstructionx1 … x2-1: lower face masked, upper face notx1 … x2, both facesSLCC … k k; the integer indices from the.smvfile are kept onSubSlice(bound_indices,index_ranges())to_global(return_coordinates=True)for cell-centred slicesPBZ=0.4→ z = 0.45, as Smokeview labels it)Obstruction.get_subobstructions)get_2d_slice_from_3dXBat the mesh's index; cell-centred cuts on a node chosen by roundingPBZThe placeholder mode follows FDS's own rule (
CORNER_VALUEindump.f90): a node gets the ambient value if all cells of its mesh around it are solid.Checked against Smokeview and FDS
New test case
slcf_masks_fds611(FDS 6.11.1, input intests/cases/fds_inputs/slcf_masks.fds, so the release and nightly checks run it too): three meshes, one adjoining another only partly, and obstructions inside a mesh, across a mesh boundary, at the outside of the domain, two sharing a face, one with a hole, and ones ending at a mesh boundary.PBZ=0.7andPBY=0.8, cell-centredPBZ=0.4throughto_global(masked=True)); all 600 areas agree with fdsreader (master: 181/200 on the cell-centred one). The readings are tests..smvfile on every slice and mesh.tests/test_slice_to_global.pykeep their expectations from master.Behaviour changes (for the release notes)
masked=Truegives different arrays: cell-centred masks are one cell smaller per side, node-based masks are no longer shifted towards the lower corner, cell-centred planes may move to the other cell layer.Mesh.get_obstruction_mask_slice()returns the mask in the shape of the subslice's data.masked=Trueare unchanged.Not included
extentof a cell-centred plane still lies on node k, while its coordinates now are the cell centre.&GEOMare not part of either mask; velocity slices (face values) follow a different rule in FDS.The slices, Plot3D and Smoke3D example notebooks were run again; the slices example no longer needs the known-issue note.
🤖 Generated with Claude Code