mirror of
https://github.com/NGSolve/netgen.git
synced 2024-12-24 21:10:33 +05:00
fix GenerateBoundaryLayer for new OCC meshes with single segments (not one segment per adjacent face)
This commit is contained in:
parent
715f86b3b5
commit
7f5b288c51
@ -91,6 +91,94 @@ namespace netgen
|
|||||||
cout << "Quads: " << nq << endl;
|
cout << "Quads: " << nq << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// depending on the geometry type, the mesh contains segments multiple times (once for each face)
|
||||||
|
bool HaveSingleSegments( const Mesh & mesh )
|
||||||
|
{
|
||||||
|
auto& topo = mesh.GetTopology();
|
||||||
|
NgArray<SurfaceElementIndex> surf_els;
|
||||||
|
|
||||||
|
for(auto segi : Range(mesh.LineSegments()))
|
||||||
|
{
|
||||||
|
mesh.GetTopology().GetSegmentSurfaceElements(segi+1, surf_els);
|
||||||
|
if(surf_els.Size()<2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto seg = mesh[segi];
|
||||||
|
auto pi0 = min(seg[0], seg[1]);
|
||||||
|
auto pi1 = max(seg[0], seg[1]);
|
||||||
|
auto p0_segs = topo.GetVertexSegments(seg[0]);
|
||||||
|
|
||||||
|
for(auto segi_other : p0_segs)
|
||||||
|
{
|
||||||
|
if(segi_other == segi)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto seg_other = mesh[segi_other];
|
||||||
|
auto pi0_other = min(seg_other[0], seg_other[1]);
|
||||||
|
auto pi1_other = max(seg_other[0], seg_other[1]);
|
||||||
|
if( pi0_other == pi0 && pi1_other == pi1 )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// found segment with multiple adjacent surface elements but no other segments with same points -> have single segments
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// duplicates segments (and sets seg.si accordingly) to have a unified data structure for all geometry types
|
||||||
|
Array<Segment> BuildSegments( Mesh & mesh )
|
||||||
|
{
|
||||||
|
Array<Segment> segments;
|
||||||
|
auto& topo = mesh.GetTopology();
|
||||||
|
|
||||||
|
NgArray<SurfaceElementIndex> surf_els;
|
||||||
|
|
||||||
|
for(auto segi : Range(mesh.LineSegments()))
|
||||||
|
{
|
||||||
|
auto seg = mesh[segi];
|
||||||
|
mesh.GetTopology().GetSegmentSurfaceElements(segi+1, surf_els);
|
||||||
|
for(auto seli : surf_els)
|
||||||
|
{
|
||||||
|
const auto & sel = mesh[seli];
|
||||||
|
seg.si = sel.GetIndex();
|
||||||
|
|
||||||
|
auto np = sel.GetNP();
|
||||||
|
for(auto i : Range(np))
|
||||||
|
{
|
||||||
|
if(sel[i] == seg[0])
|
||||||
|
{
|
||||||
|
if(sel[(i+1)%np] != seg[1])
|
||||||
|
swap(seg[0], seg[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
seg.edgenr = topo.GetEdge(segi)+1;
|
||||||
|
segments.Append(seg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MergeAndAddSegments( Mesh & mesh, FlatArray<Segment> new_segments)
|
||||||
|
{
|
||||||
|
INDEX_2_HASHTABLE<bool> already_added( 2*new_segments.Size() );
|
||||||
|
|
||||||
|
for(auto & seg : new_segments)
|
||||||
|
{
|
||||||
|
INDEX_2 i2 (seg[0], seg[1]);
|
||||||
|
i2.Sort();
|
||||||
|
|
||||||
|
if(!already_added.Used(i2))
|
||||||
|
{
|
||||||
|
mesh.AddSegment(seg);
|
||||||
|
already_added.Set(i2, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GenerateBoundaryLayer(Mesh& mesh, const BoundaryLayerParameters& blp)
|
void GenerateBoundaryLayer(Mesh& mesh, const BoundaryLayerParameters& blp)
|
||||||
{
|
{
|
||||||
static Timer timer("Create Boundarylayers");
|
static Timer timer("Create Boundarylayers");
|
||||||
@ -109,12 +197,20 @@ namespace netgen
|
|||||||
domains.Invert();
|
domains.Invert();
|
||||||
|
|
||||||
mesh.UpdateTopology();
|
mesh.UpdateTopology();
|
||||||
|
|
||||||
|
bool have_single_segments = HaveSingleSegments(mesh);
|
||||||
|
Array<Segment> segments;
|
||||||
|
if(have_single_segments)
|
||||||
|
segments = BuildSegments(mesh);
|
||||||
|
else
|
||||||
|
segments = mesh.LineSegments();
|
||||||
|
|
||||||
auto& meshtopo = mesh.GetTopology();
|
auto& meshtopo = mesh.GetTopology();
|
||||||
|
|
||||||
int np = mesh.GetNP();
|
int np = mesh.GetNP();
|
||||||
int ne = mesh.GetNE();
|
int ne = mesh.GetNE();
|
||||||
int nse = mesh.GetNSE();
|
int nse = mesh.GetNSE();
|
||||||
int nseg = mesh.GetNSeg();
|
int nseg = segments.Size();
|
||||||
|
|
||||||
Array<Array<PointIndex>, PointIndex> mapto(np);
|
Array<Array<PointIndex>, PointIndex> mapto(np);
|
||||||
|
|
||||||
@ -178,7 +274,7 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bit array to keep track of segments already processed
|
// Bit array to keep track of segments already processed
|
||||||
BitArray segs_done(nseg);
|
BitArray segs_done(nseg+1);
|
||||||
segs_done.Clear();
|
segs_done.Clear();
|
||||||
|
|
||||||
// map for all segments with same points
|
// map for all segments with same points
|
||||||
@ -188,10 +284,11 @@ namespace netgen
|
|||||||
// 1 == adjacent surface doesn't grow layer, but layer ends on it
|
// 1 == adjacent surface doesn't grow layer, but layer ends on it
|
||||||
// 2 == adjacent surface is interior surface that ends on layer
|
// 2 == adjacent surface is interior surface that ends on layer
|
||||||
// 3 == adjacent surface is exterior surface that ends on layer (not allowed yet)
|
// 3 == adjacent surface is exterior surface that ends on layer (not allowed yet)
|
||||||
Array<Array<pair<SegmentIndex, int>>, SegmentIndex> segmap(mesh.GetNSeg());
|
Array<Array<pair<SegmentIndex, int>>, SegmentIndex> segmap(segments.Size());
|
||||||
|
|
||||||
// moved segments
|
// moved segments
|
||||||
Array<SegmentIndex> moved_segs;
|
Array<SegmentIndex> moved_segs;
|
||||||
|
Array<Segment> new_segments;
|
||||||
|
|
||||||
// boundaries to project endings to
|
// boundaries to project endings to
|
||||||
BitArray project_boundaries(fd_old+1);
|
BitArray project_boundaries(fd_old+1);
|
||||||
@ -199,30 +296,18 @@ namespace netgen
|
|||||||
project_boundaries.Clear();
|
project_boundaries.Clear();
|
||||||
move_boundaries.Clear();
|
move_boundaries.Clear();
|
||||||
|
|
||||||
Array<SurfaceElementIndex, SegmentIndex> seg2surfel(mesh.GetNSeg());
|
for(auto si : Range(segments))
|
||||||
for(auto si : Range(mesh.SurfaceElements()))
|
|
||||||
{
|
|
||||||
NgArray<int> surfeledges;
|
|
||||||
meshtopo.GetSurfaceElementEdges(si+1, surfeledges);
|
|
||||||
for(auto edgenr : surfeledges)
|
|
||||||
for(auto sei : Range(mesh.LineSegments()))
|
|
||||||
if(meshtopo.GetEdge(sei)+1 == edgenr &&
|
|
||||||
mesh[sei].si == mesh[si].GetIndex())
|
|
||||||
seg2surfel[sei] = si;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto si : Range(mesh.LineSegments()))
|
|
||||||
{
|
{
|
||||||
if(segs_done[si]) continue;
|
if(segs_done[si]) continue;
|
||||||
const auto& segi = mesh[si];
|
const auto& segi = segments[si];
|
||||||
if(si_map[segi.si] == -1) continue;
|
if(si_map[segi.si] == -1) continue;
|
||||||
segs_done.SetBit(si);
|
segs_done.SetBit(si);
|
||||||
segmap[si].Append(make_pair(si, 0));
|
segmap[si].Append(make_pair(si, 0));
|
||||||
moved_segs.Append(si);
|
moved_segs.Append(si);
|
||||||
for(auto sj : Range(mesh.LineSegments()))
|
for(auto sj : Range(segments))
|
||||||
{
|
{
|
||||||
if(segs_done.Test(sj)) continue;
|
if(segs_done.Test(sj)) continue;
|
||||||
const auto& segj = mesh[sj];
|
const auto& segj = segments[sj];
|
||||||
if((segi[0] == segj[0] && segi[1] == segj[1]) ||
|
if((segi[0] == segj[0] && segi[1] == segj[1]) ||
|
||||||
(segi[0] == segj[1] && segi[1] == segj[0]))
|
(segi[0] == segj[1] && segi[1] == segj[0]))
|
||||||
{
|
{
|
||||||
@ -291,10 +376,10 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(const auto& seg : mesh.LineSegments())
|
for(const auto& seg : segments)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for(const auto& seg2 : mesh.LineSegments())
|
for(const auto& seg2 : segments)
|
||||||
if(((seg[0] == seg2[0] && seg[1] == seg2[1]) || (seg[0] == seg2[1] && seg[1] == seg2[0])) && blp.surfid.Contains(seg2.si))
|
if(((seg[0] == seg2[0] && seg[1] == seg2[1]) || (seg[0] == seg2[1] && seg[1] == seg2[0])) && blp.surfid.Contains(seg2.si))
|
||||||
count++;
|
count++;
|
||||||
if(count == 1)
|
if(count == 1)
|
||||||
@ -325,10 +410,10 @@ namespace netgen
|
|||||||
{
|
{
|
||||||
// copy here since we will add segments and this would
|
// copy here since we will add segments and this would
|
||||||
// invalidate a reference!
|
// invalidate a reference!
|
||||||
auto segi = mesh[sei];
|
auto segi = segments[sei];
|
||||||
for(auto [sej, type] : segmap[sei])
|
for(auto [sej, type] : segmap[sei])
|
||||||
{
|
{
|
||||||
auto segj = mesh[sej];
|
auto segj = segments[sej];
|
||||||
if(type == 0)
|
if(type == 0)
|
||||||
{
|
{
|
||||||
Segment s;
|
Segment s;
|
||||||
@ -340,7 +425,7 @@ namespace netgen
|
|||||||
seg2edge[pair] = ++max_edge_nr;
|
seg2edge[pair] = ++max_edge_nr;
|
||||||
s.edgenr = seg2edge[pair];
|
s.edgenr = seg2edge[pair];
|
||||||
s.si = si_map[segj.si];
|
s.si = si_map[segj.si];
|
||||||
mesh.AddSegment(s);
|
new_segments.Append(s);
|
||||||
}
|
}
|
||||||
// here we need to grow the quad elements
|
// here we need to grow the quad elements
|
||||||
else if(type == 1)
|
else if(type == 1)
|
||||||
@ -361,7 +446,7 @@ namespace netgen
|
|||||||
s0[2] = PointIndex::INVALID;
|
s0[2] = PointIndex::INVALID;
|
||||||
s0.edgenr = segj.edgenr;
|
s0.edgenr = segj.edgenr;
|
||||||
s0.si = segj.si;
|
s0.si = segj.si;
|
||||||
mesh.AddSegment(s0);
|
new_segments.Append(s0);
|
||||||
|
|
||||||
for(auto i : Range(blp.heights))
|
for(auto i : Range(blp.heights))
|
||||||
{
|
{
|
||||||
@ -372,6 +457,11 @@ namespace netgen
|
|||||||
sel[1] = p2;
|
sel[1] = p2;
|
||||||
sel[2] = p3;
|
sel[2] = p3;
|
||||||
sel[3] = p4;
|
sel[3] = p4;
|
||||||
|
for(auto i : Range(4))
|
||||||
|
{
|
||||||
|
sel.GeomInfo()[i].u = 0.0;
|
||||||
|
sel.GeomInfo()[i].v = 0.0;
|
||||||
|
}
|
||||||
sel.SetIndex(segj.si);
|
sel.SetIndex(segj.si);
|
||||||
mesh.AddSurfaceElement(sel);
|
mesh.AddSurfaceElement(sel);
|
||||||
|
|
||||||
@ -385,7 +475,7 @@ namespace netgen
|
|||||||
seg2edge[pair] = ++max_edge_nr;
|
seg2edge[pair] = ++max_edge_nr;
|
||||||
s1.edgenr = seg2edge[pair];
|
s1.edgenr = seg2edge[pair];
|
||||||
s1.si = segj.si;
|
s1.si = segj.si;
|
||||||
mesh.AddSegment(s1);
|
new_segments.Append(s1);
|
||||||
Segment s2;
|
Segment s2;
|
||||||
s2[0] = p4;
|
s2[0] = p4;
|
||||||
s2[1] = p1;
|
s2[1] = p1;
|
||||||
@ -395,7 +485,7 @@ namespace netgen
|
|||||||
seg2edge[pair] = ++max_edge_nr;
|
seg2edge[pair] = ++max_edge_nr;
|
||||||
s2.edgenr = seg2edge[pair];
|
s2.edgenr = seg2edge[pair];
|
||||||
s2.si = segj.si;
|
s2.si = segj.si;
|
||||||
mesh.AddSegment(s2);
|
new_segments.Append(s2);
|
||||||
p1 = p4;
|
p1 = p4;
|
||||||
p2 = p3;
|
p2 = p3;
|
||||||
}
|
}
|
||||||
@ -408,7 +498,7 @@ namespace netgen
|
|||||||
seg2edge[pair] = ++max_edge_nr;
|
seg2edge[pair] = ++max_edge_nr;
|
||||||
s3.edgenr = seg2edge[pair];
|
s3.edgenr = seg2edge[pair];
|
||||||
s3.si = segj.si;
|
s3.si = segj.si;
|
||||||
mesh.AddSegment(s3);
|
new_segments.Append(s3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -473,7 +563,7 @@ namespace netgen
|
|||||||
|
|
||||||
for(SegmentIndex sei = 0; sei < nseg; sei++)
|
for(SegmentIndex sei = 0; sei < nseg; sei++)
|
||||||
{
|
{
|
||||||
auto& seg = mesh[sei];
|
auto& seg = segments[sei];
|
||||||
if(move_boundaries.Test(seg.si))
|
if(move_boundaries.Test(seg.si))
|
||||||
for(auto& p : seg.PNums())
|
for(auto& p : seg.PNums())
|
||||||
if(mapto[p].Size())
|
if(mapto[p].Size())
|
||||||
@ -627,6 +717,13 @@ namespace netgen
|
|||||||
else
|
else
|
||||||
mesh.GetFaceDescriptor(i).SetDomainIn(new_mat_nr);
|
mesh.GetFaceDescriptor(i).SetDomainIn(new_mat_nr);
|
||||||
}
|
}
|
||||||
|
if(have_single_segments)
|
||||||
|
MergeAndAddSegments(mesh, new_segments);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(auto & seg : new_segments)
|
||||||
|
mesh.AddSegment(seg);
|
||||||
|
}
|
||||||
mesh.GetTopology().ClearEdges();
|
mesh.GetTopology().ClearEdges();
|
||||||
mesh.UpdateTopology();
|
mesh.UpdateTopology();
|
||||||
}
|
}
|
||||||
@ -1279,6 +1376,11 @@ namespace netgen
|
|||||||
// Swap(newel[2], newel[3]);
|
// Swap(newel[2], newel[3]);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
for(auto i : Range(4))
|
||||||
|
{
|
||||||
|
newel.GeomInfo()[i].u = 0.0;
|
||||||
|
newel.GeomInfo()[i].v = 0.0;
|
||||||
|
}
|
||||||
mesh.AddSurfaceElement(newel);
|
mesh.AddSurfaceElement(newel);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,21 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from netgen.csg import *
|
from netgen.csg import *
|
||||||
|
|
||||||
|
geometries=[unit_cube]
|
||||||
|
|
||||||
|
try:
|
||||||
|
import netgen.occ as occ
|
||||||
|
box = occ.Box( (0,0,0), (1,1,1) )
|
||||||
|
box.faces.Min(occ.Y).name = "back"
|
||||||
|
box.faces.Max(occ.Y).name = "front"
|
||||||
|
box.faces.Min(occ.X).name = "left"
|
||||||
|
box.faces.Max(occ.X).name = "right"
|
||||||
|
box.faces.Min(occ.Z).name = "bottom"
|
||||||
|
box.faces.Max(occ.Z).name = "top"
|
||||||
|
geometries.append(occ.OCCGeometry(box))
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
def GetNSurfaceElements(mesh, boundaries, adjacent_domain=None):
|
def GetNSurfaceElements(mesh, boundaries, adjacent_domain=None):
|
||||||
nse_in_layer = 0
|
nse_in_layer = 0
|
||||||
for el in mesh.Elements2D():
|
for el in mesh.Elements2D():
|
||||||
@ -14,8 +29,9 @@ def GetNSurfaceElements(mesh, boundaries, adjacent_domain=None):
|
|||||||
return nse_in_layer
|
return nse_in_layer
|
||||||
|
|
||||||
@pytest.mark.parametrize("outside", [True, False])
|
@pytest.mark.parametrize("outside", [True, False])
|
||||||
def test_boundarylayer(outside, capfd):
|
@pytest.mark.parametrize("geo", geometries)
|
||||||
mesh = unit_cube.GenerateMesh(maxh=0.3)
|
def test_boundarylayer(outside, geo, capfd):
|
||||||
|
mesh = geo.GenerateMesh(maxh=0.3)
|
||||||
ne_before = mesh.ne
|
ne_before = mesh.ne
|
||||||
layer_surfacenames = ["right", "top", "left", "back", "bottom"]
|
layer_surfacenames = ["right", "top", "left", "back", "bottom"]
|
||||||
mesh.BoundaryLayer("|".join(layer_surfacenames), [0.01, 0.01], "layer", outside=outside)
|
mesh.BoundaryLayer("|".join(layer_surfacenames), [0.01, 0.01], "layer", outside=outside)
|
||||||
|
Loading…
Reference in New Issue
Block a user