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