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 ncommon;
369 int orderSurface;
370 if (dim==2) {
371 if (FEType=="P1") {
372 ncommon = 2;
373 }
374 else if(FEType=="P2"){
375 ncommon = 3;
376 }
377 }
378 else if (dim==3) {
379 if (FEType=="P1") {
380 ncommon = 3;
381 }
382 else if(FEType=="P2"){
383 ncommon = 6;
384 }
385 }
386 else
387 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Wrong Dimension.");
388
389 idx_t objval = 0;
390 vec_idx_Type epart(ne,-1);
391 vec_idx_Type npart(nn,-1);
392
393 // Partitioning elements with metis
394 if (verbose)
395 std::cout << "-- Start partitioning with Metis ... " << std::flush;
396
397 {
398 FEDD_TIMER_START(partitionTimer," : MeshPartitioner : Partition Elements");
399 idx_t nparts = std::get<1>( rankRanges_[meshNumber] ) - std::get<0>( rankRanges_[meshNumber] ) + 1;
400 if ( nparts > 1 ) {
401 int rank = this->comm_->getRank();
402 // upperRange - lowerRange +1
403 idx_t returnCode = METIS_PartMeshDual(&ne, &nn, eptr_vec.data(), eind_vec.data(), NULL, NULL, &ncommon, &nparts, NULL, options, &objval, epart.data(), npart.data());
404 if ( verbose )
405 std::cout << "\n--\t Metis return code: " << returnCode;
406 }
407 else{
408 for (int i=0; i<ne; i++)
409 epart.at(i) = 0;
410 }
411 }
412
413 if (verbose){
414 std::cout << "\n--\t objval: " << objval << std::endl;
415 std::cout << "-- done!" << std::endl;
416 }
417
418 if (verbose)
419 std::cout << "-- Set Elements ... " << std::flush;
420
421 vec_GO_Type locepart(0);
422 vec_GO_Type pointsRepIndices(0);
423 // Global Edge IDs of local elements
424 vec_GO_Type locedpart(0);
425
426 // Getting global IDs of element's nodes
427 for (int i=0; i<ne; i++) {
428 if (epart.at(i) == comm_->getRank() - std::get<0>( rankRanges_[meshNumber] ) ){
429 locepart.push_back(i);
430 for (int j=eptr_vec.at(i); j<eptr_vec.at(i+1); j++)
431 pointsRepIndices.push_back( eind_vec.at(j) ); // Ids of element nodes, globalIDs
432 }
433 }
434 // Sorting ids with global and corresponding local values to create repeated map
435 make_unique(pointsRepIndices);
436 if (verbose)
437 std::cout << "done!" << std::endl;
438
439 // Building repeated node map
440 Teuchos::ArrayView<GO> pointsRepGlobMapping = Teuchos::arrayViewFromVector( pointsRepIndices );
441 meshUnstr->mapRepeated_.reset( new Map<LO,GO,NO>(OTGO::invalid(), pointsRepGlobMapping, 0, this->comm_) );
442 MapConstPtr_Type mapRepeated = meshUnstr->mapRepeated_;
443
444 // We keep the global elements if we want to build edges later. Otherwise they will be deleted
445 ElementsPtr_Type elementsGlobal = Teuchos::rcp( new Elements_Type( *elementsMesh ) );
446
447 // Resetting elements to add the corresponding local IDs instead of global ones
448 meshUnstr->elementsC_.reset(new Elements ( FEType, dim ) );
449 {
450 Teuchos::ArrayView<GO> elementsGlobalMapping = Teuchos::arrayViewFromVector( locepart );
451 // elementsGlobalMapping -> elements per Processor
452
453 meshUnstr->elementMap_.reset(new Map<LO,GO,NO>( (GO) -1, elementsGlobalMapping, 0, this->comm_) );
454
455 {
456 int localSurfaceCounter = 0;
457 for (int i=0; i<locepart.size(); i++) {
458 std::vector<int> tmpElement;
459 for (int j = eptr_vec.at(locepart.at(i)); j < eptr_vec.at(locepart.at(i) + 1); j++) {
460 // local indices
461 int index = mapRepeated->getLocalElement(static_cast<GO>(eind_vec.at(j)));
462 tmpElement.push_back(index);
463 }
464 //std::sort(tmpElement.begin(), tmpElement.end());
465 FiniteElement fe( tmpElement, elementsGlobal->getElement( locepart.at(i) ).getFlag() );
466 // convert global IDs of (old) globally owned subelements to local IDs
467 if (buildSurfaces) {
468 FiniteElement feGlobalIDs = elementsGlobal->getElement( locepart.at(i) );
469 if (feGlobalIDs.subElementsInitialized()){
470 ElementsPtr_Type subEl = feGlobalIDs.getSubElements();
471 subEl->globalToLocalIDs( mapRepeated );
472 fe.setSubElements( subEl );
473 }
474 }
475 meshUnstr->elementsC_->addElement( fe );
476 }
477 }
478 }
479
480 // Next we distribute the coordinates and flags correctly
481
482
483 meshUnstr->readMeshEntity("node"); // We reread the nodes, as they were deleted earlier
484
485 if (verbose)
486 std::cout << "-- Build Repeated Points Volume ... " << std::flush;
487
488 // building the unique map
489 meshUnstr->mapUnique_ = meshUnstr->mapRepeated_->buildUniqueMap( rankRanges_[meshNumber] );
490
491 // free(epart);
492 if (verbose)
493 std::cout << "-- Building unique & repeated points ... " << std::flush;
494 {
495 vec2D_dbl_Type points = *meshUnstr->getPointsRepeated();
496 vec_int_Type flags = *meshUnstr->getBCFlagRepeated();
497 meshUnstr->pointsRep_.reset( new std::vector<std::vector<double> >( meshUnstr->mapRepeated_->getNodeNumElements(), std::vector<double>(dim,-1.) ) );
498 meshUnstr->bcFlagRep_.reset( new std::vector<int> ( meshUnstr->mapRepeated_->getNodeNumElements(), 0 ) );
499
500 int pointIDcont;
501 for (int i=0; i<pointsRepIndices.size() ; i++) {
502 pointIDcont = pointsRepIndices.at(i);
503 for (int j=0; j<dim; j++)
504 meshUnstr->pointsRep_->at(i).at(j) = points[pointIDcont][j];
505 meshUnstr->bcFlagRep_->at(i) = flags[pointIDcont];
506 }
507 }
508
509 // Setting unique points and flags
510 meshUnstr->pointsUni_.reset(new std::vector<std::vector<double> >( meshUnstr->mapUnique_->getNodeNumElements(), std::vector<double>(dim,-1.) ) );
511 meshUnstr->bcFlagUni_.reset(new std::vector<int> ( meshUnstr->mapUnique_->getNodeNumElements(), 0) );
512 GO indexGlobal;
513 MapConstPtr_Type map = meshUnstr->getMapRepeated();
514 vec2D_dbl_ptr_Type pointsRep = meshUnstr->pointsRep_;
515 for (int i=0; i<meshUnstr->mapUnique_->getNodeNumElements() ; i++) {
516 indexGlobal = meshUnstr->mapUnique_->getGlobalElement(i);
517 for (int j=0; j<dim; j++) {
518 meshUnstr->pointsUni_->at(i).at(j) = pointsRep->at( map->getLocalElement( indexGlobal) ).at(j);
519 }
520 meshUnstr->bcFlagUni_->at(i) = meshUnstr->bcFlagRep_->at( map->getLocalElement( indexGlobal) );
521 }
522
523 // Finally we build the edges. As part of the edge build involves nodes and elements,
524 // they should be build last to avoid any local and global IDs mix up
525 if (!buildEdges)
526 elementsGlobal.reset();
527
528 locepart.erase(locepart.begin(),locepart.end());
529 if (verbose)
530 std::cout << "done!" << std::endl;
531
532 if (buildSurfaces){
533 this->setEdgesToSurfaces( meshNumber ); // Adding edges as subelements in the 3D case. All dim-1-Subelements were already set
534 }
535 else
536 meshUnstr->deleteSurfaceElements();
537
538 if (buildEdges) {
539 if (verbose)
540 std::cout << "-- Build edge element list ... " << std::endl << std::flush;
541
542 buildEdgeListParallel( meshUnstr, elementsGlobal );
543
544 if (verbose)
545 std::cout << std::endl << " done!"<< std::endl;
546
547 MapConstPtr_Type elementMap = meshUnstr->getElementMap();
548
549 FEDD_TIMER_START(partitionEdgesTimer," : MeshPartitioner : Partition Edges");
550 meshUnstr->getEdgeElements()->partitionEdges( elementMap, mapRepeated );
551 FEDD_TIMER_STOP(partitionEdgesTimer);
552
553 // edge global indices on different processors
554 for( int i=0; i<meshUnstr->getEdgeElements()->numberElements() ; i++){
555 locedpart.push_back(meshUnstr->getEdgeElements()->getGlobalID((LO) i));
556 }
557
558 // Setup for the EdgeMap
559 Teuchos::ArrayView<GO> edgesGlobalMapping = Teuchos::arrayViewFromVector( locedpart );
560 meshUnstr->edgeMap_.reset(new Map<LO,GO,NO>( (GO) -1, edgesGlobalMapping, 0, this->comm_) );
561 }
562
563
564 if (verbose)
565 std::cout << "done!" << std::endl;
566
567 if (verbose)
568 std::cout << "-- Partition interface ... " << std::flush;
569 meshUnstr->partitionInterface();
570
571 if (verbose)
572 std::cout << "done!" << std::endl;
573
574}
575
576
579template <class SC, class LO, class GO, class NO>
581 bool verbose ( comm_->getRank() == 0 );
582 MeshUnstrPtr_Type meshUnstr = Teuchos::rcp_dynamic_cast<MeshUnstr_Type>( domains_[meshNumber]->getMesh() );
583 ElementsPtr_Type elementsMesh = meshUnstr->getElementsC();
584 MapConstPtr_Type mapRepeated = meshUnstr->mapRepeated_;
585 if (verbose)
586 std::cout << "-- Set edges of surfaces of elements ... " << std::flush;
587
588 FEDD_TIMER_START(surfacesTimer," : MeshPartitioner : Set Surfaces of Edge Elements");
589 vec2D_int_Type localEdgeIDPermutation;
590 setLocalSurfaceEdgeIndices( localEdgeIDPermutation, meshUnstr->getEdgeElementOrder() );
591
592 int volumeID = meshUnstr->volumeID_;
593
594 ElementsPtr_Type elements = meshUnstr->getElementsC();
595 ElementsPtr_Type edgeElements = meshUnstr->getSurfaceEdgeElements();
596
597 /* First, we convert the surface edge elements to a 2D array so we can use std::find.*/
598 // Can we use/implement find for Elements_Type?
599 vec2D_int_Type edgeElements_vec( edgeElements->numberElements() );
600 vec_int_Type edgeElementsFlag_vec( edgeElements->numberElements() );
601 for (int i=0; i<edgeElements_vec.size(); i++){
602 vec_int_Type edge = edgeElements->getElement(i).getVectorNodeListNonConst();
603 std::sort( edge.begin(), edge.end() );
604 edgeElements_vec.at(i) = edge;
605 edgeElementsFlag_vec.at(i) = edgeElements->getElement(i).getFlag();
606 }
607
608 vec_int_ptr_Type flags = meshUnstr->bcFlagRep_;
609 int elementEdgeSurfaceCounter;
610 for (int i=0; i<elements->numberElements(); i++) {
611 elementEdgeSurfaceCounter = 0;
612 bool mark = false;
613 for (int j=0; j<elements->getElement( i ).size(); j++) {
614 if ( flags->at( elements->getElement( i ).getNode( j ) ) < volumeID )
615 elementEdgeSurfaceCounter++;
616 }
617 if (elementEdgeSurfaceCounter >= meshUnstr->getEdgeElementOrder()){
618 //We want to find all surfaces of element i and set the surfaces to the element
619 findAndSetSurfaceEdges( edgeElements_vec, edgeElementsFlag_vec, elements->getElement(i), localEdgeIDPermutation, mapRepeated );
620 }
621 }
622 if (verbose)
623 std::cout << "done!" << std::endl;
624}
625
628template <class SC, class LO, class GO, class NO>
630
631 bool verbose ( comm_->getRank() == 0 );
632 MeshUnstrPtr_Type meshUnstr = Teuchos::rcp_dynamic_cast<MeshUnstr_Type>( domains_[meshNumber]->getMesh() );
633 ElementsPtr_Type elementsMesh = meshUnstr->getElementsC(); // Previously read Elements
634
635 if (verbose)
636 std::cout << "-- Set surfaces of elements ... " << std::flush;
637
638 FEDD_TIMER_START(surfacesTimer," : MeshPartitioner : Set Surfaces of Elements");
639
640 vec2D_int_Type localSurfaceIDPermutation;
641 // get permutations
642 setLocalSurfaceIndices( localSurfaceIDPermutation, meshUnstr->getSurfaceElementOrder() );
643
644 int volumeID = meshUnstr->volumeID_;
645 ElementsPtr_Type surfaceElements = meshUnstr->getSurfaceElements();
646
647 /* First, we convert the surface Elements to a 2D array so we can use std::find.
648 and partition it at the same time. We use a simple linear partition. This is done to reduce
649 times spend for std::find. The result is then communicated. We therefore use the unpartitoned elements*/
650 // Can we use/implement find for Elements_Type?
651
652 int size = this->comm_->getSize();
653
654 LO numSurfaceEl = surfaceElements->numberElements();// / size;
655 /*LO rest = surfaceElements->numberElements() % size;
656
657 vec_GO_Type offsetVec(size);
658 for (int i=0; i<size; i++) {
659 offsetVec[i] = numSurfaceEl * i;
660 if ( i<rest && i == this->comm_->getRank() ) {
661 numSurfaceEl++;
662 offsetVec[i]+=i;
663 }
664 else
665 offsetVec[i]+=rest;
666 }*/
667
668 vec2D_int_Type surfElements_vec( numSurfaceEl );
669 vec2D_int_Type surfElements_vec_sorted( numSurfaceEl );
670
671 vec_int_Type surfElementsFlag_vec( numSurfaceEl );
672 vec_GO_Type offsetVec(size);
673 int offset = offsetVec[this->comm_->getRank()];
674
675 for (int i=0; i<surfElements_vec.size(); i++){
676 vec_int_Type surface = surfaceElements->getElement(i ).getVectorNodeListNonConst(); // surfaceElements->getElement(i + offset).getVectorNodeListNonConst();
677 surfElements_vec.at(i) = surface;
678 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
679 surfElements_vec_sorted.at(i) = surface;
680 surfElementsFlag_vec.at(i) = surfaceElements->getElement(i).getFlag(); // surfaceElements->getElement(i + offset).getFlag();
681
682 }
683
684 // Delete the surface elements. They will be added to the elements in the following loop.
685 surfaceElements.reset();
686 vec_int_ptr_Type flags = meshUnstr->bcFlagRep_;
687
688 int elementSurfaceCounter;
689 int surfaceElOrder = meshUnstr->getSurfaceElementOrder();
690 for (int i=0; i<elementsMesh->numberElements(); i++) {
691 elementSurfaceCounter = 0;
692 for (int j=0; j<elementsMesh->getElement( i ).size(); j++) {
693 if ( flags->at( elementsMesh->getElement( i ).getNode( j ) ) < volumeID )
694 elementSurfaceCounter++;
695 }
696
697 if (elementSurfaceCounter >= surfaceElOrder){
698 FEDD_TIMER_START(findSurfacesTimer," : MeshPartitioner : Find and Set Surfaces");
699 //We want to find all surfaces of element i and set the surfaces to the element
700 this->findAndSetSurfacesPartitioned( surfElements_vec_sorted, surfElements_vec, surfElementsFlag_vec, elementsMesh->getElement(i), localSurfaceIDPermutation, offsetVec, i );
701 }
702 }
703
704 if (verbose)
705 std::cout << "done!" << std::endl;
706}
707
710template <class SC, class LO, class GO, class NO>
711void 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 ){
712
713 // In general we look through the different permutations the input element 'element' can have and if they correspond to a surface.
714 // The mesh's surface elements 'surfElements_vec' are then used to determine the corresponding surface
715 // If found, the nodes are then used to build the subelement and the corresponding surfElementFlag is set.
716 // The Ids are global at this point, as the values are not distributed yet.
717
718 int loc, id1Glob, id2Glob, id3Glob;
719 int size = this->comm_->getSize();
720 vec_int_Type locAll(size);
721 if (dim_ == 2) {
722 for (int j=0; j<permutation.size(); j++) {
723 id1Glob = element.getNode( permutation.at(j).at(0) ) ;
724 id2Glob = element.getNode( permutation.at(j).at(1) ) ;
725
726 vec_int_Type tmpSurface(2);
727 if (id1Glob > id2Glob){
728 tmpSurface[0] = id2Glob;
729 tmpSurface[1] = id1Glob;
730 }
731 else{
732 tmpSurface[0] = id1Glob;
733 tmpSurface[1] = id2Glob;
734 }
735
736 loc = searchInSurfaces( surfElements_vec, tmpSurface );
737
738 Teuchos::gatherAll<int,int>( *this->comm_, 1, &loc, locAll.size(), &locAll[0] );
739
740 int surfaceRank = -1;
741 int counter = 0;
742 while (surfaceRank<0 && counter<size) {
743 if (locAll[counter] > -1)
744 surfaceRank = counter;
745 counter++;
746 }
747 int surfFlag = -1;
748 if (loc>-1)
749 surfFlag = surfElementsFlag_vec[loc];
750
751 if (surfaceRank>-1) {
752 Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&loc);
753 Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&surfFlag);
754
755 FiniteElement feSurface( tmpSurface, surfFlag);
756 if ( !element.subElementsInitialized() )
757 element.initializeSubElements( "P1", 1 ); // only P1 for now
758
759 element.addSubElement( feSurface );
760 }
761 }
762 }
763 else if (dim_ == 3){
764 for (int j=0; j<permutation.size(); j++) {
765
766 id1Glob = element.getNode( permutation.at(j).at(0) ) ;
767 id2Glob = element.getNode( permutation.at(j).at(1) ) ;
768 id3Glob = element.getNode( permutation.at(j).at(2) ) ;
769
770 vec_int_Type tmpSurface = {id1Glob , id2Glob , id3Glob};
771 sort( tmpSurface.begin(), tmpSurface.end() );
772 loc = searchInSurfaces( surfElements_vec, tmpSurface );
773 /*Teuchos::gatherAll<int,int>( *this->comm_, 1, &loc, locAll.size(), &locAll[0] );
774
775 int surfaceRank = -1;
776 int counter = 0;
777 while (surfaceRank<0 && counter<size) {
778 if (locAll[counter] > -1)
779 surfaceRank = counter;
780 counter++;
781 }
782 int surfFlag = -1;
783 if (loc>-1)
784 surfFlag = surfElementsFlag_vec[loc];
785
786 if (surfaceRank>-1) {*/
787 if(loc > -1 ){
788 //Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&loc);
789 //Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&surfFlag);
790
791 int surfFlag = surfElementsFlag_vec[loc];
792 //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;
793 FiniteElement feSurface( surfElements_vec_unsorted[loc], surfFlag);
794 if ( !element.subElementsInitialized() )
795 element.initializeSubElements( "P1", 2 ); // only P1 for now
796
797 element.addSubElement( feSurface );
798 }
799 }
800 }
801
802}
803
804
805template <class SC, class LO, class GO, class NO>
806void MeshPartitioner<SC,LO,GO,NO>::buildEdgeListParallel( MeshUnstrPtr_Type mesh, ElementsPtr_Type elementsGlobal ){
807 FEDD_TIMER_START(edgeListTimer," : MeshReader : Build Edge List");
808 ElementsPtr_Type elements = mesh->getElementsC();
809
810 TEUCHOS_TEST_FOR_EXCEPTION( elements->getFiniteElementType() != "P1", std::runtime_error ,"Unknown discretization for method buildEdgeList(...).");
811 CommConstPtr_Type comm = mesh->getComm();
812 bool verbose(comm->getRank()==0);
813
814 MapConstPtr_Type repeatedMap = mesh->getMapRepeated();
815 // Building local edges with repeated node list
816 vec2D_int_Type localEdgeIndices(0);
817 setLocalEdgeIndices( localEdgeIndices );
818 EdgeElementsPtr_Type edges = Teuchos::rcp( new EdgeElements_Type() );
819 for (int i=0; i<elementsGlobal->numberElements(); i++) {
820 for (int j=0; j<localEdgeIndices.size(); j++) {
821
822 int id1 = elementsGlobal->getElement( i ).getNode( localEdgeIndices[j][0] );
823 int id2 = elementsGlobal->getElement( i ).getNode( localEdgeIndices[j][1] );
824 vec_int_Type edgeVec(2);
825 if (id1<id2){
826 edgeVec[0] = id1;
827 edgeVec[1] = id2;
828 }
829 else{
830 edgeVec[0] = id2;
831 edgeVec[1] = id1;
832 }
833
834 FiniteElement edge( edgeVec );
835 edges->addEdge( edge, i );
836 }
837 }
838 // we do not need elementsGlobal anymore
839 elementsGlobal.reset();
840
841 vec2D_GO_Type combinedEdgeElements;
842 FEDD_TIMER_START(edgeListUniqueTimer," : MeshReader : Make Edge List Unique");
843 edges->sortUniqueAndSetGlobalIDs( combinedEdgeElements );
844 FEDD_TIMER_STOP(edgeListUniqueTimer);
845 //Next we need to communicate all edge information. This will not scale at all!
846
847 edges->setElementsEdges( combinedEdgeElements );
848
849 mesh->setEdgeElements( edges );
850
851};
852
853template <class SC, class LO, class GO, class NO>
854void MeshPartitioner<SC,LO,GO,NO>::setLocalEdgeIndices(vec2D_int_Type &localEdgeIndices ){
855 if ( dim_ == 2 ) {
856 localEdgeIndices.resize(3,vec_int_Type(2,-1));
857 localEdgeIndices.at(0).at(0) = 0;
858 localEdgeIndices.at(0).at(1) = 1;
859 localEdgeIndices.at(1).at(0) = 0;
860 localEdgeIndices.at(1).at(1) = 2;
861 localEdgeIndices.at(2).at(0) = 1;
862 localEdgeIndices.at(2).at(1) = 2;
863 }
864 else if( dim_ == 3) {
865 localEdgeIndices.resize(6,vec_int_Type(2,-1));
866 localEdgeIndices.at(0).at(0) = 0;
867 localEdgeIndices.at(0).at(1) = 1;
868 localEdgeIndices.at(1).at(0) = 0;
869 localEdgeIndices.at(1).at(1) = 2;
870 localEdgeIndices.at(2).at(0) = 1;
871 localEdgeIndices.at(2).at(1) = 2;
872 localEdgeIndices.at(3).at(0) = 0;
873 localEdgeIndices.at(3).at(1) = 3;
874 localEdgeIndices.at(4).at(0) = 1;
875 localEdgeIndices.at(4).at(1) = 3;
876 localEdgeIndices.at(5).at(0) = 2;
877 localEdgeIndices.at(5).at(1) = 3;
878
879 }
880}
881
882template <class SC, class LO, class GO, class NO>
883void MeshPartitioner<SC,LO,GO,NO>::makeContinuousElements(ElementsPtr_Type elements, vec_idx_Type& eind_vec, vec_idx_Type& eptr_vec ){
884
885 int nodesPerElement = elements->nodesPerElement();
886
887 int elcounter=0;
888 for (int i=0; i<elements->numberElements(); i++) {
889 for (int j=0; j<nodesPerElement; j++) {
890 eind_vec.push_back( elements->getElement( i ).getNode( j ) );
891 }
892 eptr_vec.push_back(elcounter);
893 elcounter += nodesPerElement;
894 }
895 eptr_vec.push_back(elcounter);
896
897}
898
899
900template <class SC, class LO, class GO, class NO>
901void MeshPartitioner<SC,LO,GO,NO>::setLocalSurfaceEdgeIndices( vec2D_int_Type &localSurfaceEdgeIndices, int edgesElementOrder ){
902
903 if ( dim_ == 3 ) {
904
905 if (edgesElementOrder == 2) { //P1
906 localSurfaceEdgeIndices.resize(6,vec_int_Type(2,-1));
907 localSurfaceEdgeIndices.at(0).at(0) = 0;
908 localSurfaceEdgeIndices.at(0).at(1) = 1;
909 localSurfaceEdgeIndices.at(1).at(0) = 0;
910 localSurfaceEdgeIndices.at(1).at(1) = 2;
911 localSurfaceEdgeIndices.at(2).at(0) = 0;
912 localSurfaceEdgeIndices.at(2).at(1) = 3;
913 localSurfaceEdgeIndices.at(3).at(0) = 1;
914 localSurfaceEdgeIndices.at(3).at(1) = 2;
915 localSurfaceEdgeIndices.at(4).at(0) = 1;
916 localSurfaceEdgeIndices.at(4).at(1) = 3;
917 localSurfaceEdgeIndices.at(5).at(0) = 2;
918 localSurfaceEdgeIndices.at(5).at(1) = 3;
919 }
920 }
921}
922
923template <class SC, class LO, class GO, class NO>
924void 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){
925
926 int loc, id1Glob, id2Glob;
927 if (dim_ == 3){
928 for (int j=0; j<permutation.size(); j++) {
929 id1Glob = mapRepeated->getGlobalElement( element.getNode( permutation.at(j).at(0) ) );
930 id2Glob = mapRepeated->getGlobalElement( element.getNode( permutation.at(j).at(1) ) );
931 vec_int_Type tmpEdge(0);
932 if (id2Glob > id1Glob)
933 tmpEdge = {id1Glob , id2Glob};
934 else
935 tmpEdge = {id2Glob , id1Glob};
936
937 loc = searchInSurfaces( edgeElements_vec, tmpEdge );
938
939 if (loc>-1) {
940
941 int id1 = element.getNode( permutation.at(j).at(0) );
942 int id2 = element.getNode( permutation.at(j).at(1) );
943 vec_int_Type tmpEdgeLocal(0);
944 if (id2>id1)
945 tmpEdgeLocal = { id1 , id2 };
946 else
947 tmpEdgeLocal = { id2 , id1 };
948
949 // 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.
950 FiniteElement feEdge( tmpEdgeLocal, edgeElementsFlag_vec[loc] );
951 // 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.
952 // We then have to initialize the edge as subelement.
953 // 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
954 if ( !element.subElementsInitialized() ){
955 element.initializeSubElements( "P1", 1 ); // only P1 for now
956 element.addSubElement( feEdge );
957 }
958 else{
959 ElementsPtr_Type surfaces = element.getSubElements();
960 if(surfaces->getDimension() == 2) // We set the edge to the corresponding surface element(s)
961 surfaces->setToCorrectElement( feEdge ); // Case we have surface subelements
962 else{ // simply adding the edge as subelement
963 element.addSubElement( feEdge ); // Case we dont have surface subelements
964 // Comment: Theoretically edges as subelement are only truely relevant when we apply a neuman bc on an edge which is currently not the case.
965 // This is just in case!
966 }
967 }
968 }
969 }
970 }
971
972}
973
974template <class SC, class LO, class GO, class NO>
975int MeshPartitioner<SC,LO,GO,NO>::searchInSurfaces( vec2D_int_Type& surfaces, vec_int_Type searchSurface){
976
977 int loc = -1;
978
979 vec2D_int_Type::iterator it = find(surfaces.begin(),surfaces.end(), searchSurface);
980
981 if (it!=surfaces.end())
982 loc = distance(surfaces.begin(),it);
983
984 return loc;
985}
986
987template <class SC, class LO, class GO, class NO>
988void MeshPartitioner<SC,LO,GO,NO>::setLocalSurfaceIndices(vec2D_int_Type &localSurfaceIndices, int surfaceElementOrder ){
989
990 if ( dim_ == 2 ) {
991
992 if (surfaceElementOrder == 2) { //P1
993 localSurfaceIndices.resize(3,vec_int_Type(3,-1));
994 localSurfaceIndices.at(0).at(0) = 0;
995 localSurfaceIndices.at(0).at(1) = 1;
996 localSurfaceIndices.at(1).at(0) = 0;
997 localSurfaceIndices.at(1).at(1) = 2;
998 localSurfaceIndices.at(2).at(0) = 1;
999 localSurfaceIndices.at(2).at(1) = 2;
1000 }
1001 else
1002 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "No permutation for this surface yet.");
1003 }
1004 else if ( dim_ == 3 ){
1005 if (surfaceElementOrder == 3) {
1006 localSurfaceIndices.resize(4,vec_int_Type(3,-1));
1007 localSurfaceIndices.at(0).at(0) = 0;
1008 localSurfaceIndices.at(0).at(1) = 1;
1009 localSurfaceIndices.at(0).at(2) = 2;
1010 localSurfaceIndices.at(1).at(0) = 0;
1011 localSurfaceIndices.at(1).at(1) = 1;
1012 localSurfaceIndices.at(1).at(2) = 3;
1013 localSurfaceIndices.at(2).at(0) = 1;
1014 localSurfaceIndices.at(2).at(1) = 2;
1015 localSurfaceIndices.at(2).at(2) = 3;
1016 localSurfaceIndices.at(3).at(0) = 0;
1017 localSurfaceIndices.at(3).at(1) = 2;
1018 localSurfaceIndices.at(3).at(2) = 3;
1019 }
1020 else
1021 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "No permutation for this surface yet.");
1022 }
1023}
1024
1025
1026}
1027#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:711
int searchInSurfaces(vec2D_int_Type &surfaces, vec_int_Type searchSurface)
Searching on particular surface in a surface list.
Definition MeshPartitioner_def.hpp:975
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:629
void buildEdgeListParallel(MeshUnstrPtr_Type mesh, ElementsPtr_Type elementsGlobal)
Making the edge list parallel.
Definition MeshPartitioner_def.hpp:806
void setEdgesToSurfaces(int meshNumber)
Only used in 3D to set the edges as subelements to surfaces.
Definition MeshPartitioner_def.hpp:580
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:924
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:901
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:854
Adaptive Mesh Refinement.
Definition AdaptiveMeshRefinement_decl.hpp:36