gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
meshPartition.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 // Contributed by Anthony Royer.
7 
8 #include <vector>
9 #include <set>
10 #include <sstream>
11 #include <algorithm>
12 #include <ctime>
13 #include <limits>
14 #include <stack>
15 #include <cstdlib>
16 #include <map>
17 #include <unordered_map>
18 #include "GmshConfig.h"
19 #include "GmshMessage.h"
20 #include "GModel.h"
21 #include "ElementType.h"
22 
24  bool operator()(const std::pair<int, GEntity *> &p1,
25  const std::pair<int, GEntity *> &p2) const
26  {
27  if(p1.first != p2.first) return p1.first < p2.first;
28  if(p1.second->dim() != p2.second->dim())
29  return p1.second->dim() < p2.second->dim();
30  return p1.second->tag() < p2.second->tag();
31  }
32 };
33 
34 typedef std::set<std::pair<int, GEntity *>, OriGEntityPtrFullLessThan>
36 
37 #define hashmap std::unordered_map
38 #define hashmapentity \
39  std::unordered_map<GEntity *, setorientity, GEntityPtrFullHash, \
40  GEntityPtrFullEqual>
41 #define hashmapelement \
42  std::unordered_map<MElement *, GEntity *, MElementPtrHash, MElementPtrEqual>
43 #define hashmapelementpart \
44  std::unordered_map<MElement *, int, MElementPtrHash, MElementPtrEqual>
45 #define hashmapface \
46  std::unordered_map<MFace, \
47  std::vector<std::pair<MElement *, std::vector<int> > >, \
48  MFaceHash, MFaceEqual>
49 #define hashmapedge \
50  std::unordered_map<MEdge, \
51  std::vector<std::pair<MElement *, std::vector<int> > >, \
52  MEdgeHash, MEdgeEqual>
53 #define hashmapvertex \
54  std::unordered_map<MVertex *, \
55  std::vector<std::pair<MElement *, std::vector<int> > >, \
56  MVertexPtrHash, MVertexPtrEqual>
57 
58 #if defined(HAVE_METIS)
59 
60 #include "OS.h"
61 #include "Context.h"
62 #include "partitionRegion.h"
63 #include "partitionFace.h"
64 #include "partitionEdge.h"
65 #include "partitionVertex.h"
66 #include "ghostRegion.h"
67 #include "ghostFace.h"
68 #include "ghostEdge.h"
69 #include "MFaceHash.h"
70 #include "MEdgeHash.h"
71 #include "MTriangle.h"
72 #include "MQuadrangle.h"
73 #include "MTetrahedron.h"
74 #include "MHexahedron.h"
75 #include "MPrism.h"
76 #include "MPyramid.h"
77 #include "MTrihedron.h"
78 #include "MElementCut.h"
79 #include "MPoint.h"
80 
81 extern "C" {
82 #include <metis.h>
83 }
84 
85 // Graph of the mesh for partitioning purposes.
86 class Graph {
87 private:
88  // The GModel
89  GModel *_model;
90  // The number of partitions
91  std::size_t _nparts;
92  // The number of elements
93  std::size_t _ne;
94  // The number of nodes
95  std::size_t _nn;
96  // The dimension of the mesh
97  int _dim;
98  // The list of nodes belonging to the ith element of the mesh are stored in
99  // consecutive locations of eind starting at position eptr[i] up to (but not
100  // including) position eptr[i+1]. The size of the eind array is of size equal
101  // to the sum of the number of nodes in all the elements of the mesh.
102  std::vector<idx_t> _eind;
103  // The size of the eptr array is n + 1, where n is the number of elements in
104  // the mesh.
105  std::vector<idx_t> _eptr;
106  // The metis graph structure
107  idx_t *_xadj, *_adjncy;
108  // The weight associated to each elements of eptr
109  idx_t *_vwgt;
110  // Element corresponding to each graph element in eptr
111  std::vector<MElement *> _element;
112  // Vertex corresponding to each graph vertex in eptr
113  std::vector<idx_t> _vertex;
114  // The partitions output from the partitioner, in an integer type independent
115  // from METIS
116  std::vector<int> _partition;
117 
118 public:
119  Graph(GModel *model)
120  : _model(model), _nparts(0), _ne(0), _nn(0), _dim(0), _xadj(nullptr),
121  _adjncy(nullptr), _vwgt(nullptr)
122  {
123  }
124  ~Graph() { clear(); }
125  std::size_t nparts() const { return _nparts; };
126  std::size_t ne() const { return _ne; };
127  std::size_t nn() const { return _nn; };
128  int dim() const { return _dim; };
129  std::size_t eind(std::size_t i) const { return _eind[i]; };
130  std::size_t eptr(std::size_t i) const { return _eptr[i]; };
131  idx_t xadj(std::size_t i) const { return _xadj[i]; };
132  idx_t *xadj() const { return _xadj; };
133  idx_t adjncy(std::size_t i) const { return _adjncy[i]; };
134  idx_t *adjncy() const { return _adjncy; };
135  idx_t *vwgt() const { return _vwgt; };
136  MElement *element(std::size_t i) const { return _element[i]; };
137  idx_t vertex(std::size_t i) const { return _vertex[i]; };
138  int partition(std::size_t i) const { return _partition[i]; };
139  std::size_t numNodes() const { return _ne; };
140  std::size_t numEdges() const { return _xadj[_ne] / 2; };
141  void nparts(std::size_t nparts) { _nparts = nparts; };
142  void ne(std::size_t ne) { _ne = ne; };
143  void nn(std::size_t nn) { _nn = nn; };
144  void dim(int dim) { _dim = dim; };
145  void eindResize(std::size_t size)
146  {
147  _eind.clear();
148  _eind.resize(size, 0);
149  }
150  void eind(std::size_t i, idx_t eind) { _eind[i] = eind; };
151  void eptrResize(std::size_t size)
152  {
153  _eptr.clear();
154  _eptr.resize(size, 0);
155  }
156  void eptr(std::size_t i, idx_t eptr) { _eptr[i] = eptr; };
157  void elementResize(std::size_t size)
158  {
159  _element.clear();
160  _element.resize(size, nullptr);
161  }
162  void element(std::size_t i, MElement *element) { _element[i] = element; };
163  void vertexResize(std::size_t size)
164  {
165  _vertex.clear();
166  _vertex.resize(size, -1);
167  }
168  void adjncy(std::size_t i, idx_t adjncy) { _adjncy[i] = adjncy; };
169  void vertex(std::size_t i, idx_t vertex) { _vertex[i] = vertex; };
170  void partition(const std::vector<idx_t> &epart)
171  {
172  // converts into METIS-independent integer type
173  _partition.resize(epart.size());
174  for(std::size_t i = 0; i < epart.size(); i++) _partition[i] = epart[i];
175  };
176  void clear()
177  {
178  if(_xadj) {
179  delete[] _xadj;
180  _xadj = nullptr;
181  }
182  if(_adjncy) {
183  delete[] _adjncy;
184  _adjncy = nullptr;
185  }
186  if(_vwgt) {
187  delete[] _vwgt;
188  _vwgt = nullptr;
189  }
190  }
191  void clearDualGraph()
192  {
193  if(_xadj) {
194  delete[] _xadj;
195  _xadj = nullptr;
196  }
197  if(_adjncy) {
198  delete[] _adjncy;
199  _adjncy = nullptr;
200  }
201  }
202  void eraseVertex()
203  {
204  for(std::size_t i = 0; i < _vertex.size(); i++) _vertex[i] = -1;
205  }
206  std::vector<std::set<MElement *, MElementPtrLessThan> >
207  getBoundaryElements(idx_t size = 0)
208  {
209  std::vector<std::set<MElement *, MElementPtrLessThan> > elements(
210  (size ? size : _nparts), std::set<MElement *, MElementPtrLessThan>());
211  for(std::size_t i = 0; i < _ne; i++) {
212  for(idx_t j = _xadj[i]; j < _xadj[i + 1]; j++) {
213  if(_partition[i] != _partition[_adjncy[j]]) {
214  if(_element[i]->getDim() == _dim) {
215  elements[_partition[i]].insert(_element[i]);
216  }
217  }
218  }
219  }
220 
221  return elements;
222  }
223  std::vector<GEntity *> createGhostEntities()
224  {
225  std::vector<GEntity *> ghostEntities(_nparts, (GEntity *)nullptr);
226  int elementaryNumber = _model->getMaxElementaryNumber(_dim);
227  for(std::size_t i = 1; i <= _nparts; i++) {
228  switch(_dim) {
229  case 1:
230  ghostEntities[i - 1] = new ghostEdge(_model, ++elementaryNumber, i);
231  _model->add(static_cast<ghostEdge *>(ghostEntities[i - 1]));
232  break;
233  case 2:
234  ghostEntities[i - 1] = new ghostFace(_model, ++elementaryNumber, i);
235  _model->add(static_cast<ghostFace *>(ghostEntities[i - 1]));
236  break;
237  case 3:
238  ghostEntities[i - 1] = new ghostRegion(_model, ++elementaryNumber, i);
239  _model->add(static_cast<ghostRegion *>(ghostEntities[i - 1]));
240  break;
241  default: break;
242  }
243  }
244  return ghostEntities;
245  }
246  void assignGhostCells()
247  {
248  std::vector<GEntity *> ghostEntities = createGhostEntities();
249  for(std::size_t i = 0; i < _ne; i++) {
250  std::set<int> ghostCellsPartition;
251  for(idx_t j = _xadj[i]; j < _xadj[i + 1]; j++) {
252  if(_partition[i] != _partition[_adjncy[j]] &&
253  ghostCellsPartition.find(_partition[_adjncy[j]]) ==
254  ghostCellsPartition.end()) {
255  if(_element[i]->getDim() == _dim) {
256  switch(_dim) {
257  case 1:
258  static_cast<ghostEdge *>(ghostEntities[_partition[_adjncy[j]]])
259  ->addElement(_element[i]->getType(), _element[i],
260  _partition[i] + 1);
261  break;
262  case 2:
263  static_cast<ghostFace *>(ghostEntities[_partition[_adjncy[j]]])
264  ->addElement(_element[i]->getType(), _element[i],
265  _partition[i] + 1);
266  break;
267  case 3:
268  static_cast<ghostRegion *>(ghostEntities[_partition[_adjncy[j]]])
269  ->addElement(_element[i]->getType(), _element[i],
270  _partition[i] + 1);
271  break;
272  default: break;
273  }
274  ghostCellsPartition.insert(_partition[_adjncy[j]]);
275  }
276  }
277  }
278  }
279  }
280  void createDualGraph(bool connectedAll)
281  {
282  std::vector<idx_t> nptr(_nn + 1, 0);
283  std::vector<idx_t> nind(_eptr[_ne], 0);
284 
285  for(std::size_t i = 0; i < _ne; i++) {
286  for(idx_t j = _eptr[i]; j < _eptr[i + 1]; j++) { nptr[_eind[j]]++; }
287  }
288 
289  for(std::size_t i = 1; i < _nn; i++) nptr[i] += nptr[i - 1];
290  for(std::size_t i = _nn; i > 0; i--) nptr[i] = nptr[i - 1];
291  nptr[0] = 0;
292 
293  for(std::size_t i = 0; i < _ne; i++) {
294  for(idx_t j = _eptr[i]; j < _eptr[i + 1]; j++) {
295  nind[nptr[_eind[j]]++] = i;
296  }
297  }
298 
299  for(std::size_t i = _nn; i > 0; i--) nptr[i] = nptr[i - 1];
300  nptr[0] = 0;
301 
302  _xadj = new idx_t[_ne + 1];
303  for(std::size_t i = 0; i < _ne + 1; i++) _xadj[i] = 0;
304 
305  std::vector<idx_t> nbrs(_ne, 0);
306  std::vector<idx_t> marker(_ne, 0);
307  for(std::size_t i = 0; i < _ne; i++) {
308  std::size_t l = 0;
309  for(idx_t j = _eptr[i]; j < _eptr[i + 1]; j++) {
310  for(idx_t k = nptr[_eind[j]]; k < nptr[_eind[j] + 1]; k++) {
311  if(nind[k] != (idx_t)i) {
312  if(marker[nind[k]] == 0) nbrs[l++] = nind[k];
313  marker[nind[k]]++;
314  }
315  }
316  }
317 
318  std::size_t nbrsNeighbors = 0;
319  for(std::size_t j = 0; j < l; j++) {
320  if(marker[nbrs[j]] >=
321  (connectedAll ?
322  1 :
323  _element[i]->numCommonNodesInDualGraph(_element[nbrs[j]])))
324  nbrsNeighbors++;
325  marker[nbrs[j]] = 0;
326  nbrs[j] = 0;
327  }
328 
329  _xadj[i] = nbrsNeighbors;
330  }
331 
332  for(std::size_t i = 1; i < _ne; i++) _xadj[i] = _xadj[i] + _xadj[i - 1];
333  for(std::size_t i = _ne; i > 0; i--) _xadj[i] = _xadj[i - 1];
334  _xadj[0] = 0;
335 
336  _adjncy = new idx_t[_xadj[_ne]];
337  for(idx_t i = 0; i < _xadj[_ne]; i++) _adjncy[i] = 0;
338 
339  for(std::size_t i = 0; i < _ne; i++) {
340  std::size_t l = 0;
341  for(idx_t j = _eptr[i]; j < _eptr[i + 1]; j++) {
342  for(idx_t k = nptr[_eind[j]]; k < nptr[_eind[j] + 1]; k++) {
343  if(nind[k] != (idx_t)i) {
344  if(marker[nind[k]] == 0) nbrs[l++] = nind[k];
345  marker[nind[k]]++;
346  }
347  }
348  }
349 
350  for(std::size_t j = 0; j < l; j++) {
351  if(marker[nbrs[j]] >=
352  (connectedAll ?
353  1 :
354  _element[i]->numCommonNodesInDualGraph(_element[nbrs[j]]))) {
355  _adjncy[_xadj[i]] = nbrs[j];
356  _xadj[i] = _xadj[i] + 1;
357  }
358  marker[nbrs[j]] = 0;
359  nbrs[j] = 0;
360  }
361  }
362  for(std::size_t i = _ne; i > 0; i--) _xadj[i] = _xadj[i - 1];
363  _xadj[0] = 0;
364  }
365  void fillDefaultWeights()
366  {
367  if(CTX::instance()->mesh.partitionLinWeight == 1 &&
374  return;
375 
376  _vwgt = new idx_t[_ne];
377  if(CTX::instance()->mesh.partitionLinWeight == -1 ||
384  for(std::size_t i = 0; i < _ne; i++) {
385  if(!_element[i]) { _vwgt[i] = 1; }
386  else {
387  _vwgt[i] = (_element[i]->getDim() == _dim ? 1 : 0);
388  }
389  }
390  }
391  else {
392  for(std::size_t i = 0; i < _ne; i++) {
393  if(!_element[i]) { _vwgt[i] = 1; }
394  else {
395  switch(_element[i]->getType()) {
396  case TYPE_LIN:
397  _vwgt[i] = CTX::instance()->mesh.partitionLinWeight;
398  break;
399  case TYPE_TRI:
400  _vwgt[i] = CTX::instance()->mesh.partitionTriWeight;
401  break;
402  case TYPE_QUA:
403  _vwgt[i] = CTX::instance()->mesh.partitionQuaWeight;
404  break;
405  case TYPE_TET:
406  _vwgt[i] = CTX::instance()->mesh.partitionTetWeight;
407  break;
408  case TYPE_PYR:
409  _vwgt[i] = CTX::instance()->mesh.partitionPyrWeight;
410  break;
411  case TYPE_PRI:
412  _vwgt[i] = CTX::instance()->mesh.partitionPriWeight;
413  break;
414  case TYPE_HEX:
415  _vwgt[i] = CTX::instance()->mesh.partitionHexWeight;
416  break;
417  default: _vwgt[i] = 1; break;
418  }
419  }
420  }
421  }
422  }
423 };
424 
425 template <class ITERATOR>
426 static void fillElementsToNodesMap(Graph &graph, GEntity *entity,
427  idx_t &eptrIndex, idx_t &eindIndex,
428  idx_t &numVertex, ITERATOR it_beg,
429  ITERATOR it_end)
430 {
431  for(ITERATOR it = it_beg; it != it_end; ++it) {
432  const std::size_t numVertices = (*it)->getNumPrimaryVertices();
433  graph.element(eptrIndex++, *it);
434  graph.eptr(eptrIndex, graph.eptr(eptrIndex - 1) + numVertices);
435  for(std::size_t i = 0; i < numVertices; i++) {
436  if(graph.vertex((*it)->getVertex(i)->getNum() - 1) == -1) {
437  graph.vertex((*it)->getVertex(i)->getNum() - 1, numVertex++);
438  }
439  graph.eind(eindIndex, graph.vertex((*it)->getVertex(i)->getNum() - 1));
440  eindIndex++;
441  }
442  }
443 }
444 
445 static std::size_t getSizeOfEind(GModel *model)
446 {
447  std::size_t size = 0;
448  // Loop over volumes
449  for(auto it = model->firstRegion(); it != model->lastRegion(); ++it) {
450  size += 4 * (*it)->tetrahedra.size();
451  size += 8 * (*it)->hexahedra.size();
452  size += 6 * (*it)->prisms.size();
453  size += 5 * (*it)->pyramids.size();
454  size += 4 * (*it)->trihedra.size();
455  }
456 
457  // Loop over surfaces
458  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
459  size += 3 * (*it)->triangles.size();
460  size += 4 * (*it)->quadrangles.size();
461  }
462 
463  // Loop over curves
464  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
465  size += 2 * (*it)->lines.size();
466  }
467 
468  // Loop over points
469  for(auto it = model->firstVertex(); it != model->lastVertex(); ++it) {
470  size += 1 * (*it)->points.size();
471  }
472 
473  return size;
474 }
475 
476 // Creates a mesh data structure used by Metis routines. Returns: 0 = success, 1
477 // = no elements found, 2 = error.
478 static int makeGraph(GModel *model, Graph &graph, int selectDim)
479 {
480  std::size_t eindSize = 0;
481  if(selectDim < 0) {
482  graph.ne(model->getNumMeshElements());
483  graph.nn(model->getNumMeshVertices());
484  graph.dim(model->getMeshDim());
485  graph.elementResize(graph.ne());
486  graph.vertexResize(model->getMaxVertexNumber());
487  graph.eptrResize(graph.ne() + 1);
488  graph.eptr(0, 0);
489  eindSize = getSizeOfEind(model);
490  graph.eindResize(eindSize);
491  }
492  else {
493  GModel *tmp = new GModel();
494  std::vector<GEntity *> entities;
495  model->getEntities(entities);
496 
497  std::set<MVertex *> vertices;
498  for(std::size_t i = 0; i < entities.size(); i++) {
499  if(entities[i]->dim() == selectDim) {
500  switch(entities[i]->dim()) {
501  case 3: tmp->add(static_cast<GRegion *>(entities[i])); break;
502  case 2: tmp->add(static_cast<GFace *>(entities[i])); break;
503  case 1: tmp->add(static_cast<GEdge *>(entities[i])); break;
504  case 0: tmp->add(static_cast<GVertex *>(entities[i])); break;
505  default: break;
506  }
507  for(std::size_t j = 0; j < entities[i]->getNumMeshElements(); j++) {
508  for(std::size_t k = 0;
509  k < entities[i]->getMeshElement(j)->getNumVertices(); k++) {
510  vertices.insert(entities[i]->getMeshElement(j)->getVertex(k));
511  }
512  }
513  }
514  }
515 
516  graph.ne(tmp->getNumMeshElements());
517  graph.nn(vertices.size());
518  graph.dim(tmp->getMeshDim());
519  graph.elementResize(graph.ne());
520  graph.vertexResize(model->getMaxVertexNumber());
521  graph.eptrResize(graph.ne() + 1);
522  graph.eptr(0, 0);
523  eindSize = getSizeOfEind(tmp);
524  graph.eindResize(eindSize);
525 
526  tmp->remove();
527  delete tmp;
528  }
529 
530  idx_t eptrIndex = 0;
531  idx_t eindIndex = 0;
532  idx_t numVertex = 0;
533 
534  if(graph.ne() == 0) {
535  Msg::Error("No mesh elements were found");
536  return 1;
537  }
538  if(graph.dim() == 0) {
539  Msg::Error("Cannot partition a point");
540  return 1;
541  }
542 
543  // Loop over volumes
544  if(selectDim < 0 || selectDim == 3) {
545  for(auto it = model->firstRegion(); it != model->lastRegion(); ++it) {
546  GRegion *r = *it;
547  fillElementsToNodesMap(graph, r, eptrIndex, eindIndex, numVertex,
548  r->tetrahedra.begin(), r->tetrahedra.end());
549  fillElementsToNodesMap(graph, r, eptrIndex, eindIndex, numVertex,
550  r->hexahedra.begin(), r->hexahedra.end());
551  fillElementsToNodesMap(graph, r, eptrIndex, eindIndex, numVertex,
552  r->prisms.begin(), r->prisms.end());
553  fillElementsToNodesMap(graph, r, eptrIndex, eindIndex, numVertex,
554  r->pyramids.begin(), r->pyramids.end());
555  fillElementsToNodesMap(graph, r, eptrIndex, eindIndex, numVertex,
556  r->trihedra.begin(), r->trihedra.end());
557  }
558  }
559 
560  // Loop over surfaces
561  if(selectDim < 0 || selectDim == 2) {
562  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
563  GFace *f = *it;
564  fillElementsToNodesMap(graph, f, eptrIndex, eindIndex, numVertex,
565  f->triangles.begin(), f->triangles.end());
566  fillElementsToNodesMap(graph, f, eptrIndex, eindIndex, numVertex,
567  f->quadrangles.begin(), f->quadrangles.end());
568  }
569  }
570 
571  // Loop over curves
572  if(selectDim < 0 || selectDim == 1) {
573  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
574  GEdge *e = *it;
575  fillElementsToNodesMap(graph, e, eptrIndex, eindIndex, numVertex,
576  e->lines.begin(), e->lines.end());
577  }
578  }
579 
580  // Loop over points
581  if(selectDim < 0 || selectDim == 0) {
582  for(auto it = model->firstVertex(); it != model->lastVertex(); ++it) {
583  GVertex *v = *it;
584  fillElementsToNodesMap(graph, v, eptrIndex, eindIndex, numVertex,
585  v->points.begin(), v->points.end());
586  }
587  }
588 
589  return 0;
590 }
591 
592 // Partition a graph created by makeGraph using Metis library. Returns: 0 =
593 // success, 1 = error, 2 = exception thrown.
594 static int partitionGraph(Graph &graph, bool verbose)
595 {
596 #ifdef HAVE_METIS
597  std::stringstream opt;
598  try {
599  idx_t metisOptions[METIS_NOPTIONS];
600  METIS_SetDefaultOptions(metisOptions);
601 
602  opt << "npart:" << graph.nparts();
603 
604  opt << ", sizeof(idx_t):" << 8 * sizeof(idx_t);
605 
606  opt << ", ptype:";
607  switch(CTX::instance()->mesh.metisAlgorithm) {
608  case 1: // Recursive
609  metisOptions[METIS_OPTION_PTYPE] = METIS_PTYPE_RB;
610  opt << "rb";
611  break;
612  case 2: // K-way
613  metisOptions[METIS_OPTION_PTYPE] = METIS_PTYPE_KWAY;
614  opt << "kway";
615  break;
616  default: opt << "default"; break;
617  }
618 
619  opt << ", ufactor:";
621  metisOptions[METIS_OPTION_UFACTOR] =
624  }
625  else {
626  opt << "default";
627  }
628 
629  opt << ", ctype:";
630  switch(CTX::instance()->mesh.metisEdgeMatching) {
631  case 1: // Random matching
632  metisOptions[METIS_OPTION_CTYPE] = METIS_CTYPE_RM;
633  opt << "rm";
634  break;
635  case 2: // Sorted heavy-edge matching
636  metisOptions[METIS_OPTION_CTYPE] = METIS_CTYPE_SHEM;
637  opt << "shem";
638  break;
639  default: opt << "default"; break;
640  }
641 
642  opt << ", rtype:";
643  switch(CTX::instance()->mesh.metisRefinementAlgorithm) {
644  case 1: // FM-based cut refinement
645  metisOptions[METIS_OPTION_RTYPE] = METIS_RTYPE_FM;
646  opt << "fm";
647  break;
648  case 2: // Greedy boundary refinement
649  metisOptions[METIS_OPTION_RTYPE] = METIS_RTYPE_GREEDY;
650  opt << "greedy";
651  break;
652  case 3: // Two-sided node FM refinement
653  metisOptions[METIS_OPTION_RTYPE] = METIS_RTYPE_SEP2SIDED;
654  opt << "sep2sided";
655  break;
656  case 4: // One-sided node FM refinement
657  metisOptions[METIS_OPTION_RTYPE] = METIS_RTYPE_SEP1SIDED;
658  opt << "sep1sided";
659  break;
660  default: opt << "default"; break;
661  }
662 
663  opt << ", objtype:";
664  switch(CTX::instance()->mesh.metisObjective) {
665  case 1: // Min. cut
666  metisOptions[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
667  opt << "cut";
668  break;
669  case 2: // Min. communication volume (slower)
670  metisOptions[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
671  opt << "vol";
672  break;
673  default: opt << "default"; break;
674  }
675 
676  opt << ", minconn:";
677  switch(CTX::instance()->mesh.metisMinConn) {
678  case 0:
679  metisOptions[METIS_OPTION_MINCONN] = 0;
680  opt << 0;
681  break;
682  case 1:
683  metisOptions[METIS_OPTION_MINCONN] = 1;
684  opt << 1;
685  break;
686  default: opt << "default"; break;
687  }
688 
689  if(verbose) Msg::Info("Running METIS with %s", opt.str().c_str());
690 
691  // C numbering
692  metisOptions[METIS_OPTION_NUMBERING] = 0;
693 
694  idx_t objval;
695  std::vector<idx_t> epart(graph.ne());
696  idx_t ne = graph.ne();
697  idx_t numPart = graph.nparts();
698  idx_t ncon = 1;
699  graph.fillDefaultWeights();
700 
701  int metisError = 0;
702  graph.createDualGraph(false);
703 
704  if(metisOptions[METIS_OPTION_PTYPE] == METIS_PTYPE_KWAY) {
705  metisError = METIS_PartGraphKway(
706  &ne, &ncon, graph.xadj(), graph.adjncy(), graph.vwgt(), nullptr,
707  nullptr, &numPart, nullptr, nullptr, metisOptions, &objval, &epart[0]);
708  }
709  else {
710  metisError = METIS_PartGraphRecursive(
711  &ne, &ncon, graph.xadj(), graph.adjncy(), graph.vwgt(), nullptr,
712  nullptr, &numPart, nullptr, nullptr, metisOptions, &objval, &epart[0]);
713  }
714 
715  switch(metisError) {
716  case METIS_OK: break;
717  case METIS_ERROR_INPUT: Msg::Error("METIS input error"); return 1;
718  case METIS_ERROR_MEMORY: Msg::Error("METIS memory error"); return 1;
719  case METIS_ERROR:
720  default: Msg::Error("METIS error"); return 1;
721  }
722 
723  // Check and correct the topology
724  for(int i = 1; i < 4; i++) {
725  for(std::size_t j = 0; j < graph.ne(); j++) {
726  if(graph.element(j)->getDim() == graph.dim()) continue;
727 
728  for(idx_t k = graph.xadj(j); k < graph.xadj(j + 1); k++) {
729  if(graph.element(j)->getDim() ==
730  graph.element(graph.adjncy(k))->getDim() - i) {
731  if(epart[j] != epart[graph.adjncy(k)]) {
732  epart[j] = epart[graph.adjncy(k)];
733  break;
734  }
735  }
736  }
737  }
738  }
739  graph.partition(epart);
740  if(verbose) Msg::Info("%d partitions, %d total edge-cuts", numPart, objval);
741  } catch(...) {
742  Msg::Error("METIS exception");
743  return 2;
744  }
745 #endif
746 
747  return 0;
748 }
749 
750 template <class ENTITY, class ITERATOR>
751 static void
752 assignElementsToEntities(GModel *model, hashmapelementpart &elmToPartition,
753  std::vector<ENTITY *> &newEntities, ITERATOR it_beg,
754  ITERATOR it_end, int &elementaryNumber)
755 {
756  for(ITERATOR it = it_beg; it != it_end; ++it) {
757  int partition = elmToPartition[(*it)] - 1;
758 
759  if(!newEntities[partition]) {
760  std::vector<int> partitions;
761  partitions.push_back(partition + 1);
762  ENTITY *de = new ENTITY(model, ++elementaryNumber, partitions);
763  model->add(de);
764  newEntities[partition] = de;
765  }
766 
767  newEntities[partition]->addElement((*it)->getType(), *it);
768  }
769 }
770 
771 template <class ITERATOR>
772 static void setVerticesToEntity(GEntity *entity, ITERATOR it_beg,
773  ITERATOR it_end)
774 {
775  for(ITERATOR it = it_beg; it != it_end; ++it) {
776  for(std::size_t i = 0; i < (*it)->getNumVertices(); i++) {
777  if(!(*it)->getVertex(i)->onWhat()) {
778  (*it)->getVertex(i)->setEntity(entity);
779  entity->addMeshVertex((*it)->getVertex(i));
780  }
781  }
782  }
783 }
784 
785 template <class ITERATOR>
786 static void removeVerticesEntity(ITERATOR it_beg, ITERATOR it_end)
787 {
788  for(ITERATOR it = it_beg; it != it_end; ++it) {
789  for(std::size_t i = 0; i < (*it)->getNumMeshElements(); i++) {
790  for(std::size_t j = 0; j < (*it)->getMeshElement(i)->getNumVertices();
791  j++) {
792  (*it)->getMeshElement(i)->getVertex(j)->setEntity(nullptr);
793  }
794  }
795  (*it)->mesh_vertices.clear();
796  }
797 }
798 
799 // Assign the vertices to its corresponding entity
800 static void assignMeshVertices(GModel *model)
801 {
802  removeVerticesEntity(model->firstVertex(), model->lastVertex());
803  removeVerticesEntity(model->firstEdge(), model->lastEdge());
804  removeVerticesEntity(model->firstFace(), model->lastFace());
805  removeVerticesEntity(model->firstRegion(), model->lastRegion());
806 
807  // Loop over points
808  for(auto it = model->firstVertex(); it != model->lastVertex(); ++it) {
809  setVerticesToEntity(*it, (*it)->points.begin(), (*it)->points.end());
810  }
811 
812  // Loop over curves
813  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
814  setVerticesToEntity(*it, (*it)->lines.begin(), (*it)->lines.end());
815  }
816 
817  // Loop over surfaces
818  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
819  setVerticesToEntity(*it, (*it)->triangles.begin(), (*it)->triangles.end());
820  setVerticesToEntity(*it, (*it)->quadrangles.begin(),
821  (*it)->quadrangles.end());
822  }
823 
824  // Loop over volumes
825  for(auto it = model->firstRegion(); it != model->lastRegion(); ++it) {
826  setVerticesToEntity(*it, (*it)->tetrahedra.begin(),
827  (*it)->tetrahedra.end());
828  setVerticesToEntity(*it, (*it)->hexahedra.begin(), (*it)->hexahedra.end());
829  setVerticesToEntity(*it, (*it)->prisms.begin(), (*it)->prisms.end());
830  setVerticesToEntity(*it, (*it)->pyramids.begin(), (*it)->pyramids.end());
831  setVerticesToEntity(*it, (*it)->trihedra.begin(), (*it)->trihedra.end());
832  }
833 }
834 
835 static void fillConnectedElements(
836  std::vector<std::set<MElement *, MElementPtrLessThan> > &connectedElements,
837  Graph &graph)
838 {
839  std::stack<idx_t> elementStack;
840  std::set<MElement *, MElementPtrLessThan> elements;
841  idx_t startElement = 0;
842  bool stop = true;
843  std::size_t size = 0;
844  idx_t isolatedElements = 0;
845 
846  do {
847  // Inititalization
848  elementStack.push(startElement);
849  elements.insert(graph.element(startElement));
850 
851  while(elementStack.size() != 0) {
852  idx_t top = elementStack.top();
853  elementStack.pop();
854  elements.insert(graph.element(top));
855 
856  for(idx_t i = graph.xadj(top); i < graph.xadj(top + 1); i++) {
857  if(graph.adjncy(i) != 0) {
858  elementStack.push(graph.adjncy(i));
859  graph.adjncy(i, 0);
860  }
861  }
862  }
863  connectedElements.push_back(elements);
864  size += elements.size();
865  elements.clear();
866 
867  stop = (size == graph.ne() ? true : false);
868 
869  startElement = 0;
870  if(!stop) {
871  for(std::size_t i = 0; i < graph.ne(); i++) {
872  for(idx_t j = graph.xadj(i); j < graph.xadj(i + 1); j++) {
873  if(graph.adjncy(j) != 0) {
874  startElement = i;
875  i = graph.ne();
876  break;
877  }
878  }
879  }
880  if(startElement == 0) {
881  idx_t skipIsolatedElements = 0;
882  for(std::size_t i = 1; i < graph.ne(); i++) {
883  if(graph.xadj(i) == graph.xadj(i + 1)) {
884  if(skipIsolatedElements == isolatedElements) {
885  startElement = i;
886  isolatedElements++;
887  break;
888  }
889  skipIsolatedElements++;
890  }
891  }
892  }
893  }
894  } while(!stop);
895 }
896 
897 static bool
898 divideNonConnectedEntities(GModel *model, int dim,
899  std::set<GRegion *, GEntityPtrLessThan> &regions,
900  std::set<GFace *, GEntityPtrLessThan> &faces,
901  std::set<GEdge *, GEntityPtrLessThan> &edges,
902  std::set<GVertex *, GEntityPtrLessThan> &vertices)
903 {
904  bool ret = false;
905 
906  // Loop over points
907  if(dim < 0 || dim == 0) {
908  int elementaryNumber = model->getMaxElementaryNumber(0);
909 
910  for(auto it = vertices.begin(); it != vertices.end(); ++it) {
911  if((*it)->geomType() == GEntity::PartitionPoint) {
912  partitionVertex *vertex = static_cast<partitionVertex *>(*it);
913 
914  if(vertex->getNumMeshElements() > 1) {
915  ret = true;
916  for(std::size_t i = 0; i < vertex->getNumMeshElements(); i++) {
917  // Create the new partitionVertex
918  partitionVertex *pvertex = new partitionVertex(
919  model, ++elementaryNumber, vertex->getPartitions());
920  // Assign parent entity
921  pvertex->setParentEntity(vertex->getParentEntity());
922  // Add to model
923  model->add(pvertex);
924  // Add elements
925  pvertex->addElement(vertex->getMeshElement(i)->getType(),
926  vertex->getMeshElement(i));
927  // Move B-Rep
928  std::vector<GEdge *> BRepEdges = vertex->edges();
929  if(!BRepEdges.empty()) {
930  for(auto itBRep = BRepEdges.begin(); itBRep != BRepEdges.end();
931  ++itBRep) {
932  if(vertex == (*itBRep)->getBeginVertex()) {
933  (*itBRep)->setVertex(pvertex, 1);
934  pvertex->addEdge(*itBRep);
935  }
936  if(vertex == (*itBRep)->getEndVertex()) {
937  (*itBRep)->setVertex(pvertex, -1);
938  pvertex->addEdge(*itBRep);
939  }
940  }
941  }
942  }
943 
944  model->remove(vertex);
945  vertex->points.clear();
946  vertex->mesh_vertices.clear();
947  delete vertex;
948  }
949  }
950  }
951  }
952 
953  // Loop over curves
954  if(dim < 0 || dim == 1) {
955  // We build a graph
956  Graph graph(model);
957  graph.ne(model->getNumMeshElements(1));
958  graph.nn(model->getNumMeshVertices(1));
959  graph.dim(model->getMeshDim());
960  graph.elementResize(graph.ne());
961  graph.vertexResize(model->getMaxVertexNumber());
962  graph.eptrResize(graph.ne() + 1);
963  graph.eptr(0, 0);
964  std::size_t eindSize = getSizeOfEind(model);
965  graph.eindResize(eindSize);
966 
967  int elementaryNumber = model->getMaxElementaryNumber(1);
968 
969  for(auto it = edges.begin(); it != edges.end(); ++it) {
970  if((*it)->geomType() == GEntity::PartitionCurve) {
971  partitionEdge *edge = static_cast<partitionEdge *>(*it);
972 
973  graph.ne(edge->getNumMeshElements());
974  graph.dim(1);
975  graph.eptr(0, 0);
976  graph.clearDualGraph();
977  graph.eraseVertex();
978 
979  idx_t eptrIndex = 0;
980  idx_t eindIndex = 0;
981  idx_t numVertex = 0;
982 
983  fillElementsToNodesMap(graph, edge, eptrIndex, eindIndex, numVertex,
984  edge->lines.begin(), edge->lines.end());
985  graph.nn(numVertex);
986  graph.createDualGraph(false);
987 
988  // if a graph contains more than ((n-1)*(n-2))/2 edges (where n is the
989  // number of nodes), then it is connected.
990  if(((graph.numNodes() - 1) * (graph.numNodes() - 2)) / 2 <
991  graph.numEdges()) {
992  continue;
993  }
994 
995  std::vector<std::set<MElement *, MElementPtrLessThan> >
996  connectedElements;
997  fillConnectedElements(connectedElements, graph);
998 
999  if(connectedElements.size() > 1) {
1000  ret = true;
1001  std::vector<GFace *> BRepFaces = edge->faces();
1002 
1003  std::vector<int> oldOrientations;
1004  oldOrientations.reserve(BRepFaces.size());
1005 
1006  if(!BRepFaces.empty()) {
1007  for(auto itBRep = BRepFaces.begin(); itBRep != BRepFaces.end();
1008  ++itBRep) {
1009  oldOrientations.push_back((*itBRep)->delEdge(edge));
1010  }
1011  }
1012 
1013  for(std::size_t i = 0; i < connectedElements.size(); i++) {
1014  // Create the new partitionEdge
1015  partitionEdge *pedge =
1016  new partitionEdge(model, ++elementaryNumber, nullptr, nullptr,
1017  edge->getPartitions());
1018  // Assign parent entity
1019  pedge->setParentEntity(edge->getParentEntity());
1020  // Add to model
1021  model->add(pedge);
1022  for(auto itSet = connectedElements[i].begin();
1023  itSet != connectedElements[i].end(); ++itSet) {
1024  // Add elements
1025  pedge->addElement((*itSet)->getType(), (*itSet));
1026  }
1027  // Move B-Rep
1028  if(BRepFaces.size() > 0) {
1029  std::size_t j = 0;
1030  for(auto itBRep = BRepFaces.begin(); itBRep != BRepFaces.end();
1031  ++itBRep) {
1032  (*itBRep)->setEdge(pedge, oldOrientations[j]);
1033  pedge->addFace(*itBRep);
1034  j++;
1035  }
1036  }
1037  }
1038 
1039  model->remove(edge);
1040  edge->lines.clear();
1041  edge->mesh_vertices.clear();
1042  delete edge;
1043  }
1044 
1045  connectedElements.clear();
1046  }
1047  }
1048  }
1049 
1050  // Loop over surfaces
1051  if(dim < 0 || dim == 2) {
1052  // We build a graph
1053  Graph graph(model);
1054  graph.ne(model->getNumMeshElements(2));
1055  graph.nn(model->getNumMeshVertices(2));
1056  graph.dim(model->getMeshDim());
1057  graph.elementResize(graph.ne());
1058  graph.vertexResize(model->getMaxVertexNumber());
1059  graph.eptrResize(graph.ne() + 1);
1060  graph.eptr(0, 0);
1061  std::size_t eindSize = getSizeOfEind(model);
1062  graph.eindResize(eindSize);
1063 
1064  int elementaryNumber = model->getMaxElementaryNumber(2);
1065 
1066  for(auto it = faces.begin(); it != faces.end(); ++it) {
1067  if((*it)->geomType() == GEntity::PartitionSurface) {
1068  partitionFace *face = static_cast<partitionFace *>(*it);
1069 
1070  graph.ne(face->getNumMeshElements());
1071  graph.dim(2);
1072  graph.eptr(0, 0);
1073  graph.clearDualGraph();
1074  graph.eraseVertex();
1075 
1076  idx_t eptrIndex = 0;
1077  idx_t eindIndex = 0;
1078  idx_t numVertex = 0;
1079 
1080  fillElementsToNodesMap(graph, face, eptrIndex, eindIndex, numVertex,
1081  face->triangles.begin(), face->triangles.end());
1082  fillElementsToNodesMap(graph, face, eptrIndex, eindIndex, numVertex,
1083  face->quadrangles.begin(),
1084  face->quadrangles.end());
1085  graph.nn(numVertex);
1086  graph.createDualGraph(false);
1087 
1088  // if a graph contains more than ((n-1)*(n-2))/2 edges
1089  // (where n is the number of nodes), then it is connected.
1090  if(((graph.numNodes() - 1) * (graph.numNodes() - 2)) / 2 <
1091  graph.numEdges()) {
1092  continue;
1093  }
1094 
1095  std::vector<std::set<MElement *, MElementPtrLessThan> >
1096  connectedElements;
1097  fillConnectedElements(connectedElements, graph);
1098 
1099  if(connectedElements.size() > 1) {
1100  ret = true;
1101  std::list<GRegion *> BRepRegions = face->regions();
1102  std::vector<int> oldOrientations;
1103  if(BRepRegions.size() > 0) {
1104  for(auto itBRep = BRepRegions.begin(); itBRep != BRepRegions.end();
1105  ++itBRep) {
1106  oldOrientations.push_back((*itBRep)->delFace(face));
1107  }
1108  }
1109 
1110  for(std::size_t i = 0; i < connectedElements.size(); i++) {
1111  // Create the new partitionFace
1112  partitionFace *pface = new partitionFace(model, ++elementaryNumber,
1113  face->getPartitions());
1114  // Assign parent entity
1115  pface->setParentEntity(face->getParentEntity());
1116  // Add to model
1117  model->add(pface);
1118  for(auto itSet = connectedElements[i].begin();
1119  itSet != connectedElements[i].end(); ++itSet) {
1120  // Add elements
1121  pface->addElement((*itSet)->getType(), (*itSet));
1122  }
1123  // Move B-Rep
1124  if(BRepRegions.size() > 0) {
1125  std::size_t j = 0;
1126  for(auto itBRep = BRepRegions.begin();
1127  itBRep != BRepRegions.end(); ++itBRep) {
1128  (*itBRep)->setFace(pface, oldOrientations[j]);
1129  pface->addRegion(*itBRep);
1130  j++;
1131  }
1132  }
1133  }
1134 
1135  model->remove(face);
1136  face->triangles.clear();
1137  face->quadrangles.clear();
1138  face->mesh_vertices.clear();
1139  delete face;
1140  }
1141 
1142  connectedElements.clear();
1143  }
1144  }
1145  }
1146 
1147  // Loop over volumes
1148  if(dim < 0 || dim == 3) {
1149  // We build a graph
1150  Graph graph(model);
1151  graph.ne(model->getNumMeshElements(3));
1152  graph.nn(model->getNumMeshVertices(3));
1153  graph.dim(model->getMeshDim());
1154  graph.elementResize(graph.ne());
1155  graph.vertexResize(model->getMaxVertexNumber());
1156  graph.eptrResize(graph.ne() + 1);
1157  graph.eptr(0, 0);
1158  std::size_t eindSize = getSizeOfEind(model);
1159  graph.eindResize(eindSize);
1160 
1161  int elementaryNumber = model->getMaxElementaryNumber(3);
1162 
1163  for(auto it = regions.begin(); it != regions.end(); ++it) {
1164  if((*it)->geomType() == GEntity::PartitionVolume) {
1165  partitionRegion *region = static_cast<partitionRegion *>(*it);
1166 
1167  graph.ne(region->getNumMeshElements());
1168  graph.dim(3);
1169  graph.eptr(0, 0);
1170  graph.clearDualGraph();
1171  graph.eraseVertex();
1172 
1173  idx_t eptrIndex = 0;
1174  idx_t eindIndex = 0;
1175  idx_t numVertex = 0;
1176 
1177  fillElementsToNodesMap(graph, region, eptrIndex, eindIndex, numVertex,
1178  region->tetrahedra.begin(),
1179  region->tetrahedra.end());
1180  fillElementsToNodesMap(graph, region, eptrIndex, eindIndex, numVertex,
1181  region->hexahedra.begin(),
1182  region->hexahedra.end());
1183  fillElementsToNodesMap(graph, region, eptrIndex, eindIndex, numVertex,
1184  region->prisms.begin(), region->prisms.end());
1185  fillElementsToNodesMap(graph, region, eptrIndex, eindIndex, numVertex,
1186  region->pyramids.begin(),
1187  region->pyramids.end());
1188  fillElementsToNodesMap(graph, region, eptrIndex, eindIndex, numVertex,
1189  region->trihedra.begin(),
1190  region->trihedra.end());
1191  graph.nn(numVertex);
1192  graph.createDualGraph(false);
1193 
1194  // if a graph contains more than ((n-1)*(n-2))/2 edges (where n is the
1195  // number of nodes), then it is connected.
1196  if(((graph.numNodes() - 1) * (graph.numNodes() - 2)) / 2 <
1197  graph.numEdges()) {
1198  continue;
1199  }
1200 
1201  std::vector<std::set<MElement *, MElementPtrLessThan> >
1202  connectedElements;
1203  fillConnectedElements(connectedElements, graph);
1204 
1205  if(connectedElements.size() > 1) {
1206  ret = true;
1207  for(std::size_t i = 0; i < connectedElements.size(); i++) {
1208  // Create the new partitionRegion
1209  partitionRegion *pregion = new partitionRegion(
1210  model, ++elementaryNumber, region->getPartitions());
1211  // Assign d parent entity
1212  pregion->setParentEntity(region->getParentEntity());
1213  // Add to model
1214  model->add(pregion);
1215  for(auto itSet = connectedElements[i].begin();
1216  itSet != connectedElements[i].end(); ++itSet) {
1217  // Add elements
1218  pregion->addElement((*itSet)->getType(), (*itSet));
1219  }
1220  }
1221 
1222  model->remove(region);
1223  region->tetrahedra.clear();
1224  region->hexahedra.clear();
1225  region->prisms.clear();
1226  region->pyramids.clear();
1227  region->trihedra.clear();
1228  region->mesh_vertices.clear();
1229  delete region;
1230  }
1231 
1232  connectedElements.clear();
1233  }
1234  }
1235  }
1236 
1237  return ret;
1238 }
1239 
1240 // Create the new volume entities (omega)
1241 static void createNewEntities(GModel *model, hashmapelementpart &elmToPartition)
1242 {
1243  std::set<GRegion *, GEntityPtrLessThan> regions = model->getRegions();
1244  std::set<GFace *, GEntityPtrLessThan> faces = model->getFaces();
1245  std::set<GEdge *, GEntityPtrLessThan> edges = model->getEdges();
1246  std::set<GVertex *, GEntityPtrLessThan> vertices = model->getVertices();
1247 
1248  int elementaryNumber = model->getMaxElementaryNumber(0);
1249  for(auto it = vertices.begin(); it != vertices.end(); ++it) {
1250  std::vector<partitionVertex *> newVertices(model->getNumPartitions(),
1251  nullptr);
1252 
1253  assignElementsToEntities(model, elmToPartition, newVertices,
1254  (*it)->points.begin(), (*it)->points.end(),
1255  elementaryNumber);
1256 
1257  for(std::size_t i = 0; i < model->getNumPartitions(); i++) {
1258  if(newVertices[i]) {
1259  static_cast<partitionVertex *>(newVertices[i])->setParentEntity((*it));
1260  }
1261  }
1262 
1263  (*it)->mesh_vertices.clear();
1264 
1265  (*it)->points.clear();
1266  }
1267 
1268  elementaryNumber = model->getMaxElementaryNumber(1);
1269  for(auto it = edges.begin(); it != edges.end(); ++it) {
1270  std::vector<partitionEdge *> newEdges(model->getNumPartitions(), nullptr);
1271 
1272  assignElementsToEntities(model, elmToPartition, newEdges,
1273  (*it)->lines.begin(), (*it)->lines.end(),
1274  elementaryNumber);
1275 
1276  for(std::size_t i = 0; i < model->getNumPartitions(); i++) {
1277  if(newEdges[i]) {
1278  static_cast<partitionEdge *>(newEdges[i])->setParentEntity(*it);
1279  }
1280  }
1281 
1282  (*it)->mesh_vertices.clear();
1283 
1284  (*it)->lines.clear();
1285  }
1286 
1287  elementaryNumber = model->getMaxElementaryNumber(2);
1288  for(auto it = faces.begin(); it != faces.end(); ++it) {
1289  std::vector<partitionFace *> newFaces(model->getNumPartitions(), nullptr);
1290 
1291  assignElementsToEntities(model, elmToPartition, newFaces,
1292  (*it)->triangles.begin(), (*it)->triangles.end(),
1293  elementaryNumber);
1294  assignElementsToEntities(model, elmToPartition, newFaces,
1295  (*it)->quadrangles.begin(),
1296  (*it)->quadrangles.end(), elementaryNumber);
1297 
1298  std::list<GRegion *> BRepRegions = (*it)->regions();
1299  for(std::size_t i = 0; i < model->getNumPartitions(); i++) {
1300  if(newFaces[i]) {
1301  static_cast<partitionFace *>(newFaces[i])->setParentEntity(*it);
1302  }
1303  }
1304 
1305  (*it)->mesh_vertices.clear();
1306 
1307  (*it)->triangles.clear();
1308  (*it)->quadrangles.clear();
1309  }
1310 
1311  elementaryNumber = model->getMaxElementaryNumber(3);
1312  for(auto it = regions.begin(); it != regions.end(); ++it) {
1313  std::vector<partitionRegion *> newRegions(model->getNumPartitions(),
1314  nullptr);
1315 
1316  assignElementsToEntities(model, elmToPartition, newRegions,
1317  (*it)->tetrahedra.begin(), (*it)->tetrahedra.end(),
1318  elementaryNumber);
1319  assignElementsToEntities(model, elmToPartition, newRegions,
1320  (*it)->hexahedra.begin(), (*it)->hexahedra.end(),
1321  elementaryNumber);
1322  assignElementsToEntities(model, elmToPartition, newRegions,
1323  (*it)->prisms.begin(), (*it)->prisms.end(),
1324  elementaryNumber);
1325  assignElementsToEntities(model, elmToPartition, newRegions,
1326  (*it)->pyramids.begin(), (*it)->pyramids.end(),
1327  elementaryNumber);
1328  assignElementsToEntities(model, elmToPartition, newRegions,
1329  (*it)->trihedra.begin(), (*it)->trihedra.end(),
1330  elementaryNumber);
1331 
1332  for(std::size_t i = 0; i < model->getNumPartitions(); i++) {
1333  if(newRegions[i]) {
1334  static_cast<partitionRegion *>(newRegions[i])->setParentEntity(*it);
1335  }
1336  }
1337 
1338  (*it)->mesh_vertices.clear();
1339 
1340  (*it)->tetrahedra.clear();
1341  (*it)->hexahedra.clear();
1342  (*it)->prisms.clear();
1343  (*it)->pyramids.clear();
1344  (*it)->trihedra.clear();
1345  }
1346 
1347  // If we don't create the partition topology let's just assume that the user
1348  // does not care about multiply connected partitions or partition boundaries.
1350  regions = model->getRegions();
1351  faces = model->getFaces();
1352  edges = model->getEdges();
1353  vertices = model->getVertices();
1354  divideNonConnectedEntities(model, -1, regions, faces, edges, vertices);
1355 }
1356 
1357 static void fillElementToEntity(GModel *model, hashmapelement &elmToEntity,
1358  int dim)
1359 {
1360  // Loop over volumes
1361  if(dim < 0 || dim == 3) {
1362  for(auto it = model->firstRegion(); it != model->lastRegion(); ++it) {
1363  for(auto itElm = (*it)->tetrahedra.begin();
1364  itElm != (*it)->tetrahedra.end(); ++itElm)
1365  elmToEntity.insert(std::make_pair(*itElm, *it));
1366  for(auto itElm = (*it)->hexahedra.begin();
1367  itElm != (*it)->hexahedra.end(); ++itElm)
1368  elmToEntity.insert(std::make_pair(*itElm, *it));
1369  for(auto itElm = (*it)->prisms.begin(); itElm != (*it)->prisms.end();
1370  ++itElm)
1371  elmToEntity.insert(std::make_pair(*itElm, *it));
1372  for(auto itElm = (*it)->pyramids.begin(); itElm != (*it)->pyramids.end();
1373  ++itElm)
1374  elmToEntity.insert(std::make_pair(*itElm, *it));
1375  for(auto itElm = (*it)->trihedra.begin(); itElm != (*it)->trihedra.end();
1376  ++itElm)
1377  elmToEntity.insert(std::make_pair(*itElm, *it));
1378  }
1379  }
1380 
1381  // Loop over surfaces
1382  if(dim < 0 || dim == 2) {
1383  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
1384  for(auto itElm = (*it)->triangles.begin();
1385  itElm != (*it)->triangles.end(); ++itElm)
1386  elmToEntity.insert(std::make_pair(*itElm, *it));
1387  for(auto itElm = (*it)->quadrangles.begin();
1388  itElm != (*it)->quadrangles.end(); ++itElm)
1389  elmToEntity.insert(std::make_pair(*itElm, *it));
1390  }
1391  }
1392 
1393  // Loop over curves
1394  if(dim < 0 || dim == 1) {
1395  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
1396  for(auto itElm = (*it)->lines.begin(); itElm != (*it)->lines.end();
1397  ++itElm)
1398  elmToEntity.insert(std::make_pair(*itElm, *it));
1399  }
1400  }
1401 
1402  // Loop over points
1403  if(dim < 0 || dim == 0) {
1404  for(auto it = model->firstVertex(); it != model->lastVertex(); ++it) {
1405  for(auto itElm = (*it)->points.begin(); itElm != (*it)->points.end();
1406  ++itElm)
1407  elmToEntity.insert(std::make_pair(*itElm, *it));
1408  }
1409  }
1410 }
1411 
1412 static MElement *getReferenceElement(
1413  const std::vector<std::pair<MElement *, std::vector<int> > > &elementPairs)
1414 {
1415  int min = std::numeric_limits<int>::max();
1416  std::vector<std::pair<MElement *, std::vector<int> > > minSizeElementPairs;
1417  std::vector<std::pair<MElement *, std::vector<int> > > minSizeElementPairsTmp;
1418 
1419  // Take only the elements having the less partition in commun. For exemple we
1420  // take (1,2) and (3,8) but not (2,5,9) or (1,4,5,7)
1421  for(std::size_t i = 0; i < elementPairs.size(); i++) {
1422  if(min > (int)elementPairs[i].second.size()) {
1423  minSizeElementPairs.clear();
1424  min = elementPairs[i].second.size();
1425  minSizeElementPairs.push_back(elementPairs[i]);
1426  }
1427  else if(min == (int)elementPairs[i].second.size()) {
1428  minSizeElementPairs.push_back(elementPairs[i]);
1429  }
1430  }
1431 
1432  // Check if the element separated different partitions
1433  if(minSizeElementPairs.size() == elementPairs.size()) {
1434  bool isEqual = true;
1435  for(std::size_t i = 1; i < minSizeElementPairs.size(); i++) {
1436  if(minSizeElementPairs[i].second != minSizeElementPairs[0].second) {
1437  isEqual = false;
1438  break;
1439  }
1440  }
1441  if(isEqual) return nullptr;
1442  }
1443 
1444  while(minSizeElementPairs.size() > 1) {
1445  min = std::numeric_limits<int>::max();
1446  for(std::size_t i = 0; i < minSizeElementPairs.size(); i++) {
1447  // The partition vector is sorted thus we can check only the first element
1448  if(minSizeElementPairs[i].second.size() == 0)
1449  return minSizeElementPairs[0].first;
1450  if(min > minSizeElementPairs[i].second[0]) {
1451  min = minSizeElementPairs[i].second[0];
1452  }
1453  }
1454 
1455  for(std::size_t i = 0; i < minSizeElementPairs.size(); i++) {
1456  if(min == minSizeElementPairs[i].second[0]) {
1457  minSizeElementPairs[i].second.erase(
1458  minSizeElementPairs[i].second.begin());
1459  minSizeElementPairsTmp.push_back(minSizeElementPairs[i]);
1460  }
1461  }
1462  minSizeElementPairs.clear();
1463  minSizeElementPairs = std::move(minSizeElementPairsTmp);
1464  minSizeElementPairsTmp.clear();
1465  }
1466 
1467  return minSizeElementPairs[0].first;
1468 }
1469 
1470 static void getPartitionInVector(
1471  std::vector<int> &partitions,
1472  const std::vector<std::pair<MElement *, std::vector<int> > > &boundaryPair)
1473 {
1474  for(std::size_t i = 0; i < boundaryPair.size(); i++) {
1475  for(std::size_t j = 0; j < boundaryPair[i].second.size(); j++) {
1476  if(std::find(partitions.begin(), partitions.end(),
1477  boundaryPair[i].second[j]) == partitions.end()) {
1478  partitions.push_back(boundaryPair[i].second[j]);
1479  }
1480  }
1481  }
1482 
1483  std::sort(partitions.begin(), partitions.end());
1484 }
1485 
1486 template <class PART_ENTITY, class LESS_PART_ENTITY>
1487 static PART_ENTITY *createPartitionEntity(
1488  std::pair<typename std::multimap<PART_ENTITY *, GEntity *,
1489  LESS_PART_ENTITY>::iterator,
1490  typename std::multimap<PART_ENTITY *, GEntity *,
1491  LESS_PART_ENTITY>::iterator> &ret,
1492  GModel *model, int &numEntity, const std::vector<int> &partitions,
1493  GEntity *referenceEntity, PART_ENTITY **newEntity,
1494  typename std::multimap<PART_ENTITY *, GEntity *, LESS_PART_ENTITY> &pentities)
1495 {
1496  PART_ENTITY *ppe = nullptr;
1497  // Create the new partition entity for the mesh
1498  if(ret.first == ret.second) {
1499  // Create new entity and add them to the model
1500  ppe = new PART_ENTITY(model, ++numEntity, partitions);
1501  ppe->setParentEntity(referenceEntity->getParentEntity());
1502  pentities.insert(std::make_pair(ppe, referenceEntity));
1503  model->add(ppe);
1504  *newEntity = ppe;
1505  }
1506  else {
1507  for(auto it = ret.first; it != ret.second; ++it) {
1508  if(referenceEntity == it->second) { ppe = it->first; }
1509  }
1510  if(!ppe) {
1511  // Create new entity and add them to the model
1512  ppe = new PART_ENTITY(model, ++numEntity, partitions);
1513  ppe->setParentEntity(referenceEntity->getParentEntity());
1514  pentities.insert(std::make_pair(ppe, referenceEntity));
1515  model->add(ppe);
1516  *newEntity = ppe;
1517  }
1518  }
1519 
1520  return ppe;
1521 }
1522 
1523 static partitionFace *assignPartitionBoundary(
1524  GModel *model, MFace &me, MElement *reference,
1525  const std::vector<int> &partitions,
1526  std::multimap<partitionFace *, GEntity *, partitionFacePtrLessThan> &pfaces,
1527  hashmapelement &elementToEntity, int &numEntity)
1528 {
1529  partitionFace *newEntity = nullptr;
1530  partitionFace pf(model, partitions);
1531  std::pair<std::multimap<partitionFace *, GEntity *,
1532  partitionFacePtrLessThan>::iterator,
1533  std::multimap<partitionFace *, GEntity *,
1534  partitionFacePtrLessThan>::iterator>
1535  ret = pfaces.equal_range(&pf);
1536 
1537  partitionFace *ppf =
1538  createPartitionEntity(ret, model, numEntity, partitions,
1539  elementToEntity[reference], &newEntity, pfaces);
1540  int numFace = 0;
1541  for(int i = 0; i < reference->getNumFaces(); i++) {
1542  if(reference->getFace(i) == me) {
1543  numFace = i;
1544  break;
1545  }
1546  }
1547 
1548  if(me.getNumVertices() == 3) {
1549  std::vector<MVertex *> verts;
1550  reference->getFaceVertices(numFace, verts);
1551 
1552  if(verts.size() == 3) {
1553  MTriangle *element = new MTriangle(verts);
1554  ppf->addTriangle(element);
1555  }
1556  else if(verts.size() == 6) {
1557  MTriangle6 *element = new MTriangle6(verts);
1558  ppf->addTriangle(element);
1559  }
1560  else {
1561  MTriangleN *element =
1562  new MTriangleN(verts, verts.back()->getPolynomialOrder());
1563  ppf->addTriangle(element);
1564  }
1565  }
1566  else if(me.getNumVertices() == 4) {
1567  std::vector<MVertex *> verts;
1568  reference->getFaceVertices(numFace, verts);
1569 
1570  if(verts.size() == 4) {
1571  MQuadrangle *element = new MQuadrangle(verts);
1572  ppf->addQuadrangle(element);
1573  }
1574  else if(verts.size() == 8) {
1575  MQuadrangle8 *element = new MQuadrangle8(verts);
1576  ppf->addQuadrangle(element);
1577  }
1578  else if(verts.size() == 9) {
1579  MQuadrangle9 *element = new MQuadrangle9(verts);
1580  ppf->addQuadrangle(element);
1581  }
1582  else {
1584  new MQuadrangleN(verts, verts.back()->getPolynomialOrder());
1585  ppf->addQuadrangle(element);
1586  }
1587  }
1588 
1589  return newEntity;
1590 }
1591 
1592 static partitionEdge *assignPartitionBoundary(
1593  GModel *model, MEdge &me, MElement *reference,
1594  const std::vector<int> &partitions,
1595  std::multimap<partitionEdge *, GEntity *, partitionEdgePtrLessThan> &pedges,
1596  hashmapelement &elementToEntity, int &numEntity)
1597 {
1598  partitionEdge *newEntity = nullptr;
1599  partitionEdge pe(model, partitions);
1600  std::pair<std::multimap<partitionEdge *, GEntity *,
1601  partitionEdgePtrLessThan>::iterator,
1602  std::multimap<partitionEdge *, GEntity *,
1603  partitionEdgePtrLessThan>::iterator>
1604  ret = pedges.equal_range(&pe);
1605 
1606  partitionEdge *ppe =
1607  createPartitionEntity(ret, model, numEntity, partitions,
1608  elementToEntity[reference], &newEntity, pedges);
1609 
1610  int numEdge = 0;
1611  for(int i = 0; i < reference->getNumEdges(); i++) {
1612  if(reference->getEdge(i) == me) {
1613  numEdge = i;
1614  break;
1615  }
1616  }
1617 
1618  if(me.getNumVertices() == 2) {
1619  std::vector<MVertex *> verts;
1620  reference->getEdgeVertices(numEdge, verts);
1621 
1622  if(verts.size() == 2) {
1623  MLine *element = new MLine(verts);
1624  ppe->addLine(element);
1625  }
1626  else if(verts.size() == 3) {
1627  MLine3 *element = new MLine3(verts);
1628  ppe->addLine(element);
1629  }
1630  else {
1631  MLineN *element = new MLineN(verts);
1632  ppe->addLine(element);
1633  }
1634  }
1635 
1636  return newEntity;
1637 }
1638 
1639 static partitionVertex *assignPartitionBoundary(
1640  GModel *model, MVertex *ve, MElement *reference,
1641  const std::vector<int> &partitions,
1642  std::multimap<partitionVertex *, GEntity *, partitionVertexPtrLessThan>
1643  &pvertices,
1644  hashmapelement &elementToEntity, int &numEntity)
1645 {
1646  partitionVertex *newEntity = nullptr;
1647  partitionVertex pv(model, partitions);
1648  std::pair<std::multimap<partitionVertex *, GEntity *,
1649  partitionVertexPtrLessThan>::iterator,
1650  std::multimap<partitionVertex *, GEntity *,
1651  partitionVertexPtrLessThan>::iterator>
1652  ret = pvertices.equal_range(&pv);
1653 
1654  partitionVertex *ppv =
1655  createPartitionEntity(ret, model, numEntity, partitions,
1656  elementToEntity[reference], &newEntity, pvertices);
1657 
1658  ppv->addPoint(new MPoint(ve));
1659 
1660  return newEntity;
1661 }
1662 
1663 static int computeOrientation(MElement *reference, MElement *element)
1664 {
1665  if(element->getDim() == 2) {
1666  std::vector<MVertex *> vertices;
1667  element->getVertices(vertices);
1668  MFace face = element->getFace(0);
1669  for(int i = 0; i < reference->getNumFaces(); i++) {
1670  if(reference->getFace(i) == face) {
1671  std::vector<MVertex *> referenceVertices;
1672  reference->getFaceVertices(i, referenceVertices);
1673 
1674  if(referenceVertices == vertices)
1675  return 1;
1676  else
1677  return -1;
1678  }
1679  }
1680  }
1681  else if(element->getDim() == 1) {
1682  std::vector<MVertex *> vertices;
1683  element->getVertices(vertices);
1684  MEdge face = element->getEdge(0);
1685  for(int i = 0; i < reference->getNumEdges(); i++) {
1686  if(reference->getEdge(i) == face) {
1687  std::vector<MVertex *> referenceVertices;
1688  reference->getEdgeVertices(i, referenceVertices);
1689 
1690  if(referenceVertices == vertices)
1691  return 1;
1692  else
1693  return -1;
1694  }
1695  }
1696  }
1697  else if(element->getDim() == 0) {
1698  std::vector<MVertex *> vertices;
1699  element->getVertices(vertices);
1700 
1701  std::vector<MVertex *> referenceVertices;
1702  reference->getVertices(referenceVertices);
1703 
1704  if(referenceVertices[0] == vertices[0]) return 1;
1705  if(referenceVertices[1] == vertices[0]) return -1;
1706  }
1707 
1708  return 0;
1709 }
1710 
1711 static void assignBrep(GModel *model,
1712  std::map<GEntity *, MElement *, GEntityPtrFullLessThan>
1713  &boundaryEntityAndRefElement,
1714  GEntity *e)
1715 {
1716  if(e->dim() == 2) {
1717  partitionFace *entity = static_cast<partitionFace *>(e);
1718 
1719  for(auto it = boundaryEntityAndRefElement.begin();
1720  it != boundaryEntityAndRefElement.end(); ++it) {
1721  static_cast<GRegion *>(it->first)->setFace(
1722  entity, computeOrientation(it->second, entity->getMeshElement(0)));
1723  entity->addRegion(static_cast<GRegion *>(it->first));
1724  }
1725  }
1726  else if(e->dim() == 1) {
1727  partitionEdge *entity = static_cast<partitionEdge *>(e);
1728 
1729  for(auto it = boundaryEntityAndRefElement.begin();
1730  it != boundaryEntityAndRefElement.end(); ++it) {
1731  static_cast<GFace *>(it->first)->setEdge(
1732  entity, computeOrientation(it->second, entity->getMeshElement(0)));
1733  entity->addFace(static_cast<GFace *>(it->first));
1734  }
1735  }
1736  else if(e->dim() == 0) {
1737  partitionVertex *entity = static_cast<partitionVertex *>(e);
1738 
1739  for(auto it = boundaryEntityAndRefElement.begin();
1740  it != boundaryEntityAndRefElement.end(); ++it) {
1741  static_cast<GEdge *>(it->first)->setVertex(
1742  entity, computeOrientation(it->second, entity->getMeshElement(0)));
1743  entity->addEdge(static_cast<GEdge *>(it->first));
1744  }
1745  }
1746 }
1747 
1748 static void assignNewEntityBRep(Graph &graph, hashmapelement &elementToEntity)
1749 {
1750  std::set<std::pair<GEntity *, GEntity *> > brepWithoutOri;
1751  hashmapentity brep;
1752  for(std::size_t i = 0; i < graph.ne(); i++) {
1753  MElement *current = graph.element(i);
1754  for(idx_t j = graph.xadj(i); j < graph.xadj(i + 1); j++) {
1755  if(current->getDim() == graph.element(graph.adjncy(j))->getDim() + 1) {
1756  GEntity *g1 = elementToEntity[current];
1757  GEntity *g2 = elementToEntity[graph.element(graph.adjncy(j))];
1758  if(brepWithoutOri.find(std::pair<GEntity *, GEntity *>(g1, g2)) ==
1759  brepWithoutOri.end()) {
1760  const int ori =
1761  computeOrientation(current, graph.element(graph.adjncy(j)));
1762  brepWithoutOri.insert(std::make_pair(g1, g2));
1763  brep[g1].insert(std::make_pair(ori, g2));
1764  }
1765  }
1766  }
1767  }
1768 
1769  for(auto it = brep.begin(); it != brep.end(); ++it) {
1770  switch(it->first->dim()) {
1771  case 3:
1772  for(auto itSet = it->second.begin(); itSet != it->second.end(); ++itSet) {
1773  static_cast<GRegion *>(it->first)->setFace(
1774  static_cast<GFace *>(itSet->second), itSet->first);
1775  static_cast<GFace *>(itSet->second)
1776  ->addRegion(static_cast<GRegion *>(it->first));
1777  }
1778  break;
1779  case 2:
1780  for(auto itSet = it->second.begin(); itSet != it->second.end(); ++itSet) {
1781  static_cast<GFace *>(it->first)->setEdge(
1782  static_cast<GEdge *>(itSet->second), itSet->first);
1783  static_cast<GEdge *>(itSet->second)
1784  ->addFace(static_cast<GFace *>(it->first));
1785  }
1786  break;
1787  case 1:
1788  for(auto itSet = it->second.begin(); itSet != it->second.end(); ++itSet) {
1789  static_cast<GEdge *>(it->first)->setVertex(
1790  static_cast<GVertex *>(itSet->second), itSet->first);
1791  static_cast<GVertex *>(itSet->second)
1792  ->addEdge(static_cast<GEdge *>(it->first));
1793  }
1794  break;
1795  default: break;
1796  }
1797  }
1798 }
1799 
1800 // Create the new entities between each partitions (sigma and bndSigma).
1801 static void createPartitionTopology(
1802  GModel *model,
1803  const std::vector<std::set<MElement *, MElementPtrLessThan> >
1804  &boundaryElements,
1805  Graph &meshGraph)
1806 {
1807  int meshDim = model->getMeshDim();
1808  hashmapelement elementToEntity;
1809  fillElementToEntity(model, elementToEntity, -1);
1810  assignNewEntityBRep(meshGraph, elementToEntity);
1811 
1812  std::multimap<partitionFace *, GEntity *, partitionFacePtrLessThan> pfaces;
1813  std::multimap<partitionEdge *, GEntity *, partitionEdgePtrLessThan> pedges;
1814  std::multimap<partitionVertex *, GEntity *, partitionVertexPtrLessThan>
1815  pvertices;
1816 
1817  hashmapface faceToElement;
1818  hashmapedge edgeToElement;
1819  hashmapvertex vertexToElement;
1820 
1821  std::set<GRegion *, GEntityPtrLessThan> regions = model->getRegions();
1822  std::set<GFace *, GEntityPtrLessThan> faces = model->getFaces();
1823  std::set<GEdge *, GEntityPtrLessThan> edges = model->getEdges();
1824  std::set<GVertex *, GEntityPtrLessThan> vertices = model->getVertices();
1825 
1826  if(meshDim >= 3) {
1827  Msg::Info(" - Creating partition surfaces");
1828 
1829  for(std::size_t i = 0; i < model->getNumPartitions(); i++) {
1830  for(auto it = boundaryElements[i].begin();
1831  it != boundaryElements[i].end(); ++it) {
1832  for(int j = 0; j < (*it)->getNumFaces(); j++) {
1833  faceToElement[(*it)->getFace(j)].push_back(
1834  std::make_pair(*it, std::vector<int>(1, i + 1)));
1835  }
1836  }
1837  }
1838  int numFaceEntity = model->getMaxElementaryNumber(2);
1839  for(auto it = faceToElement.begin(); it != faceToElement.end(); ++it) {
1840  MFace f = it->first;
1841 
1842  std::vector<int> partitions;
1843  getPartitionInVector(partitions, it->second);
1844  if(partitions.size() < 2) continue;
1845 
1846  MElement *reference = getReferenceElement(it->second);
1847  if(!reference) continue;
1848 
1849  partitionFace *pf =
1850  assignPartitionBoundary(model, f, reference, partitions, pfaces,
1851  elementToEntity, numFaceEntity);
1852  if(pf) {
1853  std::map<GEntity *, MElement *, GEntityPtrFullLessThan>
1854  boundaryEntityAndRefElement;
1855  for(std::size_t i = 0; i < it->second.size(); i++)
1856  boundaryEntityAndRefElement.insert(std::make_pair(
1857  elementToEntity[it->second[i].first], it->second[i].first));
1858 
1859  assignBrep(model, boundaryEntityAndRefElement, pf);
1860  }
1861  }
1862  faceToElement.clear();
1863 
1864  faces = model->getFaces();
1865  divideNonConnectedEntities(model, 2, regions, faces, edges, vertices);
1866  elementToEntity.clear();
1867  fillElementToEntity(model, elementToEntity, 2);
1868  }
1869 
1870  if(meshDim >= 2) {
1871  Msg::Info(" - Creating partition curves");
1872 
1873  if(meshDim == 2) {
1874  for(std::size_t i = 0; i < model->getNumPartitions(); i++) {
1875  for(auto it = boundaryElements[i].begin();
1876  it != boundaryElements[i].end(); ++it) {
1877  for(int j = 0; j < (*it)->getNumEdges(); j++) {
1878  edgeToElement[(*it)->getEdge(j)].push_back(
1879  std::make_pair(*it, std::vector<int>(1, i + 1)));
1880  }
1881  }
1882  }
1883  }
1884  else {
1885  Graph subGraph(model);
1886  makeGraph(model, subGraph, 2);
1887  subGraph.createDualGraph(false);
1888  std::vector<idx_t> part(subGraph.ne());
1889  int partIndex = 0;
1890 
1891  std::map<idx_t, std::vector<int> > mapOfPartitions;
1892  idx_t mapOfPartitionsTag = 0;
1893  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
1894  if((*it)->geomType() == GEntity::PartitionSurface) {
1895  std::vector<int> partitions =
1896  static_cast<partitionFace *>(*it)->getPartitions();
1897  mapOfPartitions.insert(std::make_pair(mapOfPartitionsTag, partitions));
1898  // Must absolutely be in the same order as in the makeGraph function
1899  for(auto itElm = (*it)->triangles.begin();
1900  itElm != (*it)->triangles.end(); ++itElm)
1901  part[partIndex++] = mapOfPartitionsTag;
1902  for(auto itElm = (*it)->quadrangles.begin();
1903  itElm != (*it)->quadrangles.end(); ++itElm)
1904  part[partIndex++] = mapOfPartitionsTag;
1905  mapOfPartitionsTag++;
1906  }
1907  }
1908  subGraph.partition(part);
1909 
1910  std::vector<std::set<MElement *, MElementPtrLessThan> >
1911  subBoundaryElements = subGraph.getBoundaryElements(mapOfPartitionsTag);
1912 
1913  for(idx_t i = 0; i < mapOfPartitionsTag; i++) {
1914  for(auto it = subBoundaryElements[i].begin();
1915  it != subBoundaryElements[i].end(); ++it) {
1916  for(int j = 0; j < (*it)->getNumEdges(); j++) {
1917  edgeToElement[(*it)->getEdge(j)].push_back(
1918  std::make_pair(*it, mapOfPartitions[i]));
1919  }
1920  }
1921  }
1922  }
1923 
1924  int numEdgeEntity = model->getMaxElementaryNumber(1);
1925  for(auto it = edgeToElement.begin(); it != edgeToElement.end(); ++it) {
1926  MEdge e = it->first;
1927 
1928  std::vector<int> partitions;
1929  getPartitionInVector(partitions, it->second);
1930  if(partitions.size() < 2) continue;
1931 
1932  MElement *reference = getReferenceElement(it->second);
1933  if(!reference) continue;
1934 
1935  partitionEdge *pe =
1936  assignPartitionBoundary(model, e, reference, partitions, pedges,
1937  elementToEntity, numEdgeEntity);
1938  if(pe) {
1939  std::map<GEntity *, MElement *, GEntityPtrFullLessThan>
1940  boundaryEntityAndRefElement;
1941  for(std::size_t i = 0; i < it->second.size(); i++) {
1942  boundaryEntityAndRefElement.insert(std::make_pair(
1943  elementToEntity[it->second[i].first], it->second[i].first));
1944  }
1945 
1946  assignBrep(model, boundaryEntityAndRefElement, pe);
1947  }
1948  }
1949  edgeToElement.clear();
1950 
1951  edges = model->getEdges();
1952  divideNonConnectedEntities(model, 1, regions, faces, edges, vertices);
1953  elementToEntity.clear();
1954  fillElementToEntity(model, elementToEntity, 1);
1955  }
1956 
1957  if(meshDim >= 1) {
1958  Msg::Info(" - Creating partition points");
1959  if(meshDim == 1) {
1960  for(std::size_t i = 0; i < model->getNumPartitions(); i++) {
1961  for(auto it = boundaryElements[i].begin();
1962  it != boundaryElements[i].end(); ++it) {
1963  for(std::size_t j = 0; j < (*it)->getNumPrimaryVertices(); j++) {
1964  vertexToElement[(*it)->getVertex(j)].push_back(
1965  std::make_pair(*it, std::vector<int>(1, i + 1)));
1966  }
1967  }
1968  }
1969  }
1970  else {
1971  Graph subGraph(model);
1972  makeGraph(model, subGraph, 1);
1973  subGraph.createDualGraph(false);
1974  std::vector<idx_t> part(subGraph.ne());
1975  int partIndex = 0;
1976 
1977  std::map<idx_t, std::vector<int> > mapOfPartitions;
1978  idx_t mapOfPartitionsTag = 0;
1979  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
1980  if((*it)->geomType() == GEntity::PartitionCurve) {
1981  std::vector<int> partitions =
1982  static_cast<partitionEdge *>(*it)->getPartitions();
1983  mapOfPartitions.insert(std::make_pair(mapOfPartitionsTag, partitions));
1984  // Must absolutely be in the same order as in the makeGraph function
1985  for(auto itElm = (*it)->lines.begin(); itElm != (*it)->lines.end();
1986  ++itElm)
1987  part[partIndex++] = mapOfPartitionsTag;
1988  mapOfPartitionsTag++;
1989  }
1990  }
1991  subGraph.partition(part);
1992 
1993  std::vector<std::set<MElement *, MElementPtrLessThan> >
1994  subBoundaryElements = subGraph.getBoundaryElements(mapOfPartitionsTag);
1995 
1996  for(idx_t i = 0; i < mapOfPartitionsTag; i++) {
1997  for(auto it = subBoundaryElements[i].begin();
1998  it != subBoundaryElements[i].end(); ++it) {
1999  for(std::size_t j = 0; j < (*it)->getNumPrimaryVertices(); j++) {
2000  vertexToElement[(*it)->getVertex(j)].push_back(
2001  std::make_pair(*it, mapOfPartitions[i]));
2002  }
2003  }
2004  }
2005  }
2006  int numVertexEntity = model->getMaxElementaryNumber(0);
2007  for(auto it = vertexToElement.begin(); it != vertexToElement.end(); ++it) {
2008  MVertex *v = it->first;
2009 
2010  std::vector<int> partitions;
2011  getPartitionInVector(partitions, it->second);
2012  if(partitions.size() < 2) continue;
2013 
2014  MElement *reference = getReferenceElement(it->second);
2015  if(!reference) continue;
2016 
2017  partitionVertex *pv =
2018  assignPartitionBoundary(model, v, reference, partitions, pvertices,
2019  elementToEntity, numVertexEntity);
2020  if(pv) {
2021  std::map<GEntity *, MElement *, GEntityPtrFullLessThan>
2022  boundaryEntityAndRefElement;
2023  for(std::size_t i = 0; i < it->second.size(); i++)
2024  boundaryEntityAndRefElement.insert(std::make_pair(
2025  elementToEntity[it->second[i].first], it->second[i].first));
2026 
2027  assignBrep(model, boundaryEntityAndRefElement, pv);
2028  }
2029  }
2030  vertexToElement.clear();
2031 
2032  vertices = model->getVertices();
2033  divideNonConnectedEntities(model, 0, regions, faces, edges, vertices);
2034  }
2035 }
2036 
2037 static void addPhysical(GModel *model, GEntity *entity,
2038  hashmap<std::string, int> &nameToNumber,
2039  std::vector<GModel::piter> &iterators, int &numPhysical)
2040 {
2041  GEntity *parent = entity->getParentEntity();
2042  if(parent == nullptr) return;
2043 
2044  if(!CTX::instance()->mesh.partitionCreatePhysicals ||
2046  if(parent->dim() == entity->dim()) {
2047  // reuse physicals from parent entity
2048  entity->physicals = parent->physicals;
2049  }
2050  return;
2051  }
2052 
2053  std::size_t numPartitions = 0;
2054  if(entity->dim() == 3) {
2055  numPartitions = static_cast<partitionRegion *>(entity)->numPartitions();
2056  }
2057  else if(entity->dim() == 2) {
2058  numPartitions = static_cast<partitionFace *>(entity)->numPartitions();
2059  }
2060  else if(entity->dim() == 1) {
2061  numPartitions = static_cast<partitionEdge *>(entity)->numPartitions();
2062  }
2063  else if(entity->dim() == 0) {
2064  numPartitions = static_cast<partitionVertex *>(entity)->numPartitions();
2065  }
2066 
2067  std::vector<int> physical = parent->getPhysicalEntities();
2068  int dim = entity->dim();
2069  for(size_t phys = 0; phys < physical.size(); ++phys) {
2070  std::string name = "_part{";
2071 
2072  for(std::size_t i = 0; i < numPartitions; i++) {
2073  if(i > 0) name += ",";
2074  int partition = 0;
2075  if(entity->dim() == 3) {
2076  partition = static_cast<partitionRegion *>(entity)->getPartition(i);
2077  }
2078  else if(entity->dim() == 2) {
2079  partition = static_cast<partitionFace *>(entity)->getPartition(i);
2080  }
2081  else if(entity->dim() == 1) {
2082  partition = static_cast<partitionEdge *>(entity)->getPartition(i);
2083  }
2084  else if(entity->dim() == 0) {
2085  partition = static_cast<partitionVertex *>(entity)->getPartition(i);
2086  }
2087  name += std::to_string(partition);
2088  }
2089  name += "}_physical{";
2090  name +=
2091  std::to_string(physical[phys]) + "}_dim{" + std::to_string(dim) + "}";
2092 
2093  int number = 0;
2094  auto it = nameToNumber.find(name);
2095  if(it == nameToNumber.end()) {
2096  number = ++numPhysical;
2097  iterators[entity->dim()] = model->setPhysicalName(
2098  iterators[entity->dim()], name, entity->dim(), number);
2099  nameToNumber.insert(std::make_pair(name, number));
2100  }
2101  else {
2102  number = it->second;
2103  }
2104  entity->addPhysicalEntity(number);
2105  }
2106 
2107  if(physical.size() == 0) {
2108  std::string name = "_part{";
2109 
2110  for(std::size_t i = 0; i < numPartitions; i++) {
2111  if(i > 0) name += ",";
2112  int partition = 0;
2113  if(entity->dim() == 3) {
2114  partition = static_cast<partitionRegion *>(entity)->getPartition(i);
2115  }
2116  else if(entity->dim() == 2) {
2117  partition = static_cast<partitionFace *>(entity)->getPartition(i);
2118  }
2119  else if(entity->dim() == 1) {
2120  partition = static_cast<partitionEdge *>(entity)->getPartition(i);
2121  }
2122  else if(entity->dim() == 0) {
2123  partition = static_cast<partitionVertex *>(entity)->getPartition(i);
2124  }
2125  name += std::to_string(partition);
2126  }
2127  name += "}_";
2128  name += "physical{0}_dim{" + std::to_string(dim) + "}";
2129 
2130  int number = 0;
2131  auto it = nameToNumber.find(name);
2132  if(it == nameToNumber.end()) {
2133  number = ++numPhysical;
2134  iterators[entity->dim()] = model->setPhysicalName(
2135  iterators[entity->dim()], name, entity->dim(), number);
2136  nameToNumber.insert(std::make_pair(name, number));
2137  }
2138  else {
2139  number = it->second;
2140  }
2141  entity->addPhysicalEntity(number);
2142  }
2143 }
2144 
2145 // Assign physical group information
2146 static void assignPhysicals(GModel *model)
2147 {
2148  hashmap<std::string, int> nameToNumber;
2149  std::vector<GModel::piter> iterators;
2150  model->getInnerPhysicalNamesIterators(iterators);
2151  int numPhysical = model->getMaxPhysicalNumber(-1);
2152  // Loop over volumes
2153  for(auto it = model->firstRegion(); it != model->lastRegion(); ++it) {
2154  if((*it)->geomType() == GEntity::PartitionVolume) {
2155  addPhysical(model, *it, nameToNumber, iterators, numPhysical);
2156  }
2157  }
2158 
2159  // Loop over surfaces
2160  for(auto it = model->firstFace(); it != model->lastFace(); ++it) {
2161  if((*it)->geomType() == GEntity::PartitionSurface) {
2162  addPhysical(model, *it, nameToNumber, iterators, numPhysical);
2163  }
2164  }
2165 
2166  // Loop over curves
2167  for(auto it = model->firstEdge(); it != model->lastEdge(); ++it) {
2168  if((*it)->geomType() == GEntity::PartitionCurve) {
2169  addPhysical(model, *it, nameToNumber, iterators, numPhysical);
2170  }
2171  }
2172 
2173  // Loop over points
2174  for(auto it = model->firstVertex(); it != model->lastVertex(); ++it) {
2175  if((*it)->geomType() == GEntity::PartitionPoint) {
2176  addPhysical(model, *it, nameToNumber, iterators, numPhysical);
2177  }
2178  }
2179 }
2180 
2181 bool cmp_hedges(const std::pair<MEdge, size_t> &he0,
2182  const std::pair<MEdge, size_t> &he1)
2183 {
2184  MEdgeLessThan cmp;
2185  return cmp(he0.first, he1.first);
2186 }
2187 
2188 int PartitionFaceMinEdgeLength(GFace *gf, int np, double tol)
2189 {
2190  std::vector<std::pair<MEdge, size_t> > halfEdges;
2191  halfEdges.reserve(gf->triangles.size() * 3);
2192  for(size_t i = 0; i < gf->triangles.size(); ++i) {
2193  for(size_t j = 0; j < 3; ++j) {
2194  halfEdges.push_back(std::make_pair(gf->triangles[i]->getEdge(j), i));
2195  }
2196  }
2197  std::sort(halfEdges.begin(), halfEdges.end(), cmp_hedges);
2198  std::vector<idx_t> neighbors(gf->triangles.size() * 3, -1);
2199  std::vector<double> neighborsWeight(gf->triangles.size() * 3, -1);
2200  MEdgeEqual eq;
2201  double minEdgeLength = std::numeric_limits<double>::max();
2202  for(size_t i = 0; i + 1 < halfEdges.size(); ++i) {
2203  if(eq(halfEdges[i].first, halfEdges[i + 1].first)) {
2204  size_t t0 = halfEdges[i].second;
2205  size_t t1 = halfEdges[i + 1].second;
2206  double l = halfEdges[i].first.length();
2207  minEdgeLength = std::min(l, minEdgeLength);
2208  for(int j = 0; j < 3; ++j) {
2209  if(neighbors[t0 * 3 + j] == -1) {
2210  neighbors[t0 * 3 + j] = t1;
2211  neighborsWeight[t0 * 3 + j] = l;
2212  break;
2213  }
2214  }
2215  for(int j = 0; j < 3; ++j) {
2216  if(neighbors[t1 * 3 + j] == -1) {
2217  neighbors[t1 * 3 + j] = t0;
2218  neighborsWeight[t1 * 3 + j] = l;
2219  break;
2220  }
2221  }
2222  i++;
2223  }
2224  }
2225  std::vector<idx_t> adjncy;
2226  std::vector<idx_t> xadjncy;
2227  std::vector<idx_t> adjncyw;
2228  xadjncy.push_back(0);
2229  for(size_t i = 0; i < gf->triangles.size(); ++i) {
2230  for(size_t j = 0; j < 3; ++j) {
2231  if(neighbors[i * 3 + j] == -1) break;
2232  adjncy.push_back(neighbors[i * 3 + j]);
2233  adjncyw.push_back(
2234  (idx_t)(neighborsWeight[i * 3 + j] / minEdgeLength * 10));
2235  }
2236  xadjncy.push_back(adjncy.size());
2237  }
2238  idx_t nvtxs = gf->triangles.size(), ncon = 1, nparts = np, objval;
2239  std::vector<idx_t> epart(gf->triangles.size());
2240  real_t ubvec = tol;
2241  METIS_PartGraphKway(&nvtxs, &ncon, &xadjncy[0], &adjncy[0], nullptr, nullptr,
2242  &adjncyw[0], &nparts, nullptr, &ubvec, nullptr, &objval,
2243  &epart[0]);
2244  for(size_t i = 0; i < gf->triangles.size(); ++i) {
2245  gf->triangles[i]->setPartition(epart[i]);
2246  }
2247  return 0;
2248 }
2249 
2250 // Partition a mesh into n parts. Returns: 0 = success, 1 = error
2251 
2252 int PartitionMesh(GModel *model, int numPart)
2253 {
2254  if(numPart <= 0) return 0;
2255 
2256  Msg::StatusBar(true, "Partitioning mesh...");
2257  double t1 = Cpu(), w1 = TimeOfDay();
2258 
2259  Graph graph(model);
2260  if(makeGraph(model, graph, -1)) return 1;
2261  graph.nparts(numPart);
2262  if(partitionGraph(graph, true)) return 1;
2263 
2264  std::vector<std::size_t> elmCount[TYPE_MAX_NUM + 1];
2265  for(int i = 0; i < TYPE_MAX_NUM + 1; i++) { elmCount[i].resize(numPart, 0); }
2266 
2267  // Assign partitions to elements
2268  hashmapelementpart elmToPartition;
2269  for(std::size_t i = 0; i < graph.ne(); i++) {
2270  if(graph.element(i)) {
2271  if(graph.nparts() > 1) {
2272  elmToPartition.insert(std::make_pair(
2273  graph.element(i), graph.partition(i) + 1));
2274  elmCount[graph.element(i)->getType()][graph.partition(i)]++;
2275  // Should be removed
2276  graph.element(i)->setPartition(graph.partition(i) + 1);
2277  }
2278  else {
2279  elmToPartition.insert(std::make_pair(graph.element(i), 1));
2280  // Should be removed
2281  graph.element(i)->setPartition(1);
2282  }
2283  }
2284  }
2285  model->setNumPartitions(graph.nparts());
2286 
2287  createNewEntities(model, elmToPartition);
2288  elmToPartition.clear();
2289 
2290  double t2 = Cpu(), w2 = TimeOfDay();
2291  Msg::StatusBar(true, "Done partitioning mesh (Wall %gs, CPU %gs)", w2 - w1,
2292  t2 - t1);
2293 
2294  for(std::size_t i = 0; i < TYPE_MAX_NUM + 1; i++) {
2295  std::vector<std::size_t> &count = elmCount[i];
2296  std::size_t minCount = std::numeric_limits<std::size_t>::max();
2297  std::size_t maxCount = 0;
2298  std::size_t totCount = 0;
2299  for(std::size_t j = 0; j < count.size(); j++) {
2300  minCount = std::min(count[j], minCount);
2301  maxCount = std::max(count[j], maxCount);
2302  totCount += count[j];
2303  }
2304  if(totCount > 0) {
2305  Msg::Info(" - Repartition of %d %s: %lu(min) %lu(max) %g(avg)", totCount,
2306  ElementType::nameOfParentType(i, totCount > 1).c_str(),
2307  minCount, maxCount, totCount / (double)numPart);
2308  }
2309  }
2310 
2311  if(CTX::instance()->mesh.partitionCreateTopology) {
2312  Msg::StatusBar(true, "Creating partition topology...");
2313  std::vector<std::set<MElement *, MElementPtrLessThan> > boundaryElements =
2314  graph.getBoundaryElements();
2315  createPartitionTopology(model, boundaryElements, graph);
2316  boundaryElements.clear();
2317  double t3 = Cpu(), w3 = TimeOfDay();
2318  Msg::StatusBar(true, "Done creating partition topology (Wall %gs, CPU %gs)",
2319  w3 - w2, t3 - t2);
2320  }
2321 
2322  assignPhysicals(model);
2323  assignMeshVertices(model);
2324 
2325  if(CTX::instance()->mesh.partitionCreateGhostCells) {
2326  double t4 = Cpu(), w4 = TimeOfDay();
2327  Msg::StatusBar(true, "Creating ghost cells...");
2328  graph.clearDualGraph();
2329  graph.createDualGraph(true);
2330  graph.assignGhostCells();
2331  double t5 = Cpu(), w5 = TimeOfDay();
2332  Msg::StatusBar(true, "Done creating ghost cells (Wall %gs, CPU %gs)",
2333  w5 - w4, t5 - t4);
2334  }
2335 
2336  return 0;
2337 }
2338 
2339 template <class ITERATOR, class PART_ENTITY>
2340 static void assignToParent(std::set<MVertex *> &verts, PART_ENTITY *entity,
2341  ITERATOR it_beg, ITERATOR it_end)
2342 {
2343  for(ITERATOR it = it_beg; it != it_end; ++it) {
2344  entity->getParentEntity()->addElement((*it)->getType(), *it);
2345  (*it)->setPartition(0);
2346 
2347  for(std::size_t i = 0; i < (*it)->getNumVertices(); i++) {
2348  if(verts.find((*it)->getVertex(i)) == verts.end()) {
2349  (*it)->getVertex(i)->setEntity(entity->getParentEntity());
2350  entity->getParentEntity()->addMeshVertex((*it)->getVertex(i));
2351  verts.insert((*it)->getVertex(i));
2352  }
2353  }
2354  }
2355 }
2356 
2357 // Un-partition a mesh and return to the initial mesh geomerty. Returns: 0 =
2358 // success, 1 = error.
2359 int UnpartitionMesh(GModel *model)
2360 {
2361  // make a copy so we can iterate safely (we will remove some entities)
2362  std::set<GRegion *, GEntityPtrLessThan> regions = model->getRegions();
2363  std::set<GFace *, GEntityPtrLessThan> faces = model->getFaces();
2364  std::set<GEdge *, GEntityPtrLessThan> edges = model->getEdges();
2365  std::set<GVertex *, GEntityPtrLessThan> vertices = model->getVertices();
2366 
2367  std::set<MVertex *> verts;
2368 
2369  // Loop over points
2370  for(auto it = vertices.begin(); it != vertices.end(); ++it) {
2371  GVertex *vertex = *it;
2372 
2373  if(vertex->geomType() == GEntity::PartitionPoint) {
2374  partitionVertex *pvertex = static_cast<partitionVertex *>(vertex);
2375  if(pvertex->getParentEntity() && pvertex->getParentEntity()->dim() == 0) {
2376  assignToParent(verts, pvertex, pvertex->points.begin(),
2377  pvertex->points.end());
2378  }
2379  else {
2380  for(std::size_t j = 0; j < pvertex->points.size(); j++)
2381  delete pvertex->points[j];
2382  }
2383  pvertex->points.clear();
2384  pvertex->mesh_vertices.clear();
2385 
2386  model->remove(pvertex);
2387  delete pvertex;
2388  }
2389  }
2390 
2391  // Loop over curves
2392  for(auto it = edges.begin(); it != edges.end(); ++it) {
2393  GEdge *edge = *it;
2394  if(edge->geomType() == GEntity::PartitionCurve) {
2395  partitionEdge *pedge = static_cast<partitionEdge *>(edge);
2396  if(pedge->getParentEntity() && pedge->getParentEntity()->dim() == 1) {
2397  assignToParent(verts, pedge, pedge->lines.begin(), pedge->lines.end());
2398  }
2399  else {
2400  for(std::size_t j = 0; j < pedge->lines.size(); j++)
2401  delete pedge->lines[j];
2402  }
2403  pedge->lines.clear();
2404  pedge->mesh_vertices.clear();
2405  pedge->setBeginVertex(nullptr);
2406  pedge->setEndVertex(nullptr);
2407 
2408  model->remove(pedge);
2409  delete pedge;
2410  }
2411  else if(edge->geomType() == GEntity::GhostCurve) {
2412  model->remove(edge);
2413  delete edge;
2414  }
2415  }
2416 
2417  // Loop over surfaces
2418  for(auto it = faces.begin(); it != faces.end(); ++it) {
2419  GFace *face = *it;
2420 
2421  if(face->geomType() == GEntity::PartitionSurface) {
2422  partitionFace *pface = static_cast<partitionFace *>(face);
2423  if(pface->getParentEntity() && pface->getParentEntity()->dim() == 2) {
2424  assignToParent(verts, pface, pface->triangles.begin(),
2425  pface->triangles.end());
2426  assignToParent(verts, pface, pface->quadrangles.begin(),
2427  pface->quadrangles.end());
2428  }
2429  else {
2430  for(std::size_t j = 0; j < pface->triangles.size(); j++)
2431  delete pface->triangles[j];
2432  for(std::size_t j = 0; j < pface->quadrangles.size(); j++)
2433  delete pface->quadrangles[j];
2434  }
2435  pface->triangles.clear();
2436  pface->quadrangles.clear();
2437  pface->mesh_vertices.clear();
2438  pface->set(std::vector<GEdge *>());
2439  pface->setOrientations(std::vector<int>());
2440 
2441  model->remove(pface);
2442  delete pface;
2443  }
2444  else if(face->geomType() == GEntity::GhostSurface) {
2445  model->remove(face);
2446  delete face;
2447  }
2448  }
2449 
2450  // Loop over volumes
2451  for(auto it = regions.begin(); it != regions.end(); ++it) {
2452  GRegion *region = *it;
2453 
2454  if(region->geomType() == GEntity::PartitionVolume) {
2455  partitionRegion *pregion = static_cast<partitionRegion *>(region);
2456  if(pregion->getParentEntity() && pregion->getParentEntity()->dim() == 3) {
2457  assignToParent(verts, pregion, pregion->tetrahedra.begin(),
2458  pregion->tetrahedra.end());
2459  assignToParent(verts, pregion, pregion->hexahedra.begin(),
2460  pregion->hexahedra.end());
2461  assignToParent(verts, pregion, pregion->prisms.begin(),
2462  pregion->prisms.end());
2463  assignToParent(verts, pregion, pregion->pyramids.begin(),
2464  pregion->pyramids.end());
2465  assignToParent(verts, pregion, pregion->trihedra.begin(),
2466  pregion->trihedra.end());
2467  }
2468  else {
2469  for(std::size_t j = 0; j < pregion->tetrahedra.size(); j++)
2470  delete pregion->tetrahedra[j];
2471  for(std::size_t j = 0; j < pregion->hexahedra.size(); j++)
2472  delete pregion->hexahedra[j];
2473  for(std::size_t j = 0; j < pregion->prisms.size(); j++)
2474  delete pregion->prisms[j];
2475  for(std::size_t j = 0; j < pregion->pyramids.size(); j++)
2476  delete pregion->pyramids[j];
2477  for(std::size_t j = 0; j < pregion->trihedra.size(); j++)
2478  delete pregion->trihedra[j];
2479  }
2480  pregion->tetrahedra.clear();
2481  pregion->hexahedra.clear();
2482  pregion->prisms.clear();
2483  pregion->pyramids.clear();
2484  pregion->trihedra.clear();
2485  pregion->mesh_vertices.clear();
2486  pregion->set(std::vector<GFace *>());
2487  pregion->setOrientations(std::vector<int>());
2488 
2489  model->remove(pregion);
2490  delete pregion;
2491  }
2492  else if(region->geomType() == GEntity::GhostVolume) {
2493  model->remove(region);
2494  delete region;
2495  }
2496  }
2497 
2498  model->setNumPartitions(0);
2499 
2500  std::map<std::pair<int, int>, std::string> physicalNames =
2501  model->getPhysicalNames();
2502  for(auto it = physicalNames.begin(); it != physicalNames.end(); ++it) {
2503  std::size_t found = it->second.find("_");
2504  if(found != std::string::npos) {
2505  model->removePhysicalGroup(it->first.first, it->first.second);
2506  }
2507  }
2508 
2509  return 0;
2510 }
2511 
2512 // Create the partition according to the element split given by elmToPartition
2513 // Returns: 0 = success, 1 = no elements found/invalid data.
2514 int PartitionUsingThisSplit(GModel *model,
2515  std::vector<std::pair<MElement *, int> > &elmToPart)
2516 {
2517  Graph graph(model);
2518  if(makeGraph(model, graph, -1)) return 1;
2519 
2520  int numPart = 0;
2521  hashmapelementpart elmToPartition;
2522  std::vector<std::pair<MElement*, int> > elmGhosts;
2523  for(auto item : elmToPart) {
2524  MElement *el = item.first;
2525  int part = item.second;
2526  if(part == 0) {
2527  Msg::Error("Partition tag cannot be 0");
2528  return 1;
2529  }
2530  if(part > 0) elmToPartition[el] = part;
2531  else elmGhosts.push_back(std::make_pair(el, -part));
2532  numPart = std::max(std::abs(part), numPart);
2533  }
2534 
2535  graph.createDualGraph(false);
2536  graph.nparts(numPart);
2537 
2538  if(elmToPartition.size() != graph.ne()) {
2539  Msg::Error("All elements are not partitioned");
2540  return 1;
2541  }
2542 
2543  std::vector<idx_t> part(graph.ne());
2544  for(std::size_t i = 0; i < graph.ne(); i++) {
2545  if(graph.element(i)) { part[i] = elmToPartition[graph.element(i)] - 1; }
2546  }
2547 
2548  // Check and correct the topology
2549  for(int i = 1; i < 4; i++) {
2550  for(std::size_t j = 0; j < graph.ne(); j++) {
2551  if(graph.element(j)->getDim() == graph.dim()) continue;
2552 
2553  for(idx_t k = graph.xadj(j); k < graph.xadj(j + 1); k++) {
2554  if(graph.element(j)->getDim() ==
2555  graph.element(graph.adjncy(k))->getDim() - i) {
2556  if(part[j] != part[graph.adjncy(k)]) {
2557  part[j] = part[graph.adjncy(k)];
2558  break;
2559  }
2560  }
2561  }
2562  }
2563  }
2564  graph.partition(part);
2565 
2566  model->setNumPartitions(graph.nparts());
2567 
2568  createNewEntities(model, elmToPartition);
2569 
2570  if(CTX::instance()->mesh.partitionCreateTopology) {
2571  Msg::StatusBar(true, "Creating partition topology...");
2572  std::vector<std::set<MElement *, MElementPtrLessThan> > boundaryElements =
2573  graph.getBoundaryElements();
2574  createPartitionTopology(model, boundaryElements, graph);
2575  boundaryElements.clear();
2576  Msg::StatusBar(true, "Done creating partition topology");
2577  }
2578 
2579  assignPhysicals(model);
2580  assignMeshVertices(model);
2581 
2582  if (!elmGhosts.empty()) {
2583  std::sort(elmGhosts.begin(), elmGhosts.end());
2584  auto last = std::unique(elmGhosts.begin(), elmGhosts.end());
2585  elmGhosts.erase(last, elmGhosts.end());
2586  std::vector<GEntity *> ghostEntities = graph.createGhostEntities();
2587  for (auto elmGhost : elmGhosts) {
2588  MElement *el = elmGhost.first;
2589  int part = elmGhost.second;
2590  if(el->getDim() == graph.dim()) {
2591  switch(graph.dim()) {
2592  case 1:
2593  static_cast<ghostEdge *>(ghostEntities[part - 1])
2594  ->addElement(el->getType(), el, elmToPartition[el]);
2595  break;
2596  case 2:
2597  static_cast<ghostFace *>(ghostEntities[part - 1])
2598  ->addElement(el->getType(), el, elmToPartition[el]);
2599  break;
2600  case 3:
2601  static_cast<ghostRegion *>(ghostEntities[part - 1])
2602  ->addElement(el->getType(), el, elmToPartition[el]);
2603  break;
2604  default: break;
2605  }
2606  }
2607  }
2608  }
2610  graph.clearDualGraph();
2611  graph.createDualGraph(true);
2612  graph.assignGhostCells();
2613  }
2614  elmToPartition.clear();
2615 
2616  return 0;
2617 }
2618 
2619 // Import a mesh partitionned by a tag given to the element and create the
2620 // topology (omega, sigma, bndSigma, ...). Returns: 0 = success, 1 = no elements
2621 // found.
2623 {
2624  Msg::StatusBar(true, "Converting old partitioning...");
2625 
2626  std::vector<std::pair<MElement *, int> > elmToPartition;
2627  std::set<int> partitions;
2628  std::vector<GEntity *> entities;
2629  model->getEntities(entities);
2630  for(std::size_t i = 0; i < entities.size(); i++) {
2631  for(std::size_t j = 0; j < entities[i]->getNumMeshElements(); j++) {
2632  MElement *e = entities[i]->getMeshElement(j);
2633  idx_t part = e->getPartition();
2634  if(part < 0) part = -part;
2635  if(!part) part = 1;
2636  elmToPartition.push_back(std::make_pair(e, part));
2637  partitions.insert(part);
2638  }
2639  }
2640 
2641  return PartitionUsingThisSplit(model, elmToPartition);
2642 }
2643 
2644 #else
2645 
2646 int PartitionMesh(GModel *model, int numPart)
2647 {
2648  Msg::Error("Gmsh must be compiled with METIS support to partition meshes");
2649  return 0;
2650 }
2651 
2652 int UnpartitionMesh(GModel *model) { return 0; }
2653 
2654 int ConvertOldPartitioningToNewOne(GModel *model) { return 0; }
2655 
2657  GModel *model, std::vector<std::pair<MElement *, int> > &elmToPartition)
2658 {
2659  Msg::Error("Gmsh must be compiled with METIS support to partition meshes");
2660  return 0;
2661 }
2662 
2663 int PartitionFaceMinEdgeLength(GFace *gf, int np, double tol)
2664 {
2665  Msg::Error("Gmsh must be compiled with METIS support to partition meshes");
2666  return 0;
2667 }
2668 
2669 #endif
GVertex::addEdge
void addEdge(GEdge *e)
Definition: GVertex.cpp:37
MTriangle.h
TimeOfDay
double TimeOfDay()
Definition: OS.cpp:399
MTrihedron.h
GModel::firstEdge
eiter firstEdge()
Definition: GModel.h:356
partitionEdge
Definition: partitionEdge.h:12
GEntity::GhostCurve
@ GhostCurve
Definition: GEntity.h:125
MEdge
Definition: MEdge.h:14
GEdge::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GEdge.cpp:173
GFace::addQuadrangle
void addQuadrangle(MQuadrangle *q)
Definition: GFace.h:440
ElementType::nameOfParentType
std::string nameOfParentType(int type, bool plural=false)
Definition: ElementType.cpp:882
GModel::getMaxElementaryNumber
int getMaxElementaryNumber(int dim)
Definition: GModel.cpp:817
ghostRegion
Definition: ghostRegion.h:18
hashmapelement
#define hashmapelement
Definition: meshPartition.cpp:41
GModel::getNumMeshVertices
std::size_t getNumMeshVertices(int dim=-1) const
Definition: GModel.cpp:1529
ghostFace
Definition: ghostFace.h:17
hashmapface
#define hashmapface
Definition: meshPartition.cpp:45
TYPE_LIN
#define TYPE_LIN
Definition: GmshDefines.h:65
GModel::getFaces
std::set< GFace *, GEntityPtrLessThan > getFaces() const
Definition: GModel.h:376
GFace
Definition: GFace.h:33
MLine3
Definition: MLine.h:128
GFace::triangles
std::vector< MTriangle * > triangles
Definition: GFace.h:428
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
GEdge::lines
std::vector< MLine * > lines
Definition: GEdge.h:42
ghostFace.h
OS.h
MElement::getFaceVertices
virtual void getFaceVertices(const int num, std::vector< MVertex * > &v) const
Definition: MElement.h:225
contextMeshOptions::partitionQuaWeight
int partitionQuaWeight
Definition: Context.h:74
TYPE_MAX_NUM
#define TYPE_MAX_NUM
Definition: GmshDefines.h:77
MVertex
Definition: MVertex.h:24
MElement::getDim
virtual int getDim() const =0
GEntity::getParentEntity
virtual GEntity * getParentEntity()
Definition: GEntity.h:199
GModel::remove
bool remove(GRegion *r)
Definition: GModel.cpp:435
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
GEdge::setEndVertex
void setEndVertex(GVertex *gv)
Definition: GEdge.h:62
GEntity::physicals
std::vector< int > physicals
Definition: GEntity.h:65
LegendrePolynomials::f
void f(int n, double u, double *val)
Definition: orthogonalBasis.cpp:77
GRegion::set
void set(std::vector< GFace * > const &f)
Definition: GRegion.h:67
contextMeshOptions::partitionPyrWeight
int partitionPyrWeight
Definition: Context.h:76
GModel::getRegions
std::set< GRegion *, GEntityPtrLessThan > getRegions() const
Definition: GModel.h:372
GVertex::addElement
void addElement(int type, MElement *e)
Definition: GVertex.cpp:196
element::getEdge
virtual void getEdge(int num, int &start, int &end)=0
TYPE_TRI
#define TYPE_TRI
Definition: GmshDefines.h:66
partitionEdge::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionEdge.h:36
GModel::getInnerPhysicalNamesIterators
void getInnerPhysicalNamesIterators(std::vector< piter > &iterators)
Definition: GModel.cpp:929
GVertex::edges
virtual std::vector< GEdge * > const & edges() const
Definition: GVertex.h:54
PartitionUsingThisSplit
int PartitionUsingThisSplit(GModel *model, std::vector< std::pair< MElement *, int > > &elmToPartition)
Definition: meshPartition.cpp:2656
GRegion::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GRegion.cpp:60
partitionFace
Definition: partitionFace.h:12
OriGEntityPtrFullLessThan::operator()
bool operator()(const std::pair< int, GEntity * > &p1, const std::pair< int, GEntity * > &p2) const
Definition: meshPartition.cpp:24
MPoint.h
GModel::firstVertex
viter firstVertex()
Definition: GModel.h:357
hashmapelementpart
#define hashmapelementpart
Definition: meshPartition.cpp:43
partitionRegion::getPartitions
virtual const std::vector< int > & getPartitions() const
Definition: partitionRegion.h:39
GEdge::addLine
void addLine(MLine *line)
Definition: GEdge.h:266
GVertex::addPoint
void addPoint(MPoint *p)
Definition: GVertex.h:122
GModel::getMaxVertexNumber
std::size_t getMaxVertexNumber() const
Definition: GModel.h:222
GEntity::addPhysicalEntity
virtual void addPhysicalEntity(int physicalTag)
Definition: GEntity.h:284
MElement::getEdgeVertices
virtual void getEdgeVertices(const int num, std::vector< MVertex * > &v) const
Definition: MElement.h:221
GFace::addRegion
void addRegion(GRegion *r)
Definition: GFace.h:69
GModel::getMeshDim
int getMeshDim() const
Definition: GModel.cpp:998
GmshMessage.h
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
partitionFace::getPartitions
virtual const std::vector< int > & getPartitions() const
Definition: partitionFace.h:39
UnpartitionMesh
int UnpartitionMesh(GModel *model)
Definition: meshPartition.cpp:2652
GModel::getNumMeshElements
std::size_t getNumMeshElements(int dim=-1) const
Definition: GModel.cpp:1540
w1
const double w1
Definition: GaussQuadratureHex.cpp:18
MEdgeLessThan
Definition: MEdge.h:122
GEntity
Definition: GEntity.h:31
TYPE_PRI
#define TYPE_PRI
Definition: GmshDefines.h:70
GFace::regions
std::list< GRegion * > regions() const
Definition: GFace.h:92
partitionVertex::getPartitions
virtual const std::vector< int > & getPartitions() const
Definition: partitionVertex.h:39
GEntity::PartitionVolume
@ PartitionVolume
Definition: GEntity.h:124
GModel::getNumPartitions
std::size_t getNumPartitions() const
Definition: GModel.h:602
GRegion::setOrientations
void setOrientations(const std::vector< int > &f)
Definition: GRegion.h:68
GModel::setNumPartitions
void setNumPartitions(std::size_t npart)
Definition: GModel.h:603
GEntity::GhostSurface
@ GhostSurface
Definition: GEntity.h:126
GFace::quadrangles
std::vector< MQuadrangle * > quadrangles
Definition: GFace.h:429
contextMeshOptions::partitionCreateGhostCells
int partitionCreateGhostCells
Definition: Context.h:72
GEntity::PartitionCurve
@ PartitionCurve
Definition: GEntity.h:122
GEdge::addFace
void addFace(GFace *f)
Definition: GEdge.cpp:200
partitionFacePtrLessThan
Definition: partitionFace.h:48
MEdgeHash.h
MLine
Definition: MLine.h:21
GVertex::points
std::vector< MPoint * > points
Definition: GVertex.h:120
contextMeshOptions::partitionHexWeight
int partitionHexWeight
Definition: Context.h:75
hashmapvertex
#define hashmapvertex
Definition: meshPartition.cpp:53
PartitionFaceMinEdgeLength
int PartitionFaceMinEdgeLength(GFace *gf, int np, double tol)
Definition: meshPartition.cpp:2663
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
GRegion::hexahedra
std::vector< MHexahedron * > hexahedra
Definition: GRegion.h:164
MElement::getEdge
virtual MEdge getEdge(int num) const =0
GModel::lastFace
fiter lastFace()
Definition: GModel.h:359
MFace
Definition: MFace.h:20
MQuadrangleN
Definition: MQuadrangle.h:449
GModel::getVertices
std::set< GVertex *, GEntityPtrLessThan > getVertices() const
Definition: GModel.h:378
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
MElement::getType
virtual int getType() const =0
GVertex::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GVertex.cpp:124
MElementCut.h
MHexahedron.h
GModel::lastVertex
viter lastVertex()
Definition: GModel.h:361
contextMeshOptions::partitionTriWeight
int partitionTriWeight
Definition: Context.h:74
MElement::getNumFaces
virtual int getNumFaces()=0
GVertex
Definition: GVertex.h:23
GModel::getMaxPhysicalNumber
int getMaxPhysicalNumber(int dim)
Definition: GModel.cpp:917
MQuadrangle8
Definition: MQuadrangle.h:203
ElementType::getType
int getType(int parentType, int order, bool serendip=false)
Definition: ElementType.cpp:757
partitionRegion.h
MElement::getFace
virtual MFace getFace(int num) const =0
GModel
Definition: GModel.h:44
GVertex::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GVertex.h:104
Cpu
double Cpu()
Definition: OS.cpp:366
GFace::addElement
void addElement(int type, MElement *e)
Definition: GFace.cpp:2739
setorientity
std::set< std::pair< int, GEntity * >, OriGEntityPtrFullLessThan > setorientity
Definition: meshPartition.cpp:35
MLineN
Definition: MLine.h:207
partitionRegion
Definition: partitionRegion.h:12
contextMeshOptions::partitionOldStyleMsh2
int partitionOldStyleMsh2
Definition: Context.h:77
MPyramid.h
MTriangleN
Definition: MTriangle.h:315
GEntity::geomType
virtual GeomType geomType() const
Definition: GEntity.h:238
GModel::firstFace
fiter firstFace()
Definition: GModel.h:355
GRegion::trihedra
std::vector< MTrihedron * > trihedra
Definition: GRegion.h:167
partitionRegion::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionRegion.h:34
hashmapedge
#define hashmapedge
Definition: meshPartition.cpp:49
GModel::add
bool add(GRegion *r)
Definition: GModel.h:394
CTX::mesh
contextMeshOptions mesh
Definition: Context.h:313
contextMeshOptions::partitionLinWeight
int partitionLinWeight
Definition: Context.h:75
MElement
Definition: MElement.h:30
partitionEdgePtrLessThan
Definition: partitionEdge.h:50
GEntity::GhostVolume
@ GhostVolume
Definition: GEntity.h:127
ConvertOldPartitioningToNewOne
int ConvertOldPartitioningToNewOne(GModel *model)
Definition: meshPartition.cpp:2654
partitionFace.h
partitionEdge.h
GVertex::geomType
virtual GeomType geomType() const
Definition: GVertex.h:72
partitionEdge::getPartitions
virtual const std::vector< int > & getPartitions() const
Definition: partitionEdge.h:41
GModel::getEntities
void getEntities(std::vector< GEntity * > &entities, int dim=-1) const
Definition: GModel.cpp:651
element
Definition: shapeFunctions.h:12
GRegion
Definition: GRegion.h:28
GModel::getEdges
std::set< GEdge *, GEntityPtrLessThan > getEdges() const
Definition: GModel.h:377
partitionEdge::setParentEntity
virtual void setParentEntity(GEntity *e)
Definition: partitionEdge.h:35
GRegion::prisms
std::vector< MPrism * > prisms
Definition: GRegion.h:165
GEdge::faces
virtual std::vector< GFace * > faces() const
Definition: GEdge.h:113
GFace::getMeshElement
MElement * getMeshElement(std::size_t index) const
Definition: GFace.cpp:234
MTriangle
Definition: MTriangle.h:26
partitionRegion::setParentEntity
virtual void setParentEntity(GEntity *r)
Definition: partitionRegion.h:33
TYPE_PYR
#define TYPE_PYR
Definition: GmshDefines.h:69
GRegion::pyramids
std::vector< MPyramid * > pyramids
Definition: GRegion.h:166
MElement::getVertices
void getVertices(std::vector< MVertex * > &verts)
Definition: MElement.h:103
GModel::firstRegion
riter firstRegion()
Definition: GModel.h:354
MFaceHash.h
GEntity::PartitionSurface
@ PartitionSurface
Definition: GEntity.h:123
TYPE_QUA
#define TYPE_QUA
Definition: GmshDefines.h:67
GModel::lastRegion
riter lastRegion()
Definition: GModel.h:358
GRegion::addElement
void addElement(int type, MElement *e)
Definition: GRegion.cpp:613
Context.h
MTetrahedron.h
MTriangle6
Definition: MTriangle.h:191
partitionVertex::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionVertex.h:34
MQuadrangle.h
MPoint
Definition: MPoint.h:16
GModel::removePhysicalGroup
void removePhysicalGroup(int dim, int num)
Definition: GModel.cpp:901
partitionVertexPtrLessThan
Definition: partitionVertex.h:48
contextMeshOptions::metisMaxLoadImbalance
double metisMaxLoadImbalance
Definition: Context.h:80
GEdge
Definition: GEdge.h:26
TYPE_HEX
#define TYPE_HEX
Definition: GmshDefines.h:71
MPrism.h
GEntity::getPhysicalEntities
virtual std::vector< int > getPhysicalEntities()
Definition: GEntity.h:288
GModel::setPhysicalName
int setPhysicalName(const std::string &name, int dim, int num=0)
Definition: GModel.cpp:937
TYPE_TET
#define TYPE_TET
Definition: GmshDefines.h:68
OriGEntityPtrFullLessThan
Definition: meshPartition.cpp:23
PartitionMesh
int PartitionMesh(GModel *model, int numPart)
Definition: meshPartition.cpp:2646
partitionFace::setParentEntity
virtual void setParentEntity(GEntity *f)
Definition: partitionFace.h:33
GEdge::setBeginVertex
void setBeginVertex(GVertex *gv)
Definition: GEdge.h:61
MQuadrangle9
Definition: MQuadrangle.h:325
partitionVertex
Definition: partitionVertex.h:12
MEdgeEqual
Definition: MEdge.h:118
GEntity::PartitionPoint
@ PartitionPoint
Definition: GEntity.h:121
GModel::lastEdge
eiter lastEdge()
Definition: GModel.h:360
GModel.h
MFace::getNumVertices
std::size_t getNumVertices() const
Definition: MFace.h:29
ghostEdge.h
GEdge::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GEdge.h:201
ElementType::getNumVertices
int getNumVertices(int type)
Definition: ElementType.cpp:456
partitionFace::getParentEntity
virtual GEntity * getParentEntity()
Definition: partitionFace.h:34
ElementType.h
GEdge::addElement
void addElement(int type, MElement *e)
Definition: GEdge.cpp:775
GFace::getNumMeshElements
std::size_t getNumMeshElements() const
Definition: GFace.cpp:181
MElement::getPartition
virtual int getPartition() const
Definition: MElement.h:92
MEdge::getNumVertices
std::size_t getNumVertices() const
Definition: MEdge.h:38
contextMeshOptions::metisAlgorithm
int metisAlgorithm
Definition: Context.h:78
GEntity::dim
virtual int dim() const
Definition: GEntity.h:196
partitionVertex.h
ghostEdge
Definition: ghostEdge.h:15
ghostRegion.h
MElement::getNumEdges
virtual int getNumEdges() const =0
hashmapentity
#define hashmapentity
Definition: meshPartition.cpp:38
GFace::setOrientations
void setOrientations(const std::vector< int > &f)
Definition: GFace.h:129
contextMeshOptions::partitionPriWeight
int partitionPriWeight
Definition: Context.h:76
contextMeshOptions::partitionCreateTopology
int partitionCreateTopology
Definition: Context.h:72
contextMeshOptions::partitionTetWeight
int partitionTetWeight
Definition: Context.h:75
MQuadrangle
Definition: MQuadrangle.h:26
GRegion::tetrahedra
std::vector< MTetrahedron * > tetrahedra
Definition: GRegion.h:163
GFace::set
void set(const std::vector< GEdge * > &f)
Definition: GFace.h:125
partitionVertex::setParentEntity
virtual void setParentEntity(GEntity *v)
Definition: partitionVertex.h:33
GEntity::addMeshVertex
void addMeshVertex(MVertex *v)
Definition: GEntity.h:382
GFace::addTriangle
void addTriangle(MTriangle *t)
Definition: GFace.h:436
faces
static int faces[4][3]
Definition: meshGRegionDelaunayInsertion.cpp:165