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 MeshUnstrPtr_Type meshUnstr = Teuchos::rcp_dynamic_cast<MeshUnstr_Type>( domains_[meshNumber]->getMesh() );
235
236 // Reading nodes
237 meshUnstr->readMeshEntity("node");
238 // We delete the point at this point. We only need the flags to determine surface elements. We will load them again later.
239 meshUnstr->pointsRep_.reset();
240 // Reading elements
241 meshUnstr->readMeshEntity("element");
242 // Reading surfaces
243 meshUnstr->readMeshEntity("surface");
244 // Reading line segments
245 meshUnstr->readMeshEntity("line");
246
247
248
249 bool verbose ( comm_->getRank() == 0 );
250 bool buildEdges = pList_->get("Build Edge List", true);
251 bool buildSurfaces = pList_->get("Build Surface List", true);
252
253 // Adding surface as subelement to elements
254 if (buildSurfaces)
255 this->setSurfacesToElements( meshNumber );
256 else
257 meshUnstr->deleteSurfaceElements();
258
259 // Serially distributed elements
260 ElementsPtr_Type elementsMesh = meshUnstr->getElementsC();
261
262 // Setup Metis
263 idx_t options[METIS_NOPTIONS];
264 METIS_SetDefaultOptions(options);
265 options[METIS_OPTION_NUMBERING] = 0;
266 options[METIS_OPTION_SEED] = 666;
267 options[METIS_OPTION_CONTIG] = pList_->get("Contiguous",false); //0: Does not force contiguous partitions; 1: Forces contiguous partitions.
268 options[METIS_OPTION_MINCONN] = 0; // 1: Explicitly minimize the maximum connectivity.
269 options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;// or METIS_OBJTYPE_VOL
270 // options[METIS_OPTION_RTYPE] = METIS_RTYPE_GREEDY;
271 options[METIS_OPTION_NITER] = 50; // default is 10
272 options[METIS_OPTION_CCORDER] = 1;
273 idx_t ne = meshUnstr->getNumElementsGlobal(); // Global number of elements
274 idx_t nn = meshUnstr->getNumGlobalNodes(); // Global number of nodes
275 idx_t ned = meshUnstr->getEdgeElements()->numberElements(); // Global number of edges
276
277
278 int dim = meshUnstr->getDimension();
279 std::string FEType = domains_[meshNumber]->getFEType();
280
281 // Setup for paritioning with metis
282 vec_idx_Type eptr_vec(0); // Vector for local elements ptr (local is still global at this point)
283 vec_idx_Type eind_vec(0); // Vector for local elements ids
284
285 makeContinuousElements(elementsMesh, eind_vec, eptr_vec);
286
287 idx_t *eptr = &eptr_vec.at(0);
288 idx_t *eind = &eind_vec.at(0);
289
290 idx_t ncommon;
291 int orderSurface;
292 if (dim==2) {
293 if (FEType=="P1") {
294 ncommon = 2;
295 }
296 else if(FEType=="P2"){
297 ncommon = 3;
298 }
299 }
300 else if (dim==3) {
301 if (FEType=="P1") {
302 ncommon = 3;
303 }
304 else if(FEType=="P2"){
305 ncommon = 6;
306 }
307 }
308 else
309 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Wrong Dimension.");
310
311 idx_t objval = 0;
312 vec_idx_Type epart(ne,-1);
313 vec_idx_Type npart(nn,-1);
314
315 // Partitioning elements with metis
316 if (verbose)
317 std::cout << "-- Start partitioning with Metis ... " << std::flush;
318
319 {
320 FEDD_TIMER_START(partitionTimer," : MeshPartitioner : Partition Elements");
321 idx_t nparts = std::get<1>( rankRanges_[meshNumber] ) - std::get<0>( rankRanges_[meshNumber] ) + 1;
322 if ( nparts > 1 ) {
323 int rank = this->comm_->getRank();
324 // upperRange - lowerRange +1
325 idx_t returnCode = METIS_PartMeshDual(&ne, &nn, eptr, eind, NULL, NULL, &ncommon, &nparts, NULL, options, &objval, &epart[0], &npart[0]);
326 if ( verbose )
327 std::cout << "\n--\t Metis return code: " << returnCode;
328 }
329 else{
330 for (int i=0; i<ne; i++)
331 epart[i] = 0;
332 }
333 }
334
335 if (verbose){
336 std::cout << "\n--\t objval: " << objval << std::endl;
337 std::cout << "-- done!" << std::endl;
338 }
339
340 if (verbose)
341 std::cout << "-- Set Elements ... " << std::flush;
342
343 vec_GO_Type locepart(0);
344 vec_GO_Type pointsRepIndices(0);
345 // Global Edge IDs of local elements
346 vec_GO_Type locedpart(0);
347
348 // Getting global IDs of element's nodes
349 for (int i=0; i<ne; i++) {
350 if (epart[i] == comm_->getRank() - std::get<0>( rankRanges_[meshNumber] ) ){
351 locepart.push_back(i);
352 for (int j=eptr[i]; j<eptr[i+1]; j++)
353 pointsRepIndices.push_back( eind[j] ); // Ids of element nodes, globalIDs
354 }
355 }
356 // TODO KHo why erase the vectors here? eind points to the underlying array and is used later.
357 eind_vec.erase(eind_vec.begin(), eind_vec.end());
358 eptr_vec.erase(eptr_vec.begin(), eptr_vec.end());
359
360 // Sorting ids with global and corresponding local values to create repeated map
361 make_unique(pointsRepIndices);
362 if (verbose)
363 std::cout << "done!" << std::endl;
364
365 // Building repeated node map
366 Teuchos::ArrayView<GO> pointsRepGlobMapping = Teuchos::arrayViewFromVector( pointsRepIndices );
367 meshUnstr->mapRepeated_.reset( new Map<LO,GO,NO>(OTGO::invalid(), pointsRepGlobMapping, 0, this->comm_) );
368 MapConstPtr_Type mapRepeated = meshUnstr->mapRepeated_;
369
370 // We keep the global elements if we want to build edges later. Otherwise they will be deleted
371 ElementsPtr_Type elementsGlobal = Teuchos::rcp( new Elements_Type( *elementsMesh ) );
372
373 // Resetting elements to add the corresponding local IDs instead of global ones
374 meshUnstr->elementsC_.reset(new Elements ( FEType, dim ) );
375 {
376 Teuchos::ArrayView<GO> elementsGlobalMapping = Teuchos::arrayViewFromVector( locepart );
377 // elementsGlobalMapping -> elements per Processor
378
379 meshUnstr->elementMap_.reset(new Map<LO,GO,NO>( (GO) -1, elementsGlobalMapping, 0, this->comm_) );
380
381 {
382 int localSurfaceCounter = 0;
383 for (int i=0; i<locepart.size(); i++) {
384 std::vector<int> tmpElement;
385 for (int j=eptr[locepart.at(i)]; j<eptr[locepart.at(i)+1]; j++) {
386 //local indices
387 int index = mapRepeated->getLocalElement( (long long) eind[j] );
388 tmpElement.push_back(index);
389 }
390 //std::sort(tmpElement.begin(), tmpElement.end());
391 FiniteElement fe( tmpElement, elementsGlobal->getElement( locepart.at(i) ).getFlag() );
392 // convert global IDs of (old) globally owned subelements to local IDs
393 if (buildSurfaces) {
394 FiniteElement feGlobalIDs = elementsGlobal->getElement( locepart.at(i) );
395 if (feGlobalIDs.subElementsInitialized()){
396 ElementsPtr_Type subEl = feGlobalIDs.getSubElements();
397 subEl->globalToLocalIDs( mapRepeated );
398 fe.setSubElements( subEl );
399 }
400 }
401 meshUnstr->elementsC_->addElement( fe );
402 }
403 }
404 }
405
406 // Next we distribute the coordinates and flags correctly
407
408
409 meshUnstr->readMeshEntity("node"); // We reread the nodes, as they were deleted earlier
410
411 if (verbose)
412 std::cout << "-- Build Repeated Points Volume ... " << std::flush;
413
414 // building the unique map
415 meshUnstr->mapUnique_ = meshUnstr->mapRepeated_->buildUniqueMap( rankRanges_[meshNumber] );
416
417 // free(epart);
418 if (verbose)
419 std::cout << "-- Building unique & repeated points ... " << std::flush;
420 {
421 vec2D_dbl_Type points = *meshUnstr->getPointsRepeated();
422 vec_int_Type flags = *meshUnstr->getBCFlagRepeated();
423 meshUnstr->pointsRep_.reset( new std::vector<std::vector<double> >( meshUnstr->mapRepeated_->getNodeNumElements(), std::vector<double>(dim,-1.) ) );
424 meshUnstr->bcFlagRep_.reset( new std::vector<int> ( meshUnstr->mapRepeated_->getNodeNumElements(), 0 ) );
425
426 int pointIDcont;
427 for (int i=0; i<pointsRepIndices.size() ; i++) {
428 pointIDcont = pointsRepIndices.at(i);
429 for (int j=0; j<dim; j++)
430 meshUnstr->pointsRep_->at(i).at(j) = points[pointIDcont][j];
431 meshUnstr->bcFlagRep_->at(i) = flags[pointIDcont];
432 }
433 }
434
435 // Setting unique points and flags
436 meshUnstr->pointsUni_.reset(new std::vector<std::vector<double> >( meshUnstr->mapUnique_->getNodeNumElements(), std::vector<double>(dim,-1.) ) );
437 meshUnstr->bcFlagUni_.reset(new std::vector<int> ( meshUnstr->mapUnique_->getNodeNumElements(), 0) );
438 GO indexGlobal;
439 MapConstPtr_Type map = meshUnstr->getMapRepeated();
440 vec2D_dbl_ptr_Type pointsRep = meshUnstr->pointsRep_;
441 for (int i=0; i<meshUnstr->mapUnique_->getNodeNumElements() ; i++) {
442 indexGlobal = meshUnstr->mapUnique_->getGlobalElement(i);
443 for (int j=0; j<dim; j++) {
444 meshUnstr->pointsUni_->at(i).at(j) = pointsRep->at( map->getLocalElement( indexGlobal) ).at(j);
445 }
446 meshUnstr->bcFlagUni_->at(i) = meshUnstr->bcFlagRep_->at( map->getLocalElement( indexGlobal) );
447 }
448
449 // Finally we build the edges. As part of the edge build involves nodes and elements,
450 // they should be build last to avoid any local and global IDs mix up
451 if (!buildEdges)
452 elementsGlobal.reset();
453
454 locepart.erase(locepart.begin(),locepart.end());
455 if (verbose)
456 std::cout << "done!" << std::endl;
457
458 if (buildSurfaces){
459 this->setEdgesToSurfaces( meshNumber ); // Adding edges as subelements in the 3D case. All dim-1-Subelements were already set
460 }
461 else
462 meshUnstr->deleteSurfaceElements();
463
464 if (buildEdges) {
465 if (verbose)
466 std::cout << "-- Build edge element list ... " << std::endl << std::flush;
467
468 buildEdgeListParallel( meshUnstr, elementsGlobal );
469
470 if (verbose)
471 std::cout << std::endl << " done!"<< std::endl;
472
473 MapConstPtr_Type elementMap = meshUnstr->getElementMap();
474
475 FEDD_TIMER_START(partitionEdgesTimer," : MeshPartitioner : Partition Edges");
476 meshUnstr->getEdgeElements()->partitionEdges( elementMap, mapRepeated );
477 FEDD_TIMER_STOP(partitionEdgesTimer);
478
479 // edge global indices on different processors
480 for( int i=0; i<meshUnstr->getEdgeElements()->numberElements() ; i++){
481 locedpart.push_back(meshUnstr->getEdgeElements()->getGlobalID((LO) i));
482 }
483
484 // Setup for the EdgeMap
485 Teuchos::ArrayView<GO> edgesGlobalMapping = Teuchos::arrayViewFromVector( locedpart );
486 meshUnstr->edgeMap_.reset(new Map<LO,GO,NO>( (GO) -1, edgesGlobalMapping, 0, this->comm_) );
487 }
488
489
490 if (verbose)
491 std::cout << "done!" << std::endl;
492
493 if (verbose)
494 std::cout << "-- Partition interface ... " << std::flush;
495 meshUnstr->partitionInterface();
496
497 if (verbose)
498 std::cout << "done!" << std::endl;
499
500}
501
502
505template <class SC, class LO, class GO, class NO>
507 bool verbose ( comm_->getRank() == 0 );
508 MeshUnstrPtr_Type meshUnstr = Teuchos::rcp_dynamic_cast<MeshUnstr_Type>( domains_[meshNumber]->getMesh() );
509 ElementsPtr_Type elementsMesh = meshUnstr->getElementsC();
510 MapConstPtr_Type mapRepeated = meshUnstr->mapRepeated_;
511 if (verbose)
512 std::cout << "-- Set edges of surfaces of elements ... " << std::flush;
513
514 FEDD_TIMER_START(surfacesTimer," : MeshPartitioner : Set Surfaces of Edge Elements");
515 vec2D_int_Type localEdgeIDPermutation;
516 setLocalSurfaceEdgeIndices( localEdgeIDPermutation, meshUnstr->getEdgeElementOrder() );
517
518 int volumeID = meshUnstr->volumeID_;
519
520 ElementsPtr_Type elements = meshUnstr->getElementsC();
521 ElementsPtr_Type edgeElements = meshUnstr->getSurfaceEdgeElements();
522
523 /* First, we convert the surface edge elements to a 2D array so we can use std::find.*/
524 // Can we use/implement find for Elements_Type?
525 vec2D_int_Type edgeElements_vec( edgeElements->numberElements() );
526 vec_int_Type edgeElementsFlag_vec( edgeElements->numberElements() );
527 for (int i=0; i<edgeElements_vec.size(); i++){
528 vec_int_Type edge = edgeElements->getElement(i).getVectorNodeListNonConst();
529 std::sort( edge.begin(), edge.end() );
530 edgeElements_vec.at(i) = edge;
531 edgeElementsFlag_vec.at(i) = edgeElements->getElement(i).getFlag();
532 }
533
534 vec_int_ptr_Type flags = meshUnstr->bcFlagRep_;
535 int elementEdgeSurfaceCounter;
536 for (int i=0; i<elements->numberElements(); i++) {
537 elementEdgeSurfaceCounter = 0;
538 bool mark = false;
539 for (int j=0; j<elements->getElement( i ).size(); j++) {
540 if ( flags->at( elements->getElement( i ).getNode( j ) ) < volumeID )
541 elementEdgeSurfaceCounter++;
542 }
543 if (elementEdgeSurfaceCounter >= meshUnstr->getEdgeElementOrder()){
544 //We want to find all surfaces of element i and set the surfaces to the element
545 findAndSetSurfaceEdges( edgeElements_vec, edgeElementsFlag_vec, elements->getElement(i), localEdgeIDPermutation, mapRepeated );
546 }
547 }
548 if (verbose)
549 std::cout << "done!" << std::endl;
550}
551
554template <class SC, class LO, class GO, class NO>
556
557 bool verbose ( comm_->getRank() == 0 );
558 MeshUnstrPtr_Type meshUnstr = Teuchos::rcp_dynamic_cast<MeshUnstr_Type>( domains_[meshNumber]->getMesh() );
559 ElementsPtr_Type elementsMesh = meshUnstr->getElementsC(); // Previously read Elements
560
561 if (verbose)
562 std::cout << "-- Set surfaces of elements ... " << std::flush;
563
564 FEDD_TIMER_START(surfacesTimer," : MeshPartitioner : Set Surfaces of Elements");
565
566 vec2D_int_Type localSurfaceIDPermutation;
567 // get permutations
568 setLocalSurfaceIndices( localSurfaceIDPermutation, meshUnstr->getSurfaceElementOrder() );
569
570 int volumeID = meshUnstr->volumeID_;
571 ElementsPtr_Type surfaceElements = meshUnstr->getSurfaceElements();
572
573 /* First, we convert the surface Elements to a 2D array so we can use std::find.
574 and partition it at the same time. We use a simple linear partition. This is done to reduce
575 times spend for std::find. The result is then communicated. We therefore use the unpartitoned elements*/
576 // Can we use/implement find for Elements_Type?
577
578 int size = this->comm_->getSize();
579
580 LO numSurfaceEl = surfaceElements->numberElements();// / size;
581 /*LO rest = surfaceElements->numberElements() % size;
582
583 vec_GO_Type offsetVec(size);
584 for (int i=0; i<size; i++) {
585 offsetVec[i] = numSurfaceEl * i;
586 if ( i<rest && i == this->comm_->getRank() ) {
587 numSurfaceEl++;
588 offsetVec[i]+=i;
589 }
590 else
591 offsetVec[i]+=rest;
592 }*/
593
594 vec2D_int_Type surfElements_vec( numSurfaceEl );
595 vec2D_int_Type surfElements_vec_sorted( numSurfaceEl );
596
597 vec_int_Type surfElementsFlag_vec( numSurfaceEl );
598 vec_GO_Type offsetVec(size);
599 int offset = offsetVec[this->comm_->getRank()];
600
601 for (int i=0; i<surfElements_vec.size(); i++){
602 vec_int_Type surface = surfaceElements->getElement(i ).getVectorNodeListNonConst(); // surfaceElements->getElement(i + offset).getVectorNodeListNonConst();
603 surfElements_vec.at(i) = surface;
604 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
605 surfElements_vec_sorted.at(i) = surface;
606 surfElementsFlag_vec.at(i) = surfaceElements->getElement(i).getFlag(); // surfaceElements->getElement(i + offset).getFlag();
607
608 }
609
610 // Delete the surface elements. They will be added to the elements in the following loop.
611 surfaceElements.reset();
612 vec_int_ptr_Type flags = meshUnstr->bcFlagRep_;
613
614 int elementSurfaceCounter;
615 int surfaceElOrder = meshUnstr->getSurfaceElementOrder();
616 for (int i=0; i<elementsMesh->numberElements(); i++) {
617 elementSurfaceCounter = 0;
618 for (int j=0; j<elementsMesh->getElement( i ).size(); j++) {
619 if ( flags->at( elementsMesh->getElement( i ).getNode( j ) ) < volumeID )
620 elementSurfaceCounter++;
621 }
622
623 if (elementSurfaceCounter >= surfaceElOrder){
624 FEDD_TIMER_START(findSurfacesTimer," : MeshPartitioner : Find and Set Surfaces");
625 //We want to find all surfaces of element i and set the surfaces to the element
626 this->findAndSetSurfacesPartitioned( surfElements_vec_sorted, surfElements_vec, surfElementsFlag_vec, elementsMesh->getElement(i), localSurfaceIDPermutation, offsetVec, i );
627 }
628 }
629
630 if (verbose)
631 std::cout << "done!" << std::endl;
632}
633
636template <class SC, class LO, class GO, class NO>
637void 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 ){
638
639 // In general we look through the different permutations the input element 'element' can have and if they correspond to a surface.
640 // The mesh's surface elements 'surfElements_vec' are then used to determine the corresponding surface
641 // If found, the nodes are then used to build the subelement and the corresponding surfElementFlag is set.
642 // The Ids are global at this point, as the values are not distributed yet.
643
644 int loc, id1Glob, id2Glob, id3Glob;
645 int size = this->comm_->getSize();
646 vec_int_Type locAll(size);
647 if (dim_ == 2) {
648 for (int j=0; j<permutation.size(); j++) {
649 id1Glob = element.getNode( permutation.at(j).at(0) ) ;
650 id2Glob = element.getNode( permutation.at(j).at(1) ) ;
651
652 vec_int_Type tmpSurface(2);
653 if (id1Glob > id2Glob){
654 tmpSurface[0] = id2Glob;
655 tmpSurface[1] = id1Glob;
656 }
657 else{
658 tmpSurface[0] = id1Glob;
659 tmpSurface[1] = id2Glob;
660 }
661
662 loc = searchInSurfaces( surfElements_vec, tmpSurface );
663
664 Teuchos::gatherAll<int,int>( *this->comm_, 1, &loc, locAll.size(), &locAll[0] );
665
666 int surfaceRank = -1;
667 int counter = 0;
668 while (surfaceRank<0 && counter<size) {
669 if (locAll[counter] > -1)
670 surfaceRank = counter;
671 counter++;
672 }
673 int surfFlag = -1;
674 if (loc>-1)
675 surfFlag = surfElementsFlag_vec[loc];
676
677 if (surfaceRank>-1) {
678 Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&loc);
679 Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&surfFlag);
680
681 FiniteElement feSurface( tmpSurface, surfFlag);
682 if ( !element.subElementsInitialized() )
683 element.initializeSubElements( "P1", 1 ); // only P1 for now
684
685 element.addSubElement( feSurface );
686 }
687 }
688 }
689 else if (dim_ == 3){
690 for (int j=0; j<permutation.size(); j++) {
691
692 id1Glob = element.getNode( permutation.at(j).at(0) ) ;
693 id2Glob = element.getNode( permutation.at(j).at(1) ) ;
694 id3Glob = element.getNode( permutation.at(j).at(2) ) ;
695
696 vec_int_Type tmpSurface = {id1Glob , id2Glob , id3Glob};
697 sort( tmpSurface.begin(), tmpSurface.end() );
698 loc = searchInSurfaces( surfElements_vec, tmpSurface );
699 /*Teuchos::gatherAll<int,int>( *this->comm_, 1, &loc, locAll.size(), &locAll[0] );
700
701 int surfaceRank = -1;
702 int counter = 0;
703 while (surfaceRank<0 && counter<size) {
704 if (locAll[counter] > -1)
705 surfaceRank = counter;
706 counter++;
707 }
708 int surfFlag = -1;
709 if (loc>-1)
710 surfFlag = surfElementsFlag_vec[loc];
711
712 if (surfaceRank>-1) {*/
713 if(loc > -1 ){
714 //Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&loc);
715 //Teuchos::broadcast<int,int>(*this->comm_,surfaceRank,1,&surfFlag);
716
717 int surfFlag = surfElementsFlag_vec[loc];
718 //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;
719 FiniteElement feSurface( surfElements_vec_unsorted[loc], surfFlag);
720 if ( !element.subElementsInitialized() )
721 element.initializeSubElements( "P1", 2 ); // only P1 for now
722
723 element.addSubElement( feSurface );
724 }
725 }
726 }
727
728}
729
730
731template <class SC, class LO, class GO, class NO>
732void MeshPartitioner<SC,LO,GO,NO>::buildEdgeListParallel( MeshUnstrPtr_Type mesh, ElementsPtr_Type elementsGlobal ){
733 FEDD_TIMER_START(edgeListTimer," : MeshReader : Build Edge List");
734 ElementsPtr_Type elements = mesh->getElementsC();
735
736 TEUCHOS_TEST_FOR_EXCEPTION( elements->getFiniteElementType() != "P1", std::runtime_error ,"Unknown discretization for method buildEdgeList(...).");
737 CommConstPtr_Type comm = mesh->getComm();
738 bool verbose(comm->getRank()==0);
739
740 MapConstPtr_Type repeatedMap = mesh->getMapRepeated();
741 // Building local edges with repeated node list
742 vec2D_int_Type localEdgeIndices(0);
743 setLocalEdgeIndices( localEdgeIndices );
744 EdgeElementsPtr_Type edges = Teuchos::rcp( new EdgeElements_Type() );
745 for (int i=0; i<elementsGlobal->numberElements(); i++) {
746 for (int j=0; j<localEdgeIndices.size(); j++) {
747
748 int id1 = elementsGlobal->getElement( i ).getNode( localEdgeIndices[j][0] );
749 int id2 = elementsGlobal->getElement( i ).getNode( localEdgeIndices[j][1] );
750 vec_int_Type edgeVec(2);
751 if (id1<id2){
752 edgeVec[0] = id1;
753 edgeVec[1] = id2;
754 }
755 else{
756 edgeVec[0] = id2;
757 edgeVec[1] = id1;
758 }
759
760 FiniteElement edge( edgeVec );
761 edges->addEdge( edge, i );
762 }
763 }
764 // we do not need elementsGlobal anymore
765 elementsGlobal.reset();
766
767 vec2D_GO_Type combinedEdgeElements;
768 FEDD_TIMER_START(edgeListUniqueTimer," : MeshReader : Make Edge List Unique");
769 edges->sortUniqueAndSetGlobalIDs( combinedEdgeElements );
770 FEDD_TIMER_STOP(edgeListUniqueTimer);
771 //Next we need to communicate all edge information. This will not scale at all!
772
773 edges->setElementsEdges( combinedEdgeElements );
774
775 mesh->setEdgeElements( edges );
776
777};
778
779template <class SC, class LO, class GO, class NO>
780void MeshPartitioner<SC,LO,GO,NO>::setLocalEdgeIndices(vec2D_int_Type &localEdgeIndices ){
781 if ( dim_ == 2 ) {
782 localEdgeIndices.resize(3,vec_int_Type(2,-1));
783 localEdgeIndices.at(0).at(0) = 0;
784 localEdgeIndices.at(0).at(1) = 1;
785 localEdgeIndices.at(1).at(0) = 0;
786 localEdgeIndices.at(1).at(1) = 2;
787 localEdgeIndices.at(2).at(0) = 1;
788 localEdgeIndices.at(2).at(1) = 2;
789 }
790 else if( dim_ == 3) {
791 localEdgeIndices.resize(6,vec_int_Type(2,-1));
792 localEdgeIndices.at(0).at(0) = 0;
793 localEdgeIndices.at(0).at(1) = 1;
794 localEdgeIndices.at(1).at(0) = 0;
795 localEdgeIndices.at(1).at(1) = 2;
796 localEdgeIndices.at(2).at(0) = 1;
797 localEdgeIndices.at(2).at(1) = 2;
798 localEdgeIndices.at(3).at(0) = 0;
799 localEdgeIndices.at(3).at(1) = 3;
800 localEdgeIndices.at(4).at(0) = 1;
801 localEdgeIndices.at(4).at(1) = 3;
802 localEdgeIndices.at(5).at(0) = 2;
803 localEdgeIndices.at(5).at(1) = 3;
804
805 }
806}
807
808template <class SC, class LO, class GO, class NO>
809void MeshPartitioner<SC,LO,GO,NO>::makeContinuousElements(ElementsPtr_Type elements, vec_idx_Type& eind_vec, vec_idx_Type& eptr_vec ){
810
811 int nodesPerElement = elements->nodesPerElement();
812
813 int elcounter=0;
814 for (int i=0; i<elements->numberElements(); i++) {
815 for (int j=0; j<nodesPerElement; j++) {
816 eind_vec.push_back( elements->getElement( i ).getNode( j ) );
817 }
818 eptr_vec.push_back(elcounter);
819 elcounter += nodesPerElement;
820 }
821 eptr_vec.push_back(elcounter);
822
823}
824
825
826template <class SC, class LO, class GO, class NO>
827void MeshPartitioner<SC,LO,GO,NO>::setLocalSurfaceEdgeIndices( vec2D_int_Type &localSurfaceEdgeIndices, int edgesElementOrder ){
828
829 if ( dim_ == 3 ) {
830
831 if (edgesElementOrder == 2) { //P1
832 localSurfaceEdgeIndices.resize(6,vec_int_Type(2,-1));
833 localSurfaceEdgeIndices.at(0).at(0) = 0;
834 localSurfaceEdgeIndices.at(0).at(1) = 1;
835 localSurfaceEdgeIndices.at(1).at(0) = 0;
836 localSurfaceEdgeIndices.at(1).at(1) = 2;
837 localSurfaceEdgeIndices.at(2).at(0) = 0;
838 localSurfaceEdgeIndices.at(2).at(1) = 3;
839 localSurfaceEdgeIndices.at(3).at(0) = 1;
840 localSurfaceEdgeIndices.at(3).at(1) = 2;
841 localSurfaceEdgeIndices.at(4).at(0) = 1;
842 localSurfaceEdgeIndices.at(4).at(1) = 3;
843 localSurfaceEdgeIndices.at(5).at(0) = 2;
844 localSurfaceEdgeIndices.at(5).at(1) = 3;
845 }
846 }
847}
848
849template <class SC, class LO, class GO, class NO>
850void 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){
851
852 int loc, id1Glob, id2Glob;
853 if (dim_ == 3){
854 for (int j=0; j<permutation.size(); j++) {
855 id1Glob = mapRepeated->getGlobalElement( element.getNode( permutation.at(j).at(0) ) );
856 id2Glob = mapRepeated->getGlobalElement( element.getNode( permutation.at(j).at(1) ) );
857 vec_int_Type tmpEdge(0);
858 if (id2Glob > id1Glob)
859 tmpEdge = {id1Glob , id2Glob};
860 else
861 tmpEdge = {id2Glob , id1Glob};
862
863 loc = searchInSurfaces( edgeElements_vec, tmpEdge );
864
865 if (loc>-1) {
866
867 int id1 = element.getNode( permutation.at(j).at(0) );
868 int id2 = element.getNode( permutation.at(j).at(1) );
869 vec_int_Type tmpEdgeLocal(0);
870 if (id2>id1)
871 tmpEdgeLocal = { id1 , id2 };
872 else
873 tmpEdgeLocal = { id2 , id1 };
874
875 // 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.
876 FiniteElement feEdge( tmpEdgeLocal, edgeElementsFlag_vec[loc] );
877 // 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.
878 // We then have to initialize the edge as subelement.
879 // 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
880 if ( !element.subElementsInitialized() ){
881 element.initializeSubElements( "P1", 1 ); // only P1 for now
882 element.addSubElement( feEdge );
883 }
884 else{
885 ElementsPtr_Type surfaces = element.getSubElements();
886 if(surfaces->getDimension() == 2) // We set the edge to the corresponding surface element(s)
887 surfaces->setToCorrectElement( feEdge ); // Case we have surface subelements
888 else{ // simply adding the edge as subelement
889 element.addSubElement( feEdge ); // Case we dont have surface subelements
890 // Comment: Theoretically edges as subelement are only truely relevant when we apply a neuman bc on an edge which is currently not the case.
891 // This is just in case!
892 }
893 }
894 }
895 }
896 }
897
898}
899
900template <class SC, class LO, class GO, class NO>
901int MeshPartitioner<SC,LO,GO,NO>::searchInSurfaces( vec2D_int_Type& surfaces, vec_int_Type searchSurface){
902
903 int loc = -1;
904
905 vec2D_int_Type::iterator it = find(surfaces.begin(),surfaces.end(), searchSurface);
906
907 if (it!=surfaces.end())
908 loc = distance(surfaces.begin(),it);
909
910 return loc;
911}
912
913template <class SC, class LO, class GO, class NO>
914void MeshPartitioner<SC,LO,GO,NO>::setLocalSurfaceIndices(vec2D_int_Type &localSurfaceIndices, int surfaceElementOrder ){
915
916 if ( dim_ == 2 ) {
917
918 if (surfaceElementOrder == 2) { //P1
919 localSurfaceIndices.resize(3,vec_int_Type(3,-1));
920 localSurfaceIndices.at(0).at(0) = 0;
921 localSurfaceIndices.at(0).at(1) = 1;
922 localSurfaceIndices.at(1).at(0) = 0;
923 localSurfaceIndices.at(1).at(1) = 2;
924 localSurfaceIndices.at(2).at(0) = 1;
925 localSurfaceIndices.at(2).at(1) = 2;
926 }
927 else
928 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "No permutation for this surface yet.");
929 }
930 else if ( dim_ == 3 ){
931 if (surfaceElementOrder == 3) {
932 localSurfaceIndices.resize(4,vec_int_Type(3,-1));
933 localSurfaceIndices.at(0).at(0) = 0;
934 localSurfaceIndices.at(0).at(1) = 1;
935 localSurfaceIndices.at(0).at(2) = 2;
936 localSurfaceIndices.at(1).at(0) = 0;
937 localSurfaceIndices.at(1).at(1) = 1;
938 localSurfaceIndices.at(1).at(2) = 3;
939 localSurfaceIndices.at(2).at(0) = 1;
940 localSurfaceIndices.at(2).at(1) = 2;
941 localSurfaceIndices.at(2).at(2) = 3;
942 localSurfaceIndices.at(3).at(0) = 0;
943 localSurfaceIndices.at(3).at(1) = 2;
944 localSurfaceIndices.at(3).at(2) = 3;
945 }
946 else
947 TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "No permutation for this surface yet.");
948 }
949}
950
951
952}
953#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:637
int searchInSurfaces(vec2D_int_Type &surfaces, vec_int_Type searchSurface)
Searching on particular surface in a surface list.
Definition MeshPartitioner_def.hpp:901
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:555
void buildEdgeListParallel(MeshUnstrPtr_Type mesh, ElementsPtr_Type elementsGlobal)
Making the edge list parallel.
Definition MeshPartitioner_def.hpp:732
void setEdgesToSurfaces(int meshNumber)
Only used in 3D to set the edges as subelements to surfaces.
Definition MeshPartitioner_def.hpp:506
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:850
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:827
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:780
Adaptive Mesh Refinement.
Definition AdaptiveMeshRefinement_decl.hpp:33