Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
GetVariablesValuesParallelOperation.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2023 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-2023 */
9/* */
10/* Opérations pour accéder aux valeurs de variables d'un autre sous-domaine. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/Array.h"
15#include "arcane/utils/ITraceMng.h"
16
17#include "arcane/Timer.h"
18#include "arcane/VariableTypes.h"
19#include "arcane/IParallelMng.h"
20#include "arcane/ISerializer.h"
21#include "arcane/SerializeMessage.h"
22#include "arcane/IItemFamily.h"
23
24#include "arcane/impl/GetVariablesValuesParallelOperation.h"
25
26#include <map>
27
28/*---------------------------------------------------------------------------*/
29/*---------------------------------------------------------------------------*/
30
31namespace Arcane
32{
33
34/*---------------------------------------------------------------------------*/
35/*---------------------------------------------------------------------------*/
36
37GetVariablesValuesParallelOperation::
38GetVariablesValuesParallelOperation(IParallelMng* pm)
39: m_parallel_mng(pm)
40{
41}
42
43/*---------------------------------------------------------------------------*/
44/*---------------------------------------------------------------------------*/
45
46GetVariablesValuesParallelOperation::
47~GetVariablesValuesParallelOperation()
48{
49}
50
51/*---------------------------------------------------------------------------*/
52/*---------------------------------------------------------------------------*/
53
54IParallelMng* GetVariablesValuesParallelOperation::
55parallelMng()
56{
57 return m_parallel_mng;
58}
59
60/*---------------------------------------------------------------------------*/
61/*---------------------------------------------------------------------------*/
62
63void GetVariablesValuesParallelOperation::
64getVariableValues(VariableItemReal& variable,
67 RealArrayView values)
68{
69 IParallelMng* pm = m_parallel_mng;
70 Timer::Phase tphase(pm->timeStats(),TP_Communication);
71
72 if (!pm->isParallel()){
73 _getVariableValuesSequential(variable,unique_ids,values);
74 return;
75 }
76
77 String func_id("MpiParallelMng::getVariableValues()");
78
79 ItemGroup group = variable.itemGroup();
80 ITraceMng* trace = pm->traceMng();
82
83 if (group.null())
84 trace->fatal() << "MpiParallelDispatchT::getVariableValues() "
85 << "the variable '" << variable.name() << "' is not defined "
86 << "on a group.";
87 Integer nb_item = unique_ids.size();
88 if (nb_item!=values.size())
89 trace->fatal() << "MpiParallelDispatchT::getVariableValues() "
90 << "the arrays 'unique_ids' and 'values' don't have the same "
91 << "number of elements (respectively "
92 << nb_item << " and " << values.size() << ").";
93 if (nb_item!=sub_domain_ids.size())
94 trace->fatal() << "MpiParallelDispatchT::getVariableValues() "
95 << "the arrays 'unique_ids' and 'sub_domains_ids' don't have the same "
96 << "number of elements (respectively "
97 << nb_item << " et " << sub_domain_ids.size() << ").";
98
99 typedef std::map<Int32,Helper> SubDomainUniqueIdMap;
101
102 for( Integer i=0; i<nb_item; ++i ){
103 Int32 sd = sub_domain_ids[i];
104 if (sd==NULL_SUB_DOMAIN_ID)
105 throw FatalErrorException(func_id,"null sub_domain_id");
106 }
107
108 for( Integer i=0; i<nb_item; ++i ){
109 Int32 sd = sub_domain_ids[i];
110 //TODO ne pas ajouter les éléments de son propre sous-domaine à la liste
112 h.m_unique_ids.add(unique_ids[i]);
113 h.m_indexes.add(i);
114 }
115
117 Integer my_rank = pm->commRank();
118 for( SubDomainUniqueIdMap::const_iterator b=sub_domain_list.begin();
119 b!=sub_domain_list.end(); ++b ){
120 Int32 sd = b->first;
121 Integer n = b->second.m_unique_ids.size();
125 }
126
130 for( Integer i=0, is=total_sub_domain_nb_to_send.size(); i<is; i+=3 ){
133 //Integer nb_exchange = total_sub_domain_nb_to_send[i+2];
134 //trace->info() << " SEND=" << rank_send
135 //<< " RECV= " << rank_recv
136 //<< " N= " << nb_exchange;
137 if (rank_send==rank_recv)
138 continue;
139 SerializeMessage* sm = 0;
140 if (rank_recv==my_rank){
141 //trace->info() << " ADD RECV MESSAGE recv=" << rank_recv << " send=" << rank_send;
142 sm = new SerializeMessage(rank_recv,rank_send,ISerializeMessage::MT_Recv);
143 }
144 else if (rank_send==my_rank){
145 //trace->info() << " ADD SEND MESSAGE recv=" << rank_recv << " send=" << rank_send;
146 sm = new SerializeMessage(rank_send,rank_recv,ISerializeMessage::MT_Send);
147 ISerializer* s = sm->serializer();
148 s->setMode(ISerializer::ModeReserve);
149 auto xiter = sub_domain_list.find(rank_recv);
150 if (xiter==sub_domain_list.end())
151 ARCANE_FATAL("Can not find rank '{0}'",rank_recv);
152 Span<const Int64> z_unique_ids = xiter->second.m_unique_ids;
153 Int64 nb = z_unique_ids.size();
154 s->reserve(DT_Int64,1); // Pour la taille
155 s->reserveSpan(DT_Int64,nb); // Pour le tableau
156 s->allocateBuffer();
157 s->setMode(ISerializer::ModePut);
158 s->putInt64(nb);
160 }
161 if (sm)
162 messages.add(sm);
163 }
164
166
170
173 for( Integer i=0, is=messages.size(); i<is; ++i ){
176 if (sm->isSend()){
177 // Pour recevoir les valeurs
178 //trace->info() << " ADD RECV2 MESSAGE recv=" << my_rank << " send=" << sm->destSubDomain();
179 new_sm = new SerializeMessage(my_rank,sm->destination().value(),ISerializeMessage::MT_Recv);
180 }
181 else{
182 ISerializer* s = sm->serializer();
183 s->setMode(ISerializer::ModeGet);
184 Int64 nb = s->getInt64();
185 tmp_unique_ids.resize(nb);
186 tmp_local_ids.resize(nb);
187 tmp_values.resize(nb);
189 item_family->itemsUniqueIdToLocalId(tmp_local_ids,tmp_unique_ids);
190 for( Integer z=0; z<nb; ++z ){
192 tmp_values[z] = variable[item];
193 }
194
195 //trace->info() << " ADD SEND2 MESSAGE recv=" << my_rank << " send=" << sm->destSubDomain();
196 new_sm = new SerializeMessage(my_rank,sm->destination().value(),ISerializeMessage::MT_Send);
197 ISerializer* s2 = new_sm->serializer();
198 s2->setMode(ISerializer::ModeReserve);
199 s2->reserve(DT_Int64,1);
200 s2->reserveSpan(DT_Real,nb);
201 s2->allocateBuffer();
202 s2->setMode(ISerializer::ModePut);
203 s2->putInt64(nb);
204 s2->putSpan(tmp_values);
205 }
207 }
208
209 // Supprime les messages qui ne sont plus utilisés
210 _deleteMessages(messages);
211
213
214 for( Integer i=0, is=values_messages.size(); i<is; ++i ){
216 //ISerializeMessage* new_sm = 0;
217 if (sm->isSend()){
218 }
219 else{
220 ISerializer* s = sm->serializer();
221 s->setMode(ISerializer::ModeGet);
222 Int64 nb = s->getInt64();
223 tmp_values.resize(nb);
224 Int32 sender = sm->destination().value();
226 //trace->info() << " GET VALUES from=" << sm->destSubDomain() << " n=" << nb;
227 Span<const Int32> indexes = sub_domain_list[sender].m_indexes;
228 for( Int64 z=0; z<nb; ++z )
229 values[indexes[z]] = tmp_values[z];
230 }
231 }
232
233 // Enfin, traite ses propres éléments
234 // TODO: FAIRE CE TRAITEMENT EN ATTENDANT LES MESSAGES
235 {
237 Span<const Int32> indexes(h.m_indexes.constSpan());
238 Int64 nb = h.m_unique_ids.largeSize();
239 tmp_local_ids.resize(nb);
240 item_family->itemsUniqueIdToLocalId(tmp_local_ids,h.m_unique_ids);
241 for( Int64 z=0; z<nb; ++z ){
243 values[indexes[z]] = variable[item];
244 }
245 }
246
247 // Supprime les messages qui ne sont plus utilisés
248 _deleteMessages(values_messages);
249
250#if 0
251 {
252 // Pour faire une petite vérification
253 Integer nb_values = values.size();
255 ref_values.fill(0.0);
256 getVariableValues(variable,unique_ids,ref_values);
257 bool has_error = false;
258 for( Integer i=0; i<nb_values; ++i ){
259 if (!math::isEqual(ref_values[i],values[i])){
260 trace->pinfo() << " Incorrect values ref=" << ref_values[i] << " v=" << values[i];
261 has_error = true;
262 }
263 }
264 if (has_error)
265 trace->fatal() << func_id << " incorrect values";
266 }
267#endif
268}
269
270/*---------------------------------------------------------------------------*/
271/*---------------------------------------------------------------------------*/
272
273void GetVariablesValuesParallelOperation::
274getVariableValues(VariableItemReal& variable,
276 RealArrayView values)
277{
278 IParallelMng* pm = m_parallel_mng;
279 Timer::Phase tphase(pm->timeStats(),TP_Communication);
280
281 if (!pm->isParallel()){
282 _getVariableValuesSequential(variable,unique_ids,values);
283 return;
284 }
285
286 ItemGroup group = variable.itemGroup();
287 ITraceMng* trace = pm->traceMng();
288 if (group.null())
289 trace->fatal() << "MpiParallelDispatchT::getVariableValues() "
290 << "the variable '" << variable.name() << "' is not defined "
291 << "on a group.";
292 Integer size = unique_ids.size();
293 if (size!=values.size())
294 trace->fatal() << "MpiParallelDispatchT::getVariableValues() "
295 << "the arrays 'unique_ids' and 'values' don't have the same "
296 << "number of elements (respectivemely "
297 << size << " and " << values.size() << ").";
298
299 Integer nb_proc = pm->commSize();
300 Integer nb_phase = 0;
301 while(nb_proc!=0 && nb_phase<32){
302 nb_proc /= 2;
303 ++nb_phase;
304 }
305 if (nb_phase<3)
306 nb_phase = 1;
307 trace->info() << " NB PHASE=" << nb_phase;
308 nb_phase = 1;
309 if (nb_phase==1){
310 _getVariableValues(variable,unique_ids,values);
311 }
312 else{
313 Integer nb_done = 0;
314 for( Integer i=0; i<nb_phase; ++i ){
315 Integer first = (i*size) / nb_phase;
316 Integer last = ((i+1)*size) / nb_phase;
317 if ((i+1)==nb_phase)
318 last = size;
319 Integer n = last - first;
320 nb_done += n;
321 trace->debug() << "GetVariableValue: first=" << first << " last=" << last << " n=" << n
322 << " size=" << size;
323 RealArrayView local_values(n,values.data()+first);
325 _getVariableValues(variable,local_unique_ids,local_values);
326 }
327 if (nb_done!=size){
328 trace->fatal() << "MpiParallelMng::getVariableValue() Internal error in size: "
329 << " size=" << size << " done=" << nb_done;
330 }
331 }
332}
333
334/*---------------------------------------------------------------------------*/
335/*---------------------------------------------------------------------------*/
336
337void GetVariablesValuesParallelOperation::
338_deleteMessages(Array<ISerializeMessage*>& messages)
339{
340 for( Integer i=0, is=messages.size(); i<is; ++i )
341 delete messages[i];
342 messages.clear();
343}
344
345/*---------------------------------------------------------------------------*/
346/*---------------------------------------------------------------------------*/
347
348template<class Type> void GetVariablesValuesParallelOperation::
349_getVariableValues(ItemVariableScalarRefT<Type>& variable,
350 Int64ConstArrayView unique_ids,
351 ArrayView<Type> values)
352{
353 IParallelMng* pm = m_parallel_mng;
354 ItemGroup group = variable.itemGroup();
355 ITraceMng* msg = pm->traceMng();
356 IItemFamily* item_family = group.itemFamily();
357
358 // Pour eviter un bug MPI sur certaines machines,
359 // si la liste est vide, creer une liste temporaire
360 UniqueArray<Int64> dummy_unique_ids;
361 UniqueArray<Real> dummy_values;
362 if (unique_ids.empty()){
363 dummy_unique_ids.resize(1);
364 dummy_values.resize(1);
365 dummy_unique_ids[0] = NULL_ITEM_ID;
366 unique_ids = dummy_unique_ids.view();
367 values = dummy_values.view();
368 }
369
370 // Principe de fonctionnement.
371 // Chaque sous-domaine recupère la totalité des unique_ids dont on veut
372 // les valeurs (allGatherVariable).
373 // On alloue ensuite un tableau dimensionné à ce nombre de unique_id qui
374 // contiendra les valeurs des entités (tableau all_value).
375 // Chaque sous-domaine remplit ce tableau comme suit:
376 // - si l'entité lui appartient, remplit avec la valeur de la variable
377 // - sinon, remplit avec la valeur minimale possible suivant \a Type.
378 // Le processeur 0 effectue ensuite une réduction Max de ce tableau,
379 // qui contiendra alors la bonne valeur pour chacun de ses éléments.
380 // Il ne reste plus alors qu'a faire un 'scatter' symétrique du
381 // premier 'gather'.
382
383 Int64UniqueArray all_unique_ids;
384 pm->allGatherVariable(unique_ids,all_unique_ids);
385 Integer all_size = all_unique_ids.size();
386 Int32UniqueArray all_local_ids(all_size);
387 item_family->itemsUniqueIdToLocalId(all_local_ids,all_unique_ids,false);
388
389 ConstArrayView<Type> variable_a(variable.asArray());
390 UniqueArray<Type> all_values(all_size);
391
392 msg->debug() << "MpiParallelMng::_getVariableValues(): size=" << all_size
393 << " values_size=" << sizeof(Type)*all_size;
394
395 // Remplit le tableau des valeurs avec la valeur maximale possible
396 // pour le type. Il suffit ensuite de faire un ReduceMin
397 Type max_value = std::numeric_limits<Type>::max();
398 ItemInfoListView internal_items(item_family);
399
400 for( Integer i=0; i<all_size; ++i ){
401 Integer lid = all_local_ids[i];
402 if (lid==NULL_ITEM_ID)
403 all_values[i] = max_value;
404 else{
405 all_values[i] = (internal_items[lid].isOwn()) ? variable_a[lid] : max_value;
406 }
407 }
408
409 //MpiParallelDispatchT<double>* mpd = dynamic_cast<MpiParallelDispatchT<double>*>(m_double);
410 pm->reduce(Parallel::ReduceMin,all_values);
411
412 // Scinde le tableau sur les autres processeurs
413 pm->scatterVariable(all_values,values,0);
414}
415
416/*---------------------------------------------------------------------------*/
417/*---------------------------------------------------------------------------*/
418
419template<class Type> void GetVariablesValuesParallelOperation::
420_getVariableValuesSequential(ItemVariableScalarRefT<Type>& variable,
421 Int64ConstArrayView unique_ids,
422 ArrayView<Type> values)
423{
424 ITraceMng* trace = m_parallel_mng->traceMng();
425 ItemGroup group = variable.itemGroup();
426 if (group.null())
427 trace->fatal() << "SequentialParallelDispatchT::getVariableValues() "
428 << "the variable '" << variable.name() << "' is not defined "
429 << "on a group.";
430 //eItemKind ik = group.itemKind();
431 IItemFamily* family = group.itemFamily();
432 Integer size = unique_ids.size();
433 if (size!=values.size())
434 trace->fatal() << "SequentialParallelDispatchT::getVariableValues() "
435 << "the arrays 'unique_ids' and 'values' don't have the same "
436 << "number of elements (respectively "
437 << size << " and " << values.size() << ").";
438
439 //TODO: faire par morceaux.
440 Int32UniqueArray local_ids(size);
441 family->itemsUniqueIdToLocalId(local_ids,unique_ids);
442 ConstArrayView<Type> variable_a(variable.asArray());
443 for( Integer i=0; i<size; ++i )
444 values[i] = variable_a[local_ids[i]];
445}
446
447/*---------------------------------------------------------------------------*/
448/*---------------------------------------------------------------------------*/
449
450}
451
452/*---------------------------------------------------------------------------*/
453/*---------------------------------------------------------------------------*/
454
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Interface d'une famille d'entités.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual ITimeStats * timeStats() const =0
Gestionnaire de statistiques associé (peut être nul)
virtual void processMessages(ConstArrayView< ISerializeMessage * > messages)=0
Exécute les opérations des messages messages.
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.
virtual IItemFamily * itemFamily() const =0
Famille d'entité associée.
Groupe d'entités de maillage.
Definition ItemGroup.h:49
bool null() const
true is le groupe est le groupe nul
Definition ItemGroup.h:70
Vue sur une liste pour obtenir des informations sur les entités.
Classe de base d'un élément de maillage.
Definition Item.h:83
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Message utilisant un SerializeBuffer.
Positionne la phase de l'action en cours d'exécution.
Definition Timer.h:128
IVariable * variable() const
Variable associée.
String name() const
Nom de la variable.
Vue modifiable d'un tableau d'un type T.
constexpr Integer size() const noexcept
Retourne la taille du tableau.
constexpr const_pointer data() const noexcept
Pointeur sur le début de la vue.
Vue constante d'un tableau de type T.
Exception lorsqu'une erreur fatale est survenue.
virtual void allocateBuffer()=0
Alloue la mémoire du sérialiseur.
virtual void reserveSpan(eDataType dt, Int64 n)=0
Réserve de la mémoire pour n valeurs de dt.
virtual void putSpan(Span< const Real > values)
Ajoute le tableau values.
virtual void getSpan(Span< Real > values)
Récupère le tableau values.
virtual Int64 getInt64()=0
Récupère une taille.
virtual void reserve(eDataType dt, Int64 n)=0
Réserve de la mémoire pour n objets de type dt.
virtual void setMode(eMode new_mode)=0
Positionne le fonctionnement actuel.
virtual void putInt64(Int64 value)=0
Ajoute l'entier value.
Interface du gestionnaire de traces.
virtual TraceMessageDbg debug(Trace::eDebugLevel=Trace::Medium)=0
Flot pour un message de debug.
virtual TraceMessage pinfo()=0
Flot pour un message d'information parallèle.
virtual TraceMessage info()=0
Flot pour un message d'information.
virtual TraceMessage fatal()=0
Flot pour un message d'erreur fatale.
Chaîne de caractères unicode.
Vecteur 1D de données avec sémantique par valeur (style STL).
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
UniqueArray< Int64 > Int64UniqueArray
Tableau dynamique à une dimension d'entiers 64 bits.
Definition UtilsTypes.h:513
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:515
@ DT_Int64
Donnée de type entier 64 bits.
Definition DataTypes.h:44
@ DT_Real
Donnée de type réel.
Definition DataTypes.h:41
Int32 Integer
Type représentant un entier.
Type
Type of JSON value.
Definition rapidjson.h:665