|
|
| CutCellBody () noexcept |
| | Constructor. Leaves the body empty; call define before reading any moment.
|
| |
|
| ~CutCellBody () noexcept=default |
| | Destructor.
|
| |
| bool | define (const CutCellSurface &a_surface) noexcept |
| | Build the body from the values the surface is reconstructed from.
|
| |
| bool | isConnected () const noexcept |
| | Whether the fluid this body holds is one connected region.
|
| |
| bool | interfaceIsPlanar () const noexcept |
| | Whether every polygon of the interface lies in one plane.
|
| |
| bool | subdivide (CutCellBody *a_children) const noexcept |
| | Cut this body into the bodies of the 2^SpaceDim cells one refinement finer that fill its cell.
|
| |
| bool | hasMultiValuedChildren (const int a_refRat) const noexcept |
| | Whether cutting this body for a refinement asks for a child whose fluid is in more than one piece.
|
| |
| Real | volumeFraction () const noexcept |
| | Volume fraction.
|
| |
| const RealVect & | volumeCentroid () const noexcept |
| | Volume centroid, relative to the cell centre, in units of the cell size.
|
| |
| Real | areaFraction (const int a_dir, const Side::LoHiSide a_side) const noexcept |
| | Area fraction of one cell face.
|
| |
| const RealVect & | faceCentroid (const int a_dir, const Side::LoHiSide a_side) const noexcept |
| | Centroid of one cell face, relative to the face centre, in units of the cell size.
|
| |
| Real | boundaryArea () const noexcept |
| | Magnitude of the interface's area vector.
|
| |
| Real | trueBoundaryArea () const noexcept |
| | Area of the interface itself, as the sum of its triangles' areas.
|
| |
| const RealVect & | normal () const noexcept |
| | Unit normal to the interface, pointing into the fluid.
|
| |
| const RealVect & | boundaryCentroid () const noexcept |
| | Interface centroid, relative to the cell centre, in units of the cell size.
|
| |
| Real | closureResidual () const noexcept |
| | How far the assembled polygons are from enclosing a volume.
|
| |
| void | appendInterfaceFacets (Vector< Real > &a_facets, const IntVect &a_cell, const RealVect &a_probLo, const Real a_dx) const noexcept |
| | Append this body's interface, as triangles in physical coordinates.
|
| |
| void | printPolygons (std::ostream &a_out) const noexcept |
| | Print every polygon this body holds, in the cell's own frame, for inspection.
|
| |
| bool | restrictFace (const CutCellSurface *a_children, const int a_dir, const int a_side) noexcept |
| | Replace one face's chord with the chords of the children that cover it.
|
| |
| bool | closeInterface () noexcept |
| | Rebuild the interface from the face polygons this body holds.
|
| |
| bool | closeBoundary (const int a_face) noexcept |
| | Close the body over the edges no polygon carries in reverse, with a patch lying in a given face.
|
| |
| bool | snapFace (const int a_dir, const int a_side, const bool a_neighbourIsFluid) noexcept |
| | Make one face agree with a neighbour that holds no solid, or none that holds no fluid, and let what the face loses become interface.
|
| |
| bool | weldTJunctions () noexcept |
| | Split every polygon edge at the vertices of other polygons that lie on it.
|
| |
| int | numPolygons () const noexcept |
| | How many polygons this body holds.
|
| |
| int | widestPolygon () const noexcept |
| | Largest number of vertices any of this body's polygons holds.
|
| |
| Real | divergenceResidual () const noexcept |
| | Residual in the identity the moments must satisfy among themselves.
|
| |
|
| void | defineDegenerate (const CutCellSurface &a_surface, const Kind a_kind) noexcept |
| | Moments of a cell the interface only touches, never enters.
|
| |
| bool | defineCut (const CutCellSurface &a_surface) noexcept |
| | Assemble the polygons of a cell the interface passes through.
|
| |
| bool | mergeCoplanar (const Polygon *a_in, const int a_num, Polygon *a_out, const int a_maxOut, int &a_numOut) const noexcept |
| | Merge coplanar polygons into the boundary of their union.
|
| |
| int | faceWalk (const int a_dir, const int a_side, const CutCellSurface &a_surface, Polygon *a_out) const noexcept |
| | The fluid part of one cell face, as outward-oriented polygons.
|
| |
| void | orientOutward (Polygon &a_polygon, const int a_dir, const int a_side) const noexcept |
| | Reverse a face polygon if its area vector points into the fluid.
|
| |
| bool | partitions (const CutCellBody *a_children) const noexcept |
| | Whether a set of children partitions this body, in every moment that has to add up.
|
| |
| void | accumulateMoments () noexcept |
| | Take the moments of the assembled polygons.
|
| |
|
|
Polygon | m_polygon [s_maxPolygons] |
| | The polygons bounding the fluid.
|
| |
|
int | m_numPolygons |
| | Number of polygons in use.
|
| |
|
Real | m_volumeFraction |
| | Volume fraction.
|
| |
|
Real | m_areaFraction [s_numFaces] |
| | Area fraction of each cell face, indexed 2*dir + side.
|
| |
|
Real | m_boundaryArea |
| | Magnitude of the interface's area vector.
|
| |
|
Real | m_trueBoundaryArea |
| | Area of the interface itself.
|
| |
|
RealVect | m_volumeCentroid |
| | Volume centroid.
|
| |
|
RealVect | m_faceCentroid [s_numFaces] |
| | Centroid of each cell face, indexed 2*dir + side.
|
| |
|
RealVect | m_normal |
| | Unit normal to the interface, into the fluid.
|
| |
|
RealVect | m_boundaryCentroid |
| | Interface centroid.
|
| |
|
RealVect | m_closure |
| | Sum of the outward area vectors over every polygon.
|
| |
The closed polyhedron bounding the fluid in one cut cell, and its moments.
The body is assembled from two kinds of polygon. Each cell face contributes the fluid part of that face, found by walking the face's circuit of corners and edges and closing the region off with a straight chord between the crossings. The interface contributes triangles spanning the loop those crossings form, which is not planar in general and is what closes the body.
The moments are then exact integrals of that polyhedron rather than quadratures of the implicit function, which is what makes the divergence identity kappa = (1/SpaceDim)*[sum(alpha)/2 - a_B*(x_B . n)] hold to rounding, and what makes the eight children of a subdivided body sum back to it exactly.
The price is the chord: where Chombo integrates the curved arc the interface really follows, this integrates the straight line between its endpoints. In two dimensions the interface in a cut cell genuinely is that line and nothing is lost.
| bool PolyhedralEB::CutCellBody::hasMultiValuedChildren |
( |
const int |
a_refRat | ) |
const |
|
noexcept |
Whether cutting this body for a refinement asks for a child whose fluid is in more than one piece.
The single-valued property is not inherited: a body whose eight children are all single valued can still have a grandchild that is not, so asking one level down says nothing about two. This asks to the ratio the mesh will actually use, and it is the test to put in front of any cell that a finer grid may subdivide, whether or not the cell sits on a refinement boundary.
A planar interface is answered from interfaceIsPlanar without building anything, since convexity settles every ratio. Otherwise the body is cut in halves repeatedly, log2(a_refRat) times, and every body produced on the way down is asked – not only those at the final ratio. That is deliberate: the intermediate bodies are what a recursive subdivision would actually build, so one of them being multi-valued is a failure even when the cells the mesh ends up with are not. A direct a_refRat-way clip of this body is not the same computation, because each round re-expresses its children in their own frames and closes their interfaces there; when subdivide learns to clip by a ratio in one step, this should follow it.
A body that cannot be cut at all – one whose children would need more polygons or vertices than they can hold – is not reported here. That is a separate failure, and subdivide already returns it.
- Parameters
-
| [in] | a_refRat | Refinement ratio to test, a power of two and at least two. |
- Returns
- True if any body produced on the way to that ratio holds fluid in more than one piece.
| bool PolyhedralEB::CutCellBody::partitions |
( |
const CutCellBody * |
a_children | ) |
const |
|
protectednoexcept |
Whether a set of children partitions this body, in every moment that has to add up.
What subdivide has to deliver, checked rather than asserted so that a caller learns of it. First, that every child holds its fluid in one piece: a child that does not is reported by returning false before anything is summed, because it is a fact about a parent whose interface is twisted rather than a fault to stop on, and hasMultiValuedChildren asks exactly that. Then four things: the children's volumes add to this one's, the apertures of the children on a face of this cell add to that face's, the two children meeting at an interior face agree about it – which is what lets those sums cancel, and what a cell cut from this one relies on to join its sibling – and the children's interface area vectors add to this one's. Each child is also required to satisfy the divergence identity on its own, since a child that does not is not a body whatever it sums to.
A quantity spanning fewer dimensions than the cell is counted once too often per dimension it does not span, so volumes carry 2^-SpaceDim and areas 2^-(SpaceDim-1).
- Parameters
-
| [in] | a_children | The 2^SpaceDim bodies, in quadrant order. |
- Returns
- True if every sum returns this body's own moment to rounding.
| bool PolyhedralEB::CutCellBody::snapFace |
( |
const int |
a_dir, |
|
|
const int |
a_side, |
|
|
const bool |
a_neighbourIsFluid |
|
) |
| |
|
noexcept |
Make one face agree with a neighbour that holds no solid, or none that holds no fluid, and let what the face loses become interface.
A neighbour whose kind was decided otherwise than from its own corners leaves this cell describing a face the neighbour does not agree with: this cell's chord on the shared face ends against nothing, and the two sides read different apertures for it. That happens when the volume threshold or the dust rule turns a cell into a regular or a covered one from its own body, and when the graph fills a cell holding more than one sheet, which is covered whatever its nodes read. The face takes the neighbour's answer – the whole face, or none of it – and the footprint it gives up becomes part of the interface, which lies in the plane of that face. The identity sum(alpha_hi - alpha_lo) = a_B*n survives it exactly, since the aperture and the boundary's area vector gain the same vector. The moments are recomputed, unlike restrictFace, because this body is one a cell takes its moments from.
- Parameters
-
| [in] | a_dir | Direction of the face. |
| [in] | a_side | Side of the cell the face is on. |
| [in] | a_neighbourIsFluid | True if the neighbour holds no solid, false if it holds no fluid. |
- Returns
- True if the body closed again and its volume stayed in range.
| bool PolyhedralEB::CutCellBody::subdivide |
( |
CutCellBody * |
a_children | ) |
const |
|
noexcept |
Cut this body into the bodies of the 2^SpaceDim cells one refinement finer that fill its cell.
A genuine subdivision of the polyhedron, not a reconstruction of it at the finer spacing: each child is this body intersected with its own octant, so the children partition this body and their moments sum back to its own exactly rather than to within the curvature over the cell. That is what makes a cell cut from its parent join the parent's own description – the two share the faces between them by construction, which two independent reconstructions of the same region do not.
The children come back in quadrant order: bit d of a child's index is the side it lies on in direction d, zero low and one high, matching faceCorners and restrictFace. Each is expressed in its own cell's frame, so a length here is twice one there. A child that the fluid misses entirely comes back empty, which reads as covered; one the fluid fills comes back whole.
A vertex of a child is not a crossing of the child's own edges, so the provenance those carry is dropped; closeInterface already handles polygons in that state, since a restricted face leaves them the same way.
- Parameters
-
| [out] | a_children | The 2^SpaceDim bodies, in quadrant order. |
- Returns
- False if a child's fluid region is not connected, if a child would need more polygons or vertices than it can hold, or if the children do not add back up to this body in every moment partitions checks.
| constexpr int PolyhedralEB::CutCellBody::s_maxVertices = 20 |
|
staticconstexprprotected |
Largest number of vertices one of those polygons can carry.
Fourteen was enough for a face carrying a single chord, where the widest polygon measured across four geometries held ten. A face that carries the chords of the cells on the other side of a seam instead of one of its own needs thirteen, measured over 16,640 cut faces, which leaves a single vertex of headroom – not a margin. Twenty restores one.
Raising this costs memory on every body, since a body holds s_maxPolygons of them and the vertex arrays dominate: a polygon goes from 456 to 648 bytes and a body from about 9.4 kB to 13.3 kB. Bodies are transient, built per cut and dropped, so that is paid per thread during a refinement rather than per cell of the index space.
Lowering it is what does damage. Sixteen and eight refused between 156 and 5,226 cells per geometry and lost conservation to 1.8e-2, which is why these two numbers are what they are.