CoMMA 1.3.2
A geometric agglomerator for unstructured meshes
Loading...
Searching...
No Matches
Dual_Graph.h
Go to the documentation of this file.
1#ifndef COMMA_PROJECT_DUAL_GRAPH_H
2#define COMMA_PROJECT_DUAL_GRAPH_H
3
4/*
5 * CoMMA
6 *
7 * Copyright © 2024 ONERA
8 *
9 * Authors: Nicolas Lantos, Alberto Remigi, and Riccardo Milani
10 * Contributors: Karim Anemiche
11 *
12 * This Source Code Form is subject to the terms of the Mozilla Public
13 * License, v. 2.0. If a copy of the MPL was not distributed with this
14 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
15 */
16
17#include <algorithm>
18#include <cassert>
19#include <climits>
20#include <deque>
21#include <functional>
22#include <limits>
23#include <set>
24#include <unordered_map>
25#include <unordered_set>
26#include <vector>
27
28#include "CoMMA/CoMMADefs.h"
29#include "CoMMA/Seeds_Pool.h"
30#include "CoMMA/Util.h"
31
32namespace comma {
33
42template<
43 typename CoMMAIndexType,
44 typename CoMMAWeightType,
45 typename CoMMAIntType>
46class Graph {
47public:
49 using ContainerIndexType = std::vector<CoMMAIndexType>;
51 using ContainerWeightType = std::vector<CoMMAWeightType>;
53 using ContainerIndexConstIt = typename ContainerIndexType::const_iterator;
55 using ContainerWeightConstIt = typename ContainerWeightType::const_iterator;
56
67 const CoMMAIndexType &nb_c,
68 const ContainerIndexType &m_crs_row_ptr,
69 const ContainerIndexType &m_crs_col_ind,
70 const ContainerWeightType &m_crs_values,
71 const ContainerWeightType &volumes
72 ) :
73 _number_of_cells(nb_c),
74 _m_CRS_Row_Ptr(m_crs_row_ptr),
75 _m_CRS_Col_Ind(m_crs_col_ind),
76 _m_CRS_Values(m_crs_values),
77 _volumes(volumes) {
79 fill(_visited.begin(), _visited.end(), false);
80 }
81
83 virtual ~Graph() = default;
84
87 CoMMAIndexType _number_of_cells;
88
90 std::vector<bool> _visited;
91
94
97
100
103
107 void DFS(const CoMMAIndexType &i_fc) {
108 _visited[i_fc] = true;
109 for (auto it = neighbours_cbegin(i_fc); it != neighbours_cend(i_fc); ++it) {
110 if (!_visited[*it]) {
111 DFS(*it);
112 }
113 }
114 }
115
119 void BFS(const CoMMAIndexType &root) {
120 std::deque<CoMMAIndexType> coda;
122 coda.push_back(root);
123 std::vector<bool> visited(_number_of_cells, false);
124 visited[root] = true;
125 std::vector<std::optional<CoMMAIndexType>> prev(
126 _number_of_cells, std::nullopt
127 );
128 while (!coda.empty()) {
129 CoMMAIndexType node = coda.front();
130 coda.pop_front();
131 for (auto it = neighbours_cbegin(node); it != neighbours_cend(node);
132 ++it) {
133 if (!visited[*it]) {
134 coda.push_pack(*it);
135 visited[*it] = true;
136 prev[it] = node;
137 }
138 }
139 }
140 // to print the inverse path
141 CoMMAIndexType retro = prev[_number_of_cells - 1];
142 while (retro.has_value()) {
143 path.push_back(retro);
144 retro = prev[retro];
145 }
146 reverse(path.begin(), path.end());
147 // for (CoMMAIntType i = 0; i < _number_of_cells; i++) {
148 // std::cout<<"BFS"<<path[i]<<std::endl;
149 // }
150 }
151
156 inline CoMMAIntType get_nb_of_neighbours(const CoMMAIndexType i_c) const {
157 // Return the number of neighbours of the ith cell
158 return _m_CRS_Row_Ptr[i_c + 1] - _m_CRS_Row_Ptr[i_c];
159 }
160
166 ContainerIndexType get_neighbours(const CoMMAIndexType &i_c) const {
167 // given the index of a cell return the neighbourhoods of this cell
168 CoMMAIndexType ind = _m_CRS_Row_Ptr[i_c];
169 CoMMAIndexType ind_p_one = _m_CRS_Row_Ptr[i_c + 1];
170 // insert the values of the CRS_value from begin+ind (pointed to the face)
171 // till the next pointed one, so related to all the connected areas (and
172 // hence to the faces)
173 ContainerIndexType result(
174 _m_CRS_Col_Ind.begin() + ind, _m_CRS_Col_Ind.begin() + ind_p_one
175 );
176 return result;
177 }
178
183 inline ContainerIndexConstIt neighbours_cbegin(const CoMMAIndexType &i_c
184 ) const {
185 return std::next(_m_CRS_Col_Ind.cbegin(), _m_CRS_Row_Ptr[i_c]);
186 }
187
193 inline ContainerIndexConstIt neighbours_cend(const CoMMAIndexType &i_c
194 ) const {
195 return std::next(_m_CRS_Col_Ind.cbegin(), _m_CRS_Row_Ptr[i_c + 1]);
196 }
197
204 inline ContainerWeightType get_weights(const CoMMAIndexType &i_c) const {
205 // Given the index of a cell, return the value of the faces connected
206 CoMMAIndexType ind = _m_CRS_Row_Ptr[i_c];
207 CoMMAIndexType ind_p_one = _m_CRS_Row_Ptr[i_c + 1];
208 // insert the values of the CRS_value from begin+ind (pointed to the face)
209 // till the next pointed one, so related to all the connected areas (and
210 // hence to the faces)
211 ContainerWeightType result(
212 _m_CRS_Values.begin() + ind, _m_CRS_Values.begin() + ind_p_one
213 );
214 return result;
215 }
216
221 inline ContainerWeightConstIt weights_cbegin(const CoMMAIndexType &i_c
222 ) const {
223 return std::next(_m_CRS_Values.cbegin(), _m_CRS_Row_Ptr[i_c]);
224 }
225
231 inline ContainerWeightConstIt weights_cend(const CoMMAIndexType &i_c) const {
232 return std::next(_m_CRS_Values.cbegin(), _m_CRS_Row_Ptr[i_c + 1]);
233 }
234
239 for (auto i = decltype(_number_of_cells){0}; i < _number_of_cells; ++i) {
240 _visited.push_back(false);
241 }
242 if (_number_of_cells == 1) {
243 return (true);
244 }
246 for (auto i = decltype(_number_of_cells){0}; i < _number_of_cells; ++i) {
247 if (!_visited[i]) {
248 return (false);
249 }
250 }
251 return (true);
252 }
253
259 const std::unordered_set<CoMMAIndexType> &s_fc
260 ) const {
261 // Compute Compactness of a cc
262 // Be careful: connectivity is assumed
263 if (s_fc.size() > 1) {
264 std::unordered_map<CoMMAIndexType, CoMMAIntType> dict_fc_compactness =
266 if (dict_fc_compactness.empty()) {
267 return 0;
268 }
269 return min_element(
270 dict_fc_compactness.begin(),
271 dict_fc_compactness.end(),
272 [](const auto &left, const auto &right) {
273 return left.second < right.second;
274 }
275 )->second;
276 }
277 return 0;
278 }
279
286 std::unordered_map<CoMMAIndexType, CoMMAIntType>
288 const std::unordered_set<CoMMAIndexType> &s_fc
289 ) const {
290 std::unordered_map<CoMMAIndexType, CoMMAIntType> dict_fc_compactness;
291 if (!s_fc.empty()) {
292 if (s_fc.size() == 1) {
293 dict_fc_compactness[*s_fc.begin()] = 0;
294 } else {
295 for (const CoMMAIndexType &i_fc : s_fc) {
296 dict_fc_compactness[i_fc] = count_if(
297 this->_m_CRS_Col_Ind.cbegin() + this->_m_CRS_Row_Ptr[i_fc],
298 this->_m_CRS_Col_Ind.cbegin() + this->_m_CRS_Row_Ptr[i_fc + 1],
299 [&](const auto &neigh) { return s_fc.count(neigh) > 0; }
300 );
301 }
302 }
303 }
304 return dict_fc_compactness;
305 }
306};
307
316template<
317 typename CoMMAIndexType,
318 typename CoMMAWeightType,
319 typename CoMMAIntType>
320class Subgraph : public Graph<CoMMAIndexType, CoMMAWeightType, CoMMAIntType> {
321public:
325 using typename BaseClass::ContainerIndexType;
327 using typename BaseClass::ContainerWeightType;
328
343 const CoMMAIndexType &nb_c,
344 const ContainerIndexType &m_crs_row_ptr,
345 const ContainerIndexType &m_crs_col_ind,
346 const ContainerWeightType &m_crs_values,
347 const ContainerWeightType &volumes,
348 const ContainerIndexType &mapping_l_to_g,
349 const bool &is_isotropic
350 ) :
351 Graph<CoMMAIndexType, CoMMAWeightType, CoMMAIntType>(
352 nb_c, m_crs_row_ptr, m_crs_col_ind, m_crs_values, volumes
353 ),
354 _is_isotropic(is_isotropic),
355 _cardinality(static_cast<CoMMAIntType>(nb_c)),
356 _mapping_l_to_g(mapping_l_to_g) {
357 // Compactness computation
358 _compactness = static_cast<CoMMAIntType>(nb_c);
359 for (auto c = decltype(nb_c){0}; c < nb_c; ++c) {
360 const auto n_neighs =
361 static_cast<CoMMAIntType>(m_crs_row_ptr[c + 1] - m_crs_row_ptr[c]);
362 if (n_neighs < _compactness) {
363 _compactness = n_neighs;
364 }
365 }
366 }
367
369 ~Subgraph() override = default;
370
373
377 CoMMAIntType _cardinality;
378
382 CoMMAIntType _compactness;
383
389
399 const ContainerIndexType &v_neigh,
400 const CoMMAIndexType &i_fc,
401 const CoMMAWeightType &volume,
402 const ContainerWeightType &weight
403 ) {
404 // Use the mapping
405 // local vector of neighbourhood
406 ContainerIndexType v_l_neigh{};
407 // @todo this solution clearly help in the connection of the subnode BUT can
408 // bring to instability and errors.
409 for (const auto &elem : v_neigh) {
410 const auto low1 =
411 std::find(_mapping_l_to_g.begin(), _mapping_l_to_g.end(), elem);
412 if (low1 != _mapping_l_to_g.end()) {
413 v_l_neigh.push_back(low1 - _mapping_l_to_g.begin());
414 }
415 }
416 // variable to add weight for each face
417 CoMMAIntType iter_weight = 0;
418 CoMMAIndexType local_index = this->_m_CRS_Row_Ptr.size() - 1;
419 // initialization pointers for insertion, pointing to the first element of
420 // each
421 auto row_end = this->_m_CRS_Row_Ptr.end() - 1;
422
423 // cycle on the set of neighbours
424 for (const auto &elem : v_l_neigh) {
425 // insert the node and the weight (we have an iterator for this and
426 // remember that at edge is associated one weight) look at here
427 // https://stackoverflow.com/questions/71299247/inserting-an-element-in-given-positions-more-than-one-of-a-vector/71299304#71299304
428 // to understand why we re-initialize.
429 this->_m_CRS_Col_Ind.insert(
430 this->_m_CRS_Col_Ind.begin() + this->_m_CRS_Row_Ptr[elem], local_index
431 );
432 this->_m_CRS_Values.insert(
433 this->_m_CRS_Values.begin() + this->_m_CRS_Row_Ptr[elem],
434 weight[iter_weight]
435 );
436 // We modify the row pointer as far it is related with what we have done
437 // before
438 for (auto it = this->_m_CRS_Row_Ptr.begin() + elem;
439 it != this->_m_CRS_Row_Ptr.end();
440 ++it) {
441 ++(*it);
442 }
443 // we do the same.
444 this->_m_CRS_Col_Ind.insert(this->_m_CRS_Col_Ind.end(), elem);
445 this->_m_CRS_Values.insert(
446 this->_m_CRS_Values.end(), weight[iter_weight]
447 );
448 // We increment the weight flag iterator
449 ++iter_weight;
450 }
451 this->_m_CRS_Row_Ptr.push_back(*row_end + v_neigh.size());
452 this->_volumes.push_back(volume);
453 _mapping_l_to_g.push_back(i_fc);
454 }
455
460 void remove_node(const CoMMAIndexType &elemento) {
461 // Pass to the local
462 auto low =
463 std::find(_mapping_l_to_g.begin(), _mapping_l_to_g.end(), elemento);
464 const CoMMAIndexType i_fc = low - _mapping_l_to_g.begin();
465 // Getting neighbours, store them before erasing
466 ContainerIndexType v_neigh = this->get_neighbours(i_fc);
467
468 // weight iterator for erasing in the weight vector
469 auto pos_col = this->_m_CRS_Col_Ind.begin();
470 auto pos_Values = this->_m_CRS_Values.begin();
471 for (const auto &elem : v_neigh) {
472 CoMMAIndexType ind = this->_m_CRS_Row_Ptr[elem];
473 CoMMAIndexType ind_p_one = this->_m_CRS_Row_Ptr[elem + 1];
474 // Constant to keep track and erase the weight
475 for (auto it = pos_col + ind; it != pos_col + ind_p_one; ++it) {
476 if (*it == i_fc) {
477 this->_m_CRS_Col_Ind.erase(it);
478 // define the exact position of the element for the processing of the
479 // weight later.
480 this->_m_CRS_Values.erase(pos_Values + (it - pos_col));
481 // for each found i decrease the successive of 1 for the offset
482 for (auto it_bis = this->_m_CRS_Row_Ptr.begin() + elem + 1;
483 it_bis != this->_m_CRS_Row_Ptr.end();
484 ++it_bis) {
485 *it_bis = *it_bis - 1;
486 }
487 }
488 }
489 }
490 // reduce the row ptr value of the deleted value
491 // do the same with i_fc
492 CoMMAIndexType ind = this->_m_CRS_Row_Ptr[i_fc];
493 CoMMAIndexType ind_p_one = this->_m_CRS_Row_Ptr[i_fc + 1];
494 for (auto it = pos_col + ind; it != pos_col + ind_p_one; ++it) {
495 this->_m_CRS_Col_Ind.erase(it);
496 // define the exact position of the element for the processing of the
497 // weight later.
498 this->_m_CRS_Values.erase(pos_Values + (it - pos_col));
499 // for each found i decrease the successive of 1 for the offset
500 for (auto it_bis = this->_m_CRS_Row_Ptr.begin() + i_fc + 1;
501 it_bis != this->_m_CRS_Row_Ptr.end();
502 ++it_bis) {
503 *it_bis = *it_bis - 1;
504 }
505 }
506 // Get rid of the col element
507 auto Col_pointer = this->_m_CRS_Row_Ptr.begin() + i_fc;
508 // Modify the mapping
509 auto mapping_pointer = _mapping_l_to_g.begin() + i_fc;
510 auto volumes_pointer = this->_volumes.begin() + i_fc;
511 this->_volumes.erase(volumes_pointer);
512 this->_m_CRS_Row_Ptr.erase(Col_pointer);
513 _mapping_l_to_g.erase(mapping_pointer);
514 // now we do not have nomore our node, but we must create a mapping between
515 // the before and now, and translate it in the col_ind and update the
516 // mapping with the global graph mapping for the renumbering of the nodes
517 std::vector<std::optional<CoMMAIndexType>> internal_mapping;
518 internal_mapping.reserve(this->_m_CRS_Row_Ptr.size() + 1);
519 CoMMAIndexType indice = 0;
520 for (auto ix = decltype(this->_m_CRS_Row_Ptr.size()){0};
521 ix < this->_m_CRS_Row_Ptr.size() + 1;
522 ++ix) {
523 if (static_cast<decltype(i_fc)>(ix) != i_fc) {
524 internal_mapping.push_back(indice);
525 indice++;
526 } else {
527 internal_mapping.push_back(std::nullopt);
528 }
529 }
530 for (auto &actual : this->_m_CRS_Col_Ind) {
531 assert(internal_mapping[actual].has_value());
532 actual = internal_mapping[actual].value();
533 }
534 }
535};
536
544template<
545 typename CoMMAIndexType,
546 typename CoMMAWeightType,
547 typename CoMMAIntType>
548class Dual_Graph : public Graph<CoMMAIndexType, CoMMAWeightType, CoMMAIntType> {
549public:
553 using typename BaseClass::ContainerIndexType;
555 using typename BaseClass::ContainerWeightType;
557 using CoMMAPairType = std::pair<CoMMAIndexType, CoMMAWeightType>;
560 std::set<CoMMAPairType, CustomPairGreaterFunctor<CoMMAPairType>>;
561
578 const CoMMAIndexType &nb_c,
579 const ContainerIndexType &m_crs_row_ptr,
580 const ContainerIndexType &m_crs_col_ind,
581 const ContainerWeightType &m_crs_values,
582 const ContainerWeightType &volumes,
583 const std::vector<std::vector<CoMMAWeightType>> &centers,
584 const std::vector<CoMMAIntType> &n_bnd_faces,
585 const CoMMAIntType dimension,
586 const ContainerIndexType &anisotropic_compliant_fc
587 ) :
588 Graph<CoMMAIndexType, CoMMAWeightType, CoMMAIntType>(
589 nb_c, m_crs_row_ptr, m_crs_col_ind, m_crs_values, volumes
590 ),
591 _n_bnd_faces(n_bnd_faces),
593 anisotropic_compliant_fc.begin(), anisotropic_compliant_fc.end()
594 ),
595 _centers(centers) {
596 // Function to compute the aspect-ratio
597 _compute_AR = dimension == 2
598 ? [](
599 const CoMMAWeightType min_s, const CoMMAWeightType max_s
600 ) -> CoMMAWeightType { return max_s / min_s; }
601 : [](
602 const CoMMAWeightType min_s, const CoMMAWeightType max_s
603 ) -> CoMMAWeightType { return sqrt(max_s / min_s); };
604 }
605
607 ~Dual_Graph() override = default;
608
610 const std::vector<CoMMAIntType> &_n_bnd_faces;
611
617 const std::unordered_set<CoMMAIndexType> _s_anisotropic_compliant_cells;
618
620 const std::vector<std::vector<CoMMAWeightType>> &_centers;
621
627 std::function<CoMMAWeightType(const CoMMAWeightType, const CoMMAWeightType)>
629
634 inline CoMMAIntType get_n_boundary_faces(const CoMMAIndexType idx_c) const {
635 return _n_bnd_faces[idx_c];
636 }
637
643 inline CoMMAIntType get_total_n_faces(const CoMMAIndexType idx_c) const {
644 return this->_n_bnd_faces[idx_c] + this->get_nb_of_neighbours(idx_c);
645 }
646
651 inline bool is_on_boundary(const CoMMAIndexType idx_c) const {
652 return _n_bnd_faces[idx_c] > 0;
653 }
654
661 inline CoMMAWeightType estimated_boundary_weight(const CoMMAIndexType idx_c
662 ) const {
663 // Approximate with an average of the internal faces
664 // We could choose many kinds of average, e.g. arithmetic or geometric, I
665 // honestly don't know if one is better then the other...
666 // Here, we use the arithmetic one for performance concerns.
667 // However, the geometric one, which should be less sensitive to outliers
668 // is given below as well.
669 return this->_n_bnd_faces[idx_c] == 0 ? 0.
670 : this->_n_bnd_faces[idx_c]
671#if 1
672 * std::reduce(this->weights_cbegin(idx_c),
673 this->weights_cend(idx_c),
674 CoMMAWeightType{0.})
675 / this->get_nb_of_neighbours(idx_c);
676#else
677 * pow(std::accumulate(
678 this->weights_cbegin(idx_c),
679 this->weights_cend(idx_c),
680 CoMMAWeightType{1.},
681 std::multiplies<>()
682 ),
683 CoMMAWeightType{1.} / this->get_nb_of_neighbours(idx_c));
684#endif
685 }
686
693 inline CoMMAWeightType estimated_total_weight(const CoMMAIndexType idx_c
694 ) const {
695 return std::reduce(this->weights_cbegin(idx_c), this->weights_cend(idx_c))
696 + this->estimated_boundary_weight(idx_c);
697 }
698
708 inline CoMMAWeightType get_center_direction(
709 const CoMMAIndexType &a,
710 const CoMMAIndexType &b,
711 std::vector<CoMMAWeightType> &dir
712 ) {
713 return get_direction<CoMMAWeightType>(
714 this->_centers[a], this->_centers[b], dir
715 );
716 }
717
740 std::vector<CoMMAWeightType> &alt_weights,
741 ContainerWeightType &max_weights,
742 std::vector<bool> &is_anisotropic,
743 std::deque<CoMMAIndexType> &aniso_seeds_pool,
744 const CoMMAWeightType threshold_anisotropy,
745 const ContainerWeightType &priority_weights,
746 const CoMMACellCouplingT cell_coupling,
747 const CoMMAIndexType preserving
748 ) {
749 if (cell_coupling == CoMMACellCouplingT::MIN_DISTANCE) {
750 // We have to build the new weights. Preparing the storage.
751 alt_weights.resize(this->_m_CRS_Values.size());
752 std::fill(alt_weights.begin(), alt_weights.end(), 0.0);
753 }
754 CoMMASetOfPairType aniso_w_weights{};
755 if (threshold_anisotropy < 0) {
756 switch (cell_coupling) {
758 for (const CoMMAIndexType i_fc : _s_anisotropic_compliant_cells) {
759 aniso_w_weights.emplace(i_fc, priority_weights[i_fc]);
760 max_weights[i_fc] = *(
761 max_element(this->weights_cbegin(i_fc), this->weights_cend(i_fc))
762 );
763 }
764 break;
765 }
767 for (const CoMMAIndexType i_fc : _s_anisotropic_compliant_cells) {
768 aniso_w_weights.emplace(i_fc, priority_weights[i_fc]);
769 CoMMAWeightType max_ov_dist = 0.0;
770 const auto offset = this->_m_CRS_Row_Ptr[i_fc];
771 auto n_it = std::next(this->_m_CRS_Col_Ind.cbegin(), offset);
772 auto w_it = std::next(alt_weights.begin(), offset);
773 for (; n_it != this->neighbours_cend(i_fc); ++n_it, ++w_it) {
774 const auto dist = 1.
775 / squared_euclidean_distance<CoMMAWeightType>(
776 this->_centers[i_fc], this->_centers[*n_it]
777 );
778 *w_it = dist;
779 if (dist > max_ov_dist) max_ov_dist = dist;
780 } // for neigh
781 max_weights[i_fc] = max_ov_dist;
782 }
783 break;
784 }
785 default:
786 break;
787 } // end switch
788 } else {
789 for (const CoMMAIndexType i_fc : _s_anisotropic_compliant_cells) {
790 // The max weight is always computed since it's needed for the AR
791 CoMMAWeightType max_weight = 0.0;
792 CoMMAWeightType min_weight =
793 std::numeric_limits<CoMMAWeightType>::max();
794
795 // computation of min_weight, max_weight for the current cell
796 // Process of every faces/Neighbours and compute for the current cell
797 // the neighbourhood and the area associated with the neighbourhood
798 // cells
799 auto n_it = this->neighbours_cbegin(i_fc);
800 auto w_it = this->weights_cbegin(i_fc);
801 auto nb_neighbours = this->get_nb_of_neighbours(i_fc);
802 for (; n_it != this->neighbours_cend(i_fc)
803 && w_it != this->weights_cend(i_fc);
804 ++n_it, ++w_it) {
805 // to avoid special case where the boundary value are stored
806 if (*n_it != i_fc) {
807 if (max_weight < *w_it) {
808 max_weight = *w_it;
809 }
810 if (min_weight > *w_it) {
811 min_weight = *w_it;
812 }
813 } else {
814 nb_neighbours--;
815 }
816 }
817 // Compute the aspect-ratio and add cell to list if necessary
818 const auto ar = _compute_AR(min_weight, max_weight);
819 // Anisotropy criteria for the line Admissibility
820 if (ar >= threshold_anisotropy) {
821 switch (preserving) {
822 case 2:
823 if ((is_on_boundary(i_fc) > 0 && nb_neighbours == 3)
824 || nb_neighbours == 4)
825 aniso_w_weights.emplace(i_fc, priority_weights[i_fc]);
826 break;
827 case 3:
828 if ((is_on_boundary(i_fc) > 0 && nb_neighbours == 5)
829 || nb_neighbours == 6)
830 aniso_w_weights.emplace(i_fc, priority_weights[i_fc]);
831 case 0:
832 default:
833 // If the ratio is more than the given threshold of the biggest
834 // with the smallest cell, add it
835 aniso_w_weights.emplace(i_fc, priority_weights[i_fc]);
836 break;
837 } // End switch
838 } // End if ar
839
840 // Updating weights according to coupling
841 switch (cell_coupling) {
843 max_weights[i_fc] = max_weight;
844 break;
845 }
847 const auto offset = this->_m_CRS_Row_Ptr[i_fc];
848 auto n_it = std::next(this->_m_CRS_Col_Ind.cbegin(), offset);
849 auto w_it = std::next(alt_weights.begin(), offset);
850 CoMMAWeightType max_ov_dist = 0.0;
851 for (; n_it != this->neighbours_cend(i_fc); ++n_it, ++w_it) {
852 const auto dist = 1.
853 / squared_euclidean_distance<CoMMAWeightType>(
854 this->_centers[i_fc], this->_centers[*n_it]
855 );
856 *w_it = dist;
857 if (dist > max_ov_dist) max_ov_dist = dist;
858 } // for neigh
859 max_weights[i_fc] = max_ov_dist;
860 break;
861 }
862 default:
863 break;
864 } // end switch
865
866 } // End for compliant cells
867 } // End if threshold
868
869 // Build result
870 for (const auto &[i_fc, w] : aniso_w_weights) {
871 is_anisotropic[i_fc] = true;
872 aniso_seeds_pool.emplace_back(i_fc);
873 }
874 }
875
879 inline CoMMAIndexType get_nb_cells() const { return this->_number_of_cells; }
880
889 inline std::unordered_set<CoMMAIndexType> get_neighbourhood_of_cc(
890 const std::unordered_set<CoMMAIndexType> &s_seeds,
891 const std::vector<bool> &is_fc_agglomerated_tmp
892 ) const {
893 std::unordered_set<CoMMAIndexType> cc_neighs{};
894 for (const auto fc : s_seeds)
895 for (auto n = this->neighbours_cbegin(fc); n != this->neighbours_cend(fc);
896 ++n)
897 if (!is_fc_agglomerated_tmp[*n] && s_seeds.find(*n) == s_seeds.end())
898 // If not agglomerated and not part of the coarse cell
899 cc_neighs.insert(*n);
900 return cc_neighs;
901 }
902
918 const std::unordered_set<CoMMAIndexType> &s_seeds,
919 CoMMAIntType &nb_of_order_of_neighbourhood,
920 std::unordered_map<CoMMAIndexType, CoMMAIntType> &d_n_of_seed,
921 const CoMMAIntType max_card,
922 const std::vector<bool> &is_fc_agglomerated_tmp
923 ) const {
924 // Basic checks
925 assert(max_card > 1);
926 // dict of FC with the order of neighbouring from seed
927 std::unordered_map<CoMMAIndexType, CoMMAIntType> d_n_of_order_o_m_one;
928 // we initialize for seeds where order is 0
929 for (const CoMMAIndexType &i_fc : s_seeds) {
930 d_n_of_order_o_m_one[i_fc] = 0;
931 }
932
933 CoMMAIntType i_order = 1;
934
935 while ((i_order < nb_of_order_of_neighbourhood + 1)
936 || static_cast<CoMMAIntType>(
937 d_n_of_seed.size() + d_n_of_order_o_m_one.size()
938 )
939 < max_card) {
940 std::unordered_map<CoMMAIndexType, CoMMAIntType> d_n_of_order_o;
941
942 // If here, add elements of previous elements to output dictionary
943 for (auto id_M_one : d_n_of_order_o_m_one) {
944 d_n_of_seed[id_M_one.first] = id_M_one.second;
945 }
946
947 for (const auto &i_k_v : d_n_of_order_o_m_one) {
948 // For all the cells in the previous neighbourhood order...
949
950 CoMMAIndexType seed_tmp = i_k_v.first;
951
952 for (auto i_fc_n = this->neighbours_cbegin(seed_tmp);
953 i_fc_n != this->neighbours_cend(seed_tmp);
954 ++i_fc_n) {
955 // For all the neighbours of current seed...
956
957 if ((d_n_of_seed.count(*i_fc_n) == 0)
958 && ((!is_fc_agglomerated_tmp[*i_fc_n]))) {
959 // If not yet in the final dictionary and not yet agglomerated...
960
961 if (d_n_of_order_o.count(*i_fc_n) == 0) {
962 // If not yet in the current neighbourhood order...
963 // a fc can be access via multiple ways. We look for the quickest
964 if (d_n_of_order_o_m_one.count(*i_fc_n)) {
965 // If it was already in the previous neighbourhood order
966
967 if (i_order < d_n_of_order_o_m_one[*i_fc_n]) {
968 // If current order smaller than the previous one
969 // ...update the order
970 d_n_of_order_o[*i_fc_n] = i_order;
971 }
972 } else {
973 // ...add the neighbour
974 d_n_of_order_o[*i_fc_n] = i_order;
975 }
976 }
977 }
978 }
979 }
980
981 // Exit condition (while)
982 if (d_n_of_order_o.empty()) {
983 // No more neighbours available:
984 break;
985 }
986
987 // Update previous order
988 d_n_of_order_o_m_one.clear();
989 for (auto id : d_n_of_order_o) {
990 d_n_of_order_o_m_one[id.first] = id.second;
991 }
992 i_order++;
993 } // End of while
994 // Update of d_n_of_seed
995 // d_n_of_seed.update(d_n_of_order_o_m_one)
996 for (auto id_M_one : d_n_of_order_o_m_one) {
997 d_n_of_seed[id_M_one.first] = id_M_one.second;
998 }
999
1000 // We remove the seed from the neighbours of seed
1001 for (const CoMMAIndexType &i_fc : s_seeds) {
1002 d_n_of_seed.erase(i_fc);
1003 }
1004
1005 nb_of_order_of_neighbourhood = i_order;
1006 }
1007};
1008
1009} // end namespace comma
1010
1011#endif // COMMA_PROJECT_DUAL_GRAPH_H
A class implementing the CRS global graph representation of the global mesh.
Definition: Dual_Graph.h:548
CoMMAIntType get_n_boundary_faces(const CoMMAIndexType idx_c) const
Return how many boundary faces a certain cell has.
Definition: Dual_Graph.h:634
void compute_neighbourhood_of_cc(const std::unordered_set< CoMMAIndexType > &s_seeds, CoMMAIntType &nb_of_order_of_neighbourhood, std::unordered_map< CoMMAIndexType, CoMMAIntType > &d_n_of_seed, const CoMMAIntType max_card, const std::vector< bool > &is_fc_agglomerated_tmp) const
Compute the dictionary of compactness of fine cells inside a coarse cell.
Definition: Dual_Graph.h:917
bool is_on_boundary(const CoMMAIndexType idx_c) const
Whether a cell is on the boundary.
Definition: Dual_Graph.h:651
CoMMAIntType get_total_n_faces(const CoMMAIndexType idx_c) const
Return total number of faces, that is, number of neighbours plus number of boundaries.
Definition: Dual_Graph.h:643
const std::vector< std::vector< CoMMAWeightType > > & _centers
Vector of cell centers.
Definition: Dual_Graph.h:620
CoMMAWeightType estimated_total_weight(const CoMMAIndexType idx_c) const
Sum of wall the weights (faces) of a cell. Since there is no knowledge about boundary faces,...
Definition: Dual_Graph.h:693
Dual_Graph(const CoMMAIndexType &nb_c, const ContainerIndexType &m_crs_row_ptr, const ContainerIndexType &m_crs_col_ind, const ContainerWeightType &m_crs_values, const ContainerWeightType &volumes, const std::vector< std::vector< CoMMAWeightType > > &centers, const std::vector< CoMMAIntType > &n_bnd_faces, const CoMMAIntType dimension, const ContainerIndexType &anisotropic_compliant_fc)
Constructor of the class.
Definition: Dual_Graph.h:577
void tag_anisotropic_cells(std::vector< CoMMAWeightType > &alt_weights, ContainerWeightType &max_weights, std::vector< bool > &is_anisotropic, std::deque< CoMMAIndexType > &aniso_seeds_pool, const CoMMAWeightType threshold_anisotropy, const ContainerWeightType &priority_weights, const CoMMACellCouplingT cell_coupling, const CoMMAIndexType preserving)
Tag cells as anisotropic if their aspect-ratio is over a given threshold and order them according to ...
Definition: Dual_Graph.h:739
CoMMAIndexType get_nb_cells() const
Getter that returns the number of cells.
Definition: Dual_Graph.h:879
std::unordered_set< CoMMAIndexType > get_neighbourhood_of_cc(const std::unordered_set< CoMMAIndexType > &s_seeds, const std::vector< bool > &is_fc_agglomerated_tmp) const
Get the fine cells neighbours of a coarse cell.
Definition: Dual_Graph.h:889
std::pair< CoMMAIndexType, CoMMAWeightType > CoMMAPairType
Type of pair.
Definition: Dual_Graph.h:557
const std::vector< CoMMAIntType > & _n_bnd_faces
Vector telling how many boundary faces each cell has.
Definition: Dual_Graph.h:610
CoMMAWeightType get_center_direction(const CoMMAIndexType &a, const CoMMAIndexType &b, std::vector< CoMMAWeightType > &dir)
Compute the direction from vertex a to vertex b and store it as unit vector in dir.
Definition: Dual_Graph.h:708
std::vector< CoMMAWeightType > ContainerWeightType
Type for containers of weights.
Definition: Dual_Graph.h:51
std::vector< CoMMAIndexType > ContainerIndexType
Type for containers of indices.
Definition: Dual_Graph.h:49
std::set< CoMMAPairType, CustomPairGreaterFunctor< CoMMAPairType > > CoMMASetOfPairType
Type of set of pairs.
Definition: Dual_Graph.h:560
~Dual_Graph() override=default
Destructor of the class.
std::function< CoMMAWeightType(const CoMMAWeightType, const CoMMAWeightType)> _compute_AR
Function which computes the aspect-ratio from the minimum and maximum faces In 3D: In 2D: (Recal...
Definition: Dual_Graph.h:628
const std::unordered_set< CoMMAIndexType > _s_anisotropic_compliant_cells
Elements that are checked if they are anisotropic. If an element satisfies the condition for being an...
Definition: Dual_Graph.h:617
CoMMAWeightType estimated_boundary_weight(const CoMMAIndexType idx_c) const
Approximate the value of a boundary face using the known internal faces. It uses a (geometric) averag...
Definition: Dual_Graph.h:661
An interface class responsible of storing the cell centered dual graph and of acting on it (it is an ...
Definition: Dual_Graph.h:46
ContainerWeightConstIt weights_cbegin(const CoMMAIndexType &i_c) const
Get constant pointer to the first neighbour of cell i_c.
Definition: Dual_Graph.h:221
ContainerWeightType _m_CRS_Values
Vector of area weight of CRS representation.
Definition: Dual_Graph.h:99
void DFS(const CoMMAIndexType &i_fc)
Depth First Search (DFS) recursive function.
Definition: Dual_Graph.h:107
Graph(const CoMMAIndexType &nb_c, const ContainerIndexType &m_crs_row_ptr, const ContainerIndexType &m_crs_col_ind, const ContainerWeightType &m_crs_values, const ContainerWeightType &volumes)
Constructor of the class.
Definition: Dual_Graph.h:66
ContainerIndexType get_neighbours(const CoMMAIndexType &i_c) const
Based on the CRS representation retrieves the neighbours of the cell given as an input.
Definition: Dual_Graph.h:166
typename ContainerWeightType::const_iterator ContainerWeightConstIt
Type for constant iterators of containers of weights.
Definition: Dual_Graph.h:55
ContainerIndexConstIt neighbours_cend(const CoMMAIndexType &i_c) const
Get constant pointer to the element following the last neighbour of cell i_c.
Definition: Dual_Graph.h:193
CoMMAIntType compute_min_fc_compactness_inside_a_cc(const std::unordered_set< CoMMAIndexType > &s_fc) const
Compute the minimum compactness of fine cells inside a coarse cell.
Definition: Dual_Graph.h:258
std::unordered_map< CoMMAIndexType, CoMMAIntType > compute_fc_compactness_inside_a_cc(const std::unordered_set< CoMMAIndexType > &s_fc) const
Compute the dictionary of compactness of fine cells inside a coarse cell.
Definition: Dual_Graph.h:287
CoMMAIntType get_nb_of_neighbours(const CoMMAIndexType i_c) const
Retrieve the number of neighbours.
Definition: Dual_Graph.h:156
typename ContainerIndexType::const_iterator ContainerIndexConstIt
Type for constant iterators of containers of indices.
Definition: Dual_Graph.h:53
ContainerIndexType _m_CRS_Row_Ptr
Vector of row pointer of CRS representation.
Definition: Dual_Graph.h:93
bool check_connectivity()
Check the connectivity of the graph.
Definition: Dual_Graph.h:238
ContainerWeightConstIt weights_cend(const CoMMAIndexType &i_c) const
Get constant pointer to the element following the last neighbour of cell i_c.
Definition: Dual_Graph.h:231
ContainerIndexType _m_CRS_Col_Ind
Vector of column index of CRS representation.
Definition: Dual_Graph.h:96
std::vector< CoMMAWeightType > ContainerWeightType
Type for containers of weights.
Definition: Dual_Graph.h:51
std::vector< CoMMAIndexType > ContainerIndexType
Type for containers of indices.
Definition: Dual_Graph.h:49
CoMMAIndexType _number_of_cells
Number of nodes in the Graph (it corresponds to the number of cells in the subgraph or the dual graph...
Definition: Dual_Graph.h:87
virtual ~Graph()=default
Destructor of the class.
ContainerWeightType _volumes
Vector of volumes.
Definition: Dual_Graph.h:102
ContainerIndexConstIt neighbours_cbegin(const CoMMAIndexType &i_c) const
Get constant pointer to the first neighbour of cell i_c.
Definition: Dual_Graph.h:183
ContainerWeightType get_weights(const CoMMAIndexType &i_c) const
Based on the area of the faces composing the cell given as an input, we retrieve the faces connecting...
Definition: Dual_Graph.h:204
std::vector< bool > _visited
Helper vector for the DFS.
Definition: Dual_Graph.h:90
void BFS(const CoMMAIndexType &root)
Breadth First Search (BFS) function.
Definition: Dual_Graph.h:119
A class implementing the CRS subgraph representation. It is used in the framework of CoMMA for the im...
Definition: Dual_Graph.h:320
bool _is_isotropic
Whether it originates from an isotropic cell.
Definition: Dual_Graph.h:372
CoMMAIntType _compactness
Compactness of the given subgraph. The compactness is the minimum number of internal neighbours.
Definition: Dual_Graph.h:382
~Subgraph() override=default
Destructor of the class.
void insert_node(const ContainerIndexType &v_neigh, const CoMMAIndexType &i_fc, const CoMMAWeightType &volume, const ContainerWeightType &weight)
Insert a node in the subgraph and add it to the mapping the.
Definition: Dual_Graph.h:398
ContainerIndexType _mapping_l_to_g
Mapping from the local number of node to the global. Being a subgraph this variable connect the local...
Definition: Dual_Graph.h:388
Subgraph(const CoMMAIndexType &nb_c, const ContainerIndexType &m_crs_row_ptr, const ContainerIndexType &m_crs_col_ind, const ContainerWeightType &m_crs_values, const ContainerWeightType &volumes, const ContainerIndexType &mapping_l_to_g, const bool &is_isotropic)
Constructor of the class.
Definition: Dual_Graph.h:342
CoMMAIntType _cardinality
Cardinality of the given subgraph, alias the number of nodes contained.
Definition: Dual_Graph.h:377
std::vector< CoMMAWeightType > ContainerWeightType
Type for containers of weights.
Definition: Dual_Graph.h:51
void remove_node(const CoMMAIndexType &elemento)
Remove a node from the CRS representation and automatically adjust the mapping.
Definition: Dual_Graph.h:460
std::vector< CoMMAIndexType > ContainerIndexType
Type for containers of indices.
Definition: Dual_Graph.h:49
Definition: Agglomerator.h:37
CoMMACellCouplingT
Type of coupling between cells in an anisotropic line.
Definition: CoMMADefs.h:103
@ MIN_DISTANCE
Definition: CoMMADefs.h:107
@ MAX_WEIGHT
Definition: CoMMADefs.h:105