TrioCFD 1.9.9_beta
TrioCFD documentation
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 call to: Raccord_distant::printOn(Sortie& ) (+ finl)
36 *
37 * @param (Sortie& s) an output stream
38 * @return (Sortie&) the modified output stream
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 call to: Raccord_distant::readOn(Entree& )
54 *
55 * @param (Entree& s) an input stream
56 * @return (Entree&) the modified input stream
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 Returns in DoubleTab x the trace on the distant connector of DoubleTab y located at elements of the distant domain
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 // Resize x if not done yet
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 Returns in DoubleTab x the trace on the distant connector of DoubleTab y located at 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 // Resize x if not done yet
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 Returns in DoubleVect x the trace on the distant connector of DoubleVect y located at faces of the distant connector
166 *
167 */
168template<>
169void Raccord_distant_homogene_32_64<int>::trace_face_distant(const DoubleVect& y, DoubleVect& x) const
170{
171 // Verify that the array is indeed indexed on the connector faces
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 // Resize x if not done yet
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 Initialises the distant connector with the boundary and the discretised domain opposite to the distant connector, and the discretised domain of the distant connector
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 // Identify faces by their centres of gravity
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 // Then exchange the arrays of centres of gravity
284 // send the arrays
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 // Process the information: each proc knows all XV
292 // If the proc holds a portion of the 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 of local xv and all remote_xv (concatenated)
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 of the closest points in remote_xvs for each point of local_xv
321 MCAuto<DataArrayIdType> glob_idx(DataArrayIdType::New());
322
323 glob_idx = remote_xvs->findClosestTupleId(local_xvs);
324
325 // for each face of local_xv: tolerance check, fill array
326 for (int ind_face = 0, face1 = prem_face1; ind_face<nb_face1; ind_face++, face1++)
327 {
328 // convert global index (glob_idx(ind_face)) to the pair (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 // tolerance check
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 // fill arrays
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
Returns the value of bit e, then sets bit e to 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
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
class Domaine_dis_base This class is the base of the hierarchy of discretized domains.
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
Returns the number of the i-th neighbor of face.
Definition Faces.h:165
int_t num_premiere_face() const
Definition Frontiere.h:67
const Nom & le_nom() const override
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this 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:94
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
static double precision_geom
Definition Objet_U.h:81
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
static int nproc()
Returns the number of processors in the current group. See Comm_Group::nproc() and PE_Groups::current...
Definition Process.cpp:102
static int me()
Returns the rank of the local processor in the current communication group. See Comm_Group::rank() an...
Definition Process.cpp:122
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
Class Raccord_distant This class represents a connector between 2 problems where one is solved by TRU...
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
Launches the data exchange between all processors.
Sortie & send_buffer(int num_PE) const
Returns the buffer corresponding to processor num_PE to stack data to send.
void end_comm() const
Clears the buffers and releases resources: reading of received data from buffers is complete.
Entree & recv_buffer(int num_PE) const
Returns the buffer corresponding to processor num_PE to read received data.
void begin_comm() const
Reserves communication buffers for a new communication.
void set_send_recv_pe_list(const ArrOfInt &send_pe_list, const ArrOfInt &recv_pe_list, const int me_to_me=0)
Defines the list of processors to send data to and receive data from.
Base class for output streams.
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)