Merge branch 'parallel_edgeswapping' into 'master'

Parallel edgeswapping

See merge request jschoeberl/netgen!274
This commit is contained in:
Joachim Schöberl 2019-10-10 05:36:11 +00:00
commit e9d545bcdc
9 changed files with 833 additions and 875 deletions

View File

@ -96,12 +96,6 @@ void ParallelFor( int first, int next, const TFunc & f )
template<typename T>
inline atomic<T> & AsAtomic (T & d)
{
return reinterpret_cast<atomic<T>&> (d);
}
typedef void (*TaskManager)(std::function<void(int,int)>);
typedef void (*Tracer)(string, bool); // false .. start, true .. stop

View File

@ -7,24 +7,6 @@
namespace netgen
{
class Neighbour
{
int nr[3];
int orient[3];
public:
Neighbour () { ; }
void SetNr (int side, int anr) { nr[side] = anr; }
int GetNr (int side) { return nr[side]; }
void SetOrientation (int side, int aorient) { orient[side] = aorient; }
int GetOrientation (int side) { return orient[side]; }
};
class trionedge
{
public:
@ -37,239 +19,25 @@ namespace netgen
};
void MeshOptimize2d :: EdgeSwapping (Mesh & mesh, int usemetric)
{
static Timer timer("EdgeSwapping (2D)"); RegionTimer reg(timer);
if (!faceindex)
{
if (usemetric)
PrintMessage (3, "Edgeswapping, metric");
else
PrintMessage (3, "Edgeswapping, topological");
for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
{
EdgeSwapping (mesh, usemetric);
if (multithread.terminate)
throw NgException ("Meshing stopped");
}
faceindex = 0;
mesh.CalcSurfacesOfNode();
return;
}
static int timerstart = NgProfiler::CreateTimer ("EdgeSwapping 2D start");
NgProfiler::StartTimer (timerstart);
Array<SurfaceElementIndex> seia;
mesh.GetSurfaceElementsOfFace (faceindex, seia);
/*
for (int i = 0; i < seia.Size(); i++)
if (mesh[seia[i]].GetNP() != 3)
{
GenericImprove (mesh);
return;
}
*/
for (SurfaceElementIndex sei : seia)
if (mesh[sei].GetNP() != 3)
{
GenericImprove (mesh);
return;
}
int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr();
Array<Neighbour> neighbors(mesh.GetNSE());
INDEX_2_HASHTABLE<trionedge> other(2*seia.Size() + 2);
Array<bool> swapped(mesh.GetNSE());
NgArray<int,PointIndex::BASE> pdef(mesh.GetNP());
NgArray<double,PointIndex::BASE> pangle(mesh.GetNP());
// int e;
// double d;
// Vec3d nv1, nv2;
// double loch(-1);
static const double minangle[] = { 0, 1.481, 2.565, 3.627, 4.683, 5.736, 7, 9 };
for (int i = 0; i < seia.Size(); i++)
{
const Element2d & sel = mesh[seia[i]];
for (int j = 0; j < 3; j++)
pangle[sel[j]] = 0.0;
}
// pangle = 0;
for (int i = 0; i < seia.Size(); i++)
{
const Element2d & sel = mesh[seia[i]];
for (int j = 0; j < 3; j++)
{
POINTTYPE typ = mesh[sel[j]].Type();
if (typ == FIXEDPOINT || typ == EDGEPOINT)
{
pangle[sel[j]] +=
Angle (mesh[sel[(j+1)%3]] - mesh[sel[j]],
mesh[sel[(j+2)%3]] - mesh[sel[j]]);
}
}
}
// for (PointIndex pi = PointIndex::BASE;
// pi < mesh.GetNP()+PointIndex::BASE; pi++)
// pdef = 0;
for (int i = 0; i < seia.Size(); i++)
{
const Element2d & sel = mesh[seia[i]];
for (int j = 0; j < 3; j++)
{
PointIndex pi = sel[j];
if (mesh[pi].Type() == INNERPOINT || mesh[pi].Type() == SURFACEPOINT)
pdef[pi] = -6;
else
for (int j = 0; j < 8; j++)
if (pangle[pi] >= minangle[j])
pdef[pi] = -1-j;
}
}
/*
for (int i = 0; i < seia.Size(); i++)
{
const Element2d & sel = mesh[seia[i]];
for (int j = 0; j < 3; j++)
pdef[sel[j]]++;
}
*/
for (SurfaceElementIndex sei : seia)
for (PointIndex pi : mesh[sei].PNums<3>())
pdef[pi]++;
// for (int i = 0; i < seia.Size(); i++)
for (SurfaceElementIndex sei : seia)
for (int j = 0; j < 3; j++)
{
neighbors[sei].SetNr (j, -1);
neighbors[sei].SetOrientation (j, 0);
}
/*
NgArray<Vec3d> normals(mesh.GetNP());
for (i = 1; i <= mesh.GetNSE(); i++)
{
Element2d & hel = mesh.SurfaceElement(i);
if (hel.GetIndex() == faceindex)
for (k = 1; k <= 3; k++)
{
int pi = hel.PNum(k);
SelectSurfaceOfPoint (mesh.Point(pi), hel.GeomInfoPi(k));
int surfi = mesh.GetFaceDescriptor(faceindex).SurfNr();
GetNormalVector (surfi, mesh.Point(pi), normals.Elem(pi));
normals.Elem(pi) /= normals.Elem(pi).Length();
}
}
*/
/*
for (int i = 0; i < seia.Size(); i++)
{
const Element2d & sel = mesh[seia[i]];
*/
for (SurfaceElementIndex sei : seia)
{
const Element2d & sel = mesh[sei];
for (int j = 0; j < 3; j++)
{
PointIndex pi1 = sel.PNumMod(j+2);
PointIndex pi2 = sel.PNumMod(j+3);
// double loch = mesh.GetH(mesh[pi1]);
// INDEX_2 edge(pi1, pi2);
// edge.Sort();
if (mesh.IsSegment (pi1, pi2))
continue;
/*
if (segments.Used (edge))
continue;
*/
INDEX_2 ii2 (pi1, pi2);
if (other.Used (ii2))
{
// INDEX_2 i2s(ii2);
// i2s.Sort();
/*
int i2 = other.Get(ii2).tnr;
int j2 = other.Get(ii2).sidenr;
*/
auto othertrig = other.Get(ii2);
SurfaceElementIndex i2 = othertrig.tnr;
int j2 = othertrig.sidenr;
neighbors[sei].SetNr (j, i2);
neighbors[sei].SetOrientation (j, j2);
neighbors[i2].SetNr (j2, sei);
neighbors[i2].SetOrientation (j2, j);
}
else
{
other.Set (INDEX_2 (pi2, pi1), trionedge (sei, j));
}
}
}
for (SurfaceElementIndex sei : seia)
swapped[sei] = false;
NgProfiler::StopTimer (timerstart);
int t = 4;
bool done = false;
while (!done && t >= 2)
{
for (int i = 0; i < seia.Size(); i++)
{
SurfaceElementIndex t1 = seia[i];
if (mesh[t1].IsDeleted())
continue;
if (mesh[t1].GetIndex() != faceindex)
continue;
if (multithread.terminate)
throw NgException ("Meshing stopped");
for (int o1 = 0; o1 < 3; o1++)
bool MeshOptimize2d :: EdgeSwapping (Mesh & mesh, const int usemetric,
Array<Neighbour> &neighbors,
Array<bool> &swapped,
const SurfaceElementIndex t1, const int o1,
const int t,
Array<int,PointIndex> &pdef,
const bool check_only)
{
bool should;
bool do_swap = false;
SurfaceElementIndex t2 = neighbors[t1].GetNr (o1);
int o2 = neighbors[t1].GetOrientation (o1);
if (t2 == -1) continue;
if (swapped[t1] || swapped[t2]) continue;
if (t2 == -1) return false;
if (swapped[t1] || swapped[t2]) return false;
const int faceindex = mesh[t1].GetIndex();
const int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr();
PointIndex pi1 = mesh[t1].PNumMod(o1+1+1);
PointIndex pi2 = mesh[t1].PNumMod(o1+1+2);
@ -289,7 +57,7 @@ namespace netgen
allowswap = allowswap && fabs(1.-(auxvec1*auxvec2)/(auxvec1.Length()*auxvec2.Length())) > 1e-4;
if(!allowswap)
continue;
return false;
// normal of new
Vec<3> nv1 = Cross (auxvec1, auxvec2);
@ -300,7 +68,7 @@ namespace netgen
if(!allowswap)
continue;
return false;
Vec<3> nv2 = Cross (auxvec1, auxvec2);
@ -379,24 +147,11 @@ namespace netgen
if (legal2 < legal1) should = false;
}
if (should)
do_swap = should;
if (should && !check_only)
{
// do swapping !
done = true;
/*
mesh[t1] = { pi1, pi4, pi3 };
mesh[t2] = { pi2, pi3, pi4 };
mesh[t1].GeomInfoPi(1) = gi1;
mesh[t1].GeomInfoPi(2) = gi4;
mesh[t1].GeomInfoPi(3) = gi3;
mesh[t2].GeomInfoPi(1) = gi2;
mesh[t2].GeomInfoPi(2) = gi3;
mesh[t2].GeomInfoPi(3) = gi4;
*/
mesh[t1] = { { pi1, gi1 }, { pi4, gi4 }, { pi3, gi3 } };
mesh[t2] = { { pi2, gi2 }, { pi3, gi3 }, { pi4, gi4 } };
@ -409,8 +164,187 @@ namespace netgen
swapped[t2] = true;
}
}
return do_swap;
}
void MeshOptimize2d :: EdgeSwapping (Mesh & mesh, int usemetric)
{
static Timer timer("EdgeSwapping (2D)"); RegionTimer reg(timer);
static Timer timer_nb("EdgeSwapping-Find neighbors");
if (usemetric)
PrintMessage (3, "Edgeswapping, metric");
else
PrintMessage (3, "Edgeswapping, topological");
static int timerstart = NgProfiler::CreateTimer ("EdgeSwapping 2D start");
NgProfiler::StartTimer (timerstart);
Array<SurfaceElementIndex> seia;
bool mixed = false;
if(faceindex==0)
{
seia.SetSize(mesh.GetNSE());
ParallelFor( Range(seia), [&] (auto i) NETGEN_LAMBDA_INLINE
{
SurfaceElementIndex sei(i);
seia[i] = sei;
if (mesh[sei].GetNP() != 3)
mixed = true;
});
}
else
{
mesh.GetSurfaceElementsOfFace (faceindex, seia);
for (SurfaceElementIndex sei : seia)
if (mesh[sei].GetNP() != 3)
mixed = true;
}
if(mixed)
return GenericImprove(mesh);
Array<Neighbour> neighbors(mesh.GetNSE());
auto elements_on_node = mesh.CreatePoint2SurfaceElementTable(faceindex);
Array<bool> swapped(mesh.GetNSE());
Array<int,PointIndex> pdef(mesh.GetNP());
Array<double,PointIndex> pangle(mesh.GetNP());
static const double minangle[] = { 0, 1.481, 2.565, 3.627, 4.683, 5.736, 7, 9 };
if(faceindex == 0)
{
ParallelFor( Range(pangle), [&] (auto i) NETGEN_LAMBDA_INLINE
{
pangle[i] = 0.0;
});
}
else
{
ParallelFor( Range(seia), [&] (auto i) NETGEN_LAMBDA_INLINE
{
const Element2d & sel = mesh[seia[i]];
for (int j = 0; j < 3; j++)
pangle[sel[j]] = 0.0;
});
}
ParallelFor( Range(seia), [&] (auto i) NETGEN_LAMBDA_INLINE
{
const Element2d & sel = mesh[seia[i]];
for (int j = 0; j < 3; j++)
{
POINTTYPE typ = mesh[sel[j]].Type();
if (typ == FIXEDPOINT || typ == EDGEPOINT)
{
AtomicAdd(pangle[sel[j]],
Angle (mesh[sel[(j+1)%3]] - mesh[sel[j]],
mesh[sel[(j+2)%3]] - mesh[sel[j]]));
}
}
});
ParallelFor( Range(seia), [&] (auto i) NETGEN_LAMBDA_INLINE
{
const Element2d & sel = mesh[seia[i]];
for (int j = 0; j < 3; j++)
{
PointIndex pi = sel[j];
if (mesh[pi].Type() == INNERPOINT || mesh[pi].Type() == SURFACEPOINT)
pdef[pi] = -6;
else
for (int j = 0; j < 8; j++)
if (pangle[pi] >= minangle[j])
pdef[pi] = -1-j;
}
});
ParallelFor( Range(seia), [&pdef, &neighbors, &mesh, &seia, &elements_on_node] (auto i) NETGEN_LAMBDA_INLINE
{
auto sei = seia[i];
for (PointIndex pi : mesh[sei].template PNums<3>())
AsAtomic(pdef[pi])++;
for (int j = 0; j < 3; j++)
{
neighbors[sei].SetNr (j, -1);
neighbors[sei].SetOrientation (j, 0);
}
const auto sel = mesh[sei];
for (int j = 0; j < 3; j++)
{
PointIndex pi1 = sel.PNumMod(j+2);
PointIndex pi2 = sel.PNumMod(j+3);
for (auto sei_other : elements_on_node[pi1])
{
if(sei_other==sei) continue;
const auto & other = mesh[sei_other];
int pi1_other = -1;
int pi2_other = -1;
bool common_edge = false;
for (int k = 0; k < 3; k++)
{
if(other[k] == pi1)
pi1_other = k;
if(other[k] == pi2)
{
pi2_other = k;
common_edge = true;
}
}
if(common_edge)
{
neighbors[sei].SetNr (j, sei_other);
neighbors[sei].SetOrientation (j, 3-pi1_other-pi2_other);
}
}
}
});
for (SurfaceElementIndex sei : seia)
swapped[sei] = false;
NgProfiler::StopTimer (timerstart);
Array<std::pair<SurfaceElementIndex,int>> improvement_candidates(3*seia.Size());
atomic<int> cnt(0);
int t = 4;
bool done = false;
while (!done && t >= 2)
{
cnt = 0;
ParallelFor( Range(seia), [&] (auto i) NETGEN_LAMBDA_INLINE
{
SurfaceElementIndex t1 = seia[i];
if (mesh[t1].IsDeleted())
return;
if (mesh[t1].GetIndex() != faceindex)
return;
if (multithread.terminate)
throw NgException ("Meshing stopped");
for (int o1 = 0; o1 < 3; o1++)
if(EdgeSwapping(mesh, usemetric, neighbors, swapped, t1, o1, t, pdef, true))
improvement_candidates[cnt++]= std::make_pair(t1,o1);
});
auto elements_with_improvement = improvement_candidates.Range(cnt.load());
QuickSort(elements_with_improvement);
for (auto [t1,o1] : elements_with_improvement)
done |= EdgeSwapping(mesh, usemetric, neighbors, swapped, t1, o1, t, pdef, false);
t--;
}

View File

@ -2,6 +2,20 @@
#define FILE_IMPROVE2
class Neighbour
{
int nr[3];
int orient[3];
public:
Neighbour () { ; }
void SetNr (int side, int anr) { nr[side] = anr; }
int GetNr (int side) { return nr[side]; }
void SetOrientation (int side, int aorient) { orient[side] = aorient; }
int GetOrientation (int side) { return orient[side]; }
};
///
class MeshOptimize2d
@ -22,6 +36,8 @@ public:
void ProjectBoundaryPoints(NgArray<int> & surfaceindex,
const NgArray<Point<3>* > & from, NgArray<Point<3>* > & dest);
bool EdgeSwapping (Mesh & mesh, const int usemetric, Array<Neighbour> &neighbors, Array<bool> &swapped,
const SurfaceElementIndex t1, const int edge, const int t, Array<int,PointIndex> &pdef, const bool check_only=false);
void EdgeSwapping (Mesh & mesh, int usemetric);
void CombineImprove (Mesh & mesh);
void SplitImprove (Mesh & mesh);

View File

@ -21,6 +21,7 @@ namespace netgen
void MeshOptimize2d :: GenericImprove (Mesh & mesh)
{
static Timer timer("MeshOptimize2d::GenericImprove"); RegionTimer reg(timer);
if (!faceindex)
{
if (writestatus)

View File

@ -6205,14 +6205,19 @@ namespace netgen
{
for (PointIndex pi : myrange)
QuickSort(elementsonnode[pi]);
});
}, ngcore::TasksPerThread(4));
return move(elementsonnode);
}
Table<SurfaceElementIndex, PointIndex> Mesh :: CreatePoint2SurfaceElementTable() const
Table<SurfaceElementIndex, PointIndex> Mesh :: CreatePoint2SurfaceElementTable( int faceindex ) const
{
static Timer timer("Mesh::CreatePoint2SurfaceElementTable"); RegionTimer rt(timer);
TableCreator<SurfaceElementIndex, PointIndex> creator(GetNP());
if(faceindex==0)
{
for ( ; !creator.Done(); creator++)
ngcore::ParallelForRange
(Range(surfelements), [&] (auto myrange)
@ -6220,7 +6225,21 @@ namespace netgen
for (SurfaceElementIndex ei : myrange)
for (PointIndex pi : (*this)[ei].PNums())
creator.Add (pi, ei);
});
}, ngcore::TasksPerThread(4));
}
else
{
Array<SurfaceElementIndex> face_els;
GetSurfaceElementsOfFace(faceindex, face_els);
for ( ; !creator.Done(); creator++)
ngcore::ParallelForRange
(Range(face_els), [&] (auto myrange)
{
for (auto i : myrange)
for (PointIndex pi : (*this)[face_els[i]].PNums())
creator.Add (pi, face_els[i]);
}, ngcore::TasksPerThread(4));
}
auto elementsonnode = creator.MoveTable();
ngcore::ParallelForRange

View File

@ -762,7 +762,7 @@ namespace netgen
Table<ElementIndex, PointIndex> CreatePoint2ElementTable() const;
Table<SurfaceElementIndex, PointIndex> CreatePoint2SurfaceElementTable() const;
Table<SurfaceElementIndex, PointIndex> CreatePoint2SurfaceElementTable( int faceindex=0 ) const;
DLL_HEADER bool PureTrigMesh (int faceindex = 0) const;
DLL_HEADER bool PureTetMesh () const;

View File

@ -306,7 +306,6 @@ int STLSurfaceMeshing (STLGeometry & geom, class Mesh & mesh, const MeshingParam
mesh.CalcSurfacesOfNode();
optmesh.EdgeSwapping (mesh, 0);
mesh.CalcSurfacesOfNode();
optmesh.ImproveMesh (mesh, mparam);
}

File diff suppressed because it is too large Load Diff

View File

@ -58,6 +58,8 @@ def getMeshingparameters(filename):
return standard[:3] # this gets too big for finer meshsizes
if filename == "screw.step":
return standard[3:] # coarser meshes don't work here
if filename == "part1.stl":
return standard[0:1] + standard[2:] # very coarse does not work
return standard
_geofiles = [f for f in getFiles(".geo")] + [f for f in getFiles(".stl")]