Arcane  v3.16.0.0
Documentation développeur
Tout Classes Espaces de nommage Fichiers Fonctions Variables Définitions de type Énumérations Valeurs énumérées Amis Macros Groupes Pages Concepts
GetVariablesValuesParallelOperation.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* GetVariablesValuesParallelOperation.cc (C) 2000-2025 */
9/* */
10/* Opérations pour accéder aux valeurs de variables d'un autre sous-domaine. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ITraceMng.h"
15
16#include "arcane/core/Timer.h"
17#include "arcane/core/VariableTypes.h"
18#include "arcane/core/IParallelMng.h"
19#include "arcane/core/ISerializer.h"
20#include "arcane/core/IItemFamily.h"
21#include "arcane/core/ISerializeMessage.h"
22
23#include "arcane/impl/GetVariablesValuesParallelOperation.h"
24
25#include "arccore/message_passing/ISerializeMessageList.h"
26
27#include <map>
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31
32namespace Arcane
33{
34using namespace MessagePassing;
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39GetVariablesValuesParallelOperation::
40GetVariablesValuesParallelOperation(IParallelMng* pm)
41: m_parallel_mng(pm)
42{
43}
44
45/*---------------------------------------------------------------------------*/
46/*---------------------------------------------------------------------------*/
47
48IParallelMng* GetVariablesValuesParallelOperation::
49parallelMng()
50{
51 return m_parallel_mng;
52}
53
54/*---------------------------------------------------------------------------*/
55/*---------------------------------------------------------------------------*/
56
57void GetVariablesValuesParallelOperation::
58getVariableValues(VariableItemReal& variable,
59 ConstArrayView<Int64> unique_ids,
60 ConstArrayView<Int32> sub_domain_ids,
61 ArrayView<Real> values)
62{
63 IParallelMng* pm = m_parallel_mng;
64 Timer::Phase tphase(pm->timeStats(), TP_Communication);
65
66 if (!pm->isParallel()) {
67 _getVariableValuesSequential(variable, unique_ids, values);
68 return;
69 }
70
71 ItemGroup group = variable.itemGroup();
72 IItemFamily* item_family = variable.variable()->itemFamily();
73
74 if (group.null())
75 ARCANE_FATAL("The variable '{0}' is not defined on a group.", variable.name());
76
77 Int32 nb_item = unique_ids.size();
78 if (nb_item != values.size())
79 ARCANE_FATAL("The arrays 'unique_ids' and 'values' don't have the same "
80 "number of elements (respectively {0} and {1}).",
81 nb_item, values.size());
82
83 if (nb_item != sub_domain_ids.size())
84 ARCANE_FATAL("The arrays 'unique_ids' and 'sub_domains_ids' don't have the same "
85 "number of elements (respectively {0} and {1}).",
86 nb_item, sub_domain_ids.size());
87
88 using SubDomainUniqueIdMap = std::map<Int32, Helper>;
89 SubDomainUniqueIdMap sub_domain_list;
90
91 for (Integer i = 0; i < nb_item; ++i) {
92 Int32 sd = sub_domain_ids[i];
93 if (sd == NULL_SUB_DOMAIN_ID)
94 ARCANE_FATAL("Null SubDomainId for index {0}", i);
95 //TODO ne pas ajouter les éléments de son propre sous-domaine à la liste
96 Helper& h = sub_domain_list[sd];
97 h.m_unique_ids.add(unique_ids[i]);
98 h.m_indexes.add(i);
99 }
100
101 UniqueArray<Int32> sub_domain_nb_to_send;
102 Int32 my_rank = pm->commRank();
103 for (auto& [sd, helper] : sub_domain_list) {
104 Integer n = helper.m_unique_ids.size();
105 sub_domain_nb_to_send.add(my_rank);
106 sub_domain_nb_to_send.add(sd);
107 sub_domain_nb_to_send.add(n);
108 }
109
110 UniqueArray<Int32> total_sub_domain_nb_to_send;
111 pm->allGatherVariable(sub_domain_nb_to_send, total_sub_domain_nb_to_send);
112 UniqueArray<Ref<ISerializeMessage>> messages;
113 Ref<ISerializeMessageList> message_list(pm->createSerializeMessageListRef());
114 for (Integer i = 0, is = total_sub_domain_nb_to_send.size(); i < is; i += 3) {
115 Int32 rank_send = total_sub_domain_nb_to_send[i];
116 Int32 rank_recv = total_sub_domain_nb_to_send[i + 1];
117 //Integer nb_exchange = total_sub_domain_nb_to_send[i+2];
118 //trace->info() << " SEND=" << rank_send
119 //<< " RECV= " << rank_recv
120 //<< " N= " << nb_exchange;
121 if (rank_send == rank_recv)
122 continue;
123 Ref<ISerializeMessage> sm;
124 if (rank_recv == my_rank) {
125 //trace->info() << " ADD RECV MESSAGE recv=" << rank_recv << " send=" << rank_send;
126 sm = message_list->createAndAddMessage(MessageRank(rank_send), ePointToPointMessageType::MsgReceive);
127 }
128 else if (rank_send == my_rank) {
129 //trace->info() << " ADD SEND MESSAGE recv=" << rank_recv << " send=" << rank_send;
130 sm = message_list->createAndAddMessage(MessageRank(rank_recv), ePointToPointMessageType::MsgSend);
131 ISerializer* s = sm->serializer();
132 s->setMode(ISerializer::ModeReserve);
133 auto xiter = sub_domain_list.find(rank_recv);
134 if (xiter == sub_domain_list.end())
135 ARCANE_FATAL("Can not find rank '{0}'", rank_recv);
136 Span<const Int64> z_unique_ids = xiter->second.m_unique_ids;
137 Int64 nb = z_unique_ids.size();
138 s->reserveInt64(1); // Pour la taille
139 s->reserveSpan(eBasicDataType::Int64, nb); // Pour le tableau
140 s->allocateBuffer();
141 s->setMode(ISerializer::ModePut);
142 s->putInt64(nb);
143 s->putSpan(z_unique_ids);
144 }
145 if (sm.get())
146 messages.add(sm);
147 }
148
149 message_list->waitMessages(eWaitType::WaitAll);
150
151 UniqueArray<Int64> tmp_unique_ids;
152 UniqueArray<Int32> tmp_local_ids;
153 UniqueArray<Real> tmp_values;
154
155 UniqueArray<Ref<ISerializeMessage>> values_messages;
156 ItemInfoListView items_internal(item_family);
157 for (Ref<ISerializeMessage> sm : messages) {
158 Ref<ISerializeMessage> new_sm;
159 if (sm->isSend()) {
160 // Pour recevoir les valeurs
161 //trace->info() << " ADD RECV2 MESSAGE recv=" << my_rank << " send=" << sm->destSubDomain();
162 new_sm = message_list->createAndAddMessage(MessageRank(sm->destination().value()), ePointToPointMessageType::MsgReceive);
163 }
164 else {
165 ISerializer* s = sm->serializer();
166 s->setMode(ISerializer::ModeGet);
167 Int64 nb = s->getInt64();
168 tmp_unique_ids.resize(nb);
169 tmp_local_ids.resize(nb);
170 tmp_values.resize(nb);
171 s->getSpan(tmp_unique_ids);
172 item_family->itemsUniqueIdToLocalId(tmp_local_ids, tmp_unique_ids);
173 for (Integer z = 0; z < nb; ++z) {
174 Item item = items_internal[tmp_local_ids[z]];
175 tmp_values[z] = variable[item];
176 }
177
178 //trace->info() << " ADD SEND2 MESSAGE recv=" << my_rank << " send=" << sm->destSubDomain();
179 new_sm = message_list->createAndAddMessage(MessageRank(sm->destination().value()), ePointToPointMessageType::MsgSend);
180 ISerializer* s2 = new_sm->serializer();
181 s2->setMode(ISerializer::ModeReserve);
182 s2->reserveInt64(1);
183 s2->reserveSpan(eBasicDataType::Real, nb);
184 s2->allocateBuffer();
185 s2->setMode(ISerializer::ModePut);
186 s2->putInt64(nb);
187 s2->putSpan(tmp_values);
188 }
189 values_messages.add(new_sm);
190 }
191
192 // Supprime les messages qui ne sont plus utilisés
193 messages.clear();
194
195 message_list->waitMessages(eWaitType::WaitAll);
196
197 for (Ref<ISerializeMessage> sm : values_messages) {
198 if (sm->isSend()) {
199 }
200 else {
201 ISerializer* s = sm->serializer();
202 s->setMode(ISerializer::ModeGet);
203 Int64 nb = s->getInt64();
204 tmp_values.resize(nb);
205 Int32 sender = sm->destination().value();
206 s->getSpan(tmp_values);
207 //trace->info() << " GET VALUES from=" << sm->destSubDomain() << " n=" << nb;
208 Span<const Int32> indexes = sub_domain_list[sender].m_indexes;
209 for (Int64 z = 0; z < nb; ++z)
210 values[indexes[z]] = tmp_values[z];
211 }
212 }
213
214 // Enfin, traite ses propres éléments
215 // TODO: FAIRE CE TRAITEMENT EN ATTENDANT LES MESSAGES
216 {
217 Helper h(sub_domain_list[my_rank]);
218 Span<const Int32> indexes(h.m_indexes.constSpan());
219 Int64 nb = h.m_unique_ids.largeSize();
220 tmp_local_ids.resize(nb);
221 item_family->itemsUniqueIdToLocalId(tmp_local_ids, h.m_unique_ids);
222 for (Int64 z = 0; z < nb; ++z) {
223 Item item = items_internal[tmp_local_ids[z]];
224 values[indexes[z]] = variable[item];
225 }
226 }
227
228 // Supprime les messages qui ne sont plus utilisés
229 values_messages.clear();
230 //_deleteMessages(values_messages);
231
232#if 0
233 {
234 // Pour faire une petite vérification
235 Integer nb_values = values.size();
236 RealUniqueArray ref_values(nb_values);
237 ref_values.fill(0.0);
238 getVariableValues(variable,unique_ids,ref_values);
239 bool has_error = false;
240 for( Integer i=0; i<nb_values; ++i ){
241 if (!math::isEqual(ref_values[i],values[i])){
242 trace->pinfo() << " Incorrect values ref=" << ref_values[i] << " v=" << values[i];
243 has_error = true;
244 }
245 }
246 if (has_error)
247 trace->fatal() << func_id << " incorrect values";
248 }
249#endif
250}
251
252/*---------------------------------------------------------------------------*/
253/*---------------------------------------------------------------------------*/
254
255void GetVariablesValuesParallelOperation::
256getVariableValues(VariableItemReal& variable, Int64ConstArrayView unique_ids,
257 RealArrayView values)
258{
259 IParallelMng* pm = m_parallel_mng;
260 Timer::Phase tphase(pm->timeStats(), TP_Communication);
261
262 if (!pm->isParallel()) {
263 _getVariableValuesSequential(variable, unique_ids, values);
264 return;
265 }
266
267 ItemGroup group = variable.itemGroup();
268 ITraceMng* trace = pm->traceMng();
269 if (group.null())
270 ARCANE_FATAL("The variable '{0}' is not defined on a group.", variable.name());
271
272 Int32 size = unique_ids.size();
273 if (size != values.size())
274 ARCANE_FATAL("The arrays 'unique_ids' and 'values' don't have the same "
275 "number of elements (respectively {0} and {1}).",
276 size, values.size());
277
278 Int32 nb_proc = pm->commSize();
279 Integer nb_phase = 0;
280 while (nb_proc != 0 && nb_phase < 32) {
281 nb_proc /= 2;
282 ++nb_phase;
283 }
284 if (nb_phase < 3)
285 nb_phase = 1;
286 trace->info() << " NB PHASE=" << nb_phase;
287 nb_phase = 1;
288 if (nb_phase == 1) {
289 _getVariableValues(variable, unique_ids, values);
290 }
291 else {
292 Integer nb_done = 0;
293 for (Integer i = 0; i < nb_phase; ++i) {
294 Integer first = (i * size) / nb_phase;
295 Integer last = ((i + 1) * size) / nb_phase;
296 if ((i + 1) == nb_phase)
297 last = size;
298 Integer n = last - first;
299 nb_done += n;
300 trace->debug() << "GetVariableValue: first=" << first << " last=" << last << " n=" << n
301 << " size=" << size;
302 RealArrayView local_values(n, values.data() + first);
303 Int64ConstArrayView local_unique_ids(n, unique_ids.data() + first);
304 _getVariableValues(variable, local_unique_ids, local_values);
305 }
306 if (nb_done != size) {
307 trace->fatal() << "MpiParallelMng::getVariableValue() Internal error in size: "
308 << " size=" << size << " done=" << nb_done;
309 }
310 }
311}
312
313/*---------------------------------------------------------------------------*/
314/*---------------------------------------------------------------------------*/
315
316template <class Type> void GetVariablesValuesParallelOperation::
317_getVariableValues(ItemVariableScalarRefT<Type>& variable,
318 Int64ConstArrayView unique_ids,
319 ArrayView<Type> values)
320{
321 IParallelMng* pm = m_parallel_mng;
322 ItemGroup group = variable.itemGroup();
323 ITraceMng* msg = pm->traceMng();
324 IItemFamily* item_family = group.itemFamily();
325
326 // Pour éviter un bug MPI sur certaines machines,
327 // si la liste est vide, on crée une liste temporaire
328 UniqueArray<Int64> dummy_unique_ids;
329 UniqueArray<Real> dummy_values;
330 if (unique_ids.empty()) {
331 dummy_unique_ids.resize(1);
332 dummy_values.resize(1);
333 dummy_unique_ids[0] = NULL_ITEM_ID;
334 unique_ids = dummy_unique_ids.view();
335 values = dummy_values.view();
336 }
337
338 // Principe de fonctionnement.
339 // Chaque sous-domaine récupère la totalité des unique_ids dont on veut
340 // les valeurs (allGatherVariable).
341 // On alloue ensuite un tableau dimensionné à ce nombre de uniqueId() qui
342 // contiendra les valeurs des entités (tableau all_value).
343 // Chaque sous-domaine remplit ce tableau comme suit :
344 // * si l'entité lui appartient, remplit avec la valeur de la variable
345 // * sinon, remplit avec la valeur minimale possible suivant \a Type.
346 // Le processeur 0 effectue ensuite une réduction Max de ce tableau,
347 // qui contiendra alors la bonne valeur pour chacun de ses éléments.
348 // Il ne reste plus alors qu'à faire un 'scatter' symétrique du
349 // premier 'gather'.
350
351 Int64UniqueArray all_unique_ids;
352 pm->allGatherVariable(unique_ids, all_unique_ids);
353 Integer all_size = all_unique_ids.size();
354 Int32UniqueArray all_local_ids(all_size);
355 item_family->itemsUniqueIdToLocalId(all_local_ids, all_unique_ids, false);
356
357 ConstArrayView<Type> variable_a(variable.asArray());
358 UniqueArray<Type> all_values(all_size);
359
360 msg->debug() << "MpiParallelMng::_getVariableValues(): size=" << all_size
361 << " values_size=" << sizeof(Type) * all_size;
362
363 // Remplit le tableau des valeurs avec la valeur maximale possible
364 // pour le type. Il suffit ensuite de faire un ReduceMin
365 Type max_value = std::numeric_limits<Type>::max();
366 ItemInfoListView internal_items(item_family);
367
368 for (Integer i = 0; i < all_size; ++i) {
369 Integer lid = all_local_ids[i];
370 if (lid == NULL_ITEM_ID)
371 all_values[i] = max_value;
372 else {
373 all_values[i] = (internal_items[lid].isOwn()) ? variable_a[lid] : max_value;
374 }
375 }
376
377 pm->reduce(Parallel::ReduceMin, all_values);
378
379 // Scinde le tableau sur les autres processeurs
380 pm->scatterVariable(all_values, values, 0);
381}
382
383/*---------------------------------------------------------------------------*/
384/*---------------------------------------------------------------------------*/
385
386template <class Type> void GetVariablesValuesParallelOperation::
387_getVariableValuesSequential(ItemVariableScalarRefT<Type>& variable,
388 Int64ConstArrayView unique_ids,
389 ArrayView<Type> values)
390{
391 ItemGroup group = variable.itemGroup();
392 if (group.null())
393 ARCANE_FATAL("The variable '{0}' is not defined on a group.", variable.name());
394
395 IItemFamily* family = group.itemFamily();
396 Int32 size = unique_ids.size();
397 if (size != values.size())
398 ARCANE_FATAL("The arrays 'unique_ids' and 'values' don't have the same "
399 "number of elements (respectively {0} and {1}).",
400 size, values.size());
401
402 //TODO: faire par morceaux.
403 UniqueArray<Int32> local_ids(size);
404 family->itemsUniqueIdToLocalId(local_ids, unique_ids);
405 ConstArrayView<Type> variable_a(variable.asArray());
406 for (Integer i = 0; i < size; ++i)
407 values[i] = variable_a[local_ids[i]];
408}
409
410/*---------------------------------------------------------------------------*/
411/*---------------------------------------------------------------------------*/
412
413}
414
415/*---------------------------------------------------------------------------*/
416/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Vue modifiable d'un tableau d'un type T.
constexpr const_pointer data() const noexcept
Pointeur sur le début de la vue.
constexpr Integer size() const noexcept
Retourne la taille du tableau.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
ArrayView< T > view() const
Vue mutable sur ce tableau.
constexpr const_pointer data() const noexcept
Pointeur sur la mémoire allouée.
constexpr Integer size() const noexcept
Nombre d'éléments du tableau.
constexpr bool empty() const noexcept
true si le tableau est vide (size()==0)
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual void itemsUniqueIdToLocalId(Int32ArrayView local_ids, Int64ConstArrayView unique_ids, bool do_fatal=true) const =0
Converti un tableau de numéros uniques en numéros locaux.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
virtual ITimeStats * timeStats() const =0
Gestionnaire de statistiques associé (peut être nul)
virtual void allGatherVariable(ConstArrayView< char > send_buf, Array< char > &recv_buf)=0
Effectue un regroupement sur tous les processeurs.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
virtual void scatterVariable(ConstArrayView< char > send_buf, ArrayView< char > recv_buf, Integer root)=0
Scinde un tableau sur plusieurs processeurs.
virtual bool isParallel() const =0
Retourne true si l'exécution est parallèle.
virtual char reduce(eReduceType rt, char v)=0
Effectue la réduction de type rt sur le réel v et retourne la valeur.
Interface du gestionnaire de traces.
virtual TraceMessage fatal()=0
Flot pour un message d'erreur fatale.
virtual TraceMessage info()=0
Flot pour un message d'information.
virtual TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium)=0
Flot pour un message de debug.
Groupe d'entités de maillage.
Definition ItemGroup.h:49
IItemFamily * itemFamily() const
Famille d'entité à laquelle appartient ce groupe (0 pour le group nul)
Definition ItemGroup.h:123
bool null() const
true is le groupe est le groupe nul
Definition ItemGroup.h:70
Variable scalaire sur un type d'entité du maillage.
Positionne la phase de l'action en cours d'exécution.
Definition Timer.h:128
Vecteur 1D de données avec sémantique par valeur (style STL).
String name() const
Nom de la variable.
ItemVariableScalarRefT< Real > VariableItemReal
Grandeur de type réel.
Déclarations des types et méthodes utilisés par les mécanismes d'échange de messages.
Definition Parallel.h:50
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Int32 Integer
Type représentant un entier.
ConstArrayView< Int64 > Int64ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:567
UniqueArray< Real > RealUniqueArray
Tableau dynamique à une dimension de réels.
Definition UtilsTypes.h:436
ArrayView< Real > RealArrayView
Equivalent C d'un tableau à une dimension de réels.
Definition UtilsTypes.h:546
std::int32_t Int32
Type entier signé sur 32 bits.
Type
Type of JSON value.
Definition rapidjson.h:665