TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
MD_Vector_tools.cpp
1/****************************************************************************
2* Copyright (c) 2026, 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 <Schema_Comm_Vecteurs.h>
17#include <MD_Vector_composite.h>
18#include <Echange_EV_Options.h>
19#include <MD_Vector_tools.h>
20#include <MD_Vector_seq.h>
21#include <communications.h>
22#include <Schema_Comm.h>
23#include <TRUSTTrav.h>
24#include <Perf_counters.h>
25#include <vector>
26#include <typeindex>
27
28Schema_Comm_Vecteurs MD_Vector_tools::comm;
29MD_Vector MD_Vector_tools::last_md;
30static std::type_index last_type_idx(typeid(void *)); // love this one ;-)
31int MD_Vector_tools::last_linesize = 0;
32Echange_EV_Options MD_Vector_tools::last_opt;
33
34
36{
37public:
38 // for each item in the source vector, should it be kept
40 // new C index of each item in the source vector to renumber.
41 // (for items not kept, must point to a geometrically equivalent item)
42 // renum_ can be a global or a local number.
43 IntVect renum_;
44 // number of non-zero items in items_to_keep_:
46};
47
48namespace
49{
50
51/** Should we use resize() or resize_dim0 to resize array ...
52 */
53template <typename _SIZE_, typename _TYPE_>
54bool resize_tab_or_vect(TRUSTVect<_TYPE_,_SIZE_>& v, _SIZE_ sz, int sz_r, RESIZE_OPTIONS opt)
55{
56 using TAB = TRUSTTab<_TYPE_, _SIZE_>;
57 TAB* vv = dynamic_cast<TAB*>(&v);
58 if (vv)
59 {
60 TAB& t = *vv;
61 const _SIZE_ n = t.dimension_tot(0);
62 if (n == sz_r || n == 0) t.resize_dim0(sz, opt);
63 else if (n == sz) { /* ok no resize */ }
64 else return true;
65 }
66 else
67 {
68 const _SIZE_ n = v.size_totale();
69 if (n == sz_r || n == 0) { v.resize(sz, opt); }
70 else if (n == sz) { /* ok no resize */ }
71 else return true;
72 }
73 return false;
74}
75
76} // end anonymous NS
77
78template <class VECT, class TAB>
79static void creer_tableau_distribue_(const MD_Vector& md, VECT& v, RESIZE_OPTIONS opt)
80{
81 if (v.get_md_vector())
82 {
83 // Si ce message apparait et qu'on est sur de ce qu'on fait,
84 // faire ceci avant d'appeler creer_tableau_distribue:
85 // vect.set_md_vector(MD_Vector()); // Annule le descripteur et garde le vecteur.
86 // ou
87 // vect.reset(); // Detruit completement le contenu du vecteur
88 Cerr << "Internal error in MD_Vector_tools::creer_tableau_distribue:\n"
89 << " Vector already has a parallel vector structure" << finl;
91 }
92 int sz = md->get_nb_items_tot();
93 // Attention, sz_r peut valoir -1 dans certains cas. Alors le test n==sz_r sera toujours faux,
94 // mais c'est bien ce qu'on veut...
95 int sz_r = md->get_nb_items_reels();
96 bool err = ::resize_tab_or_vect(v, sz, sz_r, opt);
97
98 if (err)
99 {
100 Cerr << "Internal error in MD_Vector_tools::creer_tableau_distribue:\n"
101 << " Input vector has wrong size or dimension(0): expected 0 or size_reele=" << sz_r << finl;
103 }
104 v.set_md_vector(md);
105}
106
107template <typename _TYPE_, typename _SIZE_>
108static void creer_tableau_seq_(const MD_Vector& md, TRUSTVect<_TYPE_,_SIZE_>& v, RESIZE_OPTIONS opt)
109{
110 const MD_Vector_seq * md_seq = dynamic_cast<const MD_Vector_seq *>(&md.valeur());
111 assert(md_seq != nullptr); // sequential, cast should always be OK
112
113 // _SIZE_ might be int, but md_seq->get_nb_items is always trustIdType:
114 trustIdType sz0 = md_seq->get_nb_items();
115 _SIZE_ sz = std::is_same<_SIZE_, int>::value ? Process::check_int_overflow(sz0) : sz0;
116
117 bool err = ::resize_tab_or_vect(v, sz, -1, opt);
118 if (err)
119 {
120 Cerr << "Internal error in MD_Vector_tools::creer_tableau_seq_:\n"
121 << " Input vector has wrong size or dimension(0)" << finl;
123 }
124 // Important - keep the same MD_Vector object:
125 v.set_md_vector(md);
126}
127
128
129/*! @brief transforme v en un tableau parallele ayant la structure md.
130 *
131 * md doit est non nul !
132 * Les dimension(i>=1) du tableau v (si c'est un IntTab ou DoubleTab) sont conservees,
133 * les dimension(0) et dimension_tot(0) sont modifiees en fonction du nombre d'items
134 * specifies dans le MD_Vector.
135 * La dimension initiale du vecteur doit etre soit 0, soit md.get_nb_items_reels(),
136 * soit md.get_nb_items_tot(). Si besoin, la taille du tableau est modifiee et on
137 * initialise le tableau selon opt.
138 * ATTENTION, virtual_exchange() n'est PAS appele. Les cases virtuelles ne sont pas initialisees...
139 */
140void MD_Vector_tools::creer_tableau_distribue(const MD_Vector& md, Array_base& v, RESIZE_OPTIONS opt)
141{
142 if (!md)
143 {
144 Cerr << "Error in MD_Vector_tools::creer_tableau_distribue(): MD_Vector is null" << finl;
146 }
147
148 IntVect* intV = dynamic_cast<IntVect*>(&v);
149 DoubleVect* doubleV = dynamic_cast<DoubleVect*>(&v);
150 FloatVect* floatV = dynamic_cast<FloatVect*>(&v);
151#if INT_is_64_ == 2
152 BigIntVect* bintV = dynamic_cast<BigIntVect*>(&v);
153 TIDVect* tidV = dynamic_cast<TIDVect*>(&v);
154 BigTIDVect* btidV = dynamic_cast<BigTIDVect*>(&v);
155 BigDoubleVect* bdoubleV = dynamic_cast<BigDoubleVect*>(&v);
156#endif
157
158 if(sub_type(MD_Vector_seq, md.valeur()))
159 {
160 /* [ABN] Here we would like to do
161 assert(Process::is_sequential());
162 * but we can not: for example when reading a MED file we construct temporarily a dummy domain
163 * which looks like a sequential one, even if we are actually running parallel ... too bad.
164 */
165 if (intV) creer_tableau_seq_<int, int>(md, *intV, opt);
166 else if (doubleV) creer_tableau_seq_<double, int>(md, *doubleV, opt);
167 else if (floatV) creer_tableau_seq_<float, int>(md, *floatV, opt);
168#if INT_is_64_ == 2
169 else if (bintV) creer_tableau_seq_<int, trustIdType>(md, *bintV, opt);
170 else if (tidV) creer_tableau_seq_<trustIdType, int>(md, *tidV, opt);
171 else if (btidV) creer_tableau_seq_<trustIdType, trustIdType>(md, *btidV, opt);
172 else if (bdoubleV) creer_tableau_seq_<double, trustIdType>(md, *bdoubleV, opt);
173#endif
174 else
175 {
176 Cerr << "Internal error in MD_Vector_tools::creer_tableau_seq():\n"
177 << " Invalid array type " << v.que_suis_je()
178 << "\n Array must be a subtype of IntVect or DoubleVect or FloatVect" << finl;
180 }
181 }
182 else // parallel computation **or** composite descriptor (MD_Vector_composite)
183 {
184 if (intV) creer_tableau_distribue_<IntVect, IntTab>(md, *intV, opt);
185 else if (doubleV) creer_tableau_distribue_<DoubleVect, DoubleTab>(md, *doubleV, opt);
186 else if (floatV) creer_tableau_distribue_<FloatVect, FloatTab>(md, *floatV, opt);
187#if INT_is_64_ == 2
188 else if (tidV) creer_tableau_distribue_<TIDVect, TIDTab>(md, *tidV, opt);
189 else if (bintV || btidV || bdoubleV)
190 {
191 Cerr << "Internal error in MD_Vector_tools::creer_tableau_distribue(const MD_Vector & md, Array_base & v):" << finl
192 << " -> Trying to create a distributed array for a 'big' array (greater than 32b) - shoud never be necessary." << finl;
194 }
195#endif
196 else
197 {
198 Cerr << "Internal error in MD_Vector_tools::creer_tableau_distribue(const MD_Vector & md, Array_base & v):\n"
199 << " Invalid array type " << v.que_suis_je()
200 << "\n Array must be a subtype of IntVect or DoubleVect or FloatVect" << finl;
202 }
203 }
204}
205
206
207template <typename _TYPE_>
208void MD_Vector_tools::perform_virtual_exchange(const MD_Vector& md, TRUSTVect<_TYPE_>& v, const Echange_EV_Options& opt, IsExchangeBlocking is_exchange_blocking, const std::string kernel_name)
209{
210 const MD_Vector_base& mdv = md.valeur();
211 const std::type_index type_idx(typeid(_TYPE_));
212
213 if ((is_exchange_blocking == IsExchangeBlocking::DefaultBlocking)||(is_exchange_blocking == IsExchangeBlocking::NonBlockingStart))
214 {
215
216 if (md == last_md && v.line_size() == last_linesize && last_type_idx == type_idx && last_opt == opt)
217 {
218 /* Do nothing if not the first pass, and nothing (including data type) has changed */
219 }
220 else
221 {
222 last_md = md;
223 last_linesize = v.line_size();
224 last_type_idx = type_idx;
225 last_opt = opt;
226 comm.begin_init();
227 mdv.initialize_comm(opt, comm, v);
228 comm.end_init();
229 }
230 bool bufferOnDevice = Process::is_parallel() && v.isDataOnDevice();
231 comm.begin_comm(bufferOnDevice); // buffer allocated on device
232 mdv.prepare_send_data(opt, comm, v); // pack buffer on device (read_from_vect_items)
233 }
234 comm.exchange(is_exchange_blocking, kernel_name); // buffer d2h + MPI + buffer h2d
235 if ((is_exchange_blocking == IsExchangeBlocking::DefaultBlocking)||(is_exchange_blocking == IsExchangeBlocking::NonBlockingFinish))
236 {
237 mdv.process_recv_data(opt, comm, v); // unpack buffer on device (write_to_vect_items + write_to_vect_blocs)
238 comm.end_comm();
239 }
240}
241
242template<typename _TYPE_>
243void MD_Vector_tools::select_virtual_exchange_operation(const MD_Vector& md, TRUSTVect<_TYPE_>& v, MD_Vector_tools::Operations_echange opt, IsExchangeBlocking is_exchange_blocking, const std::string kernel_name)
244{
245 switch(opt)
246 {
248 perform_virtual_exchange(md, v, echange_ev_opt_default,is_exchange_blocking, kernel_name);
249 break;
251 perform_virtual_exchange(md, v, Echange_EV_Options(Echange_EV_Options::SUM));
252 break;
254 perform_virtual_exchange(md, v, Echange_EV_Options(Echange_EV_Options::SUM));
255 perform_virtual_exchange(md, v, echange_ev_opt_default);
256 break;
258 perform_virtual_exchange(md, v, Echange_EV_Options(Echange_EV_Options::MAX));
259 break;
261 perform_virtual_exchange(md, v, Echange_EV_Options(Echange_EV_Options::MINCOL1));
262 break;
263 default:
264 Cerr << "select_virtual_exchange_operation operation not implemented" << finl;
266 }
267}
268
269template<typename _TYPE_>
270inline void MD_Vector_tools::call_virtual_exchange(TRUSTVect<_TYPE_>& v, MD_Vector_tools::Operations_echange opt, IsExchangeBlocking is_exchange_blocking, const std::string kernel_name)
271{
272 const MD_Vector& md = v.get_md_vector();
273 if (md && Process::is_parallel())
274 {
275 // [ABN] in some weird cases (like building a temporary domain when reading a MED file)
276 // we might end up calling the current method with a sequential MD_Vector:
277 if (sub_type(MD_Vector_seq, md.valeur())) return;
278 //Only time synchronous virtual exchange
279 if (is_exchange_blocking == IsExchangeBlocking::DefaultBlocking) statistics().begin_count(STD_COUNTERS::virtual_swap);
280 select_virtual_exchange_operation(v.get_md_vector(), v, opt,is_exchange_blocking, kernel_name);
281 if (is_exchange_blocking == IsExchangeBlocking::DefaultBlocking) statistics().end_count(STD_COUNTERS::virtual_swap);
282 }
283 //else Cerr << "Warning: A call to ::virtual_exchange() is done on a non-distributed vector." << finl; /Process::exit();
284}
285
286void MD_Vector_tools::echange_espace_virtuel(IntVect& v, Operations_echange opt, IsExchangeBlocking is_exchange_blocking, const std::string kernel_name) { call_virtual_exchange<int>(v,opt, is_exchange_blocking, kernel_name); }
287#if INT_is_64_ == 2
288void MD_Vector_tools::echange_espace_virtuel(TIDVect& v, Operations_echange opt, IsExchangeBlocking is_exchange_blocking, const std::string kernel_name) { call_virtual_exchange<trustIdType>(v,opt,is_exchange_blocking, kernel_name); }
289#endif
290void MD_Vector_tools::echange_espace_virtuel(DoubleVect& v, Operations_echange opt, IsExchangeBlocking is_exchange_blocking, const std::string kernel_name) { call_virtual_exchange<double>(v,opt,is_exchange_blocking, kernel_name); }
291void MD_Vector_tools::echange_espace_virtuel(FloatVect& v, Operations_echange opt, IsExchangeBlocking is_exchange_blocking, const std::string kernel_name) { call_virtual_exchange<float>(v,opt,is_exchange_blocking, kernel_name); }
292
294{
295 Cerr << "MD_Vector_tools::compute_sequential_items_index" << finl;
297}
298
299/*! @brief cree un descripteur pour un sous-ensemble d'un vecteur.
300 *
301 * renum fournit la structure et le descripteur du vecteur source (doit avoir line_size==1)
302 * renum doit contenir -1 pour les items du vecteur source a ne pas conserver et une
303 * valeur positive ou nulle pour les items a conserver.
304 * La valeur renum[i] donne l'indice de cet item dans le nouveau tableau.
305 * Attention, si un item du vecteur source est recu d'un autre processeur et doit etre conserve,
306 * ce meme item doit aussi etre conserve sur le processeur qui envoie cet item.
307 *
308 */
309void MD_Vector_tools::creer_md_vect_renum(const IntVect& renum, MD_Vector& md_vect)
310{
311 const MD_Vector& src_md = renum.get_md_vector();
312 if (!src_md)
313 {
314 Cerr << "Internal error in MD_Vector_tools::creer_md_vect_renum: descripteur nul !" << finl;
316 }
317 if (renum.line_size() != 1)
318 {
319 Cerr << "Internal error in MD_Vector_tools::creer_md_vect_renum: line_size != 1" << finl;
321 }
322 src_md->fill_md_vect_renum(renum, md_vect);
323}
324
325/*! @brief Idem que creer_md_vect_renum() mais cree une numerotation par defaut.
326 *
327 * Le tableau flags_renum doit contenir en entree une valeur POSITIVE OU NULLE pour les
328 * valeurs a conserver et une valeur negative pour les autres.
329 * En sortie, flags_renum contient l'indice de l'item dans le tableau reduit s'il est
330 * conserve, sinon la valeur d'origine non modifiee.
331 * Les items sont places dans l'ordre croissant de leur indice local sur dans le descripteur
332 * d'origine.
333 *
334 */
335void MD_Vector_tools::creer_md_vect_renum_auto(IntVect& flags_renum, MD_Vector& md_vect)
336{
337 const int n = flags_renum.size_array();
338 int count = 0;
339 for (int i = 0; i < n; i++)
340 {
341 int x = flags_renum[i];
342 if (x >= 0)
343 flags_renum[i] = count++;
344 }
345 creer_md_vect_renum(flags_renum, md_vect);
346}
347
348/*! @brief dumps vector v with its parallel descriptor to os.
349 *
350 * os must be a file type with one file per process (no shared file).
351 *
352 */
353void MD_Vector_tools::dump_vector_with_md(const DoubleVect& v, Sortie& os)
354{
355 assert(v.line_size() == 1); // Only Vect! not tab.
356
357 const MD_Vector_base& md = v.get_md_vector().valeur();
358 os << md.que_suis_je() << finl;
359 os << md << finl;
360
361 os << v.size_array() << finl;
362 os.put(v.addr(), v.size_array(), v.line_size());
363 os << finl;
364}
365
366/*! @brief restores a vector saved by dump_vector_with_md.
367 *
368 * The code must run with the same number of processors.
369 * "v" will have a newly created copy of the descriptor (not equal to any
370 * other descriptor previously loaded). If "identical" descriptors are needed
371 * for several vectors, you might want to call set_md_vector() afterwards to
372 * attach another descriptor. See save_matrice_conditionnel()
373 */
375{
376
377 v.reset();
378 OWN_PTR(MD_Vector_base) md_ptr;
379 Nom md_type;
380 is >> md_type;
381 md_ptr.typer(md_type);
382 is >> md_ptr.valeur();
383
384 // Creation du MD_Vector attache au tableau
385 MD_Vector md;
386 md.copy(md_ptr.valeur());
387
388 DoubleVect toto;
389 toto.resize(md_ptr->get_nb_items_tot(), RESIZE_OPTIONS::NOCOPY_NOINIT);
390 int size_tot;
391 is >> size_tot;
392 is.get(toto.addr(), size_tot);
393 toto.set_md_vector(md);
394
395 // Attache v a toto et oublie toto...
396 v.reset();
397 v.ref(toto);
398}
Empty class used as a base for all the arrays.
Definition Array_base.h:41
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual int get(int *ob, std::streamsize n)
Definition Entree.cpp:222
Base class for distributed vectors parallel descriptors.
virtual void process_recv_data(const Echange_EV_Options &opt, Schema_Comm_Vecteurs &, DoubleVect &) const =0
virtual void prepare_send_data(const Echange_EV_Options &opt, Schema_Comm_Vecteurs &, DoubleVect &) const =0
virtual void initialize_comm(const Echange_EV_Options &opt, Schema_Comm_Vecteurs &, DoubleVect &) const =0
virtual int get_nb_items_tot() const
virtual int get_nb_items_reels() const
virtual void fill_md_vect_renum(const IntVect &renum, MD_Vector &md_vect) const =0
Dummy parallel descriptor used for sequential computations.
trustIdType get_nb_items() const
static void dump_vector_with_md(const DoubleVect &, Sortie &)
dumps vector v with its parallel descriptor to os.
static void creer_md_vect_renum_auto(IntVect &flags_renum, MD_Vector &md_vect)
Idem que creer_md_vect_renum() mais cree une numerotation par defaut.
static void creer_tableau_distribue(const MD_Vector &, Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
transforme v en un tableau parallele ayant la structure md.
static void restore_vector_with_md(DoubleVect &, Entree &)
restores a vector saved by dump_vector_with_md.
static void creer_md_vect_renum(const IntVect &renum, MD_Vector &md_vect)
cree un descripteur pour un sous-ensemble d'un vecteur.
static void compute_sequential_items_index(const MD_Vector &, MD_Vector_renumber &, int line_size=1)
static void echange_espace_virtuel(IntVect &, Operations_echange opt=ECHANGE_EV, IsExchangeBlocking is_exchange_blocking=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")
: Cette classe est un OWN_PTR mais l'objet pointe est partage entre plusieurs
Definition MD_Vector.h:48
void copy(const MD_Vector_base &)
construction d'un objet MD_Vector par copie d'un objet existant.
Definition MD_Vector.cpp:26
const MD_Vector_base & valeur() const
Definition MD_Vector.h:77
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
void begin_count(const STD_COUNTERS &std_cnt, int counter_lvl=-100000)
void end_count(const std::string &custom_count_name, int count_increment=1, long int quantity_increment=0)
End the count of a counter and update the counter values.
static int check_int_overflow(trustIdType)
Definition Process.cpp:428
static bool is_parallel()
Definition Process.cpp:110
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
Classe de base des flux de sortie.
Definition Sortie.h:52
virtual int put(const unsigned *ob, std::streamsize n, std::streamsize nb_colonnes=1)
Definition Sortie.cpp:101
_SIZE_ size_array() const
_TYPE_ * addr()
bool isDataOnDevice() const
: Tableau a n entrees pour n<= 4.
Definition TRUSTTab.h:31
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
int line_size() const
Definition TRUSTVect.tpp:67
virtual void set_md_vector(const MD_Vector &)
void reset() override
met l'objet dans l'etat obtenu par le constructeur par defaut.
Definition TRUSTVect.h:189
void resize(_SIZE_, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTVect.tpp:91
virtual const MD_Vector & get_md_vector() const
Definition TRUSTVect.h:123
virtual void ref(const TRUSTVect &)