Find the equal-or-larger face neighbour of node across its local face s using the
classic octree ascend/descend search. Returns:
nbr - neighbour node id (0 = physical domain boundary). It is either a LEAF at
any level <= level(node), or an INTERNAL node at exactly level(node)
(meaning the shared face is subdivided on the neighbour side, i.e. finer
neighbours exist).
ns - the neighbour's local face that faces node.
nf - the flip between the two shared faces (0..7, sideInfo(4) convention),
inherited from the base-mesh face where the search crosses a root boundary.
With this, a 2:1 hanging face is exactly "nbr is a leaf with level(nbr) =
level(node)-1", and finer neighbours are exactly "nbr is internal".
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(OctreeMesh3D), | intent(in) | :: | this | |||
| integer, | intent(in) | :: | node | |||
| integer, | intent(in) | :: | s | |||
| integer, | intent(out) | :: | nbr | |||
| integer, | intent(out) | :: | ns | |||
| integer, | intent(out) | :: | nf |
recursive subroutine FaceNeighbor_OctreeMesh3D(this,node,s,nbr,ns,nf)
!! Find the equal-or-larger face neighbour of `node` across its local face s using the
!! classic octree ascend/descend search. Returns:
!! nbr - neighbour node id (0 = physical domain boundary). It is either a LEAF at
!! any level <= level(node), or an INTERNAL node at exactly level(node)
!! (meaning the shared face is subdivided on the neighbour side, i.e. finer
!! neighbours exist).
!! ns - the neighbour's local face that faces `node`.
!! nf - the flip between the two shared faces (0..7, sideInfo(4) convention),
!! inherited from the base-mesh face where the search crosses a root boundary.
!! With this, a 2:1 hanging face is exactly "nbr is a leaf with level(nbr) =
!! level(node)-1", and finer neighbours are exactly "nbr is internal".
implicit none
class(OctreeMesh3D),intent(in) :: this
integer,intent(in) :: node,s
integer,intent(out) :: nbr,ns,nf
! Local
integer :: p,c,pnbr,ps,pf,t,tq
if(this%level(node) == 0) then
! Cross a base-mesh face: neighbour root, its face, and the base flip.
nbr = this%rootNbr(s,this%rootElem(node))
ns = this%rootNbrSide(s,this%rootElem(node))
nf = this%rootFlip(s,this%rootElem(node))
return
endif
p = this%parent(node)
c = this%octant(node)
if(oc_internal(s,c)) then
! Neighbour is the sibling on the other side of an interior face of the parent.
nbr = this%child(oc_reflect(s,c),p)
ns = oc_opposite(s)
nf = 0
return
endif
! Otherwise ascend: find the parent's neighbour across the same face, then descend.
call FaceNeighbor_OctreeMesh3D(this,p,s,pnbr,ps,pf)
if(pnbr == 0) then
nbr = 0
ns = 0
nf = 0
return
endif
if(this%child(1,pnbr) == 0) then
! Parent's neighbour is a leaf (equal or larger than the parent) -> our larger
! neighbour.
nbr = pnbr
ns = ps
nf = pf
return
endif
! Parent's neighbour is internal (at level(node)-1): descend one level to the child
! that borders `node`, matching face quadrants across the face through the flip.
t = oc_subpos(c,s)
tq = faceQuadPerm(t,pf)
nbr = this%child(childOfFace(tq,ps),pnbr)
ns = ps
nf = pf
endsubroutine FaceNeighbor_OctreeMesh3D