Finite Element Domain Decomposition Library
FEDDLib
Loading...
Searching...
No Matches
MeshPartitioner_def.hpp
1#ifndef MeshPartitioner_def_hpp
2#define MeshPartitioner_def_hpp
3
12
13namespace FEDD {
14template <class SC, class LO, class GO, class NO>
15MeshPartitioner<SC,LO,GO,NO>::MeshPartitioner()
16{
17
18}
19
20template <class SC, class LO, class GO, class NO>
21MeshPartitioner<SC,LO,GO,NO>::MeshPartitioner( DomainPtrArray_Type domains, ParameterListPtr_Type pL, std::string feType, int dimension )
22{
23 domains_ = domains;
24 pList_ = pL;
25 feType_ = feType;
26 comm_ = domains_[0]->getComm();
27 rankRanges_.resize( domains_.size() );
28 dim_ = dimension;
29}
30
31template <class SC, class LO, class GO, class NO>
32MeshPartitioner<SC,LO,GO,NO>::~MeshPartitioner(){
33
34}
35
36
37
38template <class SC, class LO, class GO, class NO>
39void MeshPartitioner<SC,LO,GO,NO>::readAndPartition( int volumeID, std::string meshUnit, bool convertToCM)
40{
41 if(volumeID != 10 ){
42 if(this->comm_->getRank()==0){
43 std::cout << " #### WARNING: The volumeID was set manually and is no longer 10. Please make sure your volumeID corresponds to the volumeID in your mesh file. #### " << std::endl;
44 }
45 }
46 //Read
47 std::string delimiter = pList_->get( "Delimiter", " " );
48 for (int i=0; i<domains_.size(); i++) {
49 std::string meshName = pList_->get( "Mesh " + std::to_string(i+1) + " Name", "noName" );
50 TEUCHOS_TEST_FOR_EXCEPTION( meshName == "noName", std::runtime_error, "No mesh name given.");
51 domains_[i]->initializeUnstructuredMesh( domains_[i]->getDimension(), "P1",volumeID, meshUnit, convertToCM ); //we only allow to read P1 meshes.
52 domains_[i]->readMeshSize( meshName, delimiter );
53 }
54
55 this->determineRanks();
56
57 for (int i=0; i<domains_.size(); i++){
58 this->readAndPartitionMesh( i );
59 domains_[i]->getMesh()->rankRange_ = rankRanges_[i];
60 }
61
62}
63template <class SC, class LO, class GO, class NO>
64void MeshPartitioner<SC,LO,GO,NO>::determineRanks(){
65 bool verbose ( comm_->getRank() == 0 );
66 vec_int_Type fractions( domains_.size(), 0 );
67 bool autoPartition = pList_->get( "Automatic partition", false );
68 if ( autoPartition ) {
69 //determine sum of elements and fractions based of domain contributions
70 GO sumElements = 0;
71 for (int i=0; i<domains_.size(); i++)
72 sumElements += domains_[i]->getNumElementsGlobal();
73
74 for (int i=0; i<fractions.size(); i++)
75 fractions[i] = (domains_[i]->getNumElementsGlobal()*100) / sumElements;
76
77 int diff = std::accumulate(fractions.begin(), fractions.end(), 0) - 100;
78 auto iterator = fractions.begin();
79 while (diff>0) {
80 (*iterator)--;
81 iterator++;
82 diff--;
83 }
84 iterator = fractions.begin();
85 while (diff<0) {
86 (*iterator)++;
87 iterator++;
88 diff++;
89 }
90
91 this->determineRanksFromFractions( fractions );
92
93 if (verbose) {
94 std::cout << "\t --- ---------------- ---" << std::endl;
95 std::cout << "\t --- Mesh Partitioner ---" << std::endl;
96 std::cout << "\t --- ---------------- ---" << std::endl;
97 std::cout << "\t --- Automatic partition for "<< comm_->getSize() <<" ranks" << std::endl;
98 for (int i=0; i<domains_.size(); i++) {
99 std::cout << "\t --- Fraction mesh "<<std::to_string(i+1) << " : " << fractions[i] <<
100 " of 100; rank range: " << std::get<0>( rankRanges_[i] )<< " to "<< std::get<1>( rankRanges_[i] ) << std::endl;
101 }
102 }
103
104 }
105 else if( autoPartition == false && pList_->get("Mesh 1 fraction ranks",-1) >= 0 ){
106 for (int i=0; fractions.size(); i++)
107 fractions[i] = pList_->get("Mesh " + std::to_string(i+1) + " fraction ranks", -1);
108
109 TEUCHOS_TEST_FOR_EXCEPTION( std::accumulate(fractions.begin(), fractions.end(), 0) != 100, std::runtime_error, "Fractions do not sum up to 100!");
110 this->determineRanksFromFractions( fractions );
111
112 if (verbose) {
113 std::cout << "\t --- ---------------- ---" << std::endl;
114 std::cout << "\t --- Mesh Partitioner ---" << std::endl;
115 std::cout << "\t --- ---------------- ---" << std::endl;
116 std::cout << "\t --- Fraction partition for "<< comm_->getSize() <<" ranks" << std::endl;
117 for (int i=0; i<domains_.size(); i++) {
118 std::cout << "\t --- Fraction mesh "<<std::to_string(i+1) << " : " << fractions[i] <<
119 " of 100; rank range: " << std::get<0>( rankRanges_[i] )<< " to "<< std::get<1>( rankRanges_[i] ) << std::endl;
120 }
121 }
122 }
123 else if( autoPartition == false && pList_->get("Mesh 1 fraction ranks",-1) < 0 && pList_->get("Mesh 1 number ranks",-1) > 0 ){
124 int size = comm_->getSize();
125 vec_int_Type numberRanks(domains_.size());
126 for (int i=0; i<numberRanks.size(); i++)
127 numberRanks[i] = pList_->get("Mesh " + std::to_string(i+1) + " number ranks",0);
128
129 TEUCHOS_TEST_FOR_EXCEPTION( std::accumulate(numberRanks.begin(), numberRanks.end(), 0) > size, std::runtime_error, "Too many ranks requested for mesh partition!");
130 this->determineRanksFromNumberRanks( numberRanks );
131 if (verbose) {
132 std::cout << "\t --- ---------------- ---" << std::endl;
133 std::cout << "\t --- Mesh Partitioner ---" << std::endl;
134 std::cout << "\t --- ---------------- ---" << std::endl;
135 std::cout << "\t --- Rank number partition for "<< comm_->getSize() <<" ranks" << std::endl;
136 for (int i=0; i<domains_.size(); i++) {
137 std::cout << "\t --- Rank range mesh "<<std::to_string(i+1) << " :" << std::get<0>( rankRanges_[i] )<< " to "<< std::get<1>( rankRanges_[i] ) << std::endl;
138 }
139 }
140
141 }
142 else{
143 for (int i=0; i<domains_.size(); i++)
144 rankRanges_[i] = std::make_tuple( 0, comm_->getSize()-1 );
145 if (verbose) {
146 std::cout << "\t --- ---------------- ---" << std::endl;
147 std::cout << "\t --- Mesh Partitioner ---" << std::endl;
148 std::cout << "\t --- ---------------- ---" << std::endl;
149 std::cout << "\t --- Every mesh on every rank" << std::endl;
150 }
151 }
152}
153
154template <class SC, class LO, class GO, class NO>
155void MeshPartitioner<SC,LO,GO,NO>::determineRanksFromFractions( vec_int_Type& fractions ){
156
157 int lowerRank = 0; int size = comm_->getSize();
158 int upperRank = 0;
159 for (int i=0; i<fractions.size(); i++){
160 upperRank = lowerRank + fractions[i] / 100. * size - 1;
161 if (upperRank<lowerRank)
162 upperRank++;
163 rankRanges_[i] = std::make_tuple( lowerRank, upperRank );
164 if (size>1)
165 lowerRank = upperRank + 1;
166 else
167 lowerRank = upperRank;
168 }
169 int startLoc = 0;
170 while ( upperRank > size-1 ) {
171 for (int i=startLoc; i<rankRanges_.size(); i++){
172 if (i>0)
173 std::get<0>( rankRanges_[i] )--;
174 std::get<1>( rankRanges_[i] )--;
175 }
176 startLoc++;
177 upperRank--;
178 }
179 startLoc = 0;
180 while ( upperRank < size-1 ) {
181 for (int i=startLoc; i<rankRanges_.size(); i++){
182 if (i>0)
183 std::get<0>( rankRanges_[i] )++;
184 std::get<1>( rankRanges_[i] )++;
185 }
186 startLoc++;
187 upperRank++;
188 }
189}
190
191template <class SC, class LO, class GO, class NO>
192void MeshPartitioner<SC,LO,GO,NO>::determineRanksFromNumberRanks( vec_int_Type& numberRanks ){
193
194 int lowerRank = 0; int size = comm_->getSize();
195 int upperRank = 0;
196 for (int i=0; i<numberRanks.size(); i++){
197 upperRank = lowerRank + numberRanks[i] - 1;
198 rankRanges_[i] = std::make_tuple( lowerRank, upperRank );
199 lowerRank = upperRank + 1;
200 }
201
202 int startLoc = 0;
203 while ( upperRank > size-1 ) {
204 for (int i=startLoc; i<rankRanges_.size(); i++){
205 if (i>0)
206 std::get<0>( rankRanges_[i] )--;
207 std::get<1>( rankRanges_[i] )--;
208 }
209 startLoc++;
210 upperRank--;
211 }
212 startLoc = 0;
213 while ( upperRank < size-1 ) {
214 for (int i=startLoc; i<rankRanges_.size(); i++){
215 if (i>0)
216 std::get<0>( rankRanges_[i] )++;
217 std::get<1>( rankRanges_[i] )++;
218 }
219 startLoc++;
220 upperRank++;
221 }
222
223}
224
226
227template <class SC, class LO, class GO, class NO>
228void MeshPartitioner<SC,LO,GO,NO>::readAndPartitionMesh( int meshNumber ){
229
230 typedef Teuchos::OrdinalTraits<GO> OTGO;
231
232 MeshUnstrPtr_Type meshUnstr = Teuchos::rcp_dynamic_cast<MeshUnstr_Type>( domains_[meshNumber]->getMesh() );
233
234 // Reading nodes
235 meshUnstr->readMeshEntity("node");
236 // We delete the point at this point. We only need the flags to determine surface elements. We will load them again later.
237 meshUnstr->pointsRep_.reset();
238 // Reading elements
239 meshUnstr->readMeshEntity("element");
240 // Reading surfaces
241 meshUnstr->readMeshEntity("surface");
242 // Reading line segments
243 meshUnstr->readMeshEntity("line");
244
245
246
247 bool verbose ( comm_->getRank() == 0 );
248 bool buildEdges = pList_->get("Build Edge List", true);
249 bool buildSurfaces = pList_->get("Build Surface List", true);
250
251 // Adding surface as subelement to elements
252 if (buildSurfaces)
253 this->setSurfacesToElements( meshNumber );
254 else
255 meshUnstr->deleteSurfaceElements();
256
257 // Serially distributed elements
258 ElementsPtr_Type elementsMesh = meshUnstr->getElementsC();
259
260 // Setup Metis
261 idx_t options[METIS_NOPTIONS];
262 METIS_SetDefaultOptions(options);
263
264 // METIS DOKU: https://www.lrz.de/services/software/mathematik/metis/metis_5_0.pdf
265
266 /*
267 options[METIS_OPTION_NUMBERING]
268 Used to indicate which numbering scheme is used for the adjacency structure of a graph or the element-
269 node structure of a mesh. The possible values are:
270 0 C-style numbering is assumed that starts from 0.
271 1 Fortran-style numbering is assumed that starts from 1.
272 */
273 options[METIS_OPTION_NUMBERING] = 0;
274
275 /*
276 options[METIS_OPTION_SEED]
277 Specifies the seed for the random number generator.
278 */
279 options[METIS_OPTION_SEED] = 666;
280
281 /*
282 ptions[METIS_OPTION_CONTIG]
283 Specifies that the partitioning routines should try to produce partitions that are contiguous. Note that if the
284 input graph is not connected this option is ignored.
285 */
286 options[METIS_OPTION_CONTIG] = pList_->get("Contiguous",false); //0: Does not force contiguous partitions; 1: Forces contiguous partitions.
287
288 /*
289 options[METIS_OPTION_NCUTS]
290 Specifies the number of different partitionings that it will compute. The final partitioning is the one that
291 achieves the best edgecut or communication volume. Default is 1.
292 */
293 options[METIS_OPTION_NCUTS] = pList_->get("NCUTS",1);
294
295 /*
296 options[METIS_OPTION_MINCONN]
297 Specifies that the partitioning routines should try to minimize the maximum degree of the subdomain graph,
298 i.e., the graph in which each partition is a node, and edges connect subdomains with a shared interface.
299 */
300 options[METIS_OPTION_MINCONN] = pList_->get("MINCONN",1); //0; // 1: Explicitly minimize the maximum connectivity.
301
302 /*
303 options[METIS_OPTION_OBJTYPE]: Specifies the type of objective. Possible values are:
304 METIS_OBJTYPE_CUT Edge-cut minimization.
305 METIS_OBJTYPE_VOL Total communication volume minimization.
306 */
307 idx_t objtype = METIS_OBJTYPE_CUT;
308 if( pList_->get("OBJTYPE","METIS_OBJTYPE_CUT") == "METIS_OBJTYPE_CUT")
309 objtype =METIS_OBJTYPE_CUT;
310 else if(pList_->get("OBJTYPE","METIS_OBJTYPE_CUT") == "METIS_OBJTYPE_VOL")
311 objtype = METIS_OBJTYPE_VOL;
312 options[METIS_OPTION_OBJTYPE] =objtype; // METIS_OBJTYPE_CUT;// or METIS_OBJTYPE_VOL
313
314 /*
315 options[METIS_OPTION_RTYPE]
316 Determines the algorithm used for refinement. Possible values are:
317 METIS_RTYPE_FM FM-based cut refinement.
318 METIS_RTYPE_GREEDY Greedy-based cut and volume refinement.
319 METIS_RTYPE_SEP2SIDED Two-sided node FM refinement.
320 METIS_RTYPE_SEP1SIDED One-sided node FM refinement.
321 */
322 idx_t rtype = METIS_RTYPE_FM;
323 if(pList_->get("RTYPE","METIS_RTYPE_FM")=="METIS_RTYPE_FM")
324 rtype = METIS_RTYPE_FM;
325 else if(pList_->get("RTYPE","METIS_RTYPE_FM")== "METIS_RTYPE_GREEDY")
326 rtype = METIS_RTYPE_GREEDY;
327 else if(pList_->get("RTYPE","METIS_RTYPE_FM") == "METIS_RTYPE_SEP2SIDED")
328 rtype = METIS_RTYPE_SEP2SIDED;
329 else if(pList_->get("RTYPE","METIS_RTYPE_FM") == "METIS_RTYPE_SEP1SIDED")
330 rtype = METIS_RTYPE_SEP1SIDED;
331
332 options[METIS_OPTION_RTYPE] = rtype; //pList_->get("RTYPE","METIS_RTYPE_FM"); // METIS_RTYPE_GREEDY;
333
334 /*
335 options[METIS_OPTION_NITER]
336 Specifies the number of iterations for the refinement algorithms at each stage of the uncoarsening process.
337 Default is 10.
338 */
339 options[METIS_OPTION_NITER] = pList_->get("NITER",50); // 50; // default is 10
340
341 /*
342 options[METIS_OPTION_CCORDER]
343 Specifies if the connected components of the graph should first be identified and ordered separately.
344 */
345 options[METIS_OPTION_CCORDER] = pList_->get("CCORDER",1);
346
347 /*options[METIS OPTION DBGLVL]
348 Specifies the amount of progress/debugging information will be printed during the execution of the algo-
349 rithms. The default value is 0 (no debugging/progress information). A non-zero value can be supplied that
350 is obtained by a bit-wise OR of the following values
351 */
352 options[METIS_OPTION_DBGLVL] = pList_->get("DBGLVL",0);
353
354 idx_t ne = meshUnstr->getNumElementsGlobal(); // Global number of elements
355 idx_t nn = meshUnstr->getNumGlobalNodes(); // Global number of nodes
356 idx_t ned = meshUnstr->getEdgeElements()->numberElements(); // Global number of edges
357
358
359 int dim = meshUnstr->getDimension();
360 std::string FEType = domains_[meshNumber]->getFEType();
361
362 // Setup for paritioning with metis
363 vec_idx_Type eptr_vec(0); // Vector for local elements ptr (local is still global at this point)
364 vec_idx_Type eind_vec(0); // Vector for local elements ids
365
366 makeContinuousElements(elementsMesh, eind_vec, eptr_vec);
367
368 idx_t *eptr = &eptr_vec.at(0);
369 idx_t *eind = &eind_vec.at(0);
370
371 idx_t ncommon;
372 int orderSurface;
373 if (dim==2) {
374 if (FEType=="P1") {
375 ncommon = 2;
376 }
377 else if(FEType=="P2"){
378 ncommon = 3;
379 }
380 }
381 else if (dim==3) {
382 if (FEType=="P1") {
383 ncommon = 3;
384 }
385 else if(FEType=="P2"){
386 ncommon = 6;
387 }
388 }
389 else
390 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Wrong Dimension.");
391
392 idx_t objval = 0;
393 vec_idx_Type epart(ne,-1);
394 vec_idx_Type npart(nn,-1);
395
396 // Partitioning elements with metis
397 if (verbose)
398 std::cout << "-- Start partitioning with Metis ... " << std::flush;
399
400 {
401 FEDD_TIMER_START(partitionTimer," : MeshPartitioner : Partition Elements");
402 idx_t nparts = std::get<1>( rankRanges_[meshNumber] ) - std::get<0>( rankRanges_[meshNumber] ) + 1;
403 if ( nparts > 1 ) {
404 int rank = this->comm_->getRank();
405 // upperRange - lowerRange +1
406 idx_t returnCode = METIS_PartMeshDual(&ne, &nn, eptr, eind, NULL, NULL, &ncommon, &nparts, NULL, options, &objval, &epart[0], &npart[0]);
407 if ( verbose )
408 std::cout << "\n--\t Metis return code: " << returnCode;
409 }
410 else{
411 for (int i=0; i<ne; i++)
412 epart[i] = 0;
413 }
414 }
415
416 if (verbose){
417 std::cout << "\n--\t objval: " << objval << std::endl;
418 std::cout << "-- done!" << std::endl;
419 }
420
421 if (verbose)
422 std::cout << "-- Set Elements ... " << std::flush;
423
424 vec_GO_Type locepart(0);
425 vec_GO_Type pointsRepIndices(0);
426 // Global Edge IDs of local elements
427 vec_GO_Type locedpart(0);
428
429 // Getting global IDs of element's nodes
430 for (int i=0; i<ne; i++) {
431 if (epart[i] == comm_->getRank() - std::get<0>( rankRanges_[meshNumber] ) ){
432 locepart.push_back(i);
433 for (int j=eptr[i]; j<eptr[i+1]; j++)
434 pointsRepIndices.push_back( eind[j] ); // Ids of element nodes, globalIDs
435 }
436 }
437 // TODO KHo why erase the vectors here? eind points to the underlying array and is used later.
438 eind_vec.erase(eind_vec.begin(), eind_vec.end());
439 eptr_vec.erase(eptr_vec.begin(), eptr_vec.end());
440
441 // Sorting ids with global and corresponding local values to create repeated map
442 make_unique(pointsRepIndices);
443 if (verbose)
444 std::cout << "done!" << std::endl;
445
446 // Building repeated node map
447 Teuchos::ArrayView<GO> pointsRepGlobMapping = Teuchos::arrayViewFromVector( pointsRepIndices );
448 meshUnstr->mapRepeated_.reset( new Map<LO,GO,NO>(OTGO::invalid(), pointsRepGlobMapping, 0, this->comm_) );
449 MapConstPtr_Type mapRepeated = meshUnstr->mapRepeated_;
450
451 // We keep the global elements if we want to build edges later. Otherwise they will be deleted
452 ElementsPtr_Type elementsGlobal = Teuchos::rcp( new Elements_Type( *elementsMesh ) );
453
454 // Resetting elements to add the corresponding local IDs instead of global ones
455 meshUnstr->elementsC_.reset(new Elements ( FEType, dim ) );
456 {
457 Teuchos::ArrayView<GO> elementsGlobalMapping = Teuchos::arrayViewFromVector( locepart );
458 // elementsGlobalMapping -> elements per Processor
459
460 meshUnstr->elementMap_.reset(new Map<LO,GO,NO>( (GO) -1, elementsGlobalMapping, 0, this->comm_) );
461
462 {
463 int localSurfaceCounter = 0;
464 for (int i=0; i<locepart.size(); i++) {
465 std::vector<int> tmpElement;
466 for (int j=eptr[locepart.at(i)]; j<eptr[locepart.at(i)+1]; j++) {
467 //local indices
468 int index = mapRepeated->getLocalElement( (long long) eind[j] );
469 tmpElement.push_back(index);
470 }
471 //std::sort(tmpElement.begin(), tmpElement.end());
472 FiniteElement fe( tmpElement, elementsGlobal->getElement( locepart.at(i) ).getFlag() );
473 // convert global IDs of (old) globally owned subelements to local IDs
474 if (buildSurfaces) {
475 FiniteElement feGlobalIDs = elementsGlobal->getElement( locepart.at(i) );
476 if (feGlobalIDs.subElementsInitialized()){
477 ElementsPtr_Type subEl = feGlobalIDs.getSubElements();
478 subEl->globalToLocalIDs( mapRepeated );
479 fe.setSubElements( subEl );
480 }
481 }
482 meshUnstr->elementsC_->addElement( fe );
483 }
484 }
485 }
486
487 // Next we distribute the coordinates and flags correctly
488
489
490 meshUnstr->readMeshEntity("node"); // We reread the nodes, as they were deleted earlier
491
492 if (verbose)
493 std::cout << "-- Build Repeated Points Volume ... " << std::flush;
494
495 // building the unique map
496 meshUnstr->mapUnique_ = meshUnstr->mapRepeated_->buildUniqueMap( rankRanges_[meshNumber] );
497
498 // free(epart);
499 if (verbose)
500 std::cout << "-- Building unique & repeated points ... " << std::flush;
501 {
502 vec2D_dbl_Type points = *meshUnstr->getPointsRepeated();
503 vec_int_Type flags = *meshUnstr->getBCFlagRepeated();
504 meshUnstr->pointsRep_.reset( new std::vector<std::vector<double> >( meshUnstr->mapRepeated_->getNodeNumElements(), std::vector<double>(dim,-1.) ) );
505 meshUnstr->bcFlagRep_.reset( new std::vector<int> ( meshUnstr->mapRepeated_->getNodeNumElements(), 0 ) );
506
507 int pointIDcont;
508 for (int i=0; i<pointsRepIndices.size() ; i++) {
509 pointIDcont = pointsRepIndices.at(i);
510 for (int j=0; j<dim; j++)
511 meshUnstr->pointsRep_->at(i).at(j) = points[pointIDcont][j];
512 meshUnstr->bcFlagRep_->at(i) = flags[pointIDcont];
513 }
514 }
515
516 // Setting unique points and flags
517 meshUnstr->pointsUni_.reset(new std::vector<std::vector<double> >( meshUnstr->mapUnique_->getNodeNumElements(), std::vector<double>(dim,-1.) ) );
518 meshUnstr->bcFlagUni_.reset(new std::vector<int> ( meshUnstr->mapUnique_->getNodeNumElements(), 0) );
519 GO indexGlobal;
520 MapConstPtr_Type map = meshUnstr->getMapRepeated();
521 vec2D_dbl_ptr_Type pointsRep = meshUnstr->pointsRep_;
522 for (int i=0; i<meshUnstr->mapUnique_->getNodeNumElements() ; i++) {
523 indexGlobal = meshUnstr->mapUnique_->getGlobalElement(i);
524 for (int j=0; j<dim; j++) {
525 meshUnstr->pointsUni_->at(i).at(j) = pointsRep->at( map->getLocalElement( indexGlobal) ).at(j);
526 }
527 meshUnstr->bcFlagUni_->at(i) = meshUnstr->bcFlagRep_->at( map->getLocalElement( indexGlobal) );
528 }
529
530 // Finally we build the edges. As part of the edge build involves nodes and elements,
531 // they should be build last to avoid any local and global IDs mix up
532 if (!buildEdges)
533 elementsGlobal.reset();
534
535 locepart.erase(locepart.begin(),locepart.end());
536 if (verbose)
537 std::cout << "done!" << std::endl;
538
539 if (buildSurfaces){
540 this->setEdgesToSurfaces( meshNumber ); // Adding edges as subelements in the 3D case. All dim-1-Subelements were already set
541 }
542 else
543 meshUnstr->deleteSurfaceElements();
544
545 if (buildEdges) {
546 if (verbose)
547 std::cout << "-- Build edge element list ... " << std::endl << std::flush;
548
549 buildEdgeListParallel( meshUnstr, elementsGlobal );
550
551 if (verbose)
552 std::cout << std::endl << " done!"<< std::endl;
553
554 MapConstPtr_Type elementMap = meshUnstr->getElementMap();
555
556 FEDD_TIMER_START(partitionEdgesTimer," : MeshPartitioner : Partition Edges");
557 meshUnstr->getEdgeElements()->partitionEdges( elementMap, mapRepeated );
558 FEDD_TIMER_STOP(partitionEdgesTimer);
559
560 // edge global indices on different processors
561 for( int i=0; i<meshUnstr->getEdgeElements()->numberElements() ; i++){
562 locedpart.push_back(meshUnstr->getEdgeElements()->getGlobalID((LO) i));
563 }
564
565 // Setup for the EdgeMap
566 Teuchos::ArrayView<GO> edgesGlobalMapping = Teuchos::arrayViewFromVector( locedpart );
567 meshUnstr->edgeMap_.reset(new Map<LO,GO,NO>( (GO) -1, edgesGlobalMapping, 0, this->comm_) );
568 }
569
570
571 if (verbose)
572 std::cout << "done!" << std::endl;
573
574 if (verbose)
575 std::cout << "-- Partition interface ... " << std::flush;
576 meshUnstr->partitionInterface();
577
578 if (verbose)
579 std::cout << "done!" << std::endl;
580
581}
582
583
586template <class SC, class LO, class GO, class NO>
588 bool verbose ( comm_->getRank() == 0 );
589 MeshUnstrPtr_Type meshUnstr = Teuchos::rcp_dynamic_cast<MeshUnstr_Type>( domains_[meshNumber]->getMesh() );
590 ElementsPtr_Type elementsMesh = meshUnstr->getElementsC();
591 MapConstPtr_Type mapRepeated = meshUnstr->mapRepeated_;
592 if (verbose)
593 std::cout << "-- Set edges of surfaces of elements ... " << std::flush;
594
595 FEDD_TIMER_START(surfacesTimer," : MeshPartitioner : Set Surfaces of Edge Elements");
596 vec2D_int_Type localEdgeIDPermutation;
597 setLocalSurfaceEdgeIndices( localEdgeIDPermutation, meshUnstr->getEdgeElementOrder() );
598
599 int volumeID = meshUnstr->volumeID_;
600
601 ElementsPtr_Type elements = meshUnstr->getElementsC();
602 ElementsPtr_Type edgeElements = meshUnstr->getSurfaceEdgeElements();
603
604 /* First, we convert the surface edge elements to a 2D array so we can use std::find.*/
605 // Can we use/implement find for Elements_Type?
606 vec2D_int_Type edgeElements_vec( edgeElements->numberElements() );
607 vec_int_Type edgeElementsFlag_vec( edgeElements->numberElements() );
608 for (int i=0; i<edgeElements_vec.size(); i++){
609 vec_int_Type edge = edgeElements->getElement(i).getVectorNodeListNonConst();
610 std::sort( edge.begin(), edge.end() );
611 edgeElements_vec.at(i) = edge;
612 edgeElementsFlag_vec.at(i) = edgeElements->getElement(i).getFlag();
613 }
614
615 vec_int_ptr_Type flags = meshUnstr->bcFlagRep_;
616 int elementEdgeSurfaceCounter;
617 for (int i=0; i<elements->numberElements(); i++) {
618 elementEdgeSurfaceCounter = 0;
619 bool mark = false;
620 for (int j=0; j<elements->getElement( i ).size(); j++) {
621 if ( flags->at( elements->getElement( i ).getNode( j ) ) < volumeID )
622 elementEdgeSurfaceCounter++;
623 }
624 if (elementEdgeSurfaceCounter >= meshUnstr->getEdgeElementOrder()){
625 //We want to find all surfaces of element i and set the surfaces to the element
626 findAndSetSurfaceEdges( edgeElements_vec, edgeElementsFlag_vec, elements->getElement(i), localEdgeIDPermutation, mapRepeated );
627 }
628 }
629 if (verbose)
630 std::cout << "done!" << std::endl;
631}
632
635template <class SC, class LO, class GO, class NO>
637
638 bool verbose ( comm_->getRank() == 0 );
639 MeshUnstrPtr_Type meshUnstr = Teuchos::rcp_dynamic_cast<MeshUnstr_Type>( domains_[meshNumber]->getMesh() );
640 ElementsPtr_Type elementsMesh = meshUnstr->getElementsC(); // Previously read Elements
641
642 if (verbose)
643 std::cout << "-- Set surfaces of elements ... " << std::flush;
644
645 FEDD_TIMER_START(surfacesTimer," : MeshPartitioner : Set Surfaces of Elements");
646
647 vec2D_int_Type localSurfaceIDPermutation;
648 // get permutations
649 setLocalSurfaceIndices( localSurfaceIDPermutation, meshUnstr->getSurfaceElementOrder() );
650
651 int volumeID = meshUnstr->volumeID_;
652 ElementsPtr_Type surfaceElements = meshUnstr->getSurfaceElements();
653
654 /* First, we convert the surface Elements to a 2D array so we can use std::find.
655 and partition it at the same time. We use a simple linear partition. This is done to reduce
656 times spend for std::find. The result is then communicated. We therefore use the unpartitoned elements*/
657 // Can we use/implement find for Elements_Type?
658
659 int size = this->comm_->getSize();
660
661 LO numSurfaceEl = surfaceElements->numberElements();// / size;
662 /*LO rest = surfaceElements->numberElements() % size;
663
664 vec_GO_Type offsetVec(size);
665 for (int i=0; i<size; i++) {
666 offsetVec[i] = numSurfaceEl * i;
667 if ( i<rest && i == this->comm_->getRank() ) {
668 numSurfaceEl++;
669 offsetVec[i]+=i;
670 }
671 else
672 offsetVec[i]+=rest;
673 }*/
674
675 vec2D_int_Type surfElements_vec( numSurfaceEl );
676 vec2D_int_Type surfElements_vec_sorted( numSurfaceEl );
677
678 vec_int_Type surfElementsFlag_vec( numSurfaceEl );
679 vec_GO_Type offsetVec(size);
680 int offset = offsetVec[this->comm_->getRank()];
681
682 for (int i=0; i<surfElements_vec.size(); i++){
683 vec_int_Type surface = surfaceElements->getElement(i ).getVectorNodeListNonConst(); // surfaceElements->getElement(i + offset).getVectorNodeListNonConst();
684 surfElements_vec.at(i) = surface;
685 std::sort( surface.begin(), surface.end() ); // We need to maintain a consistent numbering in the surface elements, so we use a sorted and unsorted vector
686 surfElements_vec_sorted.at(i) = surface;
687 surfElementsFlag_vec.at(i) = surfaceElements->getElement(i).getFlag(); // surfaceElements->getElement(i + offset).getFlag();
688
689 }
690
691 // Delete the surface elements. They will be added to the elements in the following loop.
692 surfaceElements.reset();
693 vec_int_ptr_Type flags = meshUnstr->bcFlagRep_;
694
695 int elementSurfaceCounter;
696 int surfaceElOrder = meshUnstr->getSurfaceElementOrder();
697 for (int i=0; i<elementsMesh->numberElements(); i++) {
698 elementSurfaceCounter = 0;
699 for (int j=0; j<elementsMesh->getElement( i ).size(); j++) {
700 if ( flags->at( elementsMesh->getElement( i ).getNode( j ) ) < volumeID )
701 elementSurfaceCounter++;
702 }
703
704 if (elementSurfaceCounter >= surfaceElOrder){
705 FEDD_TIMER_START(findSurfacesTimer," : MeshPartitioner : Find and Set Surfaces");
706 //We want to find all surfaces of element i and set the surfaces to the element
707 this->findAndSetSurfacesPartitioned( surfElements_vec_sorted, surfElements_vec, surfElementsFlag_vec, elementsMesh->getElement(i), localSurfaceIDPermutation, offsetVec, i );
708 }
709 }
710
711 if (verbose)
712 std::cout << "done!" << std::endl;
713}
714
717template <class SC, class LO, class GO, class NO>
718void MeshPartitioner<SC,LO,GO,NO>::findAndSetSurfacesPartitioned( vec2D_int_Type& surfElements_vec, vec2D_int_Type& surfElements_vec_unsorted, vec_int_Type& surfElementsFlag_vec, FiniteElement& element, vec2D_int_Type& permutation , vec_GO_Type& linearSurfacePartitionOffset, int globalElID ){
719
720 // In general we look through the different permutations the input element 'element' can have and if they correspond to a surface.
721 // The mesh's surface elements 'surfElements_vec' are then used to determine the corresponding surface
722 // If found, the nodes are then used to build the subelement and the corresponding surfElementFlag is set.
723 // The Ids are global at this point, as the values are not distributed yet.
724
725 int loc, id1Glob, id2Glob, id3Glob;
726 int size = this->comm_->getSize();
727 vec_int_Type locAll(size);
728 if (dim_ == 2) {
729 for (int j=0; j<permutation.size(); j++) {
730 id1Glob = element.getNode( permutation.at(j).at(0) ) ;
731 id2Glob = element.getNode( permutation.at(j).at(1) ) ;
732
733 vec_int_Type tmpSurface(2);
734 if (id1Glob > id2Glob){
735 tmpSurface[0] = id2Glob;
736 tmpSurface[1] = id1Glob;
737 }
738 else{
739 tmpSurface[0] = id1Glob;
740 tmpSurface[1] = id2Glob;
741 }
742
743 loc = searchInSurfaces( surfElements_vec, tmpSurface );
744
745 Teuchos::gatherAll<int,int>( *this->comm_, 1, &loc, locAll.size(), &locAll[0] );
746
747 int surfaceRank = -1;
748 int counter = 0;
749 while (surfaceRank<0 && counter<size) {
750 if (locAll[counter] > -1)
751 surfaceRank = counter;
752 counter++;
753 }
754 int surfFlag = -1;
755 if (loc>-1)
756 surfFlag = surfElementsFlag_vec[loc];
757
758 if (surfaceRank>-1) {
759 Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&loc);
760 Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&surfFlag);
761
762 FiniteElement feSurface( tmpSurface, surfFlag);
763 if ( !element.subElementsInitialized() )
764 element.initializeSubElements( "P1", 1 ); // only P1 for now
765
766 element.addSubElement( feSurface );
767 }
768 }
769 }
770 else if (dim_ == 3){
771 for (int j=0; j<permutation.size(); j++) {
772
773 id1Glob = element.getNode( permutation.at(j).at(0) ) ;
774 id2Glob = element.getNode( permutation.at(j).at(1) ) ;
775 id3Glob = element.getNode( permutation.at(j).at(2) ) ;
776
777 vec_int_Type tmpSurface = {id1Glob , id2Glob , id3Glob};
778 sort( tmpSurface.begin(), tmpSurface.end() );
779 loc = searchInSurfaces( surfElements_vec, tmpSurface );
780 /*Teuchos::gatherAll<int,int>( *this->comm_, 1, &loc, locAll.size(), &locAll[0] );
781
782 int surfaceRank = -1;
783 int counter = 0;
784 while (surfaceRank<0 && counter<size) {
785 if (locAll[counter] > -1)
786 surfaceRank = counter;
787 counter++;
788 }
789 int surfFlag = -1;
790 if (loc>-1)
791 surfFlag = surfElementsFlag_vec[loc];
792
793 if (surfaceRank>-1) {*/
794 if(loc > -1 ){
795 //Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&loc);
796 //Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&surfFlag);
797
798 int surfFlag = surfElementsFlag_vec[loc];
799 //cout << " Surfaces set to elements on Proc " << this->comm_->getRank() << " " << surfElements_vec_unsorted[loc][0] << " " << surfElements_vec_unsorted[loc][1] << " " << surfElements_vec_unsorted[loc][2] << endl;
800 FiniteElement feSurface( surfElements_vec_unsorted[loc], surfFlag);
801 if ( !element.subElementsInitialized() )
802 element.initializeSubElements( "P1", 2 ); // only P1 for now
803
804 element.addSubElement( feSurface );
805 }
806 }
807 }
808
809}
810
811
812template <class SC, class LO, class GO, class NO>
813void MeshPartitioner<SC,LO,GO,NO>::buildEdgeListParallel( MeshUnstrPtr_Type mesh, ElementsPtr_Type elementsGlobal ){
814 FEDD_TIMER_START(edgeListTimer," : MeshReader : Build Edge List");
815 ElementsPtr_Type elements = mesh->getElementsC();
816
817 TEUCHOS_TEST_FOR_EXCEPTION( elements->getFiniteElementType() != "P1", std::runtime_error ,"Unknown discretization for method buildEdgeList(...).");
818 CommConstPtr_Type comm = mesh->getComm();
819 bool verbose(comm->getRank()==0);
820
821 MapConstPtr_Type repeatedMap = mesh->getMapRepeated();
822 // Building local edges with repeated node list
823 vec2D_int_Type localEdgeIndices(0);
824 setLocalEdgeIndices( localEdgeIndices );
825 EdgeElementsPtr_Type edges = Teuchos::rcp( new EdgeElements_Type() );
826 for (int i=0; i<elementsGlobal->numberElements(); i++) {
827 for (int j=0; j<localEdgeIndices.size(); j++) {
828
829 int id1 = elementsGlobal->getElement( i ).getNode( localEdgeIndices[j][0] );
830 int id2 = elementsGlobal->getElement( i ).getNode( localEdgeIndices[j][1] );
831 vec_int_Type edgeVec(2);
832 if (id1<id2){
833 edgeVec[0] = id1;
834 edgeVec[1] = id2;
835 }
836 else{
837 edgeVec[0] = id2;
838 edgeVec[1] = id1;
839 }
840
841 FiniteElement edge( edgeVec );
842 edges->addEdge( edge, i );
843 }
844 }
845 // we do not need elementsGlobal anymore
846 elementsGlobal.reset();
847
848 vec2D_GO_Type combinedEdgeElements;
849 FEDD_TIMER_START(edgeListUniqueTimer," : MeshReader : Make Edge List Unique");
850 edges->sortUniqueAndSetGlobalIDs( combinedEdgeElements );
851 FEDD_TIMER_STOP(edgeListUniqueTimer);
852 //Next we need to communicate all edge information. This will not scale at all!
853
854 edges->setElementsEdges( combinedEdgeElements );
855
856 mesh->setEdgeElements( edges );
857
858};
859
860template <class SC, class LO, class GO, class NO>
861void MeshPartitioner<SC,LO,GO,NO>::setLocalEdgeIndices(vec2D_int_Type &localEdgeIndices ){
862 if ( dim_ == 2 ) {
863 localEdgeIndices.resize(3,vec_int_Type(2,-1));
864 localEdgeIndices.at(0).at(0) = 0;
865 localEdgeIndices.at(0).at(1) = 1;
866 localEdgeIndices.at(1).at(0) = 0;
867 localEdgeIndices.at(1).at(1) = 2;
868 localEdgeIndices.at(2).at(0) = 1;
869 localEdgeIndices.at(2).at(1) = 2;
870 }
871 else if( dim_ == 3) {
872 localEdgeIndices.resize(6,vec_int_Type(2,-1));
873 localEdgeIndices.at(0).at(0) = 0;
874 localEdgeIndices.at(0).at(1) = 1;
875 localEdgeIndices.at(1).at(0) = 0;
876 localEdgeIndices.at(1).at(1) = 2;
877 localEdgeIndices.at(2).at(0) = 1;
878 localEdgeIndices.at(2).at(1) = 2;
879 localEdgeIndices.at(3).at(0) = 0;
880 localEdgeIndices.at(3).at(1) = 3;
881 localEdgeIndices.at(4).at(0) = 1;
882 localEdgeIndices.at(4).at(1) = 3;
883 localEdgeIndices.at(5).at(0) = 2;
884 localEdgeIndices.at(5).at(1) = 3;
885
886 }
887}
888
889template <class SC, class LO, class GO, class NO>
890void MeshPartitioner<SC,LO,GO,NO>::makeContinuousElements(ElementsPtr_Type elements, vec_idx_Type& eind_vec, vec_idx_Type& eptr_vec ){
891
892 int nodesPerElement = elements->nodesPerElement();
893
894 int elcounter=0;
895 for (int i=0; i<elements->numberElements(); i++) {
896 for (int j=0; j<nodesPerElement; j++) {
897 eind_vec.push_back( elements->getElement( i ).getNode( j ) );
898 }
899 eptr_vec.push_back(elcounter);
900 elcounter += nodesPerElement;
901 }
902 eptr_vec.push_back(elcounter);
903
904}
905
906
907template <class SC, class LO, class GO, class NO>
908void MeshPartitioner<SC,LO,GO,NO>::setLocalSurfaceEdgeIndices( vec2D_int_Type &localSurfaceEdgeIndices, int edgesElementOrder ){
909
910 if ( dim_ == 3 ) {
911
912 if (edgesElementOrder == 2) { //P1
913 localSurfaceEdgeIndices.resize(6,vec_int_Type(2,-1));
914 localSurfaceEdgeIndices.at(0).at(0) = 0;
915 localSurfaceEdgeIndices.at(0).at(1) = 1;
916 localSurfaceEdgeIndices.at(1).at(0) = 0;
917 localSurfaceEdgeIndices.at(1).at(1) = 2;
918 localSurfaceEdgeIndices.at(2).at(0) = 0;
919 localSurfaceEdgeIndices.at(2).at(1) = 3;
920 localSurfaceEdgeIndices.at(3).at(0) = 1;
921 localSurfaceEdgeIndices.at(3).at(1) = 2;
922 localSurfaceEdgeIndices.at(4).at(0) = 1;
923 localSurfaceEdgeIndices.at(4).at(1) = 3;
924 localSurfaceEdgeIndices.at(5).at(0) = 2;
925 localSurfaceEdgeIndices.at(5).at(1) = 3;
926 }
927 }
928}
929
930template <class SC, class LO, class GO, class NO>
931void MeshPartitioner<SC,LO,GO,NO>::findAndSetSurfaceEdges( vec2D_int_Type& edgeElements_vec, vec_int_Type& edgeElementsFlag_vec, FiniteElement& element, vec2D_int_Type& permutation, MapConstPtr_Type mapRepeated){
932
933 int loc, id1Glob, id2Glob;
934 if (dim_ == 3){
935 for (int j=0; j<permutation.size(); j++) {
936 id1Glob = mapRepeated->getGlobalElement( element.getNode( permutation.at(j).at(0) ) );
937 id2Glob = mapRepeated->getGlobalElement( element.getNode( permutation.at(j).at(1) ) );
938 vec_int_Type tmpEdge(0);
939 if (id2Glob > id1Glob)
940 tmpEdge = {id1Glob , id2Glob};
941 else
942 tmpEdge = {id2Glob , id1Glob};
943
944 loc = searchInSurfaces( edgeElements_vec, tmpEdge );
945
946 if (loc>-1) {
947
948 int id1 = element.getNode( permutation.at(j).at(0) );
949 int id2 = element.getNode( permutation.at(j).at(1) );
950 vec_int_Type tmpEdgeLocal(0);
951 if (id2>id1)
952 tmpEdgeLocal = { id1 , id2 };
953 else
954 tmpEdgeLocal = { id2 , id1 };
955
956 // If no partition was performed, all information is still global at this point. We still use the function below and partition the mesh and surfaces later.
957 FiniteElement feEdge( tmpEdgeLocal, edgeElementsFlag_vec[loc] );
958 // In some cases an edge is the only part of the surface of an Element. In that case there does not exist a triangle subelement.
959 // We then have to initialize the edge as subelement.
960 // In very coarse meshes it is even possible that an interior element has multiple surface edges or nodes connected to the surface, which is why we might even set interior edges as subelements
961 if ( !element.subElementsInitialized() ){
962 element.initializeSubElements( "P1", 1 ); // only P1 for now
963 element.addSubElement( feEdge );
964 }
965 else{
966 ElementsPtr_Type surfaces = element.getSubElements();
967 if(surfaces->getDimension() == 2) // We set the edge to the corresponding surface element(s)
968 surfaces->setToCorrectElement( feEdge ); // Case we have surface subelements
969 else{ // simply adding the edge as subelement
970 element.addSubElement( feEdge ); // Case we dont have surface subelements
971 // Comment: Theoretically edges as subelement are only truely relevant when we apply a neuman bc on an edge which is currently not the case.
972 // This is just in case!
973 }
974 }
975 }
976 }
977 }
978
979}
980
981template <class SC, class LO, class GO, class NO>
982int MeshPartitioner<SC,LO,GO,NO>::searchInSurfaces( vec2D_int_Type& surfaces, vec_int_Type searchSurface){
983
984 int loc = -1;
985
986 vec2D_int_Type::iterator it = find(surfaces.begin(),surfaces.end(), searchSurface);
987
988 if (it!=surfaces.end())
989 loc = distance(surfaces.begin(),it);
990
991 return loc;
992}
993
994template <class SC, class LO, class GO, class NO>
995void MeshPartitioner<SC,LO,GO,NO>::setLocalSurfaceIndices(vec2D_int_Type &localSurfaceIndices, int surfaceElementOrder ){
996
997 if ( dim_ == 2 ) {
998
999 if (surfaceElementOrder == 2) { //P1
1000 localSurfaceIndices.resize(3,vec_int_Type(3,-1));
1001 localSurfaceIndices.at(0).at(0) = 0;
1002 localSurfaceIndices.at(0).at(1) = 1;
1003 localSurfaceIndices.at(1).at(0) = 0;
1004 localSurfaceIndices.at(1).at(1) = 2;
1005 localSurfaceIndices.at(2).at(0) = 1;
1006 localSurfaceIndices.at(2).at(1) = 2;
1007 }
1008 else
1009 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "No permutation for this surface yet.");
1010 }
1011 else if ( dim_ == 3 ){
1012 if (surfaceElementOrder == 3) {
1013 localSurfaceIndices.resize(4,vec_int_Type(3,-1));
1014 localSurfaceIndices.at(0).at(0) = 0;
1015 localSurfaceIndices.at(0).at(1) = 1;
1016 localSurfaceIndices.at(0).at(2) = 2;
1017 localSurfaceIndices.at(1).at(0) = 0;
1018 localSurfaceIndices.at(1).at(1) = 1;
1019 localSurfaceIndices.at(1).at(2) = 3;
1020 localSurfaceIndices.at(2).at(0) = 1;
1021 localSurfaceIndices.at(2).at(1) = 2;
1022 localSurfaceIndices.at(2).at(2) = 3;
1023 localSurfaceIndices.at(3).at(0) = 0;
1024 localSurfaceIndices.at(3).at(1) = 2;
1025 localSurfaceIndices.at(3).at(2) = 3;
1026 }
1027 else
1028 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "No permutation for this surface yet.");
1029 }
1030}
1031
1032
1033}
1034#endif
Definition Elements.hpp:23
Definition FiniteElement.hpp:17
Definition Map_decl.hpp:30
void readAndPartition(int volumeID=10, std::string meshUnit="cm", bool convertToCM=false)
Main Function of partitioner. Called with volume ID in order to set in case it is not equal to ten....
Definition MeshPartitioner_def.hpp:39
void findAndSetSurfacesPartitioned(vec2D_int_Type &surfElements_vec, vec2D_int_Type &surfElements_vec_unsorted, vec_int_Type &surfElementsFlag_vec, FiniteElement &element, vec2D_int_Type &permutation, vec_GO_Type &linearSurfacePartitionOffset, int globalElID)
Finding the surfaces corresponding to a specfic element and then setting subelements.
Definition MeshPartitioner_def.hpp:718
int searchInSurfaces(vec2D_int_Type &surfaces, vec_int_Type searchSurface)
Searching on particular surface in a surface list.
Definition MeshPartitioner_def.hpp:982
void setSurfacesToElements(int meshNumber)
Setting surfaces, i.e. edges in 2D and triangles in 3D, as subelements to the corresponding elements.
Definition MeshPartitioner_def.hpp:636
void buildEdgeListParallel(MeshUnstrPtr_Type mesh, ElementsPtr_Type elementsGlobal)
Making the edge list parallel.
Definition MeshPartitioner_def.hpp:813
void setEdgesToSurfaces(int meshNumber)
Only used in 3D to set the edges as subelements to surfaces.
Definition MeshPartitioner_def.hpp:587
void findAndSetSurfaceEdges(vec2D_int_Type &edgeElements_vec, vec_int_Type &edgeElementsFlag_vec, FiniteElement &element, vec2D_int_Type &permutation, MapConstPtr_Type mapRepeated)
Only relevant in 3D. Finding the edges corresponding to the specfic element and then setting as subsu...
Definition MeshPartitioner_def.hpp:931
void setLocalSurfaceEdgeIndices(vec2D_int_Type &localSurfaceEdgeIndices, int edgesElementOrder)
Setting local IDs to the edges in 3D case with respect to the local numbering of elements.
Definition MeshPartitioner_def.hpp:908
void setLocalEdgeIndices(vec2D_int_Type &localEdgeIndices)
Setting surfaces, i.e. edges in 2D and triangles in 3D, as subelements to the corresponding elements.
Definition MeshPartitioner_def.hpp:861
Adaptive Mesh Refinement.
Definition AdaptiveMeshRefinement_decl.hpp:36