gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
GeomMeshMatcher.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 //
6 // Contributor(s):
7 // Bastien Gorissen, Koen Hillewaert
8 //
9 
10 #include <cstdarg>
11 #include <algorithm>
12 #include <list>
13 #include <vector>
14 #include "GeomMeshMatcher.h"
15 #include "Pair.h"
16 #include "discreteVertex.h"
17 #include "GmshMessage.h"
18 #include "SOrientedBoundingBox.h"
19 #include "MElement.h"
20 #include "MTriangle.h"
21 #include "MQuadrangle.h"
22 #include "MVertex.h"
23 #include "MLine.h"
24 #include "MPyramid.h"
25 #include "MTrihedron.h"
26 #include "MPrism.h"
27 #include "MPoint.h"
28 #include "MHexahedron.h"
29 #include "MTetrahedron.h"
30 #include "OS.h"
31 #include "Context.h"
32 
33 #include "closestVertex.h"
34 
36 
37 template <class T, class container>
38 void getIntersection(std::vector<T> &res, std::vector<container> &lists)
39 {
40  res.clear();
41  if(lists.empty()) return;
42  container const &first_list = lists[0];
43  bool allsame = true;
44  for(auto item = first_list.begin(); item != first_list.end(); item++) {
45  bool found = true;
46 
47  for(auto list_iter = lists.begin(); list_iter != lists.end(); list_iter++) {
48  if(*(list_iter) != first_list) {
49  allsame = false;
50  if(std::find((*list_iter).begin(), (*list_iter).end(), (*item)) ==
51  (*list_iter).end()) {
52  found = false;
53  }
54  else {
55  found = true;
56  break;
57  }
58  }
59  }
60  if(found || allsame) { res.push_back(*item); }
61  }
62 }
63 
64 template <class T> T findMatching(std::vector<Pair<T, T> > &matching, T &entity)
65 {
66  for(auto pair = matching.begin(); pair != matching.end(); pair++) {
67  if((*pair).left() == entity) return ((*pair).right());
68  }
69  return (0);
70 }
71 
72 // Matching vertices
73 
74 std::vector<Pair<GVertex *, GVertex *> > *
76 {
77  // Vector that will be returned.
78  std::vector<Pair<GVertex *, GVertex *> > *coresp_v =
79  new std::vector<Pair<GVertex *, GVertex *> >;
80  int num_matched_vertices = 0;
81  int num_total_vertices = m2->getNumVertices();
82 
83  std::vector<GVertex *> vertices;
84 
85  for(auto vit = m1->firstVertex(); vit != m1->lastVertex(); vit++) {
86  GVertex *v1 = (GVertex *)*vit;
87 
88  // FIXME: need a *much* better way to fix the tolerance...
89  double tol = CTX::instance()->geom.matchMeshTolerance;
90 
91  discreteVertex *choice = nullptr;
92  double best_score = DBL_MAX;
93 
94  for(auto vit2 = m2->firstVertex(); vit2 != m2->lastVertex(); vit2++) {
95  discreteVertex *v2 = (discreteVertex *)*vit2;
96 
97  // We match the vertices if their coordinates are the same under the
98  // specified tolerance.
99  double score =
100  std::max(fabs(v1->x() - v2->x()),
101  std::max(fabs(v1->y() - v2->y()), fabs(v1->z() - v2->z())));
102  if(score < tol && score < best_score) {
103  choice = v2;
104  best_score = score;
105  }
106  }
107 
108  if(choice && best_score != DBL_MAX) {
109  choice->physicals = v1->physicals;
110  coresp_v->push_back(Pair<GVertex *, GVertex *>(v1, choice));
111  num_matched_vertices++;
112  }
113  }
114 
115  if(num_matched_vertices != num_total_vertices) ok = false;
116  Msg::Info("Matched %i nodes out of %i", num_matched_vertices,
117  num_total_vertices);
118  return (coresp_v);
119 }
120 
121 // Matching edges
122 
123 std::vector<Pair<GEdge *, GEdge *> > *
125  std::vector<Pair<GVertex *, GVertex *> > *coresp_v,
126  bool &ok)
127 {
128  int num_matched_edges = 0;
129  int num_total_edges = m2->getNumEdges();
130 
131  // Vector that will be returned.
132  std::vector<Pair<GEdge *, GEdge *> > *coresp_e =
133  new std::vector<Pair<GEdge *, GEdge *> >;
134 
135  std::vector<GEdge *> closed_curves;
136 
137  for(auto eit = m1->firstEdge(); eit != m1->lastEdge(); eit++) {
138  GEdge *e1 = (GEdge *)*eit;
139 
140  GVertex *v1 = e1->getBeginVertex();
141  GVertex *v2 = e1->getEndVertex();
142 
143  std::vector<GEdge *> common_edges;
144  std::vector<std::vector<GEdge *> > lists;
145 
146  if(v1 == v2) {
147  Msg::Debug("Found a closed curve");
148  closed_curves.push_back(e1);
149 
150  for(auto eit2 = m2->firstEdge(); eit2 != m2->lastEdge(); eit2++) {
151  GEdge *e2 = (GEdge *)*eit2;
152  GVertex *v3 = e2->getBeginVertex();
153  GVertex *v4 = e2->getEndVertex();
154  if(v3 == v4) {
155  Msg::Debug("Found a loop (%i) in the mesh %i %i", e2->tag(),
156  v3->tag(), v3->tag());
157  common_edges.push_back(e2);
158  }
159  }
160  }
161  else {
162  bool ok1 = false;
163  bool ok2 = false;
164  if(findMatching<GVertex *>(*coresp_v, v1) != 0) {
165  ok1 = true;
166  lists.push_back((findMatching<GVertex *>(*coresp_v, v1))->edges());
167  }
168  if(findMatching<GVertex *>(*coresp_v, v2) != 0) {
169  ok2 = true;
170  lists.push_back((findMatching<GVertex *>(*coresp_v, v2))->edges());
171  }
172  if(ok1 && ok2) getIntersection<GEdge *>(common_edges, lists);
173  }
174 
175  GEdge *choice = nullptr;
176  if(common_edges.size() == 0) continue;
177  if(common_edges.size() == 1) { choice = common_edges[0]; }
178  else {
179  // More than one edge between the two points ? No worries, let
180  // us use those bounding boxes !
181  // So, first step is to build an array of points taken on the geo entity
182  // Then, compute the minimal bounding box
183  SOrientedBoundingBox geo_obb = e1->getOBB();
184 
185  double best_score = DBL_MAX;
186  // Next, let's iterate over the mesh entities.
187  for(auto candidate = common_edges.begin();
188  candidate != common_edges.end(); candidate++) {
189  SOrientedBoundingBox mesh_obb = (*candidate)->getOBB();
190 
191  double score = SOrientedBoundingBox::compare(geo_obb, mesh_obb);
192  if(score < best_score) {
193  best_score = score;
194  choice = (*candidate);
195  }
196  }
197  }
198  coresp_e->push_back(Pair<GEdge *, GEdge *>(e1, choice));
199 
200  // copy topological information
201  if(choice) {
202  // choice->setTag(e1->tag());
203  choice->physicals = e1->physicals;
204  }
205 
206  num_matched_edges++;
207  }
208 
209  Msg::Info("Matched %i curves out of %i", num_matched_edges, num_total_edges);
210  if(num_matched_edges != num_total_edges) ok = false;
211  return (coresp_e);
212 }
213 
214 // Matching faces
215 
216 std::vector<Pair<GFace *, GFace *> > *
218  std::vector<Pair<GEdge *, GEdge *> > *coresp_e,
219  bool &ok)
220 {
221  int num_matched_faces = 0;
222  int num_total_faces = m2->getNumFaces();
223 
224  std::vector<Pair<GFace *, GFace *> > *coresp_f =
225  new std::vector<Pair<GFace *, GFace *> >;
226 
227  for(auto fit = m1->firstFace(); fit != m1->lastFace(); fit++) {
228  GFace *f1 = (GFace *)*fit;
229 
230  std::vector<std::vector<GFace *> > lists;
231 
232  std::vector<GEdge *> boundary_edges = f1->edges();
233 
234  for(auto boundary_edge = boundary_edges.begin();
235  boundary_edge != boundary_edges.end(); boundary_edge++) {
236  // if (boundary_edge->getBeginVertex() ==
237  // boundary_edge->getEndVertex() &&
238  if(!(*boundary_edge)->isSeam(f1)) {
239  GEdge *ge = findMatching<GEdge *>(*coresp_e, *boundary_edge);
240  if(!ge)
241  Msg::Error("Could not find curve %i in surface %i during matching",
242  (*boundary_edge)->tag(), f1->tag());
243  else
244  lists.push_back(ge->faces());
245  }
246  }
247  std::vector<GFace *> common_faces;
248  getIntersection<GFace *>(common_faces, lists);
249  GFace *choice = nullptr;
250 
251  if(common_faces.size() == 0) {
252  Msg::Debug("Could not match surface %i", f1->tag());
253  continue;
254  }
255 
256  if(common_faces.size() == 1) { choice = common_faces[0]; }
257  else {
258  // Then, compute the minimal bounding box
259  SOrientedBoundingBox geo_obb = f1->getOBB();
260 
261  double best_score = DBL_MAX;
262  // Next, let's iterate over the mesh entities.
263  for(auto candidate = common_faces.begin();
264  candidate != common_faces.end(); candidate++) {
265  SOrientedBoundingBox mesh_obb = (*candidate)->getOBB();
266  Msg::Info("Comparing score : %g",
267  SOrientedBoundingBox::compare(geo_obb, mesh_obb));
268  double score = SOrientedBoundingBox::compare(geo_obb, mesh_obb);
269 
270  if(score < best_score) {
271  best_score = score;
272  choice = (*candidate);
273  }
274  }
275  }
276 
277  if(choice) {
278  Msg::Debug("Surfaces %i and %i match", f1->tag(), choice->tag());
279  coresp_f->push_back(Pair<GFace *, GFace *>(f1, choice));
280  // copy topological information
281  choice->setTag(f1->tag());
282  f1->physicals = choice->physicals;
283  num_matched_faces++;
284  }
285  }
286 
287  Msg::Info("Matched %i surfaces out of %i", num_matched_faces,
288  num_total_faces);
289 
290  return coresp_f;
291 }
292 
293 // Matching regions
294 
295 std::vector<Pair<GRegion *, GRegion *> > *
297  std::vector<Pair<GFace *, GFace *> > *coresp_f,
298  bool &ok)
299 
300 {
301  int num_matched_regions = 0;
302  int num_total_regions = 0;
303 
304  std::vector<Pair<GRegion *, GRegion *> > *coresp_r =
305  new std::vector<Pair<GRegion *, GRegion *> >;
306 
307  std::vector<GEntity *> m1_entities;
308  m1->getEntities(m1_entities, 3);
309  std::vector<GEntity *> m2_entities;
310  m2->getEntities(m2_entities, 3);
311 
312  if(m1_entities.empty() || m2_entities.empty()) {
313  Msg::Info("No volumes could be matched since one of the models does "
314  "not have any");
315  return coresp_r;
316  }
317 
318  for(auto entity1 = m1_entities.begin(); entity1 != m1_entities.end();
319  entity1++) {
320  // if ((*entity1)->dim() != 3) continue;
321  num_total_regions++;
322 
323  // std::vector<list<GRegion*> > lists;
324  std::vector<GFace *> boundary_faces = ((GFace *)(*entity1))->faces();
325  std::vector<GFace *> coresp_bound_faces;
326  std::vector<GRegion *> common_regions;
327 
328  for(auto boundary_face = boundary_faces.begin();
329  boundary_face != boundary_faces.end(); boundary_face++) {
330  coresp_bound_faces.push_back(
331  findMatching<GFace *>(*coresp_f, *boundary_face));
332  }
333  for(auto entity2 = m2_entities.begin(); entity2 != m2_entities.end();
334  entity2++) {
335  if((*entity2)->dim() != 3) continue;
336  std::vector<std::vector<GFace *> > lists;
337  lists.push_back(coresp_bound_faces);
338  lists.push_back(((GRegion *)*entity2)->faces());
339  std::vector<GFace *> common_faces;
340  getIntersection<GFace *>(common_faces, lists);
341  if(common_faces.size() == coresp_bound_faces.size()) {
342  common_regions.push_back((GRegion *)*entity2);
343  }
344  }
345 
346  if(common_regions.size() == 1) {
347  coresp_r->push_back(
348  Pair<GRegion *, GRegion *>((GRegion *)*entity1, common_regions[0]));
349  common_regions[0]->setTag(((GRegion *)*entity1)->tag());
350  (*entity1)->physicals = common_regions[0]->physicals;
351  num_matched_regions++;
352  }
353  else if(common_regions.size() > 1) {
354  // So, first step is to build an array of points taken on the geo entity
355 
356  /*
357  This is made in a backward fashion compared to the other entities...
358  */
359  std::vector<GEdge *> boundaries = ((GRegion *)*entity1)->edges();
360 
361  // Then, compute the minimal bounding box
362  SOrientedBoundingBox geo_obb = ((GRegion *)*entity1)->getOBB();
363 
364  GRegion *choice = nullptr;
365  double best_score = DBL_MAX;
366  // Next, let's iterate over the mesh entities.
367  for(auto candidate = common_regions.begin();
368  candidate != common_regions.end(); candidate++) {
369  // Again, build an array with the vertices.
370  SOrientedBoundingBox mesh_obb = (*candidate)->getOBB();
371  Msg::Info("Comparing score: %g",
372  SOrientedBoundingBox::compare(geo_obb, mesh_obb));
373  double score = SOrientedBoundingBox::compare(geo_obb, mesh_obb);
374 
375  if(score < best_score) {
376  best_score = score;
377  choice = (*candidate);
378  }
379  }
380  coresp_r->push_back(
381  Pair<GRegion *, GRegion *>((GRegion *)*entity1, choice));
382  if(choice) {
383  choice->setTag(((GRegion *)*entity1)->tag());
384  (*entity1)->physicals = choice->physicals;
385  }
386  num_matched_regions++;
387  }
388  }
389 
390  Msg::Info("Volumes matched: %i / %i", num_matched_regions,
391  num_total_regions);
392  if(num_matched_regions != num_total_regions) ok = false;
393  return coresp_r;
394 }
395 
396 // Public
398 {
401  }
403 }
404 
406 {
408 }
409 
410 static GVertex *getGVertex(MVertex *v1, GModel *gm, const double TOL)
411 {
412  GVertex *best = nullptr;
413  double bestScore = TOL;
414  for(auto it = gm->firstEdge(); it != gm->lastEdge(); ++it) {
415  {
416  GVertex *v2 = (*it)->getBeginVertex();
417  double score = sqrt((v1->x() - v2->x()) * (v1->x() - v2->x()) +
418  (v1->y() - v2->y()) * (v1->y() - v2->y()) +
419  (v1->z() - v2->z()) * (v1->z() - v2->z()));
420  if(score < bestScore) {
421  bestScore = score;
422  best = v2;
423  }
424  }
425  {
426  GVertex *v2 = (*it)->getEndVertex();
427  double score = sqrt((v1->x() - v2->x()) * (v1->x() - v2->x()) +
428  (v1->y() - v2->y()) * (v1->y() - v2->y()) +
429  (v1->z() - v2->z()) * (v1->z() - v2->z()));
430  if(score < bestScore) {
431  bestScore = score;
432  best = v2;
433  }
434  }
435  }
436  return best;
437 }
438 
439 static GPoint getGEdge(MVertex *v1, GModel *gm, const double TOL)
440 {
441  GPoint gpBest;
442  double bestScore = TOL;
443 
444  for(auto it = gm->firstEdge(); it != gm->lastEdge(); ++it) {
445  GEdge *e = *it;
446  double pp;
447  GPoint gp = e->closestPoint(SPoint3(v1->x(), v1->y(), v1->z()), pp);
448  double score = sqrt((v1->x() - gp.x()) * (v1->x() - gp.x()) +
449  (v1->y() - gp.y()) * (v1->y() - gp.y()) +
450  (v1->z() - gp.z()) * (v1->z() - gp.z()));
451  if(score < bestScore) {
452  bestScore = score;
453  gpBest = gp;
454  }
455  }
456 
457  return gpBest;
458 }
459 
460 static GPoint getGFace(MVertex *v1, GModel *gm, const double TOL)
461 {
462  GPoint gpBest;
463  double bestScore = TOL;
464  for(auto it = gm->firstFace(); it != gm->lastFace(); ++it) {
465  GFace *gf = *it;
466  SPoint2 pp;
467  double guess[2] = {0, 0};
468  GPoint gp = gf->closestPoint(SPoint3(v1->x(), v1->y(), v1->z()), guess);
469  double score = sqrt((v1->x() - gp.x()) * (v1->x() - gp.x()) +
470  (v1->y() - gp.y()) * (v1->y() - gp.y()) +
471  (v1->z() - gp.z()) * (v1->z() - gp.z()));
472  if(score < bestScore) {
473  bestScore = score;
474  gpBest = gp;
475  }
476  }
477  return gpBest;
478 }
479 
480 int GeomMeshMatcher::forceTomatch(GModel *geom, GModel *mesh, const double TOL)
481 {
482  // assume that the geometry is the right one
483 
484  std::vector<GEntity *> entities;
485  mesh->getEntities(entities);
486  for(std::size_t i = 0; i < entities.size(); i++) {
487  for(std::size_t j = 0; j < entities[i]->mesh_vertices.size(); j++) {
488  MVertex *v = entities[i]->mesh_vertices[j];
489  GVertex *gv = getGVertex(v, geom, TOL);
490  bool found = 0;
491  if(gv) {
492  found = 1;
493  MVertex *vvv = new MVertex(v->x(), v->y(), v->z(), gv, v->getNum());
494  gv->mesh_vertices.push_back(vvv);
495  gv->points.push_back(new MPoint(vvv, v->getNum()));
496  }
497  else if(v->onWhat()->dim() == 1) {
498  GPoint gp = getGEdge(v, geom, 1.e22);
499  if(gp.g()) {
500  GEntity *gg = (GEntity *)gp.g();
501  found = 1;
502  gg->mesh_vertices.push_back(
503  new MEdgeVertex(gp.x(), gp.y(), gp.z(), gg, gp.u(), v->getNum()));
504  }
505  }
506  if(!found && v->onWhat()->dim() <= 2) {
507  GPoint gp = getGFace(v, geom, TOL);
508  if(gp.g()) {
509  GEntity *gg = (GEntity *)gp.g();
510  found = 1;
511  gg->mesh_vertices.push_back(new MFaceVertex(
512  gp.x(), gp.y(), gp.z(), gg, gp.u(), gp.v(), v->getNum()));
513  }
514  }
515  if(!found)
516  Msg::Error("Node %d classified on entity of dimension %d and tag %d "
517  "not matched", v->getNum(), v->onWhat()->dim(),
518  v->onWhat()->tag());
519  }
520  }
521  for(auto it = mesh->firstEdge(); it != mesh->lastEdge(); ++it) {
522  for(std::size_t i = 0; i < (*it)->lines.size(); i++) {
523  MVertex *v1 =
524  geom->getMeshVertexByTag((*it)->lines[i]->getVertex(0)->getNum());
525  MVertex *v2 =
526  geom->getMeshVertexByTag((*it)->lines[i]->getVertex(1)->getNum());
527  if(v1 && v2) {
528  GEdge *ge = nullptr;
529  if(v1->onWhat()->dim() == 1) ge = (GEdge *)v1->onWhat();
530  if(v2->onWhat()->dim() == 1) ge = (GEdge *)v2->onWhat();
531  if(ge) {
532  double u1, u2;
533  reparamMeshVertexOnEdge(v1, ge, u1);
534  reparamMeshVertexOnEdge(v2, ge, u2);
535  if(u1 < u2)
536  ge->lines.push_back(new MLine(v1, v2));
537  else
538  ge->lines.push_back(new MLine(v2, v1));
539  }
540  else
541  Msg::Error("Could not find curve");
542  }
543  else {
544  if(!v1)
545  Msg::Error("Could not find node %lu",
546  (*it)->lines[i]->getVertex(0)->getNum());
547  if(!v2)
548  Msg::Error("Could not find node %lu",
549  (*it)->lines[i]->getVertex(1)->getNum());
550  }
551  }
552  }
553  for(auto it = mesh->firstFace(); it != mesh->lastFace(); ++it) {
554  for(std::size_t i = 0; i < (*it)->triangles.size(); i++) {
555  MVertex *v1 =
556  geom->getMeshVertexByTag((*it)->triangles[i]->getVertex(0)->getNum());
557  MVertex *v2 =
558  geom->getMeshVertexByTag((*it)->triangles[i]->getVertex(1)->getNum());
559  MVertex *v3 =
560  geom->getMeshVertexByTag((*it)->triangles[i]->getVertex(2)->getNum());
561  if(v1->onWhat()->dim() == 2)
562  ((GFace *)v1->onWhat())->triangles.push_back(new MTriangle(v1, v2, v3));
563  else if(v2->onWhat()->dim() == 2)
564  ((GFace *)v2->onWhat())->triangles.push_back(new MTriangle(v1, v2, v3));
565  else if(v3->onWhat()->dim() == 2)
566  ((GFace *)v3->onWhat())->triangles.push_back(new MTriangle(v1, v2, v3));
567  }
568  for(std::size_t i = 0; i < (*it)->quadrangles.size(); i++) {
569  MVertex *v1 =
570  geom->getMeshVertexByTag((*it)->quadrangles[i]->getVertex(0)->getNum());
571  MVertex *v2 =
572  geom->getMeshVertexByTag((*it)->quadrangles[i]->getVertex(1)->getNum());
573  MVertex *v3 =
574  geom->getMeshVertexByTag((*it)->quadrangles[i]->getVertex(2)->getNum());
575  MVertex *v4 =
576  geom->getMeshVertexByTag((*it)->quadrangles[i]->getVertex(3)->getNum());
577 
578  if(v1->onWhat()->dim() == 2)
579  ((GFace *)v1->onWhat())
580  ->quadrangles.push_back(new MQuadrangle(v1, v2, v3, v4));
581  else if(v2->onWhat()->dim() == 2)
582  ((GFace *)v2->onWhat())
583  ->quadrangles.push_back(new MQuadrangle(v1, v2, v3, v4));
584  else if(v3->onWhat()->dim() == 2)
585  ((GFace *)v3->onWhat())
586  ->quadrangles.push_back(new MQuadrangle(v1, v2, v3, v4));
587  else if(v4->onWhat()->dim() == 2)
588  ((GFace *)v4->onWhat())
589  ->quadrangles.push_back(new MQuadrangle(v1, v2, v3, v4));
590  }
591  }
592  geom->writeMSH("hopla.msh", 2.2, false, false, true);
593  return 0;
594 }
595 
596 template <class GEType>
597 static void copy_periodicity(std::vector<Pair<GEType *, GEType *> > &eCor,
598  std::map<MVertex *, MVertex *> &mesh_to_geom)
599 {
600  typename std::multimap<GEType *, GEType *> eMap; // (eCor.begin(),eCor.end());
601  auto eIter = eCor.begin();
602  for(; eIter != eCor.end(); ++eIter) {
603  eMap.insert(std::make_pair(eIter->second(), eIter->first()));
604  }
605 
606  auto srcIter = eMap.begin();
607 
608  for(; srcIter != eMap.end(); ++srcIter) {
609  GEType *oldTgt = srcIter->first;
610  GEType *oldSrc = dynamic_cast<GEType *>(oldTgt->getMeshMaster());
611 
612  if(oldSrc != nullptr && oldSrc != oldTgt) {
613  GEType *newTgt = srcIter->second;
614  auto tgtIter = eMap.find(oldSrc);
615  if(tgtIter == eMap.end()) {
616  Msg::Error("Could not find matched entity for %d, which has a matched "
617  "periodic counterpart %d", oldSrc->tag(), oldTgt->tag());
618  continue;
619  }
620  GEType *newSrc = tgtIter->second;
621  newTgt->setMeshMaster(newSrc, oldTgt->affineTransform);
622 
623  std::map<MVertex *, MVertex *> &oldV2v = oldTgt->correspondingVertices;
624  std::map<MVertex *, MVertex *> &newV2v = newTgt->correspondingVertices;
625 
626  auto vIter = oldV2v.begin();
627  for(; vIter != oldV2v.end(); ++vIter) {
628  MVertex *oldTgtV = vIter->first;
629  MVertex *oldSrcV = vIter->second;
630 
631  auto newTvIter = mesh_to_geom.find(oldTgtV);
632  auto newSvIter = mesh_to_geom.find(oldSrcV);
633 
634  if(newTvIter == mesh_to_geom.end()) {
635  Msg::Error("Could not find copy of target node %d in entity %d "
636  "of dim %d", oldTgtV->getIndex(), oldTgt->tag(),
637  oldTgt->dim());
638  continue;
639  }
640 
641  if(newSvIter == mesh_to_geom.end()) {
642  Msg::Error("Could not find copy of source node %d in entity %d "
643  "of dim %d", oldSrcV->getIndex(), oldSrc->tag(),
644  oldSrc->dim());
645  continue;
646  }
647  newV2v[newTvIter->second] = newSvIter->second;
648  }
649  }
650  }
651 }
652 
653 template <class GEType>
654 static bool apply_periodicity(std::vector<Pair<GEType *, GEType *> > &eCor)
655 {
656  typename std::multimap<GEType *, GEType *> eMap; // (eCor.begin(),eCor.end());
657  auto eIter = eCor.begin();
658  for(; eIter != eCor.end(); ++eIter) {
659  eMap.insert(std::make_pair(eIter->second(), eIter->first()));
660  }
661 
662  auto srcIter = eMap.begin();
663 
664  int dim = -1;
665 
666  for(; srcIter != eMap.end(); ++srcIter) {
667  GEType *newTgt = srcIter->second;
668  newTgt->updateCorrespondingVertices();
669  newTgt->alignElementsWithMaster();
670  if(dim == -1) dim = newTgt->dim();
671  }
672 
673  if(dim < 2) { // required for multiple periodic directions
674  for(srcIter = eMap.begin(); srcIter != eMap.end(); ++srcIter) {
675  GEType *newTgt = srcIter->second;
676  newTgt->copyMasterCoordinates();
677  newTgt->alignElementsWithMaster();
678  }
679  }
680 
681  return false;
682 }
683 
684 static void copy_vertices(GVertex *to, GVertex *from,
685  std::map<MVertex *, MVertex *> &_mesh_to_geom)
686 {
687  to->deleteMesh();
688  if(from) {
689  for(std::size_t i = 0; i < 1; i++) {
690  MVertex *v_from = from->mesh_vertices[i];
691  MVertex *v_to = new MVertex(v_from->x(), v_from->y(), v_from->z(), to);
692  to->mesh_vertices.push_back(v_to);
693  _mesh_to_geom[v_from] = v_to;
694  }
695  }
696 }
697 static void copy_vertices(GRegion *to, GRegion *from,
698  std::map<MVertex *, MVertex *> &_mesh_to_geom)
699 {
700  to->deleteMesh();
701  if(from) {
702  for(std::size_t i = 0; i < from->mesh_vertices.size(); i++) {
703  MVertex *v_from = from->mesh_vertices[i];
704  MVertex *v_to = new MVertex(v_from->x(), v_from->y(), v_from->z(), to);
705  to->mesh_vertices.push_back(v_to);
706  _mesh_to_geom[v_from] = v_to;
707  }
708  }
709 }
710 static void copy_vertices(GEdge *to, GEdge *from,
711  std::map<MVertex *, MVertex *> &_mesh_to_geom)
712 {
713  to->deleteMesh();
714  if(!from) {
715  Msg::Warning("Curve %d in the mesh do not match any curve in the model",
716  to->tag());
717  return;
718  }
719  if(!to) {
720  Msg::Warning("Curve %d in the geometry do not match any curve in the mesh",
721  from->tag());
722  return;
723  }
724 
725  for(std::size_t i = 0; i < from->mesh_vertices.size(); i++) {
726  MVertex *v_from = from->mesh_vertices[i];
727  double t;
728  GPoint gp =
729  to->closestPoint(SPoint3(v_from->x(), v_from->y(), v_from->z()), t);
730  MEdgeVertex *v_to = new MEdgeVertex(gp.x(), gp.y(), gp.z(), to, gp.u());
731  to->mesh_vertices.push_back(v_to);
732  _mesh_to_geom[v_from] = v_to;
733  }
734 }
735 
736 static void copy_vertices(GFace *to, GFace *from,
737  std::map<MVertex *, MVertex *> &_mesh_to_geom)
738 {
739  for(std::size_t i = 0; i < from->mesh_vertices.size(); i++) {
740  MVertex *v_from = from->mesh_vertices[i];
741  double uv[2];
742  GPoint gp =
743  to->closestPoint(SPoint3(v_from->x(), v_from->y(), v_from->z()), uv);
744  double DDD = (v_from->x() - gp.x()) * (v_from->x() - gp.x()) +
745  (v_from->y() - gp.y()) * (v_from->y() - gp.y()) +
746  (v_from->z() - gp.z()) * (v_from->z() - gp.z());
747 
748  if(sqrt(DDD) > 1.e-1)
749  Msg::Error("Impossible to match node: original (%g,%g,%g), new (%g,%g,%g)",
750  v_from->x(), v_from->y(), v_from->z(), gp.x(), gp.y(), gp.z());
751 
752  else if(sqrt(DDD) > 1.e-3)
753  Msg::Warning("One mesh node (%g,%g,%g) of surface %d is difficult to match: "
754  "closest point (%g,%g,%g)", v_from->x(), v_from->y(), v_from->z(),
755  to->tag(), gp.x(), gp.y(), gp.z());
756 
757  MFaceVertex *v_to = new MFaceVertex(v_from->x(), v_from->y(), v_from->z(),
758  to, gp.u(), gp.v());
759  to->mesh_vertices.push_back(v_to);
760  _mesh_to_geom[v_from] = v_to;
761  }
762 }
763 
764 template <class ELEMENT>
765 static void copy_elements(std::vector<ELEMENT *> &to,
766  std::vector<ELEMENT *> &from,
767  std::map<MVertex *, MVertex *> &_mesh_to_geom)
768 {
769  MElementFactory toto;
770  to.clear();
771  for(std::size_t i = 0; i < from.size(); i++) {
772  ELEMENT *e = from[i];
773  std::vector<MVertex *> nodes;
774  for(std::size_t j = 0; j < e->getNumVertices(); j++) {
775  auto vIter = _mesh_to_geom.find(e->getVertex(j));
776  if(vIter == _mesh_to_geom.end()) {
777  Msg::Error("Could not find match for node %i during element copy",
778  e->getVertex(j)->getNum());
779  }
780  else
781  nodes.push_back(vIter->second);
782  }
783  if(nodes.size() == e->getNumVertices())
784  to.push_back((ELEMENT *)(toto.create(e->getTypeForMSH(), nodes)));
785  }
786 }
787 
788 void copy_vertices(GModel *geom, GModel *mesh,
789  std::map<MVertex *, MVertex *> &_mesh_to_geom,
790  std::vector<Pair<GVertex *, GVertex *> > *coresp_v,
791  std::vector<Pair<GEdge *, GEdge *> > *coresp_e,
792  std::vector<Pair<GFace *, GFace *> > *coresp_f,
793  std::vector<Pair<GRegion *, GRegion *> > *coresp_r)
794 {
795  // copy all elements
796  for(std::size_t i = 0; i < coresp_v->size(); ++i)
797  copy_vertices((*coresp_v)[i].first(), (*coresp_v)[i].second(),
798  _mesh_to_geom);
799  for(std::size_t i = 0; i < coresp_e->size(); ++i)
800  copy_vertices((*coresp_e)[i].first(), (*coresp_e)[i].second(),
801  _mesh_to_geom);
802  for(std::size_t i = 0; i < coresp_f->size(); ++i)
803  copy_vertices((*coresp_f)[i].first(), (*coresp_f)[i].second(),
804  _mesh_to_geom);
805  for(std::size_t i = 0; i < coresp_r->size(); ++i)
806  copy_vertices((*coresp_r)[i].first(), (*coresp_r)[i].second(),
807  _mesh_to_geom);
808 }
809 void copy_elements(GModel *geom, GModel *mesh,
810  std::map<MVertex *, MVertex *> &_mesh_to_geom,
811  std::vector<Pair<GVertex *, GVertex *> > *coresp_v,
812  std::vector<Pair<GEdge *, GEdge *> > *coresp_e,
813  std::vector<Pair<GFace *, GFace *> > *coresp_f,
814  std::vector<Pair<GRegion *, GRegion *> > *coresp_r)
815 {
816  // copy all elements
817 
818  for(std::size_t i = 0; i < coresp_v->size(); ++i) {
819  GVertex *dest = (*coresp_v)[i].first();
820  GVertex *orig = (*coresp_v)[i].second();
821  copy_elements<MPoint>(dest->points, orig->points, _mesh_to_geom);
822  }
823 
824  for(std::size_t i = 0; i < coresp_e->size(); ++i) {
825  GEdge *dest = (*coresp_e)[i].first();
826  GEdge *orig = (*coresp_e)[i].second();
827  copy_elements<MLine>(dest->lines, orig->lines, _mesh_to_geom);
828  }
829 
830  for(std::size_t i = 0; i < coresp_f->size(); ++i) {
831  GFace *dest = (*coresp_f)[i].first();
832  GFace *orig = (*coresp_f)[i].second();
833  copy_elements<MTriangle>(dest->triangles, orig->triangles, _mesh_to_geom);
834  copy_elements<MQuadrangle>(dest->quadrangles, orig->quadrangles,
835  _mesh_to_geom);
836  }
837 
838  for(std::size_t i = 0; i < coresp_r->size(); ++i) {
839  GRegion *dest = (*coresp_r)[i].first();
840  GRegion *orig = (*coresp_r)[i].second();
841  copy_elements<MTetrahedron>(dest->tetrahedra, orig->tetrahedra,
842  _mesh_to_geom);
843  copy_elements<MHexahedron>(dest->hexahedra, orig->hexahedra, _mesh_to_geom);
844  copy_elements<MPrism>(dest->prisms, orig->prisms, _mesh_to_geom);
845  copy_elements<MPyramid>(dest->pyramids, orig->pyramids, _mesh_to_geom);
846  copy_elements<MTrihedron>(dest->trihedra, orig->trihedra, _mesh_to_geom);
847  }
848 }
849 
851 {
852  Msg::StatusBar(true, "Matching discrete mesh to CAD model...");
853  double t1 = Cpu(), w1 = TimeOfDay();
854 
855  GModel::setCurrent(geom);
856  geom->setPhysicalNames(mesh->getPhysicalNames());
857 
858  bool ok = true;
859 
860  std::vector<Pair<GVertex *, GVertex *> > *coresp_v(nullptr);
861  std::vector<Pair<GEdge *, GEdge *> > *coresp_e(nullptr);
862  std::vector<Pair<GFace *, GFace *> > *coresp_f(nullptr);
863  std::vector<Pair<GRegion *, GRegion *> > *coresp_r(nullptr);
864 
865  coresp_v = matchVertices(geom, mesh, ok);
866  if(ok) {
867  coresp_e = matchEdges(geom, mesh, coresp_v, ok);
868  if(ok) {
869  coresp_f = matchFaces(geom, mesh, coresp_e, ok);
870  if(ok) { coresp_r = matchRegions(geom, mesh, coresp_f, ok); }
871  else
872  Msg::Error("Could only match %i surfaces out of %i: stopping match",
873  coresp_f->size(), mesh->getNumFaces());
874  }
875  else
876  Msg::Error("Could only match %i curves out of %i: stopping match",
877  coresp_e->size(), mesh->getNumEdges());
878  }
879  else
880  Msg::Error("Could only match %i points out of %i: check mesh/CAD or "
881  "increase Geom.MatchMeshTolerance (currently %g)",
882  coresp_v->size(), mesh->getNumVertices(),
884 
885  std::map<MVertex *, MVertex *> _mesh_to_geom;
886 
887  if(ok) {
888  Msg::Info("Copying mesh nodes and elements to CAD model entities...");
889  copy_vertices(geom, mesh, _mesh_to_geom, coresp_v, coresp_e, coresp_f,
890  coresp_r);
891  copy_elements(geom, mesh, _mesh_to_geom, coresp_v, coresp_e, coresp_f,
892  coresp_r);
893  Msg::Info("Applying periodicity to CAD model entities...");
894  if(!apply_periodicity(*coresp_v))
895  copy_periodicity(*coresp_v, _mesh_to_geom);
896  if(!apply_periodicity(*coresp_e))
897  copy_periodicity(*coresp_e, _mesh_to_geom);
898  if(!apply_periodicity(*coresp_f))
899  copy_periodicity(*coresp_f, _mesh_to_geom);
900  }
901 
902  if(coresp_v) delete coresp_v;
903  if(coresp_e) delete coresp_e;
904  if(coresp_f) delete coresp_f;
905  if(coresp_r) delete coresp_r;
906 
907  if(ok)
908  Msg::StatusBar(true, "Successfully matched mesh to CAD (Wall %gs, CPU %gs)",
909  TimeOfDay() - w1, Cpu() - t1);
910  else
911  Msg::Error("Failed to match mesh to CAD");
912 
913  return ok ? 1 : 0;
914 }
MTriangle.h
TimeOfDay
double TimeOfDay()
Definition: OS.cpp:399
MTrihedron.h
GFace::getOBB
virtual SOrientedBoundingBox getOBB()
Definition: GFace.cpp:292
GModel::firstEdge
eiter firstEdge()
Definition: GModel.h:356
GFace::edges
virtual std::vector< GEdge * > const & edges() const
Definition: GFace.h:121
GeomMeshMatcher.h
GVertex::z
virtual double z() const =0
getGEdge
static GPoint getGEdge(MVertex *v1, GModel *gm, const double TOL)
Definition: GeomMeshMatcher.cpp:439
GPoint::y
double y() const
Definition: GPoint.h:22
getIntersection
void getIntersection(std::vector< T > &res, std::vector< container > &lists)
Definition: GeomMeshMatcher.cpp:38
GFace
Definition: GFace.h:33
GFace::triangles
std::vector< MTriangle * > triangles
Definition: GFace.h:428
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
getGVertex
static GVertex * getGVertex(MVertex *v1, GModel *gm, const double TOL)
Definition: GeomMeshMatcher.cpp:410
GEdge::lines
std::vector< MLine * > lines
Definition: GEdge.h:42
SPoint2
Definition: SPoint2.h:12
MElementFactory
Definition: MElement.h:517
OS.h
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
GRegion::deleteMesh
virtual void deleteMesh()
Definition: GRegion.cpp:39
MVertex
Definition: MVertex.h:24
GeomMeshMatcher::instance
static GeomMeshMatcher * instance()
Definition: GeomMeshMatcher.cpp:397
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
Msg::StatusBar
static void StatusBar(bool log, const char *fmt,...)
Definition: GmshMessage.cpp:686
MVertex::z
double z() const
Definition: MVertex.h:62
GEntity::physicals
std::vector< int > physicals
Definition: GEntity.h:65
SPoint3
Definition: SPoint3.h:14
GeomMeshMatcher::matchRegions
std::vector< Pair< GRegion *, GRegion * > > * matchRegions(GModel *m1, GModel *m2, std::vector< Pair< GFace *, GFace * > > *coresp_f, bool &ok)
Definition: GeomMeshMatcher.cpp:296
MVertex::getNum
std::size_t getNum() const
Definition: MVertex.h:86
GeomMeshMatcher::GeomMeshMatcher
GeomMeshMatcher()
Definition: GeomMeshMatcher.h:35
SOrientedBoundingBox.h
SOrientedBoundingBox
Definition: SOrientedBoundingBox.h:33
discreteVertex::x
virtual double x() const
Definition: discreteVertex.cpp:45
GModel::getMeshVertexByTag
MVertex * getMeshVertexByTag(int n)
Definition: GModel.cpp:1953
apply_periodicity
static bool apply_periodicity(std::vector< Pair< GEType *, GEType * > > &eCor)
Definition: GeomMeshMatcher.cpp:654
GEntity::setTag
void setTag(int tag)
Definition: GEntity.h:281
MVertex::onWhat
GEntity * onWhat() const
Definition: MVertex.h:82
MPoint.h
GModel::firstVertex
viter firstVertex()
Definition: GModel.h:357
GmshMessage.h
MLine.h
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
w1
const double w1
Definition: GaussQuadratureHex.cpp:18
GEntity
Definition: GEntity.h:31
discreteVertex::y
virtual double y() const
Definition: discreteVertex.cpp:53
GPoint
Definition: GPoint.h:13
GFace::closestPoint
virtual GPoint closestPoint(const SPoint3 &queryPoint, const double initialGuess[2]) const
Definition: GFace.cpp:1323
Pair.h
reparamMeshVertexOnEdge
bool reparamMeshVertexOnEdge(MVertex *v, const GEdge *ge, double &param)
Definition: MVertex.cpp:592
GeomMeshMatcher::forceTomatch
int forceTomatch(GModel *geom, GModel *mesh, const double TOL)
Definition: GeomMeshMatcher.cpp:480
GFace::quadrangles
std::vector< MQuadrangle * > quadrangles
Definition: GFace.h:429
discreteVertex.h
MLine
Definition: MLine.h:21
GVertex::points
std::vector< MPoint * > points
Definition: GVertex.h:120
GPoint::z
double z() const
Definition: GPoint.h:23
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
GRegion::hexahedra
std::vector< MHexahedron * > hexahedra
Definition: GRegion.h:164
GModel::lastFace
fiter lastFace()
Definition: GModel.h:359
discreteVertex
Definition: discreteVertex.h:15
GVertex::deleteMesh
virtual void deleteMesh()
Definition: GVertex.cpp:20
GPoint::u
double u() const
Definition: GPoint.h:27
GEdge::getOBB
virtual SOrientedBoundingBox getOBB()
Definition: GEdge.cpp:234
GEntity::mesh_vertices
std::vector< MVertex * > mesh_vertices
Definition: GEntity.h:56
GModel::getPhysicalNames
const std::map< std::pair< int, int >, std::string > & getPhysicalNames() const
Definition: GModel.h:437
GeomMeshMatcher::_gmm_instance
static GeomMeshMatcher * _gmm_instance
Definition: GeomMeshMatcher.h:34
MHexahedron.h
MEdgeVertex
Definition: MVertex.h:137
GModel::lastVertex
viter lastVertex()
Definition: GModel.h:361
GVertex
Definition: GVertex.h:23
GeomMeshMatcher
Definition: GeomMeshMatcher.h:21
MVertex.h
GModel::getNumVertices
std::size_t getNumVertices() const
Definition: GModel.h:347
GModel
Definition: GModel.h:44
copy_vertices
static void copy_vertices(GVertex *to, GVertex *from, std::map< MVertex *, MVertex * > &_mesh_to_geom)
Definition: GeomMeshMatcher.cpp:684
Cpu
double Cpu()
Definition: OS.cpp:366
GEdge::getBeginVertex
virtual GVertex * getBeginVertex() const
Definition: GEdge.h:63
MPyramid.h
GModel::firstFace
fiter firstFace()
Definition: GModel.h:355
copy_elements
static void copy_elements(std::vector< ELEMENT * > &to, std::vector< ELEMENT * > &from, std::map< MVertex *, MVertex * > &_mesh_to_geom)
Definition: GeomMeshMatcher.cpp:765
GRegion::trihedra
std::vector< MTrihedron * > trihedra
Definition: GRegion.h:167
getGFace
static GPoint getGFace(MVertex *v1, GModel *gm, const double TOL)
Definition: GeomMeshMatcher.cpp:460
GEntity::tag
int tag() const
Definition: GEntity.h:280
MFaceVertex
Definition: MVertex.h:168
GModel::getNumFaces
std::size_t getNumFaces() const
Definition: GModel.h:345
GModel::setPhysicalNames
void setPhysicalNames(const std::map< std::pair< int, int >, std::string > &names)
Definition: GModel.h:441
GPoint::g
const GEntity * g() const
Definition: GPoint.h:29
GModel::getEntities
void getEntities(std::vector< GEntity * > &entities, int dim=-1) const
Definition: GModel.cpp:651
CTX::geom
contextGeometryOptions geom
Definition: Context.h:311
GRegion
Definition: GRegion.h:28
GModel::getNumEdges
std::size_t getNumEdges() const
Definition: GModel.h:346
GRegion::prisms
std::vector< MPrism * > prisms
Definition: GRegion.h:165
discreteVertex::z
virtual double z() const
Definition: discreteVertex.cpp:61
GEdge::faces
virtual std::vector< GFace * > faces() const
Definition: GEdge.h:113
MTriangle
Definition: MTriangle.h:26
GVertex::x
virtual double x() const =0
GRegion::pyramids
std::vector< MPyramid * > pyramids
Definition: GRegion.h:166
MElementFactory::create
MElement * create(int type, std::vector< MVertex * > &v, std::size_t num=0, int part=0, bool owner=false, int parent=0, MElement *parent_ptr=nullptr, MElement *d1=nullptr, MElement *d2=nullptr)
Definition: MElement.cpp:2556
GModel::writeMSH
int writeMSH(const std::string &name, double version=2.2, bool binary=false, bool saveAll=false, bool saveParametric=false, double scalingFactor=1.0, int elementStartNum=0, int saveSinglePartition=0, bool append=false)
Definition: GModelIO_MSH.cpp:76
GVertex::y
virtual double y() const =0
GModel::setCurrent
static int setCurrent(GModel *m)
Definition: GModel.cpp:147
GEdge::closestPoint
virtual GPoint closestPoint(const SPoint3 &queryPoint, double &param) const
Definition: GEdge.cpp:552
MVertex::getIndex
long int getIndex() const
Definition: MVertex.h:93
Context.h
MTetrahedron.h
SOrientedBoundingBox::compare
static double compare(SOrientedBoundingBox &obb1, SOrientedBoundingBox &obb2)
Definition: SOrientedBoundingBox.cpp:553
MQuadrangle.h
GeomMeshMatcher::matchFaces
std::vector< Pair< GFace *, GFace * > > * matchFaces(GModel *m1, GModel *m2, std::vector< Pair< GEdge *, GEdge * > > *coresp_e, bool &ok)
Definition: GeomMeshMatcher.cpp:217
findMatching
T findMatching(std::vector< Pair< T, T > > &matching, T &entity)
Definition: GeomMeshMatcher.cpp:64
GeomMeshMatcher::destroy
static void destroy()
Definition: GeomMeshMatcher.cpp:405
MElement.h
Pair
Definition: Pair.h:10
copy_periodicity
static void copy_periodicity(std::vector< Pair< GEType *, GEType * > > &eCor, std::map< MVertex *, MVertex * > &mesh_to_geom)
Definition: GeomMeshMatcher.cpp:597
GEdge::deleteMesh
virtual void deleteMesh()
Definition: GEdge.cpp:53
MPoint
Definition: MPoint.h:16
GEdge
Definition: GEdge.h:26
MPrism.h
GPoint::v
double v() const
Definition: GPoint.h:28
GModel::lastEdge
eiter lastEdge()
Definition: GModel.h:360
GeomMeshMatcher::matchVertices
std::vector< Pair< GVertex *, GVertex * > > * matchVertices(GModel *m1, GModel *m2, bool &ok)
Definition: GeomMeshMatcher.cpp:75
MVertex::y
double y() const
Definition: MVertex.h:61
GEdge::getEndVertex
virtual GVertex * getEndVertex() const
Definition: GEdge.h:64
closestVertex.h
GEntity::dim
virtual int dim() const
Definition: GEntity.h:196
contextGeometryOptions::matchMeshTolerance
double matchMeshTolerance
Definition: Context.h:110
GeomMeshMatcher::match
int match(GModel *geom, GModel *mesh)
Definition: GeomMeshMatcher.cpp:850
GPoint::x
double x() const
Definition: GPoint.h:21
MQuadrangle
Definition: MQuadrangle.h:26
GeomMeshMatcher::matchEdges
std::vector< Pair< GEdge *, GEdge * > > * matchEdges(GModel *m1, GModel *m2, std::vector< Pair< GVertex *, GVertex * > > *coresp_v, bool &ok)
Definition: GeomMeshMatcher.cpp:124
GRegion::tetrahedra
std::vector< MTetrahedron * > tetrahedra
Definition: GRegion.h:163
MVertex::x
double x() const
Definition: MVertex.h:60
faces
static int faces[4][3]
Definition: meshGRegionDelaunayInsertion.cpp:165