TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Raccord_distant_homogene.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 <Raccord_distant_homogene.h>
17#include <TRUSTTab.h>
18#include <Schema_Comm.h>
19#include <ArrOfBit.h>
20#include <Domaine_dis_base.h>
21#include <Domaine_VF.h>
22#include <TRUSTTabs.h>
23#include <Domaine.h>
24#include <communications.h>
25
26#include <medcoupling++.h>
27#ifdef MEDCOUPLING_
28#include <MEDCouplingMemArray.hxx>
29
30using namespace MEDCoupling;
31#endif
32
33Implemente_instanciable_32_64(Raccord_distant_homogene_32_64,"Raccord_distant_homogene",Raccord_distant_32_64<_T_>);
34
35/*! @brief Simple appel a: Raccord_distant::printOn(Sortie& ) (+ finl)
36 *
37 * @param (Sortie& s) un flot de sortie
38 * @return (Sortie&) le flot de sortie modifie
39 */
40template <typename _SIZE_>
42{
44 s << (int)1 <<finl;
45 s << tab_envoi << finl;
46 s << tab_recep << finl;
47 s << nom_frontiere_voisine_ << finl;
48 s << est_initialise_ << finl;
49 s << e_ << finl;
50 return s;
51}
52
53/*! @brief Simple appel a: Raccord_distant::readOn(Entree& )
54 *
55 * @param (Entree& s) un flot d'entree
56 * @return (Entree&) le flot d'entree modifie
57 */
58template <typename _SIZE_>
60{
62 int flag;
63 s >> flag;
64 if(flag==1)
65 {
66 s >> tab_envoi;
67 s >> tab_recep;
68 s >> nom_frontiere_voisine_;
69 s >> est_initialise_;
70 s >> e_;
71 }
72 return s;
73}
74
75
76/*! @brief Retourne dans le DoubleTab x la trace sur le raccord distant du DoubleTab y localise aux elements du domaine distant
77 */
78template<>
79void Raccord_distant_homogene_32_64<int>::trace_elem_distant(const DoubleTab& y, DoubleTab& x) const
80{
81 assert(est_initialise());
82 const int nb_compo_= y.line_size();
83
84 const IntTab& send_data = Tab_Envoi();
85 const ArrOfInt& recv_data = Tab_Recep();
86 const Faces& lesfaces = faces();
87 const int n1 = send_data.dimension(0);
88 const int n2 = recv_data.size_array();
89
90 // On dimensionne x si ce n'est pas fait
91 if (x.size_array()==0 && n2!=0)
92 x.resize(n2, nb_compo_);
93 else if (x.dimension(0) != n2)
94 {
95 Cerr << "Call to Frontiere::trace_elem with a DoubleTab x not located on boundary faces." << finl;
97 }
98 Schema_Comm schema;
99 schema.set_send_recv_pe_list(send_pe_list_, recv_pe_list_);
100 schema.begin_comm();
101 for (int i = 0; i < n1; i++)
102 {
103 const int pe_dest = send_data(i, 0);
104 const int face = send_data(i, 1);
105 int item = lesfaces.voisin(face,0);
106 if (item == -1)
107 item = lesfaces.voisin(face,1);
108
109 for (int j=0; j<nb_compo_; j++)
110 schema.send_buffer(pe_dest) << y(item,j);
111 }
113
114 for (int i = 0; i < n2; i++)
115 {
116 const int pe_source = recv_data[i];
117 for(int j=0; j<nb_compo_; j++)
118 schema.recv_buffer(pe_source) >> x(i,j);
119 }
120 schema.end_comm();
121}
122
123
124/*! @brief Retourne dans le DoubleTab x la trace sur le raccord distant du DoubleTab y localise aux faces
125 *
126 */
127template<>
128void Raccord_distant_homogene_32_64<int>::trace_face_distant(const DoubleTab& y, DoubleTab& x) const
129{
130 assert(est_initialise());
131 int n, N = y.line_size();
132
133 const IntTab& send_data = Tab_Envoi();
134 const ArrOfInt& recv_data = Tab_Recep();
135 const int n1 = send_data.dimension(0);
136 const int n2 = recv_data.size_array();
137
138 // On dimensionne x si ce n'est pas fait
139 if (x.size_array()==0 && n2!=0)
140 {
141 if (y.nb_dim() == 2) x.resize(n2, y.dimension(1));
142 else if (y.nb_dim() == 3) x.resize(n2, y.dimension(1), y.dimension(2));
143 else if (y.nb_dim() == 4) x.resize(n2, y.dimension(1), y.dimension(2), y.dimension(3));
144 }
145
146 Schema_Comm schema;
147 schema.set_send_recv_pe_list(send_pe_list_, recv_pe_list_);
148 schema.begin_comm();
149 for (int i = 0; i < n1; i++)
150 {
151 const int pe_dest = send_data(i, 0);
152 const int face = num_premiere_face() + send_data(i, 1);
153 for (n = 0; n < N; n++) schema.send_buffer(pe_dest) << y.addr()[N * face + n];
154 }
156 for (int i = 0; i < n2; i++)
157 {
158 const int pe_source = recv_data[i];
159 for (n = 0; n < N; n++) schema.recv_buffer(pe_source) >> x.addr()[N * i + n];
160 }
161 schema.end_comm();
162}
163
164
165/*! @brief Retourne dans le DoubleVect x la trace sur le raccord distant du DoubleVect y localise aux faces du raccord distant
166 *
167 */
168template<>
169void Raccord_distant_homogene_32_64<int>::trace_face_distant(const DoubleVect& y, DoubleVect& x) const
170{
171 // Verifie que l'on passe bien un tableau aux faces du raccord
172 assert(y.size()==nb_faces());
173 assert(est_initialise());
174 const IntTab& send_data = Tab_Envoi();
175 const ArrOfInt& recv_data = Tab_Recep();
176 const int n1 = send_data.dimension(0);
177 const int n2 = recv_data.size_array();
178
179 // On dimensionne x si ce n'est pas fait
180 if (x.size_array()==0 && n2!=0)
181 x.resize(n2);
182
183 Schema_Comm schema;
184 schema.set_send_recv_pe_list(send_pe_list_, recv_pe_list_);
185 schema.begin_comm();
186 for (int i = 0; i < n1; i++)
187 {
188 const int pe_dest = send_data(i, 0);
189 const int face = send_data(i, 1);
190 schema.send_buffer(pe_dest) << y(face);
191 }
193 for (int i = 0; i < n2; i++)
194 {
195 const int pe_source = recv_data[i];
196 schema.recv_buffer(pe_source) >> x(i);
197 }
198 schema.end_comm();
199}
200
201// 64 bits version of these should never be called:
202template<typename _SIZE_>
203void Raccord_distant_homogene_32_64<_SIZE_>::trace_elem_distant(const DoubleTab& y, DoubleTab& x) const
204{
205 assert(false);
206 throw;
207}
208
209template<typename _SIZE_>
210void Raccord_distant_homogene_32_64<_SIZE_>::trace_face_distant(const DoubleTab& y, DoubleTab& x) const
211{
212 assert(false);
213 throw;
214}
215
216template<typename _SIZE_>
217void Raccord_distant_homogene_32_64<_SIZE_>::trace_face_distant(const DoubleVect& y, DoubleVect& x) const
218{
219 assert(false);
220 throw;
221}
222
223
224template <typename _SIZE_>
226{
227 const IntTab& send_data = Tab_Envoi();
228 const ArrOfInt& recv_data = Tab_Recep();
229 const int n1 = send_data.dimension(0);
230 const int n2 = recv_data.size_array();
231
232 const int nbproc = Process::nproc();
233 ArrOfBit flags(nbproc);
234 flags = 0;
235 for (int i = 0; i < n1; i++)
236 {
237 const int pe = send_data(i, 0);
238 if (!flags.testsetbit(pe))
239 send_pe_list_.append_array(pe);
240 }
241 flags = 0;
242 for (int i = 0; i < n2; i++)
243 {
244 const int pe = recv_data[i];
245 if (!flags.testsetbit(pe))
246 recv_pe_list_.append_array(pe);
247 }
248 send_pe_list_.ordonne_array();
249 recv_pe_list_.ordonne_array();
250}
251
252/*! @brief Initialise le raccord distant avec la frontiere et le domaine discretise opposes au raccord distant, et le domaine discretise du raccord distant
253 * Only called from Champ_front* instances, so can remain 32 bits only.
254 */
255template <>
256void Raccord_distant_homogene_32_64<int>::initialise(const Frontiere& opposed_boundary,
257 const Domaine_dis_base& opposed_domaine_dis, const Domaine_dis_base& domaine_dis)
258{
259 Raccord_distant_homogene& raccord_distant = *this;
260 if(raccord_distant.est_initialise())
261 {
262 Cerr << "Remote connection " << raccord_distant.le_nom() << " already initialized." << finl;
263 Cerr << "Error, contact TRUST support." << finl;
265 }
266 int dim=Objet_U::dimension;
267 raccord_distant.nom_frontiere_voisine()=opposed_boundary.le_nom();
268 const Domaine_VF& domaine_dis_vf = ref_cast(Domaine_VF, domaine_dis);
269 // On va identifier les faces par leur centres de gravite
270 int parts = Process::nproc();
271 DoubleTabs remote_xv(parts);
272 int prem_face2 = raccord_distant.num_premiere_face();
273 int nb_face2 = raccord_distant.nb_faces();
274 int moi = Process::me();
275 remote_xv[moi].resize(nb_face2,dim);
276 for (int ind_face=0 ; ind_face < nb_face2 ; ind_face++)
277 {
278 int face = prem_face2 + ind_face;
279 for (int j=0 ; j<dim ; j++)
280 remote_xv[moi](ind_face,j) = domaine_dis_vf.xv(face,j);
281 }
282
283 // Puis on echange les tableaux des centres de gravites
284 // envoi des tableaux
285 for (int p = 0; p < parts; p++)
286 envoyer_broadcast(remote_xv[p], p);
287
288 ArrsOfInt racc_vois(parts);
289
290#ifdef MEDCOUPLING_
291 // On traite les informations, chaque proc connait tous les XV
292 // Si le proc porte un morceau du raccord_distant
293 int prem_face1 = opposed_boundary.num_premiere_face();
294 int nb_face1 = opposed_boundary.nb_faces();
295 if (nb_face1>0)
296 {
297 const Domaine_VF& opposed_domaine_dis_vf = ref_cast(Domaine_VF,opposed_domaine_dis);
298 const DoubleTab& local_xv = opposed_domaine_dis_vf.xv();
299
300 ArrOfInt& Recep=raccord_distant.Tab_Recep();
301 Recep.resize_array(nb_face1);
302 //double tolerance = 1e-8; //not very tolerant, are we?
303 double tolerance = Objet_U::precision_geom * 100 ; //default value 1e-8 not very tolerant, are we?
304
305 //DataArrayDoubles des xv locaux et de tous les remote_xv (a la suite)
306 std::vector<MCAuto<DataArrayDouble> > vxv(parts);
307 std::vector<const DataArrayDouble*> cvxv(parts);
308 for (int p = 0; p < parts; p++)
309 {
310 vxv[p] = DataArrayDouble::New();
311 vxv[p]->useExternalArrayWithRWAccess(remote_xv[p].addr(), remote_xv[p].dimension(0), remote_xv[p].dimension(1));
312 cvxv[p] = vxv[p];
313 }
314 MCAuto<DataArrayDouble> remote_xvs(DataArrayDouble::Aggregate(cvxv)), local_xvs(DataArrayDouble::New());
315 local_xvs->alloc(nb_face1, dim);
316 for (int ind_face = 0; ind_face < nb_face1; ind_face++)
317 for (int j = 0; j < dim; j++)
318 local_xvs->setIJ(ind_face, j, local_xv(prem_face1 + ind_face, j));
319
320 //indices des points de remote_xvs les plus proches de chaque point de local_xv
321 MCAuto<DataArrayIdType> glob_idx(DataArrayIdType::New());
322
323 glob_idx = remote_xvs->findClosestTupleId(local_xvs);
324
325 //pour chaque face de local_xv : controle de la tolerance, remplissage de tableau
326 for (int ind_face = 0, face1 = prem_face1; ind_face<nb_face1; ind_face++, face1++)
327 {
328 //retour de l'indice global (glob_idx(ind_face)) au couple (proc, ind_face2)
329 int proc = 0;
330 mcIdType ind_face2_big = glob_idx->getIJ(ind_face, 0);
331 while (ind_face2_big >= remote_xv[proc].dimension(0))
332 {
333 ind_face2_big -= remote_xv[proc].dimension(0);
334 proc++;
335 }
336 assert(ind_face2_big < std::numeric_limits<int>::max());
337 int ind_face2 = (int)ind_face2_big;
338 assert(ind_face2 < remote_xv[proc].dimension(0));
339
340 //controle de la tolerance
341 double distance2 = 0;
342 for (int j=0; j<dim; j++)
343 {
344 double x1=local_xv(face1,j);
345 double x2=remote_xv[proc](ind_face2,j);
346 distance2 += (x1-x2)*(x1-x2);
347 }
348 if (distance2 > tolerance * tolerance)
349 {
350 Cerr << "Warning, there is no remote face found on the local boundary " << opposed_boundary.le_nom() << " for the face local number " << ind_face << " (";
351 for (int j=0; j<dim; j++) Cerr << " " << local_xv(face1,j);
352 Cerr << " )" << finl << "the nearest face on the remote boundary " << raccord_distant.le_nom() << " is the face " << ind_face2 << " (";
353 for (int j=0; j<dim; j++) Cerr << " " << remote_xv[proc](ind_face2,j);
354 Cerr << " )" << finl << "which is located at a distance of " << sqrt(distance2) << " and it is above the geometric tolerance " << tolerance << finl;
355 Cerr << "Check your mesh or contact TRUST support." << finl;
357 }
358
359 //remplissage des tableaux
360 Recep[ind_face]=proc;
361 racc_vois[proc].append_array(ind_face2);
362 }
363 }
364#else
365 Cerr<<"Raccord_distant_homogene_32_64 needs TRUST compiled with MEDCoupling."<<finl;
366 exit();
367#endif
368 ArrsOfInt facteurs(Process::nproc());
369 envoyer_all_to_all(racc_vois, facteurs);
370
371 IntTab& Envoi = raccord_distant.Tab_Envoi();
372 if (nb_face2 > 0)
373 Envoi.resize(nb_face2, 2);
374 int ind = 0;
375 for (int p = 0; p < parts; p++)
376 {
377 const ArrOfInt& facteur = facteurs[p];
378 const int sz = facteur.size_array();
379 for (int d=0 ; d<sz ; d++)
380 {
381 Envoi(ind,0) = p;
382 Envoi(ind,1) = facteur[d];
383 ind++;
384 }
385 }
386 raccord_distant.e() = 0;
387 raccord_distant.est_initialise() = 1;
388 raccord_distant.completer();
389 Cerr <<"Initialize the remote connection " << domaine_dis.domaine().le_nom() << "/" << raccord_distant.le_nom() << "<-" << opposed_domaine_dis.domaine().le_nom() << "/" << opposed_boundary.le_nom() << finl;
390}
391
392// 64 bit version should fail
393template <typename _SIZE_>
395 const Domaine_dis_base& opposed_domaine_dis, const Domaine_dis_base& domaine_dis)
396{
397 assert(false);
398 throw;
399}
400
401
403#if INT_is_64_ == 2
405#endif
406
407
int testsetbit(int_t i) const
Renvoie la valeur du bit e, puis met le bit e a 1.
Definition ArrOfBit.h:85
class Domaine_VF
Definition Domaine_VF.h:44
double xv(int num_face, int k) const
Definition Domaine_VF.h:76
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
classe Domaine_dis_base Cette classe est la base de la hierarchie des domaines discretisees.
const Domaine & domaine() const
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
int_t voisin(int_t, int) const
Renvoie le numero du i-ieme voisin de face.
Definition Faces.h:165
int_t num_premiere_face() const
Definition Frontiere.h:67
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Frontiere.h:49
int_t nb_faces() const
Definition Frontiere.h:59
const Faces_t & faces() const
Definition Frontiere.h:54
static int dimension
Definition Objet_U.h:99
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
static double precision_geom
Definition Objet_U.h:86
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
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 int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
Classe Raccord_distant Cette classe represente un raccord entre 2 problemes dont un est resolu par TR...
void trace_face_distant(const DoubleTab &, DoubleTab &) const override
void initialise(const Frontiere_t &, const Domaine_dis_base &, const Domaine_dis_base &)
void trace_elem_distant(const DoubleTab &, DoubleTab &) const override
Frontiere_32_64< _SIZE_ > Frontiere_t
void echange_taille_et_messages() const
Cette methode lance l'echange de donnees entre tous les processeurs.
Sortie & send_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y entasser des donnees a envoyer.
void end_comm() const
Vide les buffers et libere les ressources: on a fini de lire les donnees recues dans les buffers.
Entree & recv_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y lire les donnees recues.
void begin_comm() const
Reserve les buffers de comm pour une nouvelle communication.
void set_send_recv_pe_list(const ArrOfInt &send_pe_list, const ArrOfInt &recv_pe_list, const int me_to_me=0)
Definit la liste des processeurs a qui on va envoyer et de qui on va recevoir des donnees.
Classe de base des flux de sortie.
Definition Sortie.h:52
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
_TYPE_ * addr()
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
int nb_dim() const
Definition TRUSTTab.h:199
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
int line_size() const
Definition TRUSTVect.tpp:67
void resize(_SIZE_, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTVect.tpp:91
void resize(int i)