FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
parti_domain_control.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
9
10#include <kernel/geometry/mesh_file_reader.hpp>
11#include <kernel/geometry/boundary_factory.hpp>
12#include <kernel/geometry/common_factories.hpp>
13
14#include <control/domain/parti_domain_control_base.hpp>
15
16namespace FEAT
17{
18 namespace Control
19 {
20 namespace Domain
21 {
32 {
33 args.support("parti-type", "<types...>\n"
34 "Specifies which partitioner types are allowed to be used.\n"
35 "May contain the following types:\n"
36 "2level extern genetic metis naive zoltan"
37 );
38 args.support("parti-extern-name", "<names...>\n"
39 "Specifies the names of the allowed extern partitions."
40 );
41 args.support("parti-rank-elems", "<count>\n"
42 "Specifies the minimum number of elements per rank for a-posteriori partitioning."
43 );
44 args.support("parti-genetic-time", "<time-init> <time-mutate>\n"
45 "Specifies the time for initial distribution and mutation for the genetic partitioner."
46 );
47 }
48
60 template<typename DomainLevel_>
63 {
64 public:
68 using typename BaseClass::LevelType;
70 using typename BaseClass::LayerType;
72 using typename BaseClass::MeshType;
74 using typename BaseClass::AtlasType;
76 using typename BaseClass::MeshNodeType;
78 using typename BaseClass::MeshPartType;
80 using typename BaseClass::Ancestor;
82 using typename BaseClass::WeightType;
83
84 protected:
87
92
94 std::deque<String> _extern_parti_names;
95
98
99 public:
109 explicit PartiDomainControl(const Dist::Comm& comm_, bool support_multi_layered) :
110 BaseClass(comm_, support_multi_layered),
114 _permutation_strategy(Geometry::PermutationStrategy::none)
115 {
116 }
117
120 {
121 }
122
135 virtual bool parse_args(SimpleArgParser& args) override
136 {
137 if(!BaseClass::parse_args(args))
138 return false;
139
140 // parse --parti-extern-name <names...>
141 {
142 auto it = args.query("parti-extern-name");
143 if(it != nullptr)
144 _extern_parti_names = it->second;
145 }
146
147 // okay
148 return true;
149 }
150
161 virtual bool parse_property_map(const PropertyMap& pmap) override
162 {
164 return false;
165
166 auto parti_extern_name_p = pmap.query("parti-extern-name");
167 if(parti_extern_name_p.second)
168 {
169 this->_extern_parti_names = parti_extern_name_p.first.split_by_whitespaces();
170 }
171
172 return true;
173 }
174
184 virtual void create(const std::deque<String>& filenames, String dirpath = "")
185 {
186 // create a mesh file reader
187 Geometry::MeshFileReader mesh_reader;
188
189 // add the files
190 mesh_reader.add_mesh_files(this->_comm, filenames, dirpath);
191
192 // finally, create the control
193 this->create(mesh_reader);
194 }
195
202 virtual void create(Geometry::MeshFileReader& mesh_reader)
203 {
204 // ensure that the domain control is still empty
205 XASSERTM(!this->_was_created, "domain has already been created");
206 XASSERT(this->size_physical() == std::size_t(0));
207 XASSERT(this->size_virtual() == std::size_t(0));
208
209 TimeStamp stamp_create;
210
211 // parse mesh and create control
212 this->create(mesh_reader.parse(this->_atlas, &_parti_set));
213
214 // clear partition set after creation
215 _parti_set.clear();
216
217 // collect partition statistics
219 }
220
227 virtual void create(std::unique_ptr<MeshNodeType> base_mesh_node)
228 {
229 TimeStamp stamp_create;
230
231 // call base-class create
232 this->_create(std::move(base_mesh_node));
233
234 // finally, apply mesh permutation
235 this->_was_created = false;
237 this->_was_created = true;
238
239 // collect partition statistics
241 }
242
251 virtual void create_rectilinear(Index num_elems_x, Index num_elems_y = 0u, Index num_elems_z = 0u)
252 {
253 // ensure that the domain control is still empty
254 XASSERTM(!this->_was_created, "domain has already been created");
255 XASSERT(this->size_physical() == std::size_t(0));
256 XASSERT(this->size_virtual() == std::size_t(0));
257
258 TimeStamp stamp_create;
259
260 // allocate a base-mesh node and create mesh
261 std::unique_ptr<MeshNodeType> base_mesh_node = MeshNodeType::make_unique(
262 Geometry::StructUnitCubeFactory<MeshType>::make_unique_from(num_elems_x, num_elems_y, num_elems_z));
263
264 // get mesh and create boundary
265 {
266 Geometry::BoundaryFactory<MeshType> bnd_factory(*base_mesh_node->get_mesh());
267 base_mesh_node->add_mesh_part("bnd", bnd_factory.make_unique());
268 }
269
270 // create control
271 this->create(std::move(base_mesh_node));
272
273 // collect partition statistics
275 }
276
284 {
285 XASSERTM(!this->_was_created, "This function has to be called before domain control creation!");
286 _permutation_strategy = strategy;
287 }
288
291 {
293 }
294
299 {
300 // nothing to do?
302 return;
303
304 // loop over all levels and permute
305 for(std::size_t i(0); i < this->size_physical(); ++i)
306 {
307 this->at(i)->get_mesh_node()->create_permutation(this->_permutation_strategy);
308 }
309 }
310
311 protected:
318 virtual void _reset_parti_types() override
319 {
322 }
323
332 virtual bool _parse_parti_type(const String& type) override
333 {
334 if(type.compare_no_case("extern") == 0)
335 return _allow_parti_extern = true;
336 else if(type.compare_no_case("2level") == 0)
337 return _allow_parti_2level = true;
338 else
339 return BaseClass::_parse_parti_type(type);
340 }
341
348 virtual void _create(std::unique_ptr<MeshNodeType> base_mesh_node)
349 {
350 // ensure that the domain control is still empty
351 XASSERTM(!this->_was_created, "domain has already been created");
352 XASSERT(this->size_physical() == std::size_t(0));
353 XASSERT(this->size_virtual() == std::size_t(0));
354
355 TimeStamp stamp_create;
356
357 // create the domain control
358#ifdef FEAT_HAVE_MPI
359 if(this->_comm.size() == 1)
360 {
361 // We've got just one process, so it's a simple choice:
362 this->_create_single_process(std::move(base_mesh_node));
363 }
364 else if(this->_support_multi_layered && (this->_desired_levels.size() > std::size_t(2)))
365 {
366 // The application supports multi-layered domain controls and
367 // the user wants that, so create a multi-layered one:
368 this->_create_multi_layered(std::move(base_mesh_node));
369 }
370 else
371 {
372 // Create a single-layered domain control:
373 this->_create_single_layered(std::move(base_mesh_node));
374 }
375#else // not FEAT_HAVE_MPI
376 {
377 // In the non-MPI case, we always have only one process:
378 this->_create_single_process(std::move(base_mesh_node));
379 }
380#endif // FEAT_HAVE_MPI
381
382 // compile virtual levels
383 this->compile_virtual_levels();
384
385 // collect partition statistics
387
388 // domain created
389 this->_was_created = true;
390 }
391
403 virtual void _create_single_process(std::unique_ptr<MeshNodeType> base_mesh_node)
404 {
405 // create and push single layer
406 this->push_layer(std::make_shared<LayerType>(this->_comm.comm_dup(), 0));
407
408 // create single ancestry
410 Ancestor& ancestor = this->_ancestry.front();
411
412 // use the whole base mesh here
413 ancestor.parti_info = "Using base-mesh";
414
415 // refine up to desired minimum level
416 int lvl = 0;
417 for(; lvl < ancestor.desired_level_min; ++lvl)
418 {
419 // refine the patch mesh
420 base_mesh_node = base_mesh_node->refine_unique(this->_adapt_mode);
421 }
422
423 // save chosen minimum level if it is not equal to the desired maximum level
424 if(lvl < ancestor.desired_level_max)
425 this->_chosen_levels.push_front(std::make_pair(lvl, 0));
426
427 // refine up to maximum level and push to control
428 for(; lvl < ancestor.desired_level_max; ++lvl)
429 {
430 // refine the base mesh
431 auto refined_node = base_mesh_node->refine_unique(this->_adapt_mode);
432
433 // push this level
434 this->push_level_front(0, std::make_shared<LevelType>(lvl, std::move(base_mesh_node)));
435
436 // continue with refined node
437 base_mesh_node = std::move(refined_node);
438 }
439
440 // save chosen maximum level
441 this->_chosen_levels.push_front(std::make_pair(lvl, 1));
442
443 // push finest level
444 this->push_level_front(0, std::make_shared<LevelType>(lvl, std::move(base_mesh_node)));
445 }
446
447 // Note: all following member functions are only required for parallel builds,
448 // so we enclose them in the following #if-block to reduce compile times.
449
450#if defined(FEAT_HAVE_MPI) || defined(DOXYGEN)
451
458 virtual void _create_single_layered(std::unique_ptr<MeshNodeType> base_mesh_node)
459 {
460 // create and push single layer
461 std::shared_ptr<LayerType> layer = std::make_shared<LayerType>(this->_comm.comm_dup(), 0);
462 this->push_layer(layer);
463
464 // create single-layered ancestry
466 Ancestor& ancestor = this->_ancestry.front();
467
468 // do we have to keep the base-mesh levels on this process?
469 const bool keep_base = this->_keep_base_levels && (this->_comm.rank() == 0);
470
471 // choose a partitioning strategy
472 this->_check_parti(ancestor, *base_mesh_node, true);
473
474 // refine up to chosen partition level
475 int lvl = 0;
476 for(; lvl < ancestor.parti_level; ++lvl)
477 {
478 // refine the base mesh
479 base_mesh_node = base_mesh_node->refine_unique(this->_adapt_mode);
480 }
481
482 // apply partitioner
483 if(!this->_apply_parti(ancestor, *base_mesh_node))
484 {
485 XABORTM("Failed to find a suitable partitioning");
486 }
487
488 // extract our patch
489 std::vector<int> neighbor_ranks;
490 std::unique_ptr<MeshNodeType> patch_mesh_node(
491 base_mesh_node->extract_patch(neighbor_ranks, ancestor.parti_graph, this->_comm.rank()));
492
493 // set the neighbor ranks of our child layer
494 layer->set_neighbor_ranks(neighbor_ranks);
495
496 // if we have to keep the base-mesh levels, then we also need the patches
497 if(keep_base)
498 {
499 // Note: patch mesh-part for rank = 0 was already created by 'extract_patch' call
500 for(int i(1); i < ancestor.num_parts; ++i)
501 {
502 base_mesh_node->create_patch_meshpart(ancestor.parti_graph, i);
503 }
504 }
505
506 // refine up to minimum level
507 for(; lvl < ancestor.desired_level_min; ++lvl)
508 {
509 // refine the patch mesh
510 patch_mesh_node = patch_mesh_node->refine_unique(this->_adapt_mode);
511
512 // keep base mesh node?
513 if(keep_base)
514 base_mesh_node = base_mesh_node->refine_unique(this->_adapt_mode);
515 }
516
517 // save chosen minimum level
518 if(lvl < ancestor.desired_level_max)
519 this->_chosen_levels.push_front(std::make_pair(lvl, 0));
520
521 // refine up to maximum level
522 for(; lvl < ancestor.desired_level_max; ++lvl)
523 {
524 // refine the patch mesh
525 auto refined_node = patch_mesh_node->refine_unique(this->_adapt_mode);
526
527 // push this (unrefined) level
528 this->push_level_front(0, std::make_shared<LevelType>(lvl, std::move(patch_mesh_node)));
529
530 // continue with refined node
531 patch_mesh_node = std::move(refined_node);
532
533 // keep base mesh node?
534 if(keep_base)
535 {
536 // refine base-mesh node
537 auto refined_base_mesh_node = base_mesh_node->refine_unique(this->_adapt_mode);
538
539 // push this (unrefined) level
540 this->_base_levels.push_front(std::make_shared<LevelType>(lvl, std::move(base_mesh_node)));
541
542 // continue with refined node
543 base_mesh_node = std::move(refined_base_mesh_node);
544 }
545 }
546
547 // save chosen maximum level
548 this->_chosen_levels.push_front(std::make_pair(lvl, this->_comm.size()));
549
550 // push finest level
551 this->push_level_front(0, std::make_shared<LevelType>(lvl, std::move(patch_mesh_node)));
552
553 // keep base mesh node?
554 if(keep_base)
555 this->_base_levels.push_front(std::make_shared<LevelType>(lvl, std::move(base_mesh_node)));
556 }
557
564 virtual void _create_multi_layered(std::unique_ptr<MeshNodeType> base_mesh_node)
565 {
566 // create layers
568
569 // create ancestry
571
572 // do we have to keep the base-mesh levels on this process?
573 const bool keep_base = this->_keep_base_levels && (this->_comm.rank() == 0);
574
575 // make sure we have at most 2 layers if we want to keep the base-mesh levels
576 XASSERTM(!keep_base || (this->_ancestry.size() <= std::size_t(1)), "cannot keep base levels for more than 2 domain layers (yet)");
577
578 // we start counting at level 0
579 int lvl = 0;
580
581 // move the base-mesh pointer to a new parent-mesh pointer;
582 // the base-mesh is always the one on the layer with only 1 process
583 std::unique_ptr<MeshNodeType> parent_mesh_node = std::move(base_mesh_node);
584 base_mesh_node.reset();
585
586 // loop over all global layers in reverse order (coarse to fine)
587 for(std::size_t slayer = this->_ancestry.size(); slayer > std::size_t(0); )
588 {
589 // is this the base-mesh layer aka the 1-process layer?
590 const bool is_base_layer = (slayer == this->_ancestry.size());
591
592 --slayer;
593
594 // get the ancestor object
595 Ancestor& ancestor = this->_ancestry.at(slayer);
596
597 // determine the minimum desired level of our parent layer
598 int parent_min_lvl = -1;
599 if(!is_base_layer)
600 parent_min_lvl = this->_chosen_levels.front().first;
601 else if(this->_ancestry.size() + 1u < this->_desired_levels.size())
602 parent_min_lvl = this->_desired_levels.back().first;
603
604 // check available partitioning strategies
605 this->_check_parti(ancestor, *parent_mesh_node, is_base_layer);
606
607 // the check_parti function returns the partitioning level w.r.t. the current
608 // level (which may be > 0), so we have to compensate that by adding our current level:
609 ancestor.parti_level += lvl;
610
611 // Note: each progeny group within the main communicator may have chosen a different
612 // partitioning level at this point. We will compensate this by adjusting the minimum
613 // refinement level of the child layer after the partitioning step below.
614
615 // refine up to the chosen partitioning level
616 for(; lvl < ancestor.parti_level; ++lvl)
617 {
618 // refine the base-mesh node
619 auto refined_node = parent_mesh_node->refine_unique(this->_adapt_mode);
620
621 // push the base mesh into our parent layer if desired
622 if((ancestor.layer_p >= 0) && (parent_min_lvl >= 0) && (lvl >= parent_min_lvl))
623 {
624 this->push_level_front(ancestor.layer_p, std::make_shared<LevelType>(lvl, std::move(parent_mesh_node)));
625 }
626
627 // continue with refined node
628 parent_mesh_node = std::move(refined_node);
629
630 // refine base-mesh node if we have one
631 if(base_mesh_node)
632 {
633 // refine base-mesh node
634 auto refined_base_mesh_node = base_mesh_node->refine_unique(this->_adapt_mode);
635
636 // push this (unrefined) level
637 this->_base_levels.push_front(std::make_shared<LevelType>(lvl, std::move(base_mesh_node)));
638
639 // continue with refined node
640 base_mesh_node = std::move(refined_base_mesh_node);
641 }
642 }
643
644 // we're now at the partitioning level, so apply the partitioner
645 if(!this->_apply_parti(ancestor, *parent_mesh_node))
646 {
647 XABORTM("Failed to find a suitable partitioning");
648 }
649
650 // extract our patch
651 std::vector<int> neighbor_ranks;
652 std::unique_ptr<MeshNodeType> patch_mesh_node(
653 parent_mesh_node->extract_patch(neighbor_ranks, ancestor.parti_graph, ancestor.progeny_child));
654
655 // translate neighbor ranks by progeny group to obtain the neighbor ranks
656 // w.r.t. this layer's communicator
657 {
658 std::map<int,int> halo_map;
659 for(auto& i : neighbor_ranks)
660 {
661 int old_i(i);
662 halo_map.emplace(old_i, i += ancestor.progeny_group);
663 }
664 patch_mesh_node->rename_halos(halo_map);
665 }
666
667 // does this process participate in the parent layer or do we need to keep the base-meshes anyways?
668 if((ancestor.layer_p >= 0) || (keep_base && is_base_layer))
669 {
670 // Note: patch mesh-part for rank = 0 was already created by 'extract_patch' call
671 for(int i(1); i < ancestor.num_parts; ++i)
672 {
673 parent_mesh_node->create_patch_meshpart(ancestor.parti_graph, i);
674 }
675 }
676
677 // make sure we choose the same minimum level for all processes, because we may
678 // have chosen different partitioning levels for each patch
679 int global_level_min = Math::max(ancestor.desired_level_min, ancestor.parti_level);
680 this->_comm.allreduce(&global_level_min, &global_level_min, std::size_t(1), Dist::op_max);
681
682 // make sure our minimum level is greater than the minimum level of the previous layer,
683 // because each layer must contain at least one non-ghost level
684 if(!is_base_layer)
685 global_level_min = Math::max(global_level_min, this->_chosen_levels.front().first+1);
686
687 // refine up to desired minimum level of this layer
688 for(; lvl < global_level_min; ++lvl)
689 {
690 // refine the base mesh node
691 std::unique_ptr<MeshNodeType> coarse_mesh_node(std::move(parent_mesh_node));
692 parent_mesh_node = coarse_mesh_node->refine_unique(this->_adapt_mode);
693
694 // push base mesh to parent layer if desired
695 if((ancestor.layer_p >= 0) && (parent_min_lvl >= 0) && (lvl >= parent_min_lvl))
696 {
697 // clear patches before pushing this node as they are redundant here
698 coarse_mesh_node->clear_patches();
699 this->push_level_front(ancestor.layer_p, std::make_shared<LevelType>(lvl, std::move(coarse_mesh_node)));
700 }
701
702 // refine the patch mesh
703 patch_mesh_node = patch_mesh_node->refine_unique(this->_adapt_mode);
704
705 // refine base-mesh node if we have one
706 if(base_mesh_node)
707 {
708 // refine base-mesh node
709 auto refined_base_mesh_node = base_mesh_node->refine_unique(this->_adapt_mode);
710
711 // push this (unrefined) level
712 this->_base_levels.push_front(std::make_shared<LevelType>(lvl, std::move(base_mesh_node)));
713
714 // continue with refined node
715 base_mesh_node = std::move(refined_base_mesh_node);
716 }
717 }
718
719 // split the halos of our base-mesh and compute the halos of our patches from that
720 this->_split_basemesh_halos(ancestor, *parent_mesh_node, *patch_mesh_node, neighbor_ranks);
721
722 // does this process participate in the child layer?
723 if(ancestor.layer >= 0)
724 {
725 // set the neighbor ranks in our child layer
726 this->_layers.at(std::size_t(ancestor.layer))->set_neighbor_ranks(neighbor_ranks);
727 }
728
729 // set chosen minimum level for this layer
730 if(!is_base_layer)
731 this->_chosen_levels.push_front(std::make_pair(lvl, this->_ancestry.at(slayer+1u).num_procs));
732 else if(parent_min_lvl < 0)
733 this->_chosen_levels.push_front(std::make_pair(lvl, 0));
734 else
735 {
736 this->_chosen_levels.push_front(std::make_pair(parent_min_lvl, 0));
737 this->_chosen_levels.push_front(std::make_pair(lvl, 1));
738 }
739
740 // if we have to keep the base-mesh, then we have to create a clone here if we're still on the base layer;
741 // we don't need to worry that this is a clone, because it will get refined in the next layer anyways
742 if(keep_base && is_base_layer)
743 {
744 XASSERT(base_mesh_node.get() == nullptr);
745 base_mesh_node = parent_mesh_node->clone_unique();
746 }
747
748 // push the finest base-mesh
749 if(ancestor.layer_p >= 0)
750 {
751 this->push_level_front(ancestor.layer_p, std::make_shared<LevelType>(lvl, std::move(parent_mesh_node)));
752 }
753
754 // continue with the next layer
755 parent_mesh_node = std::move(patch_mesh_node);
756 }
757
758 // get the desired maximum level
759 // if we have more than one layer, make sure that the finest one contains at
760 // least one level, as otherwise the finest global level would be a ghost level
761 int desired_level_max = Math::max(this->_ancestry.front().desired_level_max, lvl+1);
762
763 for(; lvl < desired_level_max; ++lvl)
764 {
765 // refine the patch mesh
766 auto refined_node = parent_mesh_node->refine_unique(this->_adapt_mode);
767
768 // push patch mesh to this level
769 this->push_level_front(0, std::make_shared<LevelType>(lvl, std::move(parent_mesh_node)));
770
771 // continue with refined node
772 parent_mesh_node = std::move(refined_node);
773
774 // refine base-mesh node if we have one
775 if(base_mesh_node)
776 {
777 // refine base-mesh node
778 auto refined_base_mesh_node = base_mesh_node->refine_unique(this->_adapt_mode);
779
780 // push this (unrefined) level
781 this->_base_levels.push_front(std::make_shared<LevelType>(lvl, std::move(base_mesh_node)));
782
783 // continue with refined node
784 base_mesh_node = std::move(refined_base_mesh_node);
785 }
786 }
787
788 // push finest level
789 this->push_level_front(0, std::make_shared<LevelType>(lvl, std::move(parent_mesh_node)));
790
791 // set chosen maximum level for finest layer
792 this->_chosen_levels.push_front(std::make_pair(lvl, this->_comm.size()));
793
794 // refine base-mesh node if we have one
795 if(base_mesh_node)
796 this->_base_levels.push_front(std::make_shared<LevelType>(lvl, std::move(base_mesh_node)));
797 }
798
824 virtual bool _check_parti(Ancestor& ancestor, const MeshNodeType& mesh_node, bool is_base_layer) override
825 {
826 // Try to find an appropriate a-priori partitioning first:
827 if(is_base_layer && this->_check_parti_extern(ancestor))
828 return true;
829
830 if(this->_check_parti_2level(ancestor, mesh_node))
831 return true;
832
833 // call base class
834 return BaseClass::_check_parti(ancestor, mesh_node, is_base_layer);
835 }
836
847 {
848 // is this even allowed?
849 if(!this->_allow_parti_extern)
850 return false;
851
852 // check whether we have a suitable partition
853 const Geometry::Partition* part = this->_parti_set.find_partition(ancestor.num_parts, _extern_parti_names);
854 if(part == nullptr)
855 return false;
856
857 // set our ancestor partitioning
858 ancestor.parti_apriori = true;
859 ancestor.parti_info = String("Found extern partition '") + part->get_name() + "'";
860 ancestor.parti_level = part->get_level();
861 ancestor.parti_graph = part->get_patches().clone();
862 return true;
863 }
864
877 bool _check_parti_2level(Ancestor& ancestor, const MeshNodeType& base_mesh_node)
878 {
879 // is this even allowed?
880 if(!this->_allow_parti_2level)
881 return false;
882
883 // create a 2-level partitioner
884 Geometry::Parti2Lvl<MeshType> partitioner(*base_mesh_node.get_mesh(), Index(ancestor.num_parts));
885
886 // successful?
887 if(!partitioner.success())
888 return false;
889
890 // found a valid 2-level partitioning
891 ancestor.parti_apriori = true;
892 ancestor.parti_info = String("Found 2-level partition");
893 ancestor.parti_level = int(partitioner.parti_level());
894 ancestor.parti_graph = partitioner.build_elems_at_rank();
895 return true;
896 }
897#endif // defined(FEAT_HAVE_MPI) || defined(DOXYGEN)
898 }; // class PartiDomainControl<...>
899 } // namespace Domain
900 } // namespace Control
901} // namespace FEAT
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
FEAT Kernel base header.
Graph clone() const
Clones this graph.
Definition: graph.hpp:311
bool _keep_base_levels
keep base-mesh levels on root process?
bool parti_apriori
specifies whether the chosen partitioning is an a-priori partitioning strategy
int desired_level_max
the desired minimum and maximum refinement levels for this layer
int parti_level
the refinement level on which the patch is to be partitioned
String parti_info
a string containing some information about the chosen partitioning
Adjacency::Graph parti_graph
this is the actual elements-at-rank partitioning graph
int layer_p
the index of the parent layer or -1, if this process is not part of the parent layer
int layer
the index of the layer that this ancestor object belongs to
int num_parts
the number of partitions for each patch of the parent layer
int progeny_child
Which direct child this process belongs to in its progeny group.
Base-Class for Hierarchical Domain Control implementations.
virtual void _reset_parti_types()
Resets/disables all partitioner types.
std::deque< std::pair< int, int > > _desired_levels
desired level deque
std::deque< std::pair< int, int > > _chosen_levels
chosen level deque
virtual void _create_ancestry_scattered()
Creates the layers for a multi-layered domain control in a scattered fashion.
Real WeightType
weight type for partitioner element weights; always Real
std::deque< Ancestor > _ancestry
the partition ancestry deque
virtual bool parse_args(SimpleArgParser &args)
Parses the partitioner options from an argument parser.
Geometry::RootMeshNode< MeshType > MeshNodeType
our root mesh node type
virtual bool _parse_parti_type(const String &type)
Parses a partitioner type.
LevelType::PartType MeshPartType
our mesh-part type
virtual void _create_ancestry_single()
Creates the ancestry for a single layer (or a single process)
Geometry::AdaptMode _adapt_mode
the adapt mode for refinement
bool _was_created
specifies whether the domain control was already created
virtual bool parse_property_map(const PropertyMap &pmap)
Parses the partitioner options from a PropertyMap.
virtual bool _check_parti(Ancestor &ancestor, const MeshNodeType &mesh_node, bool is_base_layer)
Checks for an appropriate partitioning strategy.
bool _support_multi_layered
support multi-layered hierarchy?
virtual bool _apply_parti(Ancestor &ancestor, MeshNodeType &base_mesh_node)
Applies an a-posteriori partitioner.
virtual void _create_multi_layers_scattered()
Creates the layers for a multi-layered domain control in a scattered fashion.
virtual void _split_basemesh_halos(const Ancestor &ancestor, const MeshNodeType &base_mesh_node, MeshNodeType &patch_mesh_node, std::vector< int > &neighbor_ranks)
Splits the base-mesh halos and computes the inter-patch-mesh halos.
Recursively Partitioned Domain Control.
PartiDomainControl(const Dist::Comm &comm_, bool support_multi_layered)
Constructor.
bool _allow_parti_extern
allow extern partitioner?
virtual void _create(std::unique_ptr< MeshNodeType > base_mesh_node)
Creates a domain control from a base-mesh node.
virtual void create_rectilinear(Index num_elems_x, Index num_elems_y=0u, Index num_elems_z=0u)
Creates a domain control from a structured rectilinear base mesh.
virtual bool _parse_parti_type(const String &type) override
Parses a partitioner type.
virtual void _create_multi_layered(std::unique_ptr< MeshNodeType > base_mesh_node)
Creates a multi-layered mesh hierarchy.
Geometry::PermutationStrategy get_permutation_strategy() const
bool _allow_parti_2level
allow 2-level partitioner?
Geometry::PartitionSet _parti_set
the extern partition sets
Control::Domain::PartiDomainControlBase< DomainLevel_ > BaseClass
Our base class.
Geometry::PermutationStrategy _permutation_strategy
the permutation strategy for the mesh permutation
virtual void _create_single_process(std::unique_ptr< MeshNodeType > base_mesh_node)
Creates a single-layered mesh hierarchy for a single process.
virtual void _create_single_layered(std::unique_ptr< MeshNodeType > base_mesh_node)
Creates a single-layered mesh hierarchy.
virtual bool parse_args(SimpleArgParser &args) override
Parses the partitioner options from an argument parser.
bool _check_parti_2level(Ancestor &ancestor, const MeshNodeType &base_mesh_node)
Checks whether the 2-level partitioner can be applied.
virtual void create(Geometry::MeshFileReader &mesh_reader)
Creates a domain control from a MeshFileReader.
virtual void create(std::unique_ptr< MeshNodeType > base_mesh_node)
Creates a domain control from a base-mesh node.
virtual void create_mesh_permutations()
Creates the mesh permutations based on the chosen permutation strategy.
void set_permutation_strategy(Geometry::PermutationStrategy strategy)
Sets the permutation strategy for mesh permutation.
bool _check_parti_extern(Ancestor &ancestor)
Checks whether an extern partition is given.
virtual void create(const std::deque< String > &filenames, String dirpath="")
Creates a domain control from a list of filenames.
std::deque< String > _extern_parti_names
required partition name for extern partitioning
virtual void _reset_parti_types() override
Resets/disables all partitioner types.
virtual bool _check_parti(Ancestor &ancestor, const MeshNodeType &mesh_node, bool is_base_layer) override
Checks for an appropriate partitioning strategy.
virtual bool parse_property_map(const PropertyMap &pmap) override
Parses the partitioner options from a PropertyMap.
Communicator class.
Definition: dist.hpp:1349
void allreduce(const void *sendbuf, void *recvbuf, std::size_t count, const Datatype &datatype, const Operation &op) const
Blocking All-Reduce.
Definition: dist.cpp:655
int size() const
Returns the size of this communicator.
Definition: dist.hpp:1506
Comm comm_dup() const
Creates a copy of this communicator.
Definition: dist.cpp:459
int rank() const
Returns the rank of this process in this communicator.
Definition: dist.hpp:1494
BoundaryFactory implementation.
void add_mesh_files(const Dist::Comm &comm, const std::deque< String > &filenames, String dirpath="")
Adds a list of mesh files to the list of streams to be parsed.
void parse(MeshNodeLinker< RootMesh_ > &linker, RootMeshNode< RootMesh_ > &root_mesh_node, MeshAtlas< RootMesh_ > &mesh_atlas, PartitionSet *part_set=nullptr)
Parses the mesh file into a mesh node and a mesh atlas.
MeshType * get_mesh()
Returns the mesh of this node.
Definition: mesh_node.hpp:225
2-Level-Partitioner class template declaration
Definition: parti_2lvl.hpp:38
const Adjacency::Graph & get_patches() const
const Partition * find_partition(int size, const String &name="", int prio=0) const
Tries to find a suitable partition in the set.
static std::unique_ptr< RootMeshNode > make_unique(std::unique_ptr< MeshType > mesh, MeshAtlasType *atlas=nullptr)
Creates a new RootMeshNode on the heap and returns a unique pointer to it.
Definition: mesh_node.hpp:837
Structured unit-cube mesh factory.
A class organizing a tree of key-value pairs.
std::pair< String, bool > query(String key_path) const
Queries a value by its key path.
Simple argument parser implementation.
const std::pair< int, std::deque< String > > * query(const String &option) const
Query the parameters of an option.
void support(const String &option, const String &description=String())
Adds an option to the set of supported options.
static double toe_partition
time of partitioning in seconds, needs initialization
Definition: statistics.hpp:167
String class implementation.
Definition: string.hpp:47
int compare_no_case(const String &other) const
Compares two strings without regard to case.
Definition: string.hpp:680
Time stamp class.
Definition: time_stamp.hpp:54
double elapsed_now() const
Calculates the time elapsed between the time stamp and now.
Definition: time_stamp.hpp:121
void add_supported_pdc_args(SimpleArgParser &args)
Adds the supported arguments of the PartiDomainControl to an argument parser.
const Operation op_max(MPI_MAX)
Operation wrapper for MPI_MAX.
Definition: dist.hpp:273
PermutationStrategy
Mesh permutation strategy enumeration.
@ none
no permutation strategy
T_ max(T_ a, T_ b)
Returns the maximum of two values.
Definition: math.hpp:137
FEAT namespace.
Definition: adjactor.hpp:12
std::uint64_t Index
Index data type.