formatting

This commit is contained in:
Matthias Hochsteger 2024-10-08 16:20:53 +02:00
parent e5af7bca42
commit 82965f63b0
5 changed files with 1709 additions and 1437 deletions

64
.clang-format Normal file
View File

@ -0,0 +1,64 @@
Language: Cpp
BasedOnStyle: LLVM
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: InlineOnly
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
IndentBraces: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakInheritanceList: AfterColon
ColumnLimit: 0
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: true
EmptyLineBeforeAccessModifier: Never
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 2
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
PointerAlignment: Left
ReflowComments: true
SortIncludes: false
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterFunctionDefinitionName: true
AfterFunctionDeclarationName: true
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInSquareBrackets: false
Standard: Latest
TabWidth: 2
UseTab: Never

View File

@ -8,22 +8,28 @@
#include "global.hpp" #include "global.hpp"
#include "meshfunc.hpp" #include "meshfunc.hpp"
namespace netgen { namespace netgen
{
struct SpecialPointException : public Exception { struct SpecialPointException : public Exception
SpecialPointException() : Exception("") {} {
SpecialPointException()
: Exception("") {}
}; };
std::tuple<int, int> FindCloseVectors (FlatArray<Vec<3>> ns, std::tuple<int, int> FindCloseVectors (FlatArray<Vec<3>> ns,
bool find_max = true) { bool find_max = true)
{
int maxpos1; int maxpos1;
int maxpos2; int maxpos2;
double val = find_max ? -1e99 : 1e99; double val = find_max ? -1e99 : 1e99;
for (auto i : Range(ns)) for (auto i : Range(ns))
for (auto j : Range(i + 1, ns.Size())) { for (auto j : Range(i + 1, ns.Size()))
{
double ip = ns[i] * ns[j]; double ip = ns[i] * ns[j];
if ((find_max && (ip > val)) || (!find_max && (ip < val))) { if ((find_max && (ip > val)) || (!find_max && (ip < val)))
{
val = ip; val = ip;
maxpos1 = i; maxpos1 = i;
maxpos2 = j; maxpos2 = j;
@ -32,12 +38,14 @@ std::tuple<int, int> FindCloseVectors(FlatArray<Vec<3>> ns,
return {maxpos1, maxpos2}; return {maxpos1, maxpos2};
} }
Vec<3> CalcGrowthVector(FlatArray<Vec<3>> ns) { Vec<3> CalcGrowthVector (FlatArray<Vec<3>> ns)
{
if (ns.Size() == 0) if (ns.Size() == 0)
return {0, 0, 0}; return {0, 0, 0};
if (ns.Size() == 1) if (ns.Size() == 1)
return ns[0]; return ns[0];
if (ns.Size() == 2) { if (ns.Size() == 2)
{
auto gw = ns[0]; auto gw = ns[0];
auto n = ns[1]; auto n = ns[1];
auto npn = gw * n; auto npn = gw * n;
@ -48,13 +56,15 @@ Vec<3> CalcGrowthVector(FlatArray<Vec<3>> ns) {
gw += (nn - npn) / (nn - npn * npn / npnp) * (n - npn / npnp * gw); gw += (nn - npn) / (nn - npn * npn / npnp) * (n - npn / npnp * gw);
return gw; return gw;
} }
if (ns.Size() == 3) { if (ns.Size() == 3)
{
DenseMatrix mat(3, 3); DenseMatrix mat(3, 3);
for (auto i : Range(3)) for (auto i : Range(3))
for (auto j : Range(3)) for (auto j : Range(3))
mat(i, j) = ns[i][j]; mat(i, j) = ns[i][j];
if (fabs(mat.Det()) > 1e-6) { if (fabs(mat.Det()) > 1e-6)
{
DenseMatrix mat(3, 3); DenseMatrix mat(3, 3);
for (auto i : Range(3)) for (auto i : Range(3))
for (auto j : Range(3)) for (auto j : Range(3))
@ -88,17 +98,20 @@ Vec<3> CalcGrowthVector(FlatArray<Vec<3>> ns) {
} }
SpecialBoundaryPoint ::GrowthGroup ::GrowthGroup(FlatArray<int> faces_, SpecialBoundaryPoint ::GrowthGroup ::GrowthGroup(FlatArray<int> faces_,
FlatArray<Vec<3>> normals) { FlatArray<Vec<3>> normals)
{
faces = faces_; faces = faces_;
growth_vector = CalcGrowthVector(normals); growth_vector = CalcGrowthVector(normals);
} }
SpecialBoundaryPoint ::SpecialBoundaryPoint( SpecialBoundaryPoint ::SpecialBoundaryPoint(
const std::map<int, Vec<3>> &normals) { const std::map<int, Vec<3>>& normals)
{
// find opposing face normals // find opposing face normals
Array<Vec<3>> ns; Array<Vec<3>> ns;
Array<int> faces; Array<int> faces;
for (auto [face, normal] : normals) { for (auto [face, normal] : normals)
{
ns.Append(normal); ns.Append(normal);
faces.Append(face); faces.Append(face);
} }
@ -116,7 +129,8 @@ SpecialBoundaryPoint ::SpecialBoundaryPoint(
Array<Vec<3>> normals1, normals2; Array<Vec<3>> normals1, normals2;
for (auto [facei, normali] : normals) for (auto [facei, normali] : normals)
if (facei != minface1 && facei != minface2) { if (facei != minface1 && facei != minface2)
{
g1_faces.Append(facei); g1_faces.Append(facei);
g2_faces.Append(facei); g2_faces.Append(facei);
} }
@ -128,11 +142,12 @@ SpecialBoundaryPoint ::SpecialBoundaryPoint(
growth_groups.Append(GrowthGroup(g2_faces, normals2)); growth_groups.Append(GrowthGroup(g2_faces, normals2));
} }
Vec<3> BoundaryLayerTool ::getEdgeTangent(PointIndex pi, int edgenr, Vec<3> BoundaryLayerTool ::getEdgeTangent(PointIndex pi, int edgenr, FlatArray<Segment*> segs)
FlatArray<Segment *> segs) { {
Vec<3> tangent = 0.0; Vec<3> tangent = 0.0;
ArrayMem<PointIndex, 2> pts; ArrayMem<PointIndex, 2> pts;
for (auto *p_seg : segs) { for (auto* p_seg : segs)
{
auto& seg = *p_seg; auto& seg = *p_seg;
if (seg.edgenr != edgenr) if (seg.edgenr != edgenr)
continue; continue;
@ -140,7 +155,8 @@ Vec<3> BoundaryLayerTool ::getEdgeTangent(PointIndex pi, int edgenr,
if (!pts.Contains(other)) if (!pts.Contains(other))
pts.Append(other); pts.Append(other);
} }
if (pts.Size() != 2) { if (pts.Size() != 2)
{
cout << "getEdgeTangent pi = " << pi << ", edgenr = " << edgenr << endl; cout << "getEdgeTangent pi = " << pi << ", edgenr = " << edgenr << endl;
cout << pts << endl; cout << pts << endl;
for (auto* p_seg : segs) for (auto* p_seg : segs)
@ -151,7 +167,8 @@ Vec<3> BoundaryLayerTool ::getEdgeTangent(PointIndex pi, int edgenr,
return tangent.Normalize(); return tangent.Normalize();
} }
void BoundaryLayerTool ::LimitGrowthVectorLengths() { void BoundaryLayerTool ::LimitGrowthVectorLengths()
{
static Timer tall("BoundaryLayerTool::LimitGrowthVectorLengths"); static Timer tall("BoundaryLayerTool::LimitGrowthVectorLengths");
RegionTimer rtall(tall); RegionTimer rtall(tall);
@ -161,11 +178,13 @@ void BoundaryLayerTool ::LimitGrowthVectorLengths() {
// depending on the geometry type, the mesh contains segments multiple times // depending on the geometry type, the mesh contains segments multiple times
// (once for each face) // (once for each face)
bool HaveSingleSegments(const Mesh &mesh) { bool HaveSingleSegments (const Mesh& mesh)
{
auto& topo = mesh.GetTopology(); auto& topo = mesh.GetTopology();
NgArray<SurfaceElementIndex> surf_els; NgArray<SurfaceElementIndex> surf_els;
for (auto segi : Range(mesh.LineSegments())) { for (auto segi : Range(mesh.LineSegments()))
{
mesh.GetTopology().GetSegmentSurfaceElements(segi + 1, surf_els); mesh.GetTopology().GetSegmentSurfaceElements(segi + 1, surf_els);
if (surf_els.Size() < 2) if (surf_els.Size() < 2)
continue; continue;
@ -175,7 +194,8 @@ bool HaveSingleSegments(const Mesh &mesh) {
auto pi1 = max(seg[0], seg[1]); auto pi1 = max(seg[0], seg[1]);
auto p0_segs = topo.GetVertexSegments(seg[0]); auto p0_segs = topo.GetVertexSegments(seg[0]);
for (auto segi_other : p0_segs) { for (auto segi_other : p0_segs)
{
if (segi_other == segi) if (segi_other == segi)
continue; continue;
@ -196,22 +216,27 @@ bool HaveSingleSegments(const Mesh &mesh) {
// duplicates segments (and sets seg.si accordingly) to have a unified data // duplicates segments (and sets seg.si accordingly) to have a unified data
// structure for all geometry types // structure for all geometry types
Array<Segment> BuildSegments(Mesh &mesh) { Array<Segment> BuildSegments (Mesh& mesh)
{
Array<Segment> segments; Array<Segment> segments;
// auto& topo = mesh.GetTopology(); // auto& topo = mesh.GetTopology();
NgArray<SurfaceElementIndex> surf_els; NgArray<SurfaceElementIndex> surf_els;
for (auto segi : Range(mesh.LineSegments())) { for (auto segi : Range(mesh.LineSegments()))
{
auto seg = mesh[segi]; auto seg = mesh[segi];
mesh.GetTopology().GetSegmentSurfaceElements(segi + 1, surf_els); mesh.GetTopology().GetSegmentSurfaceElements(segi + 1, surf_els);
for (auto seli : surf_els) { for (auto seli : surf_els)
{
const auto& sel = mesh[seli]; const auto& sel = mesh[seli];
seg.si = sel.GetIndex(); seg.si = sel.GetIndex();
auto np = sel.GetNP(); auto np = sel.GetNP();
for (auto i : Range(np)) { for (auto i : Range(np))
if (sel[i] == seg[0]) { {
if (sel[i] == seg[0])
{
if (sel[(i + 1) % np] != seg[1]) if (sel[(i + 1) % np] != seg[1])
swap(seg[0], seg[1]); swap(seg[0], seg[1]);
break; break;
@ -224,17 +249,17 @@ Array<Segment> BuildSegments(Mesh &mesh) {
return segments; return segments;
} }
void MergeAndAddSegments(Mesh &mesh, FlatArray<Segment> segments, void MergeAndAddSegments (Mesh& mesh, FlatArray<Segment> segments, FlatArray<Segment> new_segments)
FlatArray<Segment> new_segments) { {
INDEX_2_HASHTABLE<bool> already_added(segments.Size() + INDEX_2_HASHTABLE<bool> already_added(segments.Size() + 2 * new_segments.Size());
2 * new_segments.Size());
mesh.LineSegments().SetSize0(); mesh.LineSegments().SetSize0();
auto addSegment = [&] (const auto& seg) { auto addSegment = [&] (const auto& seg) {
INDEX_2 i2(seg[0], seg[1]); INDEX_2 i2(seg[0], seg[1]);
i2.Sort(); i2.Sort();
if (!already_added.Used(i2)) { if (!already_added.Used(i2))
{
mesh.AddSegment(seg); mesh.AddSegment(seg);
already_added.Set(i2, true); already_added.Set(i2, true);
} }
@ -249,7 +274,8 @@ void MergeAndAddSegments(Mesh &mesh, FlatArray<Segment> segments,
BoundaryLayerTool::BoundaryLayerTool(Mesh& mesh_, BoundaryLayerTool::BoundaryLayerTool(Mesh& mesh_,
const BoundaryLayerParameters& params_) const BoundaryLayerParameters& params_)
: mesh(mesh_), topo(mesh_.GetTopology()), params(params_) { : mesh(mesh_), topo(mesh_.GetTopology()), params(params_)
{
static Timer timer("BoundaryLayerTool::ctor"); static Timer timer("BoundaryLayerTool::ctor");
RegionTimer regt(timer); RegionTimer regt(timer);
ProcessParameters(); ProcessParameters();
@ -281,23 +307,27 @@ BoundaryLayerTool::BoundaryLayerTool(Mesh &mesh_,
si_map[i] = i; si_map[i] = i;
} }
void BoundaryLayerTool ::CreateNewFaceDescriptors() { void BoundaryLayerTool ::CreateNewFaceDescriptors()
{
surfacefacs.SetSize(nfd_old + 1); surfacefacs.SetSize(nfd_old + 1);
surfacefacs = 0.0; surfacefacs = 0.0;
// create new FaceDescriptors // create new FaceDescriptors
for (auto i : Range(1, nfd_old + 1)) { for (auto i : Range(1, nfd_old + 1))
{
const auto& fd = mesh.GetFaceDescriptor(i); const auto& fd = mesh.GetFaceDescriptor(i);
string name = fd.GetBCName(); string name = fd.GetBCName();
if (par_surfid.Contains(i)) { if (par_surfid.Contains(i))
{
if (auto isIn = domains.Test(fd.DomainIn()); if (auto isIn = domains.Test(fd.DomainIn());
isIn != domains.Test(fd.DomainOut())) { isIn != domains.Test(fd.DomainOut()))
{
int new_si = mesh.GetNFD() + 1; int new_si = mesh.GetNFD() + 1;
surfacefacs[i] = isIn ? 1. : -1.; surfacefacs[i] = isIn ? 1. : -1.;
moved_surfaces.SetBit(i); moved_surfaces.SetBit(i);
if (!insert_only_volume_elements) { if (!insert_only_volume_elements)
{
// -1 surf nr is so that curving does not do anything // -1 surf nr is so that curving does not do anything
FaceDescriptor new_fd(-1, isIn ? new_mat_nrs[i] : fd.DomainIn(), FaceDescriptor new_fd(-1, isIn ? new_mat_nrs[i] : fd.DomainIn(), isIn ? fd.DomainOut() : new_mat_nrs[i], -1);
isIn ? fd.DomainOut() : new_mat_nrs[i], -1);
new_fd.SetBCProperty(new_si); new_fd.SetBCProperty(new_si);
new_fd.SetSurfColour(fd.SurfColour()); new_fd.SetSurfColour(fd.SurfColour());
mesh.AddFaceDescriptor(new_fd); mesh.AddFaceDescriptor(new_fd);
@ -316,22 +346,24 @@ void BoundaryLayerTool ::CreateNewFaceDescriptors() {
for (auto si : par_surfid) for (auto si : par_surfid)
if (surfacefacs[si] == 0.0) if (surfacefacs[si] == 0.0)
throw Exception("Surface " + to_string(si) + throw Exception("Surface " + to_string(si) + " is not a boundary of the domain to be grown into!");
" is not a boundary of the domain to be grown into!");
} }
void BoundaryLayerTool ::CreateFaceDescriptorsSides() { void BoundaryLayerTool ::CreateFaceDescriptorsSides()
{
if (insert_only_volume_elements) if (insert_only_volume_elements)
return; return;
BitArray face_done(mesh.GetNFD() + 1); BitArray face_done(mesh.GetNFD() + 1);
face_done.Clear(); face_done.Clear();
for (const auto &sel : mesh.SurfaceElements()) { for (const auto& sel : mesh.SurfaceElements())
{
auto facei = sel.GetIndex(); auto facei = sel.GetIndex();
if (face_done.Test(facei)) if (face_done.Test(facei))
continue; continue;
bool point_moved = false; bool point_moved = false;
// bool point_fixed = false; // bool point_fixed = false;
for (auto pi : sel.PNums()) { for (auto pi : sel.PNums())
{
if (growthvectors[pi].Length() > 0) if (growthvectors[pi].Length() > 0)
point_moved = true; point_moved = true;
/* /*
@ -339,7 +371,8 @@ void BoundaryLayerTool ::CreateFaceDescriptorsSides() {
point_fixed = true; point_fixed = true;
*/ */
} }
if (point_moved && !moved_surfaces.Test(facei)) { if (point_moved && !moved_surfaces.Test(facei))
{
int new_si = mesh.GetNFD() + 1; int new_si = mesh.GetNFD() + 1;
const auto& fd = mesh.GetFaceDescriptor(facei); const auto& fd = mesh.GetFaceDescriptor(facei);
// auto isIn = domains.Test(fd.DomainIn()); // auto isIn = domains.Test(fd.DomainIn());
@ -356,11 +389,13 @@ void BoundaryLayerTool ::CreateFaceDescriptorsSides() {
} }
} }
void BoundaryLayerTool ::CalculateGrowthVectors() { void BoundaryLayerTool ::CalculateGrowthVectors()
{
growthvectors.SetSize(np); growthvectors.SetSize(np);
growthvectors = 0.; growthvectors = 0.;
for (auto pi : mesh.Points().Range()) { for (auto pi : mesh.Points().Range())
{
const auto& p = mesh[pi]; const auto& p = mesh[pi];
if (p.Type() == INNERPOINT) if (p.Type() == INNERPOINT)
continue; continue;
@ -369,7 +404,8 @@ void BoundaryLayerTool ::CalculateGrowthVectors() {
// calculate one normal vector per face (average with angles as weights for // calculate one normal vector per face (average with angles as weights for
// multiple surface elements within a face) // multiple surface elements within a face)
for (auto sei : p2sel[pi]) { for (auto sei : p2sel[pi])
{
const auto& sel = mesh[sei]; const auto& sel = mesh[sei];
auto facei = sel.GetIndex(); auto facei = sel.GetIndex();
if (!par_surfid.Contains(facei)) if (!par_surfid.Contains(facei))
@ -391,13 +427,17 @@ void BoundaryLayerTool ::CalculateGrowthVectors() {
// combine normal vectors for each face to keep uniform distances // combine normal vectors for each face to keep uniform distances
ArrayMem<Vec<3>, 5> ns; ArrayMem<Vec<3>, 5> ns;
for (auto &[facei, n] : normals) { for (auto& [facei, n] : normals)
{
ns.Append(n); ns.Append(n);
} }
try { try
{
growthvectors[pi] = CalcGrowthVector(ns); growthvectors[pi] = CalcGrowthVector(ns);
} catch (const SpecialPointException &e) { }
catch (const SpecialPointException& e)
{
special_boundary_points.emplace(pi, normals); special_boundary_points.emplace(pi, normals);
growthvectors[pi] = growthvectors[pi] =
special_boundary_points[pi].growth_groups[0].growth_vector; special_boundary_points[pi].growth_groups[0].growth_vector;
@ -406,7 +446,8 @@ void BoundaryLayerTool ::CalculateGrowthVectors() {
} }
Array<Array<pair<SegmentIndex, int>>, SegmentIndex> Array<Array<pair<SegmentIndex, int>>, SegmentIndex>
BoundaryLayerTool ::BuildSegMap() { BoundaryLayerTool ::BuildSegMap()
{
// Bit array to keep track of segments already processed // Bit array to keep track of segments already processed
BitArray segs_done(nseg + 1); BitArray segs_done(nseg + 1);
segs_done.Clear(); segs_done.Clear();
@ -431,7 +472,8 @@ BoundaryLayerTool ::BuildSegMap() {
is_boundary_moved.SetSize(nfd_old + 1); is_boundary_moved.SetSize(nfd_old + 1);
is_boundary_moved.Clear(); is_boundary_moved.Clear();
for (auto si : Range(segments)) { for (auto si : Range(segments))
{
if (segs_done[si]) if (segs_done[si])
continue; continue;
const auto& segi = segments[si]; const auto& segi = segments[si];
@ -441,30 +483,36 @@ BoundaryLayerTool ::BuildSegMap() {
segmap[si].Append(make_pair(si, 0)); segmap[si].Append(make_pair(si, 0));
moved_segs.Append(si); moved_segs.Append(si);
is_edge_moved.SetBit(segi.edgenr); is_edge_moved.SetBit(segi.edgenr);
for (auto sj : Range(segments)) { for (auto sj : Range(segments))
{
if (segs_done.Test(sj)) if (segs_done.Test(sj))
continue; continue;
const auto& segj = segments[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])) { {
segs_done.SetBit(sj); segs_done.SetBit(sj);
int type; int type;
if (moved_surfaces.Test(segj.si)) { if (moved_surfaces.Test(segj.si))
{
type = 0; type = 0;
moved_segs.Append(sj); moved_segs.Append(sj);
} else if (const auto &fd = mesh.GetFaceDescriptor(segj.si); }
domains.Test(fd.DomainIn()) && else if (const auto& fd = mesh.GetFaceDescriptor(segj.si);
domains.Test(fd.DomainOut())) { domains.Test(fd.DomainIn()) && domains.Test(fd.DomainOut()))
{
type = 2; type = 2;
if (fd.DomainIn() == 0 || fd.DomainOut() == 0) if (fd.DomainIn() == 0 || fd.DomainOut() == 0)
is_boundary_projected.SetBit(segj.si); is_boundary_projected.SetBit(segj.si);
} else if (const auto &fd = mesh.GetFaceDescriptor(segj.si); }
!domains.Test(fd.DomainIn()) && else if (const auto& fd = mesh.GetFaceDescriptor(segj.si);
!domains.Test(fd.DomainOut())) { !domains.Test(fd.DomainIn()) && !domains.Test(fd.DomainOut()))
{
type = 3; type = 3;
// cout << "set is_moved boundary to type 3 for " << segj.si << endl; // cout << "set is_moved boundary to type 3 for " << segj.si << endl;
is_boundary_moved.SetBit(segj.si); is_boundary_moved.SetBit(segj.si);
} else { }
else
{
type = 1; type = 1;
// in case 1 we project the growthvector onto the surface // in case 1 we project the growthvector onto the surface
is_boundary_projected.SetBit(segj.si); is_boundary_projected.SetBit(segj.si);
@ -477,15 +525,19 @@ BoundaryLayerTool ::BuildSegMap() {
return segmap; return segmap;
} }
BitArray BoundaryLayerTool ::ProjectGrowthVectorsOnSurface() { BitArray BoundaryLayerTool ::ProjectGrowthVectorsOnSurface()
{
BitArray in_surface_direction(nfd_old + 1); BitArray in_surface_direction(nfd_old + 1);
in_surface_direction.Clear(); in_surface_direction.Clear();
// project growthvector on surface for inner angles // project growthvector on surface for inner angles
if (params.grow_edges) { if (params.grow_edges)
{
for (const auto& sel : mesh.SurfaceElements()) for (const auto& sel : mesh.SurfaceElements())
if (is_boundary_projected.Test(sel.GetIndex())) { if (is_boundary_projected.Test(sel.GetIndex()))
{
auto n = getNormal(sel); auto n = getNormal(sel);
for (auto i : Range(sel.PNums())) { for (auto i : Range(sel.PNums()))
{
auto pi = sel.PNums()[i]; auto pi = sel.PNums()[i];
if (growthvectors[pi].Length2() == 0.) if (growthvectors[pi].Length2() == 0.)
continue; continue;
@ -513,15 +565,17 @@ BitArray BoundaryLayerTool ::ProjectGrowthVectorsOnSurface() {
g += a * g + b * n; g += a * g + b * n;
} }
} }
} else { }
for (const auto &seg : segments) { else
{
for (const auto& seg : segments)
{
int count = 0; int count = 0;
for (const auto& seg2 : segments) for (const auto& seg2 : segments)
if (((seg[0] == seg2[0] && seg[1] == seg2[1]) || if (((seg[0] == seg2[0] && seg[1] == seg2[1]) || (seg[0] == seg2[1] && seg[1] == seg2[0])) && par_surfid.Contains(seg2.si))
(seg[0] == seg2[1] && seg[1] == seg2[0])) &&
par_surfid.Contains(seg2.si))
count++; count++;
if (count == 1) { if (count == 1)
{
growthvectors[seg[0]] = {0., 0., 0.}; growthvectors[seg[0]] = {0., 0., 0.};
growthvectors[seg[1]] = {0., 0., 0.}; growthvectors[seg[1]] = {0., 0., 0.};
} }
@ -533,7 +587,8 @@ BitArray BoundaryLayerTool ::ProjectGrowthVectorsOnSurface() {
void BoundaryLayerTool ::InsertNewElements( void BoundaryLayerTool ::InsertNewElements(
FlatArray<Array<pair<SegmentIndex, int>>, SegmentIndex> segmap, FlatArray<Array<pair<SegmentIndex, int>>, SegmentIndex> segmap,
const BitArray &in_surface_direction) { const BitArray& in_surface_direction)
{
static Timer timer("BoundaryLayerTool::InsertNewElements"); static Timer timer("BoundaryLayerTool::InsertNewElements");
RegionTimer rt(timer); RegionTimer rt(timer);
mapto.SetSize(0); mapto.SetSize(0);
@ -548,12 +603,12 @@ void BoundaryLayerTool ::InsertNewElements(
auto& identifications = mesh.GetIdentifications(); auto& identifications = mesh.GetIdentifications();
const int identnr = identifications.GetNr("boundarylayer"); const int identnr = identifications.GetNr("boundarylayer");
auto add_points = [&](PointIndex pi, Vec<3> &growth_vector, auto add_points = [&] (PointIndex pi, Vec<3>& growth_vector, Array<PointIndex>& new_points) {
Array<PointIndex> &new_points) {
Point<3> p = mesh[pi]; Point<3> p = mesh[pi];
PointIndex pi_last = pi; PointIndex pi_last = pi;
double height = 0.0; double height = 0.0;
for (auto i : Range(par_heights)) { for (auto i : Range(par_heights))
{
height += par_heights[i]; height += par_heights[i];
auto pi_new = mesh.AddPoint(p); auto pi_new = mesh.AddPoint(p);
// mesh.AddLockedPoint(pi_new); // mesh.AddLockedPoint(pi_new);
@ -567,12 +622,16 @@ void BoundaryLayerTool ::InsertNewElements(
}; };
// insert new points // insert new points
for (PointIndex pi = 1; pi <= np; pi++) { for (PointIndex pi = 1; pi <= np; pi++)
if (growthvectors[pi].Length2() != 0) { {
if (special_boundary_points.count(pi)) { if (growthvectors[pi].Length2() != 0)
{
if (special_boundary_points.count(pi))
{
for (auto& group : special_boundary_points[pi].growth_groups) for (auto& group : special_boundary_points[pi].growth_groups)
add_points(pi, group.growth_vector, group.new_points); add_points(pi, group.growth_vector, group.new_points);
} else }
else
add_points(pi, growthvectors[pi], mapto[pi]); add_points(pi, growthvectors[pi], mapto[pi]);
} }
} }
@ -602,7 +661,8 @@ void BoundaryLayerTool ::InsertNewElements(
auto getGroups = [&] (PointIndex pi, int face_index) -> Array<int> { auto getGroups = [&] (PointIndex pi, int face_index) -> Array<int> {
auto n = numGroups(pi); auto n = numGroups(pi);
Array<int> groups; Array<int> groups;
if (n == 1) { if (n == 1)
{
groups.Append(0); groups.Append(0);
return groups; return groups;
} }
@ -623,16 +683,19 @@ void BoundaryLayerTool ::InsertNewElements(
edge_map[ei] = ++edge_nr; edge_map[ei] = ++edge_nr;
return edge_map[ei]; return edge_map[ei];
}; };
if (params.grow_edges) { if (params.grow_edges)
for (auto sei : moved_segs) { {
for (auto sei : moved_segs)
{
// 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 = segments[sei]; // auto segi = segments[sei];
for (auto [sej, type] : segmap[sei]) { for (auto [sej, type] : segmap[sei])
{
auto segj = segments[sej]; auto segj = segments[sej];
if (type == 0) { if (type == 0)
auto addSegment = [&](PointIndex p0, PointIndex p1, {
bool extra_edge_nr = false) { auto addSegment = [&] (PointIndex p0, PointIndex p1, bool extra_edge_nr = false) {
Segment s; Segment s;
s[0] = p0; s[0] = p0;
s[1] = p1; s[1] = p1;
@ -656,7 +719,8 @@ void BoundaryLayerTool ::InsertNewElements(
if (g0.Size() == 1 && g1.Size() == 1) if (g0.Size() == 1 && g1.Size() == 1)
auto s = auto s =
addSegment(newPoint(p0, -1, g0[0]), newPoint(p1, -1, g1[0])); addSegment(newPoint(p0, -1, g0[0]), newPoint(p1, -1, g1[0]));
else { else
{
if (g0.Size() == 2) if (g0.Size() == 2)
addSegment(newPoint(p0, -1, g0[0]), newPoint(p0, -1, g0[1])); addSegment(newPoint(p0, -1, g0[0]), newPoint(p0, -1, g0[1]));
if (g1.Size() == 2) if (g1.Size() == 2)
@ -664,10 +728,12 @@ void BoundaryLayerTool ::InsertNewElements(
} }
} }
// here we need to grow the quad elements // here we need to grow the quad elements
else if (type == 1) { else if (type == 1)
{
PointIndex pp1 = segj[1]; PointIndex pp1 = segj[1];
PointIndex pp2 = segj[0]; PointIndex pp2 = segj[0];
if (in_surface_direction.Test(segj.si)) { if (in_surface_direction.Test(segj.si))
{
Swap(pp1, pp2); Swap(pp1, pp2);
is_boundary_moved.SetBit(segj.si); is_boundary_moved.SetBit(segj.si);
} }
@ -684,7 +750,8 @@ void BoundaryLayerTool ::InsertNewElements(
if (type == 3) if (type == 3)
new_segments_on_moved_bnd.Append(s0); new_segments_on_moved_bnd.Append(s0);
for (auto i : Range(par_heights)) { for (auto i : Range(par_heights))
{
Element2d sel(QUAD); Element2d sel(QUAD);
p3 = newPoint(pp2, i); p3 = newPoint(pp2, i);
p4 = newPoint(pp1, i); p4 = newPoint(pp1, i);
@ -692,7 +759,8 @@ void BoundaryLayerTool ::InsertNewElements(
sel[1] = p2; sel[1] = p2;
sel[2] = p3; sel[2] = p3;
sel[3] = p4; sel[3] = p4;
for (auto i : Range(4)) { for (auto i : Range(4))
{
sel.GeomInfo()[i].u = 0.0; sel.GeomInfo()[i].u = 0.0;
sel.GeomInfo()[i].v = 0.0; sel.GeomInfo()[i].v = 0.0;
} }
@ -730,17 +798,21 @@ void BoundaryLayerTool ::InsertNewElements(
new_segments.Append(s3); new_segments.Append(s3);
if (type == 3) if (type == 3)
new_segments_on_moved_bnd.Append(s0); new_segments_on_moved_bnd.Append(s0);
} else if (type == 3) { }
else if (type == 3)
{
PointIndex pp1 = segj[1]; PointIndex pp1 = segj[1];
PointIndex pp2 = segj[0]; PointIndex pp2 = segj[0];
if (!in_surface_direction.Test(segj.si)) { if (!in_surface_direction.Test(segj.si))
{
Swap(pp1, pp2); Swap(pp1, pp2);
} }
PointIndex p1 = pp1; PointIndex p1 = pp1;
PointIndex p2 = pp2; PointIndex p2 = pp2;
PointIndex p3, p4; PointIndex p3, p4;
for (auto i : Range(par_heights)) { for (auto i : Range(par_heights))
{
Element2d sel(QUAD); Element2d sel(QUAD);
p3 = newPoint(pp2, i); p3 = newPoint(pp2, i);
p4 = newPoint(pp1, i); p4 = newPoint(pp1, i);
@ -748,7 +820,8 @@ void BoundaryLayerTool ::InsertNewElements(
sel[1] = p2; sel[1] = p2;
sel[2] = p3; sel[2] = p3;
sel[3] = p4; sel[3] = p4;
for (auto i : Range(4)) { for (auto i : Range(4))
{
sel.GeomInfo()[i].u = 0.0; sel.GeomInfo()[i].u = 0.0;
sel.GeomInfo()[i].v = 0.0; sel.GeomInfo()[i].v = 0.0;
} }
@ -783,10 +856,12 @@ void BoundaryLayerTool ::InsertNewElements(
BitArray fixed_points(np + 1); BitArray fixed_points(np + 1);
fixed_points.Clear(); fixed_points.Clear();
auto p2el = mesh.CreatePoint2ElementTable(); auto p2el = mesh.CreatePoint2ElementTable();
for (SurfaceElementIndex si = 0; si < nse; si++) { for (SurfaceElementIndex si = 0; si < nse; si++)
{
// copy because surfaceels array will be resized! // copy because surfaceels array will be resized!
const auto sel = mesh[si]; const auto sel = mesh[si];
if (moved_surfaces.Test(sel.GetIndex())) { if (moved_surfaces.Test(sel.GetIndex()))
{
Array<PointIndex> points(sel.PNums()); Array<PointIndex> points(sel.PNums());
if (surfacefacs[sel.GetIndex()] > 0) if (surfacefacs[sel.GetIndex()] > 0)
Swap(points[0], points[2]); Swap(points[0], points[2]);
@ -797,7 +872,8 @@ void BoundaryLayerTool ::InsertNewElements(
for (auto pi : sel.PNums()) for (auto pi : sel.PNums())
if (numGroups(pi) > 1) if (numGroups(pi) > 1)
add_volume_element = false; add_volume_element = false;
for (auto j : Range(par_heights)) { for (auto j : Range(par_heights))
{
auto eltype = points.Size() == 3 ? PRISM : HEX; auto eltype = points.Size() == 3 ? PRISM : HEX;
Element el(eltype); Element el(eltype);
for (auto i : Range(points)) for (auto i : Range(points))
@ -810,13 +886,12 @@ void BoundaryLayerTool ::InsertNewElements(
el[sel.PNums().Size() + i] = points[i]; el[sel.PNums().Size() + i] = points[i];
auto new_index = new_mat_nrs[sel.GetIndex()]; auto new_index = new_mat_nrs[sel.GetIndex()];
if (new_index == -1) if (new_index == -1)
throw Exception("Boundary " + ToString(sel.GetIndex()) + throw Exception("Boundary " + ToString(sel.GetIndex()) + " with name " + mesh.GetBCName(sel.GetIndex() - 1) + " extruded, but no new material specified for it!");
" with name " + mesh.GetBCName(sel.GetIndex() - 1) +
" extruded, but no new material specified for it!");
el.SetIndex(new_mat_nrs[sel.GetIndex()]); el.SetIndex(new_mat_nrs[sel.GetIndex()]);
if (add_volume_element) if (add_volume_element)
mesh.AddVolumeElement(el); mesh.AddVolumeElement(el);
else { else
{
// Let the volume mesher fill the hole with pyramids/tets // Let the volume mesher fill the hole with pyramids/tets
// To insert pyramids, we need close surface identifications on open // To insert pyramids, we need close surface identifications on open
// quads // quads
@ -831,16 +906,19 @@ void BoundaryLayerTool ::InsertNewElements(
newel.SetIndex(si_map[sel.GetIndex()]); newel.SetIndex(si_map[sel.GetIndex()]);
new_sels.Append(newel); new_sels.Append(newel);
} }
if (is_boundary_moved.Test(sel.GetIndex())) { if (is_boundary_moved.Test(sel.GetIndex()))
{
for (auto& p : mesh[si].PNums()) for (auto& p : mesh[si].PNums())
if (hasMoved(p)) if (hasMoved(p))
p = newPoint(p); p = newPoint(p);
} }
} }
for (SegmentIndex sei = 0; sei < nseg; sei++) { for (SegmentIndex sei = 0; sei < nseg; sei++)
{
auto& seg = segments[sei]; auto& seg = segments[sei];
if (is_boundary_moved.Test(seg.si)) { if (is_boundary_moved.Test(seg.si))
{
// cout << "moved setg " << seg << endl; // cout << "moved setg " << seg << endl;
for (auto& p : seg.PNums()) for (auto& p : seg.PNums())
if (hasMoved(p)) if (hasMoved(p))
@ -858,7 +936,8 @@ void BoundaryLayerTool ::InsertNewElements(
}, },
mesh.GetNP()); mesh.GetNP());
for (auto &[special_pi, special_point] : special_boundary_points) { for (auto& [special_pi, special_point] : special_boundary_points)
{
if (special_point.growth_groups.Size() != 2) if (special_point.growth_groups.Size() != 2)
throw Exception("special_point.growth_groups.Size() != 2"); throw Exception("special_point.growth_groups.Size() != 2");
@ -868,7 +947,8 @@ void BoundaryLayerTool ::InsertNewElements(
// to). At exactly these points we need to insert new surface elements to // to). At exactly these points we need to insert new surface elements to
// fill the hole. // fill the hole.
std::map<int, std::array<std::set<PointIndex>, 2>> close_group; std::map<int, std::array<std::set<PointIndex>, 2>> close_group;
for (auto sei : p2sel[special_pi]) { for (auto sei : p2sel[special_pi])
{
const auto& sel = mesh[sei]; const auto& sel = mesh[sei];
for (auto p : sel.PNums()) for (auto p : sel.PNums())
if (p != special_pi) if (p != special_pi)
@ -876,19 +956,22 @@ void BoundaryLayerTool ::InsertNewElements(
p); p);
} }
for (auto [fi, groups] : close_group) { for (auto [fi, groups] : close_group)
{
const auto mapped_fi = si_map[fi]; const auto mapped_fi = si_map[fi];
std::set<PointIndex> common_points; std::set<PointIndex> common_points;
for (auto pi : groups[0]) for (auto pi : groups[0])
if (groups[1].count(pi) == 1) if (groups[1].count(pi) == 1)
common_points.insert(pi); common_points.insert(pi);
if (common_points.size() > 0) { if (common_points.size() > 0)
{
auto pi_common = mapto[*common_points.begin()].Last(); auto pi_common = mapto[*common_points.begin()].Last();
auto new_special_pi0 = special_point.growth_groups[0].new_points.Last(); auto new_special_pi0 = special_point.growth_groups[0].new_points.Last();
auto new_special_pi1 = special_point.growth_groups[1].new_points.Last(); auto new_special_pi1 = special_point.growth_groups[1].new_points.Last();
for (auto sei : p2sel[pi_common]) { for (auto sei : p2sel[pi_common])
if (mesh[sei].GetIndex() == mapped_fi && {
mesh[sei].PNums().Contains(new_special_pi0)) { if (mesh[sei].GetIndex() == mapped_fi && mesh[sei].PNums().Contains(new_special_pi0))
{
auto sel = mesh[sei]; auto sel = mesh[sei];
sel.Invert(); sel.Invert();
for (auto& pi : sel.PNums()) for (auto& pi : sel.PNums())
@ -901,10 +984,12 @@ void BoundaryLayerTool ::InsertNewElements(
} }
} }
for (auto &[pi, special_point] : special_boundary_points) { for (auto& [pi, special_point] : special_boundary_points)
{
if (special_point.growth_groups.Size() != 2) if (special_point.growth_groups.Size() != 2)
throw Exception("special_point.growth_groups.Size() != 2"); throw Exception("special_point.growth_groups.Size() != 2");
for (auto igroup : Range(2)) { for (auto igroup : Range(2))
{
auto& group = special_point.growth_groups[igroup]; auto& group = special_point.growth_groups[igroup];
std::set<int> faces; std::set<int> faces;
for (auto face : group.faces) for (auto face : group.faces)
@ -915,19 +1000,23 @@ void BoundaryLayerTool ::InsertNewElements(
for (auto sei : p2sel[pi_new]) for (auto sei : p2sel[pi_new])
faces.erase(mesh[sei].GetIndex()); faces.erase(mesh[sei].GetIndex());
for (auto face : faces) for (auto face : faces)
for (auto seg : new_segments) { for (auto seg : new_segments)
{
if ( // seg.si == face if ( // seg.si == face
(seg[0] == pi_new || seg[1] == pi_new) && (seg[0] == pi_new || seg[1] == pi_new) && (seg[0] != pi_new_other && seg[1] != pi_new_other))
(seg[0] != pi_new_other && seg[1] != pi_new_other)) { {
bool is_correct_face = false; bool is_correct_face = false;
auto pi_other = seg[0] == pi_new ? seg[1] : seg[0]; auto pi_other = seg[0] == pi_new ? seg[1] : seg[0];
for (auto sei : p2sel[pi_other]) { for (auto sei : p2sel[pi_other])
if (mesh[sei].GetIndex() == face) { {
if (mesh[sei].GetIndex() == face)
{
is_correct_face = true; is_correct_face = true;
break; break;
} }
} }
if (is_correct_face) { if (is_correct_face)
{
Element2d sel; Element2d sel;
sel[0] = seg[1]; sel[0] = seg[1];
sel[1] = seg[0]; sel[1] = seg[0];
@ -941,11 +1030,13 @@ void BoundaryLayerTool ::InsertNewElements(
} }
} }
void BoundaryLayerTool ::SetDomInOut() { void BoundaryLayerTool ::SetDomInOut()
{
if (insert_only_volume_elements) if (insert_only_volume_elements)
return; return;
for (auto i : Range(1, nfd_old + 1)) for (auto i : Range(1, nfd_old + 1))
if (moved_surfaces.Test(i)) { if (moved_surfaces.Test(i))
{
if (auto dom = mesh.GetFaceDescriptor(si_map[i]).DomainIn(); if (auto dom = mesh.GetFaceDescriptor(si_map[i]).DomainIn();
dom > ndom_old) dom > ndom_old)
mesh.GetFaceDescriptor(i).SetDomainOut(dom); mesh.GetFaceDescriptor(i).SetDomainOut(dom);
@ -955,12 +1046,14 @@ void BoundaryLayerTool ::SetDomInOut() {
} }
} }
void BoundaryLayerTool ::SetDomInOutSides() { void BoundaryLayerTool ::SetDomInOutSides()
{
if (insert_only_volume_elements) if (insert_only_volume_elements)
return; return;
BitArray done(mesh.GetNFD() + 1); BitArray done(mesh.GetNFD() + 1);
done.Clear(); done.Clear();
for (auto sei : Range(mesh.SurfaceElements())) { for (auto sei : Range(mesh.SurfaceElements()))
{
auto& sel = mesh[sei]; auto& sel = mesh[sei];
auto index = sel.GetIndex(); auto index = sel.GetIndex();
if (done.Test(index)) if (done.Test(index))
@ -982,48 +1075,56 @@ void BoundaryLayerTool ::SetDomInOutSides() {
} }
} }
void BoundaryLayerTool ::AddSegments() { void BoundaryLayerTool ::AddSegments()
{
auto& new_segs = auto& new_segs =
insert_only_volume_elements ? new_segments_on_moved_bnd : new_segments; insert_only_volume_elements ? new_segments_on_moved_bnd : new_segments;
// cout << "add new segs " << endl << new_segs << endl; // cout << "add new segs " << endl << new_segs << endl;
if (have_single_segments) if (have_single_segments)
MergeAndAddSegments(mesh, segments, new_segs); MergeAndAddSegments(mesh, segments, new_segs);
else { else
{
mesh.LineSegments() = segments; mesh.LineSegments() = segments;
for (auto& seg : new_segs) for (auto& seg : new_segs)
mesh.AddSegment(seg); mesh.AddSegment(seg);
} }
} }
void BoundaryLayerTool ::AddSurfaceElements() { void BoundaryLayerTool ::AddSurfaceElements()
{
for (auto& sel : for (auto& sel :
insert_only_volume_elements ? new_sels_on_moved_bnd : new_sels) insert_only_volume_elements ? new_sels_on_moved_bnd : new_sels)
mesh.AddSurfaceElement(sel); mesh.AddSurfaceElement(sel);
} }
void BoundaryLayerTool ::ProcessParameters() { void BoundaryLayerTool ::ProcessParameters()
if (int *bc = get_if<int>(&params.boundary); bc) { {
if (int* bc = get_if<int>(&params.boundary); bc)
{
for (int i = 1; i <= mesh.GetNFD(); i++) for (int i = 1; i <= mesh.GetNFD(); i++)
if (mesh.GetFaceDescriptor(i).BCProperty() == *bc) if (mesh.GetFaceDescriptor(i).BCProperty() == *bc)
par_surfid.Append(i); par_surfid.Append(i);
} else if (string *s = get_if<string>(&params.boundary); s) { }
else if (string* s = get_if<string>(&params.boundary); s)
{
regex pattern(*s); regex pattern(*s);
BitArray boundaries(mesh.GetNFD() + 1); BitArray boundaries(mesh.GetNFD() + 1);
boundaries.Clear(); boundaries.Clear();
for (int i = 1; i <= mesh.GetNFD(); i++) { for (int i = 1; i <= mesh.GetNFD(); i++)
{
auto& fd = mesh.GetFaceDescriptor(i); auto& fd = mesh.GetFaceDescriptor(i);
if (regex_match(fd.GetBCName(), pattern)) { if (regex_match(fd.GetBCName(), pattern))
{
boundaries.SetBit(i); boundaries.SetBit(i);
auto dom_pattern = get_if<string>(&params.domain); auto dom_pattern = get_if<string>(&params.domain);
// only add if adjacent to domain // only add if adjacent to domain
if (dom_pattern) { if (dom_pattern)
{
regex pattern(*dom_pattern); regex pattern(*dom_pattern);
bool mat1_match = bool mat1_match =
fd.DomainIn() > 0 && fd.DomainIn() > 0 && regex_match(mesh.GetMaterial(fd.DomainIn()), pattern);
regex_match(mesh.GetMaterial(fd.DomainIn()), pattern);
bool mat2_match = bool mat2_match =
fd.DomainOut() > 0 && fd.DomainOut() > 0 && regex_match(mesh.GetMaterial(fd.DomainOut()), pattern);
regex_match(mesh.GetMaterial(fd.DomainOut()), pattern);
// if boundary is inner or outer remove from list // if boundary is inner or outer remove from list
if (mat1_match == mat2_match) if (mat1_match == mat2_match)
boundaries.Clear(i); boundaries.Clear(i);
@ -1041,36 +1142,46 @@ void BoundaryLayerTool ::ProcessParameters() {
for (int i = 1; i <= mesh.GetNFD(); i++) for (int i = 1; i <= mesh.GetNFD(); i++)
if (boundaries.Test(i)) if (boundaries.Test(i))
par_surfid.Append(i); par_surfid.Append(i);
} else { }
else
{
auto& surfids = *get_if<std::vector<int>>(&params.boundary); auto& surfids = *get_if<std::vector<int>>(&params.boundary);
for (auto id : surfids) for (auto id : surfids)
par_surfid.Append(id); par_surfid.Append(id);
} }
insert_only_volume_elements = !params.new_material.has_value(); insert_only_volume_elements = !params.new_material.has_value();
if (params.new_material) { if (params.new_material)
{
if (string* mat = get_if<string>(&*params.new_material); mat) if (string* mat = get_if<string>(&*params.new_material); mat)
par_new_mat = {{".*", *mat}}; par_new_mat = {{".*", *mat}};
else else
par_new_mat = *get_if<map<string, string>>(&*params.new_material); par_new_mat = *get_if<map<string, string>>(&*params.new_material);
} }
if (params.project_boundaries.has_value()) { if (params.project_boundaries.has_value())
{
auto proj_bnd = *params.project_boundaries; auto proj_bnd = *params.project_boundaries;
if (string *s = get_if<string>(&proj_bnd); s) { if (string* s = get_if<string>(&proj_bnd); s)
{
regex pattern(*s); regex pattern(*s);
for (int i = 1; i <= mesh.GetNFD(); i++) for (int i = 1; i <= mesh.GetNFD(); i++)
if (regex_match(mesh.GetFaceDescriptor(i).GetBCName(), pattern)) if (regex_match(mesh.GetFaceDescriptor(i).GetBCName(), pattern))
par_project_boundaries.Append(i); par_project_boundaries.Append(i);
} else { }
else
{
for (auto id : *get_if<std::vector<int>>(&proj_bnd)) for (auto id : *get_if<std::vector<int>>(&proj_bnd))
par_project_boundaries.Append(id); par_project_boundaries.Append(id);
} }
} }
if (double *height = get_if<double>(&params.thickness); height) { if (double* height = get_if<double>(&params.thickness); height)
{
par_heights.Append(*height); par_heights.Append(*height);
} else { }
else
{
auto& heights = *get_if<std::vector<double>>(&params.thickness); auto& heights = *get_if<std::vector<double>>(&params.thickness);
for (auto val : heights) for (auto val : heights)
par_heights.Append(val); par_heights.Append(val);
@ -1079,14 +1190,19 @@ void BoundaryLayerTool ::ProcessParameters() {
int nr_domains = mesh.GetNDomains(); int nr_domains = mesh.GetNDomains();
domains.SetSize(nr_domains + 1); // one based domains.SetSize(nr_domains + 1); // one based
domains.Clear(); domains.Clear();
if (string *pdomain = get_if<string>(&params.domain); pdomain) { if (string* pdomain = get_if<string>(&params.domain); pdomain)
{
regex pattern(*pdomain); regex pattern(*pdomain);
for (auto i : Range(1, nr_domains + 1)) for (auto i : Range(1, nr_domains + 1))
if (regex_match(mesh.GetMaterial(i), pattern)) if (regex_match(mesh.GetMaterial(i), pattern))
domains.SetBit(i); domains.SetBit(i);
} else if (int *idomain = get_if<int>(&params.domain); idomain) { }
else if (int* idomain = get_if<int>(&params.domain); idomain)
{
domains.SetBit(*idomain); domains.SetBit(*idomain);
} else { }
else
{
for (auto i : *get_if<std::vector<int>>(&params.domain)) for (auto i : *get_if<std::vector<int>>(&params.domain))
domains.SetBit(i); domains.SetBit(i);
} }
@ -1106,14 +1222,18 @@ void BoundaryLayerTool ::ProcessParameters() {
new_mat_nrs.SetSize(mesh.FaceDescriptors().Size() + 1); new_mat_nrs.SetSize(mesh.FaceDescriptors().Size() + 1);
new_mat_nrs = -1; new_mat_nrs = -1;
if (insert_only_volume_elements) { if (insert_only_volume_elements)
for (auto i : Range(1, mesh.GetNFD() + 1)) { {
for (auto i : Range(1, mesh.GetNFD() + 1))
{
auto& fd = mesh.GetFaceDescriptor(i); auto& fd = mesh.GetFaceDescriptor(i);
auto domin = fd.DomainIn(); auto domin = fd.DomainIn();
auto domout = fd.DomainOut(); auto domout = fd.DomainOut();
for (int dom : {domin, domout}) for (int dom : {domin, domout})
if (domains.Test(dom)) { if (domains.Test(dom))
if (params.outside) { {
if (params.outside)
{
dom = domin + domout - dom; dom = domin + domout - dom;
if (dom == 0) if (dom == 0)
throw NG_EXCEPTION("No new material specified for boundarylayer " throw NG_EXCEPTION("No new material specified for boundarylayer "
@ -1122,11 +1242,15 @@ void BoundaryLayerTool ::ProcessParameters() {
new_mat_nrs[i] = dom; new_mat_nrs[i] = dom;
} }
} }
} else { }
for (auto [bcname, matname] : par_new_mat) { else
{
for (auto [bcname, matname] : par_new_mat)
{
mesh.SetMaterial(++ndom, matname); mesh.SetMaterial(++ndom, matname);
regex pattern(bcname); regex pattern(bcname);
for (auto i : Range(1, mesh.GetNFD() + 1)) { for (auto i : Range(1, mesh.GetNFD() + 1))
{
auto& fd = mesh.GetFaceDescriptor(i); auto& fd = mesh.GetFaceDescriptor(i);
if (regex_match(fd.GetBCName(), pattern)) if (regex_match(fd.GetBCName(), pattern))
new_mat_nrs[i] = ndom; new_mat_nrs[i] = ndom;
@ -1138,7 +1262,8 @@ void BoundaryLayerTool ::ProcessParameters() {
domains.Invert(); domains.Invert();
} }
void BoundaryLayerTool ::Perform() { void BoundaryLayerTool ::Perform()
{
CreateNewFaceDescriptors(); CreateNewFaceDescriptors();
CalculateGrowthVectors(); CalculateGrowthVectors();
CreateFaceDescriptorsSides(); CreateFaceDescriptorsSides();
@ -1165,7 +1290,8 @@ void BoundaryLayerTool ::Perform() {
FixSurfaceElements(); FixSurfaceElements();
for (auto [pi, data] : growth_vector_map) { for (auto [pi, data] : growth_vector_map)
{
auto [gw, height] = data; auto [gw, height] = data;
mesh[pi] += height * (*gw); mesh[pi] += height * (*gw);
} }
@ -1177,7 +1303,8 @@ void BoundaryLayerTool ::Perform() {
SetDomInOutSides(); SetDomInOutSides();
} }
void GenerateBoundaryLayer(Mesh &mesh, const BoundaryLayerParameters &blp) { void GenerateBoundaryLayer (Mesh& mesh, const BoundaryLayerParameters& blp)
{
static Timer timer("Create Boundarylayers"); static Timer timer("Create Boundarylayers");
RegionTimer regt(timer); RegionTimer regt(timer);

View File

@ -14,8 +14,10 @@ DLL_HEADER extern void InsertVirtualBoundaryLayer (Mesh & mesh);
/// Create a typical prismatic boundary layer on the given /// Create a typical prismatic boundary layer on the given
/// surfaces /// surfaces
struct SpecialBoundaryPoint { struct SpecialBoundaryPoint
struct GrowthGroup { {
struct GrowthGroup
{
Array<int> faces; Array<int> faces;
Vec<3> growth_vector; Vec<3> growth_vector;
Array<PointIndex> new_points; Array<PointIndex> new_points;
@ -23,7 +25,6 @@ struct SpecialBoundaryPoint {
GrowthGroup(FlatArray<int> faces_, FlatArray<Vec<3>> normals); GrowthGroup(FlatArray<int> faces_, FlatArray<Vec<3>> normals);
GrowthGroup(const GrowthGroup&) = default; GrowthGroup(const GrowthGroup&) = default;
GrowthGroup() = default; GrowthGroup() = default;
}; };
// std::map<int, Vec<3>> normals; // std::map<int, Vec<3>> normals;
Array<GrowthGroup> growth_groups; Array<GrowthGroup> growth_groups;

View File

@ -1,9 +1,12 @@
#include "boundarylayer.hpp" #include "boundarylayer.hpp"
namespace netgen { namespace netgen
{
namespace detail { namespace detail
struct Neighbor { {
struct Neighbor
{
PointIndex pi; PointIndex pi;
SurfaceElementIndex sei; SurfaceElementIndex sei;
double weight; double weight;
@ -11,34 +14,39 @@ struct Neighbor {
} // namespace detail } // namespace detail
Array<ArrayMem<detail::Neighbor, 20>> Array<ArrayMem<detail::Neighbor, 20>>
BuildNeighbors(FlatArray<PointIndex> points, const Mesh &mesh) { BuildNeighbors (FlatArray<PointIndex> points, const Mesh& mesh)
{
auto p2sel = mesh.CreatePoint2SurfaceElementTable(); auto p2sel = mesh.CreatePoint2SurfaceElementTable();
Array<ArrayMem<detail::Neighbor, 20>> neighbors(points.Size()); Array<ArrayMem<detail::Neighbor, 20>> neighbors(points.Size());
ArrayMem<double, 20> angles; ArrayMem<double, 20> angles;
ArrayMem<double, 20> inv_dists; ArrayMem<double, 20> inv_dists;
for (auto i : points.Range()) { for (auto i : points.Range())
{
auto& p_neighbors = neighbors[i]; auto& p_neighbors = neighbors[i];
auto pi = points[i]; auto pi = points[i];
angles.SetSize(0); angles.SetSize(0);
inv_dists.SetSize(0); inv_dists.SetSize(0);
for (auto sei : p2sel[pi]) { for (auto sei : p2sel[pi])
{
const auto& sel = mesh[sei]; const auto& sel = mesh[sei];
for (auto pi1 : sel.PNums()) { for (auto pi1 : sel.PNums())
{
if (pi1 == pi) if (pi1 == pi)
continue; continue;
auto pi2 = pi1; auto pi2 = pi1;
for (auto pi_ : sel.PNums()) { for (auto pi_ : sel.PNums())
if (pi_ != pi && pi_ != pi1) { {
if (pi_ != pi && pi_ != pi1)
{
pi2 = pi_; pi2 = pi_;
break; break;
} }
} }
p_neighbors.Append({pi1, sei, 0.0}); p_neighbors.Append({pi1, sei, 0.0});
inv_dists.Append(1.0 / (mesh[pi1] - mesh[pi]).Length()); inv_dists.Append(1.0 / (mesh[pi1] - mesh[pi]).Length());
auto dot = (mesh[pi1] - mesh[pi]).Normalize() * auto dot = (mesh[pi1] - mesh[pi]).Normalize() * (mesh[pi2] - mesh[pi]).Normalize();
(mesh[pi2] - mesh[pi]).Normalize();
angles.Append(acos(dot)); angles.Append(acos(dot));
} }
} }
@ -50,7 +58,8 @@ BuildNeighbors(FlatArray<PointIndex> points, const Mesh &mesh) {
sum_angle += angle; sum_angle += angle;
double sum_weight = 0.0; double sum_weight = 0.0;
for (auto i : Range(inv_dists)) { for (auto i : Range(inv_dists))
{
p_neighbors[i].weight = p_neighbors[i].weight =
inv_dists[i] * angles[i] / sum_inv_dist / sum_angle; inv_dists[i] * angles[i] / sum_inv_dist / sum_angle;
sum_weight += p_neighbors[i].weight; sum_weight += p_neighbors[i].weight;
@ -61,7 +70,8 @@ BuildNeighbors(FlatArray<PointIndex> points, const Mesh &mesh) {
return neighbors; return neighbors;
} }
void BoundaryLayerTool ::InterpolateGrowthVectors() { void BoundaryLayerTool ::InterpolateGrowthVectors()
{
int new_max_edge_nr = max_edge_nr; int new_max_edge_nr = max_edge_nr;
for (const auto& seg : segments) for (const auto& seg : segments)
if (seg.edgenr > new_max_edge_nr) if (seg.edgenr > new_max_edge_nr)
@ -107,7 +117,8 @@ void BoundaryLayerTool ::InterpolateGrowthVectors() {
}, },
mesh.GetNP()); mesh.GetNP());
for (auto edgenr : Range(max_edge_nr + 1, new_max_edge_nr + 1)) { for (auto edgenr : Range(max_edge_nr + 1, new_max_edge_nr + 1))
{
double edge_len = 0.; double edge_len = 0.;
auto is_end_point = [&] (PointIndex pi) { auto is_end_point = [&] (PointIndex pi) {
@ -124,7 +135,8 @@ void BoundaryLayerTool ::InterpolateGrowthVectors() {
bool any_grows = false; bool any_grows = false;
Array<PointIndex> points; Array<PointIndex> points;
for (auto *p_seg : edgenr2seg[edgenr]) { for (auto* p_seg : edgenr2seg[edgenr])
{
auto& seg = *p_seg; auto& seg = *p_seg;
if (getGW(seg[0]).Length2() != 0 || getGW(seg[1]).Length2() != 0) if (getGW(seg[0]).Length2() != 0 || getGW(seg[1]).Length2() != 0)
@ -132,7 +144,8 @@ void BoundaryLayerTool ::InterpolateGrowthVectors() {
if (points.Size() == 0) if (points.Size() == 0)
for (auto i : Range(2)) for (auto i : Range(2))
if (is_end_point(seg[i])) { if (is_end_point(seg[i]))
{
points.Append(seg[i]); points.Append(seg[i]);
points.Append(seg[1 - i]); points.Append(seg[1 - i]);
edge_len += (mesh[seg[1]] - mesh[seg[0]]).Length(); edge_len += (mesh[seg[1]] - mesh[seg[0]]).Length();
@ -140,13 +153,14 @@ void BoundaryLayerTool ::InterpolateGrowthVectors() {
} }
} }
if (!any_grows) { if (!any_grows)
PrintMessage(1, "BLayer: skip interpolating growth vectors at edge ", {
edgenr + 1); PrintMessage(1, "BLayer: skip interpolating growth vectors at edge ", edgenr + 1);
continue; continue;
} }
if (!points.Size()) { if (!points.Size())
{
cerr << "Could not find startpoint for edge " << edgenr << endl; cerr << "Could not find startpoint for edge " << edgenr << endl;
continue; continue;
} }
@ -156,11 +170,13 @@ void BoundaryLayerTool ::InterpolateGrowthVectors() {
points_set.insert(points[1]); points_set.insert(points[1]);
bool point_found = true; bool point_found = true;
while (point_found) { while (point_found)
{
if (is_end_point(points.Last())) if (is_end_point(points.Last()))
break; break;
point_found = false; point_found = false;
for (auto *p_seg : point2seg[points.Last()]) { for (auto* p_seg : point2seg[points.Last()])
{
const auto& seg = *p_seg; const auto& seg = *p_seg;
if (seg.edgenr != edgenr) if (seg.edgenr != edgenr)
continue; continue;
@ -168,10 +184,10 @@ void BoundaryLayerTool ::InterpolateGrowthVectors() {
if (plast != seg[0] && plast != seg[1]) if (plast != seg[0] && plast != seg[1])
continue; continue;
auto pnew = plast == seg[0] ? seg[1] : seg[0]; auto pnew = plast == seg[0] ? seg[1] : seg[0];
if (pnew == points[0] && points.Size() > 1) { if (pnew == points[0] && points.Size() > 1)
{
} }
if (points_set.count(pnew) > 0 && if (points_set.count(pnew) > 0 && (pnew != points[0] || points.Size() == 2))
(pnew != points[0] || points.Size() == 2))
continue; continue;
edge_len += (mesh[points.Last()] - mesh[pnew]).Length(); edge_len += (mesh[points.Last()] - mesh[pnew]).Length();
points.Append(pnew); points.Append(pnew);
@ -180,10 +196,12 @@ void BoundaryLayerTool ::InterpolateGrowthVectors() {
break; break;
} }
} }
if (!point_found) { if (!point_found)
{
cerr << "Could not find connected list of line segments for edge " cerr << "Could not find connected list of line segments for edge "
<< edgenr << endl; << edgenr << endl;
cerr << "current points: " << endl << points << endl; cerr << "current points: " << endl
<< points << endl;
continue; continue;
} }
@ -198,7 +216,8 @@ void BoundaryLayerTool ::InterpolateGrowthVectors() {
auto gt2 = getGW(points.Last()) * t2 * t2; auto gt2 = getGW(points.Last()) * t2 * t2;
double len = 0.; double len = 0.;
for (auto i : IntRange(1, points.Size() - 1)) { for (auto i : IntRange(1, points.Size() - 1))
{
auto pi = points[i]; auto pi = points[i];
len += (mesh[pi] - mesh[points[i - 1]]).Length(); len += (mesh[pi] - mesh[points[i - 1]]).Length();
auto t = getEdgeTangent(pi, edgenr, point2seg[pi]); auto t = getEdgeTangent(pi, edgenr, point2seg[pi]);
@ -209,7 +228,8 @@ void BoundaryLayerTool ::InterpolateGrowthVectors() {
} }
} }
void BoundaryLayerTool ::InterpolateSurfaceGrowthVectors() { void BoundaryLayerTool ::InterpolateSurfaceGrowthVectors()
{
static Timer tall("InterpolateSurfaceGrowthVectors"); static Timer tall("InterpolateSurfaceGrowthVectors");
RegionTimer rtall(tall); RegionTimer rtall(tall);
static Timer tsmooth("InterpolateSurfaceGrowthVectors-Smoothing"); static Timer tsmooth("InterpolateSurfaceGrowthVectors-Smoothing");
@ -248,13 +268,13 @@ void BoundaryLayerTool ::InterpolateSurfaceGrowthVectors() {
}; };
auto hasMoved = [&] (PointIndex pi) { auto hasMoved = [&] (PointIndex pi) {
return (pi - PointIndex::BASE >= np_old) || mapto[pi].Size() > 0 || return (pi - PointIndex::BASE >= np_old) || mapto[pi].Size() > 0 || special_boundary_points.count(pi);
special_boundary_points.count(pi);
}; };
// cout << __FILE__ << ":" << __LINE__ << endl; // cout << __FILE__ << ":" << __LINE__ << endl;
std::set<PointIndex> points_set; std::set<PointIndex> points_set;
for (const auto &sel : mesh.SurfaceElements()) { for (const auto& sel : mesh.SurfaceElements())
{
for (auto pi : sel.PNums()) for (auto pi : sel.PNums())
if (mesh[pi].Type() == SURFACEPOINT && hasMoved(pi)) if (mesh[pi].Type() == SURFACEPOINT && hasMoved(pi))
points_set.insert(pi); points_set.insert(pi);
@ -277,15 +297,18 @@ void BoundaryLayerTool ::InterpolateSurfaceGrowthVectors() {
BitArray interpolate_tangent(mesh.GetNP() + 1); BitArray interpolate_tangent(mesh.GetNP() + 1);
interpolate_tangent = false; interpolate_tangent = false;
for (auto pi : points) { for (auto pi : points)
{
for (auto sei : p2sel[pi]) for (auto sei : p2sel[pi])
if (is_boundary_moved[mesh[sei].GetIndex()]) if (is_boundary_moved[mesh[sei].GetIndex()])
interpolate_tangent.SetBit(pi); interpolate_tangent.SetBit(pi);
} }
constexpr int N_STEPS = 64; constexpr int N_STEPS = 64;
for ([[maybe_unused]] auto i : Range(N_STEPS)) { for ([[maybe_unused]] auto i : Range(N_STEPS))
for (auto i : points.Range()) { {
for (auto i : points.Range())
{
auto pi = points[i]; auto pi = points[i];
// cout << "AVERAGE " << pi << endl; // cout << "AVERAGE " << pi << endl;
auto& p_neighbors = neighbors[i]; auto& p_neighbors = neighbors[i];
@ -297,9 +320,11 @@ void BoundaryLayerTool ::InterpolateSurfaceGrowthVectors() {
// average only tangent component on new bl points, average whole growth // average only tangent component on new bl points, average whole growth
// vector otherwise // vector otherwise
bool do_average_tangent = true; bool do_average_tangent = true;
for (const auto &s : p_neighbors) { for (const auto& s : p_neighbors)
{
auto gw_other = getGW(s.pi) + corrections[s.pi]; auto gw_other = getGW(s.pi) + corrections[s.pi];
if (do_average_tangent) { if (do_average_tangent)
{
auto n = surf_normals[s.sei]; auto n = surf_normals[s.sei];
gw_other = gw_other - (gw_other * n) * n; gw_other = gw_other - (gw_other * n) * n;
} }
@ -320,10 +345,10 @@ void BoundaryLayerTool ::InterpolateSurfaceGrowthVectors() {
auto& correction = corrections[pi]; auto& correction = corrections[pi];
correction = 0.0; correction = 0.0;
for (const auto i : p_neighbors.Range()) { for (const auto i : p_neighbors.Range())
{
auto v = g_vectors[i]; auto v = g_vectors[i];
double weight = lambda * p_neighbors[i].weight + double weight = lambda * p_neighbors[i].weight + (1.0 - lambda) * v.Length2() / sum_len;
(1.0 - lambda) * v.Length2() / sum_len;
// if(pi == 19911) cout << "pi " << pi << "\tneighbor " << // if(pi == 19911) cout << "pi " << pi << "\tneighbor " <<
// p_neighbors[i].pi << "\tweight " << weight << endl; // p_neighbors[i].pi << "\tweight " << weight << endl;
correction += weight * v; correction += weight * v;
@ -340,7 +365,8 @@ void BoundaryLayerTool ::InterpolateSurfaceGrowthVectors() {
addGW(pi, corrections[pi]); addGW(pi, corrections[pi]);
} }
void BoundaryLayerTool ::FixSurfaceElements() { void BoundaryLayerTool ::FixSurfaceElements()
{
static Timer tall("FixSurfaceElements"); static Timer tall("FixSurfaceElements");
RegionTimer rtall(tall); RegionTimer rtall(tall);
auto np_old = this->np; auto np_old = this->np;
@ -350,7 +376,8 @@ void BoundaryLayerTool ::FixSurfaceElements() {
auto getGW = [&] (PointIndex pi) -> Vec<3> { auto getGW = [&] (PointIndex pi) -> Vec<3> {
// return growthvectors[pi]; // return growthvectors[pi];
if (growth_vector_map.count(pi) == 0) { if (growth_vector_map.count(pi) == 0)
{
non_bl_growth_vectors[pi] = .0; non_bl_growth_vectors[pi] = .0;
growth_vector_map[pi] = {&non_bl_growth_vectors[pi], 1.0}; growth_vector_map[pi] = {&non_bl_growth_vectors[pi], 1.0};
} }
@ -359,7 +386,8 @@ void BoundaryLayerTool ::FixSurfaceElements() {
}; };
auto addGW = [&] (PointIndex pi, Vec<3> vec) { auto addGW = [&] (PointIndex pi, Vec<3> vec) {
if (growth_vector_map.count(pi) == 0) { if (growth_vector_map.count(pi) == 0)
{
non_bl_growth_vectors[pi] = .0; non_bl_growth_vectors[pi] = .0;
growth_vector_map[pi] = {&non_bl_growth_vectors[pi], 1.0}; growth_vector_map[pi] = {&non_bl_growth_vectors[pi], 1.0};
} }
@ -369,7 +397,8 @@ void BoundaryLayerTool ::FixSurfaceElements() {
std::set<PointIndex> points_set; std::set<PointIndex> points_set;
// only smooth over old surface elements // only smooth over old surface elements
for (SurfaceElementIndex sei : Range(nse)) { for (SurfaceElementIndex sei : Range(nse))
{
const auto& sel = mesh[sei]; const auto& sel = mesh[sei];
if (sel.GetNP() == 3 && is_boundary_moved[sel.GetIndex()]) if (sel.GetNP() == 3 && is_boundary_moved[sel.GetIndex()])
for (auto pi : sel.PNums()) for (auto pi : sel.PNums())
@ -388,8 +417,10 @@ void BoundaryLayerTool ::FixSurfaceElements() {
auto neighbors = BuildNeighbors(points, mesh); auto neighbors = BuildNeighbors(points, mesh);
constexpr int N_STEPS = 32; constexpr int N_STEPS = 32;
for ([[maybe_unused]] auto i : Range(N_STEPS)) { for ([[maybe_unused]] auto i : Range(N_STEPS))
for (auto i : points.Range()) { {
for (auto i : points.Range())
{
auto pi = points[i]; auto pi = points[i];
auto& p_neighbors = neighbors[i]; auto& p_neighbors = neighbors[i];
@ -397,7 +428,8 @@ void BoundaryLayerTool ::FixSurfaceElements() {
double max_len = 0.0; double max_len = 0.0;
double sum_len = 0.0; double sum_len = 0.0;
for (const auto &s : p_neighbors) { for (const auto& s : p_neighbors)
{
auto v = getGW(s.pi) + corrections[s.pi]; auto v = getGW(s.pi) + corrections[s.pi];
auto len = v.Length2(); auto len = v.Length2();
sum_len += len; sum_len += len;
@ -415,10 +447,10 @@ void BoundaryLayerTool ::FixSurfaceElements() {
auto& correction = corrections[pi]; auto& correction = corrections[pi];
correction = 0.0; correction = 0.0;
for (const auto i : p_neighbors.Range()) { for (const auto i : p_neighbors.Range())
{
auto v = g_vectors[i]; auto v = g_vectors[i];
double weight = lambda * p_neighbors[i].weight + double weight = lambda * p_neighbors[i].weight + (1.0 - lambda) * v.Length2() / sum_len;
(1.0 - lambda) * v.Length2() / sum_len;
correction += weight * v; correction += weight * v;
} }
} }

View File

@ -1,9 +1,11 @@
#include "boundarylayer.hpp" #include "boundarylayer.hpp"
#include <core/array.hpp> #include <core/array.hpp>
namespace netgen { namespace netgen
{
struct Intersection_ { struct Intersection_
{
bool is_intersecting = false; bool is_intersecting = false;
double lam0 = -1, lam1 = -1; double lam0 = -1, lam1 = -1;
Point<3> p; Point<3> p;
@ -11,7 +13,8 @@ struct Intersection_ {
operator bool() const { return is_intersecting; } operator bool() const { return is_intersecting; }
}; };
struct GrowthVectorLimiter { struct GrowthVectorLimiter
{
typedef std::array<Point<3>, 2> Seg; typedef std::array<Point<3>, 2> Seg;
typedef std::array<Point<3>, 3> Trig; typedef std::array<Point<3>, 3> Trig;
@ -27,9 +30,8 @@ struct GrowthVectorLimiter {
Table<SurfaceElementIndex, PointIndex> p2sel; Table<SurfaceElementIndex, PointIndex> p2sel;
GrowthVectorLimiter(BoundaryLayerTool& tool_) GrowthVectorLimiter(BoundaryLayerTool& tool_)
: tool(tool_), params(tool_.params), mesh(tool_.mesh), : tool(tool_), params(tool_.params), mesh(tool_.mesh), height(tool_.total_height), growthvectors(tool_.growthvectors), map_from(mesh.Points().Size())
height(tool_.total_height), growthvectors(tool_.growthvectors), {
map_from(mesh.Points().Size()) {
changed_domains = tool.domains; changed_domains = tool.domains;
if (!params.outside) if (!params.outside)
changed_domains.Invert(); changed_domains.Invert();
@ -46,17 +48,20 @@ struct GrowthVectorLimiter {
auto SurfaceElementsRange () { return Range(tool.nse + tool.new_sels.Size()); } auto SurfaceElementsRange () { return Range(tool.nse + tool.new_sels.Size()); }
const auto &Get(SurfaceElementIndex sei) { const auto& Get (SurfaceElementIndex sei)
{
if (sei < tool.nse) if (sei < tool.nse)
return mesh[sei]; return mesh[sei];
return tool.new_sels[sei - tool.nse]; return tool.new_sels[sei - tool.nse];
} }
std::pair<double, double> GetMinMaxLimit(SurfaceElementIndex sei) { std::pair<double, double> GetMinMaxLimit (SurfaceElementIndex sei)
{
const auto& sel = Get(sei); const auto& sel = Get(sei);
double min_limit = GetLimit(sel[0]); double min_limit = GetLimit(sel[0]);
double max_limit = min_limit; double max_limit = min_limit;
for (auto i : IntRange(1, sel.GetNP())) { for (auto i : IntRange(1, sel.GetNP()))
{
auto limit = GetLimit(sel[i]); auto limit = GetLimit(sel[i]);
min_limit = min(min_limit, limit); min_limit = min(min_limit, limit);
max_limit = max(max_limit, limit); max_limit = max(max_limit, limit);
@ -64,13 +69,15 @@ struct GrowthVectorLimiter {
return {min_limit, max_limit}; return {min_limit, max_limit};
} }
double GetLimit(PointIndex pi) { double GetLimit (PointIndex pi)
{
if (pi <= tool.np) if (pi <= tool.np)
return limits[pi]; return limits[pi];
return limits[map_from[pi]]; return limits[map_from[pi]];
} }
bool SetLimit(PointIndex pi, double new_limit) { bool SetLimit (PointIndex pi, double new_limit)
{
double& limit = (pi <= tool.np) ? limits[pi] : limits[map_from[pi]]; double& limit = (pi <= tool.np) ? limits[pi] : limits[map_from[pi]];
if (limit <= new_limit) if (limit <= new_limit)
return false; return false;
@ -78,42 +85,46 @@ struct GrowthVectorLimiter {
return true; return true;
} }
bool ScaleLimit(PointIndex pi, double factor) { bool ScaleLimit (PointIndex pi, double factor)
{
double& limit = (pi <= tool.np) ? limits[pi] : limits[map_from[pi]]; double& limit = (pi <= tool.np) ? limits[pi] : limits[map_from[pi]];
return SetLimit(pi, limit * factor); return SetLimit(pi, limit * factor);
} }
Vec<3> GetVector(PointIndex pi_to, double shift = 1., Vec<3> GetVector (PointIndex pi_to, double shift = 1., bool apply_limit = false)
bool apply_limit = false) { {
auto [gw, height] = tool.growth_vector_map[pi_to]; auto [gw, height] = tool.growth_vector_map[pi_to];
if (apply_limit) if (apply_limit)
shift *= GetLimit(pi_to); shift *= GetLimit(pi_to);
return shift * height * (*gw); return shift * height * (*gw);
} }
Point<3> GetPoint(PointIndex pi_to, double shift = 1., Point<3> GetPoint (PointIndex pi_to, double shift = 1., bool apply_limit = false)
bool apply_limit = false) { {
if (pi_to <= tool.np || tool.growth_vector_map.count(pi_to) == 0) if (pi_to <= tool.np || tool.growth_vector_map.count(pi_to) == 0)
return mesh[pi_to]; return mesh[pi_to];
return mesh[pi_to] + GetVector(pi_to, shift, apply_limit); return mesh[pi_to] + GetVector(pi_to, shift, apply_limit);
} }
Point<3> GetMappedPoint(PointIndex pi_from, double shift = 1.) { Point<3> GetMappedPoint (PointIndex pi_from, double shift = 1.)
{
auto pi_to = tool.mapto[pi_from].Last(); auto pi_to = tool.mapto[pi_from].Last();
return GetPoint(pi_to, shift); return GetPoint(pi_to, shift);
} }
Seg GetMappedSeg(PointIndex pi_from, double shift = 1.) { Seg GetMappedSeg (PointIndex pi_from, double shift = 1.)
{
return {mesh[pi_from], GetMappedPoint(pi_from, shift)}; return {mesh[pi_from], GetMappedPoint(pi_from, shift)};
} }
Seg GetSeg(PointIndex pi_to, double shift = 1., bool apply_limit = false) { Seg GetSeg (PointIndex pi_to, double shift = 1., bool apply_limit = false)
{
return {GetPoint(pi_to, 0), GetPoint(pi_to, shift, apply_limit)}; return {GetPoint(pi_to, 0), GetPoint(pi_to, shift, apply_limit)};
} }
Trig GetTrig(SurfaceElementIndex sei, double shift = 0.0, Trig GetTrig (SurfaceElementIndex sei, double shift = 0.0, bool apply_limit = false)
bool apply_limit = false) { {
auto sel = Get(sei); auto sel = Get(sei);
Trig trig; Trig trig;
for (auto i : Range(3)) for (auto i : Range(3))
@ -121,7 +132,8 @@ struct GrowthVectorLimiter {
return trig; return trig;
} }
Trig GetMappedTrig(SurfaceElementIndex sei, double shift = 0.0) { Trig GetMappedTrig (SurfaceElementIndex sei, double shift = 0.0)
{
auto sel = Get(sei); auto sel = Get(sei);
Trig trig; Trig trig;
for (auto i : Range(3)) for (auto i : Range(3))
@ -129,8 +141,8 @@ struct GrowthVectorLimiter {
return trig; return trig;
} }
Trig GetSideTrig(SurfaceElementIndex sei, int index, double shift = 0.0, Trig GetSideTrig (SurfaceElementIndex sei, int index, double shift = 0.0, bool grow_first_vertex = true)
bool grow_first_vertex = true) { {
auto trig = GetMappedTrig(sei, 0.0); auto trig = GetMappedTrig(sei, 0.0);
auto sel = Get(sei); auto sel = Get(sei);
auto index1 = (index + 1) % 3; auto index1 = (index + 1) % 3;
@ -141,23 +153,24 @@ struct GrowthVectorLimiter {
} }
static constexpr double INTERSECTION_SAFETY = .9; static constexpr double INTERSECTION_SAFETY = .9;
bool LimitGrowthVector(PointIndex pi_to, SurfaceElementIndex sei, bool LimitGrowthVector (PointIndex pi_to, SurfaceElementIndex sei, double trig_shift, double seg_shift, bool check_prism_sides = false)
double trig_shift, double seg_shift, {
bool check_prism_sides = false) {
auto pi_from = map_from[pi_to]; auto pi_from = map_from[pi_to];
if (!pi_from.IsValid()) if (!pi_from.IsValid())
return false; return false;
auto seg = GetSeg(pi_to, seg_shift, true); auto seg = GetSeg(pi_to, seg_shift, true);
for (auto pi : Get(sei).PNums()) { for (auto pi : Get(sei).PNums())
{
if (pi == pi_from) if (pi == pi_from)
return false; return false;
if (map_from[pi] == pi_from) if (map_from[pi] == pi_from)
return false; return false;
} }
if (check_prism_sides || trig_shift > .0) { if (check_prism_sides || trig_shift > .0)
{
auto [trig_min_limit, trig_max_limit] = GetMinMaxLimit(sei); auto [trig_min_limit, trig_max_limit] = GetMinMaxLimit(sei);
if (GetLimit(pi_to) < trig_min_limit) if (GetLimit(pi_to) < trig_min_limit)
return false; return false;
@ -173,7 +186,8 @@ struct GrowthVectorLimiter {
}; };
double scaling = 1.0; double scaling = 1.0;
while (true) { while (true)
{
bool have_intersection = false; bool have_intersection = false;
auto seg = GetSeg(pi_to, scaling * seg_shift, true); auto seg = GetSeg(pi_to, scaling * seg_shift, true);
for (auto trig : getTrigs(scaling)) for (auto trig : getTrigs(scaling))
@ -190,12 +204,15 @@ struct GrowthVectorLimiter {
for (auto pi : Get(sei).PNums()) for (auto pi : Get(sei).PNums())
SetLimit(pi, new_limit); SetLimit(pi, new_limit);
return true; return true;
} else { }
else
{
auto trig = GetTrig(sei, 0.0); auto trig = GetTrig(sei, 0.0);
auto intersection = isIntersectingTrig(seg, trig); auto intersection = isIntersectingTrig(seg, trig);
// checking with original surface elements -> allow only half the distance // checking with original surface elements -> allow only half the distance
auto new_seg_limit = 0.40 * intersection.lam0 * seg_shift; auto new_seg_limit = 0.40 * intersection.lam0 * seg_shift;
if (intersection && new_seg_limit < GetLimit(pi_from)) { if (intersection && new_seg_limit < GetLimit(pi_from))
{
auto p0 = seg[0]; auto p0 = seg[0];
auto p1 = seg[1]; auto p1 = seg[1];
auto d = Dist(p0, p1); auto d = Dist(p0, p1);
@ -206,20 +223,23 @@ struct GrowthVectorLimiter {
} }
} }
void EqualizeLimits(double factor = .5) { void EqualizeLimits (double factor = .5)
{
static Timer t("GrowthVectorLimiter::EqualizeLimits"); static Timer t("GrowthVectorLimiter::EqualizeLimits");
PrintMessage(5, "GrowthVectorLimiter - equalize limits"); PrintMessage(5, "GrowthVectorLimiter - equalize limits");
RegionTimer reg(t); RegionTimer reg(t);
if (factor == 0.0) if (factor == 0.0)
return; return;
for (PointIndex pi : IntRange(tool.np, mesh.GetNP())) { for (PointIndex pi : IntRange(tool.np, mesh.GetNP()))
{
auto pi_from = map_from[pi]; auto pi_from = map_from[pi];
std::set<PointIndex> pis; std::set<PointIndex> pis;
for (auto sei : p2sel[pi]) for (auto sei : p2sel[pi])
for (auto pi_ : tool.new_sels[sei].PNums()) for (auto pi_ : tool.new_sels[sei].PNums())
pis.insert(pi_); pis.insert(pi_);
ArrayMem<double, 20> limits; ArrayMem<double, 20> limits;
for (auto pi1 : pis) { for (auto pi1 : pis)
{
auto limit = GetLimit(pi1); auto limit = GetLimit(pi1);
if (limit > 0.0) if (limit > 0.0)
limits.Append(GetLimit(pi1)); limits.Append(GetLimit(pi1));
@ -231,7 +251,8 @@ struct GrowthVectorLimiter {
double mean_limit = limits[limits.Size() / 2]; double mean_limit = limits[limits.Size() / 2];
// if mean limit is the maximum limit, take the average of second-highest // if mean limit is the maximum limit, take the average of second-highest
// and highest value // and highest value
if (mean_limit > limits[0] && mean_limit == limits.Last()) { if (mean_limit > limits[0] && mean_limit == limits.Last())
{
auto i = limits.Size() - 1; auto i = limits.Size() - 1;
while (limits[i] == limits.Last()) while (limits[i] == limits.Last())
i--; i--;
@ -245,7 +266,8 @@ struct GrowthVectorLimiter {
} }
} }
void LimitSelfIntersection(double safety = 1.4) { void LimitSelfIntersection (double safety = 1.4)
{
static Timer t("GrowthVectorLimiter::LimitSelfIntersection"); static Timer t("GrowthVectorLimiter::LimitSelfIntersection");
PrintMessage(5, "GrowthVectorLimiter - self intersection"); PrintMessage(5, "GrowthVectorLimiter - self intersection");
RegionTimer reg(t); RegionTimer reg(t);
@ -260,16 +282,20 @@ struct GrowthVectorLimiter {
return false; return false;
const auto sel = Get(sei); const auto sel = Get(sei);
auto np = sel.GetNP(); auto np = sel.GetNP();
for (auto i : Range(np)) { for (auto i : Range(np))
{
if (sel[i] > tool.np) if (sel[i] > tool.np)
return false; return false;
if (tool.mapto[sel[i]].Size() == 0) if (tool.mapto[sel[i]].Size() == 0)
return false; return false;
} }
for (auto i : Range(np)) { for (auto i : Range(np))
{
auto seg = GetMappedSeg(sel[i], shift * limits[sel[i]]); auto seg = GetMappedSeg(sel[i], shift * limits[sel[i]]);
for (auto fi : Range(np - 2)) { for (auto fi : Range(np - 2))
for (auto side : {true, false}) { {
for (auto side : {true, false})
{
auto trig = GetSideTrig(sei, i + fi, 1.0, side); auto trig = GetSideTrig(sei, i + fi, 1.0, side);
if (isIntersectingPlane(seg, trig)) if (isIntersectingPlane(seg, trig))
return true; return true;
@ -279,7 +305,8 @@ struct GrowthVectorLimiter {
return false; return false;
}; };
for (SurfaceElementIndex sei : mesh.SurfaceElements().Range()) { for (SurfaceElementIndex sei : mesh.SurfaceElements().Range())
{
auto sel = mesh[sei]; auto sel = mesh[sei];
const auto& fd = mesh.GetFaceDescriptor(sel.GetIndex()); const auto& fd = mesh.GetFaceDescriptor(sel.GetIndex());
if (sel.GetNP() == 4) if (sel.GetNP() == 4)
@ -289,7 +316,8 @@ struct GrowthVectorLimiter {
double shift = 1.0; double shift = 1.0;
const double step_factor = 0.9; const double step_factor = 0.9;
while (isIntersecting(sei, shift * safety)) { while (isIntersecting(sei, shift * safety))
{
shift *= step_factor; shift *= step_factor;
double max_limit = 0; double max_limit = 0;
for (auto i : Range(np)) for (auto i : Range(np))
@ -305,7 +333,8 @@ struct GrowthVectorLimiter {
// checks if a segment is intersecting a plane, spanned by three points, lam // checks if a segment is intersecting a plane, spanned by three points, lam
// will be set s.t. p_intersect = seg[0] + lam * (seg[1]-seg[0]) // will be set s.t. p_intersect = seg[0] + lam * (seg[1]-seg[0])
Intersection_ isIntersectingPlane (const Seg& seg, Intersection_ isIntersectingPlane (const Seg& seg,
const Trig & trig) { const Trig& trig)
{
auto t1 = trig[1] - trig[0]; auto t1 = trig[1] - trig[0];
auto t2 = trig[2] - trig[0]; auto t2 = trig[2] - trig[0];
auto n = Cross(t1, t2); auto n = Cross(t1, t2);
@ -315,14 +344,13 @@ struct GrowthVectorLimiter {
Intersection_ intersection; Intersection_ intersection;
intersection.lam0 = -v0n / (v1n - v0n); intersection.lam0 = -v0n / (v1n - v0n);
intersection.p = seg[0] + intersection.lam0 * (seg[1] - seg[0]); intersection.p = seg[0] + intersection.lam0 * (seg[1] - seg[0]);
intersection.is_intersecting = (v0n * v1n < 0) && intersection.is_intersecting = (v0n * v1n < 0) && (intersection.lam0 > -1e-8) && (intersection.lam0 < 1 + 1e-8);
(intersection.lam0 > -1e-8) &&
(intersection.lam0 < 1 + 1e-8);
return intersection; return intersection;
} }
Intersection_ isIntersectingTrig(const Seg &seg, const Trig &trig) { Intersection_ isIntersectingTrig (const Seg& seg, const Trig& trig)
{
auto intersection = isIntersectingPlane(seg, trig); auto intersection = isIntersectingPlane(seg, trig);
if (!intersection) if (!intersection)
return intersection; return intersection;
@ -338,39 +366,43 @@ struct GrowthVectorLimiter {
intersection.lam1 = 0; intersection.lam1 = 0;
double eps = 0.1; double eps = 0.1;
if (bary.X() >= -eps && bary.Y() >= -eps && if (bary.X() >= -eps && bary.Y() >= -eps && bary.X() + bary.Y() <= 1 + eps)
bary.X() + bary.Y() <= 1 + eps) { {
intersection.bary[0] = bary.X(); intersection.bary[0] = bary.X();
intersection.bary[1] = bary.Y(); intersection.bary[1] = bary.Y();
intersection.bary[2] = 1.0 - bary.X() - bary.Y(); intersection.bary[2] = 1.0 - bary.X() - bary.Y();
} else }
else
intersection.is_intersecting = false; intersection.is_intersecting = false;
return intersection; return intersection;
} }
Intersection_ isIntersectingTrig(PointIndex pi_from, PointIndex pi_to, Intersection_ isIntersectingTrig (PointIndex pi_from, PointIndex pi_to, SurfaceElementIndex sei, double shift = 0.0)
SurfaceElementIndex sei, {
double shift = 0.0) {
return isIntersectingTrig(GetSeg(pi_from, pi_to), GetTrig(sei, shift)); return isIntersectingTrig(GetSeg(pi_from, pi_to), GetTrig(sei, shift));
} }
void BuildSearchTree(double trig_shift) { void BuildSearchTree (double trig_shift)
{
static Timer t("BuildSearchTree"); static Timer t("BuildSearchTree");
RegionTimer rt(t); RegionTimer rt(t);
Box<3> bbox(Box<3>::EMPTY_BOX); Box<3> bbox(Box<3>::EMPTY_BOX);
for (PointIndex pi : mesh.Points().Range()) { for (PointIndex pi : mesh.Points().Range())
{
bbox.Add(mesh[pi]); bbox.Add(mesh[pi]);
bbox.Add(GetPoint(pi, 1.1)); bbox.Add(GetPoint(pi, 1.1));
} }
tree = make_unique<BoxTree<3>>(bbox); tree = make_unique<BoxTree<3>>(bbox);
for (auto sei : SurfaceElementsRange()) { for (auto sei : SurfaceElementsRange())
{
const auto& sel = Get(sei); const auto& sel = Get(sei);
auto sel_index = sel.GetIndex(); auto sel_index = sel.GetIndex();
Box<3> box(Box<3>::EMPTY_BOX); Box<3> box(Box<3>::EMPTY_BOX);
for (auto pi : sel.PNums()) { for (auto pi : sel.PNums())
{
box.Add(GetPoint(pi, 0.)); box.Add(GetPoint(pi, 0.));
box.Add(GetPoint(pi, trig_shift * GetLimit(pi))); box.Add(GetPoint(pi, trig_shift * GetLimit(pi)));
} }
@ -379,21 +411,21 @@ struct GrowthVectorLimiter {
} }
template <typename TFunc> template <typename TFunc>
void FindTreeIntersections(double trig_shift, double seg_shift, TFunc f, void FindTreeIntersections (double trig_shift, double seg_shift, TFunc f, BitArray* relevant_points = nullptr)
BitArray *relevant_points = nullptr) { {
static Timer t("GrowthVectorLimiter::FindTreeIntersections"); static Timer t("GrowthVectorLimiter::FindTreeIntersections");
RegionTimer rt(t); RegionTimer rt(t);
BuildSearchTree(trig_shift); BuildSearchTree(trig_shift);
auto np_new = mesh.Points().Size(); auto np_new = mesh.Points().Size();
int counter = 0; int counter = 0;
for (auto i : IntRange(tool.np, np_new)) { for (auto i : IntRange(tool.np, np_new))
{
PointIndex pi_to = i + PointIndex::BASE; PointIndex pi_to = i + PointIndex::BASE;
PointIndex pi_from = map_from[pi_to]; PointIndex pi_from = map_from[pi_to];
if (!pi_from.IsValid()) if (!pi_from.IsValid())
throw Exception("Point not mapped"); throw Exception("Point not mapped");
if (relevant_points && !relevant_points->Test(pi_to) && if (relevant_points && !relevant_points->Test(pi_to) && !relevant_points->Test(pi_from))
!relevant_points->Test(pi_from))
continue; continue;
Box<3> box(Box<3>::EMPTY_BOX); Box<3> box(Box<3>::EMPTY_BOX);
@ -401,8 +433,7 @@ struct GrowthVectorLimiter {
box.Add(GetPoint(pi_to, 0)); box.Add(GetPoint(pi_to, 0));
box.Add(GetPoint(pi_to, GetLimit(pi_from))); box.Add(GetPoint(pi_to, GetLimit(pi_from)));
tree->GetFirstIntersecting(box.PMin(), box.PMax(), tree->GetFirstIntersecting(box.PMin(), box.PMax(), [&] (SurfaceElementIndex sei) {
[&](SurfaceElementIndex sei) {
const auto& sel = Get(sei); const auto& sel = Get(sei);
if (sel.PNums().Contains(pi_from)) if (sel.PNums().Contains(pi_from))
return false; return false;
@ -415,18 +446,21 @@ struct GrowthVectorLimiter {
} }
} }
void FixIntersectingSurfaceTrigs() { void FixIntersectingSurfaceTrigs ()
{
static Timer t("GrowthVectorLimiter::FixIntersectingSurfaceTrigs"); static Timer t("GrowthVectorLimiter::FixIntersectingSurfaceTrigs");
RegionTimer reg(t); RegionTimer reg(t);
// check if surface trigs are intersecting each other // check if surface trigs are intersecting each other
bool changed = true; bool changed = true;
while (changed) { while (changed)
{
changed = false; changed = false;
Point3d pmin, pmax; Point3d pmin, pmax;
mesh.GetBox(pmin, pmax); mesh.GetBox(pmin, pmax);
BoxTree<3, SurfaceElementIndex> setree(pmin, pmax); BoxTree<3, SurfaceElementIndex> setree(pmin, pmax);
for (auto sei : SurfaceElementsRange()) { for (auto sei : SurfaceElementsRange())
{
const Element2d& tri = Get(sei); const Element2d& tri = Get(sei);
Box<3> box(Box<3>::EMPTY_BOX); Box<3> box(Box<3>::EMPTY_BOX);
@ -437,7 +471,8 @@ struct GrowthVectorLimiter {
setree.Insert(box, sei); setree.Insert(box, sei);
} }
for (auto sei : SurfaceElementsRange()) { for (auto sei : SurfaceElementsRange())
{
const Element2d& tri = Get(sei); const Element2d& tri = Get(sei);
Box<3> box(Box<3>::EMPTY_BOX); Box<3> box(Box<3>::EMPTY_BOX);
@ -452,12 +487,14 @@ struct GrowthVectorLimiter {
netgen::Point<3> tri1_points[3], tri2_points[3]; netgen::Point<3> tri1_points[3], tri2_points[3];
const netgen::Point<3>*trip1[3], *trip2[3]; const netgen::Point<3>*trip1[3], *trip2[3];
for (int k = 0; k < 3; k++) { for (int k = 0; k < 3; k++)
{
trip1[k] = &tri1_points[k]; trip1[k] = &tri1_points[k];
trip2[k] = &tri2_points[k]; trip2[k] = &tri2_points[k];
} }
auto set_points = [&] () { auto set_points = [&] () {
for (int k = 0; k < 3; k++) { for (int k = 0; k < 3; k++)
{
tri1_points[k] = GetPoint(tri[k], 1.0, true); tri1_points[k] = GetPoint(tri[k], 1.0, true);
tri2_points[k] = GetPoint(tri2[k], 1.0, true); tri2_points[k] = GetPoint(tri2[k], 1.0, true);
} }
@ -466,13 +503,13 @@ struct GrowthVectorLimiter {
set_points(); set_points();
int counter = 0; int counter = 0;
while (IntersectTriangleTriangle(&trip1[0], &trip2[0])) { while (IntersectTriangleTriangle(&trip1[0], &trip2[0]))
{
changed = true; changed = true;
PointIndex pi_max_limit = PointIndex::INVALID; PointIndex pi_max_limit = PointIndex::INVALID;
for (PointIndex pi : for (PointIndex pi :
{tri[0], tri[1], tri[2], tri2[0], tri2[1], tri2[2]}) {tri[0], tri[1], tri[2], tri2[0], tri2[1], tri2[2]})
if (pi > tool.np && (!pi_max_limit.IsValid() || if (pi > tool.np && (!pi_max_limit.IsValid() || GetLimit(pi) > GetLimit(pi_max_limit)))
GetLimit(pi) > GetLimit(pi_max_limit)))
pi_max_limit = map_from[pi]; pi_max_limit = map_from[pi];
if (!pi_max_limit.IsValid()) if (!pi_max_limit.IsValid())
@ -481,11 +518,13 @@ struct GrowthVectorLimiter {
ScaleLimit(pi_max_limit, 0.9); ScaleLimit(pi_max_limit, 0.9);
set_points(); set_points();
counter++; counter++;
if (counter > 20) { if (counter > 20)
{
cerr << "Limit intersecting surface elements: too many " cerr << "Limit intersecting surface elements: too many "
"limitation steps, sels: " "limitation steps, sels: "
<< Get(sei) << '\t' << Get(sej) << endl; << Get(sei) << '\t' << Get(sej) << endl;
for (auto si : {sei, sej}) { for (auto si : {sei, sej})
{
auto sel = Get(si); auto sel = Get(si);
cerr << "Limits: "; cerr << "Limits: ";
for (auto pi : sel.PNums()) for (auto pi : sel.PNums())
@ -505,7 +544,8 @@ struct GrowthVectorLimiter {
} }
} }
void LimitOriginalSurface(double safety) { void LimitOriginalSurface (double safety)
{
static Timer t("GrowthVectorLimiter::LimitOriginalSurface"); static Timer t("GrowthVectorLimiter::LimitOriginalSurface");
RegionTimer reg(t); RegionTimer reg(t);
PrintMessage(5, "GrowthVectorLimiter - original surface"); PrintMessage(5, "GrowthVectorLimiter - original surface");
@ -520,7 +560,8 @@ struct GrowthVectorLimiter {
}); });
} }
void LimitBoundaryLayer(double safety = 1.1) { void LimitBoundaryLayer (double safety = 1.1)
{
static Timer t("GrowthVectorLimiter::LimitBoundaryLayer"); static Timer t("GrowthVectorLimiter::LimitBoundaryLayer");
PrintMessage(5, "GrowthVectorLimiter - boundary layer"); PrintMessage(5, "GrowthVectorLimiter - boundary layer");
// now limit again with shifted surface elements // now limit again with shifted surface elements
@ -533,22 +574,24 @@ struct GrowthVectorLimiter {
relevant_points_next.SetSize(mesh.Points().Size() + 1); relevant_points_next.SetSize(mesh.Points().Size() + 1);
relevant_points.Set(); relevant_points.Set();
while (limit_counter) { while (limit_counter)
{
RegionTimer reg(t); RegionTimer reg(t);
size_t find_counter = 0; size_t find_counter = 0;
limit_counter = 0; limit_counter = 0;
relevant_points_next.Clear(); relevant_points_next.Clear();
FindTreeIntersections( FindTreeIntersections(
trig_shift, seg_shift, trig_shift, seg_shift, [&] (PointIndex pi_to, SurfaceElementIndex sei) {
[&](PointIndex pi_to, SurfaceElementIndex sei) {
find_counter++; find_counter++;
auto sel = Get(sei); auto sel = Get(sei);
if (LimitGrowthVector(pi_to, sei, trig_shift, seg_shift)) { if (LimitGrowthVector(pi_to, sei, trig_shift, seg_shift))
{
limit_counter++; limit_counter++;
relevant_points_next.SetBit(pi_to); relevant_points_next.SetBit(pi_to);
relevant_points_next.SetBit(map_from[pi_to]); relevant_points_next.SetBit(map_from[pi_to]);
for (auto pi : sel.PNums()) { for (auto pi : sel.PNums())
{
relevant_points_next.SetBit(pi); relevant_points_next.SetBit(pi);
if (pi >= tool.np) if (pi >= tool.np)
relevant_points_next.SetBit(map_from[pi]); relevant_points_next.SetBit(map_from[pi]);
@ -557,7 +600,8 @@ struct GrowthVectorLimiter {
} }
} }
for (auto pi : sel.PNums()) { for (auto pi : sel.PNums())
{
if (pi >= tool.np) if (pi >= tool.np)
return; return;
if (tool.mapto[pi].Size() == 0) if (tool.mapto[pi].Size() == 0)
@ -571,7 +615,8 @@ struct GrowthVectorLimiter {
} }
} }
void Perform() { void Perform ()
{
limits.SetSize(mesh.Points().Size()); limits.SetSize(mesh.Points().Size());
limits = 1.0; limits = 1.0;
@ -580,7 +625,8 @@ struct GrowthVectorLimiter {
// No smoothing in the last pass, to avoid generating new intersections // No smoothing in the last pass, to avoid generating new intersections
std::array smoothing_factors = {0.8, 0.7, 0.5, 0.0}; std::array smoothing_factors = {0.8, 0.7, 0.5, 0.0};
for (auto i_pass : Range(safeties.size())) { for (auto i_pass : Range(safeties.size()))
{
PrintMessage(4, "GrowthVectorLimiter pass ", i_pass); PrintMessage(4, "GrowthVectorLimiter pass ", i_pass);
double safety = safeties[i_pass]; double safety = safeties[i_pass];
// intersect segment with original surface elements // intersect segment with original surface elements
@ -600,8 +646,10 @@ struct GrowthVectorLimiter {
for (auto i : Range(growthvectors)) for (auto i : Range(growthvectors))
growthvectors[i] *= limits[i]; growthvectors[i] *= limits[i];
for (auto &[special_pi, special_point] : tool.special_boundary_points) { for (auto& [special_pi, special_point] : tool.special_boundary_points)
for (auto &group : special_point.growth_groups) { {
for (auto& group : special_point.growth_groups)
{
group.growth_vector *= limits[special_pi]; group.growth_vector *= limits[special_pi];
} }
} }