TrioCFD 1.9.9_beta
TrioCFD documentation
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 // If this message appears and you know what you are doing,
84 // do this before calling creer_tableau_distribue:
85 // vect.set_md_vector(MD_Vector()); // Cancels the descriptor and keeps the vector.
86 // or
87 // vect.reset(); // Completely destroys the vector contents
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 // Note: sz_r may be -1 in some cases. Then the test n==sz_r will always be false,
94 // but that is the intended behaviour...
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 Transforms v into a parallel array having the structure md.
130 *
131 * md must be non-null!
132 * The dimension(i>=1) of array v (if it is an IntTab or DoubleTab) are preserved,
133 * dimension(0) and dimension_tot(0) are modified according to the number of items
134 * specified in the MD_Vector.
135 * The initial size of the vector must be either 0, md.get_nb_items_reels(),
136 * or md.get_nb_items_tot(). If needed, the array size is modified and the
137 * array is initialized according to opt.
138 * WARNING, virtual_exchange() is NOT called. The virtual slots are not initialised...
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 Creates a descriptor for a subset of a vector.
300 *
301 * renum provides the structure and the descriptor of the source vector (must have line_size==1).
302 * renum must contain -1 for items of the source vector to discard and a
303 * non-negative value for items to keep.
304 * The value renum[i] gives the index of that item in the new array.
305 * Note: if an item of the source vector is received from another processor and must be kept,
306 * that same item must also be kept on the processor that sends it.
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: null descriptor!" << 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 Same as creer_md_vect_renum() but creates a default numbering.
326 *
327 * The flags_renum array must contain on input a NON-NEGATIVE value for the
328 * values to keep and a negative value for the others.
329 * On output, flags_renum contains the index of the item in the reduced array if it is
330 * kept, otherwise the original unmodified value.
331 * Items are placed in ascending order of their local index in the original descriptor.
332 *
333 */
334void MD_Vector_tools::creer_md_vect_renum_auto(IntVect& flags_renum, MD_Vector& md_vect)
335{
336 const int n = flags_renum.size_array();
337 int count = 0;
338 for (int i = 0; i < n; i++)
339 {
340 int x = flags_renum[i];
341 if (x >= 0)
342 flags_renum[i] = count++;
343 }
344 creer_md_vect_renum(flags_renum, md_vect);
345}
346
347/*! @brief dumps vector v with its parallel descriptor to os.
348 *
349 * os must be a file type with one file per process (no shared file).
350 *
351 */
352void MD_Vector_tools::dump_vector_with_md(const DoubleVect& v, Sortie& os)
353{
354 assert(v.line_size() == 1); // Only Vect! not tab.
355
356 const MD_Vector_base& md = v.get_md_vector().valeur();
357 os << md.que_suis_je() << finl;
358 os << md << finl;
359
360 os << v.size_array() << finl;
361 os.put(v.addr(), v.size_array(), v.line_size());
362 os << finl;
363}
364
365/*! @brief restores a vector saved by dump_vector_with_md.
366 *
367 * The code must run with the same number of processors.
368 * "v" will have a newly created copy of the descriptor (not equal to any
369 * other descriptor previously loaded). If "identical" descriptors are needed
370 * for several vectors, you might want to call set_md_vector() afterwards to
371 * attach another descriptor. See save_matrice_conditionnel()
372 */
374{
375
376 v.reset();
377 OWN_PTR(MD_Vector_base) md_ptr;
378 Nom md_type;
379 is >> md_type;
380 md_ptr.typer(md_type);
381 is >> md_ptr.valeur();
382
383 // Create the MD_Vector attached to the array
384 MD_Vector md;
385 md.copy(md_ptr.valeur());
386
387 DoubleVect toto;
388 toto.resize(md_ptr->get_nb_items_tot(), RESIZE_OPTIONS::NOCOPY_NOINIT);
389 int size_tot;
390 is >> size_tot;
391 is.get(toto.addr(), size_tot);
392 toto.set_md_vector(md);
393
394 // Attach v to toto and forget toto...
395 v.reset();
396 v.ref(toto);
397}
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)
Same as creer_md_vect_renum() but creates a default numbering.
static void creer_tableau_distribue(const MD_Vector &, Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Transforms v into a parallel array having the 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)
Creates a descriptor for a subset of a vector.
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")
: This class is an OWN_PTR but the pointed object is shared among multiple
Definition MD_Vector.h:48
void copy(const MD_Vector_base &)
Constructs an MD_Vector object by copying an existing object.
Definition MD_Vector.cpp:26
const MD_Vector_base & valeur() const
Definition MD_Vector.h:77
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
const Nom & que_suis_je() const
Returns the string identifying the class.
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:437
static bool is_parallel()
Definition Process.cpp:108
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
Base class for output streams.
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
N-dimensional array for 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
Resets the object to the state obtained by the default constructor.
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 &)