FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
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
8#include <kernel/geometry/mesh_node.hpp>
9#include <kernel/geometry/mesh_quality_heuristic.hpp>
10#include <kernel/util/dist.hpp>
12#include <kernel/util/math.hpp>
13
14#include <control/domain/domain_level.hpp>
15
16#include <vector>
17#include <deque>
18
19namespace FEAT
20{
24 namespace Control
25 {
29 namespace Domain
30 {
62 {
63 protected:
69 std::vector<int> _neighbor_ranks;
70
75
76 public:
77 explicit DomainLayer(Dist::Comm&& comm_, int lyr_idx) :
78 _layer_index(lyr_idx),
79 _comm(std::forward<Dist::Comm>(comm_)),
82 _parent_rank(-1)
83 {
84 }
85
86 DomainLayer(DomainLayer&& other) :
88 _comm(std::forward<Dist::Comm>(other._comm)),
89 _neighbor_ranks(std::forward<std::vector<int>>(other._neighbor_ranks)),
90 _sibling_comm(std::forward<Dist::Comm>(other._sibling_comm)),
92 {
93 }
94
95 virtual ~DomainLayer()
96 {
97 }
98
99 void set_parent(Dist::Comm&& sibling_comm_, int parent_rank)
100 {
101 _sibling_comm = std::forward<Dist::Comm>(sibling_comm_);
102 _parent_rank = parent_rank;
103 }
104
105 std::size_t bytes() const
106 {
107 return _neighbor_ranks.size() * sizeof(int);
108 }
109
110 const Dist::Comm& comm() const
111 {
112 return _comm;
113 }
114
115 const Dist::Comm* comm_ptr() const
116 {
117 return &_comm;
118 }
119
120 const Dist::Comm* sibling_comm_ptr() const
121 {
122 return &_sibling_comm;
123 }
124
125 bool is_child() const
126 {
127 return (_sibling_comm.size() > 0);
128 }
129
130 bool is_parent() const
131 {
132 return (_sibling_comm.rank() == _parent_rank);
133 }
134
135 bool is_ghost() const
136 {
137 return is_child() && !is_parent();
138 }
139
140 int get_layer_index() const
141 {
142 return _layer_index;
143 }
144
145 int get_parent_rank() const
146 {
147 return _parent_rank;
148 }
149
150 Index child_count() const
151 {
152 return Index(_sibling_comm.size());
153 }
154
155 Index neighbor_count() const
156 {
157 return Index(_neighbor_ranks.size());
158 }
159
160 void push_neighbor(int neighbor_rank_)
161 {
162 _neighbor_ranks.push_back(neighbor_rank_);
163 }
164
165 int neighbor_rank(Index i) const
166 {
167 return _neighbor_ranks.at(std::size_t(i));
168 }
169
170 void set_neighbor_ranks(const std::vector<int>& neighbors)
171 {
172 _neighbor_ranks = neighbors;
173 }
174
175 const std::vector<int>& get_neighbor_ranks() const
176 {
177 return _neighbor_ranks;
178 }
179 }; // class DomainLayer
180
188 {
190 normal,
192 parent,
194 child,
196 base
197 };
198
214 template<typename DomLvl_>
216 {
217 public:
218 typedef DomainLayer LayerType;
219 typedef DomLvl_ LevelType;
220
221 protected:
222 std::shared_ptr<LevelType> _level;
223 std::shared_ptr<LevelType> _level_child;
224 std::shared_ptr<LevelType> _level_parent;
225 std::shared_ptr<LevelType> _level_base;
226 std::shared_ptr<LayerType> _layer;
227 std::shared_ptr<LayerType> _layer_child;
228 std::shared_ptr<LayerType> _layer_parent;
229 bool _has_base;
230
231 public:
232 explicit VirtualLevel(std::shared_ptr<LevelType> level_, std::shared_ptr<LayerType> layer_) :
233 _level(level_),
234 _level_child(),
235 _level_parent(),
236 _level_base(),
237 _layer(layer_),
238 _layer_child(),
239 _layer_parent(),
240 _has_base(false)
241 {
242 }
243
244 explicit VirtualLevel(
245 std::shared_ptr<LevelType> level_child_,
246 std::shared_ptr<LayerType> layer_child_,
247 std::shared_ptr<LevelType> level_parent_,
248 std::shared_ptr<LayerType> layer_parent_) :
249 _level(level_parent_ ? level_parent_ : level_child_),
250 _level_child(level_child_),
251 _level_parent(level_parent_),
252 _level_base(),
253 _layer(layer_parent_ ? layer_parent_ : layer_child_),
254 _layer_child(layer_child_),
255 _layer_parent(layer_parent_),
256 _has_base(false)
257 {
258 XASSERT(bool(_level_child));
259 XASSERT(bool(_layer_child));
260 XASSERT(_layer_child->is_child());
261
262 if(_level_parent)
263 {
264 XASSERT(bool(_layer_parent));
265 XASSERT(_layer_child->is_parent());
266 XASSERT(_level_child->get_level_index() == _level_parent->get_level_index());
267 }
268 else
269 {
270 XASSERT(!bool(_layer_parent));
271 }
272 }
273
274 VirtualLevel(VirtualLevel&&) = default;
275 VirtualLevel& operator=(VirtualLevel&&) = default;
276 VirtualLevel(const VirtualLevel&) = delete;
277 VirtualLevel& operator=(const VirtualLevel&) = delete;
278 virtual ~VirtualLevel() = default;
279
280 bool is_child() const
281 {
282 return bool(_level_child);
283 }
284
285 bool is_parent() const
286 {
287 return bool(_level_parent);
288 }
289
290 bool is_ghost() const
291 {
292 return is_child() && !is_parent();
293 }
294
295 bool has_base() const
296 {
297 return _has_base;
298 }
299
300 void set_base(std::shared_ptr<LevelType> level_base_)
301 {
302 _level_base = level_base_;
303 _has_base = true;
304 }
305
306 void set_base()
307 {
308 _has_base = true;
309 }
310
311 LevelType& operator*()
312 {
313 return *_level;
314 }
315
316 const LevelType& operator*() const
317 {
318 return *_level;
319 }
320
321 LevelType* operator->()
322 {
323 return _level.get();
324 }
325
326 const LevelType* operator->() const
327 {
328 return _level.get();
329 }
330
331 LevelType& level()
332 {
333 return *_level;
334 }
335
336 const LevelType& level() const
337 {
338 return *_level;
339 }
340
341 LayerType& layer()
342 {
343 return *_layer;
344 }
345
346 const LayerType& layer() const
347 {
348 return *_layer;
349 }
350
351 LevelType& level_c()
352 {
353 XASSERT(bool(_level_child));
354 return *_level_child;
355 }
356
357 const LevelType& level_c() const
358 {
359 XASSERT(bool(_level_child));
360 return *_level_child;
361 }
362
363 LayerType& layer_c()
364 {
365 XASSERT(bool(_layer_child));
366 return *_layer_child;
367 }
368
369 const LayerType& layer_c() const
370 {
371 XASSERT(bool(_layer_child));
372 return *_layer_child;
373 }
374
375 LevelType& level_p()
376 {
377 XASSERT(bool(_level_parent));
378 return *_level_parent;
379 }
380
381 const LevelType& level_p() const
382 {
383 XASSERT(bool(_level_parent));
384 return *_level_parent;
385 }
386
387 LayerType& layer_p()
388 {
389 XASSERT(bool(_layer_parent));
390 return *_layer_parent;
391 }
392
393 const LayerType& layer_p() const
394 {
395 XASSERT(bool(_layer_parent));
396 return *_layer_parent;
397 }
398
399 LevelType& level_b()
400 {
401 XASSERT(bool(_level_base));
402 return *_level_base;
403 }
404
405 const LevelType& level_b() const
406 {
407 XASSERT(bool(_level_base));
408 return *_level_base;
409 }
410
423 template<typename Lambda_>
424 void apply_lambda(Lambda_&& lambda)
425 {
426 if(_level_parent)
427 lambda(*_level_parent, *_layer_parent, VirtualLevelLambda::parent);
428 if(_level_child)
429 lambda(*_level_child, *_layer_child, VirtualLevelLambda::child);
430 else
431 lambda(*_level, *_layer, VirtualLevelLambda::normal);
432 if(_level_base)
433 lambda(*_level_base, *_layer, VirtualLevelLambda::base);
434 }
435
436 std::size_t bytes() const
437 {
438 std::size_t b(0u);
439 if(_level_base)
440 b += _level_base->bytes();
441 if(is_parent())
442 return b + this->_level_child->bytes() + this->_layer_parent->bytes();
443 else if(is_child())
444 return b + this->_level_child->bytes();
445 else
446 return b + this->_level->bytes();
447 }
448 }; // class VirtualLevel<...>
449
455 template<typename DomLvl_>
457 {
458 public:
459 typedef DomLvl_ LevelType;
460 typedef DomainLayer LayerType;
462
463 typedef typename LevelType::ShapeType ShapeType;
464 typedef typename LevelType::MeshType MeshType;
465 typedef typename LevelType::MeshNodeType MeshNodeType;
467
468 protected:
469 const Dist::Comm& _comm;
470 AtlasType _atlas;
471 std::deque<std::shared_ptr<LayerType>> _layers;
472 std::deque<std::shared_ptr<LevelType>> _base_levels;
473 std::deque<std::deque<std::shared_ptr<LevelType>>> _layer_levels;
474 std::deque<VirtLevelType> _virt_levels;
475 std::size_t _num_global_layers;
476 std::size_t _virt_size;
477
480
481 public:
482 explicit DomainControl(const Dist::Comm& comm_) :
483 _comm(comm_),
484 _num_global_layers(0u),
485 _virt_size(0u),
486 _keep_base_levels(false)
487 {
488 }
489
490 virtual ~DomainControl()
491 {
492 }
493
494 static String name()
495 {
496 return "DomainControl<"+MeshType::name()+">";
497 }
498
499 virtual void print() const
500 {
501 Index pad_width(30);
502 String msg;
503
504 XASSERT(!_layers.empty());
505
506 msg = String("num_levels").pad_back(pad_width, '.') + String(": ") + stringify(size_physical());
507 _comm.print(msg);
508
509 const auto& my_mesh = front()->get_mesh();
510 Index ncells(my_mesh.get_num_entities(MeshType::shape_dim));
511 _comm.allreduce(&ncells, &ncells, std::size_t(1), Dist::op_sum);
512
513 msg = String("Cells on level "+stringify(max_level_index()).pad_back(pad_width, '.'))
514 + String(": ") + stringify(ncells);
515 _comm.print(msg);
516 }
517
518 const Dist::Comm& comm() const
519 {
520 return _comm;
521 }
522
523 std::size_t bytes() const
524 {
525 std::size_t s = _atlas.bytes();
526 for(const auto& lyr : _layers)
527 s += lyr->bytes();
528 for(const auto& lyr_lvl : _layer_levels)
529 for(const auto& lvl : lyr_lvl)
530 s += lvl->bytes();
531 return s;
532 }
533
534 std::size_t num_local_layers() const
535 {
536 return _layers.size();
537 }
538
539 std::size_t num_global_layers() const
540 {
541 return _num_global_layers;
542 }
543
544 void push_layer(std::shared_ptr<LayerType> layer)
545 {
546 // make sure that the layer index is valid
547 if(!_layers.empty())
548 {
549 XASSERT((_layers.back()->get_layer_index()+1) == layer->get_layer_index());
550 }
551 _layers.push_back(layer);
552 _layer_levels.push_back(std::deque<std::shared_ptr<LevelType>>());
553 }
554
555 LayerType& front_layer()
556 {
557 return *_layers.front();
558 }
559
560 const LayerType& front_layer() const
561 {
562 return *_layers.front();
563 }
564
565 LayerType& back_layer()
566 {
567 return *_layers.back();
568 }
569
570 const LayerType& back_layer() const
571 {
572 return *_layers.back();
573 }
574
575 int min_level_index() const
576 {
577 return _virt_levels.back()->get_level_index();
578 }
579
580 int max_level_index() const
581 {
582 return _virt_levels.front()->get_level_index();
583 }
584
585 int med_level_index() const
586 {
587 return (_layer_levels.size() < std::size_t(2) ? -1 : _layer_levels.front().back()->get_level_index());
588 }
589
590 void push_level_front(int layer_index, std::shared_ptr<LevelType> level)
591 {
592 _layer_levels.at(std::size_t(layer_index)).push_front(level);
593 }
594
595 void push_level_back(int layer_index, std::shared_ptr<LevelType> level)
596 {
597 _layer_levels.at(std::size_t(layer_index)).push_back(level);
598 }
599
600 bool has_ghost() const
601 {
603 return _virt_size < _virt_levels.size();
604 /*if(_virt_levels.empty())
605 return false;
606 else
607 return _virt_levels.back().is_ghost();*/
608 }
609
610 std::size_t size_virtual() const
611 {
612 return _virt_size;
613 }
614
615 std::size_t size_physical() const
616 {
617 if(_virt_levels.empty())
618 return std::size_t(0);
619 else if(_virt_levels.back().is_ghost())
620 return _virt_levels.size() - std::size_t(1);
621 else
622 return _virt_levels.size();
623 }
624
625 VirtLevelType& at(std::size_t i)
626 {
627 return _virt_levels.at(i);
628 }
629
630 const VirtLevelType& at(std::size_t i) const
631 {
632 return _virt_levels.at(i);
633 }
634
635 VirtLevelType& front()
636 {
637 return _virt_levels.front();
638 }
639
640 const VirtLevelType& front() const
641 {
642 return _virt_levels.front();
643 }
644
645 VirtLevelType& back()
646 {
647 return _virt_levels.back();
648 }
649
650 const VirtLevelType& back() const
651 {
652 return _virt_levels.back();
653 }
654
655 AtlasType& get_atlas()
656 {
657 return _atlas;
658 }
659
660 const AtlasType& get_atlas() const
661 {
662 return _atlas;
663 }
664
679 {
680 this->_keep_base_levels = true;
681 }
682
683 void compile_virtual_levels()
684 {
685 // get number of layers of this process
686 std::size_t my_num_layers = _layers.size();
687
688 // get global maximum of all layer sizes
689 _comm.allreduce(&my_num_layers, &_num_global_layers, std::size_t(1), Dist::op_max);
690
691 // clear virtual levels
692 _virt_levels.clear();
693
694 // push the finest level
695 _virt_levels.push_back(VirtLevelType(_layer_levels.front().front(), _layers.front()));
696
697 // do we have a base-level? If so, then set the base for the
699 {
700 if(!_base_levels.empty())
701 _virt_levels.front().set_base(_base_levels.front());
702 else
703 _virt_levels.front().set_base();
704 }
705
706 // loop over all layers, front to back
707 for(std::size_t ilay(0); ilay < _layers.size(); ++ilay)
708 {
709 // get the current layer
710 std::shared_ptr<LayerType>& layer = _layers.at(ilay);
711
712 // get the deque of the current layer's levels
713 std::deque<std::shared_ptr<LevelType>>& laylevs = _layer_levels.at(ilay);
714
715 // the front level has already been added
716 if(laylevs.size() <= std::size_t(1))
717 continue;
718
719 // push all inner layer levels
720 for(std::size_t ilev(1); (ilev+1) < laylevs.size(); ++ilev)
721 {
722 _virt_levels.push_back(VirtLevelType(laylevs.at(ilev), layer));
723
724 // push base-levels? (only for front layer)
725 if(_keep_base_levels && (ilay == std::size_t(0)))
726 {
727 if(!_base_levels.empty())
728 _virt_levels.back().set_base(_base_levels.at(ilev));
729 else
730 _virt_levels.back().set_base();
731 }
732 }
733
734 // push the last level
735 if((ilay+1) < _layers.size())
736 {
737 // that's an overlapping virtual mesh level with two physical mesh levels
738 _virt_levels.push_back(VirtLevelType(laylevs.back(), layer, _layer_levels.at(ilay+1).front(), _layers.at(ilay+1)));
739 }
740 else if(layer->is_child())
741 {
742 // that's a "ghost" virtual mesh level with only one physical mesh level on this process
743 _virt_levels.push_back(VirtLevelType(laylevs.back(), layer, nullptr, nullptr));
744 }
745 else
746 {
747 // that's a standard virtual mesh level with exactly one physical mesh level
748 _virt_levels.push_back(VirtLevelType(laylevs.back(), layer));
749 }
750
751 // push base-levels? (only for front layer)
752 if(_keep_base_levels && (ilay == std::size_t(0)))
753 {
754 if(!_base_levels.empty())
755 {
756 XASSERT(laylevs.size() == _base_levels.size());
757 _virt_levels.back().set_base(_base_levels.back());
758 }
759 else
760 _virt_levels.back().set_base();
761 }
762 }
763
764 // get virtual size of this process
765 std::size_t my_virt_size = _virt_levels.size();
766
767 // get global maximum of all virtual sizes
768 _comm.allreduce(&my_virt_size, &_virt_size, std::size_t(1), Dist::op_max);
769 }
770
771 void add_trafo_mesh_part_charts()
772 {
773 for(auto& bl : _base_levels)
774 bl->add_trafo_mesh_part_charts();
775 for(auto& ll : _layer_levels)
776 for(auto& l : ll)
777 l->add_trafo_mesh_part_charts();
778 /*for(auto it = _virt_levels.begin(); it != _virt_levels.end(); ++it)
779 {
780 if(it->is_parent())
781 it->level_p().add_trafo_mesh_part_charts();
782 if(it->is_child())
783 it->level_c().add_trafo_mesh_part_charts();
784 else
785 it->level().add_trafo_mesh_part_charts();
786 }*/
787 }
788
789 String dump_layers() const
790 {
791 String msg;
792 msg += "(" + stringify(_layers.size()) + "):";
793 for(std::size_t i(0); i < _layers.size(); ++i)
794 {
795 const auto& lyr = *_layers.at(i);
796 std::size_t np = std::size_t(Math::ilog10(lyr.comm().size()));
797 if(i > std::size_t(0))
798 msg += " |";
799 msg += " [" + stringify(lyr.comm().rank()).pad_front(np) + "]";
800 if(lyr.is_child())
801 {
802 std::size_t ns = std::size_t(Math::ilog10(lyr.comm().size()));
803 msg += " " + stringify(lyr.sibling_comm_ptr()->rank()).pad_front(ns);
804 msg += " {" + stringify(lyr.get_parent_rank()).pad_front(np);
805 msg += lyr.is_parent() ? "*}" : " }";
806 }
807 }
808 return msg;
809 }
810
811 String dump_layer_levels() const
812 {
813 String msg;
814 for(auto it = _layer_levels.begin(); it != _layer_levels.end(); ++it)
815 {
816 if(it != _layer_levels.begin())
817 msg += " |";
818 for(auto jt = it->begin(); jt != it->end(); ++jt)
819 msg += " " + stringify((*jt)->get_level_index());
820 }
821 return msg;
822 }
823
824 String dump_virt_levels() const
825 {
826 String msg;
827 for(auto it = _virt_levels.begin(); it != _virt_levels.end(); ++it)
828 {
829 std::size_t np = std::size_t(Math::ilog10((*it).layer().comm().size()));
830 if((*it).is_child())
831 np = std::size_t(Math::ilog10((*it).layer_c().comm().size()));
832 msg += " " + stringify((*it)->get_level_index());
833 msg += "[" + stringify((*it).layer().comm().size()).pad_front(np) + "]";
834 if((*it).is_child())
835 {
836 msg += " { " + stringify((*it).layer_c().get_parent_rank());
837 if((*it).is_parent())
838 msg += ":" + stringify((*it).layer_p().comm().rank()).pad_front(np) + "}";
839 else
840 msg += String(np+1, ' ') + "}";
841 }
842 }
843 return msg;
844 }
845 }; // class DomainControl<...>
846 } // namespace Domain
847 } // namespace Control
848} // namespace FEAT
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
Domain control base-class template.
void keep_base_levels()
Instructs the domain controller to keep the base-mesh levels after partitioning.
bool _keep_base_levels
keep base-mesh levels on root process?
Dist::Comm _sibling_comm
the sibling communicator
int _parent_rank
the rank of the parent in the sibling comm
std::vector< int > _neighbor_ranks
the ranks of the neighbor processes in this layer
Dist::Comm _comm
the communicator for this layer
Virtual Domain Level class template.
void apply_lambda(Lambda_ &&lambda)
Applies a lambda expression onto every level object in this virtual level.
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
int rank() const
Returns the rank of this process in this communicator.
Definition: dist.hpp:1494
void print(std::ostream &os, const String &msg, int root=0) const
Prints a message line to an output stream.
Definition: dist.cpp:782
Mesh Atlas class template.
Definition: mesh_atlas.hpp:32
std::size_t bytes() const
Definition: mesh_atlas.hpp:84
String class implementation.
Definition: string.hpp:46
String pad_back(size_type len, char c=' ') const
Pads the back of the string up to a desired length.
Definition: string.hpp:415
String pad_front(size_type len, char c=' ') const
Pads the front of the string up to a desired length.
Definition: string.hpp:392
VirtualLevelLambda
Virtual Level Lambda type enumeration.
@ child
indicates that the level is a child level
@ base
indicates that the level is a base level
@ parent
indicates that the level is a parent level
@ normal
indicates that the level is a normal level
const Operation op_max(MPI_MAX)
Operation wrapper for MPI_MAX.
Definition: dist.hpp:273
const Operation op_sum(MPI_SUM)
Operation wrapper for MPI_SUM.
Definition: dist.hpp:271
T_ ilog10(T_ x)
Computes the integral base-10 logarithm of an integer, i.e. its number of non-zero decimal digits.
Definition: math.hpp:231
FEAT namespace.
Definition: adjactor.hpp:12
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:944
std::uint64_t Index
Index data type.