TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Connex_components.cpp
1/****************************************************************************
2* Copyright (c) 2025, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <Connex_components.h>
17#include <communications.h>
18#include <TRUSTTab.h>
19#include <ArrOfBit.h>
20
21/*! @brief Calcul des ensembles connexes par faces d'elements non "marques" (les elements sont relies entre eux par un graphe
22 *
23 * symetrique passant par les faces).
24 * Une portion de domaine connexe porte un numero 0 <= i < N
25 * unique et est delimite soit par un bord, soit par un element voisin "marque"
26 * par num_compo[elem] = -1.
27 * Cette methode est sequentielle (peut etre appelee sur un seul processeur)
28 *
29 * @param (elem_faces)
30 * @param (faces_elem)
31 * @param (num_compo)
32 */
33int search_connex_components_local(const IntTab& elem_faces, const IntTab& faces_elem, IntVect& num_compo)
34{
35 const int nbelem = num_compo.size_totale();
36 const int nb_voisins = elem_faces.dimension(1);
37 assert(elem_faces.dimension_tot(0) == nbelem);
38 {
39 int i;
40 for (i = 0; i < nbelem; i++)
41 if (num_compo[i] != -1)
42 num_compo[i] = -2;
43 }
44 int start_element = 0;
45 int num_compo_courant = 0;
46 ArrOfInt liste_elems;
47
48 ArrOfInt tmp_liste;
49
50 do
51 {
52 // Cherche le prochain element non attribue a une composante connexe
53 while (start_element < nbelem && num_compo[start_element] >= -1)
54 start_element++;
55 if (start_element == nbelem)
56 break;
57 // Recherche des elements de la composante connexe a partir de cet element
58 liste_elems.resize_array(1);
59 liste_elems[0] = start_element;
60 num_compo[start_element] = num_compo_courant;
61 while (liste_elems.size_array() > 0)
62 {
63 tmp_liste.resize_array(0);
64 const int liste_elems_size = liste_elems.size_array();
65 for (int i_elem = 0; i_elem < liste_elems_size; i_elem++)
66 {
67 const int elem = liste_elems[i_elem];
68 // Ajout des voisins non attribues de cet element dans la liste a
69 // traiter a l'etape suivante
70 for (int j = 0; j < nb_voisins; j++)
71 {
72 const int face = elem_faces(elem, j);
73 const int voisin = faces_elem(face, 0) + faces_elem(face, 1) - elem;
74 if (voisin >= 0)
75 {
76 const int num = num_compo[voisin];
77 if (num == -2)
78 {
79 num_compo[voisin] = num_compo_courant;
80 tmp_liste.append_array(voisin);
81 }
82 }
83 }
84 }
85 liste_elems = tmp_liste;
86 }
87 num_compo_courant++;
88 }
89 while (1);
90 // Renvoie le nombre de composantes connexes locales trouvees
91 return num_compo_courant;
92}
93
94/*! @brief recherche des composantes connexes d'un graphe local (non distribue sur les processeurs) non symetrique.
95 *
96 * @param (graph)
97 * @param (connex_components)
98 */
99int compute_graph_connex_components(const IntTab& graph, ArrOfInt& connex_components)
100{
101 // connex_components doit deja avoir la bonne taille en entree !
102 const int nb_sommets = connex_components.size_array();
103
104 // renum_data definit des listes chainees de numeros de "sommets" appartenant a
105 // la meme composante connexe.
106 // renum_data(i,0)= numero du premier "sommet" de la liste a laquelle appartient i
107 // renum_data(i,1)= numero du "sommet" suivant dans la liste
108 IntTab renum_data(nb_sommets, 2);
109 // Au debut, chaque sommet est toute seule dans une liste:
110 int i_sommet;
111 for (i_sommet = 0; i_sommet < nb_sommets; i_sommet++)
112 {
113 renum_data(i_sommet, 0) = i_sommet;
114 renum_data(i_sommet, 1) = -1; // fin de liste
115 }
116 const int nbcouples = graph.dimension(0);
117 for (int i_couple = 0; i_couple < nbcouples; i_couple++)
118 {
119 const int compo1 = graph(i_couple, 0); // la plus petite
120 const int compo2 = graph(i_couple, 1); // la plus grande
121 assert(compo1 != compo2);
122 // Si les deux composantes sont deja dans la meme liste,
123 // ne rien faire.
124 if (renum_data(compo1, 0) == renum_data(compo2, 0))
125 continue;
126 // Reunir la liste1 contenant compo1 et la liste2 contenant compo2:
127 // 1) trouver la fin de la premiere liste
128 int fin_liste1 = compo1;
129 for (;;)
130 {
131 const int next = renum_data(fin_liste1, 1);
132 if (next < 0)
133 break;
134 fin_liste1 = next;
135 }
136 // 2) brancher la liste2 a la fin de la liste1 :
137 const int debut_liste2 = renum_data(compo2, 0);
138 renum_data(fin_liste1, 1) = debut_liste2;
139 // 2) mettre a jour le debut de liste pour liste2 :
140 i_sommet = debut_liste2;
141 const int debut_liste1 = renum_data(compo1, 0);
142 do
143 {
144 renum_data(i_sommet, 0) = debut_liste1;
145 i_sommet = renum_data(i_sommet, 1);
146 }
147 while (i_sommet >= 0);
148 }
149
150 // Creation d'une numerotation contigue pour les composantes:
151 // Prochain numero a attribuer
152 int count = 0;
153 connex_components = -1;
154 for (i_sommet = 0; i_sommet < nb_sommets; i_sommet++)
155 {
156 if (connex_components[i_sommet] < 0)
157 {
158 // sommet pas encore traite
159 // Associe un nouveau numero a tous les sommets de la composante
160 // connexe a laquelle appartient i_sommet:
161 for (int i = renum_data(i_sommet, 0); i >= 0; i = renum_data(i, 1))
162 connex_components[i] = count;
163 // Nouveau numero pour la prochaine composante
164 count++;
165 }
166 }
167 // On renvoie le nombre de composantes connexes trouvees
168 return count;
169}
170
171/*! @brief Recherche les composantes connexes d'un ensemble d'elements distribue sur tous les processeurs.
172 *
173 * Cette methode est parallele et doit etre appelee en
174 * meme temps sur tous les processeurs.
175 *
176 * @param (num_compo)
177 * @param (nb_local_components)
178 */
179int compute_global_connex_components(IntVect& num_compo, int nb_local_components)
180{
181 const int nbelem = num_compo.size();
182 const int nbelem_tot = num_compo.size_totale();
183 //int i;
184
185 // Transformation des indices locaux de composantes connexes en un indice global
186 // (on ajoute un decalage aux indices globaux avec mppartial_sum())
187 const int decalage = static_cast<int>(Process::mppartial_sum(nb_local_components)); // compo number are never huge
188 const int nb_total_components = static_cast<int>(Process::mp_sum(nb_local_components));
189 for (int i = 0; i < nbelem_tot; i++)
190 if (num_compo[i] >= 0)
191 num_compo[i] += decalage;
192
193 // Pour trouver les correspondances entre un numero de composante locale et un
194 // numero de la meme composante sur le processeur voisin, on cree une copie du
195 // tableau num_compo sur laquelle on fait un echange_espace_virtuel(). Ainsi,
196 // sur les cases virtuelles du tableau, on a dans num_compo le numero de la
197 // composante locale et dans copie_compo le numero de cette meme composante sur
198 // le processeur proprietaire de l'element. Donc ces deux numeros designent
199 // la meme composante connexe.
200 IntVect copie_compo(num_compo);
201 copie_compo.echange_espace_virtuel();
202
203 // Recherche des equivalences entre les numeros des composantes locales et
204 // les numeros des composantes voisines. On construit un graphe dont les
205 // liens relient les composantes equivalentes.
206 // Tableau de marqeurs pour les equivalences deja trouvees.
207 // Dimensions = nb composantes locales * nb_composantes total
208 // (pour ne pas prendre en compte la meme composante plusieurs fois).
209 ArrOfBit markers(nb_local_components * nb_total_components);
210 markers = 0;
211 // Tableau de correspondances entre composantes connexes locales et distantes
212 IntTab graph;
213
214 int graph_size = 0;
215 // Parcours des elements virtuels uniquement
216 for (int i = nbelem; i < nbelem_tot; i++)
217 {
218 int compo = num_compo[i];
219 if (compo < 0)
220 continue;
221 int compo2 = copie_compo[i];
222 // Index du couple compo2/compo dans le tableau markers
223 // Le tableau num_compo ne doit contenir que des composantes locales:
224 assert(compo >= decalage && compo - decalage < nb_local_components);
225 // compo2 est forcement une composante distante.
226 assert(compo2 < decalage || compo2 - decalage >= nb_local_components);
227 const int index = (compo - decalage) * nb_total_components + compo2;
228 if (!markers.testsetbit(index))
229 {
230 graph.resize(graph_size+1, 2);
231 // On met le plus petit numero de composante en colonne 0:
232 if (compo2 < compo)
233 {
234 int tmp = compo;
235 compo = compo2;
236 compo2 = tmp;
237 }
238 graph(graph_size, 0) = compo;
239 graph(graph_size, 1) = compo2;
240 graph_size++;
241 }
242 }
243
244 ArrOfInt renum;
246 {
247 // Reception des portions de graphe des autres processeurs
248 IntTab tmp;
249 const int nproc = Process::nproc();
250 int pe;
251 for (pe = 1; pe < nproc; pe++)
252 {
253 recevoir(tmp, pe, 54 /* tag */);
254 const int n2 = tmp.dimension(0);
255 graph.resize(graph_size + n2, 2);
256 for (int i = 0; i < n2; i++)
257 {
258 graph(graph_size, 0) = tmp(i, 0);
259 graph(graph_size, 1) = tmp(i, 1);
260 graph_size++;
261 }
262 }
263 // Calcul des composantes connexes du graphe
264 renum.resize_array(nb_total_components);
265 const int n = compute_graph_connex_components(graph, renum);
266 Process::Journal() << "compute_global_connex_components: nb_components=" << n << finl;
267 }
268 else
269 {
270 // Envoi du graphe local au processeur 0
271 envoyer(graph, 0, 54 /* tag */);
272 }
273
274 // Reception des composantes connexes
275 envoyer_broadcast(renum, 0 /* processeur source */);
276
277 // Renumerotation des composantes dans num_compo
278 for (int i = 0; i < nbelem_tot; i++)
279 {
280 const int x = num_compo[i];
281 if (x >= 0)
282 {
283 const int new_x = renum[x];
284 num_compo[i] = new_x;
285 }
286 }
287 // Verification: si on fait un echange espace virtuel,
288 // cela ne doit par changer le numero des composantes
289 // connexes !
290
291 int nb_components = 0;
292 // Tous les processeurs possedent le meme tableau renum, tout le monde
293 // calcule donc le meme maximum !
294 if (renum.size_array() > 0)
295 nb_components = max_array(renum) + 1;
296 return nb_components;
297}
298
static trustIdType mppartial_sum(trustIdType i)
Calul de la somme partielle de i sur les processeurs 0 a me()-1 (renvoie 0 sur le processeur 0).
Definition Process.cpp:396
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
static double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
Definition Process.cpp:86
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension_tot(int) const override
Definition TRUSTTab.tpp:160
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61