netgen/libsrc/meshing/meshclass.cpp
2022-04-29 13:05:38 +02:00

7437 lines
204 KiB
C++

#include <mystdlib.h>
#include <atomic>
#include <set>
#include "meshing.hpp"
#include "../general/gzstream.h"
#ifdef NG_PYTHON
// must be included to instantiate Archive::Shallow(NetgenGeometry&)
#include <core/python_ngcore.hpp>
#endif
namespace netgen
{
int Find3dElement (const Mesh& mesh,
const netgen::Point<3> & p,
double * lami,
const NgArray<int> * const indices,
BoxTree<3> * searchtree,
const bool allowindex = true)
{
int ne = 0;
NgArray<int> locels;
if (searchtree)
{
searchtree->GetIntersecting (p, p, locels);
ne = locels.Size();
}
else
ne = mesh.GetNE();
for (int i = 1; i <= ne; i++)
{
int ii;
if (searchtree)
ii = locels.Get(i);
else
ii = i;
if(indices != NULL && indices->Size() > 0)
{
bool contained = indices->Contains(mesh.VolumeElement(ii).GetIndex());
if((allowindex && !contained) || (!allowindex && contained)) continue;
}
if(mesh.PointContainedIn3DElement(p,lami,ii))
return ii;
}
// Not found, try uncurved variant:
for (int i = 1; i <= ne; i++)
{
int ii;
if (searchtree)
ii = locels.Get(i);
else
ii = i;
if(indices != NULL && indices->Size() > 0)
{
bool contained = indices->Contains(mesh.VolumeElement(ii).GetIndex());
if((allowindex && !contained) || (!allowindex && contained)) continue;
}
if(mesh.PointContainedIn3DElementOld(p,lami,ii))
{
(*testout) << "WARNING: found element of point " << p <<" only for uncurved mesh" << endl;
return ii;
}
}
return 0;
}
int Find2dElement (const Mesh& mesh,
const netgen::Point<3> & p,
double * lami,
const NgArray<int> * const indices,
BoxTree<3> * searchtree,
const bool allowindex = true)
{
double vlam[3];
int velement = 0;
if(mesh.GetNE())
velement = Find3dElement(mesh, p,vlam,NULL,searchtree,allowindex);
//(*testout) << "p " << p << endl;
//(*testout) << "velement " << velement << endl;
// first try to find a volume element containing p and project to face
if(velement!=0)
{
auto & topology = mesh.GetTopology();
// NgArray<int> faces;
// topology.GetElementFaces(velement,faces);
auto faces = Array<int> (topology.GetFaces(ElementIndex(velement-1)));
//(*testout) << "faces " << faces << endl;
for(int i=0; i<faces.Size(); i++)
faces[i] = topology.GetFace2SurfaceElement(faces[i]+1);
//(*testout) << "surfel " << faces << endl;
for(int i=0; i<faces.Size(); i++)
{
if(faces[i] == 0)
continue;
auto sel = mesh.SurfaceElement(faces[i]);
if(indices && indices->Size() != 0 && !indices->Contains(sel.GetIndex()))
continue;
auto & el = mesh.VolumeElement(velement);
if (el.GetType() == TET)
{
double lam4[4] = { vlam[0], vlam[1], vlam[2], 1.0-vlam[0]-vlam[1]-vlam[2] };
double face_lam = lam4[i];
if(face_lam < 1e-5)
{
// found volume point very close to a face -> use barycentric coordinates directly
lami[2] = 0.0;
for(auto j : Range(1,3))
for(auto k : Range(4))
if(sel[j] == el[k])
lami[j-1] = lam4[k]/(1.0-face_lam);
return faces[i];
}
}
if(mesh.PointContainedIn2DElement(p,lami,faces[i],true))
return faces[i];
}
}
// Did't find any matching face of a volume element, search 2d elements directly
int ne;
NgArray<int> locels;
// TODO: build search tree for surface elements
if (!mesh.GetNE() && searchtree)
{
searchtree->GetIntersecting (p, p, locels);
ne = locels.Size();
}
else
ne = mesh.GetNSE();
for (int i = 1; i <= ne; i++)
{
int ii;
if (locels.Size())
ii = locels.Get(i);
else
ii = i;
if(indices != NULL && indices->Size() > 0)
{
bool contained = indices->Contains(mesh.SurfaceElement(ii).GetIndex());
if((allowindex && !contained) || (!allowindex && contained)) continue;
}
if(mesh.PointContainedIn2DElement(p,lami,ii)) return ii;
}
return 0;
}
int Find1dElement (const Mesh& mesh,
const netgen::Point<3> & p,
double * lami,
const NgArray<int> * const indices,
BoxTree<3> * searchtree,
const bool allowindex = true)
{
double vlam[3];
int velement = Find2dElement(mesh, p, vlam, NULL, searchtree, allowindex);
if(velement == 0)
return 0;
vlam[2] = 1.-vlam[0] - vlam[1];
NgArray<int> edges;
auto & topology = mesh.GetTopology();
topology.GetSurfaceElementEdges(velement, edges);
Array<SegmentIndex> segs(edges.Size());
for(auto i : Range(edges))
segs[i] = topology.GetSegmentOfEdge(edges[i]);
for(auto i : Range(segs))
{
if(IsInvalid(segs[i]))
continue;
auto& el = mesh.SurfaceElement(velement);
if(el.GetType() == TRIG)
{
double seg_lam;
double lam;
auto seg = mesh.LineSegment(segs[i]);
for(auto k : Range(3))
{
if(seg[0] == el[k])
lam = vlam[k];
if(seg[1] == el[k])
seg_lam = vlam[k];
}
if(1.- seg_lam - lam < 1e-5)
{
// found point close to segment -> use barycentric coordinates directly
lami[0] = lam;
return int(segs[i])+1;
}
}
else
throw NgException("Quad not implemented yet!");
}
return 0;
}
static mutex buildsearchtree_mutex;
Mesh :: Mesh ()
: topology(*this), surfarea(*this)
{
boundaryedges = nullptr;
surfelementht = nullptr;
segmentht = nullptr;
lochfunc = {nullptr};
// mglevels = 1;
elementsearchtree = nullptr;
elementsearchtreets = NextTimeStamp();
majortimestamp = timestamp = NextTimeStamp();
hglob = 1e10;
hmin = 0;
numvertices = -1;
dimension = 3;
curvedelems = make_unique<CurvedElements> (*this);
clusters = make_unique<AnisotropicClusters> (*this);
ident = make_unique<Identifications> (*this);
hpelements = NULL;
coarsemesh = NULL;
ps_startelement = 0;
geomtype = NO_GEOM;
bcnames.SetSize(0);
cd2names.SetSize(0);
// this->comm = netgen :: ng_comm;
#ifdef PARALLEL
paralleltop = make_unique<ParallelMeshTopology> (*this);
#endif
}
Mesh :: ~Mesh()
{
// delete lochfunc;
// delete boundaryedges;
// delete surfelementht;
// delete segmentht;
// delete curvedelems;
// delete clusters;
// delete ident;
// delete elementsearchtree;
// delete coarsemesh;
// delete hpelements;
for (int i = 0; i < materials.Size(); i++)
delete materials[i];
for(int i = 0; i < userdata_int.Size(); i++)
delete userdata_int[i];
for(int i = 0; i < userdata_double.Size(); i++)
delete userdata_double[i];
for (int i = 0; i < bcnames.Size(); i++ )
delete bcnames[i];
for (int i = 0; i < cd2names.Size(); i++)
delete cd2names[i];
for (int i = 0; i < cd3names.Size(); i++)
delete cd3names[i];
// #ifdef PARALLEL
// delete paralleltop;
// #endif
}
void Mesh :: SetCommunicator(NgMPI_Comm acomm)
{
this->comm = acomm;
}
Mesh & Mesh :: operator= (const Mesh & mesh2)
{
geometry = mesh2.geometry;
dimension = mesh2.dimension;
points = mesh2.points;
segments = mesh2.segments;
surfelements = mesh2.surfelements;
volelements = mesh2.volelements;
lockedpoints = mesh2.lockedpoints;
facedecoding = mesh2.facedecoding;
dimension = mesh2.dimension;
hglob = mesh2.hglob;
hmin = mesh2.hmin;
maxhdomain = mesh2.maxhdomain;
materials.SetSize( mesh2.materials.Size() );
for ( int i = 0; i < mesh2.materials.Size(); i++ )
if ( mesh2.materials[i] ) materials[i] = new string ( *mesh2.materials[i] );
else materials[i] = 0;
std::map<const string*, string*> bcmap;
bcnames.SetSize( mesh2.bcnames.Size() );
for ( int i = 0; i < mesh2.bcnames.Size(); i++ )
{
if ( mesh2.bcnames[i] ) bcnames[i] = new string ( *mesh2.bcnames[i] );
else bcnames[i] = 0;
bcmap[mesh2.bcnames[i]] = bcnames[i];
}
// Remap string* members in FaceDescriptor to new mesh
for (auto & f : facedecoding)
f.SetBCName( bcmap[&f.GetBCName()] );
cd2names.SetSize(mesh2.cd2names.Size());
for (int i=0; i < mesh2.cd2names.Size(); i++)
if (mesh2.cd2names[i]) cd2names[i] = new string(*mesh2.cd2names[i]);
else cd2names[i] = 0;
cd3names.SetSize(mesh2.cd3names.Size());
for (int i=0; i < mesh2.cd3names.Size(); i++)
if (mesh2.cd3names[i]) cd3names[i] = new string(*mesh2.cd3names[i]);
else cd3names[i] = 0;
numvertices = mesh2.numvertices;
return *this;
}
void Mesh :: DeleteMesh()
{
NgLock lock(mutex);
lock.Lock();
points.SetSize(0);
segments.SetSize(0);
surfelements.SetSize(0);
volelements.SetSize(0);
lockedpoints.SetSize(0);
// surfacesonnode.SetSize(0);
// delete boundaryedges;
boundaryedges = nullptr;
segmentht = nullptr;
surfelementht = nullptr;
openelements.SetSize(0);
facedecoding.SetSize(0);
ident = make_unique<Identifications> (*this);
topology = MeshTopology (*this);
curvedelems = make_unique<CurvedElements> (*this);
clusters = make_unique<AnisotropicClusters> (*this);
for ( int i = 0; i < bcnames.Size(); i++ )
if ( bcnames[i] ) delete bcnames[i];
for (int i= 0; i< cd2names.Size(); i++)
if (cd2names[i]) delete cd2names[i];
#ifdef PARALLEL
paralleltop = make_unique<ParallelMeshTopology> (*this);
#endif
lock.UnLock();
timestamp = NextTimeStamp();
}
void Mesh :: ClearSurfaceElements()
{
surfelements.SetSize(0);
/*
for (int i = 0; i < facedecoding.Size(); i++)
facedecoding[i].firstelement = -1;
*/
for (auto & fd : facedecoding)
fd.firstelement = -1;
timestamp = NextTimeStamp();
}
PointIndex Mesh :: AddPoint (const Point3d & p, int layer)
{
return AddPoint (p, layer, INNERPOINT);
}
PointIndex Mesh :: AddPoint (const Point3d & p, int layer, POINTTYPE type)
{
// PointIndex pi = points.End();
PointIndex pi = *points.Range().end();
if (points.Size() == points.AllocSize())
{
NgLock lock(mutex);
lock.Lock();
points.Append ( MeshPoint (p, layer, type) );
lock.UnLock();
}
else
{
points.Append ( MeshPoint (p, layer, type) );
}
timestamp = NextTimeStamp();
return pi;
}
SegmentIndex Mesh :: AddSegment (const Segment & s)
{
NgLock lock(mutex);
lock.Lock();
timestamp = NextTimeStamp();
int maxn = max2 (s[0], s[1]);
maxn += 1-PointIndex::BASE;
/*
if (maxn > ptyps.Size())
{
int maxo = ptyps.Size();
ptyps.SetSize (maxn);
for (int i = maxo; i < maxn; i++)
ptyps[i] = INNERPOINT;
}
if (ptyps[s[0]] > EDGEPOINT) ptyps[s[0]] = EDGEPOINT;
if (ptyps[s[1]] > EDGEPOINT) ptyps[s[1]] = EDGEPOINT;
*/
if (maxn <= points.Size())
{
if (points[s[0]].Type() > EDGEPOINT)
points[s[0]].SetType (EDGEPOINT);
if (points[s[1]].Type() > EDGEPOINT)
points[s[1]].SetType (EDGEPOINT);
}
/*
else
{
cerr << "edge points nrs > points.Size" << endl;
}
*/
SegmentIndex si = segments.Size();
segments.Append (s);
lock.UnLock();
return si;
}
SurfaceElementIndex Mesh :: AddSurfaceElement (const Element2d & el)
{
timestamp = NextTimeStamp();
PointIndex maxn = el[0];
for (int i = 1; i < el.GetNP(); i++)
if (el[i] > maxn) maxn = el[i];
/*
maxn += 1-PointIndex::BASE;
if (maxn <= points.Size())
{
for (int i = 0; i < el.GetNP(); i++)
if (points[el[i]].Type() > SURFACEPOINT)
points[el[i]].SetType(SURFACEPOINT);
}
*/
// if (maxn < points.End())
if (maxn < *points.Range().end())
for (PointIndex pi : el.PNums())
if (points[pi].Type() > SURFACEPOINT)
points[pi].SetType(SURFACEPOINT);
SurfaceElementIndex si = surfelements.Size();
if (surfelements.AllocSize() == surfelements.Size())
{
NgLock lock(mutex);
lock.Lock();
surfelements.Append (el);
lock.UnLock();
}
else
{
surfelements.Append (el);
}
if (el.index<=0 || el.index > facedecoding.Size())
cerr << "has no facedecoding: fd.size = " << facedecoding.Size() << ", ind = " << el.index << endl;
surfelements.Last().next = facedecoding[el.index-1].firstelement;
facedecoding[el.index-1].firstelement = si;
if (SurfaceArea().Valid())
SurfaceArea().Add (el);
return si;
}
void Mesh :: SetSurfaceElement (SurfaceElementIndex sei, const Element2d & el)
{
int maxn = el[0];
for (int i = 1; i < el.GetNP(); i++)
if (el[i] > maxn) maxn = el[i];
maxn += 1-PointIndex::BASE;
if (maxn <= points.Size())
{
for (int i = 0; i < el.GetNP(); i++)
if (points[el[i]].Type() > SURFACEPOINT)
points[el[i]].SetType(SURFACEPOINT);
}
surfelements[sei] = el;
if (el.index > facedecoding.Size())
cerr << "has no facedecoding: fd.size = " << facedecoding.Size() << ", ind = " << el.index << endl;
// add lock-free to list ... slow, call RebuildSurfaceElementLists later
/*
surfelements[sei].next = facedecoding[el.index-1].firstelement;
auto & head = reinterpret_cast<atomic<SurfaceElementIndex>&> (facedecoding[el.index-1].firstelement);
while (!head.compare_exchange_weak (surfelements[sei].next, sei))
;
*/
/*
if (SurfaceArea().Valid())
SurfaceArea().Add (el);
*/
}
ElementIndex Mesh :: AddVolumeElement (const Element & el)
{
/*
int maxn = el[0];
for (int i = 1; i < el.GetNP(); i++)
if (el[i] > maxn) maxn = el[i];
maxn += 1-PointIndex::BASE;
*/
/*
if (maxn > ptyps.Size())
{
int maxo = ptyps.Size();
ptyps.SetSize (maxn);
for (i = maxo+PointIndex::BASE;
i < maxn+PointIndex::BASE; i++)
ptyps[i] = INNERPOINT;
}
*/
/*
if (maxn > points.Size())
{
cerr << "add vol element before point" << endl;
}
*/
int ve = volelements.Size();
if (volelements.Size() == volelements.AllocSize())
{
NgLock lock(mutex);
lock.Lock();
volelements.Append (el);
lock.UnLock();
}
else
{
volelements.Append (el);
}
volelements.Last().flags.illegal_valid = 0;
volelements.Last().flags.fixed = 0;
volelements.Last().flags.deleted = 0;
// while (volelements.Size() > eltyps.Size())
// eltyps.Append (FREEELEMENT);
timestamp = NextTimeStamp();
return ve;
}
void Mesh :: SetVolumeElement (ElementIndex ei, const Element & el)
{
/*
int maxn = el[0];
for (int i = 1; i < el.GetNP(); i++)
if (el[i] > maxn) maxn = el[i];
maxn += 1-PointIndex::BASE;
*/
volelements[ei] = el;
volelements[ei].flags.illegal_valid = 0;
volelements[ei].flags.fixed = 0;
volelements[ei].flags.deleted = 0;
}
void Mesh :: Save (const filesystem::path & filename) const
{
string ext0 = filename.stem().extension().string();
string ext = filename.extension().string();
if (ext0 == ".vol" && ext == ".bin")
{
BinaryOutArchive in(filename);
in & const_cast<Mesh&>(*this);
return;
}
ostream * outfile;
if (ext0 == ".vol" && ext == ".gz")
outfile = new ogzstream(filename);
else if (ext == ".vol")
outfile = new ofstream(filename);
else
outfile = new ogzstream(filesystem::path(filename).concat(".vol.gz"));
Save(*outfile);
delete outfile;
}
void Mesh :: Save (ostream & outfile) const
{
static Timer timer("Mesh::Save"); RegionTimer rt(timer);
int i, j;
double scale = 1; // globflags.GetNumFlag ("scale", 1);
int inverttets = 0; // globflags.GetDefineFlag ("inverttets");
int invertsurf = 0; // globflags.GetDefineFlag ("invertsurfacemesh");
outfile << "# Generated by NETGEN " << GetLibraryVersion("netgen") << endl << endl;
outfile << "mesh3d" << "\n";
outfile << "dimension\n" << GetDimension() << "\n";
outfile << "geomtype\n" << int(geomtype) << "\n";
outfile << "\n";
outfile << "# surfnr\tdomin\tdomout\ttlosurf\tbcprop\n";
outfile << "facedescriptors\n";
outfile << GetNFD() << "\n";
for(auto & fd : FaceDescriptors())
outfile << fd.SurfNr() << ' ' << fd.DomainIn() << ' ' << fd.DomainOut() << ' ' << fd.TLOSurface() << ' ' << fd.BCProperty() << '\n';
outfile << "\n";
outfile << "# surfnr bcnr domin domout np p1 p2 p3"
<< "\n";
switch (geomtype)
{
case GEOM_STL:
outfile << "surfaceelementsgi" << "\n";
break;
case GEOM_OCC: case GEOM_ACIS:
outfile << "surfaceelementsuv" << "\n";
break;
default:
outfile << "surfaceelements" << "\n";
}
outfile << GetNSE() << "\n";
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
{
if ((*this)[sei].GetIndex())
{
outfile << " " << GetFaceDescriptor((*this)[sei].GetIndex ()).SurfNr()+1;
outfile << " " << GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
outfile << " " << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainIn();
outfile << " " << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainOut();
}
else
outfile << " 0 0 0";
Element2d sel = (*this)[sei];
if (invertsurf)
sel.Invert();
outfile << " " << sel.GetNP();
for (j = 0; j < sel.GetNP(); j++)
outfile << " " << sel[j];
switch (geomtype)
{
case GEOM_STL:
for (j = 1; j <= sel.GetNP(); j++)
outfile << " " << sel.GeomInfoPi(j).trignum;
break;
case GEOM_OCC: case GEOM_ACIS:
for (j = 1; j <= sel.GetNP(); j++)
{
outfile << " " << sel.GeomInfoPi(j).u;
outfile << " " << sel.GeomInfoPi(j).v;
}
break;
default:
;
}
outfile << "\n";
}
outfile << "\n" << "\n";
outfile << "# matnr np p1 p2 p3 p4" << "\n";
outfile << "volumeelements" << "\n";
outfile << GetNE() << "\n";
for (ElementIndex ei = 0; ei < GetNE(); ei++)
{
outfile << (*this)[ei].GetIndex();
outfile << " " << (*this)[ei].GetNP();
Element el = (*this)[ei];
if (inverttets) el.Invert();
for (j = 0; j < el.GetNP(); j++)
outfile << " " << el[j];
outfile << "\n";
}
outfile << "\n" << "\n";
// outfile << " surf1 surf2 p1 p2" << "\n";
outfile << "# surfid 0 p1 p2 trignum1 trignum2 domin/surfnr1 domout/surfnr2 ednr1 dist1 ednr2 dist2 \n";
outfile << "edgesegmentsgi2" << "\n";
outfile << GetNSeg() << "\n";
for (i = 1; i <= GetNSeg(); i++)
{
const Segment & seg = LineSegment (i);
outfile.width(8);
outfile << seg.si; // 2D: bc number, 3D: wievielte Kante
outfile.width(8);
outfile << 0;
outfile.width(8);
outfile << seg[0];
outfile.width(8);
outfile << seg[1];
outfile << " ";
outfile.width(8);
outfile << seg.geominfo[0].trignum; // stl dreiecke
outfile << " ";
outfile.width(8);
outfile << seg.geominfo[1].trignum; // << endl; // stl dreieck
if (dimension == 3)
{
outfile << " ";
outfile.width(8);
outfile << seg.surfnr1+1;
outfile << " ";
outfile.width(8);
outfile << seg.surfnr2+1;
}
else
{
outfile << " ";
outfile.width(8);
outfile << seg.domin;
outfile << " ";
outfile.width(8);
outfile << seg.domout;
}
outfile << " ";
outfile.width(8);
outfile << seg.edgenr;
outfile << " ";
outfile.width(12);
outfile.precision(16);
outfile << seg.epgeominfo[0].dist; // splineparameter (2D)
outfile << " ";
outfile.width(8);
outfile.precision(16);
outfile << seg.epgeominfo[1].edgenr; // geometry dependent
outfile << " ";
outfile.width(12);
outfile << seg.epgeominfo[1].dist;
outfile << "\n";
}
outfile << "\n" << "\n";
outfile << "# X Y Z" << "\n";
outfile << "points" << "\n";
outfile << GetNP() << "\n";
outfile.precision(16);
outfile.setf (ios::fixed, ios::floatfield);
outfile.setf (ios::showpoint);
PointIndex pi;
for (pi = PointIndex::BASE;
pi < GetNP()+PointIndex::BASE; pi++)
{
outfile.width(22);
outfile << (*this)[pi](0)/scale << " ";
outfile.width(22);
outfile << (*this)[pi](1)/scale << " ";
outfile.width(22);
outfile << (*this)[pi](2)/scale << "\n";
}
outfile << "\n" << "\n";
outfile << "# pnum index" << "\n";
outfile << "pointelements" << "\n";
outfile << pointelements.Size() << "\n";
for (i = 0; i < pointelements.Size(); i++)
{
outfile.width(8);
outfile << pointelements[i].pnum << " ";
outfile.width(8);
outfile << pointelements[i].index << "\n";
}
if (ident -> GetMaxNr() > 0)
{
outfile << "identifications\n";
NgArray<INDEX_2> identpairs;
int cnt = 0;
for (i = 1; i <= ident -> GetMaxNr(); i++)
{
ident -> GetPairs (i, identpairs);
cnt += identpairs.Size();
}
outfile << cnt << "\n";
for (i = 1; i <= ident -> GetMaxNr(); i++)
{
ident -> GetPairs (i, identpairs);
for (j = 1; j <= identpairs.Size(); j++)
{
outfile.width (8);
outfile << identpairs.Get(j).I1();
outfile.width (8);
outfile << identpairs.Get(j).I2();
outfile.width (8);
outfile << i << "\n";
}
}
outfile << "identificationtypes\n";
outfile << ident -> GetMaxNr() << "\n";
for (i = 1; i <= ident -> GetMaxNr(); i++)
{
int type = ident -> GetType(i);
outfile << " " << type;
}
outfile << "\n";
}
int cntmat = 0;
for (i = 1; i <= materials.Size(); i++)
if (materials.Get(i) && materials.Get(i)->length())
cntmat++;
if (cntmat)
{
outfile << "materials" << endl;
outfile << cntmat << endl;
for (i = 1; i <= materials.Size(); i++)
if (materials.Get(i) && materials.Get(i)->length())
outfile << i << " " << *materials.Get(i) << endl;
}
int cntbcnames = 0;
for ( int ii = 0; ii < bcnames.Size(); ii++ )
if ( bcnames[ii] ) cntbcnames++;
if ( cntbcnames )
{
outfile << "\n\nbcnames" << endl << bcnames.Size() << endl;
for ( i = 0; i < bcnames.Size(); i++ )
outfile << i+1 << "\t" << GetBCName(i) << endl;
outfile << endl << endl;
}
int cntcd2names = 0;
for (int ii = 0; ii<cd2names.Size(); ii++)
if(cd2names[ii]) cntcd2names++;
if(cntcd2names)
{
outfile << "\n\ncd2names" << endl << cd2names.Size() << endl;
for (i=0; i<cd2names.Size(); i++)
outfile << i+1 << "\t" << GetCD2Name(i) << endl;
outfile << endl << endl;
}
int cntcd3names = 0;
for (int ii = 0; ii<cd3names.Size(); ii++)
if(cd3names[ii]) cntcd3names++;
if(cntcd3names)
{
outfile << "\n\ncd3names" << endl << cd3names.Size() << endl;
for (i=0; i<cd3names.Size(); i++)
outfile << i+1 << "\t" << GetCD3Name(i) << endl;
outfile << endl << endl;
}
/*
if ( GetDimension() == 2 )
{
for (i = 1; i <= GetNSeg(); i++)
{
const Segment & seg = LineSegment (i);
if ( ! bcprops.Contains(seg.si) && seg.GetBCName() != "" )
{
bcprops.Append(seg.si);
cntbcnames++;
}
}
}
else
{
for (sei = 0; sei < GetNSE(); sei++)
{
if ((*this)[sei].GetIndex())
{
int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
string name = GetFaceDescriptor((*this)[sei].GetIndex ()).BCName();
if ( !bcprops.Contains(bcp) &&
name != "" )
{
bcprops.Append(bcp);
cntbcnames++;
}
}
}
}
bcprops.SetSize(0);
if ( cntbcnames )
{
outfile << "\nbcnames" << endl << cntbcnames << endl;
if ( GetDimension() == 2 )
{
for (i = 1; i <= GetNSeg(); i++)
{
const Segment & seg = LineSegment (i);
if ( ! bcprops.Contains(seg.si) && seg.GetBCName() != "" )
{
bcprops.Append(seg.si);
outfile << seg.si << "\t" << seg.GetBCName() << endl;
}
}
}
else
{
for (sei = 0; sei < GetNSE(); sei++)
{
if ((*this)[sei].GetIndex())
{
int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
string name = GetFaceDescriptor((*this)[sei].GetIndex ()).BCName();
if ( !bcprops.Contains(bcp) &&
name != "" )
{
bcprops.Append(bcp);
outfile << bcp << "\t" << name << endl;
}
}
}
}
outfile << endl << endl;
}
*/
int cnt_sing = 0;
// for (PointIndex pi = points.Begin(); pi < points.End(); pi++)
// if ((*this)[pi].Singularity()>=1.) cnt_sing++;
for (auto & p : points)
if (p.Singularity() >= 1.) cnt_sing++;
if (cnt_sing)
{
outfile << "singular_points" << endl << cnt_sing << endl;
// for (PointIndex pi = points.Begin(); pi < points.End(); pi++)
for (PointIndex pi : points.Range())
if ((*this)[pi].Singularity()>=1.)
outfile << int(pi) << "\t" << (*this)[pi].Singularity() << endl;
}
cnt_sing = 0;
for (SegmentIndex si = 0; si < GetNSeg(); si++)
if ( segments[si].singedge_left ) cnt_sing++;
if (cnt_sing)
{
outfile << "singular_edge_left" << endl << cnt_sing << endl;
for (SegmentIndex si = 0; si < GetNSeg(); si++)
if ( segments[si].singedge_left )
outfile << int(si) << "\t" << segments[si].singedge_left << endl;
}
cnt_sing = 0;
for (SegmentIndex si = 0; si < GetNSeg(); si++)
if ( segments[si].singedge_right ) cnt_sing++;
if (cnt_sing)
{
outfile << "singular_edge_right" << endl << cnt_sing << endl;
for (SegmentIndex si = 0; si < GetNSeg(); si++)
if ( segments[si].singedge_right )
outfile << int(si) << "\t" << segments[si].singedge_right << endl;
}
cnt_sing = 0;
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular)
cnt_sing++;
if (cnt_sing)
{
outfile << "singular_face_inside" << endl << cnt_sing << endl;
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular)
outfile << int(sei) << "\t" <<
GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular << endl;
}
cnt_sing = 0;
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular) cnt_sing++;
if (cnt_sing)
{
outfile << "singular_face_outside" << endl << cnt_sing << endl;
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular)
outfile << int(sei) << "\t"
<< GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular << endl;
}
// Philippose - 09/07/2009
// Add mesh face colours to Netgen Vol file format
// The colours are saved in RGB triplets
int cnt_facedesc = GetNFD();
if (cnt_facedesc)
{
outfile << endl << endl << "# Surfnr Red Green Blue" << endl;
outfile << "face_colours" << endl << cnt_facedesc << endl;
outfile.precision(8);
outfile.setf(ios::fixed, ios::floatfield);
outfile.setf(ios::showpoint);
for(i = 1; i <= cnt_facedesc; i++)
{
outfile.width(8);
outfile << GetFaceDescriptor(i).SurfNr()+1 << " ";
outfile.width(12);
outfile << GetFaceDescriptor(i).SurfColour()[0] << " ";
outfile.width(12);
outfile << GetFaceDescriptor(i).SurfColour()[1] << " ";
outfile.width(12);
outfile << GetFaceDescriptor(i).SurfColour()[2];
outfile << endl;
}
outfile << "face_transparencies" << endl << cnt_facedesc << endl;
for(i = 1; i <= cnt_facedesc; i++)
{
outfile.width(8);
outfile << GetFaceDescriptor(i).SurfNr()+1 << " ";
outfile.width(12);
outfile << GetFaceDescriptor(i).SurfColour()[3] << endl;
}
}
outfile << endl << endl << "endmesh" << endl << endl;
if (geometry)
geometry -> SaveToMeshFile (outfile);
}
void Mesh :: Load (const filesystem::path & filename)
{
PrintMessage (1, "filename = ", filename);
string ext0 = filename.stem().extension().string();
string ext = filename.extension().string();
if (ext0 == ".vol" && ext == ".bin")
{
BinaryInArchive in(filename);
in & (*this);
return;
}
istream * infile = NULL;
if (ext0 == ".vol" && ext == ".gz")
infile = new igzstream (filename);
else
infile = new ifstream (filename);
if (! (infile -> good()) )
throw NgException ("mesh file not found");
Load(*infile);
delete infile;
}
// Reads mandatory integer and optional string token from input stream
// used for parsing bcnames, cd2names etc.
void ReadNumberAndName( istream & infile, int & i, string & s )
{
string line;
std::istringstream iline;
bool empty_line = true;
while(empty_line && infile)
{
std::getline(infile, line);
iline = std::istringstream{line};
iline >> i;
if(iline)
empty_line = false;
iline >> s;
}
if(!infile)
throw Exception("Reached end of file while parsing");
}
void Mesh :: Load (istream & infile)
{
static Timer timer("Mesh::Load"); RegionTimer rt(timer);
if (! (infile.good()) )
{
cout << "cannot load mesh" << endl;
throw NgException ("mesh file not found");
}
int rank = GetCommunicator().Rank();
int ntasks = GetCommunicator().Size();
char str[100];
int i, n;
double scale = 1; // globflags.GetNumFlag ("scale", 1);
int inverttets = 0; // globflags.GetDefineFlag ("inverttets");
int invertsurf = 0; // globflags.GetDefineFlag ("invertsurfacemesh");
facedecoding.SetSize(0);
bool endmesh = false;
while (infile.good() && !endmesh)
{
infile >> str;
if (strcmp (str, "dimension") == 0)
{
infile >> dimension;
}
if (strcmp (str, "geomtype") == 0)
{
int hi;
infile >> hi;
geomtype = GEOM_TYPE(hi);
}
if (strcmp (str, "facedescriptors") == 0)
{
int nfd;
infile >> nfd;
for(auto i : Range(nfd))
{
int surfnr, domin, domout, tlosurf, bcprop;
infile >> surfnr >> domin >> domout >> tlosurf >> bcprop;
auto faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, tlosurf));
GetFaceDescriptor(faceind).SetBCProperty(bcprop);
}
}
if (strcmp (str, "surfaceelements") == 0 || strcmp (str, "surfaceelementsgi")==0 || strcmp (str, "surfaceelementsuv") == 0)
{
static Timer t1("read surface elements"); RegionTimer rt1(t1);
infile >> n;
PrintMessage (3, n, " surface elements");
bool geominfo = strcmp (str, "surfaceelementsgi") == 0;
bool uv = strcmp (str, "surfaceelementsuv") == 0;
for (i = 1; i <= n; i++)
{
int surfnr, bcp, domin, domout, nep, faceind = 0;
infile >> surfnr >> bcp >> domin >> domout;
surfnr--;
bool invert_el = false;
/*
if (domin == 0)
{
invert_el = true;
Swap (domin, domout);
}
*/
for (int j = 1; j <= facedecoding.Size(); j++)
if (GetFaceDescriptor(j).SurfNr() == surfnr &&
GetFaceDescriptor(j).BCProperty() == bcp &&
GetFaceDescriptor(j).DomainIn() == domin &&
GetFaceDescriptor(j).DomainOut() == domout)
faceind = j;
// if (facedecoding.Size()) faceind = 1; // for timing
if (!faceind)
{
faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0));
GetFaceDescriptor(faceind).SetBCProperty (bcp);
}
infile >> nep;
if (!nep) nep = 3;
Element2d tri(nep);
tri.SetIndex(faceind);
for (int j = 1; j <= nep; j++)
infile >> tri.PNum(j);
if (geominfo)
for (int j = 1; j <= nep; j++)
infile >> tri.GeomInfoPi(j).trignum;
if (uv)
for (int j = 1; j <= nep; j++)
infile >> tri.GeomInfoPi(j).u >> tri.GeomInfoPi(j).v;
if (invertsurf) tri.Invert();
if (invert_el) tri.Invert();
AddSurfaceElement (tri);
}
}
if (strcmp (str, "volumeelements") == 0)
{
static Timer t1("read volume elements"); RegionTimer rt1(t1);
infile >> n;
PrintMessage (3, n, " volume elements");
for (i = 1; i <= n; i++)
{
Element el(TET);
int hi, nep;
infile >> hi;
if (hi == 0) hi = 1;
el.SetIndex(hi);
infile >> nep;
el.SetNP(nep);
el.SetCurved (nep != 4);
for (int j = 0; j < nep; j++)
infile >> (int&)(el[j]);
if (inverttets)
el.Invert();
AddVolumeElement (el);
}
}
if (strcmp (str, "edgesegments") == 0)
{
static Timer t1("read edge segments"); RegionTimer rt1(t1);
infile >> n;
for (i = 1; i <= n; i++)
{
Segment seg;
int hi;
infile >> seg.si >> hi >> seg[0] >> seg[1];
AddSegment (seg);
}
}
if (strcmp (str, "edgesegmentsgi") == 0)
{
static Timer t1("read edge segmentsgi"); RegionTimer rt1(t1);
infile >> n;
for (i = 1; i <= n; i++)
{
Segment seg;
int hi;
infile >> seg.si >> hi >> seg[0] >> seg[1]
>> seg.geominfo[0].trignum
>> seg.geominfo[1].trignum;
AddSegment (seg);
}
}
if (strcmp (str, "edgesegmentsgi2") == 0)
{
static Timer t1("read edge segmentsgi2"); RegionTimer rt1(t1);
int a;
infile >> a;
n=a;
PrintMessage (3, n, " curve elements");
for (i = 1; i <= n; i++)
{
Segment seg;
int hi;
infile >> seg.si >> hi >> seg[0] >> seg[1]
>> seg.geominfo[0].trignum
>> seg.geominfo[1].trignum
>> seg.surfnr1 >> seg.surfnr2
>> seg.edgenr
>> seg.epgeominfo[0].dist
>> seg.epgeominfo[1].edgenr
>> seg.epgeominfo[1].dist;
seg.epgeominfo[0].edgenr = seg.epgeominfo[1].edgenr;
seg.domin = seg.surfnr1;
seg.domout = seg.surfnr2;
seg.surfnr1--;
seg.surfnr2--;
AddSegment (seg);
}
}
if (strcmp (str, "points") == 0)
{
static Timer t1("read points"); RegionTimer rt1(t1);
infile >> n;
PrintMessage (3, n, " points");
for (i = 1; i <= n; i++)
{
Point3d p;
infile >> p.X() >> p.Y() >> p.Z();
p.X() *= scale;
p.Y() *= scale;
p.Z() *= scale;
AddPoint (p);
}
PrintMessage (3, n, " points done");
}
if (strcmp (str, "pointelements") == 0)
{
static Timer t1("read point elements"); RegionTimer rt1(t1);
infile >> n;
PrintMessage (3, n, " pointelements");
for (i = 1; i <= n; i++)
{
Element0d el;
infile >> el.pnum >> el.index;
pointelements.Append (el);
}
PrintMessage (3, n, " pointelements done");
}
if (strcmp (str, "identifications") == 0)
{
infile >> n;
PrintMessage (3, n, " identifications");
for (i = 1; i <= n; i++)
{
PointIndex pi1, pi2;
int ind;
infile >> pi1 >> pi2 >> ind;
ident -> Add (pi1, pi2, ind);
}
}
if (strcmp (str, "identificationtypes") == 0)
{
infile >> n;
PrintMessage (3, n, " identificationtypes");
for (i = 1; i <= n; i++)
{
int type;
infile >> type;
ident -> SetType(i,Identifications::ID_TYPE(type));
}
}
if (strcmp (str, "materials") == 0)
{
infile >> n;
for ( auto i : Range(n) )
{
int nr;
string mat;
ReadNumberAndName( infile, nr, mat );
SetMaterial (nr, mat.c_str());
}
}
if ( strcmp (str, "bcnames" ) == 0 )
{
infile >> n;
Array<int> bcnrs(n);
SetNBCNames(n);
for ( auto i : Range(n) )
{
string nextbcname;
ReadNumberAndName( infile, bcnrs[i], nextbcname );
bcnames[bcnrs[i]-1] = new string(nextbcname);
}
if ( GetDimension() == 3 )
{
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
{
if ((*this)[sei].GetIndex())
{
int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
if ( bcp <= n )
GetFaceDescriptor((*this)[sei].GetIndex ()).SetBCName(bcnames[bcp-1]);
else
GetFaceDescriptor((*this)[sei].GetIndex ()).SetBCName(0);
}
}
}
}
if ( strcmp (str, "cd2names" ) == 0)
{
infile >> n;
Array<int> cd2nrs(n);
SetNCD2Names(n);
for ( auto i : Range(n) )
{
string nextcd2name;
ReadNumberAndName( infile, cd2nrs[i], nextcd2name );
cd2names[cd2nrs[i]-1] = new string(nextcd2name);
}
if (GetDimension() < 2)
{
throw NgException("co dim 2 elements not implemented for dimension < 2");
}
}
if ( strcmp (str, "cd3names" ) == 0)
{
infile >> n;
Array<int> cd3nrs(n);
SetNCD3Names(n);
for( auto i : Range(n) )
{
string nextcd3name;
ReadNumberAndName( infile, cd3nrs[i], nextcd3name );
cd3names[cd3nrs[i]-1] = new string(nextcd3name);
}
if (GetDimension() < 3)
{
throw NgException("co dim 3 elements not implemented for dimension < 3");
}
}
if (strcmp (str, "singular_points") == 0)
{
infile >> n;
for (i = 1; i <= n; i++)
{
PointIndex pi;
double s;
infile >> pi;
infile >> s;
(*this)[pi].Singularity (s);
}
}
if (strcmp (str, "singular_edge_left") == 0)
{
infile >> n;
for (i = 1; i <= n; i++)
{
SegmentIndex si;
double s;
infile >> si;
infile >> s;
(*this)[si].singedge_left = s;
}
}
if (strcmp (str, "singular_edge_right") == 0)
{
infile >> n;
for (i = 1; i <= n; i++)
{
SegmentIndex si;
double s;
infile >> si;
infile >> s;
(*this)[si].singedge_right = s;
}
}
if (strcmp (str, "singular_face_inside") == 0)
{
infile >> n;
for (i = 1; i <= n; i++)
{
SurfaceElementIndex sei;
double s;
infile >> sei;
infile >> s;
GetFaceDescriptor((*this)[sei].GetIndex()).domin_singular = s;
}
}
if (strcmp (str, "singular_face_outside") == 0)
{
infile >> n;
for (i = 1; i <= n; i++)
{
SurfaceElementIndex sei;
double s;
infile >> sei;
infile >> s;
GetFaceDescriptor((*this)[sei].GetIndex()).domout_singular = s;
}
}
// Philippose - 09/07/2009
// Add mesh face colours to Netgen Vol file format
// The colours are read in as RGB triplets
if (strcmp (str, "face_colours") == 0)
{
int cnt_facedesc = GetNFD();
infile >> n;
if(n == cnt_facedesc)
{
for(i = 1; i <= n; i++)
{
int surfnr = 0;
Vec<4> surfcolour(0.0,1.0,0.0,1.0);
infile >> surfnr
>> surfcolour[0]
>> surfcolour[1]
>> surfcolour[2];
surfnr--;
if(surfnr > 0)
{
for(int facedesc = 1; facedesc <= cnt_facedesc; facedesc++)
{
if(surfnr == GetFaceDescriptor(facedesc).SurfNr())
{
GetFaceDescriptor(facedesc).SetSurfColour(surfcolour);
}
}
}
}
}
}
if (strcmp (str, "face_transparencies") == 0)
{
int cnt_facedesc = GetNFD();
infile >> n;
int index = 1;
if(n == cnt_facedesc)
{
for(int index = 1; index <= n; index++)
{
int surfnr;
double transp;
infile >> surfnr >> transp;
surfnr--;
if(surfnr > 0)
{
for(int facedesc = 1; facedesc <= cnt_facedesc; facedesc++)
{
if(surfnr == GetFaceDescriptor(facedesc).SurfNr())
{
auto& fd = GetFaceDescriptor(facedesc);
auto scol = fd.SurfColour();
scol[3] = transp;
fd.SetSurfColour(scol);
}
}
}
}
}
}
if (strcmp (str, "endmesh") == 0)
endmesh = true;
strcpy (str, "");
}
CalcSurfacesOfNode ();
if (ntasks == 1) // sequential run only
{
topology.Update();
clusters -> Update();
}
auto geo = geometryregister.LoadFromMeshFile (infile);
if(geo)
geometry = geo;
SetNextMajorTimeStamp();
// PrintMemInfo (cout);
}
void Mesh :: DoArchive (Archive & archive)
{
static Timer t("Mesh::Archive"); RegionTimer r(t);
#ifdef PARALLEL
auto comm = GetCommunicator();
if (archive.IsParallel() && comm.Size() > 1)
{ // parallel pickling supported only for output archives
if (comm.Rank() == 0)
archive & dimension;
auto rank = comm.Rank();
auto & partop = GetParallelTopology();
// global enumration of points:
// not used now, but will be needed for refined meshes
// GridFunciton pickling is not compatible, now
// should go to paralleltopology
// merge points
Array<PointIndex, PointIndex> globnum(points.Size());
PointIndex maxglob = -1;
for (auto pi : Range(points))
{
globnum[pi] = partop.GetGlobalPNum(pi);
// globnum[pi] = global_pnums[pi];
maxglob = max(globnum[pi], maxglob);
}
maxglob = comm.AllReduce (maxglob, MPI_MAX);
int numglob = maxglob+1-PointIndex::BASE;
if (comm.Rank() > 0)
{
comm.Send (globnum, 0, 200);
comm.Send (points, 0, 200);
}
else
{
Array<PointIndex, PointIndex> globnumi;
Array<MeshPoint, PointIndex> pointsi;
Array<MeshPoint, PointIndex> globpoints(numglob);
for (int j = 1; j < comm.Size(); j++)
{
comm.Recv (globnumi, j, 200);
comm.Recv (pointsi, j, 200);
for (auto i : Range(globnumi))
globpoints[globnumi[i]] = pointsi[i];
}
archive & globpoints;
}
// sending surface elements
auto copy_el2d (surfelements);
for (auto & el : copy_el2d)
for (auto & pi : el.PNums())
pi = globnum[pi];
if (comm.Rank() > 0)
comm.Send(copy_el2d, 0, 200);
else
{
Array<Element2d, SurfaceElementIndex> el2di;
for (int j = 1; j < comm.Size(); j++)
{
comm.Recv(el2di, j, 200);
for (auto & el : el2di)
copy_el2d += el;
}
archive & copy_el2d;
}
// sending volume elements
auto copy_el3d (volelements);
for (auto & el : copy_el3d)
for (auto & pi : el.PNums())
pi = globnum[pi];
if (comm.Rank() > 0)
comm.Send(copy_el3d, 0, 200);
else
{
Array<Element, ElementIndex> el3di;
for (int j = 1; j < comm.Size(); j++)
{
comm.Recv(el3di, j, 200);
for (auto & el : el3di)
copy_el3d += el;
}
archive & copy_el3d;
}
// sending 1D elements
auto copy_el1d (segments);
for (auto & el : copy_el1d)
for (auto & pi : el.pnums)
if (pi != PointIndex(PointIndex::INVALID))
pi = globnum[pi];
if (comm.Rank() > 0)
comm.Send(copy_el1d, 0, 200);
else
{
Array<Segment, SegmentIndex> el1di;
for (int j = 1; j < comm.Size(); j++)
{
comm.Recv(el1di, j, 200);
for (auto & el : el1di)
copy_el1d += el;
}
archive & copy_el1d;
}
if (comm.Rank() == 0)
{
archive & facedecoding;
archive & materials & bcnames & cd2names & cd3names;
auto mynv = numglob;
archive & mynv; // numvertices;
archive & *ident;
if(archive.GetVersion("netgen") >= "v6.2.2103-1")
{
archive.NeedsVersion("netgen", "v6.2.2103-1");
archive & vol_partition & surf_partition & seg_partition;
}
archive.Shallow(geometry);
archive & *curvedelems;
}
if (comm.Rank() == 0)
return;
}
#endif
archive & dimension;
archive & points;
archive & surfelements;
archive & volelements;
archive & segments;
archive & facedecoding;
archive & materials & bcnames & cd2names & cd3names;
archive & numvertices;
archive & *ident;
// cout << "archive, ngsversion = " << archive.GetVersion("netgen") << endl;
if(archive.GetVersion("netgen") >= "v6.2.2103-1")
{
// cout << "do the partition" << endl;
archive.NeedsVersion("netgen", "v6.2.2103-1");
archive & vol_partition & surf_partition & seg_partition;
}
// else
// cout << "no partition" << endl;
archive.Shallow(geometry);
archive & *curvedelems;
if (archive.Input())
{
int rank = GetCommunicator().Rank();
int ntasks = GetCommunicator().Size();
RebuildSurfaceElementLists();
CalcSurfacesOfNode ();
if (ntasks == 1) // sequential run only
{
topology.Update();
clusters -> Update();
}
SetNextMajorTimeStamp();
}
}
void Mesh :: Merge (const filesystem::path & filename, const int surfindex_offset)
{
ifstream infile(filename);
if (!infile.good())
throw NgException ("mesh file not found");
Merge(infile,surfindex_offset);
}
void Mesh :: Merge (istream & infile, const int surfindex_offset)
{
char str[100];
int i, n;
int inverttets = 0; // globflags.GetDefineFlag ("inverttets");
int oldnp = GetNP();
int oldne = GetNSeg();
int oldnd = GetNDomains();
for(SurfaceElementIndex si = 0; si < GetNSE(); si++)
for(int j=1; j<=(*this)[si].GetNP(); j++) (*this)[si].GeomInfoPi(j).trignum = -1;
int max_surfnr = 0;
for (i = 1; i <= GetNFD(); i++)
max_surfnr = max2 (max_surfnr, GetFaceDescriptor(i).SurfNr());
max_surfnr++;
if(max_surfnr < surfindex_offset) max_surfnr = surfindex_offset;
bool endmesh = false;
while (infile.good() && !endmesh)
{
infile >> str;
if (strcmp (str, "surfaceelementsgi") == 0 || strcmp (str, "surfaceelements") == 0)
{
infile >> n;
PrintMessage (3, n, " surface elements");
for (i = 1; i <= n; i++)
{
int j;
int surfnr, bcp, domin, domout, nep, faceind = 0;
infile >> surfnr >> bcp >> domin >> domout;
surfnr--;
if(domin > 0) domin += oldnd;
if(domout > 0) domout += oldnd;
surfnr += max_surfnr;
for (j = 1; j <= facedecoding.Size(); j++)
if (GetFaceDescriptor(j).SurfNr() == surfnr &&
GetFaceDescriptor(j).BCProperty() == bcp &&
GetFaceDescriptor(j).DomainIn() == domin &&
GetFaceDescriptor(j).DomainOut() == domout)
faceind = j;
if (!faceind)
{
faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0));
if(GetDimension() == 2) bcp++;
GetFaceDescriptor(faceind).SetBCProperty (bcp);
}
infile >> nep;
if (!nep) nep = 3;
Element2d tri(nep);
tri.SetIndex(faceind);
for (j = 1; j <= nep; j++)
{
infile >> tri.PNum(j);
tri.PNum(j) = tri.PNum(j) + oldnp;
}
if (strcmp (str, "surfaceelementsgi") == 0)
for (j = 1; j <= nep; j++)
{
infile >> tri.GeomInfoPi(j).trignum;
tri.GeomInfoPi(j).trignum = -1;
}
AddSurfaceElement (tri);
}
}
if (strcmp (str, "edgesegments") == 0)
{
infile >> n;
for (i = 1; i <= n; i++)
{
Segment seg;
int hi;
infile >> seg.si >> hi >> seg[0] >> seg[1];
seg[0] = seg[0] + oldnp;
seg[1] = seg[1] + oldnp;
AddSegment (seg);
}
}
if (strcmp (str, "edgesegmentsgi") == 0)
{
infile >> n;
for (i = 1; i <= n; i++)
{
Segment seg;
int hi;
infile >> seg.si >> hi >> seg[0] >> seg[1]
>> seg.geominfo[0].trignum
>> seg.geominfo[1].trignum;
seg[0] = seg[0] + oldnp;
seg[1] = seg[1] + oldnp;
AddSegment (seg);
}
}
if (strcmp (str, "edgesegmentsgi2") == 0)
{
infile >> n;
PrintMessage (3, n, " curve elements");
for (i = 1; i <= n; i++)
{
Segment seg;
int hi;
infile >> seg.si >> hi >> seg[0] >> seg[1]
>> seg.geominfo[0].trignum
>> seg.geominfo[1].trignum
>> seg.surfnr1 >> seg.surfnr2
>> seg.edgenr
>> seg.epgeominfo[0].dist
>> seg.epgeominfo[1].edgenr
>> seg.epgeominfo[1].dist;
seg.epgeominfo[0].edgenr = seg.epgeominfo[1].edgenr;
seg.surfnr1--;
seg.surfnr2--;
if(seg.surfnr1 >= 0) seg.surfnr1 = seg.surfnr1 + max_surfnr;
if(seg.surfnr2 >= 0) seg.surfnr2 = seg.surfnr2 + max_surfnr;
seg[0] = seg[0] +oldnp;
seg[1] = seg[1] +oldnp;
*testout << "old edgenr: " << seg.edgenr << endl;
seg.edgenr = seg.edgenr + oldne;
*testout << "new edgenr: " << seg.edgenr << endl;
seg.epgeominfo[1].edgenr = seg.epgeominfo[1].edgenr + oldne;
AddSegment (seg);
}
}
if (strcmp (str, "volumeelements") == 0)
{
infile >> n;
PrintMessage (3, n, " volume elements");
for (i = 1; i <= n; i++)
{
Element el(TET);
int hi, nep;
infile >> hi;
if (hi == 0) hi = 1;
el.SetIndex(hi+oldnd);
infile >> nep;
el.SetNP(nep);
for (int j = 0; j < nep; j++)
{
infile >> (int&)(el[j]);
el[j] = el[j]+oldnp;
}
if (inverttets)
el.Invert();
AddVolumeElement (el);
}
}
if (strcmp (str, "points") == 0)
{
infile >> n;
PrintMessage (3, n, " points");
for (i = 1; i <= n; i++)
{
Point3d p;
infile >> p.X() >> p.Y() >> p.Z();
AddPoint (p);
}
}
if (strcmp (str, "endmesh") == 0)
{
endmesh = true;
}
if (strcmp (str, "materials") == 0)
{
infile >> n;
for (i = 1; i <= n; i++)
{
int nr;
string mat;
infile >> nr >> mat;
SetMaterial (nr+oldnd, mat.c_str());
}
}
strcpy (str, "");
}
CalcSurfacesOfNode ();
topology.Update();
clusters -> Update();
SetNextMajorTimeStamp();
}
bool Mesh :: TestOk () const
{
for (ElementIndex ei = 0; ei < volelements.Size(); ei++)
{
for (int j = 0; j < 4; j++)
if ( (*this)[ei][j] <= PointIndex::BASE-1)
{
(*testout) << "El " << ei << " has 0 nodes: ";
for (int k = 0; k < 4; k++)
(*testout) << (*this)[ei][k];
break;
}
}
CheckMesh3D (*this);
return 1;
}
void Mesh :: SetAllocSize(int nnodes, int nsegs, int nsel, int nel)
{
points.SetAllocSize(nnodes);
segments.SetAllocSize(nsegs);
surfelements.SetAllocSize(nsel);
volelements.SetAllocSize(nel);
}
void Mesh :: BuildBoundaryEdges(bool rebuild)
{
static Timer t("Mesh::BuildBoundaryEdges"); RegionTimer reg(t);
if(!rebuild && boundaryedges)
return;
boundaryedges = make_unique<INDEX_2_CLOSED_HASHTABLE<int>>
(3 * (GetNSE() + GetNOpenElements()) + GetNSeg() + 1);
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
{
const Element2d & sel = surfelements[sei];
if (sel.IsDeleted()) continue;
// int si = sel.GetIndex();
if (sel.GetNP() <= 4)
for (int j = 0; j < sel.GetNP(); j++)
{
INDEX_2 i2;
i2.I1() = sel.PNumMod(j+1);
i2.I2() = sel.PNumMod(j+2);
i2.Sort();
boundaryedges->Set (i2, 1);
}
else if (sel.GetType()==TRIG6)
{
for (int j = 0; j < 3; j++)
{
INDEX_2 i2;
i2.I1() = sel[j];
i2.I2() = sel[(j+1)%3];
i2.Sort();
boundaryedges->Set (i2, 1);
}
}
else
cerr << "illegal element for buildboundaryedges" << endl;
}
for (int i = 0; i < openelements.Size(); i++)
{
const Element2d & sel = openelements[i];
for (int j = 0; j < sel.GetNP(); j++)
{
INDEX_2 i2;
i2.I1() = sel.PNumMod(j+1);
i2.I2() = sel.PNumMod(j+2);
i2.Sort();
boundaryedges->Set (i2, 1);
points[sel[j]].SetType(FIXEDPOINT);
}
}
for (int i = 0; i < GetNSeg(); i++)
{
const Segment & seg = segments[i];
INDEX_2 i2(seg[0], seg[1]);
i2.Sort();
boundaryedges -> Set (i2, 2);
//segmentht -> Set (i2, i);
}
}
void Mesh :: CalcSurfacesOfNode ()
{
static Timer t("Mesh::CalcSurfacesOfNode"); RegionTimer reg (t);
static Timer tn2se("Mesh::CalcSurfacesOfNode - surf on node");
static Timer tht("Mesh::CalcSurfacesOfNode - surfelementht");
// surfacesonnode.SetSize (GetNP());
TABLE<int,PointIndex::BASE> surfacesonnode(GetNP());
// delete boundaryedges;
// boundaryedges = NULL;
boundaryedges = nullptr;
// delete surfelementht;
// surfelementht = nullptr;
surfelementht = nullptr;
// delete segmentht;
/*
surfelementht = new INDEX_3_HASHTABLE<int> (GetNSE()/4 + 1);
segmentht = new INDEX_2_HASHTABLE<int> (GetNSeg() + 1);
*/
if (dimension == 3)
surfelementht = make_unique<INDEX_3_CLOSED_HASHTABLE<int>> (3*GetNSE() + 1);
segmentht = make_unique<INDEX_2_CLOSED_HASHTABLE<int>> (3*GetNSeg() + 1);
tn2se.Start();
if (dimension == 3)
/*
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
{
const Element2d & sel = surfelements[sei];
*/
for (const Element2d & sel : surfelements)
{
if (sel.IsDeleted()) continue;
int si = sel.GetIndex();
/*
for (int j = 0; j < sel.GetNP(); j++)
{
PointIndex pi = sel[j];
*/
for (PointIndex pi : sel.PNums())
{
if (!surfacesonnode[pi].Contains(si))
surfacesonnode.Add (pi, si);
/*
bool found = 0;
for (int k = 0; k < surfacesonnode[pi].Size(); k++)
if (surfacesonnode[pi][k] == si)
{
found = 1;
break;
}
if (!found)
surfacesonnode.Add (pi, si);
*/
}
}
/*
for (sei = 0; sei < GetNSE(); sei++)
{
const Element2d & sel = surfelements[sei];
if (sel.IsDeleted()) continue;
INDEX_3 i3;
i3.I1() = sel.PNum(1);
i3.I2() = sel.PNum(2);
i3.I3() = sel.PNum(3);
i3.Sort();
surfelementht -> PrepareSet (i3);
}
surfelementht -> AllocateElements();
*/
tn2se.Stop();
tht.Start();
if (dimension==3)
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
{
const Element2d & sel = surfelements[sei];
if (sel.IsDeleted()) continue;
INDEX_3 i3;
i3.I1() = sel.PNum(1);
i3.I2() = sel.PNum(2);
i3.I3() = sel.PNum(3);
i3.Sort();
surfelementht -> Set (i3, sei); // war das wichtig ??? sel.GetIndex());
}
tht.Stop();
// int np = GetNP();
if (dimension == 3)
{
static Timer t("Mesh::CalcSurfacesOfNode, pointloop"); RegionTimer reg (t);
/*
for (PointIndex pi = points.Begin(); pi < points.End(); pi++)
points[pi].SetType (INNERPOINT);
*/
for (auto & p : points)
p.SetType (INNERPOINT);
if (GetNFD() == 0)
{
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
{
const Element2d & sel = surfelements[sei];
if (sel.IsDeleted()) continue;
for (int j = 0; j < sel.GetNP(); j++)
{
PointIndex pi = SurfaceElement(sei)[j];
points[pi].SetType(FIXEDPOINT);
}
}
}
else
{
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
{
const Element2d & sel = surfelements[sei];
if (sel.IsDeleted()) continue;
for (int j = 0; j < sel.GetNP(); j++)
{
PointIndex pi = sel[j];
int ns = surfacesonnode[pi].Size();
if (ns == 1)
points[pi].SetType(SURFACEPOINT);
if (ns == 2)
points[pi].SetType(EDGEPOINT);
if (ns >= 3)
points[pi].SetType(FIXEDPOINT);
}
}
}
}
/*
for (int i = 0; i < segments.Size(); i++)
{
const Segment & seg = segments[i];
*/
for (const Segment & seg : segments)
{
for (int j = 1; j <= 2; j++)
{
PointIndex hi = (j == 1) ? seg[0] : seg[1];
if (points[hi].Type() == INNERPOINT ||
points[hi].Type() == SURFACEPOINT)
points[hi].SetType(EDGEPOINT);
}
}
for (int i = 0; i < lockedpoints.Size(); i++)
points[lockedpoints[i]].SetType(FIXEDPOINT);
for(const auto& pointel : pointelements)
points[pointel.pnum].SetType(FIXEDPOINT);
/*
for (i = 0; i < openelements.Size(); i++)
{
const Element2d & sel = openelements[i];
for (j = 0; j < sel.GetNP(); j++)
{
INDEX_2 i2;
i2.I1() = sel.PNumMod(j+1);
i2.I2() = sel.PNumMod(j+2);
i2.Sort();
boundaryedges->Set (i2, 1);
points[sel[j]].SetType(FIXEDPOINT);
}
}
*/
// eltyps.SetSize (GetNE());
// eltyps = FREEELEMENT;
for (int i = 0; i < GetNSeg(); i++)
{
const Segment & seg = segments[i];
INDEX_2 i2(seg[0], seg[1]);
i2.Sort();
//boundaryedges -> Set (i2, 2);
segmentht -> Set (i2, i);
}
}
// NgBitArray base is PointIndex::BASE ...
void Mesh :: FixPoints (const NgBitArray & fixpoints)
{
if (fixpoints.Size() != GetNP())
{
cerr << "Mesh::FixPoints: sizes don't fit" << endl;
return;
}
int np = GetNP();
/*
for (int i = 1; i <= np; i++)
if (fixpoints.Test(i))
{
points.Elem(i).SetType (FIXEDPOINT);
}
*/
for (PointIndex pi : points.Range())
if (fixpoints.Test(pi))
points[pi].SetType(FIXEDPOINT);
}
void Mesh :: FindOpenElements (int dom)
{
static Timer t("Mesh::FindOpenElements"); RegionTimer reg (t);
static Timer t_table("Mesh::FindOpenElements - build table");
static Timer t_pointloop("Mesh::FindOpenElements - pointloop");
int np = GetNP();
int ne = GetNE();
int nse = GetNSE();
t_table.Start();
auto elsonpoint = ngcore::CreateSortedTable<ElementIndex, PointIndex>( volelements.Range(),
[&](auto & table, ElementIndex ei)
{
const Element & el = (*this)[ei];
if (dom == 0 || dom == el.GetIndex())
{
if (el.GetNP() == 4)
{
INDEX_4 i4(el[0], el[1], el[2], el[3]);
i4.Sort();
table.Add (PointIndex(i4.I1()), ei);
table.Add (PointIndex(i4.I2()), ei);
}
else
{
for (PointIndex pi : el.PNums())
table.Add(pi, ei);
}
}
}, GetNP());
NgArray<int,PointIndex::BASE> numonpoint(np);
/*
numonpoint = 0;
for (ElementIndex ei = 0; ei < ne; ei++)
{
const Element & el = (*this)[ei];
if (dom == 0 || dom == el.GetIndex())
{
if (el.GetNP() == 4)
{
INDEX_4 i4(el[0], el[1], el[2], el[3]);
i4.Sort();
numonpoint[i4.I1()]++;
numonpoint[i4.I2()]++;
}
else
for (int j = 0; j < el.GetNP(); j++)
numonpoint[el[j]]++;
}
}
TABLE<ElementIndex,PointIndex::BASE> elsonpoint(numonpoint);
for (ElementIndex ei = 0; ei < ne; ei++)
{
const Element & el = (*this)[ei];
if (dom == 0 || dom == el.GetIndex())
{
if (el.GetNP() == 4)
{
INDEX_4 i4(el[0], el[1], el[2], el[3]);
i4.Sort();
elsonpoint.Add (i4.I1(), ei);
elsonpoint.Add (i4.I2(), ei);
}
else
for (int j = 0; j < el.GetNP(); j++)
elsonpoint.Add (el[j], ei);
}
}
*/
t_table.Stop();
NgArray<bool, 1> hasface(GetNFD());
for (int i = 1; i <= GetNFD(); i++)
{
int domin = GetFaceDescriptor(i).DomainIn();
int domout = GetFaceDescriptor(i).DomainOut();
hasface[i] =
( dom == 0 && (domin != 0 || domout != 0) ) ||
( dom != 0 && (domin == dom || domout == dom) );
}
numonpoint = 0;
for (SurfaceElementIndex sii = 0; sii < nse; sii++)
{
int ind = surfelements[sii].GetIndex();
/*
if (
GetFaceDescriptor(ind).DomainIn() &&
(dom == 0 || dom == GetFaceDescriptor(ind).DomainIn())
||
GetFaceDescriptor(ind).DomainOut() &&
(dom == 0 || dom == GetFaceDescriptor(ind).DomainOut())
)
*/
if (hasface[ind])
{
/*
Element2d hel = surfelements[i];
hel.NormalizeNumbering();
numonpoint[hel[0]]++;
*/
const Element2d & hel = surfelements[sii];
int mini = 0;
for (int j = 1; j < hel.GetNP(); j++)
if (hel[j] < hel[mini])
mini = j;
numonpoint[hel[mini]]++;
}
}
TABLE<SurfaceElementIndex,PointIndex::BASE> selsonpoint(numonpoint);
for (SurfaceElementIndex sii = 0; sii < nse; sii++)
{
int ind = surfelements[sii].GetIndex();
/*
if (
GetFaceDescriptor(ind).DomainIn() &&
(dom == 0 || dom == GetFaceDescriptor(ind).DomainIn())
||
GetFaceDescriptor(ind).DomainOut() &&
(dom == 0 || dom == GetFaceDescriptor(ind).DomainOut())
)
*/
if (hasface[ind])
{
/*
Element2d hel = surfelements[i];
hel.NormalizeNumbering();
selsonpoint.Add (hel[0], i);
*/
const Element2d & hel = surfelements[sii];
int mini = 0;
for (int j = 1; j < hel.GetNP(); j++)
if (hel[j] < hel[mini])
mini = j;
selsonpoint.Add (hel[mini], sii);
}
}
// PointIndex pi;
// SurfaceElementIndex sei;
// Element2d hel;
struct tval { int index; PointIndex p4; };
openelements.SetSize(0);
t_pointloop.Start();
/*
INDEX_3_CLOSED_HASHTABLE<tval> faceht(100);
for (PointIndex pi : points.Range())
if (selsonpoint[pi].Size()+elsonpoint[pi].Size())
{
faceht.SetSize (2 * selsonpoint[pi].Size() + 4 * elsonpoint[pi].Size());
for (SurfaceElementIndex sei : selsonpoint[pi])
{
Element2d hel = SurfaceElement(sei);
if (hel.GetType() == TRIG6) hel.SetType(TRIG);
int ind = hel.GetIndex();
if (GetFaceDescriptor(ind).DomainIn() &&
(dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) )
{
hel.NormalizeNumbering();
if (hel.PNum(1) == pi)
{
INDEX_3 i3(hel[0], hel[1], hel[2]);
tval i2;
i2.index = GetFaceDescriptor(ind).DomainIn();
i2.p4 = (hel.GetNP() == 3)
? PointIndex (PointIndex::INVALID)
: hel.PNum(4);
faceht.Set (i3, i2);
}
}
if (GetFaceDescriptor(ind).DomainOut() &&
(dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) )
{
hel.Invert();
hel.NormalizeNumbering();
if (hel.PNum(1) == pi)
{
INDEX_3 i3(hel[0], hel[1], hel[2]);
tval i2;
i2.index = GetFaceDescriptor(ind).DomainOut();
i2.p4 = (hel.GetNP() == 3)
? PointIndex (PointIndex::INVALID)
: hel.PNum(4);
faceht.Set (i3, i2);
}
}
}
for (ElementIndex ei : elsonpoint[pi])
{
const Element & el = VolumeElement(ei);
if (dom == 0 || el.GetIndex() == dom)
{
for (int j = 1; j <= el.GetNFaces(); j++)
{
Element2d hel(TRIG);
el.GetFace (j, hel);
hel.Invert();
hel.NormalizeNumbering();
if (hel[0] == pi)
{
INDEX_3 i3(hel[0], hel[1], hel[2]);
if (faceht.Used (i3))
{
tval i2 = faceht.Get(i3);
if (i2.index == el.GetIndex())
{
i2.index = PointIndex::BASE-1;
faceht.Set (i3, i2);
}
else
{
if (i2.index == 0)
{
PrintSysError ("more elements on face");
(*testout) << "more elements on face!!!" << endl;
(*testout) << "el = " << el << endl;
(*testout) << "hel = " << hel << endl;
(*testout) << "face = " << i3 << endl;
(*testout) << "points = " << endl;
for (int jj = 1; jj <= 3; jj++)
(*testout) << "p = " << Point(i3.I(jj)) << endl;
}
}
}
else
{
hel.Invert();
hel.NormalizeNumbering();
INDEX_3 i3(hel[0], hel[1], hel[2]);
tval i2;
i2.index = el.GetIndex();
i2.p4 = (hel.GetNP() == 3)
? PointIndex (PointIndex::INVALID)
: hel[3];
faceht.Set (i3, i2);
}
}
}
}
}
for (int i = 0; i < faceht.Size(); i++)
if (faceht.UsedPos (i))
{
INDEX_3 i3;
//INDEX_2 i2;
tval i2;
faceht.GetData (i, i3, i2);
if (i2.index != PointIndex::BASE-1)
{
Element2d tri ( (i2.p4 == PointIndex::BASE-1) ? TRIG : QUAD);
for (int l = 0; l < 3; l++)
tri[l] = i3.I(l+1);
tri.PNum(4) = i2.p4;
tri.SetIndex (i2.index);
openelements.Append (tri);
}
}
}
*/
size_t numtasks = 4*ngcore::TaskManager::GetNumThreads();
Array<Array<Element2d>> thread_openelements(numtasks);
ParallelJob
( [&](TaskInfo & ti)
{
auto myrange = points.Range().Split(ti.task_nr, ti.ntasks);
INDEX_3_CLOSED_HASHTABLE<tval> faceht(100);
for (PointIndex pi : myrange)
if (selsonpoint[pi].Size()+elsonpoint[pi].Size())
{
faceht.SetSize (2 * selsonpoint[pi].Size() + 4 * elsonpoint[pi].Size());
for (SurfaceElementIndex sei : selsonpoint[pi])
{
Element2d hel = SurfaceElement(sei);
if (hel.GetType() == TRIG6) hel.SetType(TRIG);
int ind = hel.GetIndex();
if (GetFaceDescriptor(ind).DomainIn() &&
(dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) )
{
hel.NormalizeNumbering();
if (hel.PNum(1) == pi)
{
INDEX_3 i3(hel[0], hel[1], hel[2]);
tval i2;
i2.index = GetFaceDescriptor(ind).DomainIn();
i2.p4 = (hel.GetNP() == 3)
? PointIndex (PointIndex::INVALID)
: hel.PNum(4);
faceht.Set (i3, i2);
}
}
if (GetFaceDescriptor(ind).DomainOut() &&
(dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) )
{
hel.Invert();
hel.NormalizeNumbering();
if (hel.PNum(1) == pi)
{
INDEX_3 i3(hel[0], hel[1], hel[2]);
tval i2;
i2.index = GetFaceDescriptor(ind).DomainOut();
i2.p4 = (hel.GetNP() == 3)
? PointIndex (PointIndex::INVALID)
: hel.PNum(4);
faceht.Set (i3, i2);
}
}
}
for (ElementIndex ei : elsonpoint[pi])
{
const Element & el = VolumeElement(ei);
if (dom == 0 || el.GetIndex() == dom)
{
for (int j = 1; j <= el.GetNFaces(); j++)
{
Element2d hel(TRIG);
el.GetFace (j, hel);
hel.Invert();
hel.NormalizeNumbering();
if (hel[0] == pi)
{
INDEX_3 i3(hel[0], hel[1], hel[2]);
if (faceht.Used (i3))
{
tval i2 = faceht.Get(i3);
if (i2.index == el.GetIndex())
{
i2.index = PointIndex::BASE-1;
faceht.Set (i3, i2);
}
else
{
if (i2.index == 0)
{
PrintSysError ("more elements on face");
(*testout) << "more elements on face!!!" << endl;
(*testout) << "el = " << el << endl;
(*testout) << "hel = " << hel << endl;
(*testout) << "face = " << i3 << endl;
(*testout) << "points = " << endl;
for (int jj = 1; jj <= 3; jj++)
(*testout) << "p = " << Point(i3.I(jj)) << endl;
}
}
}
else
{
hel.Invert();
hel.NormalizeNumbering();
INDEX_3 i3(hel[0], hel[1], hel[2]);
tval i2;
i2.index = el.GetIndex();
i2.p4 = (hel.GetNP() == 3)
? PointIndex (PointIndex::INVALID)
: hel[3];
faceht.Set (i3, i2);
}
}
}
}
}
for (int i = 0; i < faceht.Size(); i++)
if (faceht.UsedPos (i))
{
INDEX_3 i3;
tval i2;
faceht.GetData (i, i3, i2);
if (i2.index != PointIndex::BASE-1)
{
Element2d tri ( (i2.p4 == PointIndex::BASE-1) ? TRIG : QUAD);
for (int l = 0; l < 3; l++)
tri[l] = i3.I(l+1);
tri.PNum(4) = i2.p4;
tri.SetIndex (i2.index);
thread_openelements[ti.task_nr].Append (tri);
}
}
}}, numtasks);
for (auto & a : thread_openelements)
for (auto & el : a)
openelements.Append (el);
t_pointloop.Stop();
int cnt3 = 0;
for (int i = 0; i < openelements.Size(); i++)
if (openelements[i].GetNP() == 3)
cnt3++;
int cnt4 = openelements.Size() - cnt3;
MyStr treequad;
if (cnt4)
treequad = MyStr(" (") + MyStr(cnt3) + MyStr (" + ") +
MyStr(cnt4) + MyStr(")");
PrintMessage (5, openelements.Size(), treequad, " open elements");
BuildBoundaryEdges();
for (int i = 1; i <= openelements.Size(); i++)
{
const Element2d & sel = openelements.Get(i);
if (boundaryedges)
for (int j = 1; j <= sel.GetNP(); j++)
{
INDEX_2 i2;
i2.I1() = sel.PNumMod(j);
i2.I2() = sel.PNumMod(j+1);
i2.Sort();
boundaryedges->Set (i2, 1);
}
for (int j = 1; j <= 3; j++)
{
PointIndex pi = sel.PNum(j);
// if (pi < points.End())
if (pi < *points.Range().end())
points[pi].SetType (FIXEDPOINT);
}
}
/*
for (i = 1; i <= GetNSeg(); i++)
{
const Segment & seg = LineSegment(i);
INDEX_2 i2(seg[0], seg[1]);
i2.Sort();
if (!boundaryedges->Used (i2))
cerr << "WARNING: no boundedge, but seg edge: " << i2 << endl;
boundaryedges -> Set (i2, 2);
segmentht -> Set (i2, i-1);
}
*/
}
bool Mesh :: HasOpenQuads () const
{
int no = GetNOpenElements();
for (int i = 0; i < no; i++)
if (openelements[i].GetNP() == 4)
return true;
return false;
}
void Mesh :: FindOpenSegments (int surfnr)
{
// int i, j, k;
// new version, general elements
// hash index: pnum1-2, surfnr
// hash data : surfel-nr (pos) or segment nr(neg)
INDEX_3_HASHTABLE<int> faceht(4 * GetNSE()+GetNSeg()+1);
PrintMessage (5, "Test Opensegments");
for (int i = 1; i <= GetNSeg(); i++)
{
const Segment & seg = LineSegment (i);
if (surfnr == 0 || seg.si == surfnr)
{
INDEX_3 key(seg[0], seg[1], seg.si);
int data = -i;
if (faceht.Used (key))
{
cerr << "ERROR: Segment " << seg << " already used" << endl;
(*testout) << "ERROR: Segment " << seg << " already used" << endl;
}
faceht.Set (key, data);
}
}
/*
// not possible with surfnr as hash-index
for (int i = 1; i <= GetNSeg(); i++)
{
const Segment & seg = LineSegment (i);
if (surfnr == 0 || seg.si == surfnr)
{
INDEX_2 key(seg[1], seg[0]);
if (!faceht.Used(key))
{
cerr << "ERROR: Segment " << seg << " brother not used" << endl;
(*testout) << "ERROR: Segment " << seg << " brother not used" << endl;
}
}
}
*/
// bool buggy = false;
// ofstream bout("buggy.out");
for (int i = 1; i <= GetNSE(); i++)
{
const Element2d & el = SurfaceElement(i);
if (el.IsDeleted()) continue;
if (surfnr == 0 || el.GetIndex() == surfnr)
{
for (int j = 1; j <= el.GetNP(); j++)
{
INDEX_3 seg (el.PNumMod(j), el.PNumMod(j+1), el.GetIndex());
int data;
if (seg.I1() < PointIndex::BASE || seg.I2() < PointIndex::BASE)
cerr << "seg = " << seg << endl;
if (faceht.Used(seg))
{
faceht.Set (seg, 0);
/*
data = faceht.Get(seg);
if (data.I1() == el.GetIndex())
{
data.I1() = 0;
faceht.Set (seg, data);
}
else
{
// buggy = true;
PrintWarning ("hash table si not fitting for segment: ",
seg.I1(), "-", seg.I2(), " other = ",
data.I2(), ", surfnr = ", surfnr);
}
*/
}
else
{
Swap (seg.I1(), seg.I2());
// data.I1() = el.GetIndex();
// data.I2() = i;
faceht.Set (seg, i);
}
}
}
}
/*
if (buggy)
{
for (int i = 1; i <= GetNSeg(); i++)
bout << "seg" << i << " " << LineSegment(i) << endl;
for (int i = 1; i <= GetNSE(); i++)
bout << "sel" << i << " " << SurfaceElement(i) << " ind = "
<< SurfaceElement(i).GetIndex() << endl;
bout << "hashtable: " << endl;
for (int j = 1; j <= faceht.GetNBags(); j++)
{
bout << "bag " << j << ":" << endl;
for (int k = 1; k <= faceht.GetBagSize(j); k++)
{
INDEX_2 i2, data;
faceht.GetData (j, k, i2, data);
bout << "key = " << i2 << ", data = " << data << endl;
}
}
exit(1);
}
*/
(*testout) << "open segments: " << endl;
opensegments.SetSize(0);
for (int i = 1; i <= faceht.GetNBags(); i++)
for (int j = 1; j <= faceht.GetBagSize(i); j++)
{
INDEX_3 i2;
int data;
faceht.GetData (i, j, i2, data);
if (data) // surfnr
{
Segment seg;
seg[0] = i2.I1();
seg[1] = i2.I2();
seg.si = i2.I3();
// find geomdata:
if (data > 0)
{
// segment due to triangle
const Element2d & el = SurfaceElement (data);
for (int k = 1; k <= el.GetNP(); k++)
{
if (seg[0] == el.PNum(k))
seg.geominfo[0] = el.GeomInfoPi(k);
if (seg[1] == el.PNum(k))
seg.geominfo[1] = el.GeomInfoPi(k);
}
(*testout) << "trig seg: ";
}
else
{
// segment due to line
const Segment & lseg = LineSegment (-data);
seg.geominfo[0] = lseg.geominfo[0];
seg.geominfo[1] = lseg.geominfo[1];
(*testout) << "line seg: ";
}
(*testout) << seg[0] << " - " << seg[1]
<< " len = " << Dist (Point(seg[0]), Point(seg[1]))
<< endl;
opensegments.Append (seg);
if (seg.geominfo[0].trignum <= 0 || seg.geominfo[1].trignum <= 0)
{
(*testout) << "Problem with open segment: " << seg << endl;
}
}
}
PrintMessage (3, opensegments.Size(), " open segments found");
(*testout) << opensegments.Size() << " open segments found" << endl;
/*
ptyps.SetSize (GetNP());
for (i = 1; i <= ptyps.Size(); i++)
ptyps.Elem(i) = SURFACEPOINT;
for (i = 1; i <= GetNSeg(); i++)
{
const Segment & seg = LineSegment (i);
ptyps.Elem(seg[0]) = EDGEPOINT;
ptyps.Elem(seg[1]) = EDGEPOINT;
}
for (i = 1; i <= GetNOpenSegments(); i++)
{
const Segment & seg = GetOpenSegment (i);
ptyps.Elem(seg[0]) = EDGEPOINT;
ptyps.Elem(seg[1]) = EDGEPOINT;
}
*/
/*
for (int i = 1; i <= points.Size(); i++)
points.Elem(i).SetType(SURFACEPOINT);
*/
for (auto & p : points)
p.SetType (SURFACEPOINT);
for (int i = 1; i <= GetNSeg(); i++)
{
const Segment & seg = LineSegment (i);
points[seg[0]].SetType(EDGEPOINT);
points[seg[1]].SetType(EDGEPOINT);
}
for (int i = 1; i <= GetNOpenSegments(); i++)
{
const Segment & seg = GetOpenSegment (i);
points[seg[0]].SetType (EDGEPOINT);
points[seg[1]].SetType (EDGEPOINT);
}
/*
for (i = 1; i <= openelements.Size(); i++)
{
const Element2d & sel = openelements.Get(i);
if (boundaryedges)
for (j = 1; j <= sel.GetNP(); j++)
{
INDEX_2 i2;
i2.I1() = sel.PNumMod(j);
i2.I2() = sel.PNumMod(j+1);
i2.Sort();
boundaryedges->Set (i2, 1);
}
for (j = 1; j <= 3; j++)
{
int pi = sel.PNum(j);
if (pi <= ptyps.Size())
ptyps.Elem(pi) = FIXEDPOINT;
}
}
*/
}
void Mesh :: RemoveOneLayerSurfaceElements ()
{
int np = GetNP();
FindOpenSegments();
NgBitArray frontpoints(np+1); // for 0- and 1-based
frontpoints.Clear();
for (int i = 1; i <= GetNOpenSegments(); i++)
{
const Segment & seg = GetOpenSegment(i);
frontpoints.Set (seg[0]);
frontpoints.Set (seg[1]);
}
for (int i = 1; i <= GetNSE(); i++)
{
Element2d & sel = surfelements[i-1];
bool remove = false;
for (int j = 1; j <= sel.GetNP(); j++)
if (frontpoints.Test(sel.PNum(j)))
remove = true;
if (remove)
sel.PNum(1).Invalidate();
}
for (int i = surfelements.Size(); i >= 1; i--)
{
if (!surfelements[i-1].PNum(1).IsValid())
{
surfelements[i-1] = surfelements.Last();
surfelements.DeleteLast();
}
}
RebuildSurfaceElementLists ();
/*
for (int i = 0; i < facedecoding.Size(); i++)
facedecoding[i].firstelement = -1;
for (int i = surfelements.Size()-1; i >= 0; i--)
{
int ind = surfelements[i].GetIndex();
surfelements[i].next = facedecoding[ind-1].firstelement;
facedecoding[ind-1].firstelement = i;
}
*/
timestamp = NextTimeStamp();
// Compress();
}
void Mesh :: FreeOpenElementsEnvironment (int layers)
{
static Timer timer("FreeOpenElementsEnvironment"); RegionTimer rt(timer);
int i, j, k;
PointIndex pi;
const int large = 9999;
NgArray<int,PointIndex::BASE> dist(GetNP());
dist = large;
for (int i = 1; i <= GetNOpenElements(); i++)
{
const Element2d & face = OpenElement(i);
for (j = 0; j < face.GetNP(); j++)
dist[face[j]] = 1;
}
for (k = 1; k <= layers; k++)
for (i = 1; i <= GetNE(); i++)
{
const Element & el = VolumeElement(i);
if (el[0] == -1 || el.IsDeleted()) continue;
int elmin = large;
for (j = 0; j < el.GetNP(); j++)
if (dist[el[j]] < elmin)
elmin = dist[el[j]];
if (elmin < large)
{
for (j = 0; j < el.GetNP(); j++)
if (dist[el[j]] > elmin+1)
dist[el[j]] = elmin+1;
}
}
int cntfree = 0;
for (i = 1; i <= GetNE(); i++)
{
Element & el = VolumeElement(i);
if (el[0] == -1 || el.IsDeleted()) continue;
int elmin = large;
for (j = 0; j < el.GetNP(); j++)
if (dist[el[j]] < elmin)
elmin = dist[el[j]];
el.flags.fixed = elmin > layers;
// eltyps.Elem(i) = (elmin <= layers) ?
// FREEELEMENT : FIXEDELEMENT;
if (elmin <= layers)
cntfree++;
}
PrintMessage (5, "free: ", cntfree, ", fixed: ", GetNE()-cntfree);
(*testout) << "free: " << cntfree << ", fixed: " << GetNE()-cntfree << endl;
for (pi = PointIndex::BASE;
pi < GetNP()+PointIndex::BASE; pi++)
{
if (dist[pi] > layers+1)
points[pi].SetType(FIXEDPOINT);
}
}
void Mesh :: SetLocalH (netgen::Point<3> pmin, netgen::Point<3> pmax, double grading, int layer)
{
using netgen::Point;
Point<3> c = Center (pmin, pmax);
double d = max3 (pmax(0)-pmin(0),
pmax(1)-pmin(1),
pmax(2)-pmin(2));
d /= 2;
Point<3> pmin2 = c - Vec<3> (d, d, d);
Point<3> pmax2 = c + Vec<3> (d, d, d);
SetLocalH(make_unique<LocalH> (pmin2, pmax2, grading, dimension), layer);
}
void Mesh :: RestrictLocalH (const Point3d & p, double hloc, int layer)
{
if(hloc < hmin)
hloc = hmin;
//cout << "restrict h in " << p << " to " << hloc << endl;
if (!lochfunc[layer-1])
{
PrintWarning("RestrictLocalH called, creating mesh-size tree");
Point3d boxmin, boxmax;
GetBox (boxmin, boxmax);
SetLocalH (boxmin, boxmax, 0.8, layer);
}
lochfunc[layer-1] -> SetH (p, hloc);
}
void Mesh :: RestrictLocalHLine (const Point3d & p1,
const Point3d & p2,
double hloc, int layer)
{
if(hloc < hmin)
hloc = hmin;
// cout << "restrict h along " << p1 << " - " << p2 << " to " << hloc << endl;
int i;
int steps = int (Dist (p1, p2) / hloc) + 2;
Vec3d v(p1, p2);
for (i = 0; i <= steps; i++)
{
Point3d p = p1 + (double(i)/double(steps) * v);
RestrictLocalH (p, hloc, layer);
}
}
void Mesh :: SetMinimalH (double h)
{
hmin = h;
}
void Mesh :: SetGlobalH (double h)
{
hglob = h;
}
double Mesh :: MaxHDomain (int dom) const
{
if (maxhdomain.Size())
return maxhdomain.Get(dom);
else
return 1e10;
}
void Mesh :: SetMaxHDomain (const NgArray<double> & mhd)
{
maxhdomain.SetSize(mhd.Size());
for (int i = 1; i <= mhd.Size(); i++)
maxhdomain.Elem(i) = mhd.Get(i);
}
double Mesh :: GetH (const Point3d & p, int layer) const
{
const auto& lh = GetLocalH(layer);
double hmin = hglob;
if (lh)
{
double hl = lh->GetH (p);
if (hl < hglob)
hmin = hl;
}
return hmin;
}
double Mesh :: GetMinH (const Point3d & pmin, const Point3d & pmax, int layer)
{
const auto& lh = GetLocalH(layer);
double hmin = hglob;
if (lh)
{
double hl = lh->GetMinH (pmin, pmax);
if (hl < hmin)
hmin = hl;
}
return hmin;
}
double Mesh :: AverageH (int surfnr) const
{
int i, j, n;
double hi, hsum;
double maxh = 0, minh = 1e10;
hsum = 0;
n = 0;
for (i = 1; i <= GetNSE(); i++)
{
const Element2d & el = SurfaceElement(i);
if (surfnr == 0 || el.GetIndex() == surfnr)
{
for (j = 1; j <= 3; j++)
{
hi = Dist (Point (el.PNumMod(j)),
Point (el.PNumMod(j+1)));
hsum += hi;
if (hi > maxh) maxh = hi;
if (hi < minh) minh = hi;
n++;
}
}
}
PrintMessage (5, "minh = ", minh, " avh = ", (hsum/n), " maxh = ", maxh);
return (hsum / n);
}
void Mesh :: CalcLocalH (double grading, int layer)
{
static Timer t("Mesh::CalcLocalH"); RegionTimer reg(t);
if (!lochfunc[layer-1])
{
Point3d pmin, pmax;
GetBox (pmin, pmax);
// SetLocalH (pmin, pmax, mparam.grading);
SetLocalH (pmin, pmax, grading, layer);
}
PrintMessage (3,
"CalcLocalH: ",
GetNP(), " Points ",
GetNE(), " Elements ",
GetNSE(), " Surface Elements");
for (int i = 0; i < GetNSE(); i++)
{
const Element2d & el = surfelements[i];
int j;
if (el.GetNP() == 3)
{
double hel = -1;
for (j = 1; j <= 3; j++)
{
const Point3d & p1 = points[el.PNumMod(j)];
const Point3d & p2 = points[el.PNumMod(j+1)];
/*
INDEX_2 i21(el.PNumMod(j), el.PNumMod(j+1));
INDEX_2 i22(el.PNumMod(j+1), el.PNumMod(j));
if (! identifiedpoints->Used (i21) &&
! identifiedpoints->Used (i22) )
*/
if (!ident -> UsedSymmetric (el.PNumMod(j),
el.PNumMod(j+1)))
{
double hedge = Dist (p1, p2);
if (hedge > hel)
hel = hedge;
// lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));
// (*testout) << "trigseth, p1,2 = " << el.PNumMod(j) << ", " << el.PNumMod(j+1)
// << " h = " << (2 * Dist(p1, p2)) << endl;
}
}
if (hel > 0)
{
const Point3d & p1 = points[el.PNum(1)];
const Point3d & p2 = points[el.PNum(2)];
const Point3d & p3 = points[el.PNum(3)];
lochfunc[layer-1]->SetH (Center (p1, p2, p3), hel);
}
}
else
{
{
const Point3d & p1 = points[el.PNum(1)];
const Point3d & p2 = points[el.PNum(2)];
lochfunc[layer-1]->SetH (Center (p1, p2), 2 * Dist (p1, p2));
}
{
const Point3d & p1 = points[el.PNum(3)];
const Point3d & p2 = points[el.PNum(4)];
lochfunc[layer-1]->SetH (Center (p1, p2), 2 * Dist (p1, p2));
}
}
}
for (int i = 0; i < GetNSeg(); i++)
{
const Segment & seg = segments[i];
const Point3d & p1 = points[seg[0]];
const Point3d & p2 = points[seg[1]];
/*
INDEX_2 i21(seg[0], seg[1]);
INDEX_2 i22(seg[1], seg[0]);
if (identifiedpoints)
if (!identifiedpoints->Used (i21) && !identifiedpoints->Used (i22))
*/
if (!ident -> UsedSymmetric (seg[0], seg[1]))
{
lochfunc[layer-1]->SetH (Center (p1, p2), Dist (p1, p2));
}
}
/*
cerr << "do vol" << endl;
for (i = 1; i <= GetNE(); i++)
{
const Element & el = VolumeElement(i);
if (el.GetType() == TET)
{
int j, k;
for (j = 2; j <= 4; j++)
for (k = 1; k < j; k++)
{
const Point3d & p1 = Point (el.PNum(j));
const Point3d & p2 = Point (el.PNum(k));
lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));
(*testout) << "set vol h to " << (2 * Dist (p1, p2)) << endl;
}
}
}
*/
/*
const char * meshsizefilename =
globflags.GetStringFlag ("meshsize", NULL);
if (meshsizefilename)
{
ifstream msf(meshsizefilename);
if (msf)
{
int nmsp;
msf >> nmsp;
for (i = 1; i <= nmsp; i++)
{
Point3d pi;
double hi;
msf >> pi.X() >> pi.Y() >> pi.Z();
msf >> hi;
lochfunc->SetH (pi, hi);
}
}
}
*/
// lochfunc -> Convexify();
// lochfunc -> PrintMemInfo (cout);
}
void Mesh :: CalcLocalHFromPointDistances(double grading, int layer)
{
PrintMessage (3, "Calculating local h from point distances");
if (!lochfunc[layer-1])
{
Point3d pmin, pmax;
GetBox (pmin, pmax);
// SetLocalH (pmin, pmax, mparam.grading);
SetLocalH (pmin, pmax, grading, layer);
}
PointIndex i,j;
double hl;
for (i = PointIndex::BASE;
i < GetNP()+PointIndex::BASE; i++)
{
for(j=i+1; j<GetNP()+PointIndex::BASE; j++)
{
const Point3d & p1 = points[i];
const Point3d & p2 = points[j];
hl = Dist(p1,p2);
RestrictLocalH(p1,hl);
RestrictLocalH(p2,hl);
//cout << "restricted h at " << p1 << " and " << p2 << " to " << hl << endl;
}
}
}
void Mesh :: CalcLocalHFromSurfaceCurvature (double grading, double elperr, int layer)
{
PrintMessage (3, "Calculating local h from surface curvature");
if (!lochfunc[layer-1])
{
Point3d pmin, pmax;
GetBox (pmin, pmax);
// SetLocalH (pmin, pmax, mparam.grading);
SetLocalH (pmin, pmax, grading, layer);
}
INDEX_2_HASHTABLE<int> edges(3 * GetNP() + 2);
INDEX_2_HASHTABLE<int> bedges(GetNSeg() + 2);
int i, j;
for (i = 1; i <= GetNSeg(); i++)
{
const Segment & seg = LineSegment(i);
INDEX_2 i2(seg[0], seg[1]);
i2.Sort();
bedges.Set (i2, 1);
}
for (i = 1; i <= GetNSE(); i++)
{
const Element2d & sel = SurfaceElement(i);
if (!sel.PNum(1))
continue;
for (j = 1; j <= 3; j++)
{
INDEX_2 i2(sel.PNumMod(j), sel.PNumMod(j+1));
i2.Sort();
if (bedges.Used(i2)) continue;
if (edges.Used(i2))
{
int other = edges.Get(i2);
const Element2d & elother = SurfaceElement(other);
int pi3 = 1;
while ( (sel.PNum(pi3) == i2.I1()) ||
(sel.PNum(pi3) == i2.I2()))
pi3++;
pi3 = sel.PNum(pi3);
int pi4 = 1;
while ( (elother.PNum(pi4) == i2.I1()) ||
(elother.PNum(pi4) == i2.I2()))
pi4++;
pi4 = elother.PNum(pi4);
double rad = ComputeCylinderRadius (Point (PointIndex(i2.I1())),
Point (PointIndex(i2.I2())),
Point (PointIndex(pi3)),
Point (PointIndex(pi4)));
RestrictLocalHLine (Point(PointIndex(i2.I1())), Point(PointIndex(i2.I2())), rad/elperr);
/*
(*testout) << "pi1,2, 3, 4 = " << i2.I1() << ", " << i2.I2() << ", " << pi3 << ", " << pi4
<< " p1 = " << Point(i2.I1())
<< ", p2 = " << Point(i2.I2())
// << ", p3 = " << Point(pi3)
// << ", p4 = " << Point(pi4)
<< ", rad = " << rad << endl;
*/
}
else
edges.Set (i2, i);
}
}
// Restrict h due to line segments
for (i = 1; i <= GetNSeg(); i++)
{
const Segment & seg = LineSegment(i);
const Point3d & p1 = Point(seg[0]);
const Point3d & p2 = Point(seg[1]);
RestrictLocalH (Center (p1, p2), Dist (p1, p2));
}
/*
int i, j;
int np = GetNP();
int nseg = GetNSeg();
int nse = GetNSE();
NgArray<Vec3d> normals(np);
NgBitArray linepoint(np);
linepoint.Clear();
for (i = 1; i <= nseg; i++)
{
linepoint.Set (LineSegment(i)[0]);
linepoint.Set (LineSegment(i)[1]);
}
for (i = 1; i <= np; i++)
normals.Elem(i) = Vec3d(0,0,0);
for (i = 1; i <= nse; i++)
{
Element2d & el = SurfaceElement(i);
Vec3d nf = Cross (Vec3d (Point (el.PNum(1)), Point(el.PNum(2))),
Vec3d (Point (el.PNum(1)), Point(el.PNum(3))));
for (j = 1; j <= 3; j++)
normals.Elem(el.PNum(j)) += nf;
}
for (i = 1; i <= np; i++)
normals.Elem(i) /= (1e-12 + normals.Elem(i).Length());
for (i = 1; i <= nse; i++)
{
Element2d & el = SurfaceElement(i);
Vec3d nf = Cross (Vec3d (Point (el.PNum(1)), Point(el.PNum(2))),
Vec3d (Point (el.PNum(1)), Point(el.PNum(3))));
nf /= nf.Length();
Point3d c = Center (Point(el.PNum(1)),
Point(el.PNum(2)),
Point(el.PNum(3)));
for (j = 1; j <= 3; j++)
{
if (!linepoint.Test (el.PNum(j)))
{
double dist = Dist (c, Point(el.PNum(j)));
double dn = (nf - normals.Get(el.PNum(j))).Length();
RestrictLocalH (Point(el.PNum(j)), dist / (dn+1e-12) /elperr);
}
}
}
*/
}
void Mesh :: RestrictLocalH (resthtype rht, int nr, double loch)
{
int i;
switch (rht)
{
case RESTRICTH_FACE:
{
for (i = 1; i <= GetNSE(); i++)
{
const Element2d & sel = SurfaceElement(i);
if (sel.GetIndex() == nr)
RestrictLocalH (RESTRICTH_SURFACEELEMENT, i, loch);
}
break;
}
case RESTRICTH_EDGE:
{
for (i = 1; i <= GetNSeg(); i++)
{
const Segment & seg = LineSegment(i);
if (seg.edgenr == nr)
RestrictLocalH (RESTRICTH_SEGMENT, i, loch);
}
break;
}
case RESTRICTH_POINT:
{
RestrictLocalH (Point (nr), loch);
break;
}
case RESTRICTH_SURFACEELEMENT:
{
const Element2d & sel = SurfaceElement(nr);
Point3d p = Center (Point(sel.PNum(1)),
Point(sel.PNum(2)),
Point(sel.PNum(3)));
RestrictLocalH (p, loch);
break;
}
case RESTRICTH_SEGMENT:
{
const Segment & seg = LineSegment(nr);
RestrictLocalHLine (Point (seg[0]), Point(seg[1]), loch);
break;
}
}
}
void Mesh :: LoadLocalMeshSize (const filesystem::path & meshsizefilename)
{
// Philippose - 10/03/2009
// Improve error checking when loading and reading
// the local mesh size file
if (meshsizefilename.empty()) return;
ifstream msf(meshsizefilename);
// Philippose - 09/03/2009
// Adding print message information in case the specified
// does not exist, or does not load successfully due to
// other reasons such as access rights, etc...
if (!msf)
{
PrintMessage(3, "Error loading mesh size file: ", meshsizefilename, "....","Skipping!");
return;
}
PrintMessage (3, "Load local mesh-size file: ", meshsizefilename);
int nmsp = 0;
int nmsl = 0;
msf >> nmsp;
if(!msf.good())
throw NgException ("Mesh-size file error: No points found\n");
if(nmsp > 0)
PrintMessage (4, "Number of mesh-size restriction points: ", nmsp);
for (int i = 0; i < nmsp; i++)
{
Point3d pi;
double hi;
msf >> pi.X() >> pi.Y() >> pi.Z();
msf >> hi;
if (!msf.good())
throw NgException ("Mesh-size file error: Number of points don't match specified list size\n");
RestrictLocalH (pi, hi);
}
msf >> nmsl;
if(!msf.good())
throw NgException ("Mesh-size file error: No line definitions found\n");
if(nmsl > 0)
PrintMessage (4, "Number of mesh-size restriction lines: ", nmsl);
for (int i = 0; i < nmsl; i++)
{
Point3d p1, p2;
double hi;
msf >> p1.X() >> p1.Y() >> p1.Z();
msf >> p2.X() >> p2.Y() >> p2.Z();
msf >> hi;
if (!msf.good())
throw NgException ("Mesh-size file error: Number of line definitions don't match specified list size\n");
RestrictLocalHLine (p1, p2, hi);
}
msf.close();
}
void Mesh :: SetLocalH(shared_ptr<LocalH> loch, int layer)
{
if(layer>lochfunc.Size())
{
auto pre_size = lochfunc.Size();
lochfunc.SetSize(layer);
for(auto & func : lochfunc.Range(pre_size, layer-1))
func = lochfunc[0];
}
lochfunc[layer-1] = loch;
}
void Mesh :: GetBox (Point3d & pmin, Point3d & pmax, int dom) const
{
if (points.Size() == 0)
{
pmin = pmax = Point3d(0,0,0);
return;
}
if (dom <= 0)
{
pmin = Point3d (1e10, 1e10, 1e10);
pmax = Point3d (-1e10, -1e10, -1e10);
// for (PointIndex pi = points.Begin(); pi < points.End(); pi++)
for (PointIndex pi : points.Range())
{
pmin.SetToMin ( (*this) [pi] );
pmax.SetToMax ( (*this) [pi] );
}
}
else
{
int j, nse = GetNSE();
SurfaceElementIndex sei;
pmin = Point3d (1e10, 1e10, 1e10);
pmax = Point3d (-1e10, -1e10, -1e10);
for (sei = 0; sei < nse; sei++)
{
const Element2d & el = (*this)[sei];
if (el.IsDeleted() ) continue;
if (dom == -1 || el.GetIndex() == dom)
{
for (j = 0; j < 3; j++)
{
pmin.SetToMin ( (*this) [el[j]] );
pmax.SetToMax ( (*this) [el[j]] );
}
}
}
}
if (pmin.X() > 0.5e10)
{
pmin = pmax = Point3d(0,0,0);
}
}
void Mesh :: GetBox (Point3d & pmin, Point3d & pmax, POINTTYPE ptyp) const
{
if (points.Size() == 0)
{
pmin = pmax = Point3d(0,0,0);
return;
}
pmin = Point3d (1e10, 1e10, 1e10);
pmax = Point3d (-1e10, -1e10, -1e10);
// for (PointIndex pi = points.Begin(); pi < points.End(); pi++)
for (PointIndex pi : points.Range())
if (points[pi].Type() <= ptyp)
{
pmin.SetToMin ( (*this) [pi] );
pmax.SetToMax ( (*this) [pi] );
}
}
double Mesh :: ElementError (int eli, const MeshingParameters & mp) const
{
const Element & el = volelements[eli-1];
return CalcTetBadness (points[el[0]], points[el[1]],
points[el[2]], points[el[3]], -1, mp);
}
void Mesh :: AddLockedPoint (PointIndex pi)
{
lockedpoints.Append (pi);
}
void Mesh :: ClearLockedPoints ()
{
lockedpoints.SetSize (0);
}
void Mesh :: Compress ()
{
static Timer t("Mesh::Compress"); RegionTimer reg(t);
NgLock lock(mutex);
lock.Lock();
Array<PointIndex,PointIndex> op2np(GetNP());
Array<bool, PointIndex> pused(GetNP());
/*
(*testout) << "volels: " << endl;
for (i = 1; i <= volelements.Size(); i++)
{
for (j = 1; j <= volelements.Get(i).GetNP(); j++)
(*testout) << volelements.Get(i).PNum(j) << " ";
(*testout) << endl;
}
(*testout) << "np: " << GetNP() << endl;
*/
for (int i = 0; i < volelements.Size(); i++)
if (volelements[i][0] <= PointIndex::BASE-1 ||
volelements[i].IsDeleted())
{
volelements.DeleteElement(i);
i--;
}
for (int i = 0; i < surfelements.Size(); i++)
if (surfelements[i].IsDeleted())
{
surfelements.DeleteElement(i);
i--;
}
for (int i = 0; i < segments.Size(); i++)
if (segments[i][0] <= PointIndex::BASE-1)
{
segments.DeleteElement(i);
i--;
}
for(int i=0; i < segments.Size(); i++)
if(segments[i].edgenr < 0)
segments.DeleteElement(i--);
pused = false;
/*
for (int i = 0; i < volelements.Size(); i++)
{
const Element & el = volelements[i];
for (int j = 0; j < el.GetNP(); j++)
pused[el[j]] = true;
}
*/
/*
for (const Element & el : volelements)
for (PointIndex pi : el.PNums())
pused[pi] = true;
*/
ParallelForRange
(volelements.Range(), [&] (auto myrange)
{
for (const Element & el : volelements.Range(myrange))
for (PointIndex pi : el.PNums())
pused[pi] = true;
});
/*
for (int i = 0; i < surfelements.Size(); i++)
{
const Element2d & el = surfelements[i];
for (int j = 0; j < el.GetNP(); j++)
pused[el[j]] = true;
}
*/
ParallelForRange
(surfelements.Range(), [&] (auto myrange)
{
for (const Element2d & el : surfelements.Range(myrange))
for (PointIndex pi : el.PNums())
pused[pi] = true;
});
for (int i = 0; i < segments.Size(); i++)
{
const Segment & seg = segments[i];
for (int j = 0; j < seg.GetNP(); j++)
pused[seg[j]] = true;
}
for (int i = 0; i < openelements.Size(); i++)
{
const Element2d & el = openelements[i];
for (int j = 0; j < el.GetNP(); j++)
pused[el[j]] = true;
}
for (int i = 0; i < lockedpoints.Size(); i++)
pused[lockedpoints[i]] = true;
/*
// compress points doesn't work for identified points !
if (identifiedpoints)
{
for (i = 1; i <= identifiedpoints->GetNBags(); i++)
if (identifiedpoints->GetBagSize(i))
{
pused.Set ();
break;
}
}
*/
// pused.Set();
{
Array<MeshPoint> hpoints;
int npi = PointIndex::BASE;
for (PointIndex pi : points.Range())
if (pused[pi])
{
op2np[pi] = npi;
npi++;
hpoints.Append (points[pi]);
}
else
{
op2np[pi].Invalidate();
}
points.SetSize(0);
for (int i = 0; i < hpoints.Size(); i++)
points.Append (hpoints[i]);
}
/*
for (int i = 1; i <= volelements.Size(); i++)
{
Element & el = VolumeElement(i);
for (int j = 0; j < el.GetNP(); j++)
el[j] = op2np[el[j]];
}
*/
ParallelForRange
(volelements.Range(), [&] (auto myrange)
{
for (Element & el : volelements.Range(myrange))
for (PointIndex & pi : el.PNums())
pi = op2np[pi];
});
/*
for (int i = 1; i <= surfelements.Size(); i++)
{
Element2d & el = SurfaceElement(i);
for (int j = 0; j < el.GetNP(); j++)
el[j] = op2np[el[j]];
}
*/
ParallelForRange
(surfelements.Range(), [&] (auto myrange)
{
for (Element2d & el : surfelements.Range(myrange))
for (PointIndex & pi : el.PNums())
pi = op2np[pi];
});
for (int i = 0; i < segments.Size(); i++)
{
Segment & seg = segments[i];
for (int j = 0; j < seg.GetNP(); j++)
seg[j] = op2np[seg[j]];
}
for (int i = 1; i <= openelements.Size(); i++)
{
Element2d & el = openelements.Elem(i);
for (int j = 0; j < el.GetNP(); j++)
el[j] = op2np[el[j]];
}
for (int i = 0; i < lockedpoints.Size(); i++)
lockedpoints[i] = op2np[lockedpoints[i]];
/*
for (int i = 0; i < facedecoding.Size(); i++)
facedecoding[i].firstelement = -1;
for (int i = surfelements.Size()-1; i >= 0; i--)
{
int ind = surfelements[i].GetIndex();
surfelements[i].next = facedecoding[ind-1].firstelement;
facedecoding[ind-1].firstelement = i;
}
*/
RebuildSurfaceElementLists ();
CalcSurfacesOfNode();
// FindOpenElements();
timestamp = NextTimeStamp();
lock.UnLock();
}
void Mesh :: OrderElements()
{
for (auto & el : surfelements)
{
if (el.GetType() == TRIG)
while (el[0] > el[1] || el[0] > el[2])
{ // rotate element
auto hp = el[0];
el[0] = el[1];
el[1] = el[2];
el[2] = hp;
auto hgi = el.GeomInfoPi(1);
el.GeomInfoPi(1) = el.GeomInfoPi(2);
el.GeomInfoPi(2) = el.GeomInfoPi(3);
el.GeomInfoPi(3) = hgi;
}
}
for (auto & el : volelements)
if (el.GetType() == TET)
{
// lowest index first ...
int mini = 0;
for (int i = 1; i < 4; i++)
if (el[i] < el[mini]) mini = i;
if (mini != 0)
{ // swap 0 with mini, and the other two ...
int i3 = -1, i4 = -1;
for (int i = 1; i < 4; i++)
if (i != mini)
{
i4 = i3;
i3 = i;
}
swap (el[0], el[mini]);
swap (el[i3], el[i4]);
}
while (el[1] > el[2] || el[1] > el[3])
{ // rotate element to move second index to second position
auto hp = el[1];
el[1] = el[2];
el[2] = el[3];
el[3] = hp;
}
}
}
int Mesh :: CheckConsistentBoundary () const
{
int nf = GetNOpenElements();
INDEX_2_HASHTABLE<int> edges(nf+2);
INDEX_2 i2, i2s, edge;
int err = 0;
for (int i = 1; i <= nf; i++)
{
const Element2d & sel = OpenElement(i);
for (int j = 1; j <= sel.GetNP(); j++)
{
i2.I1() = sel.PNumMod(j);
i2.I2() = sel.PNumMod(j+1);
int sign = (i2.I2() > i2.I1()) ? 1 : -1;
i2.Sort();
if (!edges.Used (i2))
edges.Set (i2, 0);
edges.Set (i2, edges.Get(i2) + sign);
}
}
for (int i = 1; i <= edges.GetNBags(); i++)
for (int j = 1; j <= edges.GetBagSize(i); j++)
{
int cnt = 0;
edges.GetData (i, j, i2, cnt);
if (cnt)
{
PrintError ("Edge ", i2.I1() , " - ", i2.I2(), " multiple times in surface mesh");
(*testout) << "Edge " << i2 << " multiple times in surface mesh" << endl;
i2s = i2;
i2s.Sort();
for (int k = 1; k <= nf; k++)
{
const Element2d & sel = OpenElement(k);
for (int l = 1; l <= sel.GetNP(); l++)
{
edge.I1() = sel.PNumMod(l);
edge.I2() = sel.PNumMod(l+1);
edge.Sort();
if (edge == i2s)
(*testout) << "edge of element " << sel << endl;
}
}
err = 2;
}
}
return err;
}
int Mesh :: CheckOverlappingBoundary ()
{
static Timer t("Mesh::CheckOverlappingBoundary"); RegionTimer reg(t);
Point3d pmin, pmax;
GetBox (pmin, pmax);
BoxTree<3, SurfaceElementIndex> setree(pmin, pmax);
// NgArray<SurfaceElementIndex> inters;
bool overlap = 0;
bool incons_layers = 0;
for (Element2d & el : SurfaceElements())
el.badel = false;
for (SurfaceElementIndex sei : Range(SurfaceElements()))
{
const Element2d & tri = SurfaceElement(sei);
Box<3> box(Box<3>::EMPTY_BOX);
for (PointIndex pi : tri.PNums())
box.Add (Point(pi));
box.Increase(1e-3*box.Diam());
setree.Insert (box, sei);
}
std::mutex m;
// for (SurfaceElementIndex sei : Range(SurfaceElements()))
ParallelForRange
(Range(SurfaceElements()), [&] (auto myrange)
{
for (SurfaceElementIndex sei : myrange)
{
const Element2d & tri = SurfaceElement(sei);
Box<3> box(Box<3>::EMPTY_BOX);
for (PointIndex pi : tri.PNums())
box.Add (Point(pi));
setree.GetFirstIntersecting
(box.PMin(), box.PMax(),
[&] (SurfaceElementIndex sej)
{
const Element2d & tri2 = SurfaceElement(sej);
if ( (*this)[tri[0]].GetLayer() != (*this)[tri2[0]].GetLayer())
return false;
if ( (*this)[tri[0]].GetLayer() != (*this)[tri[1]].GetLayer() ||
(*this)[tri[0]].GetLayer() != (*this)[tri[2]].GetLayer())
{
incons_layers = 1;
// cout << "inconsistent layers in triangle" << endl;
}
const netgen::Point<3> *trip1[3], *trip2[3];
for (int k = 0; k < 3; k++)
{
trip1[k] = &Point (tri[k]);
trip2[k] = &Point (tri2[k]);
}
if (IntersectTriangleTriangle (&trip1[0], &trip2[0]))
{
overlap = 1;
lock_guard<std::mutex> guard(m);
if(!incons_layers)
{
PrintWarning ("Intersecting elements "
,int(sei), " and ", int(sej));
(*testout) << "Intersecting: " << endl;
(*testout) << "openelement " << sei << " with open element " << sej << endl;
cout << "el1 = " << tri << endl;
cout << "el2 = " << tri2 << endl;
cout << "layer1 = " << (*this)[tri[0]].GetLayer() << endl;
cout << "layer2 = " << (*this)[tri2[0]].GetLayer() << endl;
}
for (int k = 1; k <= 3; k++)
(*testout) << tri.PNum(k) << " ";
(*testout) << endl;
for (int k = 1; k <= 3; k++)
(*testout) << tri2.PNum(k) << " ";
(*testout) << endl;
for (int k = 0; k <= 2; k++)
(*testout) << *trip1[k] << " ";
(*testout) << endl;
for (int k = 0; k <= 2; k++)
(*testout) << *trip2[k] << " ";
(*testout) << endl;
(*testout) << "Face1 = " << GetFaceDescriptor(tri.GetIndex()) << endl;
(*testout) << "Face1 = " << GetFaceDescriptor(tri2.GetIndex()) << endl;
SurfaceElement(sei).badel = 1;
SurfaceElement(sej).badel = 1;
}
return false;
});
}
});
// bug 'fix'
if (incons_layers) overlap = 0;
return overlap;
}
int Mesh :: CheckVolumeMesh () const
{
PrintMessage (3, "Checking volume mesh");
int ne = GetNE();
DenseMatrix dtrans(3,3);
int i, j;
PrintMessage (5, "elements: ", ne);
for (i = 1; i <= ne; i++)
{
Element & el = (Element&) VolumeElement(i);
el.flags.badel = 0;
int nip = el.GetNIP();
for (j = 1; j <= nip; j++)
{
el.GetTransformation (j, Points(), dtrans);
double det = dtrans.Det();
if (det > 0)
{
PrintError ("Element ", i , " has wrong orientation");
el.flags.badel = 1;
}
}
}
return 0;
}
// Search for surface trigs with same vertices ( may happen for instance with close surfaces in stl geometies )
int Mesh :: FindIllegalTrigs ()
{
// Temporary table to store the vertex numbers of all triangles
INDEX_3_CLOSED_HASHTABLE<int> temp_tab(3*GetNSE() + 1);
size_t cnt = 0;
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
{
const Element2d & sel = surfelements[sei];
if (sel.IsDeleted()) continue;
INDEX_3 i3(sel[0], sel[1], sel[2]);
i3.Sort();
if(temp_tab.Used(i3))
{
temp_tab.Set (i3, -1);
cnt++;
}
else
{
temp_tab.Set (i3, sei);
}
}
illegal_trigs = make_unique<INDEX_3_CLOSED_HASHTABLE<int>> (2*cnt+1);
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
{
const Element2d & sel = surfelements[sei];
if (sel.IsDeleted()) continue;
INDEX_3 i3(sel[0], sel[1], sel[2]);
i3.Sort();
if(temp_tab.Get(i3)==-1)
illegal_trigs -> Set (i3, 1);
}
return cnt;
}
bool Mesh :: LegalTrig (const Element2d & el) const
{
if(illegal_trigs)
{
INDEX_3 i3 (el[0], el[1], el[2]);
i3.Sort();
if(illegal_trigs->Used(i3))
return false;
}
return 1;
if ( /* hp */ 1) // needed for old, simple hp-refinement
{
// trigs with 2 or more segments are illegal
int i;
int nseg = 0;
if (!segmentht)
{
cerr << "no segmentht allocated" << endl;
return 0;
}
// Point3d cp(0.5, 0.5, 0.5);
for (i = 1; i <= 3; i++)
{
INDEX_2 i2(el.PNumMod (i), el.PNumMod (i+1));
i2.Sort();
if (segmentht -> Used (i2))
nseg++;
}
if (nseg >= 2)
return 0;
}
return 1;
}
double Mesh :: CalcTotalBad (const MeshingParameters & mp )
{
static Timer t("CalcTotalBad"); RegionTimer reg(t);
static constexpr int n_classes = 20;
double sum = 0;
tets_in_qualclass.SetSize(n_classes);
tets_in_qualclass = 0;
ParallelForRange( IntRange(volelements.Size()), [&] (auto myrange)
{
double local_sum = 0.0;
double teterrpow = mp.opterrpow;
std::array<int,n_classes> classes_local{};
for (auto i : myrange)
{
double elbad = pow (max2(CalcBad (points, volelements[i], 0, mp),1e-10), 1/teterrpow);
int qualclass = int (n_classes / elbad + 1);
if (qualclass < 1) qualclass = 1;
if (qualclass > n_classes) qualclass = n_classes;
classes_local[qualclass-1]++;
local_sum += elbad;
}
AtomicAdd(sum, local_sum);
for (auto i : Range(n_classes))
AsAtomic(tets_in_qualclass[i]) += classes_local[i];
});
return sum;
}
///
bool Mesh :: LegalTet2 (Element & el) const
{
// static int timer1 = NgProfiler::CreateTimer ("Legaltet2");
// Test, whether 4 points have a common surface plus
// at least 4 edges at the boundary
if(!boundaryedges)
const_cast<Mesh *>(this)->BuildBoundaryEdges();
// non-tets are always legal
if (el.GetType() != TET)
{
el.SetLegal (1);
return 1;
}
POINTTYPE pointtype[4];
for(int i = 0; i < 4; i++)
pointtype[i] = (*this)[el[i]].Type();
// element has at least 2 inner points ---> legal
int cnti = 0;
for (int j = 0; j < 4; j++)
if ( pointtype[j] == INNERPOINT)
{
cnti++;
if (cnti >= 2)
{
el.SetLegal (1);
return 1;
}
}
// which faces are boundary faces ?
int bface[4];
for (int i = 0; i < 4; i++)
{
bface[i] = surfelementht->Used (INDEX_3::Sort(el[gftetfacesa[i][0]],
el[gftetfacesa[i][1]],
el[gftetfacesa[i][2]]));
}
int bedge[4][4];
int segedge[4][4];
static const int pi3map[4][4] = { { -1, 2, 1, 1 },
{ 2, -1, 0, 0 },
{ 1, 0, -1, 0 },
{ 1, 0, 0, -1 } };
static const int pi4map[4][4] = { { -1, 3, 3, 2 },
{ 3, -1, 3, 2 },
{ 3, 3, -1, 1 },
{ 2, 2, 1, -1 } };
for (int i = 0; i < 4; i++)
for (int j = 0; j < i; j++)
{
bool sege = false, be = false;
int pos = boundaryedges -> Position0(INDEX_2::Sort(el[i], el[j]));
if (pos != -1)
{
be = true;
if (boundaryedges -> GetData0(pos) == 2)
sege = true;
}
segedge[j][i] = segedge[i][j] = sege;
bedge[j][i] = bedge[i][j] = be;
}
// two boundary faces and no edge is illegal
for (int i = 0; i < 3; i++)
for (int j = i+1; j < 4; j++)
{
if (bface[i] && bface[j])
if (!segedge[pi3map[i][j]][pi4map[i][j]])
{
// 2 boundary faces without edge in between
el.SetLegal (0);
return 0;
}
}
// three boundary edges meeting in a Surface point
for (int i = 0; i < 4; i++)
{
if ( pointtype[i] == SURFACEPOINT)
{
bool alledges = 1;
for (int j = 0; j < 4; j++)
if (j != i && !bedge[i][j])
{
alledges = 0;
break;
}
if (alledges)
{
// cout << "tet illegal due to unmarked node" << endl;
el.SetLegal (0);
return 0;
}
}
}
for (int fnr = 0; fnr < 4; fnr++)
if (!bface[fnr])
for (int i = 0; i < 4; i++)
if (i != fnr)
{
int pi1 = pi3map[i][fnr];
int pi2 = pi4map[i][fnr];
if ( pointtype[i] == SURFACEPOINT)
{
// two connected edges on surface, but no face
if (bedge[i][pi1] && bedge[i][pi2])
{
el.SetLegal (0);
return 0;
}
}
if ( pointtype[i] == EDGEPOINT)
{
// connected surface edge and edge edge, but no face
if ( (bedge[i][pi1] && segedge[i][pi2]) ||
(bedge[i][pi2] && segedge[i][pi1]) )
{
el.SetLegal (0);
return 0;
}
}
}
el.SetLegal (1);
return 1;
}
int Mesh :: GetNDomains() const
{
int ndom = 0;
for (int k = 0; k < facedecoding.Size(); k++)
{
if (facedecoding[k].DomainIn() > ndom)
ndom = facedecoding[k].DomainIn();
if (facedecoding[k].DomainOut() > ndom)
ndom = facedecoding[k].DomainOut();
}
return ndom;
}
void Mesh :: SetDimension (int dim)
{
if (dimension == 3 && dim == 2)
{
// change mesh-dim from 3 to 2 (currently needed for OCC)
for (auto str : materials)
delete str;
materials.SetSize(0);
for (auto str : bcnames)
materials.Append(str);
bcnames.SetSize(0);
for (auto str : cd2names)
bcnames.Append(str);
cd2names.SetSize(0);
for (auto str : cd3names)
cd2names.Append(str);
cd3names.SetSize(0);
for (auto & seg : LineSegments())
seg.si = seg.edgenr;
}
dimension = dim;
}
void Mesh :: SurfaceMeshOrientation ()
{
int i, j;
int nse = GetNSE();
NgBitArray used(nse);
used.Clear();
INDEX_2_HASHTABLE<int> edges(nse+1);
bool haschanged = 0;
const Element2d & tri = SurfaceElement(1);
for (j = 1; j <= 3; j++)
{
INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1));
edges.Set (i2, 1);
}
used.Set(1);
bool unused;
do
{
bool changed;
do
{
changed = 0;
for (i = 1; i <= nse; i++)
if (!used.Test(i))
{
Element2d & el = surfelements[i-1];
int found = 0, foundrev = 0;
for (j = 1; j <= 3; j++)
{
INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1));
if (edges.Used(i2))
foundrev = 1;
swap (i2.I1(), i2.I2());
if (edges.Used(i2))
found = 1;
}
if (found || foundrev)
{
if (foundrev)
swap (el.PNum(2), el.PNum(3));
changed = 1;
for (j = 1; j <= 3; j++)
{
INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1));
edges.Set (i2, 1);
}
used.Set (i);
}
}
if (changed)
haschanged = 1;
}
while (changed);
unused = 0;
for (i = 1; i <= nse; i++)
if (!used.Test(i))
{
unused = 1;
const Element2d & tri = SurfaceElement(i);
for (j = 1; j <= 3; j++)
{
INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1));
edges.Set (i2, 1);
}
used.Set(i);
break;
}
}
while (unused);
if (haschanged)
timestamp = NextTimeStamp();
}
void Mesh :: Split2Tets()
{
PrintMessage (1, "Split To Tets");
bool has_prisms = 0;
int oldne = GetNE();
for (int i = 1; i <= oldne; i++)
{
Element el = VolumeElement(i);
if (el.GetType() == PRISM)
{
// prism, to 3 tets
// make minimal node to node 1
int minpi=0;
PointIndex minpnum;
minpnum = GetNP() + 1;
for (int j = 1; j <= 6; j++)
{
if (el.PNum(j) < minpnum)
{
minpnum = el.PNum(j);
minpi = j;
}
}
if (minpi >= 4)
{
for (int j = 1; j <= 3; j++)
swap (el.PNum(j), el.PNum(j+3));
minpi -= 3;
}
while (minpi > 1)
{
int hi = 0;
for (int j = 0; j <= 3; j+= 3)
{
hi = el.PNum(1+j);
el.PNum(1+j) = el.PNum(2+j);
el.PNum(2+j) = el.PNum(3+j);
el.PNum(3+j) = hi;
}
minpi--;
}
/*
version 1: edge from pi2 to pi6,
version 2: edge from pi3 to pi5,
*/
static const int ntets[2][12] =
{ { 1, 4, 5, 6, 1, 2, 3, 6, 1, 2, 5, 6 },
{ 1, 4, 5, 6, 1, 2, 3, 5, 3, 1, 5, 6 } };
const int * min2pi;
if (min2 (el.PNum(2), el.PNum(6)) <
min2 (el.PNum(3), el.PNum(5)))
{
min2pi = &ntets[0][0];
// (*testout) << "version 1 ";
}
else
{
min2pi = &ntets[1][0];
// (*testout) << "version 2 ";
}
int firsttet = 1;
for (int j = 1; j <= 3; j++)
{
Element nel(TET);
for (int k = 1; k <= 4; k++)
nel.PNum(k) = el.PNum(min2pi[4 * j + k - 5]);
nel.SetIndex (el.GetIndex());
int legal = 1;
for (int k = 1; k <= 3; k++)
for (int l = k+1; l <= 4; l++)
if (nel.PNum(k) == nel.PNum(l))
legal = 0;
// (*testout) << nel << " ";
if (legal)
{
if (firsttet)
{
VolumeElement(i) = nel;
firsttet = 0;
}
else
{
AddVolumeElement(nel);
}
}
}
if (firsttet) cout << "no legal";
(*testout) << endl;
}
else if (el.GetType() == HEX)
{
// hex to A) 2 prisms or B) to 5 tets
// make minimal node to node 1
int minpi=0;
PointIndex minpnum;
minpnum = GetNP() + 1;
for (int j = 1; j <= 8; j++)
{
if (el.PNum(j) < minpnum)
{
minpnum = el.PNum(j);
minpi = j;
}
}
if (minpi >= 5)
{
for (int j = 1; j <= 4; j++)
swap (el.PNum(j), el.PNum(j+4));
minpi -= 4;
}
while (minpi > 1)
{
int hi = 0;
for (int j = 0; j <= 4; j+= 4)
{
hi = el.PNum(1+j);
el.PNum(1+j) = el.PNum(2+j);
el.PNum(2+j) = el.PNum(3+j);
el.PNum(3+j) = el.PNum(4+j);
el.PNum(4+j) = hi;
}
minpi--;
}
static const int to_prisms[3][12] =
{ { 0, 1, 2, 4, 5, 6, 0, 2, 3, 4, 6, 7 },
{ 0, 1, 5, 3, 2, 6, 0, 5, 4, 3, 6, 7 },
{ 0, 7, 4, 1, 6, 5, 0, 3, 7, 1, 2, 6 },
};
const int * min2pi = 0;
if (min2 (el[4], el[6]) < min2 (el[5], el[7]))
min2pi = &to_prisms[0][0];
else if (min2 (el[3], el[6]) < min2 (el[2], el[7]))
min2pi = &to_prisms[1][0];
else if (min2 (el[1], el[6]) < min2 (el[2], el[5]))
min2pi = &to_prisms[2][0];
if (min2pi)
{
has_prisms = 1;
for (int j = 0; j < 2; j++)
{
Element nel(PRISM);
for (int k = 0; k < 6; k++)
nel[k] = el[min2pi[6*j + k]];
nel.SetIndex (el.GetIndex());
if (j == 0)
VolumeElement(i) = nel;
else
AddVolumeElement(nel);
}
}
else
{
// split to 5 tets
static const int to_tets[20] =
{
1, 2, 0, 5,
3, 0, 2, 7,
4, 5, 7, 0,
6, 7, 5, 2,
0, 2, 7, 5
};
for (int j = 0; j < 5; j++)
{
Element nel(TET);
for (int k = 0; k < 4; k++)
nel[k] = el[to_tets[4*j + k]];
nel.SetIndex (el.GetIndex());
if (j == 0)
VolumeElement(i) = nel;
else
AddVolumeElement(nel);
}
}
}
else if (el.GetType() == PYRAMID)
{
// pyramid, to 2 tets
// cout << "pyramid: " << el << endl;
static const int ntets[2][8] =
{ { 1, 2, 3, 5, 1, 3, 4, 5 },
{ 1, 2, 4, 5, 4, 2, 3, 5 }};
const int * min2pi;
if (min2 (el[0], el[2]) < min2 (el[1], el[3]))
min2pi = &ntets[0][0];
else
min2pi = &ntets[1][0];
bool firsttet = 1;
for (int j = 0; j < 2; j++)
{
Element nel(TET);
for (int k = 0; k < 4; k++)
nel[k] = el[min2pi[4*j + k]-1];
nel.SetIndex (el.GetIndex());
// cout << "pyramid-tet: " << nel << endl;
bool legal = 1;
for (int k = 0; k < 3; k++)
for (int l = k+1; l < 4; l++)
if (nel[k] == nel[l])
legal = 0;
if (legal)
{
(*testout) << nel << " ";
if (firsttet)
VolumeElement(i) = nel;
else
AddVolumeElement(nel);
firsttet = 0;
}
}
if (firsttet) cout << "no legal";
(*testout) << endl;
}
}
int oldnse = GetNSE();
for (int i = 1; i <= oldnse; i++)
{
Element2d el = SurfaceElement(i);
if (el.GetNP() == 4)
{
(*testout) << "split el: " << el << " to ";
static const int ntris[2][6] =
{ { 1, 2, 3, 1, 3, 4 },
{ 1, 2, 4, 4, 2, 3 }};
const int * min2pi;
if (min2 (el.PNum(1), el.PNum(3)) <
min2 (el.PNum(2), el.PNum(4)))
min2pi = &ntris[0][0];
else
min2pi = &ntris[1][0];
for (int j = 0; j <6; j++)
(*testout) << min2pi[j] << " ";
int firsttri = 1;
for (int j = 1; j <= 2; j++)
{
Element2d nel(3);
for (int k = 1; k <= 3; k++)
nel.PNum(k) = el.PNum(min2pi[3 * j + k - 4]);
nel.SetIndex (el.GetIndex());
int legal = 1;
for (int k = 1; k <= 2; k++)
for (int l = k+1; l <= 3; l++)
if (nel.PNum(k) == nel.PNum(l))
legal = 0;
if (legal)
{
(*testout) << nel << " ";
if (firsttri)
{
SurfaceElement(i) = nel;
firsttri = 0;
}
else
{
AddSurfaceElement(nel);
}
}
}
(*testout) << endl;
}
}
if (has_prisms)
Split2Tets();
else
{
for (int i = 1; i <= GetNE(); i++)
{
Element & el = VolumeElement(i);
const Point3d & p1 = Point (el.PNum(1));
const Point3d & p2 = Point (el.PNum(2));
const Point3d & p3 = Point (el.PNum(3));
const Point3d & p4 = Point (el.PNum(4));
double vol = (Vec3d (p1, p2) *
Cross (Vec3d (p1, p3), Vec3d(p1, p4)));
if (vol > 0)
swap (el.PNum(3), el.PNum(4));
}
UpdateTopology();
timestamp = NextTimeStamp();
}
RebuildSurfaceElementLists();
}
void Mesh :: BuildElementSearchTree ()
{
if (elementsearchtreets == GetTimeStamp()) return;
{
std::lock_guard<std::mutex> guard(buildsearchtree_mutex);
if (elementsearchtreets != GetTimeStamp())
{
NgLock lock(mutex);
lock.Lock();
PrintMessage (4, "Rebuild element searchtree");
elementsearchtree = nullptr;
int ne = (dimension == 2) ? GetNSE() : GetNE();
if (dimension == 3 && !GetNE() && GetNSE())
ne = GetNSE();
if (ne)
{
if (dimension == 2 || (dimension == 3 && !GetNE()) )
{
Box<3> box (Box<3>::EMPTY_BOX);
for (SurfaceElementIndex sei = 0; sei < ne; sei++)
// box.Add (points[surfelements[sei].PNums()]);
for (auto pi : surfelements[sei].PNums())
box.Add (points[pi]);
box.Increase (1.01 * box.Diam());
elementsearchtree = make_unique<BoxTree<3>> (box);
for (SurfaceElementIndex sei = 0; sei < ne; sei++)
{
// box.Set (points[surfelements[sei].PNums()]);
Box<3> box (Box<3>::EMPTY_BOX);
for (auto pi : surfelements[sei].PNums())
box.Add (points[pi]);
auto & el = surfelements[sei];
if(el.IsCurved() && curvedelems->IsSurfaceElementCurved(sei))
{
netgen::Point<2> lami [4] = {netgen::Point<2>(0.5,0), netgen::Point<2>(0,0.5), netgen::Point<2>(0.5,0.5), netgen::Point<2>(1./3,1./3)};
for (auto lam : lami)
{
netgen::Point<3> x;
Mat<3,2> Jac;
curvedelems->CalcSurfaceTransformation(lam,sei,x,Jac);
box.Add (x);
}
box.Scale(1.2);
}
elementsearchtree -> Insert (box, sei+1);
}
}
else
{
Box<3> box (Box<3>::EMPTY_BOX);
for (ElementIndex ei = 0; ei < ne; ei++)
// box.Add (points[volelements[ei].PNums()]);
for (auto pi : volelements[ei].PNums())
box.Add (points[pi]);
box.Increase (1.01 * box.Diam());
elementsearchtree = make_unique<BoxTree<3>> (box);
for (ElementIndex ei = 0; ei < ne; ei++)
{
// box.Set (points[volelements[ei].PNums()]);
Box<3> box (Box<3>::EMPTY_BOX);
for (auto pi : volelements[ei].PNums())
box.Add (points[pi]);
auto & el = volelements[ei];
if(el.IsCurved() && curvedelems->IsElementCurved(ei))
box.Scale(1.2);
elementsearchtree -> Insert (box, ei+1);
}
}
elementsearchtreets = GetTimeStamp();
}
}
}
}
int SolveLinearSystemLS (const Vec3d & col1,
const Vec3d & col2,
const Vec3d & rhs,
Vec2d & sol)
{
double a11 = col1 * col1;
double a12 = col1 * col2;
double a22 = col2 * col2;
double det = a11 * a22 - a12 * a12;
if (det*det <= 1e-24 * a11 * a22)
{
sol = Vec2d (0, 0);
return 1;
}
Vec2d aTrhs;
aTrhs.X() = col1*rhs;
aTrhs.Y() = col2*rhs;
sol.X() = ( a22 * aTrhs.X() - a12 * aTrhs.Y()) / det;
sol.Y() = (-a12 * aTrhs.X() + a11 * aTrhs.Y()) / det;
return 0;
}
bool ValidBarCoord(double lami[3], double eps=1e-12)
{
return (lami[0]<=1.+eps && lami[0]>=0.-eps && lami[1]<=1.+eps && lami[1]>=0.-eps && lami[2]<=1.+eps && lami[2]>=0.-eps );
}
bool Mesh :: PointContainedIn2DElement(const Point3d & p,
double lami[3],
const int element,
bool consider3D) const
{
Vec3d col1, col2, col3;
Vec3d rhs, sol;
const double eps = 1e-6;
NgArray<Element2d> loctrigs;
//SZ
if(SurfaceElement(element).GetType()==QUAD)
{
const Element2d & el = SurfaceElement(element);
const Point3d & p1 = Point(el.PNum(1));
const Point3d & p2 = Point(el.PNum(2));
const Point3d & p3 = Point(el.PNum(3));
const Point3d & p4 = Point(el.PNum(4));
// Coefficients of Bilinear Mapping from Ref-Elem to global Elem
// X = a + b x + c y + d x y
Vec3d a = p1;
Vec3d b = p2 - a;
Vec3d c = p4 - a;
Vec3d d = p3 - a - b - c;
/*cout << "p = " << p << endl;
cout << "p1 = " << p1 << endl;
cout << "p2 = " << p2 << endl;
cout << "p3 = " << p3 << endl;
cout << "p4 = " << p4 << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
cout << "d = " << d << endl;*/
Vec3d pa = p-a;
double dxb = d.X()*b.Y()-d.Y()*b.X();
double dxc = d.X()*c.Y()-d.Y()*c.X();
double bxc = b.X()*c.Y()-b.Y()*c.X();
double bxpa = b.X()*pa.Y()-b.Y()*pa.X();
double cxpa = c.X()*pa.Y()-c.Y()*pa.X();
double dxpa = d.X()*pa.Y()-d.Y()*pa.X();
/*cout << "dxb = " << dxb << endl;
cout << "dxc = " << dxc << endl;
cout << "bxc = " << bxc << endl;
cout << "bxpa = " << bxpa << endl;
cout << "cxpa = " << cxpa << endl;
cout << "dxpa = " << dxpa << endl;*/
/*
P = a + b x + c y + d x y
1) P1 = a1 + b1 x + c1 y + d1 x y
2) P2 = a2 + b2 x + c2 y + d2 x y
-> det(x,d) = det(a,d) + det(b,d) x + det(c,d) y
-> x = 1/det(b,d) *( det(P-a,d)-det(c,d) y )
-> y = 1/det(c,d) *( det(P-a,d)-det(b,d) x )
-> x = (P1 - a1 - c1 y)/(b1 + d1 y)
-> det(c,d) y**2 + [det(d,P-a) + det(c,b)] y + det(b,P-a) = 0
( same if we express x = (P2 - a2 - c2 y)/(b2 + d2 y) )
-> y = (P1 - a1 - b1 x)/(c1 + d1 x)
-> det(b,d) x**2 + [det(d,P-a) + det(b,c)] x + det(c,P-a) = 0
( same if we express y = (P2 - a2 - b2 x)/(c2 + d2 x)
*/
lami[2]=0.;
double eps = 1.E-12;
double c1,c2,r;
//First check if point is "exactly" a vertex point
Vec3d d1 = p-p1;
Vec3d d2 = p-p2;
Vec3d d3 = p-p3;
Vec3d d4 = p-p4;
//cout << " d1 = " << d1 << ", d2 = " << d2 << ", d3 = " << d3 << ", d4 = " << d4 << endl;
if (d1.Length2() < sqr(eps)*d2.Length2() && d1.Length2() < sqr(eps)*d3.Length2() && d1.Length2() < sqr(eps)*d4.Length2())
{
lami[0] = lami[1] = 0.;
return true;
}
else if (d2.Length2() < sqr(eps)*d1.Length2() && d2.Length2() < sqr(eps)*d3.Length2() && d2.Length2() < sqr(eps)*d4.Length2())
{
lami[0] = 1.;
lami[1] = 0.;
return true;
}
else if (d3.Length2() < sqr(eps)*d1.Length2() && d3.Length2() < sqr(eps)*d2.Length2() && d3.Length2() < sqr(eps)*d4.Length2())
{
lami[0] = lami[1] = 1.;
return true;
}
else if (d4.Length2() < sqr(eps)*d1.Length2() && d4.Length2() < sqr(eps)*d2.Length2() && d4.Length2() < sqr(eps)*d3.Length2())
{
lami[0] = 0.;
lami[1] = 1.;
return true;
}//if d is nearly 0: solve resulting linear system
else if (d.Length2() < sqr(eps)*b.Length2() && d.Length2() < sqr(eps)*c.Length2())
{
Vec2d sol;
SolveLinearSystemLS (b, c, p-a, sol);
lami[0] = sol.X();
lami[1] = sol.Y();
return ValidBarCoord(lami, eps);
}// if dxc is nearly 0: solve resulting linear equation for y and compute x
else if (fabs(dxc) < sqr(eps))
{
lami[1] = -bxpa/(dxpa-bxc);
lami[0] = (dxpa-dxc*lami[1])/dxb;
return ValidBarCoord(lami, eps);
}// if dxb is nearly 0: solve resulting linear equation for x and compute y
else if (fabs(dxb) < sqr(eps))
{
lami[0] = -cxpa/(dxpa+bxc);
lami[1] = (dxpa-dxb*lami[0])/dxc;
return ValidBarCoord(lami, eps);
}//if dxb >= dxc: solve quadratic equation in y and compute x
else if (fabs(dxb) >= fabs(dxc))
{
c1 = (bxc-dxpa)/dxc;
c2 = -bxpa/dxc;
r = c1*c1/4.0-c2;
//quadratic equation has only 1 (unstable) solution
if (fabs(r) < eps) //not eps^2!
{
lami[1] = -c1/2;
lami[0] = (dxpa-dxc*lami[1])/dxb;
return ValidBarCoord(lami, eps);
}
if (r < 0) return false;
lami[1] = -c1/2+sqrt(r);
lami[0] = (dxpa-dxc*lami[1])/dxb;
if (ValidBarCoord(lami, eps))
return true;
else
{
lami[1] = -c1/2-sqrt(r);
lami[0] = (dxpa-dxc*lami[1])/dxb;
return ValidBarCoord(lami, eps);
}
}//if dxc > dxb: solve quadratic equation in x and compute y
else
{
c1 = (-bxc-dxpa)/dxb;
c2 = -cxpa/dxb;
r = c1*c1/4.0-c2;
//quadratic equation has only 1 (unstable) solution
if (fabs(r) < eps) //not eps^2!
{
lami[0] = -c1/2;
lami[1] = (dxpa-dxb*lami[0])/dxc;
return ValidBarCoord(lami, eps);
}
if (r < 0) return false;
lami[0] = -c1/2+sqrt(r);
lami[1] = (dxpa-dxb*lami[0])/dxc;
if (ValidBarCoord(lami, eps))
return true;
else
{
lami[0] = -c1/2-sqrt(r);
lami[1] = (dxpa-dxb*lami[0])/dxc;
return ValidBarCoord(lami, eps);
}
}
/*
double dxa = d.X()*a.Y()-d.Y()*a.X();
double dxp = d.X()*p.Y()-d.Y()*p.X();
double c0,c1,c2; // ,rt;
Vec3d dp13 = p3-p1;
Vec3d dp24 = p4-p2;
double d1 = dp13.Length2();
double d2 = dp24.Length2();
// if(fabs(d.X()) <= eps && fabs(d.Y())<= eps)
//if (d.Length2() < sqr(eps))
if (d.Length2() < sqr(eps)*d1 && d.Length2() < sqr(eps)*d2)
{
//Solve Linear System
Vec2d sol;
SolveLinearSystemLS (b, c, p-a, sol);
lami[0] = sol.X();
lami[1] = sol.Y();
if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps)
return true;
//lami[0]=(c.Y()*(p.X()-a.X())-c.X()*(p.Y()-a.Y()))/
//(b.X()*c.Y() -b.Y()*c.X());
//lami[1]=(-b.Y()*(p.X()-a.X())+b.X()*(p.Y()-a.Y()))/
// (b.X()*c.Y() -b.Y()*c.X());
}
else
if(fabs(dxb) <= eps*fabs(dxc))
{
lami[1] = (dxp-dxa)/dxc;
if(fabs(b.X()+d.X()*lami[1])>=fabs(b.Y()+d.Y()*lami[1]))
lami[0] = (p.X()-a.X() - c.X()*lami[1])/(b.X()+d.X()*lami[1]);
else
lami[0] = (p.Y()-a.Y() - c.Y()*lami[1])/(b.Y()+d.Y()*lami[1]);
if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps)
return true;
}
else
if(fabs(dxc) <= eps*fabs(dxb))
{
lami[0] = (dxp-dxa)/dxb;
if(fabs(c.X()+d.X()*lami[0])>=fabs(c.Y()+d.Y()*lami[0]))
lami[1] = (p.X()-a.X() - b.X()*lami[0])/(c.X()+d.X()*lami[0]);
else
lami[1] = (p.Y()-a.Y() - b.Y()*lami[0])/(c.Y()+d.Y()*lami[0]);
if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps)
return true;
}
else //Solve quadratic equation
{
c2 = -d.X()*dxb;
c1 = b.X()*dxc - c.X()*dxb + d.X()*(dxp-dxa);
c0 = c.X()*(dxp-dxa) + (a.X()-p.X())*dxc;
double rt = c1*c1 - 4*c2*c0;
if (rt < 0.) return false;
lami[1] = (-c1 + sqrt(rt))/2/c2;
if(lami[1]<=1.+eps && lami[1]>=0.-eps)
{
lami[0] = (dxp - dxa -dxb*lami[1])/dxc;
if(lami[0]<=1.+eps && lami[0]>=0.-eps)
return true;
}
lami[1] = (-c1 - sqrt(rt))/2/c2;
lami[0] = (dxp - dxa -dxb*lami[1])/dxc;
if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps)
return true;
c2 = d.Y()*dxb;
c1 = b.Y()*dxc - c.Y()*dxb + d.Y()*(dxp-dxa);
c0 = c.Y()*(dxp -dxa) + (a.Y()-p.Y())*dxc;
rt = c1*c1 - 4*c2*c0;
if (rt < 0.) return false;
lami[1] = (-c1 + sqrt(rt))/2/c2;
if(lami[1]<=1.+eps && lami[1]>=0.-eps)
{
lami[0] = (dxp - dxa -dxb*lami[1])/dxc;
if(lami[0]<=1.+eps && lami[0]>=0.-eps)
return true;
}
lami[1] = (-c1 - sqrt(rt))/2/c2;
lami[0] = (dxp - dxa -dxb*lami[1])/dxc;
if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps)
return true;
c2 = -d.X()*dxc;
c1 = -b.X()*dxc + c.X()*dxb + d.X()*(dxp-dxa);
c0 = b.X()*(dxp -dxa) + (a.X()-p.X())*dxb;
rt = c1*c1 - 4*c2*c0;
if (rt < 0.) return false;
lami[1] = (-c1 + sqrt(rt))/2/c2;
if(lami[1]<=1.+eps && lami[1]>=0.-eps)
{
lami[0] = (dxp - dxa -dxc*lami[1])/dxb;
if(lami[0]<=1.+eps && lami[0]>=0.-eps)
return true;
}
lami[1] = (-c1 - sqrt(rt))/2/c2;
lami[0] = (dxp - dxa -dxc*lami[1])/dxb;
if(lami[1]<=1.+eps && lami[1]>=0.-eps && lami[0]<=1.+eps && lami[0]>=0.-eps)
return true;
}*/
//cout << "lam0,1 = " << lami[0] << ", " << lami[1] << endl;
/*if( lami[0] <= 1.+eps && lami[0] >= -eps && lami[1]<=1.+eps && lami[1]>=-eps)
{
if(consider3D)
{
Vec3d n = Cross(b,c);
lami[2] = 0;
for(int i=1; i<=3; i++)
lami[2] +=(p.X(i)-a.X(i)-lami[0]*b.X(i)-lami[1]*c.X(i)) * n.X(i);
if(lami[2] >= -eps && lami[2] <= eps)
return true;
}
else
return true;
}*/
return false;
}
else
{
// SurfaceElement(element).GetTets (loctets);
loctrigs.SetSize(1);
loctrigs.Elem(1) = SurfaceElement(element);
for (int j = 1; j <= loctrigs.Size(); j++)
{
const Element2d & el = loctrigs.Get(j);
const Point3d & p1 = Point(el.PNum(1));
const Point3d & p2 = Point(el.PNum(2));
const Point3d & p3 = Point(el.PNum(3));
/*
Box3d box;
box.SetPoint (p1);
box.AddPoint (p2);
box.AddPoint (p3);
box.AddPoint (p4);
if (!box.IsIn (p))
continue;
*/
col1 = p2-p1;
col2 = p3-p1;
col3 = Cross(col1,col2);
//col3 = Vec3d(0, 0, 1);
rhs = p - p1;
// int retval =
SolveLinearSystem (col1, col2, col3, rhs, sol);
//(*testout) << "retval " << retval << endl;
//(*testout) << "col1 " << col1 << " col2 " << col2 << " col3 " << col3 << " rhs " << rhs << endl;
//(*testout) << "sol " << sol << endl;
if (SurfaceElement(element).GetType() ==TRIG6 || curvedelems->IsSurfaceElementCurved(element-1))
{
netgen::Point<2> lam(1./3,1./3);
Vec<3> rhs;
Vec<2> deltalam;
netgen::Point<3> x;
Mat<3,2> Jac,Jact;
double delta=1;
bool retval;
int i = 0;
const int maxits = 30;
while(delta > 1e-16 && i<maxits)
{
curvedelems->CalcSurfaceTransformation(lam,element-1,x,Jac);
rhs = p-x;
Jac.Solve(rhs,deltalam);
lam += deltalam;
delta = deltalam.Length2();
i++;
//(*testout) << "pcie i " << i << " delta " << delta << " p " << p << " x " << x << " lam " << lam << endl;
//<< "Jac " << Jac << endl;
}
if(i==maxits)
return false;
sol.X() = lam(0);
sol.Y() = lam(1);
if (SurfaceElement(element).GetType() !=TRIG6 )
{
sol.Z() = sol.X();
sol.X() = sol.Y();
sol.Y() = 1.0 - sol.Z() - sol.X();
}
}
if (sol.X() >= -eps && sol.Y() >= -eps &&
sol.X() + sol.Y() <= 1+eps)
{
if(!consider3D || (sol.Z() >= -eps && sol.Z() <= eps))
{
lami[0] = sol.X();
lami[1] = sol.Y();
lami[2] = sol.Z();
return true;
}
}
}
}
return false;
}
bool Mesh :: PointContainedIn3DElement(const Point3d & p,
double lami[3],
const int element) const
{
//bool oldresult = PointContainedIn3DElementOld(p,lami,element);
//(*testout) << "old result: " << oldresult
// << " lam " << lami[0] << " " << lami[1] << " " << lami[2] << endl;
//if(!curvedelems->IsElementCurved(element-1))
// return PointContainedIn3DElementOld(p,lami,element);
const double eps = 1.e-4;
const Element & el = VolumeElement(element);
netgen::Point<3> lam = 0.0;
if (el.GetType() == TET || el.GetType() == TET10)
{
lam = 0.25;
}
else if (el.GetType() == PRISM)
{
lam(0) = 0.33; lam(1) = 0.33; lam(2) = 0.5;
}
else if (el.GetType() == PYRAMID)
{
lam(0) = 0.4; lam(1) = 0.4; lam(2) = 0.2;
}
else if (el.GetType() == HEX)
{
lam = 0.5;
}
Vec<3> deltalam,rhs;
netgen::Point<3> x;
Mat<3,3> Jac,Jact;
double delta=1;
bool retval;
int i = 0;
const int maxits = 30;
while(delta > 1e-16 && i<maxits)
{
curvedelems->CalcElementTransformation(lam,element-1,x,Jac);
rhs = p-x;
Jac.Solve(rhs,deltalam);
lam += deltalam;
delta = deltalam.Length2();
i++;
//(*testout) << "pcie i " << i << " delta " << delta << " p " << p << " x " << x << " lam " << lam << endl;
//<< "Jac " << Jac << endl;
}
if(i==maxits)
return false;
for(i=0; i<3; i++)
lami[i] = lam(i);
if (el.GetType() == TET || el.GetType() == TET10)
{
retval = (lam(0) > -eps &&
lam(1) > -eps &&
lam(2) > -eps &&
lam(0) + lam(1) + lam(2) < 1+eps);
}
else if (el.GetType() == PRISM || el.GetType() == PRISM15)
{
retval = (lam(0) > -eps &&
lam(1) > -eps &&
lam(2) > -eps &&
lam(2) < 1+eps &&
lam(0) + lam(1) < 1+eps);
}
else if (el.GetType() == PYRAMID || el.GetType() == PYRAMID13)
{
retval = (lam(0) > -eps &&
lam(1) > -eps &&
lam(2) > -eps &&
lam(0) + lam(2) < 1+eps &&
lam(1) + lam(2) < 1+eps);
}
else if (el.GetType() == HEX || el.GetType() == HEX20)
{
retval = (lam(0) > -eps && lam(0) < 1+eps &&
lam(1) > -eps && lam(1) < 1+eps &&
lam(2) > -eps && lam(2) < 1+eps);
}
else
throw NgException("Da haun i wos vagessn");
return retval;
}
bool Mesh :: PointContainedIn3DElementOld(const Point3d & p,
double lami[3],
const int element) const
{
Vec3d col1, col2, col3;
Vec3d rhs, sol;
const double eps = 1.e-4;
NgArray<Element> loctets;
VolumeElement(element).GetTets (loctets);
for (int j = 1; j <= loctets.Size(); j++)
{
const Element & el = loctets.Get(j);
const Point3d & p1 = Point(el.PNum(1));
const Point3d & p2 = Point(el.PNum(2));
const Point3d & p3 = Point(el.PNum(3));
const Point3d & p4 = Point(el.PNum(4));
Box3d box;
box.SetPoint (p1);
box.AddPoint (p2);
box.AddPoint (p3);
box.AddPoint (p4);
if (!box.IsIn (p))
continue;
col1 = p2-p1;
col2 = p3-p1;
col3 = p4-p1;
rhs = p - p1;
SolveLinearSystem (col1, col2, col3, rhs, sol);
if (sol.X() >= -eps && sol.Y() >= -eps && sol.Z() >= -eps &&
sol.X() + sol.Y() + sol.Z() <= 1+eps)
{
NgArray<Element> loctetsloc;
NgArray<netgen::Point<3> > pointsloc;
VolumeElement(element).GetTetsLocal (loctetsloc);
VolumeElement(element).GetNodesLocalNew (pointsloc);
const Element & le = loctetsloc.Get(j);
Point3d pp =
pointsloc.Get(le.PNum(1))
+ sol.X() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(2)))
+ sol.Y() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(3)))
+ sol.Z() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(4))) ;
lami[0] = pp.X();
lami[1] = pp.Y();
lami[2] = pp.Z();
return true;
}
}
return false;
}
int Mesh :: GetElementOfPoint (const netgen::Point<3> & p,
double lami[3],
bool build_searchtree,
const int index,
const bool allowindex) const
{
if(index != -1)
{
NgArray<int> dummy(1);
dummy[0] = index;
return GetElementOfPoint(p,lami,&dummy,build_searchtree,allowindex);
}
else
return GetElementOfPoint(p,lami,NULL,build_searchtree,allowindex);
}
int Mesh :: GetElementOfPoint (const netgen::Point<3> & p,
double lami[3],
const NgArray<int> * const indices,
bool build_searchtree,
const bool allowindex) const
{
if ( (dimension == 2 && !GetNSE()) ||
(dimension == 3 && !GetNE() && !GetNSE()) )
return -1;
if (build_searchtree)
const_cast<Mesh&>(*this).BuildElementSearchTree ();
if (dimension == 2 || (dimension==3 && !GetNE() && GetNSE()))
return Find2dElement(*this, p, lami, indices, elementsearchtree.get(), allowindex);
return Find3dElement(*this, p, lami, indices, elementsearchtree.get(), allowindex);
}
int Mesh :: GetSurfaceElementOfPoint (const netgen::Point<3> & p,
double lami[3],
bool build_searchtree,
const int index,
const bool allowindex) const
{
if(index != -1)
{
NgArray<int> dummy(1);
dummy[0] = index;
return GetSurfaceElementOfPoint(p,lami,&dummy,build_searchtree,allowindex);
}
else
return GetSurfaceElementOfPoint(p,lami,NULL,build_searchtree,allowindex);
}
int Mesh :: GetSurfaceElementOfPoint (const netgen::Point<3> & p,
double lami[3],
const NgArray<int> * const indices,
bool build_searchtree,
const bool allowindex) const
{
if (!GetNE() && build_searchtree)
const_cast<Mesh&>(*this).BuildElementSearchTree ();
if (dimension == 2)
return Find1dElement(*this, p, lami, indices, elementsearchtree.get(), allowindex);
else
return Find2dElement(*this, p, lami, indices, elementsearchtree.get(), allowindex);
return 0;
}
void Mesh::GetIntersectingVolEls(const Point3d& p1, const Point3d& p2,
NgArray<int> & locels) const
{
elementsearchtree->GetIntersecting (p1, p2, locels);
}
void Mesh :: SplitIntoParts()
{
int i, j, dom;
int ne = GetNE();
int np = GetNP();
int nse = GetNSE();
NgBitArray surfused(nse);
NgBitArray pused (np);
surfused.Clear();
dom = 0;
while (1)
{
int cntd = 1;
dom++;
pused.Clear();
int found = 0;
for (i = 1; i <= nse; i++)
if (!surfused.Test(i))
{
SurfaceElement(i).SetIndex (dom);
for (j = 1; j <= 3; j++)
pused.Set (SurfaceElement(i).PNum(j));
found = 1;
cntd = 1;
surfused.Set(i);
break;
}
if (!found)
break;
int change;
do
{
change = 0;
for (i = 1; i <= nse; i++)
{
int is = 0, isnot = 0;
for (j = 1; j <= 3; j++)
if (pused.Test(SurfaceElement(i).PNum(j)))
is = 1;
else
isnot = 1;
if (is && isnot)
{
change = 1;
for (j = 1; j <= 3; j++)
pused.Set (SurfaceElement(i).PNum(j));
}
if (is)
{
if (!surfused.Test(i))
{
surfused.Set(i);
SurfaceElement(i).SetIndex (dom);
cntd++;
}
}
}
for (i = 1; i <= ne; i++)
{
int is = 0, isnot = 0;
for (j = 1; j <= 4; j++)
if (pused.Test(VolumeElement(i).PNum(j)))
is = 1;
else
isnot = 1;
if (is && isnot)
{
change = 1;
for (j = 1; j <= 4; j++)
pused.Set (VolumeElement(i).PNum(j));
}
if (is)
{
VolumeElement(i).SetIndex (dom);
}
}
}
while (change);
PrintMessage (3, "domain ", dom, " has ", cntd, " surfaceelements");
}
/*
facedecoding.SetSize (dom);
for (i = 1; i <= dom; i++)
{
facedecoding.Elem(i).surfnr = 0;
facedecoding.Elem(i).domin = i;
facedecoding.Elem(i).domout = 0;
}
*/
ClearFaceDescriptors();
for (i = 1; i <= dom; i++)
AddFaceDescriptor (FaceDescriptor (0, i, 0, 0));
CalcSurfacesOfNode();
timestamp = NextTimeStamp();
}
void Mesh :: SplitSeparatedFaces ()
{
PrintMessage (3, "SplitSeparateFaces");
int fdi;
int np = GetNP();
NgBitArray usedp(np);
Array<SurfaceElementIndex> els_of_face;
fdi = 1;
while (fdi <= GetNFD())
{
GetSurfaceElementsOfFace (fdi, els_of_face);
if (els_of_face.Size() == 0)
{
fdi++;
continue;
}
SurfaceElementIndex firstel = els_of_face[0];
usedp.Clear();
for (int j = 1; j <= SurfaceElement(firstel).GetNP(); j++)
usedp.Set (SurfaceElement(firstel).PNum(j));
bool changed;
do
{
changed = false;
for (int i = 0; i < els_of_face.Size(); i++)
{
const Element2d & el = SurfaceElement(els_of_face[i]);
bool has = 0;
bool hasno = 0;
for (int j = 0; j < el.GetNP(); j++)
{
if (usedp.Test(el[j]))
has = true;
else
hasno = true;
}
if (has && hasno)
changed = true;
if (has)
for (int j = 0; j < el.GetNP(); j++)
usedp.Set (el[j]);
}
}
while (changed);
int nface = 0;
for (int i = 0; i < els_of_face.Size(); i++)
{
Element2d & el = SurfaceElement(els_of_face[i]);
int hasno = 0;
for (int j = 1; j <= el.GetNP(); j++)
if (!usedp.Test(el.PNum(j)))
hasno = 1;
if (hasno)
{
if (!nface)
{
FaceDescriptor nfd = GetFaceDescriptor(fdi);
nface = AddFaceDescriptor (nfd);
}
el.SetIndex (nface);
}
}
// reconnect list
if (nface)
{
facedecoding[nface-1].firstelement = -1;
facedecoding[fdi-1].firstelement = -1;
for (int i = 0; i < els_of_face.Size(); i++)
{
int ind = SurfaceElement(els_of_face[i]).GetIndex();
SurfaceElement(els_of_face[i]).next = facedecoding[ind-1].firstelement;
facedecoding[ind-1].firstelement = els_of_face[i];
}
// map the segments
for(auto& seg : segments)
if(!usedp.Test(seg[0]) || !usedp.Test(seg[1]))
if(seg.si == fdi)
seg.si = nface;
}
fdi++;
}
/*
fdi = 1;
while (fdi <= GetNFD())
{
int firstel = 0;
for (int i = 1; i <= GetNSE(); i++)
if (SurfaceElement(i).GetIndex() == fdi)
{
firstel = i;
break;
}
if (!firstel) continue;
usedp.Clear();
for (int j = 1; j <= SurfaceElement(firstel).GetNP(); j++)
usedp.Set (SurfaceElement(firstel).PNum(j));
int changed;
do
{
changed = 0;
for (int i = 1; i <= GetNSE(); i++)
{
const Element2d & el = SurfaceElement(i);
if (el.GetIndex() != fdi)
continue;
int has = 0;
int hasno = 0;
for (int j = 1; j <= el.GetNP(); j++)
{
if (usedp.Test(el.PNum(j)))
has = 1;
else
hasno = 1;
}
if (has && hasno)
changed = 1;
if (has)
for (int j = 1; j <= el.GetNP(); j++)
usedp.Set (el.PNum(j));
}
}
while (changed);
int nface = 0;
for (int i = 1; i <= GetNSE(); i++)
{
Element2d & el = SurfaceElement(i);
if (el.GetIndex() != fdi)
continue;
int hasno = 0;
for (int j = 1; j <= el.GetNP(); j++)
{
if (!usedp.Test(el.PNum(j)))
hasno = 1;
}
if (hasno)
{
if (!nface)
{
FaceDescriptor nfd = GetFaceDescriptor(fdi);
nface = AddFaceDescriptor (nfd);
}
el.SetIndex (nface);
}
}
fdi++;
}
*/
}
void Mesh :: ZRefine(const string& name, const Array<double>& slices)
{
auto nr = GetIdentifications().GetNr(name);
auto& identpts = GetIdentifications().GetIdentifiedPoints();
UpdateTopology();
std::map<std::pair<PointIndex, PointIndex>,
Array<PointIndex>> inserted_points;
BitArray mapped_points(GetNV()+1);
mapped_points = false;
// Add new points
for(auto [p1p2, idnr] : identpts)
{
if(idnr != nr)
continue;
auto& ipts = inserted_points[{p1p2.I1(), p1p2.I2()}];
auto p1 = Point(p1p2.I1());
auto p2 = Point(p1p2.I2());
ipts.Append(p1p2.I1());
mapped_points.SetBit(p1p2.I1());
for(auto slice : slices)
{
auto np = p1 + slice * (p2-p1);
auto npi = AddPoint(np);
ipts.Append(npi);
}
ipts.Append(p1p2.I2());
}
// Split segments
for(auto si : Range(segments))
{
auto& seg = segments[si];
auto p1 = seg[0];
auto p2 = seg[1];
auto c1 = inserted_points.count({p1, p2});
auto c2 = inserted_points.count({p2, p1});
if(c1 == 0 && c2 == 0)
continue;
if(c2)
Swap(p1,p2);
const auto& ipts = inserted_points[{p1,p2}];
if(c2)
seg[1] = ipts[ipts.Size()-2];
else
seg[1] = ipts[1];
for(auto i : Range(size_t(1), ipts.Size()-1))
{
Segment snew = seg;
if(c2)
{
seg[0] = ipts[ipts.Size()-1-i];
seg[1] = ipts[ipts.Size()-2-i];
}
else
{
snew[0] = ipts[i];
snew[1] = ipts[i+1];
}
AddSegment(snew);
}
}
BitArray sel_done(surfelements.Size());
sel_done = false;
// Split surface elements
auto p2sel = CreatePoint2SurfaceElementTable();
for(const auto& [pair, inserted] : inserted_points)
{
for(auto si : p2sel[pair.first])
{
if(sel_done[si])
continue;
sel_done.SetBit(si);
auto sel = surfelements[si];
map<PointIndex, Array<PointIndex>> mapped_points;
int nmapped = 0;
for(auto i : Range(sel.GetNP()))
{
auto p1 = sel[i];
auto p2 = sel[(i+1)%sel.GetNP()];
auto c1 = inserted_points.count({p1, p2});
auto c2 = inserted_points.count({p2, p1});
if(c1 == 0 && c2 == 0)
continue;
if(c2)
Swap(p1, p2);
auto& ipts = inserted_points[{p1, p2}];
auto& a1 = mapped_points[p1];
auto& a2 = mapped_points[p2];
a1 = ipts.Range(0, ipts.Size()-1);
a2 = ipts.Range(1, ipts.Size());
nmapped = ipts.Size()-1;
}
for(auto i : Range(nmapped))
{
Element2d nsel = sel;
for(auto& pi : nsel.PNums())
if(mapped_points.count(pi))
pi = mapped_points[pi][i];
AddSurfaceElement(nsel);
}
if(nmapped)
surfelements[si].Delete();
}
}
// Split volume elements
BitArray vol_done(volelements.Size());
vol_done = false;
auto p2el = CreatePoint2ElementTable(); // mapped_points);
for(const auto& [pair, inserted] : inserted_points)
{
for(auto ei : p2el[pair.first])
{
if(vol_done[ei])
continue;
vol_done.SetBit(ei);
auto el = volelements[ei];
map<PointIndex, Array<PointIndex>> mapped_points;
int nmapped = 0;
// NgArray<int> eledges;
// topology.GetElementEdges(ei+1, eledges);
// for(auto edgei : eledges)
for(auto edgei : topology.GetEdges(ElementIndex(ei)))
{
int p1, p2;
topology.GetEdgeVertices(edgei+1, p1, p2);
auto c1 = inserted_points.count({p1, p2});
auto c2 = inserted_points.count({p2, p1});
if(c1 == 0 && c2 == 0)
continue;
if(c2)
Swap(p1, p2);
auto& ipts = inserted_points[{p1, p2}];
auto& a1 = mapped_points[p1];
auto& a2 = mapped_points[p2];
a1 = ipts.Range(0, ipts.Size()-1);
a2 = ipts.Range(1, ipts.Size());
nmapped = ipts.Size()-1;
}
for(auto i : Range(nmapped))
{
Element nel = el;
for(auto& pi : nel.PNums())
if(mapped_points.count(pi))
pi = mapped_points[pi][i];
AddVolumeElement(nel);
}
if(nmapped)
volelements[ei].Delete();
}
}
Compress();
SetNextMajorTimeStamp();
}
void Mesh :: RebuildSurfaceElementLists ()
{
static Timer t("Mesh::LinkSurfaceElements"); RegionTimer reg (t);
for (int i = 0; i < facedecoding.Size(); i++)
facedecoding[i].firstelement = -1;
for (int i = surfelements.Size()-1; i >= 0; i--)
{
int ind = surfelements[i].GetIndex();
surfelements[i].next = facedecoding[ind-1].firstelement;
facedecoding[ind-1].firstelement = i;
}
}
void Mesh :: GetSurfaceElementsOfFace (int facenr, Array<SurfaceElementIndex> & sei) const
{
static int timer = NgProfiler::CreateTimer ("GetSurfaceElementsOfFace");
NgProfiler::RegionTimer reg (timer);
if(facenr==0)
{
sei.SetSize(GetNSE());
ParallelForRange( IntRange(GetNSE()), [&sei] (auto myrange)
{
for(auto i : myrange)
sei[i] = i;
});
return;
}
sei.SetSize(0);
SurfaceElementIndex si = facedecoding[facenr-1].firstelement;
while (si != -1)
{
if ( (*this)[si].GetIndex () == facenr && (*this)[si][0] >= PointIndex::BASE &&
!(*this)[si].IsDeleted() )
{
sei.Append (si);
}
si = (*this)[si].next;
}
}
void Mesh :: CalcMinMaxAngle (double badellimit, double * retvalues)
{
int i, j;
int lpi1, lpi2, lpi3, lpi4;
double phimax = 0, phimin = 10;
double facephimax = 0, facephimin = 10;
int illegaltets = 0, negativetets = 0, badtets = 0;
for (i = 1; i <= GetNE(); i++)
{
int badel = 0;
Element & el = VolumeElement(i);
if (el.GetType() != TET)
{
VolumeElement(i).flags.badel = 0;
continue;
}
if (el.Volume(Points()) < 0)
{
badel = 1;
negativetets++;
}
if (!LegalTet (el))
{
badel = 1;
illegaltets++;
(*testout) << "illegal tet: " << i << " ";
for (j = 1; j <= el.GetNP(); j++)
(*testout) << el.PNum(j) << " ";
(*testout) << endl;
}
// angles between faces
for (lpi1 = 1; lpi1 <= 3; lpi1++)
for (lpi2 = lpi1+1; lpi2 <= 4; lpi2++)
{
lpi3 = 1;
while (lpi3 == lpi1 || lpi3 == lpi2)
lpi3++;
lpi4 = 10 - lpi1 - lpi2 - lpi3;
const Point3d & p1 = Point (el.PNum(lpi1));
const Point3d & p2 = Point (el.PNum(lpi2));
const Point3d & p3 = Point (el.PNum(lpi3));
const Point3d & p4 = Point (el.PNum(lpi4));
Vec3d n(p1, p2);
n /= n.Length();
Vec3d v1(p1, p3);
Vec3d v2(p1, p4);
v1 -= (n * v1) * n;
v2 -= (n * v2) * n;
double cosphi = (v1 * v2) / (v1.Length() * v2.Length());
double phi = acos (cosphi);
if (phi > phimax) phimax = phi;
if (phi < phimin) phimin = phi;
if ((180/M_PI) * phi > badellimit)
badel = 1;
}
// angles in faces
for (j = 1; j <= 4; j++)
{
Element2d face(TRIG);
el.GetFace (j, face);
for (lpi1 = 1; lpi1 <= 3; lpi1++)
{
lpi2 = lpi1 % 3 + 1;
lpi3 = lpi2 % 3 + 1;
const Point3d & p1 = Point (el.PNum(lpi1));
const Point3d & p2 = Point (el.PNum(lpi2));
const Point3d & p3 = Point (el.PNum(lpi3));
Vec3d v1(p1, p2);
Vec3d v2(p1, p3);
double cosphi = (v1 * v2) / (v1.Length() * v2.Length());
double phi = acos (cosphi);
if (phi > facephimax) facephimax = phi;
if (phi < facephimin) facephimin = phi;
if ((180/M_PI) * phi > badellimit)
badel = 1;
}
}
VolumeElement(i).flags.badel = badel;
if (badel) badtets++;
}
if (!GetNE())
{
phimin = phimax = facephimin = facephimax = 0;
}
if (!retvalues)
{
PrintMessage (1, "");
PrintMessage (1, "between planes: phimin = ", (180/M_PI) * phimin,
" phimax = ", (180/M_PI) *phimax);
PrintMessage (1, "inside planes: phimin = ", (180/M_PI) * facephimin,
" phimax = ", (180/M_PI) * facephimax);
PrintMessage (1, "");
}
else
{
retvalues[0] = (180/M_PI) * facephimin;
retvalues[1] = (180/M_PI) * facephimax;
retvalues[2] = (180/M_PI) * phimin;
retvalues[3] = (180/M_PI) * phimax;
}
PrintMessage (3, "negative tets: ", negativetets);
PrintMessage (3, "illegal tets: ", illegaltets);
PrintMessage (3, "bad tets: ", badtets);
}
int Mesh :: MarkIllegalElements ()
{
if(!boundaryedges)
BuildBoundaryEdges();
atomic<int> cnt = 0;
ParallelForRange( Range(volelements), [&] (auto myrange)
{
int cnt_local = 0;
for(auto & el : volelements.Range(myrange))
if (!LegalTet (el))
cnt_local++;
cnt += cnt_local;
});
return cnt;
}
// #ifdef NONE
// void Mesh :: AddIdentification (int pi1, int pi2, int identnr)
// {
// INDEX_2 pair(pi1, pi2);
// // pair.Sort();
// identifiedpoints->Set (pair, identnr);
// if (identnr > maxidentnr)
// maxidentnr = identnr;
// timestamp = NextTimeStamp();
// }
// int Mesh :: GetIdentification (int pi1, int pi2) const
// {
// INDEX_2 pair(pi1, pi2);
// if (identifiedpoints->Used (pair))
// return identifiedpoints->Get(pair);
// else
// return 0;
// }
// int Mesh :: GetIdentificationSym (int pi1, int pi2) const
// {
// INDEX_2 pair(pi1, pi2);
// if (identifiedpoints->Used (pair))
// return identifiedpoints->Get(pair);
// pair = INDEX_2 (pi2, pi1);
// if (identifiedpoints->Used (pair))
// return identifiedpoints->Get(pair);
// return 0;
// }
// void Mesh :: GetIdentificationMap (int identnr, NgArray<int> & identmap) const
// {
// int i, j;
// identmap.SetSize (GetNP());
// for (i = 1; i <= identmap.Size(); i++)
// identmap.Elem(i) = 0;
// for (i = 1; i <= identifiedpoints->GetNBags(); i++)
// for (j = 1; j <= identifiedpoints->GetBagSize(i); j++)
// {
// INDEX_2 i2;
// int nr;
// identifiedpoints->GetData (i, j, i2, nr);
// if (nr == identnr)
// {
// identmap.Elem(i2.I1()) = i2.I2();
// }
// }
// }
// void Mesh :: GetIdentificationPairs (int identnr, NgArray<INDEX_2> & identpairs) const
// {
// int i, j;
// identpairs.SetSize(0);
// for (i = 1; i <= identifiedpoints->GetNBags(); i++)
// for (j = 1; j <= identifiedpoints->GetBagSize(i); j++)
// {
// INDEX_2 i2;
// int nr;
// identifiedpoints->GetData (i, j, i2, nr);
// if (identnr == 0 || nr == identnr)
// identpairs.Append (i2);
// }
// }
// #endif
int Mesh::IdentifyPeriodicBoundaries(const string &s1,
const string &s2,
const Transformation<3> &mapping,
double pointTolerance)
{
auto nr = ident->GetMaxNr() + 1;
ident->SetType(nr, Identifications::PERIODIC);
double lami[4];
set<int> identified_points;
if(pointTolerance < 0.)
{
Point3d pmin, pmax;
GetBox(pmin, pmax);
pointTolerance = 1e-8 * (pmax-pmin).Length();
}
for(const auto& se : surfelements)
{
if(GetBCName(se.index-1) != s1)
continue;
for(const auto& pi : se.PNums())
{
if(identified_points.find(pi) != identified_points.end())
continue;
auto pt = (*this)[pi];
auto mapped_pt = mapping(pt);
auto other_nr = GetElementOfPoint(mapped_pt, lami, true);
int index = -1;
if(other_nr != 0)
{
auto other_el = VolumeElement(other_nr);
for(auto i : Range(other_el.PNums().Size()))
if((mapped_pt - (*this)[other_el.PNums()[i]]).Length() < pointTolerance)
{
index = i;
break;
}
if(index == -1)
{
cout << "point coordinates = " << pt << endl;
cout << "mapped coordinates = " << mapped_pt << endl;
throw Exception("Did not find mapped point with nr " + ToString(pi) + ", are you sure your mesh is periodic?");
}
auto other_pi = other_el.PNums()[index];
identified_points.insert(pi);
ident->Add(pi, other_pi, nr);
}
else
{
cout << "point coordinates = " << pt << endl;
cout << "mapped coordinates = " << mapped_pt << endl;
throw Exception("Mapped point with nr " + ToString(pi) + " is outside of mesh, are you sure your mesh is periodic?");
}
}
}
return nr;
}
void Mesh :: InitPointCurve(double red, double green, double blue) const
{
pointcurves_startpoint.Append(pointcurves.Size());
pointcurves_red.Append(red);
pointcurves_green.Append(green);
pointcurves_blue.Append(blue);
}
void Mesh :: AddPointCurvePoint(const Point3d & pt) const
{
pointcurves.Append(pt);
}
int Mesh :: GetNumPointCurves(void) const
{
return pointcurves_startpoint.Size();
}
int Mesh :: GetNumPointsOfPointCurve(int curve) const
{
if(curve == pointcurves_startpoint.Size()-1)
return (pointcurves.Size() - pointcurves_startpoint.Last());
else
return (pointcurves_startpoint[curve+1]-pointcurves_startpoint[curve]);
}
Point3d & Mesh :: GetPointCurvePoint(int curve, int n) const
{
return pointcurves[pointcurves_startpoint[curve]+n];
}
void Mesh :: GetPointCurveColor(int curve, double & red, double & green, double & blue) const
{
red = pointcurves_red[curve];
green = pointcurves_green[curve];
blue = pointcurves_blue[curve];
}
void Mesh :: ComputeNVertices ()
{
numvertices = 0;
for (const Element & el : VolumeElements())
for (PointIndex v : el.Vertices())
if (v > numvertices) numvertices = v;
for (const Element2d & el : SurfaceElements())
for (PointIndex v : el.Vertices())
if (v > numvertices) numvertices = v;
numvertices += 1-PointIndex::BASE;
}
int Mesh :: GetNV () const
{
if (numvertices < 0)
return GetNP();
else
return numvertices;
}
void Mesh :: SetNP (int np)
{
points.SetSize(np);
// ptyps.SetSize(np);
int mlold = mlbetweennodes.Size();
mlbetweennodes.SetSize(np);
if (np > mlold)
for (int i = mlold+PointIndex::BASE;
i < np+PointIndex::BASE; i++)
{
mlbetweennodes[i].I1() = PointIndex::BASE-1;
mlbetweennodes[i].I2() = PointIndex::BASE-1;
}
GetIdentifications().SetMaxPointNr (np + PointIndex::BASE-1);
}
Table<ElementIndex, PointIndex> Mesh :: CreatePoint2ElementTable(std::optional<BitArray> points) const
{
if(points)
{
const auto & free_points = *points;
return ngcore::CreateSortedTable<ElementIndex, PointIndex>( volelements.Range(),
[&](auto & table, ElementIndex ei)
{
const auto & el = (*this)[ei];
if(el.IsDeleted())
return;
for (PointIndex pi : el.PNums())
if(free_points[pi])
table.Add (pi, ei);
}, GetNP());
}
else
return ngcore::CreateSortedTable<ElementIndex, PointIndex>( volelements.Range(),
[&](auto & table, ElementIndex ei)
{
const auto & el = (*this)[ei];
if(el.IsDeleted())
return;
for (PointIndex pi : el.PNums())
table.Add (pi, ei);
}, GetNP());
}
Table<SurfaceElementIndex, PointIndex> Mesh :: CreatePoint2SurfaceElementTable( int faceindex ) const
{
static Timer timer("Mesh::CreatePoint2SurfaceElementTable"); RegionTimer rt(timer);
if(faceindex==0)
{
return ngcore::CreateSortedTable<SurfaceElementIndex, PointIndex>( surfelements.Range(),
[&](auto & table, SurfaceElementIndex ei)
{
for (PointIndex pi : (*this)[ei].PNums())
table.Add (pi, ei);
}, GetNP());
}
Array<SurfaceElementIndex> face_els;
GetSurfaceElementsOfFace(faceindex, face_els);
return ngcore::CreateSortedTable<SurfaceElementIndex, PointIndex>( face_els.Range(),
[&](auto & table, size_t i)
{
for (PointIndex pi : (*this)[face_els[i]].PNums())
table.Add (pi, face_els[i]);
}, GetNP());
}
/*
void Mesh :: BuildConnectedNodes ()
{
if (PureTetMesh())
{
connectedtonode.SetSize(0);
return;
}
int i, j, k;
int np = GetNP();
int ne = GetNE();
TABLE<int> conto(np);
for (i = 1; i <= ne; i++)
{
const Element & el = VolumeElement(i);
if (el.GetType() == PRISM)
{
for (j = 1; j <= 6; j++)
{
int n1 = el.PNum (j);
int n2 = el.PNum ((j+2)%6+1);
// if (n1 != n2)
{
int found = 0;
for (k = 1; k <= conto.EntrySize(n1); k++)
if (conto.Get(n1, k) == n2)
{
found = 1;
break;
}
if (!found)
conto.Add (n1, n2);
}
}
}
else if (el.GetType() == PYRAMID)
{
for (j = 1; j <= 4; j++)
{
int n1, n2;
switch (j)
{
case 1: n1 = 1; n2 = 4; break;
case 2: n1 = 4; n2 = 1; break;
case 3: n1 = 2; n2 = 3; break;
case 4: n1 = 3; n2 = 2; break;
}
int found = 0;
for (k = 1; k <= conto.EntrySize(n1); k++)
if (conto.Get(n1, k) == n2)
{
found = 1;
break;
}
if (!found)
conto.Add (n1, n2);
}
}
}
connectedtonode.SetSize(np);
for (i = 1; i <= np; i++)
connectedtonode.Elem(i) = 0;
for (i = 1; i <= np; i++)
if (connectedtonode.Elem(i) == 0)
{
connectedtonode.Elem(i) = i;
ConnectToNodeRec (i, i, conto);
}
}
void Mesh :: ConnectToNodeRec (int node, int tonode,
const TABLE<int> & conto)
{
int i, n2;
// (*testout) << "connect " << node << " to " << tonode << endl;
for (i = 1; i <= conto.EntrySize(node); i++)
{
n2 = conto.Get(node, i);
if (!connectedtonode.Get(n2))
{
connectedtonode.Elem(n2) = tonode;
ConnectToNodeRec (n2, tonode, conto);
}
}
}
*/
bool Mesh :: PureTrigMesh (int faceindex) const
{
// if (!faceindex) return !mparam.quad;
if (!faceindex)
{
for (int i = 1; i <= GetNSE(); i++)
if (SurfaceElement(i).GetNP() != 3)
return false;
return true;
}
for (int i = 1; i <= GetNSE(); i++)
if (SurfaceElement(i).GetIndex() == faceindex &&
SurfaceElement(i).GetNP() != 3)
return false;
return true;
}
bool Mesh :: PureTetMesh () const
{
for (ElementIndex ei = 0; ei < GetNE(); ei++)
if (VolumeElement(ei).GetNP() != 4)
return 0;
return 1;
}
void Mesh :: UpdateTopology (NgTaskManager tm,
NgTracer tracer)
{
static Timer t("Update Topology"); RegionTimer reg(t);
topology.Update(tm, tracer);
(*tracer)("call update clusters", false);
clusters->Update();
(*tracer)("call update clusters", true);
#ifdef PARALLEL
if (paralleltop)
{
paralleltop->Reset();
paralleltop->UpdateCoarseGrid();
}
#endif
updateSignal.Emit();
}
void Mesh :: BuildCurvedElements (const Refinement * ref, int aorder, bool arational)
{
GetCurvedElements().BuildCurvedElements (ref, aorder, arational);
for (SegmentIndex seg = 0; seg < GetNSeg(); seg++)
(*this)[seg].SetCurved (GetCurvedElements().IsSegmentCurved (seg));
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
(*this)[sei].SetCurved (GetCurvedElements().IsSurfaceElementCurved (sei));
for (ElementIndex ei = 0; ei < GetNE(); ei++)
(*this)[ei].SetCurved (GetCurvedElements().IsElementCurved (ei));
SetNextMajorTimeStamp();
}
void Mesh :: BuildCurvedElements (int aorder)
{
if (!GetGeometry())
throw NgException ("don't have a geometry for mesh curving");
GetCurvedElements().BuildCurvedElements (&GetGeometry()->GetRefinement(), aorder, false);
for (SegmentIndex seg = 0; seg < GetNSeg(); seg++)
(*this)[seg].SetCurved (GetCurvedElements().IsSegmentCurved (seg));
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
(*this)[sei].SetCurved (GetCurvedElements().IsSurfaceElementCurved (sei));
for (ElementIndex ei = 0; ei < GetNE(); ei++)
(*this)[ei].SetCurved (GetCurvedElements().IsElementCurved (ei));
SetNextMajorTimeStamp();
}
void Mesh :: SetMaterial (int domnr, const string & mat)
{
if (domnr > materials.Size())
{
int olds = materials.Size();
materials.SetSize (domnr);
for (int i = olds; i < domnr-1; i++)
materials[i] = new string("default");
}
/*
materials.Elem(domnr) = new char[strlen(mat)+1];
strcpy (materials.Elem(domnr), mat);
*/
materials.Elem(domnr) = new string(mat);
}
string Mesh :: defaultmat = "default";
const string & Mesh :: GetMaterial (int domnr) const
{
if (domnr <= materials.Size())
return *materials.Get(domnr);
static string emptystring("default");
return emptystring;
}
void Mesh ::SetNBCNames ( int nbcn )
{
if ( bcnames.Size() )
for ( int i = 0; i < bcnames.Size(); i++)
if ( bcnames[i] ) delete bcnames[i];
bcnames.SetSize(nbcn);
bcnames = 0;
}
void Mesh ::SetBCName ( int bcnr, const string & abcname )
{
if (bcnr >= bcnames.Size())
{
int oldsize = bcnames.Size();
bcnames.SetSize (bcnr+1); // keeps contents
for (int i = oldsize; i <= bcnr; i++)
bcnames[i] = new string("default");
}
if ( bcnames[bcnr] ) delete bcnames[bcnr];
bcnames[bcnr] = new string ( abcname );
for (auto & fd : facedecoding)
if (fd.BCProperty() <= bcnames.Size())
fd.SetBCName (bcnames[fd.BCProperty()-1]);
}
const string & Mesh ::GetBCName ( int bcnr ) const
{
static string defaultstring = "default";
if ( !bcnames.Size() )
return defaultstring;
if (bcnr < 0 || bcnr >= bcnames.Size())
throw RangeException("Illegal bc number ", bcnr, 0, bcnames.Size());
if ( bcnames[bcnr] )
return *bcnames[bcnr];
else
return defaultstring;
}
void Mesh :: SetNCD2Names( int ncd2n )
{
if (cd2names.Size())
for(int i=0; i<cd2names.Size(); i++)
if(cd2names[i]) delete cd2names[i];
cd2names.SetSize(ncd2n);
cd2names = 0;
}
void Mesh :: SetCD2Name ( int cd2nr, const string & abcname )
{
cd2nr--;
(*testout) << "setCD2Name on edge " << cd2nr << " to " << abcname << endl;
if (cd2nr >= cd2names.Size())
{
int oldsize = cd2names.Size();
cd2names.SetSize(cd2nr+1);
for(int i= oldsize; i<= cd2nr; i++)
cd2names[i] = nullptr;
}
//if (cd2names[cd2nr]) delete cd2names[cd2nr];
if (abcname != "default" && abcname != "")
cd2names[cd2nr] = new string(abcname);
else
cd2names[cd2nr] = nullptr;
}
string Mesh :: cd2_default_name = "default";
string Mesh :: default_bc = "default";
const string & Mesh :: GetCD2Name (int cd2nr) const
{
static string defaultstring = "default";
if (!cd2names.Size())
return defaultstring;
if (cd2nr < 0 || cd2nr >= cd2names.Size())
return defaultstring;
if (cd2names[cd2nr])
return *cd2names[cd2nr];
else
return defaultstring;
}
void Mesh :: SetNCD3Names( int ncd3n )
{
if (cd3names.Size())
for(int i=0; i<cd3names.Size(); i++)
if(cd3names[i]) delete cd3names[i];
cd3names.SetSize(ncd3n);
cd3names = 0;
}
void Mesh :: SetCD3Name ( int cd3nr, const string & abcname )
{
cd3nr--;
(*testout) << "setCD3Name on vertex " << cd3nr << " to " << abcname << endl;
if (cd3nr >= cd3names.Size())
{
int oldsize = cd3names.Size();
cd3names.SetSize(cd3nr+1);
for(int i= oldsize; i<= cd3nr; i++)
cd3names[i] = nullptr;
}
if (abcname != "default")
cd3names[cd3nr] = new string(abcname);
else
cd3names[cd3nr] = nullptr;
}
int Mesh :: AddCD3Name (const string & aname)
{
for (int i = 0; i < cd3names.Size(); i++)
if (*cd3names[i] == aname)
return i;
cd3names.Append (new string(aname));
return cd3names.Size()-1;
}
string Mesh :: cd3_default_name = "default";
const string & Mesh :: GetCD3Name (int cd3nr) const
{
static string defaultstring = "default";
if (!cd3names.Size())
return defaultstring;
if (cd3nr < 0 || cd3nr >= cd3names.Size())
return defaultstring;
if (cd3names[cd3nr])
return *cd3names[cd3nr];
else
return defaultstring;
}
NgArray<string*> & Mesh :: GetRegionNamesCD (int codim)
{
switch (codim)
{
case 0: return materials;
case 1: return bcnames;
case 2: return cd2names;
case 3: return cd3names;
default: throw Exception("don't have regions of co-dimension "+ToString(codim));
}
}
void Mesh :: SetUserData(const char * id, NgArray<int> & data)
{
if(userdata_int.Used(id))
delete userdata_int[id];
NgArray<int> * newdata = new NgArray<int>(data);
userdata_int.Set(id,newdata);
}
bool Mesh :: GetUserData(const char * id, NgArray<int> & data, int shift) const
{
if(userdata_int.Used(id))
{
if(data.Size() < (*userdata_int[id]).Size()+shift)
data.SetSize((*userdata_int[id]).Size()+shift);
for(int i=0; i<(*userdata_int[id]).Size(); i++)
data[i+shift] = (*userdata_int[id])[i];
return true;
}
else
{
data.SetSize(0);
return false;
}
}
void Mesh :: SetUserData(const char * id, NgArray<double> & data)
{
if(userdata_double.Used(id))
delete userdata_double[id];
NgArray<double> * newdata = new NgArray<double>(data);
userdata_double.Set(id,newdata);
}
bool Mesh :: GetUserData(const char * id, NgArray<double> & data, int shift) const
{
if(userdata_double.Used(id))
{
if(data.Size() < (*userdata_double[id]).Size()+shift)
data.SetSize((*userdata_double[id]).Size()+shift);
for(int i=0; i<(*userdata_double[id]).Size(); i++)
data[i+shift] = (*userdata_double[id])[i];
return true;
}
else
{
data.SetSize(0);
return false;
}
}
void Mesh :: PrintMemInfo (ostream & ost) const
{
ost << "Mesh Mem:" << endl;
ost << GetNP() << " Points, of size "
<< sizeof (Point3d) << " + " << sizeof(POINTTYPE) << " = "
<< GetNP() * (sizeof (Point3d) + sizeof(POINTTYPE)) << endl;
ost << GetNSE() << " Surface elements, of size "
<< sizeof (Element2d) << " = "
<< GetNSE() * sizeof(Element2d) << endl;
ost << GetNE() << " Volume elements, of size "
<< sizeof (Element) << " = "
<< GetNE() * sizeof(Element) << endl;
// ost << "surfs on node:";
// surfacesonnode.PrintMemInfo (cout);
ost << "boundaryedges: ";
if (boundaryedges)
boundaryedges->PrintMemInfo (cout);
ost << "surfelementht: ";
if (surfelementht)
surfelementht->PrintMemInfo (cout);
}
shared_ptr<Mesh> Mesh :: Mirror ( netgen::Point<3> p_plane, Vec<3> n_plane )
{
Mesh & m = *this;
auto nm_ = make_shared<Mesh>();
Mesh & nm = *nm_;
nm = m;
Point3d pmin, pmax;
GetBox(pmin, pmax);
auto v = pmax-pmin;
double eps = v.Length()*1e-8;
auto onPlane = [&] (const MeshPoint & p) -> bool
{
auto v = p_plane-p;
auto l = v.Length();
if(l<eps) return true;
auto ret = fabs(v*n_plane)/l;
return fabs(v*n_plane) < eps;
};
/*
auto mirror = [&] (PointIndex pi) -> PointIndex
{
auto & p = m[pi];
auto v = p_plane-p;
auto l = v.Length();
if(l<eps)
return pi;
if(fabs(v*n_plane)/l < eps)
return pi;
auto new_point = p + 2*(v*n_plane)*n_plane;
return nm.AddPoint( new_point, p.GetLayer(), p.Type() );
};
Array<PointIndex, PointIndex> point_map;
point_map.SetSize(GetNP());
point_map = -1;
for(auto pi : Range(points))
point_map[pi] = mirror(pi);
*/
Array<PointIndex, PointIndex> point_map(GetNP());
Array<PointIndex, PointIndex> point_map1(GetNP());
nm.Points().SetSize(0);
for(auto pi : Range(points))
{
auto & p = m[pi];
auto v = p_plane-p;
auto l = v.Length();
if(l < eps || fabs(v*n_plane)/l < eps)
{
auto npi = nm.AddPoint(p, p.GetLayer(), p.Type());
point_map[pi] = npi;
point_map1[pi] = npi;
}
else
{
auto new_point = p + 2*(v*n_plane)*n_plane;
point_map1[pi] = nm.AddPoint(p, p.GetLayer(), p.Type());
point_map[pi] = nm.AddPoint( new_point, p.GetLayer(), p.Type() );
}
}
for(auto & el : nm.VolumeElements())
for(auto i : Range(el.GetNP()))
el[i] = point_map1[el[i]];
for(auto & el : nm.SurfaceElements())
for(auto i : Range(el.GetNP()))
el[i] = point_map1[el[i]];
for(auto & el : nm.LineSegments())
for(auto i : Range(el.GetNP()))
el[i] = point_map1[el[i]];
for(auto & el : VolumeElements())
{
auto nel = el;
for(auto i : Range(el.GetNP()))
nel[i] = point_map[el[i]];
nm.AddVolumeElement(nel);
}
for (auto ei : Range(SurfaceElements()))
{
auto & el = m[ei];
auto nel = el;
for(auto i : Range(el.GetNP()))
nel[i] = point_map[el[i]];
if(!(nel==el))
{
nel.Invert();
nm.AddSurfaceElement(nel);
}
}
for (auto ei : Range(LineSegments()))
{
auto & el = LineSegments()[ei];
auto nel = el;
bool is_same = true;
for(auto i : Range(el.GetNP()))
{
auto pi = el[i];
nel[i] = point_map[pi];
if(point_map[pi]!=pi)
is_same = false;
}
if(!is_same)
nm.AddSegment(nel);
}
nm.ComputeNVertices();
return nm_;
}
}