mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: autoHexMesh: parallel consistency, fix curvature refinement
This commit is contained in:
@ -38,7 +38,74 @@ License
|
||||
#include "featureEdgeMesh.H"
|
||||
#include "Cloud.H"
|
||||
//#include "globalIndex.H"
|
||||
//#include "OBJstream.H"
|
||||
#include "OBJstream.H"
|
||||
#include "cellSet.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
//- To compare normals
|
||||
static bool less(const vector& x, const vector& y)
|
||||
{
|
||||
for (direction i = 0; i < vector::nComponents; i++)
|
||||
{
|
||||
if (x[i] < y[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (x[i] > y[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// All components the same
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//- To compare normals
|
||||
class normalLess
|
||||
{
|
||||
const vectorList& values_;
|
||||
|
||||
public:
|
||||
|
||||
normalLess(const vectorList& values)
|
||||
:
|
||||
values_(values)
|
||||
{}
|
||||
|
||||
bool operator()(const label a, const label b) const
|
||||
{
|
||||
return less(values_[a], values_[b]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//- template specialization for pTraits<labelList> so we can have fields
|
||||
template<>
|
||||
class pTraits<labelList>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//- Component type
|
||||
typedef labelList cmptType;
|
||||
};
|
||||
|
||||
//- template specialization for pTraits<labelList> so we can have fields
|
||||
template<>
|
||||
class pTraits<vectorList>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//- Component type
|
||||
typedef vectorList cmptType;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
@ -954,64 +1021,33 @@ Foam::label Foam::meshRefinement::markSurfaceRefinement
|
||||
}
|
||||
|
||||
|
||||
// Checks if multiple intersections of a cell (by a surface with a higher
|
||||
// max than the cell level) and if so if the normals at these intersections
|
||||
// make a large angle.
|
||||
// Returns false if the nRefine limit has been reached, true otherwise.
|
||||
bool Foam::meshRefinement::checkCurvature
|
||||
// Count number of matches of first argument in second argument
|
||||
Foam::label Foam::meshRefinement::countMatches
|
||||
(
|
||||
const scalar curvature,
|
||||
const label nAllowRefine,
|
||||
|
||||
const label surfaceLevel, // current intersection max level
|
||||
const vector& surfaceNormal,// current intersection normal
|
||||
|
||||
const label cellI,
|
||||
|
||||
label& cellMaxLevel, // cached max surface level for this cell
|
||||
vector& cellMaxNormal, // cached surface normal for this cell
|
||||
|
||||
labelList& refineCell,
|
||||
label& nRefine
|
||||
const List<point>& normals1,
|
||||
const List<point>& normals2,
|
||||
const scalar tol
|
||||
) const
|
||||
{
|
||||
const labelList& cellLevel = meshCutter_.cellLevel();
|
||||
label nMatches = 0;
|
||||
|
||||
// Test if surface applicable
|
||||
if (surfaceLevel > cellLevel[cellI])
|
||||
forAll(normals1, i)
|
||||
{
|
||||
if (cellMaxLevel == -1)
|
||||
{
|
||||
// First visit of cell. Store
|
||||
cellMaxLevel = surfaceLevel;
|
||||
cellMaxNormal = surfaceNormal;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Second or more visit. Check curvature.
|
||||
if ((cellMaxNormal & surfaceNormal) < curvature)
|
||||
{
|
||||
return markForRefine
|
||||
(
|
||||
surfaceLevel, // mark with any non-neg number.
|
||||
nAllowRefine,
|
||||
refineCell[cellI],
|
||||
nRefine
|
||||
);
|
||||
}
|
||||
const vector& n1 = normals1[i];
|
||||
|
||||
// Set normal to that of highest surface. Not really necessary
|
||||
// over here but we reuse cellMax info when doing coupled faces.
|
||||
if (surfaceLevel > cellMaxLevel)
|
||||
forAll(normals2, j)
|
||||
{
|
||||
const vector& n2 = normals2[j];
|
||||
|
||||
if (magSqr(n1-n2) < tol)
|
||||
{
|
||||
cellMaxLevel = surfaceLevel;
|
||||
cellMaxNormal = surfaceNormal;
|
||||
nMatches++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Did not reach refinement limit.
|
||||
return true;
|
||||
return nMatches;
|
||||
}
|
||||
|
||||
|
||||
@ -1039,6 +1075,9 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
|
||||
// on a different surface gets refined (if its current level etc.)
|
||||
|
||||
|
||||
const PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
|
||||
|
||||
|
||||
// Collect candidate faces (i.e. intersecting any surface and
|
||||
// owner/neighbour not yet refined.
|
||||
labelList testFaces(getRefineCandidateFaces(refineCell));
|
||||
@ -1068,6 +1107,12 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
|
||||
|
||||
start[i] = cellCentres[own];
|
||||
end[i] = neiCc[bFaceI];
|
||||
|
||||
if (!isMasterFace[faceI])
|
||||
{
|
||||
Swap(start[i], end[i]);
|
||||
}
|
||||
|
||||
minLevel[i] = min(cellLevel[own], neiLevel[bFaceI]);
|
||||
}
|
||||
}
|
||||
@ -1081,10 +1126,9 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
|
||||
|
||||
|
||||
// Test for all intersections (with surfaces of higher max level than
|
||||
// minLevel) and cache per cell the max surface level and the local normal
|
||||
// on that surface.
|
||||
labelList cellMaxLevel(mesh_.nCells(), -1);
|
||||
vectorField cellMaxNormal(mesh_.nCells(), vector::zero);
|
||||
// minLevel) and cache per cell the interesting inter
|
||||
labelListList cellSurfLevels(mesh_.nCells());
|
||||
List<vectorList> cellSurfNormals(mesh_.nCells());
|
||||
|
||||
{
|
||||
// Per segment the normals of the surfaces
|
||||
@ -1104,12 +1148,29 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
|
||||
surfaceNormal,
|
||||
surfaceLevel
|
||||
);
|
||||
|
||||
|
||||
// Sort the data according to surface location. This will guarantee
|
||||
// that on coupled faces both sides visit the intersections in
|
||||
// the same order so will decide the same
|
||||
labelList visitOrder;
|
||||
forAll(surfaceNormal, pointI)
|
||||
{
|
||||
vectorList& pNormals = surfaceNormal[pointI];
|
||||
labelList& pLevel = surfaceLevel[pointI];
|
||||
|
||||
sortedOrder(pNormals, visitOrder, normalLess(pNormals));
|
||||
|
||||
pNormals = List<point>(pNormals, visitOrder);
|
||||
pLevel = UIndirectList<label>(pLevel, visitOrder);
|
||||
}
|
||||
|
||||
// Clear out unnecessary data
|
||||
start.clear();
|
||||
end.clear();
|
||||
minLevel.clear();
|
||||
|
||||
// Extract per cell information on the surface with the highest max
|
||||
// Convert face-wise data to cell.
|
||||
forAll(testFaces, i)
|
||||
{
|
||||
label faceI = testFaces[i];
|
||||
@ -1118,164 +1179,280 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
|
||||
const vectorList& fNormals = surfaceNormal[i];
|
||||
const labelList& fLevels = surfaceLevel[i];
|
||||
|
||||
forAll(fLevels, hitI)
|
||||
forAll(fNormals, hitI)
|
||||
{
|
||||
checkCurvature
|
||||
(
|
||||
curvature,
|
||||
nAllowRefine,
|
||||
|
||||
fLevels[hitI],
|
||||
fNormals[hitI],
|
||||
|
||||
own,
|
||||
cellMaxLevel[own],
|
||||
cellMaxNormal[own],
|
||||
|
||||
refineCell,
|
||||
nRefine
|
||||
);
|
||||
}
|
||||
|
||||
if (mesh_.isInternalFace(faceI))
|
||||
{
|
||||
label nei = mesh_.faceNeighbour()[faceI];
|
||||
|
||||
forAll(fLevels, hitI)
|
||||
if (fLevels[hitI] > cellLevel[own])
|
||||
{
|
||||
checkCurvature
|
||||
(
|
||||
curvature,
|
||||
nAllowRefine,
|
||||
cellSurfLevels[own].append(fLevels[hitI]);
|
||||
cellSurfNormals[own].append(fNormals[hitI]);
|
||||
}
|
||||
|
||||
fLevels[hitI],
|
||||
fNormals[hitI],
|
||||
|
||||
nei,
|
||||
cellMaxLevel[nei],
|
||||
cellMaxNormal[nei],
|
||||
|
||||
refineCell,
|
||||
nRefine
|
||||
);
|
||||
if (mesh_.isInternalFace(faceI))
|
||||
{
|
||||
label nei = mesh_.faceNeighbour()[faceI];
|
||||
if (fLevels[hitI] > cellLevel[nei])
|
||||
{
|
||||
cellSurfLevels[nei].append(fLevels[hitI]);
|
||||
cellSurfNormals[nei].append(fNormals[hitI]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Find out a measure of surface curvature and region edges.
|
||||
// Send over surface region and surface normal to neighbour cell.
|
||||
|
||||
labelList neiBndMaxLevel(mesh_.nFaces()-mesh_.nInternalFaces());
|
||||
vectorField neiBndMaxNormal(mesh_.nFaces()-mesh_.nInternalFaces());
|
||||
|
||||
for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
|
||||
// Bit of statistics
|
||||
{
|
||||
label bFaceI = faceI-mesh_.nInternalFaces();
|
||||
label own = mesh_.faceOwner()[faceI];
|
||||
|
||||
neiBndMaxLevel[bFaceI] = cellMaxLevel[own];
|
||||
neiBndMaxNormal[bFaceI] = cellMaxNormal[own];
|
||||
label nSet = 0;
|
||||
label nNormals = 9;
|
||||
forAll(cellSurfNormals, cellI)
|
||||
{
|
||||
const vectorList& normals = cellSurfNormals[cellI];
|
||||
if (normals.size())
|
||||
{
|
||||
nSet++;
|
||||
nNormals += normals.size();
|
||||
}
|
||||
}
|
||||
reduce(nSet, sumOp<label>());
|
||||
reduce(nNormals, sumOp<label>());
|
||||
Info<< "markSurfaceCurvatureRefinement :"
|
||||
<< " cells:" << mesh_.globalData().nTotalCells()
|
||||
<< " of which with normals:" << nSet
|
||||
<< " ; total normals stored:" << nNormals
|
||||
<< endl;
|
||||
}
|
||||
syncTools::swapBoundaryFaceList(mesh_, neiBndMaxLevel);
|
||||
syncTools::swapBoundaryFaceList(mesh_, neiBndMaxNormal);
|
||||
|
||||
// Loop over all faces. Could only be checkFaces.. except if they're coupled
|
||||
|
||||
|
||||
bool reachedLimit = false;
|
||||
|
||||
|
||||
// 1. Check normals per cell
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
for
|
||||
(
|
||||
label cellI = 0;
|
||||
!reachedLimit && cellI < cellSurfNormals.size();
|
||||
cellI++
|
||||
)
|
||||
{
|
||||
const vectorList& normals = cellSurfNormals[cellI];
|
||||
const labelList& levels = cellSurfLevels[cellI];
|
||||
|
||||
// n^2 comparison of all normals in a cell
|
||||
for (label i = 0; !reachedLimit && i < normals.size(); i++)
|
||||
{
|
||||
for (label j = i+1; !reachedLimit && j < normals.size(); j++)
|
||||
{
|
||||
if ((normals[i] & normals[j]) < curvature)
|
||||
{
|
||||
label maxLevel = max(levels[i], levels[j]);
|
||||
|
||||
if (cellLevel[cellI] < maxLevel)
|
||||
{
|
||||
if
|
||||
(
|
||||
!markForRefine
|
||||
(
|
||||
maxLevel,
|
||||
nAllowRefine,
|
||||
refineCell[cellI],
|
||||
nRefine
|
||||
)
|
||||
)
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "Stopped refining since reaching my cell"
|
||||
<< " limit of " << mesh_.nCells()+7*nRefine
|
||||
<< endl;
|
||||
}
|
||||
reachedLimit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 2. Find out a measure of surface curvature
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Look at normals between neighbouring surfaces
|
||||
// Loop over all faces. Could only be checkFaces, except if they're coupled
|
||||
|
||||
// Internal faces
|
||||
for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
|
||||
for
|
||||
(
|
||||
label faceI = 0;
|
||||
!reachedLimit && faceI < mesh_.nInternalFaces();
|
||||
faceI++
|
||||
)
|
||||
{
|
||||
label own = mesh_.faceOwner()[faceI];
|
||||
label nei = mesh_.faceNeighbour()[faceI];
|
||||
|
||||
if (cellMaxLevel[own] != -1 && cellMaxLevel[nei] != -1)
|
||||
{
|
||||
// Have valid data on both sides. Check curvature.
|
||||
if ((cellMaxNormal[own] & cellMaxNormal[nei]) < curvature)
|
||||
{
|
||||
// See which side to refine
|
||||
if (cellLevel[own] < cellMaxLevel[own])
|
||||
{
|
||||
if
|
||||
(
|
||||
!markForRefine
|
||||
(
|
||||
cellMaxLevel[own],
|
||||
nAllowRefine,
|
||||
refineCell[own],
|
||||
nRefine
|
||||
)
|
||||
)
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "Stopped refining since reaching my cell"
|
||||
<< " limit of " << mesh_.nCells()+7*nRefine
|
||||
<< endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
const vectorList& ownNormals = cellSurfNormals[own];
|
||||
const labelList& ownLevels = cellSurfLevels[own];
|
||||
const vectorList& neiNormals = cellSurfNormals[nei];
|
||||
const labelList& neiLevels = cellSurfLevels[nei];
|
||||
|
||||
if (cellLevel[nei] < cellMaxLevel[nei])
|
||||
|
||||
// Special case: owner normals set is a subset of the neighbour
|
||||
// normals. Do not do curvature refinement since other cell's normals
|
||||
// do not add any information. Avoids weird corner extensions of
|
||||
// refinement regions.
|
||||
bool ownIsSubset =
|
||||
countMatches(ownNormals, neiNormals)
|
||||
== ownNormals.size();
|
||||
|
||||
bool neiIsSubset =
|
||||
countMatches(neiNormals, ownNormals)
|
||||
== neiNormals.size();
|
||||
|
||||
|
||||
if (!ownIsSubset && !neiIsSubset)
|
||||
{
|
||||
// n^2 comparison of between ownNormals and neiNormals
|
||||
for (label i = 0; !reachedLimit && i < ownNormals.size(); i++)
|
||||
{
|
||||
for (label j = 0; !reachedLimit && j < neiNormals.size(); j++)
|
||||
{
|
||||
if
|
||||
(
|
||||
!markForRefine
|
||||
(
|
||||
cellMaxLevel[nei],
|
||||
nAllowRefine,
|
||||
refineCell[nei],
|
||||
nRefine
|
||||
)
|
||||
)
|
||||
// Have valid data on both sides. Check curvature.
|
||||
if ((ownNormals[i] & neiNormals[j]) < curvature)
|
||||
{
|
||||
if (debug)
|
||||
// See which side to refine.
|
||||
if (cellLevel[own] < ownLevels[i])
|
||||
{
|
||||
Pout<< "Stopped refining since reaching my cell"
|
||||
<< " limit of " << mesh_.nCells()+7*nRefine
|
||||
<< endl;
|
||||
if
|
||||
(
|
||||
!markForRefine
|
||||
(
|
||||
ownLevels[i],
|
||||
nAllowRefine,
|
||||
refineCell[own],
|
||||
nRefine
|
||||
)
|
||||
)
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "Stopped refining since reaching"
|
||||
<< " my cell limit of "
|
||||
<< mesh_.nCells()+7*nRefine << endl;
|
||||
}
|
||||
reachedLimit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cellLevel[nei] < neiLevels[j])
|
||||
{
|
||||
if
|
||||
(
|
||||
!markForRefine
|
||||
(
|
||||
neiLevels[j],
|
||||
nAllowRefine,
|
||||
refineCell[nei],
|
||||
nRefine
|
||||
)
|
||||
)
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "Stopped refining since reaching"
|
||||
<< " my cell limit of "
|
||||
<< mesh_.nCells()+7*nRefine << endl;
|
||||
}
|
||||
reachedLimit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Send over surface normal to neighbour cell.
|
||||
List<vectorList> neiSurfaceNormals;
|
||||
syncTools::swapBoundaryCellList(mesh_, cellSurfNormals, neiSurfaceNormals);
|
||||
|
||||
// Boundary faces
|
||||
for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
|
||||
for
|
||||
(
|
||||
label faceI = mesh_.nInternalFaces();
|
||||
!reachedLimit && faceI < mesh_.nFaces();
|
||||
faceI++
|
||||
)
|
||||
{
|
||||
label own = mesh_.faceOwner()[faceI];
|
||||
label bFaceI = faceI - mesh_.nInternalFaces();
|
||||
|
||||
if (cellLevel[own] < cellMaxLevel[own] && neiBndMaxLevel[bFaceI] != -1)
|
||||
const vectorList& ownNormals = cellSurfNormals[own];
|
||||
const labelList& ownLevels = cellSurfLevels[own];
|
||||
const vectorList& neiNormals = neiSurfaceNormals[bFaceI];
|
||||
|
||||
// Special case: owner normals set is a subset of the neighbour
|
||||
// normals. Do not do curvature refinement since other cell's normals
|
||||
// do not add any information. Avoids weird corner extensions of
|
||||
// refinement regions.
|
||||
bool ownIsSubset =
|
||||
countMatches(ownNormals, neiNormals)
|
||||
== ownNormals.size();
|
||||
|
||||
bool neiIsSubset =
|
||||
countMatches(neiNormals, ownNormals)
|
||||
== neiNormals.size();
|
||||
|
||||
|
||||
if (!ownIsSubset && !neiIsSubset)
|
||||
{
|
||||
// Have valid data on both sides. Check curvature.
|
||||
if ((cellMaxNormal[own] & neiBndMaxNormal[bFaceI]) < curvature)
|
||||
// n^2 comparison of between ownNormals and neiNormals
|
||||
for (label i = 0; !reachedLimit && i < ownNormals.size(); i++)
|
||||
{
|
||||
if
|
||||
(
|
||||
!markForRefine
|
||||
(
|
||||
cellMaxLevel[own],
|
||||
nAllowRefine,
|
||||
refineCell[own],
|
||||
nRefine
|
||||
)
|
||||
)
|
||||
for (label j = 0; !reachedLimit && j < neiNormals.size(); j++)
|
||||
{
|
||||
if (debug)
|
||||
// Have valid data on both sides. Check curvature.
|
||||
if ((ownNormals[i] & neiNormals[j]) < curvature)
|
||||
{
|
||||
Pout<< "Stopped refining since reaching my cell"
|
||||
<< " limit of " << mesh_.nCells()+7*nRefine
|
||||
<< endl;
|
||||
if (cellLevel[own] < ownLevels[i])
|
||||
{
|
||||
if
|
||||
(
|
||||
!markForRefine
|
||||
(
|
||||
ownLevels[i],
|
||||
nAllowRefine,
|
||||
refineCell[own],
|
||||
nRefine
|
||||
)
|
||||
)
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "Stopped refining since reaching"
|
||||
<< " my cell limit of "
|
||||
<< mesh_.nCells()+7*nRefine
|
||||
<< endl;
|
||||
}
|
||||
reachedLimit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if
|
||||
(
|
||||
returnReduce(nRefine, sumOp<label>())
|
||||
|
||||
Reference in New Issue
Block a user