some more

This commit is contained in:
Matthias Hochsteger 2023-11-29 09:19:27 +01:00
parent d6a3d875cc
commit dd337ce375
4 changed files with 484 additions and 194 deletions

View File

@ -25,8 +25,122 @@ namespace netgen
operator bool() const { return is_intersecting; }
};
std::tuple<int, int> FindCloseVectors(FlatArray<Vec<3>> ns, bool find_max = true) {
int maxpos1;
int maxpos2;
double val = find_max ? -1e99 : 1e99;
for (auto i : Range(ns))
for (auto j : Range(i + 1, ns.Size()))
{
double ip = ns[i] * ns[j];
if((find_max && (ip > val)) || (!find_max && (ip < val)))
{
val = ip;
maxpos1 = i;
maxpos2 = j;
}
}
return {maxpos1, maxpos2};
}
Vec<3> CalcGrowthVector(FlatArray<Vec<3>> ns) {
if(ns.Size() == 0) return {0,0,0};
if(ns.Size() == 1) return ns[0];
if(ns.Size() == 2)
{
auto gw = ns[0];
auto n = ns[1];
auto npn = gw * n;
auto npnp = gw * gw;
auto nn = n * n;
if(fabs(nn-npn*npn/npnp) < 1e-6)
return n;
gw += (nn - npn)/(nn - npn*npn/npnp) * (n - npn/npnp * gw);
return gw;
}
if (ns.Size() == 3)
{
DenseMatrix mat(3,3);
for(auto i : Range(3))
for(auto j : Range(3))
mat(i,j) = ns[i][j];
if(fabs(mat.Det()) > 1e-6) {
DenseMatrix mat(3,3);
for(auto i : Range(3))
for(auto j : Range(3))
mat(i, j) = ns[i] * ns[j];
Vector rhs(3);
rhs = 1.;
Vector res(3);
DenseMatrix inv(3, ns.Size());
CalcInverse(mat, inv);
inv.Mult(rhs, res);
Vec<3> growth = 0.;
for(auto i : Range(ns))
growth += res[i] * ns[i];
return growth;
}
}
auto [maxpos1, maxpos2] = FindCloseVectors(ns);
Array<Vec<3>> new_normals;
new_normals = ns;
const auto dot = ns[maxpos1] * ns[maxpos2];
auto average = 0.5*(ns[maxpos1] + ns[maxpos2]);
average.Normalize();
new_normals[maxpos1] = average;
new_normals.DeleteElement(maxpos2);
auto gw = CalcGrowthVector(new_normals);
for(auto n : ns)
if(n*gw < 0)
throw Exception("Normals not pointing in same direction as growth vector");
return gw;
}
SpecialBoundaryPoint :: GrowthGroup :: GrowthGroup(FlatArray<int> faces_, FlatArray<Vec<3>> normals)
{
faces = faces_;
growth_vector = CalcGrowthVector(normals);
}
SpecialBoundaryPoint :: SpecialBoundaryPoint( const std::map<int, Vec<3>> & normals )
{
// find opposing face normals
Array<Vec<3>> ns;
Array<int> faces;
for(auto [face, normal] : normals){
ns.Append(normal);
faces.Append(face);
}
auto [minface1, minface2] = FindCloseVectors(ns, false);
minface1 = faces[minface1];
minface2 = faces[minface2];
Array<int> g1_faces;
g1_faces.Append(minface1);
Array<int> g2_faces;
g2_faces.Append(minface2);
Array<Vec<3>> normals1, normals2;
for(auto [facei, normali] : normals)
if(facei != minface1 && facei != minface2)
{
g1_faces.Append(facei);
g2_faces.Append(facei);
}
for(auto fi : g1_faces)
normals1.Append(normals.at(fi));
for(auto fi : g2_faces)
normals2.Append(normals.at(fi));
growth_groups.Append(GrowthGroup(g1_faces, normals1));
growth_groups.Append(GrowthGroup(g2_faces, normals2));
}
struct GrowthVectorLimiter {
BoundaryLayerTool & tool;
const BoundaryLayerParameters & params;
Mesh & mesh;
double height;
@ -36,7 +150,8 @@ struct GrowthVectorLimiter {
unique_ptr<BoxTree<3>> tree;
ofstream debug;
GrowthVectorLimiter( Mesh & mesh_, const BoundaryLayerParameters & params_, FlatArray<double, PointIndex> limits_, FlatArray<Vec<3>, PointIndex> growthvectors_, double height_) :
GrowthVectorLimiter( BoundaryLayerTool & tool_, Mesh & mesh_, const BoundaryLayerParameters & params_, FlatArray<double, PointIndex> limits_, FlatArray<Vec<3>, PointIndex> growthvectors_, double height_) :
tool(tool_),
params(params_), mesh(mesh_), height(height_), limits(limits_), growthvectors(growthvectors_), debug("debug.txt") {
changed_domains = params.domains;
if(!params.outside)
@ -47,8 +162,8 @@ struct GrowthVectorLimiter {
Face GetMappedFace( SurfaceElementIndex sei );
Face GetMappedFace( SurfaceElementIndex sei, int face );
auto GetSeg(PointIndex pi, double shift=1.) {
return std::array<Point<3>, 2>{mesh[pi], mesh[pi]+shift*height*limits[pi]*growthvectors[pi]};
auto GetSeg(PointIndex pi, PointIndex pi_to, double shift=1.) {
return std::array<Point<3>, 2>{mesh[pi], mesh[pi]+shift*(mesh[pi_to]-mesh[pi])};
}
auto GetTrig(SurfaceElementIndex sei, double shift = 0.0) {
auto sel = mesh[sei];
@ -99,16 +214,24 @@ struct GrowthVectorLimiter {
static constexpr double INTERSECTION_SAFETY = .99;
void LimitGrowthVector(PointIndex pi, SurfaceElementIndex sei, double trig_shift, double seg_shift) {
Array<PointIndex> pis;
if(tool.special_boundary_points.count(pi)) {
for(auto & group : tool.special_boundary_points[pi].growth_groups)
pis.Append(group.new_points.Last());
}
else
pis.Append(tool.mapto[pi]);
for(auto pi_to : pis) {
if(trig_shift > 0) {
auto intersection = isIntersectingTrig(pi, sei, trig_shift);
auto intersection = isIntersectingTrig(pi, pi_to, sei, trig_shift);
if(!intersection) return;
double dshift = trig_shift;
while(intersection && dshift > 0.01 && dshift > intersection.lam0) {
dshift *= 0.9;
intersection = isIntersectingTrig(pi, sei, dshift);
intersection = isIntersectingTrig(pi, pi_to, sei, dshift);
}
dshift /= 0.9;
intersection = isIntersectingTrig(pi, sei, dshift);
intersection = isIntersectingTrig(pi, pi_to, sei, dshift);
if(dshift < 1)
cout << "final dshift " << dshift << "\t" << intersection.lam0 << endl;
limits[pi] *= intersection.lam0;
@ -117,7 +240,7 @@ struct GrowthVectorLimiter {
limits[sel[i]] *= dshift;
}
else {
auto seg = GetSeg(pi, seg_shift);
auto seg = GetSeg(pi, pi_to, seg_shift);
auto trig = GetTrig(sei, 0.0);
// cout << mesh[sei] << " " << pi << endl;
auto intersection = isIntersectingTrig(seg, trig);
@ -136,6 +259,7 @@ struct GrowthVectorLimiter {
// cout << "limit by 2 safety " << limits[pi] << endl;
// }
}
}
// check with shifted surface elements using growthvectors
// return;
@ -248,9 +372,9 @@ struct GrowthVectorLimiter {
return intersection;
}
Intersection_ isIntersectingPlane ( PointIndex pi, SurfaceElementIndex sei, double shift = 0.0 )
Intersection_ isIntersectingPlane ( PointIndex pi, PointIndex pi_to, SurfaceElementIndex sei, double shift = 0.0 )
{
return isIntersectingPlane(GetSeg(pi), GetTrig(sei, shift));
return isIntersectingPlane(GetSeg(pi, pi_to), GetTrig(sei, shift));
}
Intersection_ isIntersectingTrig ( std::array<Point<3>, 2> seg, std::array<Point<3>, 3> trig )
@ -284,17 +408,18 @@ struct GrowthVectorLimiter {
return intersection;
}
Intersection_ isIntersectingTrig ( PointIndex pi, SurfaceElementIndex sei, double shift=0.0)
Intersection_ isIntersectingTrig ( PointIndex pi, PointIndex pi_to, SurfaceElementIndex sei, double shift=0.0)
{
return isIntersectingTrig(GetSeg(pi), GetTrig(sei, shift));
return isIntersectingTrig(GetSeg(pi, pi_to), GetTrig(sei, shift));
}
void BuildSearchTree(double trig_shift) {
Box<3> bbox(Box<3>::EMPTY_BOX);
for(auto pi : mesh.Points().Range())
for(PointIndex pi : Range(PointIndex::BASE, PointIndex::BASE+tool.np))
{
bbox.Add(mesh[pi]);
bbox.Add(mesh[pi]+max(trig_shift, 1.)*limits[pi]*height*growthvectors[pi]);
if(tool.mapto[pi].Size() >0)
bbox.Add(mesh[tool.mapto[pi].Last()]);
}
tree = make_unique<BoxTree<3>>(bbox);
@ -387,7 +512,7 @@ struct GrowthVectorLimiter {
limits.SetSize(np);
limits = 1.0;
GrowthVectorLimiter limiter(mesh, params, limits, growthvectors, height);
GrowthVectorLimiter limiter(*this, mesh, params, limits, growthvectors, height);
// limit to not intersect with other surface elements
double trig_shift = 0;
@ -402,8 +527,8 @@ struct GrowthVectorLimiter {
// limits = 1.0;
// now limit again with shifted surace elements
trig_shift = 1.0
seg_shift = 1.0
trig_shift = 1.0;
seg_shift = 1.0;
limiter.FindTreeIntersections(trig_shift, seg_shift, [&] (PointIndex pi, SurfaceElementIndex sei) {
limiter.LimitGrowthVector(pi, sei, trig_shift, seg_shift);
});
@ -778,14 +903,23 @@ struct GrowthVectorLimiter {
{
static Timer tall("InterpolateSurfaceGrowthVectors"); RegionTimer rtall(tall);
static Timer tsmooth("InterpolateSurfaceGrowthVectors-Smoothing");
auto np_old = this->np;
auto np = mesh.GetNP();
BitArray is_point_on_bl_surface(np+1);
is_point_on_bl_surface.Clear();
BitArray is_point_on_other_surface(np+1);
is_point_on_other_surface.Clear();
auto getGW = [&] (PointIndex pi) -> Vec<3>& {
if(pi<=np_old)
return growthvectors[pi];
return *get<0>(growth_vector_map[pi]);
};
Array<Vec<3>, PointIndex> normals(np);
for(auto pi : Range(growthvectors))
normals[pi] = growthvectors[pi];
for(auto pi = np_old; pi<np; pi++){
normals[pi+PointIndex::BASE] = getGW(pi+PointIndex::BASE);
}
ParallelForRange( mesh.SurfaceElements().Range(), [&] ( auto myrange )
{
@ -801,7 +935,7 @@ struct GrowthVectorLimiter {
else
{
for(auto pi : mesh[sei].PNums())
if(mesh[pi].Type() == SURFACEPOINT)
if(pi >= np_old + PointIndex::BASE && mesh[pi].Type() == SURFACEPOINT)
is_point_on_bl_surface.SetBitAtomic(pi);
}
}
@ -813,7 +947,7 @@ struct GrowthVectorLimiter {
if(is_point_on_bl_surface[pi])
{
points.Append(pi);
growthvectors[pi] = 0.0;
getGW(pi) = 0.0;
}
if(is_point_on_other_surface[pi])
{
@ -821,6 +955,7 @@ struct GrowthVectorLimiter {
}
}
auto p2sel = mesh.CreatePoint2SurfaceElementTable();
// smooth tangential part of growth vectors from edges to surface elements
RegionTimer rtsmooth(tsmooth);
for(auto i : Range(10))
@ -828,10 +963,12 @@ struct GrowthVectorLimiter {
for(auto pi : points)
{
auto sels = p2sel[pi];
Vec<3> new_gw = growthvectors[pi];
Vec<3> new_gw = getGW(pi);
new_gw = 0.;
int cnt = 1;
std::set<PointIndex> suround;
suround.insert(pi);
double total_weight = 0;
auto normal = normals[pi];
for(auto sei: sels)
{
@ -840,22 +977,35 @@ struct GrowthVectorLimiter {
if(suround.count(pi1)==0)
{
suround.insert(pi1);
auto gw_other = growthvectors[pi1];
auto gw_other = getGW(pi1);
auto normal_other = getNormal(mesh[sei]);
auto tangent_part = gw_other - (gw_other*normal_other)*normal_other;
if(is_point_on_bl_surface[pi])
new_gw += tangent_part;
else
new_gw += gw_other;
double weight = 1.0;
// cout << "tangent part " << pi1 << tangent_part << endl;
if(is_point_on_bl_surface[pi]) {
if(mesh[pi1].Type() == FIXEDPOINT)
weight *= 13-i;
else
weight = 1.0;
new_gw += weight * tangent_part;
}
else {
new_gw += weight * gw_other;
}
total_weight += weight;
}
}
// total_weight += suround.size();
growthvectors[pi] = 1.0/suround.size() * new_gw;
getGW(pi) = 1.0/total_weight * new_gw;
}
}
for(auto pi : points)
growthvectors[pi] += normals[pi];
for(auto pi : points)
getGW(pi) += normals[pi];
// for(auto pi : mesh.Points().Range())
// cout << "point " << pi << " has type " << (int)(mesh[pi].Type()) << endl;
}
@ -1027,95 +1177,20 @@ struct GrowthVectorLimiter {
n *= 1.0/n.Length();
// combine normal vectors for each face to keep uniform distances
auto & np = growthvectors[pi];
ArrayMem<Vec<3>, 5> ns;
for (auto &[facei, n] : normals) {
ns.Append(n);
}
ArrayMem<Vec<3>, 3> removed;
// reduce to full rank of max 3
while(true)
{
// cout << "pi " << pi << endl;
// cout << "ns " << endl;
// for (auto n : ns) cout << n << endl;
if(ns.Size() <= 1)
break;
if(ns.Size() == 2 && ns[0] * ns[1] < 1 - 1e-6)
break;
if (ns.Size() == 3)
{
DenseMatrix mat(3,3);
for(auto i : Range(3))
for(auto j : Range(3))
mat(i,j) = ns[i][j];
if(fabs(mat.Det()) > 1e-6)
break;
}
int maxpos1;
int maxpos2;
double val = 0;
for (auto i : Range(ns))
{
for (auto j : Range(i + 1, ns.Size()))
{
double ip = fabs(ns[i] * ns[j]);
if(ip > val)
{
val = ip;
maxpos1 = i;
maxpos2 = j;
}
}
}
removed.Append(ns[maxpos1]);
removed.Append(ns[maxpos2]);
const auto dot = ns[maxpos1] * ns[maxpos2];
auto average = 0.5*(ns[maxpos1] + ns[maxpos2]);
average.Normalize();
ns.DeleteElement(maxpos2);
try {
growthvectors[pi] = CalcGrowthVector(ns);
}
catch(const Exception & e) {
cout << "caught excption for point " << pi << ":\t" << e.what() << endl;
special_boundary_points.emplace(pi, normals);
growthvectors[pi] = special_boundary_points[pi].growth_groups[0].growth_vector;
}
// if vectors have nearly opposite directions -> remove both
// otherwise, replace both vectors with their average
if(dot < -1+1e-3)
ns.DeleteElement(maxpos1);
else
ns[maxpos1] = average;
}
if(ns.Size() == 0)
continue;
if(ns.Size() == 1)
np = ns[0];
else if(ns.Size() == 2)
{
np = ns[0];
auto n = ns[1];
auto npn = np * n;
auto npnp = np * np;
auto nn = n * n;
if(nn-npn*npn/npnp == 0) { np = n; continue; }
np += (nn - npn)/(nn - npn*npn/npnp) * (n - npn/npnp * np);
}
else // ns.Size() == 3
{
DenseMatrix mat(3,3);
for(auto i : Range(3))
for(auto j : Range(3))
mat(i, j) = ns[i] * ns[j];
Vector rhs(3);
rhs = 1.;
Vector res(3);
DenseMatrix inv(3, ns.Size());
CalcInverse(mat, inv);
inv.Mult(rhs, res);
for(auto i : Range(ns))
np += res[i] * ns[i];
}
for(auto& n : removed)
if(n * np < 0)
cout << "WARNING: Growth vector at point " << pi << " in opposite direction to face normal!" << endl << "Growthvector = " << np << ", face normal = " << n << endl;
}
}
@ -1162,8 +1237,10 @@ struct GrowthVectorLimiter {
{
segs_done.SetBit(sj);
int type;
if(moved_surfaces.Test(segj.si))
if(moved_surfaces.Test(segj.si)) {
type = 0;
moved_segs.Append(sj);
}
else if(const auto& fd = mesh.GetFaceDescriptor(segj.si); domains.Test(fd.DomainIn()) && domains.Test(fd.DomainOut()))
{
type = 2;
@ -1251,9 +1328,21 @@ struct GrowthVectorLimiter {
void BoundaryLayerTool :: InterpolateGrowthVectors()
{
// cout << "new number of line segments " << mesh.LineSegments().Size() << endl;
int new_max_edge_nr = max_edge_nr;
for(const auto& seg : mesh.LineSegments())
if(seg.edgenr > new_max_edge_nr)
new_max_edge_nr = seg.edgenr;
auto getGW = [&] (PointIndex pi) -> Vec<3>& {
return *get<0>(growth_vector_map[pi]);
};
// cout << "edge range " << max_edge_nr << ", " << new_max_edge_nr << endl;
// interpolate tangential component of growth vector along edge
for(auto edgenr : Range(max_edge_nr))
for(auto edgenr : Range(max_edge_nr, new_max_edge_nr))
{
// cout << "SEARCH EDGE " << edgenr +1 << endl;
// if(!is_edge_moved[edgenr+1]) continue;
// build sorted list of edge
@ -1266,33 +1355,42 @@ struct GrowthVectorLimiter {
// return true;
// return false;
auto segs = topo.GetVertexSegments(pi);
// cout << "segs of " << pi << ", " << segs.Size() << endl;
auto first_edgenr = mesh[segs[0]].edgenr;
for(auto segi : segs)
if(mesh[segi].edgenr != first_edgenr)
if(mesh[segi].edgenr != first_edgenr) {
// cout << "found corner point " << pi << endl;
return true;
}
// cout << "no corner point " << pi << endl;
return false;
};
bool any_grows = false;
for(const auto& seg : segments)
for(const auto& seg : mesh.LineSegments())
{
if(seg.edgenr-1 == edgenr)
{
if(growthvectors[seg[0]].Length2() != 0 ||
growthvectors[seg[1]].Length2() != 0)
if(getGW(seg[0]).Length2() != 0 ||
getGW(seg[1]).Length2() != 0)
any_grows = true;
if(points.Size() == 0 && is_end_point(seg[0]))
if(points.Size() == 0 && (is_end_point(seg[0]) || is_end_point(seg[1])))
{
points.Append(seg[0]);
points.Append(seg[1]);
PointIndex seg0 = seg[0], seg1 = seg[1];
if(is_end_point(seg[1]))
Swap(seg0, seg1);
points.Append(seg0);
points.Append(seg1);
edge_len += (mesh[seg[1]] - mesh[seg[0]]).Length();
}
}
}
if(!any_grows)
if(!any_grows) {
cout << "skip edge " << edgenr+1 << endl;
continue;
}
if(!points.Size())
throw Exception("Could not find startpoint for edge " + ToString(edgenr));
@ -1328,24 +1426,26 @@ struct GrowthVectorLimiter {
throw Exception(string("Could not find connected list of line segments for edge ") + edgenr);
}
}
// cout << "Points " << points << endl;
if(growthvectors[points[0]].Length2() == 0 &&
growthvectors[points.Last()].Length2() == 0)
if(getGW(points[0]).Length2() == 0 &&
getGW(points.Last()).Length2() == 0)
continue;
// cout << "Points to average " << points << endl;
// tangential part of growth vectors
auto t1 = (mesh[points[1]]-mesh[points[0]]).Normalize();
auto gt1 = growthvectors[points[0]] * t1 * t1;
auto gt1 = getGW(points[0]) * t1 * t1;
auto t2 = (mesh[points.Last()]-mesh[points[points.Size()-2]]).Normalize();
auto gt2 = growthvectors[points.Last()] * t2 * t2;
auto gt2 = getGW(points.Last()) * t2 * t2;
if(!is_edge_moved[edgenr+1])
{
if(growthvectors[points[0]] * (mesh[points[1]] - mesh[points[0]]) < 0)
gt1 = 0.;
if(growthvectors[points.Last()] * (mesh[points[points.Size()-2]] - mesh[points.Last()]) < 0)
gt2 = 0.;
}
// if(!is_edge_moved[edgenr+1])
// {
// if(getGW(points[0]) * (mesh[points[1]] - mesh[points[0]]) < 0)
// gt1 = 0.;
// if(getGW(points.Last()) * (mesh[points[points.Size()-2]] - mesh[points.Last()]) < 0)
// gt2 = 0.;
// }
double len = 0.;
for(size_t i = 1; i < points.Size()-1; i++)
@ -1355,31 +1455,100 @@ struct GrowthVectorLimiter {
auto t = getEdgeTangent(pi, edgenr);
auto lam = len/edge_len;
auto interpol = (1-lam) * (gt1 * t) * t + lam * (gt2 * t) * t;
growthvectors[pi] += interpol;
if(pi==89) {
cout << "points " << points << endl;
cout << "INTERPOL" << len << ',' << t << ',' << lam << ',' << interpol << endl;
cout << gt1 << endl;
cout << gt2 << endl;
cout << getGW(pi) << endl;
}
getGW(pi) += interpol;
}
}
InterpolateSurfaceGrowthVectors();
InterpolateSurfaceGrowthVectors();
}
void BoundaryLayerTool :: InsertNewElements( FlatArray<Array<pair<SegmentIndex, int>>, SegmentIndex> segmap, const BitArray & in_surface_direction )
{
static Timer timer("BoundaryLayerTool::InsertNewElements"); RegionTimer rt(timer);
Array<Array<PointIndex>, PointIndex> mapto(np);
// insert new points
for (PointIndex pi = 1; pi <= np; pi++)
if (growthvectors[pi].Length2() != 0)
mapto.SetSize(0);
mapto.SetSize(np);
auto add_points = [&](PointIndex pi, Vec<3> & growth_vector, Array<PointIndex> & new_points)
{
Point<3> p = mesh[pi];
for(auto i : Range(params.heights))
{
Point<3> p = mesh[pi];
for(auto i : Range(params.heights))
{
p += params.heights[i] * growthvectors[pi];
mapto[pi].Append(mesh.AddPoint(p));
}
// p += params.heights[i] * growth_vector;
new_points.Append(mesh.AddPoint(p));
growth_vector_map[new_points.Last()] = { &growth_vector, params.heights[i] };
}
};
// insert new points
for (PointIndex pi = 1; pi <= np; pi++) {
if (growthvectors[pi].Length2() != 0) {
if(special_boundary_points.count(pi))
{
for(auto & group : special_boundary_points[pi].growth_groups) {
add_points(pi, group.growth_vector, group.new_points);
cout << "new points " << pi << endl << group.new_points << endl;
}
}
else
add_points(pi, growthvectors[pi], mapto[pi]);
}
}
// get point from mapto (or the group if point is mapped to multiple new points)
// layer = -1 means last point (top of boundary layer)
auto newPoint = [&](PointIndex pi, int layer = -1, int group = 0) {
if(layer == -1) layer = params.heights.Size()-1;
if(special_boundary_points.count(pi))
return special_boundary_points[pi].growth_groups[group].new_points[layer];
else
return mapto[pi][layer];
};
auto hasMoved = [&](PointIndex pi) {
return mapto[pi].Size() > 0 || special_boundary_points.count(pi);
};
auto numGroups = [&](PointIndex pi) -> size_t {
if(special_boundary_points.count(pi))
return special_boundary_points[pi].growth_groups.Size();
else
return 1;
};
auto getGroups = [&] (PointIndex pi, int face_index) -> Array<int> {
auto n = numGroups(pi);
Array<int> groups;
if(n == 1) {
groups.Append(0);
return groups;
}
const auto & all_groups = special_boundary_points[pi].growth_groups;
for(auto i : Range(n))
if(all_groups[i].faces.Contains(face_index))
groups.Append(i);
// cout << "groups " << pi << ", " << face_index << endl << groups;
return groups;
};
// add 2d quads on required surfaces
map<pair<PointIndex, PointIndex>, int> seg2edge;
map<int, int> edge_map;
int edge_nr = max_edge_nr;
auto getEdgeNr = [&] (int ei) {
if(edge_map.count(ei) == 0)
edge_map[ei] = ++edge_nr;
return edge_map[ei];
};
if(params.grow_edges)
{
for(auto sei : moved_segs)
@ -1392,16 +1561,33 @@ struct GrowthVectorLimiter {
auto segj = segments[sej];
if(type == 0)
{
Segment s;
s[0] = mapto[segj[0]].Last();
s[1] = mapto[segj[1]].Last();
s[2] = PointIndex::INVALID;
auto pair = s[0] < s[1] ? make_pair(s[0], s[1]) : make_pair(s[1], s[0]);
if(seg2edge.find(pair) == seg2edge.end())
seg2edge[pair] = ++max_edge_nr;
s.edgenr = seg2edge[pair];
s.si = si_map[segj.si];
new_segments.Append(s);
auto addSegment = [&] (PointIndex p0, PointIndex p1, bool extra_edge_nr = false) {
Segment s;
s[0] = p0;
s[1] = p1;
s[2] = PointIndex::INVALID;
auto pair = s[0] < s[1] ? make_pair(s[0], s[1]) : make_pair(s[1], s[0]);
if(extra_edge_nr)
s.edgenr = ++edge_nr;
else
s.edgenr = getEdgeNr(segj.edgenr);
s.si = si_map[segj.si];
new_segments.Append(s);
return s;
};
auto p0=segj[0], p1=segj[1];
auto g0 = getGroups(p0, segj.si);
auto g1 = getGroups(p1, segj.si);
if(g0.Size() == 1 && g1.Size() == 1)
auto s = addSegment( newPoint(p0, -1, g0[0]), newPoint(p1, -1, g1[0]) );
else {
if(g0.Size() == 2)
addSegment( newPoint(p0, -1, g0[0]), newPoint(p0, -1, g0[1]) );
if(g1.Size() == 2)
addSegment( newPoint(p1, -1, g1[0]), newPoint(p1, -1, g1[1]) );
}
}
// here we need to grow the quad elements
else if(type == 1)
@ -1427,8 +1613,8 @@ struct GrowthVectorLimiter {
for(auto i : Range(params.heights))
{
Element2d sel(QUAD);
p3 = mapto[pp2][i];
p4 = mapto[pp1][i];
p3 = newPoint(pp2, i);
p4 = newPoint(pp1, i);
sel[0] = p1;
sel[1] = p2;
sel[2] = p3;
@ -1447,9 +1633,7 @@ struct GrowthVectorLimiter {
s1[1] = p3;
s1[2] = PointIndex::INVALID;
auto pair = make_pair(p2, p3);
if(seg2edge.find(pair) == seg2edge.end())
seg2edge[pair] = ++max_edge_nr;
s1.edgenr = seg2edge[pair];
s1.edgenr = getEdgeNr(segj.edgenr);
s1.si = segj.si;
new_segments.Append(s1);
Segment s2;
@ -1457,9 +1641,7 @@ struct GrowthVectorLimiter {
s2[1] = p1;
s2[2] = PointIndex::INVALID;
pair = make_pair(p1, p4);
if(seg2edge.find(pair) == seg2edge.end())
seg2edge[pair] = ++max_edge_nr;
s2.edgenr = seg2edge[pair];
s2.edgenr = getEdgeNr(segj.edgenr);
s2.si = segj.si;
new_segments.Append(s2);
p1 = p4;
@ -1470,9 +1652,7 @@ struct GrowthVectorLimiter {
s3[1] = p4;
s3[2] = PointIndex::INVALID;
auto pair = p3 < p4 ? make_pair(p3, p4) : make_pair(p4, p3);
if(seg2edge.find(pair) == seg2edge.end())
seg2edge[pair] = ++max_edge_nr;
s3.edgenr = seg2edge[pair];
s3.edgenr = getEdgeNr(segj.edgenr);
s3.si = segj.si;
new_segments.Append(s3);
}
@ -1492,6 +1672,31 @@ struct GrowthVectorLimiter {
{
Array<PointIndex> points(sel.PNums());
if(surfacefacs[sel.GetIndex()] > 0) Swap(points[0], points[2]);
Array<int> groups(points.Size());
for(auto i : Range(points)) {
auto n = numGroups(sel[i]);
auto igroup = 0;
if(n > 1) {
double distance = 1e99;
for(auto j : Range(n)) {
auto g = getGroups(sel[i], sel.GetIndex());
auto vcenter = Center(mesh[sel[0]], mesh[sel[1]], mesh[sel[2]]);
auto dist = (vcenter-(mesh[sel[i]]+special_boundary_points[sel[i]].growth_groups[j].growth_vector)).Length2();
// cout << "check dist " << dist << ", " << distance << ", " << sel << endl;
if(dist < distance) {
distance = dist;
igroup = j;
// cout << "set igroup " << igroup << endl;
}
}
// if(g.Size()>1 && vcenter * special_boundary_points[sel[i]].growth_groups[0].growth_vector < 0)
// igroup = 1;
cout<< "have " << n << " groups, choose " << igroup << endl;
cout << getGroups(sel[i], sel.GetIndex()) << endl;
}
groups[i] = getGroups(sel[i], sel.GetIndex())[igroup];
}
for(auto j : Range(params.heights))
{
auto eltype = points.Size() == 3 ? PRISM : HEX;
@ -1499,7 +1704,7 @@ struct GrowthVectorLimiter {
for(auto i : Range(points))
el[i] = points[i];
for(auto i : Range(points))
points[i] = mapto[sel.PNums()[i]][j];
points[i] = newPoint(sel.PNums()[i], j, groups[i]);
if(surfacefacs[sel.GetIndex()] > 0) Swap(points[0], points[2]);
for(auto i : Range(points))
el[sel.PNums().Size() + i] = points[i];
@ -1507,8 +1712,8 @@ struct GrowthVectorLimiter {
mesh.AddVolumeElement(el);
}
Element2d newel = sel;
for(auto& p : newel.PNums())
p = mapto[p].Last();
for(auto i: Range(points))
newel[i] = newPoint(sel[i], -1, groups[i]);
newel.SetIndex(si_map[sel.GetIndex()]);
mesh.AddSurfaceElement(newel);
}
@ -1516,12 +1721,11 @@ struct GrowthVectorLimiter {
{
bool has_moved = false;
for(auto p : sel.PNums())
if(mapto[p].Size())
has_moved = true;
has_moved |= hasMoved(p);
if(has_moved)
for(auto p : sel.PNums())
{
if(!mapto[p].Size())
if(hasMoved(p))
{
fixed_points.SetBit(p);
if(is_boundary_moved.Test(sel.GetIndex()))
@ -1532,8 +1736,8 @@ struct GrowthVectorLimiter {
if(is_boundary_moved.Test(sel.GetIndex()))
{
for(auto& p : mesh[si].PNums())
if(mapto[p].Size())
p = mapto[p].Last();
if(hasMoved(p))
p = newPoint(p);
}
}
@ -1542,10 +1746,51 @@ struct GrowthVectorLimiter {
auto& seg = segments[sei];
if(is_boundary_moved.Test(seg.si))
for(auto& p : seg.PNums())
if(mapto[p].Size())
p = mapto[p].Last();
if(hasMoved(p))
p = newPoint(p);
}
// fill holes in surface mesh at special boundary points (with >=4 adjacent boundary faces)
auto p2sel = mesh.CreatePoint2SurfaceElementTable();
for(auto & [pi, special_point] : special_boundary_points) {
if(special_point.growth_groups.Size() != 2)
throw Exception("special_point.growth_groups.Size() != 2");
for(auto igroup : Range(2)) {
auto & group = special_point.growth_groups[igroup];
std::set<int> faces;
for(auto face : group.faces)
faces.insert(si_map[face]);
auto pi_new = group.new_points.Last();
auto pi_new_other = special_point.growth_groups[1-igroup].new_points.Last();
for(auto sei : p2sel[pi_new])
faces.erase(mesh[sei].GetIndex());
for(auto face : faces)
for(auto seg : new_segments) {
if(//seg.si == face
(seg[0] == pi_new || seg[1] == pi_new)
&& (seg[0] != pi_new_other && seg[1] != pi_new_other)
) {
bool is_correct_face = false;
auto pi_other = seg[0] == pi_new ? seg[1] : seg[0];
for(auto sei : p2sel[pi_other]) {
if(mesh[sei].GetIndex() == face) {
is_correct_face = true;
break;
}
}
if(is_correct_face) {
Element2d sel;
sel[0] = seg[1];
sel[1] = seg[0];
sel[2] = pi_new_other;
sel.SetIndex(face);
mesh.AddSurfaceElement(sel);
}
}
}
}
}
for(ElementIndex ei = 0; ei < ne; ei++)
{
auto el = mesh[ei];
@ -1556,7 +1801,7 @@ struct GrowthVectorLimiter {
{
if(fixed_points.Test(p))
fixed.Append(p);
if(mapto[p].Size())
if(hasMoved(p))
moved.Append(p);
if(moveboundarypoint.Test(p))
moved_bnd = true;
@ -1577,8 +1822,8 @@ struct GrowthVectorLimiter {
if(do_move)
{
for(auto& p : mesh[ei].PNums())
if(mapto[p].Size())
p = mapto[p].Last();
if(hasMoved(p))
p = newPoint(p);
}
if(do_insert)
{
@ -1591,7 +1836,7 @@ struct GrowthVectorLimiter {
PointIndex p3 = moved[2];
auto v1 = mesh[p1];
auto n = Cross(mesh[p2]-v1, mesh[p3]-v1);
auto d = mesh[mapto[p1][0]] - v1;
auto d = mesh[newPoint(p1,0)] - v1;
if(n*d > 0)
Swap(p2,p3);
PointIndex p4 = p1;
@ -1601,7 +1846,7 @@ struct GrowthVectorLimiter {
{
Element nel(PRISM);
nel[0] = p4; nel[1] = p5; nel[2] = p6;
p4 = mapto[p1][i]; p5 = mapto[p2][i]; p6 = mapto[p3][i];
p4 = newPoint(p1, i); p5 = newPoint(p2, i); p6 = newPoint(p3, i);
nel[3] = p4; nel[4] = p5; nel[5] = p6;
nel.SetIndex(el.GetIndex());
mesh.AddVolumeElement(nel);
@ -1615,8 +1860,8 @@ struct GrowthVectorLimiter {
PointIndex p2 = moved[1];
for(auto i : Range(params.heights))
{
PointIndex p3 = mapto[moved[1]][i];
PointIndex p4 = mapto[moved[0]][i];
PointIndex p3 = newPoint(moved[1], i);
PointIndex p4 = newPoint(moved[0], i);
Element nel(PYRAMID);
nel[0] = p1;
nel[1] = p2;
@ -1638,7 +1883,7 @@ struct GrowthVectorLimiter {
for(auto i : Range(params.heights))
{
Element nel = el;
PointIndex p2 = mapto[moved[0]][i];
PointIndex p2 = newPoint(moved[0], i);
for(auto& p : nel.PNums())
{
if(p == moved[0])
@ -1661,8 +1906,8 @@ struct GrowthVectorLimiter {
PointIndex p2 = moved[1];
for(auto i : Range(params.heights))
{
PointIndex p3 = mapto[moved[1]][i];
PointIndex p4 = mapto[moved[0]][i];
PointIndex p3 = newPoint(moved[1], i);
PointIndex p4 = newPoint(moved[0], i);
Element nel(PYRAMID);
nel[0] = p1;
nel[1] = p2;
@ -1795,8 +2040,6 @@ struct GrowthVectorLimiter {
auto in_surface_direction = ProjectGrowthVectorsOnSurface();
InterpolateGrowthVectors();
auto fout = ofstream("growthvectors.txt");
for (auto pi : Range(mesh.Points()))
{
@ -1807,13 +2050,30 @@ struct GrowthVectorLimiter {
}
fout << endl;
if(params.limit_growth_vectors)
LimitGrowthVectorLengths();
FixVolumeElements();
InsertNewElements(segmap, in_surface_direction);
SetDomInOut();
AddSegments();
mesh.CalcSurfacesOfNode();
topo.SetBuildVertex2Element(true);
mesh.UpdateTopology();
// cout << "growthvectors before " << endl<< growthvectors << endl;
InterpolateGrowthVectors();
// cout << "growthvectors after " << endl << growthvectors << endl;
if(params.limit_growth_vectors)
LimitGrowthVectorLengths();
for (auto [pi, data] : growth_vector_map) {
auto [gw, height] = data;
mesh[pi] += height * (*gw);
}
mesh.GetTopology().ClearEdges();
mesh.SetNextMajorTimeStamp();
mesh.UpdateTopology();

View File

@ -1,6 +1,10 @@
#ifndef NETGEN_BOUNDARYLAYER_HPP
#define NETGEN_BOUNDARYLAYER_HPP
#include <core/array.hpp>
#include "../include/myadt.hpp"
#include "../include/gprim.hpp"
namespace netgen
{
@ -26,6 +30,24 @@ public:
Array<size_t> project_boundaries;
};
struct SpecialBoundaryPoint {
struct GrowthGroup {
Array<int> faces;
Vec<3> growth_vector;
Array<PointIndex> new_points;
GrowthGroup(FlatArray<int> faces_, FlatArray<Vec<3>> normals);
GrowthGroup(const GrowthGroup &) = default;
GrowthGroup() = default;
};
// std::map<int, Vec<3>> normals;
Array<GrowthGroup> growth_groups;
SpecialBoundaryPoint( const std::map<int, Vec<3>> & normals );
SpecialBoundaryPoint() = default;
};
DLL_HEADER void GenerateBoundaryLayer (Mesh & mesh,
const BoundaryLayerParameters & blp);
@ -37,7 +59,6 @@ class BoundaryLayerTool
BoundaryLayerTool(Mesh & mesh_, const BoundaryLayerParameters & params_);
void Perform();
protected:
Mesh & mesh;
MeshTopology & topo;
BoundaryLayerParameters params;
@ -54,11 +75,15 @@ class BoundaryLayerTool
bool have_single_segments;
Array<Segment> segments, new_segments;
Array<Array<PointIndex>, PointIndex> mapto;
Array<double> surfacefacs;
Array<int> si_map;
Array<double, PointIndex> limits;
std::map<PointIndex, SpecialBoundaryPoint> special_boundary_points;
std::map<PointIndex, std::tuple<Vec<3>*, double>> growth_vector_map;
// major steps called in Perform()
void CreateNewFaceDescriptors();
void CreateFaceDescriptorsSides();

View File

@ -359,8 +359,10 @@ namespace netgen
if (mesh.HasOpenQuads())
{
if(debugparam.write_mesh_on_error)
if(debugparam.write_mesh_on_error) {
md.mesh->Save("open_quads_"+ToString(md.domain)+".vol.gz");
GetOpenElements(*md.mesh, md.domain)->Save("open" + ToString(md.domain)+".vol");
}
PrintSysError ("mesh has still open quads");
throw NgException ("Stop meshing since too many attempts");
// return MESHING3_GIVEUP;

View File

@ -456,7 +456,7 @@ namespace netgen
const auto& seg = (*mesh)[si];
Point<3> c = Center((*mesh)[seg[0]], (*mesh)[seg[1]]);
glRasterPos3d (c[0], c[1], c[2]);
snprintf (buf, size(buf), "%d", int(si));
snprintf (buf, size(buf), "%d", int(seg.edgenr));
MyOpenGLText (buf);
}
}
@ -507,7 +507,10 @@ namespace netgen
(*mesh)[sel[2]],
(*mesh)[sel[3]]);
glRasterPos3d (c[0], c[1], c[2]);
snprintf (buf, size(buf), "%d", int(sei));
// auto & fd = mesh->GetFaceDescriptor(sel.GetIndex());
// string s = ToString(fd.DomainIn()) + "/" + ToString(fd.DomainOut());
// snprintf (buf, size(buf), "%s", s.c_str());
snprintf (buf, size(buf), "%d", int(sel.GetIndex()));
MyOpenGLText (buf);
}
}