8#ifndef model_SimplicialMesh_cpp_
9#define model_SimplicialMesh_cpp_
41 void SimplicialMesh<dim>::createMesh(
const std::set<int>& periodicFaceIDs)
45 const auto t0= std::chrono::system_clock::now();
48 for (
const auto& eIter : this->simplexReader().
elements())
50 insertSimplex(eIter.second.first,eIter.second.second);
52 std::cout<<
greenBoldColor<<
"\r"<<
"Creating mesh "<<eleConter*100/this->simplexReader().elements().size()<<
"%"<<
magentaColor<<
" ["<<(std::chrono::duration<double>(std::chrono::system_clock::now()-
t0)).
count()<<
" sec]"<<std::flush;
58 if(simplices().size())
60 _xMin=this->
template simplexFactory<0>().liveSimplices().begin()->second->P0;
61 _xMax=this->
template simplexFactory<0>().liveSimplices().begin()->second->P0;
63 for (
const auto& nIter : this->
template simplexFactory<0>().liveSimplices())
65 for(
int d=0;d<
dim;++d)
67 if (nIter.second->P0(d)<_xMin(d))
69 _xMin(d)=nIter.second->P0(d);
71 if (nIter.second->P0(d)>_xMax(d))
73 _xMax(d)=nIter.second->P0(d);
77 _xC=0.5*(_xMax+_xMin);
81 std::cout<<
"Mesh is empty."<<std::endl;
83 std::cout<<
" xMin="<< std::setprecision(15)<<std::scientific<<_xMin.transpose()<<std::endl;
84 std::cout<<
" xMax="<< std::setprecision(15)<<std::scientific<<_xMax.transpose()<<std::endl;
85 std::cout<<
" xCenter="<< std::setprecision(15)<<std::scientific<<_xC.transpose()<<std::endl;
90 size_t bndSimplexCount=0;
91 size_t rgnBndSimplexCount=0;
95 if(simpl.second->isBoundarySimplex())
100 if(simpl.second->isRegionBoundarySimplex())
102 const auto regionIDset=simpl.second->regionIDs();
103 std::pair<size_t,size_t> regionIDs(std::make_pair(*regionIDset.begin(),*regionIDset.rbegin()));
107 regionBndIter->second.simplices().insert(simpl.second.get());
111 regionBoundaries().try_emplace(regionIDs,regionIDs,*_polyhedralMesh).first->second.simplices().insert(simpl.second.get());
113 rgnBndSimplexCount++;
119 _polyhedralMesh->buildTopology();
123 size_t bndFaceSimplexSum=0;
127 std::cout<<
" simplices: "<<
region.second->simplices().size()<<
" Simplex<"<<
dim<<
","<<
dim<<
">"<<std::endl;
128 for(
auto& face :
region.second->faces())
130 std::cout<<
" face "<<face.second->sID<<
": size="<<face.second->size()<<
",hullPts="<<face.second->convexHull().size()<<
", outNormal "<<face.second->outNormal().transpose()<<std::endl;
131 bndFaceSimplexSum+=face.second->size();
135 size_t rgnBndFaceSimplexSum=0;
138 std::cout<<
magentaColor<<
"MeshRegionBoundary ("<<rgnBnd.second.regionBndID.first<<
","<<rgnBnd.second.regionBndID.second<<
")"<<
defaultColor<<std::endl;
139 std::cout<<
" simplices: "<<rgnBnd.second.simplices().size()<<
" Simplex<"<<
dim<<
","<<
dim-1<<
">"<<std::endl;
140 for(
auto& face : rgnBnd.second.faces())
142 std::cout<<
" face "<<face.second->sID<<
": hullPts="<<face.second->convexHull().size()<<
", outNormal "<<face.second->outNormal().transpose()<<std::endl;
143 rgnBndFaceSimplexSum+=face.second->size();
144 bndFaceSimplexSum-=2*face.second->size();
148 if(bndFaceSimplexSum!=bndSimplexCount)
150 std::cout<<
"boundary simplices="<<bndSimplexCount<<std::endl;
151 std::cout<<
"simplices in external faces="<<bndFaceSimplexSum<<std::endl;
152 throw std::runtime_error(
"WRONG NUMBER OF BOUNDAY FACE SIMPLICES");
155 if(rgnBndFaceSimplexSum!=rgnBndSimplexCount)
157 std::cout<<
"region-boundary simplices="<<rgnBndSimplexCount<<std::endl;
158 std::cout<<
"simplices in internal faces="<<rgnBndFaceSimplexSum<<std::endl;
159 throw std::runtime_error(
"WRONG NUMBER OF REGION-BOUNDARY FACE SIMPLICES");
165 _xMin(
Eigen::Matrix<double,
dim,1>::Zero())
166 ,_xMax(
Eigen::Matrix<double,
dim,1>::Zero())
167 ,_xC(
Eigen::Matrix<double,
dim,1>::Zero())
174 _xMin(
Eigen::Matrix<double,
dim,1>::Zero())
175 ,_xMax(
Eigen::Matrix<double,
dim,1>::Zero())
176 ,_xC(
Eigen::Matrix<double,
dim,1>::Zero())
179 this->
read(meshFileName,
A,x0);
180 createMesh(periodicFaceIDs);
185 void SimplicialMesh<dim>::readMesh(
const std::string& meshFileName,
const Eigen::Matrix<double,dim,dim>&
A,
const Eigen::Matrix<double,dim,1>& x0,
const std::set<int>& periodicFaceIDs)
188 _periodicSimplexPairs.clear();
190 _simplexFactories.clear();
191 _polyhedralMesh = std::make_shared<PolyhedralMesh<dim>>();
192 this->
read(meshFileName,
A,x0);
193 createMesh(periodicFaceIDs);
214 throw std::runtime_error(
"Polyhedral topology has not been built");
216 return *_polyhedralMesh;
233 rgnBnd.second.update();
236 for(
const auto& face : rgnBnd.second.faces())
238 region1->
faces().emplace(face.second->sID,face.second);
239 region2->
faces().emplace(face.second->sID,face.second);
249 std::set<int> available;
252 for(
const auto& face :
region.second->faces())
254 if(face.second->isExternal())
256 faces.push_back(face.second.get());
257 available.insert(face.second->sID);
261 for(
const auto id : periodicFaceIDs)
263 if(
id != -1 && !available.count(
id))
265 throw std::runtime_error(
"Unknown external periodic face ID " + std::to_string(
id));
268 const double tolerance = 1.e-8*(
xMax()-
xMin()).norm()
269 + 64.0*std::numeric_limits<double>::epsilon()*std::max(
xMin().norm(),
xMax().norm());
271 if(!periodicFaceIDs.empty())
276 const auto& selected = lattice.pairs;
278 for(
const auto& entry : selected)
283 (shift-entry.second.first).norm()>tolerance)
285 throw std::runtime_error(
"Active periodic face has inconsistent simplex correspondence.");
287 simplexPairs.insert(matches.begin(),matches.end());
289 for(
const auto& entry : simplexPairs)
291 const auto reverse=simplexPairs.find(entry.second.partner);
292 if(reverse==simplexPairs.end() || reverse->second.partner!=entry.first ||
293 (entry.second.shift+reverse->second.shift).norm()>tolerance)
295 throw std::runtime_error(
"Nonreciprocal periodic simplex correspondence.");
299 if(reverse->second.vertexPermutation[entry.second.vertexPermutation[
i]]!=
i)
301 throw std::runtime_error(
"Nonreciprocal periodic vertex permutation.");
306 _periodicBasis = lattice.basis;
307 _periodicSimplexPairs.swap(simplexPairs);
308 for(
auto* face : faces)
310 const auto found = selected.find(face);
311 face->periodicFacePair = found == selected.end()
313 : std::make_pair(found->second.first,
static_cast<const Polyhedron<
dim,
dim-1
>*>(found->second.second));
320 return _periodicBasis;
332 throw std::runtime_error(
"Duplicate volume simplex");
363 std::set<const Simplex<dim,dim>*> searchSet;
376 const Eigen::Matrix<double,dim,1>& P)
const
398 std::set<const Simplex<dim,dim>*> searchSet;
404 const Eigen::Matrix<double,dim,1>& P,
416 std::pair<bool,const Simplex<dim,dim>*> lastSearched(
false,NULL);
417 guess->convexDelaunaynSearch(searchAllRegions,P,lastSearched,searchSet);
418 checkSearch(searchAllRegions,P,guess,lastSearched);
420 if(!lastSearched.first)
422 const std::pair<bool,const Simplex<dim,dim>*>
temp(lastSearched);
423 const Eigen::Matrix<double,dim+1,1> bary=
temp.second->pos2bary(P);
425 for(
int k=0;
k<
dim+1 && !lastSearched.first;++
k)
427 if(bary(
k)<=FLT_EPSILON)
441 for(
const auto& pIter :
temp.second->child(
k).parents())
443 if(pIter.second->region->regionID==
temp.second->region->regionID || searchAllRegions)
445 pIter.second->convexDelaunaynSearch(searchAllRegions,P,lastSearched,searchSet);
446 if (lastSearched.first)
457 if(!lastSearched.first && !lastSearched.second->isBoundarySimplex())
464 if(!lastSearched.first && !lastSearched.second->isBoundarySimplex() && !lastSearched.second->isRegionBoundarySimplex())
471 checkSearch(searchAllRegions,P,guess,lastSearched);
473 if(searchAllRegions && !lastSearched.first)
479 for(
const auto& regionEntry : this->
regions())
481 std::set<const Simplex<dim,dim>*> regionSearchSet;
483 *regionEntry.second->simplices().begin(),regionSearchSet);
484 searchSet.insert(regionSearchSet.begin(),regionSearchSet.end());
496 const Eigen::Matrix<double,dim,1>& P,
502 if(!(lastSearched.first || lastSearched.second->isBoundarySimplex()))
504 std::cout<<
"P="<<std::setprecision(15)<<std::scientific<<P.transpose()<<std::endl;
505 std::cout<<
"guess="<<guess->
xID<<std::endl;
506 std::cout<<
"lastSearched="<<lastSearched.second->xID<<std::endl;
507 assert(0 &&
"SEARCH DID NOT END ON BOUNDARY SIMPLEX");
512 if(!(lastSearched.first || lastSearched.second->isBoundarySimplex() || lastSearched.second->isRegionBoundarySimplex()))
514 std::cout<<
"P="<<std::setprecision(15)<<std::scientific<<P.transpose()<<std::endl;
515 std::cout<<
"guess="<<guess->
xID<<std::endl;
516 std::cout<<
"lastSearched="<<lastSearched.second->xID<<std::endl;
517 assert(0 &&
"SEARCH DID NOT END ON BOUNDARY/REGION-BOUNDARY SIMPLEX");
525 const double& tol)
const
530 const Eigen::Matrix<double,dim+1,1> bary(
temp.second->pos2bary(P));
532 const double baryMin(bary.minCoeff(&kMin));
547 const Eigen::Matrix<double,dim+1,1> bary(
temp.second->pos2bary(P));
549 const double baryMin(bary.minCoeff(&kMin));
bool isBoundarySimplex() const
Eigen::Matrix< double, dim, Eigen::Dynamic > PeriodicBasisType
const Eigen::Matrix< double, _dim, 1 > & xMax() const
std::pair< bool, const Simplex< _dim, _dim > * > searchRegion(const int ®ionID, const Eigen::Matrix< double, dim, 1 > &P) const
void identifyParallelFaces(const std::set< int > &)
std::pair< bool, const Simplex< _dim, _dim > * > isOnMeshBoundary(const Eigen::Matrix< double, dim, 1 > &P, const Simplex< dim, dim > *const guess, const double &tol) const
MeshRegionBoundary< dim > MeshRegionBoundaryType
std::pair< bool, const Simplex< _dim, _dim > * > searchWithGuess(const Eigen::Matrix< double, dim, 1 > &P, const Simplex< dim, dim > *const guess) const
Polyhedron< dim, dim > MeshRegionType
const PolyhedralMesh< _dim > & polyhedralMesh() const
const Eigen::Matrix< double, _dim, 1 > & xMin() const
const SimplexMapType & simplices() const
std::map< typename SimplexTraits< dim, dim >::SimplexIDType, std::shared_ptr< Simplex< dim, dim > > > SimplexMapType
const MeshRegionBoundaryType & regionBoundary(const int &i, const int &j) const
std::pair< bool, const Simplex< _dim, _dim > * > isStrictlyInsideMesh(const Eigen::Matrix< double, dim, 1 > &P, const Simplex< dim, dim > *const guess, const double &tol) const
Eigen::Matrix< double, dim, Eigen::Dynamic > periodicBasis() const
const MeshRegionBoundaryContainerType & regionBoundaries() const
const Eigen::Matrix< double, _dim, 1 > & xCenter() const
Polyhedron< _dim, _dim > * region(const size_t &id)
std::pair< bool, const Simplex< _dim, _dim > * > searchRegionWithGuess(const Eigen::Matrix< double, dim, 1 > &P, const Simplex< dim, dim > *const guess) const
void readMesh(const std::string &meshFileName, const Eigen::Matrix< double, dim, dim > &A, const Eigen::Matrix< double, dim, 1 > &x0, const std::set< int > &)
std::pair< bool, const Simplex< _dim, _dim > * > search(const Eigen::Matrix< double, dim, 1 > &P) const
void updateRegionBoundaries()
void insertSimplex(const typename SimplexTraits< dim, dim >::SimplexIDType &xIN, const int ®ionID)
void checkSearch(const bool &searchAllRegions, const Eigen::Matrix< double, dim, 1 > &P, const Simplex< dim, dim > *const guess, const std::pair< bool, const Simplex< dim, dim > * > &lastSearched) const
std::map< MeshRegionIDType, MeshRegionBoundaryType > MeshRegionBoundaryContainerType
const double & volume() const
function infiniteDisplacement syms Ax Ay Az Bx By Bz qx qy qz u L x y z real A
size_t InstanceCount< Derived >::count
static std::string magentaColor
PeriodicMeshLattice< dim > discoverPeriodicMeshLattice(const std::vector< Polyhedron< dim, dim-1 > * > &faces, double tolerance)
std::map< const Simplex< dim, dim-1 > *, PeriodicSimplexPair< dim > > PeriodicSimplexPairMap
PeriodicMeshLattice< dim > selectPeriodicMeshLattice(const PeriodicMeshLattice< dim > &full, const std::set< int > &seeds, double tolerance)
static std::string greenBoldColor
static std::string defaultColor
bool isPeriodicFacePair(const Polyhedron< dim, dim-1 > &a, const Polyhedron< dim, dim-1 > &b, Eigen::Matrix< double, dim, 1 > &shift, double tolerance, PeriodicSimplexPairMap< dim > *correspondence=nullptr)
Eigen::Matrix< double, 3, 1 > VectorDim
const MeshFacesContainerType & faces() const
ChildSimplexType & child(const int &n)
SimplexReaderBase< dim > & simplexReader()
void read(const int &meshID)
static SimplexIDType sortID(const SimplexIDType &vIN)
SimplexID< nVertices > SimplexIDType
std::string read(const fs::path &path)