chombo-discharge
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | Static Public Member Functions | Protected Member Functions | Protected Attributes | Static Protected Attributes | List of all members
PolyhedralEB::CutCellBody Class Reference

The closed polyhedron bounding the fluid in one cut cell, and its moments. More...

#include <CD_CutCellBody.H>

Collaboration diagram for PolyhedralEB::CutCellBody:
Collaboration graph
[legend]

Classes

struct  Polygon
 One polygon of the body, in the cell's own frame. More...
 

Public Types

enum class  Kind { Regular , Covered , Cut }
 How a cell relates to the interface.
 

Public Member Functions

 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.
 

Static Public Member Functions

static Kind classify (const CutCellSurface &a_surface) noexcept
 How the cell relates to the interface.
 
static int numSheets (const CutCellSurface &a_surface) noexcept
 How many separate sheets of interface the surface enters the cell as.
 

Protected Member Functions

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.
 

Protected Attributes

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.
 

Static Protected Attributes

static constexpr int s_numFaces = 2 * SpaceDim
 Number of cell faces.
 
static constexpr int s_maxPolygons = 20
 Largest number of polygons a single cut cell's body can need.
 
static constexpr int s_maxVertices = 20
 Largest number of vertices one of those polygons can carry.
 
static constexpr Real s_edgeTolerance = 1.0E-12
 Distance by which a crossing is held off an edge's endpoints.
 
static constexpr Real s_nullArea = 1.0E-18
 Area below which a polygon carries no moment and is dropped.
 

Detailed Description

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.

Member Function Documentation

◆ accumulateMoments()

void PolyhedralEB::CutCellBody::accumulateMoments ( )
protectednoexcept

Take the moments of the assembled polygons.

Face apertures are accumulated signed about the outward normal, because where the interface lies in a cell face it bounds a hole in that face and the aperture is the net area open to flux.

◆ appendInterfaceFacets()

void PolyhedralEB::CutCellBody::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.

The interface is the embedded boundary inside this cell: the polygons the body holds that belong to no cell face. Each is written as a fan of triangles, nine reals per triangle, so that the result can be gathered across ranks and written as one surface. Nothing is appended by a body that is not cut. Coordinates are formed from the cell index rather than the cell centre, so that a vertex two cells share – a point on their common face, or a crossing on a common edge – is the same double from both.

Parameters
[in,out]a_facetsCoordinates to append to.
[in]a_cellIndex of this cell.
[in]a_probLoLower-left corner of the domain.
[in]a_dxGrid spacing of the level this cell belongs to.

◆ areaFraction()

Real PolyhedralEB::CutCellBody::areaFraction ( const int  a_dir,
const Side::LoHiSide  a_side 
) const
noexcept

Area fraction of one cell face.

Parameters
[in]a_dirCoordinate direction of the face normal.
[in]a_sideWhich of the two faces in that direction.
Returns
Fraction of that face open to flux.

◆ boundaryArea()

Real PolyhedralEB::CutCellBody::boundaryArea ( ) const
noexcept

Magnitude of the interface's area vector.

This is the quantity that makes sum(alpha_hi - alpha_lo) equal a_B*n exactly, and it is what PolyGeom::bndryArea derives from the apertures. It under-counts a folded patch, for which see trueBoundaryArea.

Returns
Magnitude of the interface's area vector.

◆ boundaryCentroid()

const RealVect & PolyhedralEB::CutCellBody::boundaryCentroid ( ) const
noexcept

Interface centroid, relative to the cell centre, in units of the cell size.

Returns
Centroid of the interface, relative to the cell centre.

◆ classify()

CutCellBody::Kind PolyhedralEB::CutCellBody::classify ( const CutCellSurface &  a_surface)
staticnoexcept

How the cell relates to the interface.

The cell is cut as soon as two corners disagree under isFluid, regular if every corner is fluid and covered otherwise. An exact zero is solid, so a cell whose face lies in the interface is cut from the fluid side, full, with that face as its interface.

A cell the surface enters as more than one sheet is still called cut here. Whether such a cell should be filled instead – see numSheets for why nothing it can hold describes the feature that put two sheets in it – is a decision for whoever knows whether a finer level carries the cell: one that does is left to it, and one that does not is filled, which is what PolyhedralEBGraph::findUnresolvedCells decides.

Parameters
[in]a_surfaceCorner values in the cell's own frame.
Returns
Regular, Covered or Cut.

◆ closeBoundary()

bool PolyhedralEB::CutCellBody::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.

What closeInterface does, with the face the patch belongs to given rather than assumed to be the interface: cutting the body with a plane leaves it open along that plane, and the patch closing it lies in a face of the cell rather than in the interface. A patch in a cell face is oriented by that face, since the edges bounding the opening do not say which way round it should be.

Parameters
[in]a_faceFace the closing patch lies in, or -1 for the interface.
Returns
True if every loop closed and the result fitted in the body's storage.

◆ closeInterface()

bool PolyhedralEB::CutCellBody::closeInterface ( )
noexcept

Rebuild the interface from the face polygons this body holds.

Every face-polygon edge that no other face polygon carries in reverse bounds the interface, and walking those edges gives its loops. Used instead of the crossing loops once a face has been restricted, since a restricted face has vertices that are not crossings of this cell's edges at all.

Returns
True if every loop closed and the result fitted in the body's storage.

◆ closureResidual()

Real PolyhedralEB::CutCellBody::closureResidual ( ) const
noexcept

How far the assembled polygons are from enclosing a volume.

The sum of the outward area vectors over every polygon, which vanishes for a closed surface. Non-zero means the face polygons and the interface patch disagree about where the body's boundary is, and no moment taken from it can be trusted.

Returns
Length of the summed outward area vector, which vanishes for a closed body.

◆ define()

bool PolyhedralEB::CutCellBody::define ( const CutCellSurface &  a_surface)
noexcept

Build the body from the values the surface is reconstructed from.

Fails, rather than returning an unusable body, when the polygons do not close or when the resulting volume leaves [0,1]. Both are checked rather than assumed, because a folded or self-intersecting patch can pass every individual moment test.

Parameters
[in]a_surfaceCorner values and edge crossings in the cell's own frame.
Returns
True if the body closed and its moments are usable.

◆ defineCut()

bool PolyhedralEB::CutCellBody::defineCut ( const CutCellSurface &  a_surface)
protectednoexcept

Assemble the polygons of a cell the interface passes through.

Parameters
[in]a_surfaceCorner values and edge crossings in the cell's own frame.
Returns
True if the polygons were assembled; false if the face contours could not be paired or the crossings did not form clean loops.

◆ defineDegenerate()

void PolyhedralEB::CutCellBody::defineDegenerate ( const CutCellSurface &  a_surface,
const Kind  a_kind 
)
protectednoexcept

Moments of a cell the interface only touches, never enters.

The boundary of such a cell is one of its own faces, so the area, the normal and the centroid all follow from which face is covered rather than from any polygon.

Parameters
[in]a_surfaceCorner values in the cell's own frame.
[in]a_kindRegular or Covered, as returned by classify.

◆ divergenceResidual()

Real PolyhedralEB::CutCellBody::divergenceResidual ( ) const
noexcept

Residual in the identity the moments must satisfy among themselves.

The divergence theorem applied to a constant field, which holds for any closed body whether or not its interface patch is planar. This is also the relation PolyGeom uses to derive the boundary area and the normal from the apertures, so a non-zero residual means the stored moments and the ones Chombo will recompute disagree. Cheap enough to evaluate on every cut cell, and it is sensitive to errors that each moment's own range check passes.

Returns
Length of sum(alpha_hi - alpha_lo) - a_B*n, which vanishes for any closed body.

◆ faceCentroid()

const RealVect & PolyhedralEB::CutCellBody::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.

Parameters
[in]a_dirCoordinate direction of the face normal.
[in]a_sideWhich of the two faces in that direction.
Returns
Centroid of the open part of that face, relative to the face centre.

◆ faceWalk()

int PolyhedralEB::CutCellBody::faceWalk ( const int  a_dir,
const int  a_side,
const CutCellSurface &  a_surface,
Polygon *  a_out 
) const
protectednoexcept

The fluid part of one cell face, as outward-oriented polygons.

Walks the face's circuit of corners and edges, keeping fluid corners and inserting the crossing wherever an edge changes sign. On a face carrying four crossings the polygons are read off the chord pairing rather than off the corner signs, so that the face cannot disagree with the loop assembly, which trusts that pairing.

Parameters
[in]a_dirCoordinate direction of the face normal.
[in]a_side0 for the low face in that direction, 1 for the high face.
[in]a_surfaceCorner values and edge crossings in the cell's own frame.
[out]a_outRoom for up to two polygons.
Returns
Number of polygons written, or -1 if the face could not be walked.

◆ hasMultiValuedChildren()

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_refRatRefinement 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.

◆ interfaceIsPlanar()

bool PolyhedralEB::CutCellBody::interfaceIsPlanar ( ) const
noexcept

Whether every polygon of the interface lies in one plane.

A planar interface leaves the fluid the cell intersected with a half-space, which is convex. A convex region meets every axis-aligned box in a convex, and therefore connected, set – so a body that answers true here has single-valued children at every refinement ratio, and their children in turn, without any of them being built. It is the one property that settles the question for all ratios at once: everything else is an interpolant of the same crossings and carries no such guarantee. A body whose interface is a single triangle is planar by construction, which is most of the cut cells of a smooth surface.

Returns
True if the interface polygons share a plane, or if the body has no interface at all.

◆ isConnected()

bool PolyhedralEB::CutCellBody::isConnected ( ) const
noexcept

Whether the fluid this body holds is one connected region.

Asked of the polygons rather than of the fluid: they bound a closed surface, so two polygons that share an edge bound the same piece of fluid, and the fluid is in one piece exactly when walking that sharing reaches every polygon from any one of them. A cell the graph builds should never hold two pieces – the interface is anchored to the cell's edges, so it cannot close on itself inside the cell and leave a cavity, and a cell the surface enters as more than one sheet is filled before any body is built. A body cut from a coarser one is different: it was not built from an implicit function, and a single-sheet parent whose interface is twisted can hand a child two pieces. That is what this is asked for, and it is also what decides which polygons bound which piece, and so what opens onto a neighbouring cell.

Returns
True if every polygon is reachable from any other by shared edges, or if the body holds none.

◆ mergeCoplanar()

bool PolyhedralEB::CutCellBody::mergeCoplanar ( const Polygon *  a_in,
const int  a_num,
Polygon *  a_out,
const int  a_maxOut,
int &  a_numOut 
) const
protectednoexcept

Merge coplanar polygons into the boundary of their union.

An edge shared by two of them is interior, so cancelling every edge that appears reversed among the others leaves the union's boundary, and walking what remains gives it in order. Collinear vertices are then dropped, which is what lets a sub-face's edge along a cell edge compare equal to the coarse face's edge beside it. The union need not be connected, and a union of no area is an answer rather than a failure.

Parameters
[in]a_inPolygons to merge, all in one plane.
[in]a_numHow many.
[out]a_outThe union's boundary, one polygon per connected piece.
[in]a_maxOutHow many pieces the caller can hold.
[out]a_numOutHow many pieces were written.
Returns
True if the union was walked and fitted.

◆ normal()

const RealVect & PolyhedralEB::CutCellBody::normal ( ) const
noexcept

Unit normal to the interface, pointing into the fluid.

Returns
Unit normal to the interface, pointing into the fluid.

◆ numPolygons()

int PolyhedralEB::CutCellBody::numPolygons ( ) const
noexcept

How many polygons this body holds.

Returns
Number of polygons.

◆ numSheets()

int PolyhedralEB::CutCellBody::numSheets ( const CutCellSurface &  a_surface)
staticnoexcept

How many separate sheets of interface the surface enters the cell as.

The crossings of a cut cell close into cycles, and each cycle is spanned by its own patch. One cycle is the ordinary case: one patch, and the fluid either side of it. More than one means the cell holds a feature thinner than itself – a plate the nodes only see where it happens to swallow a corner, say – and neither the corner values nor the crossings carry enough to say what that feature is. In two dimensions the crossings pair into chords and the count is half of them.

Parameters
[in]a_surfaceCorner values and edge crossings in the cell's own frame.
Returns
Number of sheets, zero where the corners agree, or -1 where the crossings do not form cycles.

◆ orientOutward()

void PolyhedralEB::CutCellBody::orientOutward ( Polygon &  a_polygon,
const int  a_dir,
const int  a_side 
) const
protectednoexcept

Reverse a face polygon if its area vector points into the fluid.

Parameters
[in,out]a_polygonPolygon lying in the given cell face.
[in]a_dirCoordinate direction of the face normal.
[in]a_side0 for the low face in that direction, 1 for the high face.

◆ partitions()

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_childrenThe 2^SpaceDim bodies, in quadrant order.
Returns
True if every sum returns this body's own moment to rounding.

◆ printPolygons()

void PolyhedralEB::CutCellBody::printPolygons ( std::ostream &  a_out) const
noexcept

Print every polygon this body holds, in the cell's own frame, for inspection.

Parameters
[in,out]a_outStream to print to.

◆ restrictFace()

bool PolyhedralEB::CutCellBody::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.

The face is described at the resolution of the level below rather than this cell's, which is what makes it agree with cells on the other side of a refinement boundary. The interface is dropped with it, since it was built to meet the chord being replaced; call closeInterface once every face that needs restricting has been. The moments are not recomputed: they stay those of the body as defined, since a restricted body is a surface to write rather than a cell to take moments from.

Parameters
[in]a_childrenSurfaces of the children covering this face, in quadrant order.
[in]a_dirDirection of the face.
[in]a_sideSide of the cell the face is on.
Returns
True if the children's chords merged into a face this body can hold.

◆ snapFace()

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_dirDirection of the face.
[in]a_sideSide of the cell the face is on.
[in]a_neighbourIsFluidTrue 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.

◆ subdivide()

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_childrenThe 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.

◆ trueBoundaryArea()

Real PolyhedralEB::CutCellBody::trueBoundaryArea ( ) const
noexcept

Area of the interface itself, as the sum of its triangles' areas.

Equal to boundaryArea only for a planar patch. This is the weight under which a boundary centroid partitions, so it is the one a coarsening rule has to use.

Returns
Area of the interface itself.

◆ volumeCentroid()

const RealVect & PolyhedralEB::CutCellBody::volumeCentroid ( ) const
noexcept

Volume centroid, relative to the cell centre, in units of the cell size.

Returns
Centroid of the fluid, relative to the cell centre.

◆ volumeFraction()

Real PolyhedralEB::CutCellBody::volumeFraction ( ) const
noexcept

Volume fraction.

Returns
Fraction of the cell occupied by fluid.

◆ weldTJunctions()

bool PolyhedralEB::CutCellBody::weldTJunctions ( )
noexcept

Split every polygon edge at the vertices of other polygons that lie on it.

Restricting a face rebuilds it at the finer level's resolution, so an edge the face shares with a face that was left alone can be one segment on one side and several on the other, or carry a vertex on one side that the other has not got. The two sides then compare unequal and closeInterface reads both as boundary, which puts a stretch of a cell face into the interface and leaves the interface itself unclosed. Inserting each side's vertices into the other's edge makes the two agree segment for segment; the inserted vertices lie on the edge they are inserted into, so no polygon changes shape.

Returns
False if a polygon would need more vertices than it can hold.

◆ widestPolygon()

int PolyhedralEB::CutCellBody::widestPolygon ( ) const
noexcept

Largest number of vertices any of this body's polygons holds.

Returns
Vertex count of the widest polygon.

Member Data Documentation

◆ s_edgeTolerance

constexpr Real PolyhedralEB::CutCellBody::s_edgeTolerance = 1.0E-12
staticconstexprprotected

Distance by which a crossing is held off an edge's endpoints.

A corner exactly on the interface makes the surface tangent to the faces meeting there, so the contour touches a face without cutting any of its edges and marching squares cannot represent it. Displacing the crossing makes the combinatorics generic.

◆ s_maxVertices

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.

◆ s_nullArea

constexpr Real PolyhedralEB::CutCellBody::s_nullArea = 1.0E-18
staticconstexprprotected

Area below which a polygon carries no moment and is dropped.

Holding crossings off the edge endpoints leaves slivers of this order behind. They contribute nothing, but a detached one reads as a second connected component, so they are culled rather than carried.


The documentation for this class was generated from the following files: