9. AMR tagging
An adaptive grid decides where to refine before any field exists. FOSSIL answers the tagging questions from the BVH alone: does a block meet the wall, does the wall come near it, and if neither, is it inside or outside. This chapter classifies the blocks of an 8³ partition of the domain, then tags the cells of a 32³ block.
use fossil, only : surface_stl_object, BOX_CUT, BOX_NEAR, BOX_INSIDE, BOX_OUTSIDE
use penf, only : I4P, R8P
implicit none
integer(I4P), parameter :: nb = 8 ! blocks per direction
integer(I4P), parameter :: nc = 32 ! cells per direction of the tagged block
type(surface_stl_object) :: surface
real(R8P) :: lo(3, nb**3), hi(3, nb**3), x(nc + 1), hb
integer(I4P) :: codes(nb**3), tags(nc, nc, nc), i, j, k, b
call surface%load_from_file(file_name='dragon-placed.stl', guess_format=.true.)
hb = 1.2_R8P / nb ! the domain [-0.6, 0.6]^3 cut into 8^3 blocks
b = 0
do k = 1, nb ; do j = 1, nb ; do i = 1, nb
b = b + 1
lo(:, b) = -0.6_R8P + [i - 1, j - 1, k - 1] * hb
hi(:, b) = lo(:, b) + hb
enddo ; enddo ; enddo
call surface%box_classify_many(lo=lo, hi=hi, codes=codes, radius=0.05_R8P)
print '(A,I0,A,I0,A,I0,A,I0)', 'blocks: cut ', count(codes == BOX_CUT), ', near ', count(codes == BOX_NEAR), &
', inside ', count(codes == BOX_INSIDE), ', outside ', count(codes == BOX_OUTSIDE)box_classify_many(lo=, hi=, codes=)classifies n boxes given their cornerslo(3, n)andhi(3, n):BOX_CUT: the box meets the surface, by a separating-axis test against each candidate triangle, run on the box inflated by 1e-12 of the problem size. The test never misses a contact; a box closer than that may count as cut.BOX_NEAR(only withradius=> 0): not cut, but a triangle comes withinradiusof the box.BOX_INSIDE/BOX_OUTSIDE: neither; one point query at the box centre decides the side.
- The centre query uses
sign_algorithm=, whose default here isSIGN_FAST_WINDING_NUMBER, not the pseudo-normal of the point queries.inside(n)optionally returns the centre side of every box, near boxes included. box_intersects_surface(lo, hi)answers for one box;box_classify_many_deviceruns the batch on the device.
x = [(-0.6_R8P + 1.2_R8P * i / nc, i = 0, nc)] ! cell edges of one 32^3 block over the domain
call surface%tag_block(x=x, y=x, z=x, band=4, tags=tags)
print '(A)', 'tag -5 -4 -3 -2 -1 0 1 2 3 4 5'
print '(A,11I7)', 'cells', (count(tags == i), i = -5, 5)tag_block(x=, y=, z=, band=, tags=)takes the cell edges of a rectilinear block (stretched allowed) and returns one tag per cell: 0 on a cut cell, otherwise the Chebyshev cell distance to the nearest cut cell, capped atband + 1, negative inside and positive outside.band = 4gives the cut, neighbour, extension and reinitialisation rings an IB solver tags.- Each connected group of uncut cells is signed by one point query, with the same default sign algorithm.
- The block sees only itself: a cut cell in a neighbouring block does not count, so a band that must cross block faces needs the block padded with ghost cells.
A cell is cut if the wall crosses it anywhere in its height, so the cut cells follow the wall over the whole layer, not only the section at its mid-plane.
Sharp edges need finer cells than the smooth wall. After call surface%build_features(), the same call takes feature_band= and feature_tags=: a second field, the cell distance to the nearest cell crossed by a sharp, boundary or non-manifold edge. Refine where either field is small. See feature edges.
Running it
$ tut09_amr_tagging
blocks: cut 87, near 62, inside 0, outside 363
tag -5 -4 -3 -2 -1 0 1 2 3 4 5
cells 0 0 0 7 352 1689 2217 2602 3009 3361 19531- Of the 512 blocks, 87 meet the dragon and 62 more are within 0.05 of it. No block of side 0.15 fits inside the thin dragon, so none is inside.
- In the 32³ block, 1689 cells are cut. Inside, no cell is more than 2 cells from a cut cell: the dragon is at most a few cells thick at this spacing. Outside, the cells beyond the band of 4 are capped at +5.
What you learned
box_classify_many sorts blocks into cut, near, inside and outside from the tree alone; tag_block gives signed distance-to-cut bands on a block of cells. Reference: AMR tagging.
Next: 10. Cut cells.