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:
@ -910,6 +910,7 @@ void Foam::autoSnapDriver::detectNearSurfaces
|
||||
Info<< "Detecting near surfaces ..." << endl;
|
||||
|
||||
const pointField& localPoints = pp.localPoints();
|
||||
const labelList& meshPoints = pp.meshPoints();
|
||||
const refinementSurfaces& surfaces = meshRefiner_.surfaces();
|
||||
const fvMesh& mesh = meshRefiner_.mesh();
|
||||
|
||||
@ -1220,6 +1221,7 @@ void Foam::autoSnapDriver::detectNearSurfaces
|
||||
}
|
||||
|
||||
|
||||
const PackedBoolList isMasterPoint(syncTools::getMasterPoints(mesh));
|
||||
label nOverride = 0;
|
||||
|
||||
// 1. All points to non-interface surfaces
|
||||
@ -1332,7 +1334,7 @@ void Foam::autoSnapDriver::detectNearSurfaces
|
||||
}
|
||||
}
|
||||
|
||||
if (override)
|
||||
if (override && isMasterPoint[meshPoints[pointI]])
|
||||
{
|
||||
nOverride++;
|
||||
}
|
||||
@ -1399,8 +1401,6 @@ void Foam::autoSnapDriver::detectNearSurfaces
|
||||
);
|
||||
|
||||
|
||||
label nOverride = 0;
|
||||
|
||||
forAll(hit1, i)
|
||||
{
|
||||
label pointI = zonePointIndices[i];
|
||||
@ -1472,7 +1472,7 @@ void Foam::autoSnapDriver::detectNearSurfaces
|
||||
}
|
||||
}
|
||||
|
||||
if (override)
|
||||
if (override && isMasterPoint[meshPoints[pointI]])
|
||||
{
|
||||
nOverride++;
|
||||
}
|
||||
@ -1690,7 +1690,13 @@ Foam::vectorField Foam::autoSnapDriver::calcNearestSurface
|
||||
scalarField magDisp(mag(patchDisp));
|
||||
|
||||
Info<< "Wanted displacement : average:"
|
||||
<< gSum(magDisp)/returnReduce(patchDisp.size(), sumOp<label>())
|
||||
<< meshRefinement::gAverage
|
||||
(
|
||||
mesh,
|
||||
syncTools::getMasterPoints(mesh),
|
||||
pp.meshPoints(),
|
||||
magDisp
|
||||
)
|
||||
<< " min:" << gMin(magDisp)
|
||||
<< " max:" << gMax(magDisp) << endl;
|
||||
}
|
||||
@ -2548,25 +2554,30 @@ void Foam::autoSnapDriver::doSnap
|
||||
adaptPatchIDs
|
||||
)
|
||||
);
|
||||
indirectPrimitivePatch& pp = ppPtr();
|
||||
|
||||
|
||||
// Distance to attract to nearest feature on surface
|
||||
const scalarField snapDist(calcSnapDistance(mesh, snapParams, pp));
|
||||
const scalarField snapDist(calcSnapDistance(mesh, snapParams, ppPtr()));
|
||||
|
||||
|
||||
// Construct iterative mesh mover.
|
||||
Info<< "Constructing mesh displacer ..." << endl;
|
||||
Info<< "Using mesh parameters " << motionDict << nl << endl;
|
||||
|
||||
const pointMesh& pMesh = pointMesh::New(mesh);
|
||||
|
||||
motionSmoother meshMover
|
||||
autoPtr<motionSmoother> meshMoverPtr
|
||||
(
|
||||
new motionSmoother
|
||||
(
|
||||
mesh,
|
||||
pp,
|
||||
ppPtr(),
|
||||
adaptPatchIDs,
|
||||
meshRefinement::makeDisplacementField(pMesh, adaptPatchIDs),
|
||||
meshRefinement::makeDisplacementField
|
||||
(
|
||||
pointMesh::New(mesh),
|
||||
adaptPatchIDs
|
||||
),
|
||||
motionDict
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@ -2595,16 +2606,95 @@ void Foam::autoSnapDriver::doSnap
|
||||
snapParams,
|
||||
nInitErrors,
|
||||
baffles,
|
||||
meshMover
|
||||
meshMoverPtr()
|
||||
);
|
||||
|
||||
|
||||
|
||||
//- Only if in feature attraction mode:
|
||||
// Nearest feature
|
||||
vectorField patchAttraction;
|
||||
// Constraints at feature
|
||||
List<pointConstraint> patchConstraints;
|
||||
|
||||
|
||||
for (label iter = 0; iter < nFeatIter; iter++)
|
||||
{
|
||||
Info<< nl
|
||||
<< "Morph iteration " << iter << nl
|
||||
<< "-----------------" << endl;
|
||||
|
||||
|
||||
//if (iter > 0 && iter == nFeatIter/2)
|
||||
//{
|
||||
// Info<< "Splitting diagonal attractions" << endl;
|
||||
// const labelList& bFaces = ppPtr().addressing();
|
||||
//
|
||||
// DynamicList<label> splitFaces(bFaces.size());
|
||||
// DynamicList<labelPair> splits(bFaces.size());
|
||||
//
|
||||
// forAll(bFaces, faceI)
|
||||
// {
|
||||
// const labelPair split
|
||||
// (
|
||||
// findDiagonalAttraction
|
||||
// (
|
||||
// ppPtr(),
|
||||
// patchAttraction,
|
||||
// patchConstraints,
|
||||
// faceI
|
||||
// )
|
||||
// );
|
||||
//
|
||||
// if (split != labelPair(-1, -1))
|
||||
// {
|
||||
// splitFaces.append(bFaces[faceI]);
|
||||
// splits.append(split);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// autoPtr<mapPolyMesh> mapPtr = meshRefiner_.splitFaces
|
||||
// (
|
||||
// splitFaces,
|
||||
// splits
|
||||
// );
|
||||
//
|
||||
// const labelList& faceMap = mapPtr().faceMap();
|
||||
// meshRefinement::updateList(faceMap, -1, duplicateFace);
|
||||
// const labelList& reverseFaceMap = mapPtr().reverseFaceMap();
|
||||
// forAll(baffles, i)
|
||||
// {
|
||||
// labelPair& baffle = baffles[i];
|
||||
// baffle.first() = reverseFaceMap[baffle.first()];
|
||||
// baffle.second() = reverseFaceMap[baffle.second()];
|
||||
// }
|
||||
//
|
||||
// meshMoverPtr.clear();
|
||||
// ppPtr.clear();
|
||||
//
|
||||
// ppPtr = meshRefinement::makePatch(mesh, adaptPatchIDs);
|
||||
// meshMoverPtr.reset
|
||||
// (
|
||||
// new motionSmoother
|
||||
// (
|
||||
// mesh,
|
||||
// ppPtr(),
|
||||
// adaptPatchIDs,
|
||||
// meshRefinement::makeDisplacementField
|
||||
// (
|
||||
// pointMesh::New(mesh),
|
||||
// adaptPatchIDs
|
||||
// ),
|
||||
// motionDict
|
||||
// )
|
||||
// );
|
||||
//}
|
||||
|
||||
|
||||
indirectPrimitivePatch& pp = ppPtr();
|
||||
motionSmoother& meshMover = meshMoverPtr();
|
||||
|
||||
|
||||
// Calculate displacement at every patch point. Insert into
|
||||
// meshMover.
|
||||
// Calculate displacement at every patch point
|
||||
@ -2652,7 +2742,9 @@ void Foam::autoSnapDriver::doSnap
|
||||
scalar(iter+1)/nFeatIter,
|
||||
snapDist,
|
||||
disp,
|
||||
meshMover
|
||||
meshMover,
|
||||
patchAttraction,
|
||||
patchConstraints
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -125,7 +125,9 @@ class autoSnapDriver
|
||||
|
||||
void smoothAndConstrain
|
||||
(
|
||||
const PackedBoolList& isMasterEdge,
|
||||
const indirectPrimitivePatch& pp,
|
||||
const labelList& meshEdges,
|
||||
const List<pointConstraint>& constraints,
|
||||
vectorField& disp
|
||||
) const;
|
||||
@ -196,6 +198,16 @@ class autoSnapDriver
|
||||
List<pointConstraint>& patchConstraints
|
||||
) const;
|
||||
|
||||
//- Detect any diagonal attraction. Returns indices in face
|
||||
// or (-1, -1) if none
|
||||
labelPair findDiagonalAttraction
|
||||
(
|
||||
const indirectPrimitivePatch& pp,
|
||||
const vectorField& patchAttraction,
|
||||
const List<pointConstraint>& patchConstraints,
|
||||
const label faceI
|
||||
) const;
|
||||
|
||||
//- Return hit if on multiple points
|
||||
pointIndexHit findMultiPatchPoint
|
||||
(
|
||||
@ -371,7 +383,9 @@ class autoSnapDriver
|
||||
const scalar featureAttract,
|
||||
const scalarField& snapDist,
|
||||
const vectorField& nearestDisp,
|
||||
motionSmoother& meshMover
|
||||
motionSmoother& meshMover,
|
||||
vectorField& patchAttraction,
|
||||
List<pointConstraint>& patchConstraints
|
||||
) const;
|
||||
|
||||
|
||||
|
||||
@ -38,50 +38,18 @@ License
|
||||
#include "treeDataPoint.H"
|
||||
#include "indexedOctree.H"
|
||||
#include "snapParameters.H"
|
||||
#include "PatchTools.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
class listTransform
|
||||
{
|
||||
public:
|
||||
|
||||
void operator()
|
||||
(
|
||||
const vectorTensorTransform& vt,
|
||||
const bool forward,
|
||||
List<List<point> >& fld
|
||||
) const
|
||||
{
|
||||
const tensor T
|
||||
(
|
||||
forward
|
||||
? vt.R()
|
||||
: vt.R().T()
|
||||
);
|
||||
|
||||
forAll(fld, i)
|
||||
{
|
||||
List<point>& elems = fld[i];
|
||||
forAll(elems, elemI)
|
||||
{
|
||||
elems[elemI] = transform(T, elems[elemI]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class listPlusEqOp
|
||||
{
|
||||
public:
|
||||
|
||||
void operator()
|
||||
(
|
||||
List<T>& x,
|
||||
const List<T>& y
|
||||
) const
|
||||
void operator()(List<T>& x, const List<T>& y) const
|
||||
{
|
||||
label sz = x.size();
|
||||
x.setSize(sz+y.size());
|
||||
@ -159,7 +127,9 @@ bool Foam::autoSnapDriver::isFeaturePoint
|
||||
|
||||
void Foam::autoSnapDriver::smoothAndConstrain
|
||||
(
|
||||
const PackedBoolList& isMasterEdge,
|
||||
const indirectPrimitivePatch& pp,
|
||||
const labelList& meshEdges,
|
||||
const List<pointConstraint>& constraints,
|
||||
vectorField& disp
|
||||
) const
|
||||
@ -196,6 +166,10 @@ void Foam::autoSnapDriver::smoothAndConstrain
|
||||
if (nConstraints <= 1)
|
||||
{
|
||||
forAll(pEdges, i)
|
||||
{
|
||||
label edgeI = pEdges[i];
|
||||
|
||||
if (isMasterEdge[meshEdges[edgeI]])
|
||||
{
|
||||
label nbrPointI = edges[pEdges[i]].otherVertex(pointI);
|
||||
if (constraints[nbrPointI].first() >= nConstraints)
|
||||
@ -206,6 +180,7 @@ void Foam::autoSnapDriver::smoothAndConstrain
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
syncTools::syncPointList
|
||||
(
|
||||
@ -564,6 +539,9 @@ void Foam::autoSnapDriver::calcNearestFacePointProperties
|
||||
{
|
||||
const fvMesh& mesh = meshRefiner_.mesh();
|
||||
|
||||
const PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh));
|
||||
|
||||
|
||||
// For now just get all surrounding face data. Expensive - should just
|
||||
// store and sync data on coupled points only
|
||||
// (see e.g PatchToolsNormals.C)
|
||||
@ -583,7 +561,7 @@ void Foam::autoSnapDriver::calcNearestFacePointProperties
|
||||
forAll(pFaces, i)
|
||||
{
|
||||
label faceI = pFaces[i];
|
||||
if (faceSurfaceGlobalRegion[faceI] != -1)
|
||||
if (isMasterFace[faceI] && faceSurfaceGlobalRegion[faceI] != -1)
|
||||
{
|
||||
nFaces++;
|
||||
}
|
||||
@ -605,7 +583,7 @@ void Foam::autoSnapDriver::calcNearestFacePointProperties
|
||||
label faceI = pFaces[i];
|
||||
label globalRegionI = faceSurfaceGlobalRegion[faceI];
|
||||
|
||||
if (globalRegionI != -1)
|
||||
if (isMasterFace[faceI] && globalRegionI != -1)
|
||||
{
|
||||
pNormals[nFaces] = faceSurfaceNormal[faceI];
|
||||
pDisp[nFaces] = faceDisp[faceI];
|
||||
@ -694,7 +672,7 @@ void Foam::autoSnapDriver::calcNearestFacePointProperties
|
||||
pointFaceSurfNormals,
|
||||
listPlusEqOp<point>(),
|
||||
List<point>(),
|
||||
listTransform()
|
||||
mapDistribute::transform()
|
||||
);
|
||||
syncTools::syncPointList
|
||||
(
|
||||
@ -703,7 +681,7 @@ void Foam::autoSnapDriver::calcNearestFacePointProperties
|
||||
pointFaceDisp,
|
||||
listPlusEqOp<point>(),
|
||||
List<point>(),
|
||||
listTransform()
|
||||
mapDistribute::transform()
|
||||
);
|
||||
syncTools::syncPointList
|
||||
(
|
||||
@ -712,7 +690,7 @@ void Foam::autoSnapDriver::calcNearestFacePointProperties
|
||||
pointFaceCentres,
|
||||
listPlusEqOp<point>(),
|
||||
List<point>(),
|
||||
listTransform()
|
||||
mapDistribute::transformPosition()
|
||||
);
|
||||
syncTools::syncPointList
|
||||
(
|
||||
@ -722,6 +700,25 @@ void Foam::autoSnapDriver::calcNearestFacePointProperties
|
||||
listPlusEqOp<label>(),
|
||||
List<label>()
|
||||
);
|
||||
|
||||
|
||||
// Sort the data according to the face centres. This is only so we get
|
||||
// consistent behaviour serial and parallel.
|
||||
labelList visitOrder;
|
||||
forAll(pointFaceDisp, pointI)
|
||||
{
|
||||
List<point>& pNormals = pointFaceSurfNormals[pointI];
|
||||
List<point>& pDisp = pointFaceDisp[pointI];
|
||||
List<point>& pFc = pointFaceCentres[pointI];
|
||||
labelList& pFid = pointFacePatchID[pointI];
|
||||
|
||||
sortedOrder(mag(pFc)(), visitOrder);
|
||||
|
||||
pNormals = List<point>(pNormals, visitOrder);
|
||||
pDisp = List<point>(pDisp, visitOrder);
|
||||
pFc = List<point>(pFc, visitOrder);
|
||||
pFid = UIndirectList<label>(pFid, visitOrder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1360,6 +1357,70 @@ void Foam::autoSnapDriver::stringFeatureEdges
|
||||
}
|
||||
|
||||
|
||||
// If only two attractions and across face return the face indices
|
||||
Foam::labelPair Foam::autoSnapDriver::findDiagonalAttraction
|
||||
(
|
||||
const indirectPrimitivePatch& pp,
|
||||
const vectorField& patchAttraction,
|
||||
const List<pointConstraint>& patchConstraints,
|
||||
const label faceI
|
||||
) const
|
||||
{
|
||||
const face& f = pp.localFaces()[faceI];
|
||||
// For now just detect any attraction. Improve this to look at
|
||||
// actual attraction position and orientation
|
||||
|
||||
labelPair attractIndices(-1, -1);
|
||||
|
||||
if (f.size() >= 4)
|
||||
{
|
||||
forAll(f, fp)
|
||||
{
|
||||
label pointI = f[fp];
|
||||
if (patchConstraints[pointI].first() >= 2)
|
||||
{
|
||||
// Attract to feature edge or point
|
||||
if (attractIndices[0] == -1)
|
||||
{
|
||||
// First attraction. Store
|
||||
attractIndices[0] = fp;
|
||||
}
|
||||
else if (attractIndices[1] == -1)
|
||||
{
|
||||
// Second attraction. Check if not consecutive to first
|
||||
// attraction
|
||||
label fp0 = attractIndices[0];
|
||||
if (f.fcIndex(fp0) == fp || f.fcIndex(fp) == fp0)
|
||||
{
|
||||
// Consecutive. Skip.
|
||||
attractIndices = labelPair(-1, -1);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
attractIndices[1] = fp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// More than two attractions. Skip.
|
||||
attractIndices = labelPair(-1, -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (attractIndices[1] == -1)
|
||||
{
|
||||
// Found only one attraction. Skip.
|
||||
attractIndices = labelPair(-1, -1);
|
||||
}
|
||||
}
|
||||
return attractIndices;
|
||||
}
|
||||
|
||||
|
||||
Foam::pointIndexHit Foam::autoSnapDriver::findNearFeatureEdge
|
||||
(
|
||||
const indirectPrimitivePatch& pp,
|
||||
@ -1929,7 +1990,7 @@ void Foam::autoSnapDriver::featureAttractionUsingFeatureEdges
|
||||
edgeFaceNormals,
|
||||
listPlusEqOp<point>(),
|
||||
List<point>(),
|
||||
listTransform()
|
||||
mapDistribute::transform()
|
||||
);
|
||||
}
|
||||
|
||||
@ -2778,7 +2839,9 @@ Foam::vectorField Foam::autoSnapDriver::calcNearestSurfaceFeature
|
||||
const scalar featureAttract,
|
||||
const scalarField& snapDist,
|
||||
const vectorField& nearestDisp,
|
||||
motionSmoother& meshMover
|
||||
motionSmoother& meshMover,
|
||||
vectorField& patchAttraction,
|
||||
List<pointConstraint>& patchConstraints
|
||||
) const
|
||||
{
|
||||
const Switch implicitFeatureAttraction = snapParams.implicitFeatureSnap();
|
||||
@ -2851,7 +2914,7 @@ Foam::vectorField Foam::autoSnapDriver::calcNearestSurfaceFeature
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// - faceSurfaceNormal
|
||||
// - faceDisp
|
||||
// - faceCentres&faceNormal
|
||||
// - faceCentres
|
||||
List<List<point> > pointFaceSurfNormals(pp.nPoints());
|
||||
List<List<point> > pointFaceDisp(pp.nPoints());
|
||||
List<List<point> > pointFaceCentres(pp.nPoints());
|
||||
@ -2884,10 +2947,11 @@ Foam::vectorField Foam::autoSnapDriver::calcNearestSurfaceFeature
|
||||
// here.
|
||||
|
||||
// Nearest feature
|
||||
vectorField patchAttraction(localPoints.size(), vector::zero);
|
||||
patchAttraction.setSize(localPoints.size());
|
||||
patchAttraction = vector::zero;
|
||||
// Constraints at feature
|
||||
List<pointConstraint> patchConstraints(localPoints.size());
|
||||
|
||||
patchConstraints.setSize(localPoints.size());
|
||||
patchConstraints = pointConstraint();
|
||||
|
||||
if (implicitFeatureAttraction)
|
||||
{
|
||||
@ -2951,15 +3015,29 @@ Foam::vectorField Foam::autoSnapDriver::calcNearestSurfaceFeature
|
||||
patchConstraints
|
||||
);
|
||||
|
||||
const PackedBoolList isMasterPoint(syncTools::getMasterPoints(mesh));
|
||||
{
|
||||
vector avgPatchDisp = meshRefinement::gAverage
|
||||
(
|
||||
mesh,
|
||||
isMasterPoint,
|
||||
pp.meshPoints(),
|
||||
patchDisp
|
||||
);
|
||||
vector avgPatchAttr = meshRefinement::gAverage
|
||||
(
|
||||
mesh,
|
||||
isMasterPoint,
|
||||
pp.meshPoints(),
|
||||
patchAttraction
|
||||
);
|
||||
|
||||
Info<< "Attraction:" << endl
|
||||
<< " linear : max:" << gMax(patchDisp)
|
||||
<< " avg:" << gAverage(patchDisp)
|
||||
<< endl
|
||||
<< " feature : max:" << gMax(patchAttraction)
|
||||
<< " avg:" << gAverage(patchAttraction)
|
||||
<< endl;
|
||||
|
||||
<< " linear : max:" << gMaxMagSqr(patchDisp)
|
||||
<< " avg:" << avgPatchDisp << endl
|
||||
<< " feature : max:" << gMaxMagSqr(patchAttraction)
|
||||
<< " avg:" << avgPatchAttr << endl;
|
||||
}
|
||||
|
||||
// So now we have:
|
||||
// - patchDisp : point movement to go to nearest point on surface
|
||||
@ -2986,12 +3064,19 @@ Foam::vectorField Foam::autoSnapDriver::calcNearestSurfaceFeature
|
||||
|
||||
// Count
|
||||
{
|
||||
const labelList& meshPoints = pp.meshPoints();
|
||||
|
||||
label nMasterPoints = 0;
|
||||
label nPlanar = 0;
|
||||
label nEdge = 0;
|
||||
label nPoint = 0;
|
||||
|
||||
forAll(patchConstraints, pointI)
|
||||
{
|
||||
if (isMasterPoint[meshPoints[pointI]])
|
||||
{
|
||||
nMasterPoints++;
|
||||
|
||||
if (patchConstraints[pointI].first() == 1)
|
||||
{
|
||||
nPlanar++;
|
||||
@ -3005,18 +3090,19 @@ Foam::vectorField Foam::autoSnapDriver::calcNearestSurfaceFeature
|
||||
nPoint++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
label nTotPoints = returnReduce(pp.nPoints(), sumOp<label>());
|
||||
reduce(nMasterPoints, sumOp<label>());
|
||||
reduce(nPlanar, sumOp<label>());
|
||||
reduce(nEdge, sumOp<label>());
|
||||
reduce(nPoint, sumOp<label>());
|
||||
Info<< "Feature analysis : total points:"
|
||||
<< nTotPoints
|
||||
Info<< "Feature analysis : total master points:"
|
||||
<< nMasterPoints
|
||||
<< " attraction to :" << nl
|
||||
<< " feature point : " << nPoint << nl
|
||||
<< " feature edge : " << nEdge << nl
|
||||
<< " nearest surface : " << nPlanar << nl
|
||||
<< " rest : " << nTotPoints-nPoint-nEdge-nPlanar
|
||||
<< " rest : " << nMasterPoints-nPoint-nEdge-nPlanar
|
||||
<< nl
|
||||
<< endl;
|
||||
}
|
||||
@ -3035,11 +3121,29 @@ Foam::vectorField Foam::autoSnapDriver::calcNearestSurfaceFeature
|
||||
|
||||
if (featureAttract < 1-0.001)
|
||||
{
|
||||
const PackedBoolList isMasterEdge(syncTools::getMasterEdges(mesh));
|
||||
|
||||
const vectorField pointNormals
|
||||
(
|
||||
PatchTools::pointNormals
|
||||
(
|
||||
mesh,
|
||||
pp
|
||||
)
|
||||
);
|
||||
const labelList meshEdges
|
||||
(
|
||||
pp.meshEdges(mesh.edges(), mesh.pointEdges())
|
||||
);
|
||||
|
||||
|
||||
// 1. Smoothed all displacement
|
||||
vectorField smoothedPatchDisp = patchDisp;
|
||||
smoothAndConstrain
|
||||
(
|
||||
isMasterEdge,
|
||||
pp,
|
||||
meshEdges,
|
||||
patchConstraints,
|
||||
smoothedPatchDisp
|
||||
);
|
||||
@ -3047,16 +3151,18 @@ Foam::vectorField Foam::autoSnapDriver::calcNearestSurfaceFeature
|
||||
|
||||
// 2. Smoothed tangential component
|
||||
vectorField tangPatchDisp = patchDisp;
|
||||
tangPatchDisp -= (pp.pointNormals() & patchDisp) * pp.pointNormals();
|
||||
tangPatchDisp -= (pointNormals & patchDisp) * pointNormals;
|
||||
smoothAndConstrain
|
||||
(
|
||||
isMasterEdge,
|
||||
pp,
|
||||
meshEdges,
|
||||
patchConstraints,
|
||||
tangPatchDisp
|
||||
);
|
||||
|
||||
// Re-add normal component
|
||||
tangPatchDisp += (pp.pointNormals() & patchDisp) * pp.pointNormals();
|
||||
tangPatchDisp += (pointNormals & patchDisp) * pointNormals;
|
||||
|
||||
if (debug&meshRefinement::OBJINTERSECTIONS)
|
||||
{
|
||||
|
||||
@ -259,23 +259,14 @@ private:
|
||||
label& nRefine
|
||||
) const;
|
||||
|
||||
//- Mark cell if local curvature > curvature or
|
||||
// markDifferingRegions = true and intersections with different
|
||||
// regions.
|
||||
bool checkCurvature
|
||||
//- Helper: count number of normals1 that are in normals2
|
||||
label countMatches
|
||||
(
|
||||
const scalar curvature,
|
||||
const label nAllowRefine,
|
||||
const label surfaceLevel,
|
||||
const vector& surfaceNormal,
|
||||
const label cellI,
|
||||
label& cellMaxLevel,
|
||||
vector& cellMaxNormal,
|
||||
labelList& refineCell,
|
||||
label& nRefine
|
||||
const List<point>& normals1,
|
||||
const List<point>& normals2,
|
||||
const scalar tol = 1e-6
|
||||
) const;
|
||||
|
||||
|
||||
//- Mark cells for surface curvature based refinement. Marks if
|
||||
// local curvature > curvature or if on different regions
|
||||
// (markDifferingRegions)
|
||||
|
||||
@ -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)
|
||||
{
|
||||
cellMaxLevel = surfaceLevel;
|
||||
cellMaxNormal = surfaceNormal;
|
||||
const vector& n2 = normals2[j];
|
||||
|
||||
if (magSqr(n1-n2) < tol)
|
||||
{
|
||||
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,91 +1179,87 @@ 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 (fLevels[hitI] > cellLevel[own])
|
||||
{
|
||||
cellSurfLevels[own].append(fLevels[hitI]);
|
||||
cellSurfNormals[own].append(fNormals[hitI]);
|
||||
}
|
||||
|
||||
if (mesh_.isInternalFace(faceI))
|
||||
{
|
||||
label nei = mesh_.faceNeighbour()[faceI];
|
||||
|
||||
forAll(fLevels, hitI)
|
||||
if (fLevels[hitI] > cellLevel[nei])
|
||||
{
|
||||
checkCurvature
|
||||
cellSurfLevels[nei].append(fLevels[hitI]);
|
||||
cellSurfNormals[nei].append(fNormals[hitI]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Bit of statistics
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool reachedLimit = false;
|
||||
|
||||
|
||||
// 1. Check normals per cell
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
for
|
||||
(
|
||||
curvature,
|
||||
nAllowRefine,
|
||||
|
||||
fLevels[hitI],
|
||||
fNormals[hitI],
|
||||
|
||||
nei,
|
||||
cellMaxLevel[nei],
|
||||
cellMaxNormal[nei],
|
||||
|
||||
refineCell,
|
||||
nRefine
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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++)
|
||||
label cellI = 0;
|
||||
!reachedLimit && cellI < cellSurfNormals.size();
|
||||
cellI++
|
||||
)
|
||||
{
|
||||
label bFaceI = faceI-mesh_.nInternalFaces();
|
||||
label own = mesh_.faceOwner()[faceI];
|
||||
const vectorList& normals = cellSurfNormals[cellI];
|
||||
const labelList& levels = cellSurfLevels[cellI];
|
||||
|
||||
neiBndMaxLevel[bFaceI] = cellMaxLevel[own];
|
||||
neiBndMaxNormal[bFaceI] = cellMaxNormal[own];
|
||||
}
|
||||
syncTools::swapBoundaryFaceList(mesh_, neiBndMaxLevel);
|
||||
syncTools::swapBoundaryFaceList(mesh_, neiBndMaxNormal);
|
||||
|
||||
// Loop over all faces. Could only be checkFaces.. except if they're coupled
|
||||
|
||||
// Internal faces
|
||||
for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
|
||||
// n^2 comparison of all normals in a cell
|
||||
for (label i = 0; !reachedLimit && i < normals.size(); i++)
|
||||
{
|
||||
label own = mesh_.faceOwner()[faceI];
|
||||
label nei = mesh_.faceNeighbour()[faceI];
|
||||
for (label j = i+1; !reachedLimit && j < normals.size(); j++)
|
||||
{
|
||||
if ((normals[i] & normals[j]) < curvature)
|
||||
{
|
||||
label maxLevel = max(levels[i], levels[j]);
|
||||
|
||||
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 (cellLevel[cellI] < maxLevel)
|
||||
{
|
||||
if
|
||||
(
|
||||
!markForRefine
|
||||
(
|
||||
cellMaxLevel[own],
|
||||
maxLevel,
|
||||
nAllowRefine,
|
||||
refineCell[own],
|
||||
refineCell[cellI],
|
||||
nRefine
|
||||
)
|
||||
)
|
||||
@ -1213,17 +1270,93 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
|
||||
<< " limit of " << mesh_.nCells()+7*nRefine
|
||||
<< endl;
|
||||
}
|
||||
reachedLimit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cellLevel[nei] < cellMaxLevel[nei])
|
||||
|
||||
|
||||
// 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;
|
||||
!reachedLimit && faceI < mesh_.nInternalFaces();
|
||||
faceI++
|
||||
)
|
||||
{
|
||||
label own = mesh_.faceOwner()[faceI];
|
||||
label nei = mesh_.faceNeighbour()[faceI];
|
||||
|
||||
const vectorList& ownNormals = cellSurfNormals[own];
|
||||
const labelList& ownLevels = cellSurfLevels[own];
|
||||
const vectorList& neiNormals = cellSurfNormals[nei];
|
||||
const labelList& neiLevels = cellSurfLevels[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++)
|
||||
{
|
||||
// Have valid data on both sides. Check curvature.
|
||||
if ((ownNormals[i] & neiNormals[j]) < curvature)
|
||||
{
|
||||
// See which side to refine.
|
||||
if (cellLevel[own] < ownLevels[i])
|
||||
{
|
||||
if
|
||||
(
|
||||
!markForRefine
|
||||
(
|
||||
cellMaxLevel[nei],
|
||||
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
|
||||
@ -1232,32 +1365,70 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "Stopped refining since reaching my cell"
|
||||
<< " limit of " << mesh_.nCells()+7*nRefine
|
||||
<< endl;
|
||||
Pout<< "Stopped refining since reaching"
|
||||
<< " my cell limit of "
|
||||
<< mesh_.nCells()+7*nRefine << endl;
|
||||
}
|
||||
reachedLimit = true;
|
||||
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)
|
||||
{
|
||||
// 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++)
|
||||
{
|
||||
// Have valid data on both sides. Check curvature.
|
||||
if ((cellMaxNormal[own] & neiBndMaxNormal[bFaceI]) < curvature)
|
||||
if ((ownNormals[i] & neiNormals[j]) < curvature)
|
||||
{
|
||||
if (cellLevel[own] < ownLevels[i])
|
||||
{
|
||||
if
|
||||
(
|
||||
!markForRefine
|
||||
(
|
||||
cellMaxLevel[own],
|
||||
ownLevels[i],
|
||||
nAllowRefine,
|
||||
refineCell[own],
|
||||
nRefine
|
||||
@ -1266,15 +1437,21 @@ Foam::label Foam::meshRefinement::markSurfaceCurvatureRefinement
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "Stopped refining since reaching my cell"
|
||||
<< " limit of " << mesh_.nCells()+7*nRefine
|
||||
Pout<< "Stopped refining since reaching"
|
||||
<< " my cell limit of "
|
||||
<< mesh_.nCells()+7*nRefine
|
||||
<< endl;
|
||||
}
|
||||
reachedLimit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if
|
||||
(
|
||||
|
||||
Reference in New Issue
Block a user