|
|
| ComputationalGeometry () |
| | Constructor. Sets a blank geometry.
|
| |
|
virtual | ~ComputationalGeometry () |
| | Destructor.
|
| |
| const Vector< Dielectric > & | getDielectrics () const |
| | Get dielectrics.
|
| |
| const Vector< Electrode > & | getElectrodes () const |
| | Get electrodes.
|
| |
| Real | getGasPermittivity () const |
| | Get the background gas permittivity.
|
| |
| void | useScanShop (const ProblemDomain &a_beginDomain) |
| | Calls for ComputationalGeometry to use ScanShop rather than Chombo's default geometry generation tool.
|
| |
|
void | useChomboShop () |
| | Calls for ComputationalGeometry to use Chombo's geometry generation tool.
|
| |
| void | usePolyhedralShop (const ProblemDomain &a_beginDomain) |
| | Generate the geometry with PolyhedralGeometryShop.
|
| |
| void | setDielectrics (const Vector< Dielectric > &a_dielectrics) |
| | Set dielectrics.
|
| |
| void | setElectrodes (const Vector< Electrode > &a_electrodes) |
| | Set electrodes.
|
| |
| void | setGasPermittivity (const Real a_eps0) |
| | Set the background permittivity.
|
| |
| const RefCountedPtr< MultiFluidIndexSpace > & | getMfIndexSpace () const |
| | Get the multifluid index space.
|
| |
| const RefCountedPtr< BaseIF > & | getGasImplicitFunction () const |
| | Get the implicit function used to generate the gas-phase EBIS.
|
| |
| const RefCountedPtr< BaseIF > & | getSolidImplicitFunction () const |
| | Get the implicit function used to generate the solid-phase EBIS.
|
| |
| const RefCountedPtr< BaseIF > & | getImplicitFunction (const phase::which_phase a_phase) const |
| | Get implicit function for the specified phase.
|
| |
| virtual void | makeGrids (const ProblemDomain &a_startDomain, const ProblemDomain &a_stopDomain, const RealVect &a_probLo, const Real a_startDx, const Real a_refineAngle, const int a_maxGhostEB, const int a_minBlockSize, const int a_maxBlockSize) |
| | Build the grids the index space is generated over.
|
| |
| int | getNumGridLevels () const noexcept |
| | Number of levels makeGrids built.
|
| |
| GeometryService::InOut | classify (const Box &a_box, const int a_level, const phase::which_phase a_phase) const |
| | Classify a box on a level from the grids makeGrids built.
|
| |
| GeometryService::InOut | classify (const Box &a_box, const ProblemDomain &a_domain, const phase::which_phase a_phase) const |
| | Classify a box on any domain at or finer than a level makeGrids built.
|
| |
| int | getStartLevel () const noexcept |
| | Level of the start domain. Every level at or below it is whole; the cut tiles begin above it.
|
| |
| int | getLevel (const ProblemDomain &a_domain) const noexcept |
| | Level of a domain among the levels makeGrids built.
|
| |
| Vector< Box > | getBoxes (const phase::which_phase a_phase, const int a_level, const GeometryService::InOut a_type) const noexcept |
| | Boxes of one classification for a phase on a level.
|
| |
| const Vector< Box > & | getBoxes (const int a_level) const noexcept |
| | Every box on a level, both phases' boxes being the same.
|
| |
| const Vector< Box > & | getCutTiles (const int a_level) const noexcept |
| | The cut tiles on a level: the boxes of the level that carry cut cells or nest the level above, which is what a simulation grid on the level is made of. On the start level, its boxes irregular in either phase; empty below it.
|
| |
| const Vector< Box > & | getSplitBoxes (const int a_level, Vector< int > &a_reasons) const noexcept |
| | The boxes that split in the upward pass on a level, with why: 1 a pair inside the box, 2 a pair reaching into the ring outside it, 3 two surfaces facing each other across the band.
|
| |
| const Vector< GeometryService::InOut > & | getTypes (const phase::which_phase a_phase, const int a_level) const noexcept |
| | Classification of every box on a level for a phase, parallel to getBoxes(level).
|
| |
| const ProblemDomain & | getDomain (const int a_level) const noexcept |
| | Domain of a level.
|
| |
| Real | getDx (const int a_level) const noexcept |
| | Grid spacing of a level.
|
| |
| virtual void | buildGeometries (const ProblemDomain &a_finestDomain, const RealVect &a_probLo, const Real a_finestDx, const int a_nCellMax, const int a_maxGhostEB, const int a_maxCoarsen=-1) |
| | Build geometries and the MFIndexSpace.
|
| |
|
|
void | reportGrids () const |
| | Report the boxes and tiles of every level to pout.
|
| |
| void | buildImplicitFunctions () |
| | Build the composite implicit functions of the two phases from the electrodes and dielectrics.
|
| |
| Vector< Vector< GeometryService::InOut > > & | types (const phase::which_phase a_phase) noexcept |
| | The per-level classifications of one phase.
|
| |
| const Vector< Vector< GeometryService::InOut > > & | types (const phase::which_phase a_phase) const noexcept |
| | The per-level classifications of one phase.
|
| |
| void | buildStartLevel () |
| | Step 0: build and classify the start level.
|
| |
| void | buildFinerLevels (Vector< Vector< int > > &a_firstChild, Vector< Vector< int > > &a_numChildren) |
| | Step 1: the upward pass, from the start level to the stop level.
|
| |
| void | classifyBoxes (const Vector< Box > &a_boxes, const int a_level, Vector< GeometryService::InOut > &a_gasTypes, Vector< GeometryService::InOut > &a_solidTypes) const |
| | Classify a list of boxes in both phases, the work shared between the ranks.
|
| |
| Vector< int > | splitFlags (const Vector< Box > &a_boxes, const int a_level, const Vector< GeometryService::InOut > &a_gasTypes, const Vector< GeometryService::InOut > &a_solidTypes) const |
| | Whether each box must split, the work shared between the ranks.
|
| |
| GeometryService::InOut | classifyBox (const Box &a_box, const int a_level, const phase::which_phase a_phase) const |
| | Classify a box of one phase on one level as regular, covered or irregular.
|
| |
| bool | hasTwistedPatch (const Box &a_box, const int a_level, const phase::which_phase a_phase) const |
| | Whether any cut cell of the box holds an interface patch that is twisted about its own centre.
|
| |
| SplitReason | exceedsCurvature (const Box &a_box, const int a_level, const phase::which_phase a_phase) const |
| | Whether the interface turns by more than m_refineAngle between neighbouring cut cells of a box.
|
| |
| bool | doublyCrossedEdge (const Box &a_box, const int a_level, const phase::which_phase a_phase) const |
| | Whether a cell edge of a box is crossed twice by the surface at the spacing of the level above it.
|
| |
| void | makeTiles () |
| | Step 2: tile the boxes that are irregular in either phase into one properly nested set per level.
|
| |
| void | classifyTiles (const Vector< Vector< int > > &a_firstChild, const Vector< Vector< int > > &a_numChildren, Vector< Vector< GeometryService::InOut > > &a_gasTileTypes, Vector< Vector< GeometryService::InOut > > &a_solidTileTypes, Vector< Vector< int > > &a_tileHosts) const |
| | Step 3: place every tile of every level in the boxes and classify it in both phases.
|
| |
| void | buildBoxTrees () |
| | Build the spatial index over the boxes of every level.
|
| |
| std::shared_ptr< BoxTree > | buildTree (const Vector< Box > &a_boxes) const |
| | Build one spatial index over a list of boxes.
|
| |
| bool | tagUnresolvedSeams (Vector< IntVectSet > &a_tags) const |
| | Tag the cells on the coarse side of a level boundary that the level above it would cross twice.
|
| |
| void | buildTileTrees () |
| | Build the spatial index over the cut tiles of every level.
|
| |
| void | buildBoxTree (const int a_level) |
| | Build the spatial index over the boxes of one level.
|
| |
| Vector< int > | boxesMeeting (const int a_level, const Box &a_box) const |
| | Boxes of a level that intersect a box.
|
| |
| Vector< int > | tilesMeeting (const int a_level, const Box &a_box) const |
| | Cut tiles of a level that intersect a box.
|
| |
| int | containingBox (const int a_level, const IntVect &a_cell) const |
| | Index of the box of a level that contains a cell, which one box does on a level that is whole.
|
| |
| void | decimateBoxes (const Vector< Vector< GeometryService::InOut > > &a_gasTileTypes, const Vector< Vector< GeometryService::InOut > > &a_solidTileTypes, const Vector< Vector< int > > &a_tileHosts) |
| | Step 4: cut every hit box down to what the tiles left of it, and replace the lists on the tiled levels with the result.
|
| |
| void | buildCoarserLevels () |
| | Step 5: build the levels coarser than the start level, and push irregularity down onto every whole level.
|
| |
| void | buildGasGeometry (GeometryService *&a_geoserver, const ProblemDomain &a_finestDomain, const RealVect &a_probLo, const Real a_finestDx) |
| | Set up the geometry generation tool for the gas phase.
|
| |
| void | buildSolidGeometry (GeometryService *&a_geoserver, const ProblemDomain &a_finestDomain, const RealVect &a_probLo, const Real a_finestDx) |
| | Set up the geometry generation tool for the solid phase, i.e. the part inside the dielectrics.
|
| |
|
|
Generator | m_generator |
| | Generator selected by the user.
|
| |
|
RefCountedPtr< MultiFluidIndexSpace > | m_multifluidIndexSpace |
| | Multifluid index spaces.
|
| |
|
RefCountedPtr< BaseIF > | m_implicitFunctionGas |
| | The gas-phase implicit function (i.e. outside electrodes and dielectrics).
|
| |
|
RefCountedPtr< BaseIF > | m_implicitFunctionSolid |
| | The solid-phase implicit function (i.e. the inside of the dielectrics).
|
| |
|
Vector< Dielectric > | m_dielectrics |
| | List of dielectrics.
|
| |
|
Vector< Electrode > | m_electrodes |
| | List of electrodes.
|
| |
|
ProblemDomain | m_scanDomain |
| | Grid level where we begin using ScanShop.
|
| |
|
RealVect | m_probLo |
| | Lower-left corner of the domain.
|
| |
|
Real | m_eps0 |
| | Background permittivity.
|
| |
|
Real | m_refineAngle |
| | Angle, in degrees, between neighbouring normals above which an irregular box is split.
|
| |
| bool | m_refineSaddles |
| | Whether a box holding a saddle – an interface patch twisted about its own centre – is split. ComputationalGeometry.refine_saddles, optional, off by default; set it true to turn the refinement on.
|
| |
|
int | m_maxGhostEB |
| | Maximum number of ghost cells that we will ever need.
|
| |
|
int | m_startLevel |
| | Level of the start domain; every level below it is built whole.
|
| |
|
int | m_stopLevel |
| | Level of the stop domain, the finest level.
|
| |
|
int | m_minBlockSize |
| | Tile size, in cells. ComputationalGeometry.min_block_size, 8 when not given.
|
| |
|
int | m_maxBlockSize |
| | Super-tile size, in cells; the size every box makeGrids makes is split to. ComputationalGeometry.max_block_size, 8 when not given.
|
| |
|
bool | m_profile |
| | Whether makeGrids reports its levels and its timings to pout. ComputationalGeometry.profile, off by default.
|
| |
|
bool | m_verbose |
| | Whether every member function announces itself in pout. ComputationalGeometry.verbose, off by default.
|
| |
|
Vector< ProblemDomain > | m_domains |
| | Domains of the levels makeGrids builds, coarsest first.
|
| |
|
Vector< Real > | m_dx |
| | Grid spacings of the levels makeGrids builds, coarsest first.
|
| |
|
Vector< Vector< Box > > | m_cutTiles |
| | Cut-cell tiles per level, common to both phases.
|
| |
|
Vector< Vector< Box > > | m_boxes |
| | Boxes per level, common to both phases.
|
| |
|
Vector< std::shared_ptr< BoxTree > > | m_boxTrees |
| | Spatial index over the boxes of every level, one tree per level, holding the boxes' indices into m_boxes. Null on a level with no boxes, and on every level until buildBoxTrees has run.
|
| |
|
Vector< std::shared_ptr< BoxTree > > | m_tileTrees |
| | Spatial index over the cut tiles of every level, one tree per level, holding the tiles' indices into m_cutTiles. Null on a level with no tiles, and on every level until buildTileTrees has run.
|
| |
|
Vector< Vector< int > > | m_splitCounts |
| | Per level, the number of boxes that split for each SplitReason, and per level the number of tiles that lie in an irregular box (tagged) versus elsewhere (nesting), for the report.
|
| |
|
Vector< Vector< Box > > | m_splitBoxes |
| | Per level, the boxes that split in the upward pass, and why (SplitReason as an integer), parallel.
|
| |
|
Vector< Vector< int > > | m_splitReasons |
| | Per level, the reason each box in m_splitBoxes split.
|
| |
|
Vector< Vector< GeometryService::InOut > > | m_gasTypes |
| | Gas-phase classification of each box in m_boxes, parallel to it.
|
| |
|
Vector< Vector< GeometryService::InOut > > | m_solidTypes |
| | Solid-phase classification of each box in m_boxes, parallel to it.
|
| |
Abstract base class for geometries.
This class encapsulates computational geometries in chombo-discharge. If you construct this object as-is, you will get a blank geometry. To include EBs one must set the electrodes and dielectrics. This is not a pure function, so you can set those objects directly from a ComputationalGeometry object. However, in almost all cases one will want to derive from ComputationalGeometry and create a parametrized geometry (that is what $DISCHARGE_HOME/Geometries is for!).
| void ComputationalGeometry::buildCoarserLevels |
( |
| ) |
|
|
protected |
Step 5: build the levels coarser than the start level, and push irregularity down onto every whole level.
The coarser levels are built as ScanShop builds them, whole and each box classified on its own. On its own a box's classification agrees with the level above only because classifyBox is conservative for a signed-distance function; the second half makes the agreement hold by construction instead. Pseudocode:
for lvl = m_startLevel - 1 down to 0: m_boxes[lvl] = domainSplit(m_domains[lvl], m_maxBlockSize) – no block factor: these levels are not – tiled and the coarsest may be smaller – than a tile classifyBoxes(m_boxes[lvl], lvl) in both phases
for lvl = m_stopLevel - 1 down to 0, per phase: for each box b on lvl + 1 irregular in that phase: the box on lvl containing coarsen(b, 2) is irregular in that phase – exactly one box contains it: every box is a whole super-tile, a whole refinement of one, or a union – of whole tiles, and coarsen(b, 2) is at most half a tile wide on the same lattice.
Runs after decimation: the coarser levels depend on nothing above them, and the push-down needs the final lists of every level above the one it marks.
| void ComputationalGeometry::buildFinerLevels |
( |
Vector< Vector< int > > & |
a_firstChild, |
|
|
Vector< Vector< int > > & |
a_numChildren |
|
) |
| |
|
protected |
Step 1: the upward pass, from the start level to the stop level.
Pseudocode:
for lvl = m_startLevel .. m_stopLevel - 1: for each box on lvl that is regular or covered in both phases: append refine(box, 2) on lvl + 1 with both tags – never a hole beneath these for the boxes on lvl that are irregular in some phase: flags = splitFlags(...): exceedsCurvature, then doublyCrossedEdge, then hasTwistedPatch (if m_refineSaddles), in any phase where the box is irregular for each box with a flag: pieces = domainSplit(refine(box, 2), m_maxBlockSize, m_minBlockSize) classifyBoxes(all pieces, lvl + 1) in both phases, append on lvl + 1 a box without a flag is a leaf: nothing is appended, the region above it is a hole on lvl + 1
The loop always runs to m_stopLevel: once no box splits, the curvature test has nothing to do, but the boxes that are regular or covered in both phases still refine whole onto every remaining level.
The links from each box to its children are handed back for classifyTiles to descend by; they describe the lists as the upward pass leaves them and are stale once decimateBoxes has rewritten a level.
- Parameters
-
| [out] | a_firstChild | Per level and box, the index on the next level of the first child, or -1 for a leaf. |
| [out] | a_numChildren | Per level and box, the number of children: one for a whole refinement, the number of pieces for a split, zero for a leaf. |
| bool ComputationalGeometry::doublyCrossedEdge |
( |
const Box & |
a_box, |
|
|
const int |
a_level, |
|
|
const phase::which_phase |
a_phase |
|
) |
| const |
|
protected |
Whether a cell edge of a box is crossed twice by the surface at the spacing of the level above it.
The three nodes of an edge at the finer spacing are its two ends and its midpoint. Ends that agree under isFluid with a midpoint that disagrees are a surface that enters and leaves through the edge: the edge carries no crossing at this level and one in each half at the next, so a cell holding it cannot describe its own face once the level above describes the other side of it. Such a box is refined until the crossing is resolved, which is what makes the coarse side of a seam representable; a feature the finest level still does not resolve is left to it, since nothing finer describes it.
An end that reads exactly zero is on the surface, and which side of it that end belongs to is not decided at this spacing. The fluid rule breaks the tie toward solid, so an edge reading fluid, solid, zero would read fluid, solid, fluid had the tie gone the other way, which is a pair. Such an end is therefore left open: the ends count as agreeing if any reading of them makes them, and a midpoint that is itself zero decides nothing and is skipped.
- Parameters
-
| [in] | a_box | Box to test. |
| [in] | a_level | Level the box is on. |
| [in] | a_phase | Phase whose implicit function is tested. |
- Returns
- True if some cell edge of the box is crossed twice at the finer spacing.
Whether the interface turns by more than m_refineAngle between neighbouring cut cells of a box.
No index space exists at this point; the cut cells are reconstructed from the implicit function on the level, as the polyhedral shop reconstructs them, and the normal of each is that of its interface polygon. That normal depends on the edge roots alone, so it is a property of the zero set: the implicit function's gradient is not used, because inside a body built by CSG the function is not a distance and its gradient carries the kinks and medial shells of the construction. A phase without an implicit function never asks for a split. Pseudocode:
grown = grow(box, 1) & domain node values over grown, once per node; edge crossings bisected once and shared for each cell in grown: if it is cut and closes, n(cell) = polygon normal for each cut cell in the box and each cut neighbour in its 3^D block: angle > m_refineAngle: Interior if the neighbour is in the box, Ring if in the grown ring; normals facing (dot < 0): Medial the first pair inside the box decides; a ring pair decides only if the box has none of its own
Across a sharp edge the angle never shrinks with dx, so edges refine to the stop level. That is intended.
- Parameters
-
| [in] | a_box | Box to test. |
| [in] | a_level | Level the box lives on. |
| [in] | a_phase | Phase whose implicit function is asked. |
- Returns
- The reason the box must be split, or None if it need not be.
| bool ComputationalGeometry::hasTwistedPatch |
( |
const Box & |
a_box, |
|
|
const int |
a_level, |
|
|
const phase::which_phase |
a_phase |
|
) |
| const |
|
protected |
Whether any cut cell of the box holds an interface patch that is twisted about its own centre.
Four crossings on the four edges of a cell that run in one direction are coplanar exactly when f00 + f11 equals f01 + f10; the difference is the twist, and the patch through them is then a saddle. A saddle is the one shape whose fluid can fall into more than one piece when the cell is cut for a refinement, which is a cell the polyhedral path cannot carry single valued.
The test is the position of the patch's own saddle point. Outside the cell's square the patch rises or falls monotonically across the cell in at least one direction, and every sublevel set of such a patch is connected on every sub-rectangle – so the cell is safe at every refinement ratio and is left alone. Inside, it is not, and the box is split. Measured in cell widths, the twist a cell sees scales with the spacing while the tilt that opposes it does not, so refining halves the one and leaves the other: the patch the level above holds is the same saddle seen from further away.
A twist at or below 1e-8 counts as none. The crossings are solved to about 1e-10 of the edge, and a flat face aligned with the grid has its four crossings agree to the last bit, which leaves the twist and both slopes as rounding; the saddle's position is then one rounding error divided by another and falls inside the square as often as not. Without the floor, a flat surface is refined as though it were rough.
This is deliberately separate from exceedsCurvature, which cannot answer it: that rule measures how much the surface turns, and a gentle saddle turns very little while still being a saddle. It is also blind to a loop that wraps a cell corner rather than crossing four parallel edges, which carries the same risk with no quad to test; such a cell is left to the unresolved-cells rule at the finest level.
Cells are reconstructed from the implicit function on the level, as exceedsCurvature reconstructs them, so nothing is asked of an index space that does not yet exist. A phase without an implicit function never asks for a split.
- Parameters
-
| [in] | a_box | Box to test. |
| [in] | a_level | Level the box lives on. |
| [in] | a_phase | Phase whose implicit function is asked. |
- Returns
- True if some cut cell of the box holds a patch whose saddle lies within it.
| bool ComputationalGeometry::tagUnresolvedSeams |
( |
Vector< IntVectSet > & |
a_tags | ) |
const |
|
protected |
Tag the cells on the coarse side of a level boundary that the level above it would cross twice.
A cell whose edge carries no crossing while each of its halves carries one describes a surface that enters and leaves through that edge. Nothing is wrong with it until the level above describes the other side of that face: the coarse chord then has no crossing to match the two the children have, and the two descriptions cannot be reconciled. Such a cell is tagged so that the level above covers it too.
Only the cells on the coarse side of a level boundary are examined – a cell whose neighbours are all at its own level takes its chords from the same nodes they do, and a cell the level above already covers is not on the coarse side of anything. That is a shell around the tiled region rather than its volume, so the test is cheap however deep the levels go.
Face neighbours are the whole test, even though the four cells meeting along a doubly crossed edge can include one that meets the refined region along that edge alone. Of the other three, the two sharing a face with the refined one carry the same edge and are tagged on this pass, and once they are refined the fourth has a refined face neighbour and is taken on the next, which is what the repeated passes are for.
- Parameters
-
| [in,out] | a_tags | Tags, in the tiler's levels; cells are added to them. |
- Returns
- True if any cell was tagged, so that the tiles must be built again.