TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Domaine_VF.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 <Linear_algebra_tools_impl.h>
17#include <Dirichlet_paroi_defilante.h>
18#include <Build_Map_to_Structured.h>
19#include <Connectivite_som_elem.h>
20#include <Dirichlet_loi_paroi.h>
21#include <Dirichlet_homogene.h>
22#include <Static_Int_Lists.h>
23#include <MD_Vector_tools.h>
24#include <MD_Vector_base.h>
25#include <Faces_builder.h>
26#include <Analyse_Angle.h>
27#include <DeviceMemory.h>
28#include <Array_tools.h>
29#include <Domaine_VF.h>
30#include <Periodique.h>
31#include <Conds_lim.h>
32#include <Symetrie.h>
33#include <Domaine.h>
34#include <Scatter.h>
35#include <Device.h>
36#include <Navier.h>
37#include <iomanip>
38#include <utility>
39#include <set>
40
41#ifdef MPI_
42#if __cplusplus > 201703L // C++20
43#define TRUST_USE_ARBORX
44#include <ArborX.hpp>
45#endif
46#endif
47
48#include <Array_tools.h>
49#include <Reorder_Mesh.h>
50
51#include <medcoupling++.h>
52#ifdef MEDCOUPLING_
53#include <MEDCouplingMemArray.hxx>
54#include <MEDLoader.hxx>
55
56using namespace MEDCoupling;
57#endif
58
59#ifdef __APPLE__
60#pragma GCC diagnostic push
61#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
62#endif /* __APLE__*/
63
64Implemente_base(Domaine_VF,"Domaine_VF",Domaine_dis_base);
65
67{
68 os << "volumes_ : " << finl;
69 volumes_.ecrit(os);
70
71 os << "volumes_entrelaces_ : " << finl;
72 volumes_entrelaces_.ecrit(os);
73
74 os << "face_voisins_ : " << finl;
75 face_voisins_.ecrit(os);
76
77 os << "face_surfaces_ : "<<face_surfaces_<< finl;
78 face_surfaces_.ecrit(os);
79
80 os << "xp_ : " << finl;
81 xp_.ecrit(os);
82
83 os << "xv_ : " << finl;
84 xv_.ecrit(os);
85
86 os << "elem_faces_ : " << finl;
87 elem_faces_.ecrit(os);
88
89 // os << "faces_doubles_ : " << finl; // PQ : 12/10/05 : a voir ce qu'il faut faire ici ???
90 // faces_doubles_.ecrit(os);
91
92 os << "face_sommets_ : " << finl; // PQ : 12/10/05 : a voir ce qu'il faut faire ici ???
93 face_sommets_.ecrit(os);
94
95 os << "nb_faces_ : " << finl;
96 os << nb_faces() <<finl;
97
98 os << "les_bords_ : " << finl;
99 os << les_bords_ <<finl;
100
101 return os ;
102}
103
105{
106 volumes_.lit(is);
107 volumes_entrelaces_.lit(is);
108 face_voisins_.lit(is);
109 face_surfaces_.lit(is);
110 xp_.lit(is);
111 xv_.lit(is);
112 elem_faces_.lit(is);
113 // faces_doubles_.lit(is); // PQ : 12/10/05 : a voir ce qu'il faut faire ici ???
114 face_sommets_.lit(is);
115 int nb_faces_unused;
116 is >> nb_faces_unused;
117 is >> les_bords_;
118 return is ;
119}
120
121/*! @brief This method (that may be overriden in various discretisations) is used to order faces according to the
122 * constraints of each discretisation.
123 * By default we identify the non-standard faces and put them at the begining of the face list.
124 * Non-standard faces are faces whose control volumes are affected by boundary conditions.
125 */
126void Domaine_VF::order_faces(Faces& les_faces)
127{
128 Cerr << "Domaine_VF::order_faces()" << finl;
129
130 prepare_elem_non_std(les_faces);
131
132 IntTab sort_key;
133 compute_sort_key(les_faces, sort_key);
134 tri_lexicographique_tableau(sort_key);
135 if (reorder_ && reorder_->algo() != Reorder_Algo::None && !reorder_->skip_faces())
136 {
137 les_faces.calculer_centres_gravite(xv_);
138 sort_along_zcurve(les_faces, sort_key);
139 }
140 renumber_faces(les_faces, sort_key);
141}
142
143/*! @brief Identify non-standard elements (will be used later to identify non standard faces)
144 * Some discretisation (like VDF) do not need this. See override.
145 */
147{
148 // Construction de rang_elem_non_std_ :
149 // C'est un vecteur indexe par les elements du domaine.
150 // size() = nb_elem()
151 // size_tot() = nb_elem_tot()
152 // Valeurs dans le tableau :
153 // rang_elem_non_std_[i] = -1 si l'element i est standard,
154 // sinon
155 // rang_elem_non_std_[i] = j, ou j est l'indice de l'element dans
156 // les tableaux indexes par les elements non standards (par exemple le tableau Domaine_Cl_EF::type_elem_Cl_).
157 //
158 // Un element est non standard s'il est voisin d'une face frontiere.
159 {
160 const Domaine& dom = domaine();
161 const int nb_elements = nb_elem();
162 const int nb_faces_front = domaine().nb_faces_frontiere();
165 int nb_elems_non_std = 0;
166 // D'abord on marque les elements non standards avec rang_elem_non_std_[i] = 0
167 for (int i_face = 0; i_face < nb_faces_front; i_face++)
168 {
169 const int elem = les_faces.voisin(i_face, 0);
170 if (rang_elem_non_std_[elem] < 0)
171 {
172 rang_elem_non_std_[elem] = 0;
173 nb_elems_non_std++;
174 }
175 }
176 nb_elem_std_ = nb_elements - nb_elems_non_std;
177 rang_elem_non_std_.echange_espace_virtuel();
178 int count = 0;
179 const int size_tot = rang_elem_non_std_.size_totale();
180 // On remplace le marqueur "0" par un indice incremental.
181 for (int elem = 0; elem < size_tot; elem++)
182 if (rang_elem_non_std_[elem] == 0)
183 rang_elem_non_std_[elem] = count++;
184 }
185
186}
187
188/*! @brief Generate an IntTab (sort_key) with two columns allowing to sort the faces along a specific order.
189 * sort_key(i, 0) gives the sorting key
190 * sort_key(i, 1) gives the original face index
191 */
192void Domaine_VF::compute_sort_key(Faces& les_faces, IntTab& sort_key)
193{
194 // Construction du tableau de renumerotation des faces. Ce tableau,
195 // une fois trie dans l'ordre croissant donne l'ordre des faces dans
196 // le domaine_VF. La cle de tri est construite de sorte a pouvoir retrouver
197 // l'indice de la face a partir de la cle par la formule :
198 // indice_face = cle % nb_faces
199 const int nbfaces = les_faces.nb_faces();
200 sort_key.resize(nbfaces, 2);
201
202 nb_faces_std_ = 0;
203 const int nb_faces_front = domaine().nb_faces_frontiere();
204 // Attention : face_voisins_ n'est pas encore initialise, il faut passer par les_faces.voisins() :
205 const IntTab& facevoisins = les_faces.voisins();
206 // On place en premier les faces de bord:
207 for (int i = 0; i < nb_faces_front; i++)
208 {
209 sort_key(i,0) = i;
210 sort_key(i,1) = i;
211 }
212
213 for (int i=nb_faces_front; i < nbfaces; i++)
214 {
215 const int elem0 = facevoisins(i, 0);
216 const int elem1 = facevoisins(i, 1);
217 // Ces faces ont toujours deux voisins.
218 assert(elem0 >= 0 && elem1 >= 0);
219 // Si la face est voisine d'un element non standard, elle doit etre classee juste apres les faces de bord:
220 if (rang_elem_non_std_[elem0] >= 0 || rang_elem_non_std_[elem1] >= 0)
221 {
222 sort_key(i, 0) = i;
223 sort_key(i, 1) = i;
224 }
225 else // Face standard : a la fin du tableau
226 {
227 sort_key(i, 0) = i + nbfaces;
228 sort_key(i, 1) = i;
230 }
231 }
232}
233
234
235/*! @brief Tweak the face sorting keys so that internal faces (=standard faces) follow
236 * a Z-curve indexing scheme.
237 * Assumption: all special faces are already at the begining of the array in sort_key (see caller of this method)
238 * See class Reorder_Mesh
239 */
240void Domaine_VF::sort_along_zcurve(const Faces& les_faces, IntTab& sort_key) const
241{
242 assert(reorder_);
243 const int nbfaces = les_faces.nb_faces();
244 std::string algon = reorder_->algo() == Reorder_Algo::Morton ? "Morton" : "Hilbert";
245 Cerr << "****************************************************************" << finl;
246 Cerr << "[Reordering] mesh *faces* using " << algon << " scheme ..." << finl;
247 Cerr << "Nb of non-std faces put at the begining: " << nbfaces-nb_faces_std_ << "\n";
248
249 //
250 // Assumption: all special faces are already at the begining of the array (see caller of this method)
251 //
252
253 const int nb_fac = sort_key.dimension(0);
254 const int nb_fac_non_std = nb_fac - nb_faces_std_;
255
256 const int dim1 = xv_.dimension(1); // == Objet_U::dimension
257 DoubleTab face_pts(nb_faces_std_, dim1);
258 ArrOfInt renum; // will be sized by compute_renumbering
259
260 // Extract center of mass of std faces (other non std faces should remain at the begining)
261 // At this point xv_ is still "unordered" (sort_key was never used)
262 for (int i=nb_fac_non_std; i < nb_fac; i++)
263 {
264 for (int j=0; j < dim1; j++)
265 {
266 const auto f_idx = sort_key(i, 1); // the original face index
267 face_pts(i-nb_fac_non_std, j) = xv_(f_idx,j);
268 }
269 }
270
271 reorder_->dump_to_file(face_pts, "reordering_faces_before.txt");
272 reorder_->compute_renumbering(face_pts, renum);
273
274 // apply renumbering to the end of the sort_key array corresponding to standard faces
275 auto sort_key2(sort_key);
276 for (int i = nb_fac_non_std; i < nb_fac; i++)
277 {
278 int j = i-nb_fac_non_std;
279 int idx = renum[j];
280 sort_key(nb_fac_non_std+idx, 0) = sort_key2(i, 0);
281 }
282
283 // Debug - if dump is requested:
284 if (reorder_->is_dump())
285 {
286 auto face_pts2(face_pts);
287 for (int i = 0; i < nb_faces_std_; i++)
288 for (int j = 0; j < dim1; j++)
289 face_pts2(renum(i), j) = face_pts(i,j);
290 reorder_->dump_to_file(face_pts2, "reordering_faces_after.txt");
291 }
292
293 Cerr << "[Reordering] Ordering faces done!" << finl;
294 Cerr << "****************************************************************" << finl;
295}
296
297
298/*! @brief Re-index faces according to the new order given by 'sort_key'
299 *
300 */
301void Domaine_VF::renumber_faces(Faces& les_faces, IntTab& sort_key)
302{
303 const int nbfaces = les_faces.nb_faces();
304 // On reordonne les faces:
305 IntTab& faces_sommets = les_faces.les_sommets();
306 {
307 IntTab old_tab(faces_sommets);
308 const int nb_som_faces = faces_sommets.dimension(1);
309 for (int i = 0; i < nbfaces; i++)
310 {
311 const int old_i = sort_key(i,1);
312 for (int j = 0; j < nb_som_faces; j++)
313 faces_sommets(i, j) = old_tab(old_i, j);
314 }
315 }
316
317 IntTab& faces_voisins = les_faces.voisins();
318 {
319 IntTab old_tab = faces_voisins;
320 for (int i = 0; i < nbfaces; i++)
321 {
322 const int old_i = sort_key(i,1);
323 faces_voisins(i, 0) = old_tab(old_i, 0);
324 faces_voisins(i, 1) = old_tab(old_i, 1);
325 }
326 }
327
328 // Calcul de la table inversee: reverse_index[ancien_numero] = nouveau numero
329 ArrOfInt reverse_index(nbfaces);
330 for (int i = 0; i < nbfaces; i++)
331 {
332 const int j = sort_key(i,1);
333 reverse_index[j] = i;
334 }
335
336 // Renumerotation de elem_faces:
337 // Nombre d'indices de faces dans le tableau
338 const int nb_items = elem_faces_.size();
339 ArrOfInt& array = elem_faces_;
340 for (int i = 0; i < nb_items; i++)
341 {
342 const int old = array[i];
343 array[i] = old < 0 ? -1 : reverse_index[old];
344 }
345
346 // Mise a jour des indices des faces de joint:
347 Joints& joints = domaine().faces_joint();
348 const int nbjoints = joints.size();
349 for (int i_joint = 0; i_joint < nbjoints; i_joint++)
350 {
351 Joint& un_joint = joints[i_joint];
352 ArrOfInt& indices_faces = un_joint.set_joint_item(JOINT_ITEM::FACE).set_items_communs();
353 const int nbfaces2 = indices_faces.size_array();
354 assert(nbfaces2 == un_joint.nb_faces()); // renum_items_communs rempli ?
355 for (int i = 0; i < nbfaces2; i++)
356 {
357 const int old = indices_faces[i]; // ancien indice local
358 indices_faces[i] = reverse_index[old];
359 }
360 // Les faces de joint ne sont plus consecutives dans le
361 // tableau: num_premiere_face n'a plus ne sens
362 un_joint.fixer_num_premiere_face(-1);
363 }
364
365 // Mise a jour des indices des groupes de faces:
366 Groupes_Faces& groupes_faces = domaine().groupes_faces();
367 groupes_faces.renumerote(reverse_index);
368}
369
370/*! @brief Genere les faces construits les frontieres
371 *
372 */
374{
375 Cerr << "<<<<<<<<<< Discretization VF >>>>>>>>>>" << finl;
376
378
379 // Re-order the domain indices of elements and/or nodes (faces are handled later)
380 if(reorder_)
381 reorder_->reorder_domain(domaine());
382
383 Domaine& ledomaine=domaine();
384 histogramme_angle(ledomaine,Cerr);
385 Faces* les_faces_ptr=creer_faces();
386 Faces& les_faces= *les_faces_ptr;
387 {
388 {
389 Type_Face type_face = domaine().type_elem()->type_face(0);
390 les_faces.typer(type_face);
391 les_faces.associer_domaine(domaine());
392
393 Static_Int_Lists connectivite_som_elem;
394 const int nb_sommets_tot = domaine().nb_som_tot();
395 const IntTab& elements = domaine().les_elems();
396
397 construire_connectivite_som_elem(nb_sommets_tot,
398 elements,
399 connectivite_som_elem,
400 1 /* include virtual elements */);
401
402 Faces_builder faces_builder;
403 faces_builder.creer_faces_reeles(domaine(),
404 connectivite_som_elem,
405 les_faces,
407 }
408
409 order_faces(les_faces);
410
411 // Les faces sont dans l'ordre definitif, on peut remplir
412 // renum_items_communs des faces:
413 Scatter::calculer_renum_items_communs(ledomaine.faces_joint(), JOINT_ITEM::FACE);
414
415 // Remplissage de face_voisins des frontieres:
416 // a factoriser avec DomaineCut.cpp
417 {
418 const IntTab& facevoisins = les_faces.voisins();
419 const int nb_frontieres = ledomaine.nb_front_Cl();
420 for (int i_frontiere = 0; i_frontiere < nb_frontieres; i_frontiere++)
421 {
422 Frontiere& fr = ledomaine.frontiere(i_frontiere);
423 IntTab& mes_face_voisins = fr.faces().voisins();
424 const int nbfaces = fr.nb_faces();
425 const int premiere_face = fr.num_premiere_face();
426 mes_face_voisins.resize(nbfaces, 2);
427 for (int i = 0; i < nbfaces; i++)
428 {
429 mes_face_voisins(i, 0) = facevoisins(premiere_face + i, 0);
430 mes_face_voisins(i, 1) = facevoisins(premiere_face + i, 1);
431 }
432 }
433 }
434
436 // Apres la methode suivante, on aura le droit d'utiliser creer_tableau_faces() :
437 Scatter::construire_md_vector(domaine(), les_faces.nb_faces(), JOINT_ITEM::FACE, md_vector_faces_);
438
439
440 const MD_Vector& md_vect_sommets = domaine().les_sommets().get_md_vector();
441 const MD_Vector& md_vect_elements = domaine().les_elems().get_md_vector();
442 // Construction de l'espace virtuel du tableau face_sommets
444
445 // Idem pour face_voisins_
446 // Certaines faces des elements virtuels les plus externes n'ont pas d'element local voisin => erreurs non fatales
447 Scatter::construire_espace_virtuel_traduction(md_vector_faces_, md_vect_elements, les_faces.voisins(), 0 /* error not fatal */);
448
449 // Idem pour elem_faces_
451
453
454 // Assignation de face_voisins et face_sommets
455 face_voisins().ref(les_faces.voisins());
456 face_sommets().ref(les_faces.les_sommets());
457
458 // Calcul des surfaces:
459 les_faces.calculer_surfaces(face_surfaces_);
460 // Calcul de la surface des faces virtuelles
461 MD_Vector md_nul;
462 creer_tableau_faces(face_surfaces_);
463 face_surfaces_.echange_espace_virtuel();
464 face_surfaces_.set_md_vector(md_nul); // Detache la structure parallele
465
466 // Changement a la v1.5.7 beta: xv_ a maintenant un descripteur parallele: dimension(0)=nb_faces
467 les_faces.calculer_centres_gravite(xv_);
468
469 // Calcul des volumes
471 }
472 {
473 int i=0, derniere=ledomaine.nb_bords();
474 les_bords_.dimensionner(domaine().nb_front_Cl()+domaine().nb_groupes_faces());
475 for(; i<derniere; i++)
476 {
477 les_bords_[i].associer_frontiere(ledomaine.bord(i));
478 les_bords_[i].associer_Domaine_dis(*this);
479 }
480 int decal=derniere;
481 derniere+=domaine().nb_raccords();
482 for(; i<derniere; i++)
483 {
484 int j=i-decal;
485 les_bords_[i].associer_frontiere(ledomaine.raccord(j).valeur());
486 les_bords_[i].associer_Domaine_dis(*this);
487 }
488 decal=derniere;
489 derniere+=domaine().nb_frontieres_internes();
490 for(; i<derniere; i++)
491 {
492 int j=i-decal;
493 les_bords_[i].associer_frontiere(ledomaine.bords_interne(j));
494 les_bords_[i].associer_Domaine_dis(*this);
495 }
496 decal=derniere;
497 derniere+=domaine().nb_groupes_faces();
498 for(; i<derniere; i++)
499 {
500 int j=i-decal;
501 les_bords_[i].associer_frontiere(ledomaine.groupe_faces(j));
502 les_bords_[i].associer_Domaine_dis(*this);
503 }
504 }
505 // Centre de gravite des elements (tableau xp_)
506 ledomaine.calculer_centres_gravite(xp_);
507 // Centre de gravite du domaine
508 ArrOfDouble c(dimension);
510
511 // On cree les domaines frontieres
512 ledomaine.creer_mes_domaines_frontieres(*this);
513
514 delete les_faces_ptr;
515
516 // Fill in the table face_numero_bord
518
519 faces_doubles_.resize_array(nb_faces());
520 est_face_bord_.resize_array(nb_faces_tot());
521
522
523 ///////////////////////
524 // On imprime des infos
525 ///////////////////////
526 ledomaine.imprimer(); // Extremas du domaine et volumes
527 infobord(); // Aires des bords
528 info_elem_som(); // Nombre elements et sommets
529 Cerr << "<<<<<< End of Discretization VF >>>>>>>>>>" << finl;
530}
531
533{
534 Domaine& dom = domaine();
535 typer_elem(dom);
536 // Calcul du volume du domaine discretise
538}
539
541{
542 Domaine& dom = domaine();
543
544 auto& sds = les_sous_domaines_dis_[i];
545 sds.typer("Sous_domaine_VF");
546 sds->associer_sous_domaine(dom.ss_domaine(i));
547 sds->associer_domaine_dis(*this);
548 sds->discretiser();
549}
550
552{
553 Cerr <<" Domaine_VF::remplir_face_voisins_fictifs(const Domaine_Cl_dis_base& ) must be overloaded by" << que_suis_je()<<finl;
554 exit();
555 assert(0);
556}
557
558
559
560/*! @brief renvoie new(Faces) ! elle est surchargee par Domaine_VDF par ex.
561 *
562 */
564{
565 Faces* les_faces=new(Faces);
566 return les_faces;
567}
568
570{
571 Cerr << " Domaine_VF::modifier_pour_Cl" << finl;
572 for (auto& itr : conds_lim)
573 {
574 // for( cl ...
575 const Cond_lim_base& cl=itr.valeur();
576 if (sub_type(Periodique, cl))
577 {
578 // if (perio ...
579 // Modifications du tableau face_voisins
580 // Une face de type periodicite doit avoir les memes voisins que
581 // sa face associee
582 // face_voisins(face,j) = face_voisins(face_associee(face),j) j=1,2
583 //
584
585 const Periodique& la_cl_period = ref_cast(Periodique,cl);
586 const Front_VF& frontieredis = ref_cast(Front_VF,la_cl_period.frontiere_dis());
587
588 int nb_face_bord = frontieredis.nb_faces();
589 int ndeb =0;
590 int nfin = frontieredis.nb_faces_tot();
591#ifndef NDEBUG
592 int num_premiere_face = frontieredis.num_premiere_face();
593 int num_derniere_face = num_premiere_face+nfin;
594#endif
595 int face;
596
597 for (int ind_face=ndeb; ind_face<nfin; ind_face++)
598 {
599 face = frontieredis.num_face(ind_face);
600 int faassociee = la_cl_period.face_associee(ind_face);
601 faassociee = frontieredis.num_face(faassociee);
602 if (ind_face<nb_face_bord)
603 {
604 assert(faassociee>=num_premiere_face);
605 assert(faassociee<num_derniere_face);
606 }
607
608 if (face_voisins_(face,0) == -1)
609 face_voisins_(face,0) = face_voisins_(faassociee,0);
610 else if (face_voisins_(face,1) == -1)
611 face_voisins_(face,1) = face_voisins_(faassociee,1);
612 }
613 }
614 }
615
616
617 // PQ : 10/10/05 : les faces periodiques etant a double contribution
618 // l'appel a marquer_faces_double_contrib s'effectue dans cette methode
619 // afin de pouvoir beneficier de conds_lim.
620
621
623 // Construction du tableau num_fac_loc_
625}
626
627// Methode pour la construction du tableau num_fac_loc_
629{
630 const int size = nb_faces_tot();
631 num_fac_loc_.resize(size,2);
632 num_fac_loc_=-1;
633 for(int face=0; face<size; face++)
634 for (int voisin=0; voisin<2; voisin++)
635 {
636 int elem = face_voisins_(face,voisin);
637 if(elem!=-1)
638 {
639 int face_loc = numero_face_local(face,elem);
640 if (face_loc != -1) num_fac_loc_(face,voisin) = face_loc;
641 else
642 {
643 // Cas periodique
644 int autre_voisin = 1 - voisin;
645 int elem2 = face_voisins(face,autre_voisin);
646 int nb_faces_elem = elem_faces_.dimension(1);
647 for (face_loc=0; face_loc<nb_faces_elem; face_loc++)
648 {
649 const int face_glob = elem_faces(elem,face_loc);
650 const int elem_voisin1 = face_voisins(face_glob,0);
651 const int elem_voisin2 = face_voisins(face_glob,1);
652 if (elem_voisin1==elem2 || elem_voisin2==elem2)
653 {
654 num_fac_loc_(face,voisin) = face_loc;
655 break;
656 }
657 }
658 }
659 }
660 }
661}
662
663// Renvoie le numero local de face a partir des numeros globaux face et elem
664// Utiliser si possible Domaine_VF::num_fac_loc(face,voisin) car la methode est
665// optimisee, celle ci non.
666int Domaine_VF::numero_face_local(int face, int elem) const
667{
668 //int nfe=domaine().nb_faces_elem();
669 // GF pour le cas ou on a plusieurs types de faces....
670 // nb_faces_elem() renvoit le nbre de sommet par face du premier type de faces
671 int nfe=elem_faces_.dimension(1);
672 for(int face_loc=0; face_loc<nfe; face_loc++)
673 if(elem_faces_(elem, face_loc)==face)
674 return face_loc;
675 return -1;
676}
677
678/*! @brief Remplissage du tableau face_virt_pe_num_ (voir commentaire dans Domaine_VF.
679 *
680 * h)
681 *
682 */
684{
685 int i;
686
687 const int nf = nb_faces();
688 const int nf_tot = nb_faces_tot();
689 const int nb_faces_virt = nf_tot - nf;
690
691 IntTab tmp(0, 2);
692 creer_tableau_faces(tmp, RESIZE_OPTIONS::NOCOPY_NOINIT);
693 const int moi = me();
694 for (i = 0; i < nf; i++)
695 {
696 tmp(i, 0) = moi;
697 tmp(i, 1) = i;
698 }
700
701 face_virt_pe_num_.resize(nb_faces_virt, 2);
702 // Copie de la partie virtuelle de tmp dans face_virt_pe_num_
703 face_virt_pe_num_.inject_array(tmp, nb_faces_virt*2, 0 /* dest offset*/, nf * 2 /* source offset*/);
704}
705
706const IntTab& Domaine_VF::face_virt_pe_num() const
707{
708 // On verifie que le tableau a ete construit (si ca plante, c'est qu'on a
709 // oublie d'appeler construire_face_virt_pe_num()).
710 assert(face_virt_pe_num_.dimension(1) == 2);
711 return face_virt_pe_num_;
712}
713
714/*! @brief Compute the normalized boundary outward vector associated to the face global_face_number and eventually scaled by scale_factor
715 *
716 */
717DoubleTab Domaine_VF::normalized_boundaries_outward_vector(int global_face_number, double scale_factor) const
718{
719 const IntTab& neighbor_faces = face_voisins();
720 DoubleTab normal_vector(dimension); //result
721 for (int d = 0; d < dimension; d++)
722 normal_vector(d) = face_normales(global_face_number, d) / face_surfaces(global_face_number);
723
724 //now we have a normalized normal vector
725 //but it remains to orient it correctly (outwards)
726 //for this we build a vector that links middle of the face to the center of the element
727 //and then we do the inner product between this new vector and normal vector
728 //So, if the result is positive, we change the sign of normal vector
729 //else we do nothing
730 int neighbor_elem=neighbor_faces(global_face_number,0);
731 if( neighbor_elem == -1 )
732 neighbor_elem = neighbor_faces(global_face_number,1);
733 //DoubleTab vector_face_elem(dimension);
734 double inner_product=0;
735 for(int i=0; i<dimension; i++)
736 {
737 //ith component of the vector
738 double vec_face_elem = xp(neighbor_elem,i)-xv(global_face_number,i);
739 inner_product+=vec_face_elem*normal_vector(i);
740 }
741
742 if( inner_product > 0 )
743 {
744 for(int i=0; i<dimension; i++)
745 {
746 normal_vector(i)*=-1;
747 }
748 }
749
750 //now the normal vector is well oriented (outwards)
751 //we can multiply it by a given scale factor
752 for(int i=0; i<dimension; i++)
753 {
754 normal_vector(i)*=scale_factor;
755 }
756
757 return normal_vector;
758}
759
761{
762 Journal() << " Domaine_VF::marquer_faces_double_contrib" << finl;
763 // marquage des faces periodiques
764 ////////////////////////////////////////////////
765
766 est_face_bord_=0; // init for inner faces.
767 for (auto& itr : conds_lim)
768 {
769 const Cond_lim_base& cl=itr.valeur();
770 int flag = sub_type(Periodique, cl) ? 2 : 1;
771 const Front_VF& le_bord = ref_cast(Front_VF, cl.frontiere_dis());
772 for (int ind_face = 0; ind_face < le_bord.nb_faces_tot(); ind_face++)
773 {
774 int num_face = le_bord.num_face(ind_face);
775 est_face_bord_[num_face]=flag;
776 }
777 }
778 for (auto& itr : conds_lim)
779 {
780 const Cond_lim_base& cl=itr.valeur();
781 if (sub_type(Periodique, cl))
782 {
783 const Periodique& la_cl_period = ref_cast(Periodique,cl);
784 const Front_VF& frontieredis = ref_cast(Front_VF,la_cl_period.frontiere_dis());
785 int ndeb = frontieredis.num_premiere_face();
786 int nfin = ndeb + frontieredis.nb_faces();
787 for (int face=ndeb; face<nfin; face++)
788 faces_doubles_[face]=1;
789 }
790 }
791
792 // marquage des faces items communs
793 ////////////////////////////////////////////////
794 int nbjoints=nb_joints();
795
796 for(int njoint=0; njoint<nbjoints; njoint++)
797 {
798 const Joint& joint_temp = joint(njoint);
799 const IntTab& indices_faces_joint = joint_temp.joint_item(JOINT_ITEM::FACE).renum_items_communs();
800 const int nbfaces = indices_faces_joint.dimension(0);
801 for (int j = 0; j < nbfaces; j++)
802 {
803 // Pour acceder au face de joint, il existe desormais un tableau dedie renum_items_communs()
804 // car l'ancienne facon d'acceder a ces faces etait de passer par
805 // joint.num_premiere_face() et joint.nb_faces() ce qui n'est plus valable !
806 // En effet, la numerotation des faces de joint n'est plus continue desormais !
807 // joint.num_premiere_face() retourne -1 desormais pour detecter les anciens codages.
808 int face_de_joint = indices_faces_joint(j, 1);
809 faces_doubles_[face_de_joint] = 1;
810 }
811 }
812}
813
815{
816 Cerr << "==============================================" << finl;
817 Cerr << "The boundary areas of the domain " << domaine().le_nom() << " are:" << finl;
818 DoubleVect surfaces;
819
820 // Raccords
821 Raccords& raccords=domaine().faces_raccord();
822 for (int i=0; i<raccords.nb_raccords(); i++)
823 {
824 Faces& faces=raccords(i)->faces();
825 faces.associer_domaine(domaine());
826 faces.calculer_surfaces(surfaces);
827 double s=0;
828 for (int j=0; j<faces.nb_faces(); j++)
829 s=s+surfaces(j);
830 s=mp_sum(s);
831 raccords(i)->set_aire(s);
832 Cerr<<"Area of "<<raccords(i)->le_nom()<<" \t= "<<s<<finl;
833 }
834
835 // Bords
836 Bords& bords=domaine().faces_bord();
837 for (int i=0; i<bords.nb_bords(); i++)
838 {
839 Faces& faces=bords(i).faces();
840 faces.associer_domaine(domaine());
841 faces.calculer_surfaces(surfaces);
842 double s=0;
843 for (int j=0; j<faces.nb_faces(); j++)
844 s=s+surfaces(j);
845 s=mp_sum(s);
846 bords(i).set_aire(s);
847 Cerr<<"Area of "<<bords(i).le_nom()<<" \t= "<<s<<finl;
848 }
849 Cerr << "==============================================" << finl;
850}
851
853{
854 const trustIdType nbelem = domaine().les_elems().get_md_vector()->nb_items_seq_tot();
855 const trustIdType nbsom = domaine().les_sommets().get_md_vector()->nb_items_seq_tot();
856 const trustIdType nbfaces = face_voisins().get_md_vector()->nb_items_seq_tot();
857 Cerr<<"Calculation of elements and nodes on " << domaine().le_nom() << " :" << finl;
858 Cerr<<"Total number of elements = "<<nbelem<<finl;
859 Cerr<<"Total number of nodes = "<<nbsom<<finl;
860 Cerr<<"Total number of faces = "<<nbfaces<<finl;
861 Raccords& raccords=domaine().faces_raccord();
862 for (int i=0; i<raccords.nb_raccords(); i++)
863 {
864 trustIdType nb_boundary_faces = mp_sum(ref_cast(Frontiere,raccords(i).valeur()).nb_faces());
865 Cerr<< nb_boundary_faces << " of them on boundary "<<raccords(i)->le_nom()<<finl;
866
867 }
868 Bords& bords=domaine().faces_bord();
869 for (int i=0; i<bords.nb_bords(); i++)
870 {
871 trustIdType nb_boundary_faces = mp_sum(ref_cast(Frontiere,bords(i)).nb_faces());
872 Cerr<< nb_boundary_faces << " of them on boundary "<<bords(i).le_nom()<<finl;
873 }
874 Cerr<<"=============================================="<<finl;
875 trustIdType internal_item = std::min(nbelem, nbfaces);
876 internal_item = std::min(internal_item, nbsom);
877 // premiere_face_int()*dimension+1 pour ne pas alerter sur flux vectoriels aux faces frontieres:
878 DeviceMemory::internal_items_size_ = std::max((trustIdType)(premiere_face_int()*dimension+1),internal_item);
879}
880
885
886void Domaine_VF::creer_tableau_aretes(Array_base& t, RESIZE_OPTIONS opt) const
887{
888 const MD_Vector& md = md_vector_aretes();
890}
891
892void Domaine_VF::creer_tableau_faces_bord(Array_base& t, RESIZE_OPTIONS opt) const
893{
894 const MD_Vector& md = md_vector_faces_bord();
896}
897
899{
900 Cerr << "Domaine_VF::remplir_face_numero_bord" << finl;
901 face_numero_bord_.resize(nb_faces());
902 face_numero_bord_=-1; // init for inner faces.
903 Domaine& ledomaine=domaine();
904 int ndeb, nfin;
905 const int nb_bords = ledomaine.nb_bords();
906 for (int n_bord=0; n_bord<nb_bords; n_bord++)
907 {
908 const Bord& le_bord = ledomaine.bord(n_bord);
909 ndeb = le_bord.num_premiere_face();
910 nfin = ndeb + le_bord.nb_faces();
911 for (int num_face=ndeb; num_face<nfin; num_face++)
912 face_numero_bord_[num_face] = n_bord;
913 }
914
915 const int nb_raccords = ledomaine.nb_raccords() ;
916 for (int n_racc=0; n_racc<nb_raccords; n_racc++)
917 {
918 const Raccord& le_racc = ledomaine.raccord(n_racc);
919 ndeb = le_racc -> num_premiere_face();
920 nfin = ndeb + le_racc -> nb_faces();
921 for (int num_face=ndeb; num_face<nfin; num_face++)
922 face_numero_bord_[num_face] = n_racc + nb_bords;
923 }
924}
925
926const DoubleTab& Domaine_VF::xv_bord() const
927{
928 if (xv_bord_.get_md_vector() == md_vector_faces_bord()) return xv_bord_; //deja cree
930 std::copy(xv_.addr(), xv_.addr() + dimension * premiere_face_int(), xv_bord_.addr()); //faces reelles : le debut de xv_
931 xv_bord_.echange_espace_virtuel();
932 return xv_bord_;
933}
934
935/*! @brief calcul le tableau xgr pour le calcul des moments des forces aux bords :
936 *
937 *
938 */
940{
941 const DoubleTab& xgrav = xv();
942 const ArrOfDouble& c_grav=domaine().cg_moments();
944 DoubleTab xgr(nb_faces, dimension);
945 for (int num_face=0; num_face <nb_faces; num_face++)
946 for (int i=0; i<dimension; i++)
947 xgr(num_face,i)=xgrav(num_face,i)-c_grav[i];
948 return xgr;
949}
950
951/** Build internal MEDCoupling cartesian mesh and correspondances
952 *
953 */
954void Domaine_VF::build_map_mc_Cmesh(const bool with_faces)
955{
956#ifdef MEDCOUPLING_
957
958 if (domaine().type_elem()->que_suis_je() != "Quadrangle" && domaine().type_elem()->que_suis_je() != "Rectangle"
959 && domaine().type_elem()->que_suis_je() != "Hexaedre")
960 {
961 Cerr << "Error in Domaine_VF::build_mc_Cmesh ! You use the interpret Build_Map_to_Structured but your elem type is " << domaine().type_elem()->que_suis_je() << " !!!" << finl;
962 Cerr << "This option is only available for Quadrangle/Rectangle/Hexaedre types !!! Remove this interpret from your data file." << finl;
964 }
965
966 Cerr << finl;
967 Cerr << "###########################################" << finl;
968 Cerr << "@@@@@@@@ Building Structured infos @@@@@@@@" << finl;
969 Cerr << "###########################################" << finl;
970
971 /* Step 1. build mesh */
972 build_mc_Cmesh();
973
974 /* Step 2. build nodes correspondance : indx est i + nx * (j + ny * k) */
975 build_mc_Cmesh_nodesCorrespondence();
976
977 /* Step 2. build elem and face correspondance : indx est i + (nx - 1) * (j + (ny - 1) * k) */
978 build_mc_Cmesh_correspondence(with_faces);
979
980 mc_Cmesh_with_faces_corr_ = with_faces;
981 mc_Cmesh_ready_ = true;
982
983 Cerr << "##################################################" << finl;
984 Cerr << "@@@@@@@@ End of Building Structured infos @@@@@@@@" << finl;
985 Cerr << "##################################################" << finl;
986 Cerr << finl;
987
988#else
989 Cerr << "Error in Domaine_VF::build_mc_Cmesh ! You use the interpret Build_Map_to_Structured but your TRUST version is compiled without MEDCOUPLING !!!" << finl;
991#endif
992}
993
994#ifdef MEDCOUPLING_
995
996/** Build internal MEDCoupling cartesian mesh for various postprocessings.
997 */
998void Domaine_VF::build_mc_Cmesh()
999{
1000 using DAD = MCAuto<DataArrayDouble>;
1001
1002 Cerr << "Domaine_VF::build_mc_Cmesh() ... " << finl;
1003 const auto& u_mesh = domaine().get_mc_mesh(); // will be built
1004 const auto& coords = u_mesh->getCoords();
1005 trustIdType nb_soms_tmp = coords->getNumberOfTuples(), nb_elems_tmp = u_mesh->getNumberOfCells();
1006
1007 const int nb_soms = Process::check_int_overflow(nb_soms_tmp);
1008 const int nb_elems = Process::check_int_overflow(nb_elems_tmp);
1009 const int mesh_dim = u_mesh->getMeshDimension();
1010
1011 Cerr << "Domaine_VF: Creating a MEDCouplingCMesh object for the domaine_VF '" << que_suis_je() << "' & the domaine '" << domaine().le_nom() << "' ..." << finl;
1012 mc_Cmesh_ = MEDCouplingCMesh::New("TRUST_CMesh");
1013
1014 const double eps = Objet_U::precision_geom;
1015 DAD coo[3], uniq[3];
1016 for (unsigned d=0; d < (unsigned)mesh_dim; d++)
1017 {
1018 coo[d] = coords->keepSelectedComponents({d});
1019 uniq[d] = coo[d]->getDifferentValues(eps);
1020 std::sort(uniq[d]->rwBegin(), uniq[d]->rwEnd());
1021 }
1022 mc_Cmesh_x_coords_.resize(uniq[0]->getNumberOfTuples());
1023 std::copy(uniq[0]->begin(), uniq[0]->end(),mc_Cmesh_x_coords_.begin());
1024 mc_Cmesh_y_coords_.resize(uniq[1]->getNumberOfTuples());
1025 std::copy(uniq[1]->begin(), uniq[1]->end(),mc_Cmesh_y_coords_.begin());
1026 if (mesh_dim>2)
1027 {
1028 mc_Cmesh_z_coords_.resize(uniq[2]->getNumberOfTuples());
1029 std::copy(uniq[2]->begin(), uniq[2]->end(),mc_Cmesh_z_coords_.begin());
1030 }
1031
1032 const int nx = (int)mc_Cmesh_x_coords_.size(), ny = (int)mc_Cmesh_y_coords_.size();
1033 const int nz = (mesh_dim > 2) ? (int)mc_Cmesh_z_coords_.size() : 1;
1034
1035 const int nb_som_cart = nx * ny * nz;
1036 const int nb_elem_cart = (mesh_dim > 2) ? (nx - 1) * (ny - 1) * (nz - 1) : (nx - 1) * (ny - 1);
1037
1038 if (nb_som_cart != nb_soms || nb_elem_cart != nb_elems)
1039 {
1040 Cerr << "Issue in converting the TRUST mesh to MEDCouplingCMesh ... It seems that the mesh is not an IJK-like mesh !!!" << finl;
1041 Cerr << "Nb soms : " << nb_soms << " for TRUST mesh vs " << nb_som_cart << " for the MEDCouplingCMesh" << finl;
1042 Cerr << "Nb elems : " << nb_elems << " for TRUST mesh vs " << nb_elem_cart << " for the MEDCouplingCMesh" << finl;
1043 Process::exit();
1044 }
1045
1046 Cerr << "Structured mesh dimensions (nodes) : " << nx << " x " << ny;
1047 if (mesh_dim > 2) Cerr << " x " << nz;
1048 Cerr << finl;
1049
1050 if (mesh_dim > 2)
1051 mc_Cmesh_->setCoords(uniq[0], uniq[1], uniq[2]);
1052 else
1053 mc_Cmesh_->setCoords(uniq[0], uniq[1]);
1054
1055 Cerr << "Domaine_VF::build_mc_Cmesh() ... OK !" << finl;
1056}
1057
1058/** Correspondance between TRUST_CMesh elements (and faces) and TRUST
1059 *
1060 */
1061void Domaine_VF::build_mc_Cmesh_correspondence(bool withFace)
1062{
1063 using DAI = MCAuto<DataArrayIdType>;
1064 using DAD = MCAuto<DataArrayDouble>;
1065
1066 Cerr << "Domaine_VF::build_mc_Cmesh_correspondence() building elem (and potentially face) correspondence ... " << finl;
1067
1068 // Temporary unstruct version of the CMesh to establish correspondences
1069 // The exact same numbering as in the original CMesh is preserved:
1070 MCAuto<MEDCouplingUMesh> mc_unstr = mc_Cmesh_->buildUnstructured();
1071 const MEDCouplingUMesh * mc_mesh = domaine().get_mc_mesh();
1072
1073 // Renumber nodes of mc_unstr to use original TRUST node indices:
1074 mc_unstr->setCoords(mc_mesh->getCoords());
1075 DAI renumb(DataArrayIdType::New());
1076 mcIdType n_nod = mc_unstr->getCoords()->getNumberOfTuples();
1077 renumb->alloc(n_nod);
1078 std::copy(mc_Cmesh_nodesCorrespondence_.data(),mc_Cmesh_nodesCorrespondence_.data()+n_nod, renumb->rwBegin());
1079
1080 mc_unstr->renumberNodesInConn(renumb->begin()); // only in connectivity
1081
1082 // Identify elements
1083 DataArrayIdType * mP;
1084 mc_unstr->areCellsIncludedIn(mc_mesh, 2, mP); // 2: same nodal connectivity
1085
1086 // Check that we have covered all cells exactly once:
1087 DAI outliers = mP->findIdsNotInRange(0, mc_unstr->getNumberOfCells());
1088 if (outliers->getNumberOfTuples() != 0)
1089 Process::exit("ERROR: Issue in converting the TRUST mesh to MEDCouplingCMesh ... It seems that the mesh is not an IJK-like mesh!!!");
1090
1091 mc_Cmesh_elemCorrespondence_.resize(mP->getNumberOfTuples());
1092 std::copy(mP->begin(), mP->end(), mc_Cmesh_elemCorrespondence_.data());
1093
1094// // Debug
1095// Cerr << "ELEM CORRESPONDANCE" << finl;
1096// int elem_idx = 0;
1097// for (const auto& cor: mc_Cmesh_elemCorrespondence_)
1098// Cerr << "Elem struct. " << elem_idx++ << " --> Elem non struct (original TRUST) " << cor << finl;
1099
1100 if (withFace)
1101 {
1102 int mesh_dim = mc_unstr->getMeshDimension();
1103 get_mc_face_mesh();
1104
1105 DAI desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
1106 MCAuto<MEDCouplingUMesh> mc_unstr_fac(mc_unstr->buildDescendingConnectivity(desc, descIndx, revDesc, revDescIndx));
1107 mcIdType nb_fac = mc_unstr_fac->getNumberOfCells();
1108
1109 DataArrayIdType * mapFac;
1110 mc_unstr_fac->areCellsIncludedIn(mc_face_mesh_, 2, mapFac); // 2: same nodal connectivity
1111
1112 DAD faceBary = mc_face_mesh_->computeCellCenterOfMass();
1113 const double * faceBaryP = faceBary->getConstPointer();
1114 DAI permu(DataArrayIdType::New());
1115 permu->alloc(nb_fac);
1116 permu->iota();
1117
1118 auto comp_func_2d = [&](const int& i1, const int& i2) -> bool
1119 {
1120 std::array<double, 2> tup1 = { faceBaryP[i1*2+1], faceBaryP[i1*2+0] }; // Y, X
1121 std::array<double, 2> tup2 = { faceBaryP[i2*2+1], faceBaryP[i2*2+0] };
1122 return tup1 < tup2; // use **reverse** lexicographic ordering natively given by std::array
1123 };
1124
1125 auto comp_func_3d = [&](const int& i1, const int& i2) -> bool
1126 {
1127 std::array<double, 3> tup1 = { faceBaryP[i1*3+2], faceBaryP[i1*3+1], faceBaryP[i1*3+0] }; // Z, Y, X
1128 std::array<double, 3> tup2 = { faceBaryP[i2*3+2], faceBaryP[i2*3+1], faceBaryP[i2*3+0] }; // Z, Y, X
1129 return tup1 < tup2; // use **reverse** lexicographic ordering natively given by std::array
1130 };
1131
1132 if (mesh_dim == 2)
1133 std::sort(permu->rwBegin(), permu->rwEnd(), comp_func_2d);
1134 else
1135 std::sort(permu->rwBegin(), permu->rwEnd(), comp_func_3d);
1136 for (mcIdType pp: *permu) // loop on face following lexicographic ordering
1137 {
1138 int p = static_cast<int>(pp);
1139 const int ori = orientation(p); // normal
1140 if (ori == 0) mc_Cmesh_facesXCorrespondence_.push_back(p);
1141 if (ori == 1) mc_Cmesh_facesYCorrespondence_.push_back(p);
1142 if (mesh_dim > 2 && ori == 2) mc_Cmesh_facesZCorrespondence_.push_back(p);
1143 }
1144
1145 Cerr << " - Built mc_Cmesh_facesXCorrespondence_ with size " << (int)mc_Cmesh_facesXCorrespondence_.size() << finl;
1146 Cerr << " - Built mc_Cmesh_facesYCorrespondence_ with size " << (int)mc_Cmesh_facesYCorrespondence_.size() << finl;
1147 if (mesh_dim > 2)
1148 Cerr << " - Built mc_Cmesh_facesZCorrespondence_ with size " << (int)mc_Cmesh_facesZCorrespondence_.size() << finl;
1149 }
1150 Cerr << "Domaine_VF::build_mc_Cmesh_correspondence() - done!" << finl;
1151}
1152
1153
1154// magic !
1155static int findCartIndex(const std::vector<double>& vect, const double value)
1156{
1157 if (value < vect.front() || value > vect.back())
1158 return -1; // pas dedans
1159
1160 auto it = std::lower_bound(vect.begin(), vect.end(), value);
1161
1162 if (it == vect.end())
1163 return -1; // pas dedans
1164
1165 int index = static_cast<int>(std::distance(vect.begin(), it));
1166
1167 if (index > 0 && value < vect[index])
1168 index--; // juste avant !!
1169
1170 return index;
1171}
1172
1173/** Correspondance between TRUST_CMesh nodes and TRUST
1174 */
1175void Domaine_VF::build_mc_Cmesh_nodesCorrespondence()
1176{
1177 Cerr << "Domaine_VF::build_mc_Cmesh_nodesCorrespondence() ... " << finl;
1178 const auto& u_mesh = domaine().get_mc_mesh();
1179 const double* coordsP = u_mesh->getCoords()->getConstPointer();
1180 const int space_dim = static_cast<int>(u_mesh->getCoords()->getNumberOfComponents());
1181 const int nb_soms = static_cast<int>(u_mesh->getNumberOfNodes());
1182 const int mesh_dim = u_mesh->getMeshDimension();
1183 const int nx = (int)mc_Cmesh_x_coords_.size(), ny = (int)mc_Cmesh_y_coords_.size();
1184
1185 mc_Cmesh_nodesCorrespondence_.resize(nb_soms, -1);
1186
1187 for (int node = 0; node < nb_soms; ++node)
1188 {
1189 int i = findCartIndex(mc_Cmesh_x_coords_, coordsP[node*space_dim + 0]);
1190 int j = findCartIndex(mc_Cmesh_y_coords_, coordsP[node*space_dim + 1]);
1191 int k = (mesh_dim > 2) ? findCartIndex(mc_Cmesh_z_coords_, coordsP[node*space_dim + 2]) : 0;
1192
1193 if (i == -1 || j == -1 || (mesh_dim > 2 && k == -1))
1194 {
1195 Cerr << "Node " << node << " not contained in the structured mesh !!!" << finl;
1196 Process::exit();
1197 }
1198
1199 const int ijk_idx = i + nx * (j + ny * k); // Indexing for structured mesh nodes
1200 mc_Cmesh_nodesCorrespondence_[ijk_idx] = node;
1201// Cerr << "Noeud non struct. " << node << " --> Noeud struct. " << ijk_idx << finl;
1202 }
1203 Cerr << "Domaine_VF::build_mc_Cmesh_nodesCorrespondence() ... OK !" << finl;
1204}
1205
1206#endif
1207
1208void Domaine_VF::get_position(DoubleTab& positions) const
1209{
1210 positions.resize(nb_elem(), xp_.dimension(1));
1211 CDoubleTabView xp = xp_.view_ro();
1212 DoubleTabView positions_v = positions.view_wo();
1213 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_2D({0,0}, {nb_elem(), xp_.dimension(1)}), KOKKOS_LAMBDA(const int i, const int j)
1214 {
1215 positions_v(i,j) = xp(i,j);
1216 });
1217 end_gpu_timer(__KERNEL_NAME__);
1218 // Don't work with simply: ToDo fix
1219 // positions = zvf.xp();
1220}
1221
1222double Domaine_VF::compute_L1_norm(const DoubleVect& val_source, const bool basis_function, const int order) const
1223{
1224 double sum = 0.;
1225 const int ne = nb_elem();
1226 for (int i=0; i<ne; i++)
1227 {
1228 sum+=std::fabs(val_source(i))*volumes(i);
1229 }
1230 return sum;
1231}
1232
1233double Domaine_VF::compute_L2_norm(const DoubleVect& val_source, const bool basis_function, const int order) const
1234{
1235 double sum = 0.;
1236 const int ne = nb_elem();
1237 for (int i=0; i<ne; i++)
1238 {
1239 sum+=val_source(i)*val_source(i)*volumes(i);
1240 }
1241 return sum;
1242}
1243
1244void Domaine_VF::compute_average(const DoubleVect& val_source, double& sum, double& volume, const bool basis_function, const int order) const
1245{
1246 const int ne = nb_elem();
1247 CDoubleArrView vol = volumes().view_ro();
1248 CDoubleArrView val = val_source.view_ro();
1249 Kokkos::parallel_reduce(start_gpu_timer(__KERNEL_NAME__), ne, KOKKOS_LAMBDA(const int i, double & sum_tmp, double & volume_tmp)
1250 {
1251 double v = vol(i);
1252 sum_tmp += val(i) * v;
1253 volume_tmp += v;
1254 }, sum, volume);
1255 end_gpu_timer(__KERNEL_NAME__);
1256}
1257
1258void Domaine_VF::compute_average_porosity(const DoubleVect& val_source, const DoubleVect& porosity, double& sum, double& volume, const bool basis_function, const int order) const
1259{
1260 const int ne = nb_elem();
1261 CDoubleArrView vol = volumes().view_ro();
1262 CDoubleArrView poro = porosity.view_ro();
1263 CDoubleArrView val = val_source.view_ro();
1264 Kokkos::parallel_reduce(start_gpu_timer(__KERNEL_NAME__), ne, KOKKOS_LAMBDA(const int i, double & sum_tmp, double & volume_tmp)
1265 {
1266 double v = vol(i);
1267 double p = poro(i);
1268 sum_tmp += val(i) * v * p;
1269 volume_tmp += v * p;
1270 }, sum, volume);
1271 end_gpu_timer(__KERNEL_NAME__);
1272}
1273
1275{
1276 Process::exit("The function should not be used in domaine_VF, related to quadrature points (DG discretization)");
1277 //surcharge dans domaine_DG mais qui n'est pas dans kernel
1278}
1279
1281{
1282 Process::exit("The function should not be used in domaine_VF, related to quadrature points (DG discretization)");
1283 //surcharge dans domaine_DG mais qui n'est pas dans kernel
1284}
1285
1287{
1288 Process::exit("The function should not be used in domaine_VF, related to quadrature points (DG discretization)");
1289 return 0;
1290 //surcharge dans domaine_DG mais qui n'est pas dans kernel
1291}
1292
1293#ifdef TRUST_USE_ARBORX
1294// Callback to store the result indices
1295struct ExtractIndex
1296{
1297 template <typename Query, typename Value, typename Output>
1298 KOKKOS_FUNCTION void operator()(Query const&, Value const& value, Output const& out) const
1299 {
1300 out(value.index);
1301 }
1302};
1303#endif
1304
1305/*! Methode inspiree de Raccord_distant_homogene::initialise
1306 */
1308{
1309 if(dist_paroi_initialisee_) return;
1310 Cerr << "Domaine_VF::init_dist_paroi_globale..." << finl;
1311
1312 const Domaine_VF& domaine_ = *this;
1313 int D=Objet_U::dimension, nf = domaine_.nb_faces(), ne = domaine_.nb_elem();
1314 const IntTab& f_s = face_sommets();
1315 const DoubleTab& xs = domaine_.domaine().coord_sommets();
1316
1317 // On initialise les tables y_faces_ et y_elem_
1318 domaine_.creer_tableau_faces(y_faces_);
1320
1321 n_y_elem_.resize(0,D);
1322 n_y_faces_.resize(0,D);
1323
1326
1327 // On va identifier les faces par leur centres de gravite
1328 int parts = Process::nproc();
1329 int moi = Process::me();
1330 DoubleTabs remote_xv(parts);
1331
1332 // On initialise la table de faces/sommets/aretes de bords locale, on cree une table de sommets locale et on compte les aretes
1333 int nb_faces_bord_ = 0;
1334 int nb_aretes = 0;
1335 std::set<int> soms;
1336 for (auto& itr : conds_lim)
1337 if ( sub_type(Dirichlet_paroi_defilante, itr.valeur()) || sub_type(Dirichlet_homogene, itr.valeur()) ||
1338 (sub_type(Navier, itr.valeur()) && !sub_type(Symetrie, itr.valeur()) ) || sub_type(Dirichlet_loi_paroi, itr.valeur()))
1339 {
1340 int num_face_1_cl = itr->frontiere_dis().frontiere().num_premiere_face();
1341 int nb_faces_cl = itr->frontiere_dis().frontiere().nb_faces();
1342
1343 nb_faces_bord_ += itr->frontiere_dis().frontiere().nb_faces();
1344
1345 for (int f=num_face_1_cl ; f < nb_faces_cl+num_face_1_cl ; f++)
1346 {
1347 int nb_som_loc = 0;
1348 while ( (nb_som_loc < nb_som_face()) && (f_s(f, nb_som_loc) != -1))
1349 {
1350 soms.insert(f_s(f, nb_som_loc));
1351 nb_som_loc++;
1352 }
1353 nb_aretes += (D == 3 ? nb_som_loc : 0) ; // Autant d'aretes autour d'une face que de sommets !
1354 }
1355 }
1356
1357 if (Process::mp_max(nb_faces_bord_) == 0) /* test all procs */
1358 Process::exit(que_suis_je() + " : at least one boundary must be solid for the distance to the edge to be calculated !!!");
1359
1360 remote_xv[moi].resize(nb_faces_bord_ + (int)soms.size() + nb_aretes,D);
1361 int index[5] = { -1, -1, -1, -1, -1 };
1362 bool Z_numbered = que_suis_je() == "Domaine_VDF" && dimension==3;
1363 if (Z_numbered) // Numerotation en Z des sommets dans une face...
1364 {
1365 index[0] = 0;
1366 index[1] = 1;
1367 index[2] = 3;
1368 index[3] = 2;
1369 index[4] = 0;
1370 }
1371 // On remplit les coordonnes des faces et aretes de bord locales
1372 int ind_tab = 0 ; // indice de la face/sommet/arete dans le tableau
1373 for (int ind_cl = 0 ; ind_cl < conds_lim.size() ; ind_cl++)
1374 if ( sub_type(Dirichlet_paroi_defilante, conds_lim[ind_cl].valeur()) || sub_type(Dirichlet_homogene, conds_lim[ind_cl].valeur()) || (sub_type(Navier, conds_lim[ind_cl].valeur()) && !sub_type(Symetrie, conds_lim[ind_cl].valeur()) ) )
1375 {
1376 int num_face_1_cl = conds_lim[ind_cl]->frontiere_dis().frontiere().num_premiere_face();
1377 int nb_faces_cl = conds_lim[ind_cl]->frontiere_dis().frontiere().nb_faces();
1378
1379 for (int f=num_face_1_cl ; f < nb_faces_cl+num_face_1_cl ; f++)
1380 {
1381 for (int d=0 ; d<D ; d++)
1382 remote_xv[moi](ind_tab,d) = domaine_.xv(f, d); // Remplissage des faces
1383 ind_tab++;
1384
1385 if (D==3) // Remplissage des aretes
1386 {
1387 if (Z_numbered) // Numerotation en Z des sommets dans une face...
1388 {
1389 for (int id_som=1; id_som<=nb_som_face(); id_som++)
1390 {
1391 for (int d = 0; d < D; d++)
1392 remote_xv[moi](ind_tab, d) =
1393 (xs(f_s(f, index[id_som]), d) + xs(f_s(f, index[id_som - 1]), d)) / 2;
1394 ind_tab++;
1395 }
1396 }
1397 else
1398 {
1399 int id_som = 1;
1400 while ((id_som < nb_som_face()) && (f_s(f, id_som) != -1))
1401 {
1402 for (int d = 0; d < D; d++)
1403 remote_xv[moi](ind_tab, d) = (xs(f_s(f, id_som), d) + xs(f_s(f, id_som - 1), d)) / 2;
1404 id_som++;
1405 ind_tab++;
1406 }
1407 for (int d = 0; d < D; d++)
1408 remote_xv[moi](ind_tab, d) = (xs(f_s(f, 0), d) + xs(f_s(f, id_som - 1), d)) / 2;
1409 ind_tab++;
1410 }
1411 }
1412 }
1413 }
1414
1415 for (auto som:soms) // Remplissage des sommets
1416 {
1417 for (int d=0 ; d<D ; d++)
1418 remote_xv[moi](ind_tab,d) = xs(som, d);
1419 ind_tab++;
1420 }
1421
1422
1423 // Puis on echange les tableaux des centres de gravites
1424 // envoi des tableaux
1425 Cerr << "[MPI] Broadcasting remote_xv..." << finl;
1426 for (int p = 0; p < parts; p++)
1427 envoyer_broadcast(remote_xv[p], p);
1428
1429 int nb_total_points=0;
1430 for (int p = 0; p < parts; p++)
1431 nb_total_points+=remote_xv[p].dimension(0);
1432
1433 Cerr << "Number of boundary points: " << nb_total_points << finl;
1434 double GBytes = nb_total_points * 4.0 /* float */ * D / 1024.0 / 1024.0 / 1024.0;
1435 Cerr << "Estimated memory needed: " << GBytes << " GB" << finl;
1436
1437 // On traite les informations, chaque proc connait tous les XV
1438
1439// On boucle sur toutes les faces puis tous les elems
1440 const DoubleTab& local_xv = domaine_.xv();
1441 const DoubleTab& local_xp = domaine_.xp();
1442 ArrOfInt glob_idx(Process::check_int_overflow(nf+ne));
1443#ifdef TRUST_USE_ARBORX
1444 // Use ArborX on GPU to compute the nearest points cause too slow on large meshes
1445 int dim = dimension;
1446 using ExecutionSpace = Kokkos::DefaultExecutionSpace;
1447 using MemorySpace = ExecutionSpace::memory_space;
1448 using Point = ArborX::Point<3>;
1449 ExecutionSpace space;
1450 Kokkos::View<Point *, MemorySpace> query_points("local_xs", nf + ne);
1451 CDoubleTabView xv = local_xv.view_ro();
1452 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nf, KOKKOS_LAMBDA(
1453 const int i)
1454 {
1455 query_points[i] = {(float) xv(i, 0), (float) xv(i, 1), dim == 3 ? (float) xv(i, 2) : 0.f};
1456 });
1457 end_gpu_timer(__KERNEL_NAME__);
1458 CDoubleTabView xp = local_xp.view_ro();
1459 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), ne, KOKKOS_LAMBDA(
1460 const int i)
1461 {
1462 query_points[nf + i] = {(float) xp(i, 0), (float) xp(i, 1), dim == 3 ? (float) xp(i, 2) : 0.f};
1463 });
1464 end_gpu_timer(__KERNEL_NAME__);
1465 // One BVH per batch of parts (slower but less memory expensive than single BVH)
1466 ArrOfDouble distances(nf+ne);
1467 distances=DMAXFLOAT;
1468 // Define batch_size (parts per batch) to not use more than 1GB per batch
1469 double target_GB = 1.0;
1470 int num_batches = std::max(1, (int)std::ceil(GBytes / target_GB));
1471 int batch_size = std::max(1, (parts + num_batches - 1) / num_batches); // ceil(parts / num_batches)
1472 Cerr << "Number of batches: " << num_batches << ", parts per batch: " << batch_size
1473 << ", points per batch: ~" << nb_total_points / num_batches << finl;
1474 for (int batch_start = 0; batch_start < parts; batch_start += batch_size)
1475 {
1476 int batch_end = std::min(batch_start + batch_size, parts);
1477
1478 // Compute total number of points in this batch
1479 int nb_points = 0;
1480 for (int part = batch_start; part < batch_end; part++)
1481 nb_points += remote_xv[part].dimension(0);
1482 if (nb_points == 0) continue;
1483
1484 // Fill points view with all parts in this batch
1485 Kokkos::View<Point *, MemorySpace> points("remote_xv", nb_points);
1486 int point_offset = 0;
1487 for (int part = batch_start; part < batch_end; part++)
1488 {
1489 int size = remote_xv[part].dimension(0);
1490 if (size > 0)
1491 {
1492 CDoubleTabView coord = remote_xv[part].view_ro();
1493 int local_offset = point_offset; // Capture for lambda
1494 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), size, KOKKOS_LAMBDA(const int i)
1495 {
1496 points[local_offset + i] = {(float) coord(i, 0), (float) coord(i, 1),
1497 dim == 3 ? (float) coord(i, 2) : 0.f
1498 };
1499 });
1500 end_gpu_timer(__KERNEL_NAME__);
1501 }
1502 point_offset += size;
1503 }
1504
1505 // BVH
1506 Cerr << "ArborX::BoundingVolumeHierarchy for parts " << batch_start << " to " << batch_end - 1;
1507 ArborX::BoundingVolumeHierarchy bvh(space, ArborX::Experimental::attach_indices(points));
1508 Cerr << " created!" << finl;
1509 Kokkos::View<int *, MemorySpace> offsets("Example::offsets", 0);
1510 Kokkos::View<int *, MemorySpace> indices("Example::indices", 0);
1511 Cerr << "ArborX query...";
1512 bvh.query(space, ArborX::Experimental::make_nearest(query_points, 1), ExtractIndex {}, indices, offsets);
1513 Cerr << " completed!" << finl;
1514 // Compute global offset to the start of this batch
1515 int global_offset = 0;
1516 for (int pp = 0; pp < batch_start; pp++)
1517 global_offset += remote_xv[pp].dimension(0);
1518
1519 // GPU kernel: compute distances and update best matches
1520 // Use points[ar] directly (already on device) instead of remote_xv[part](ar_local, i)
1521 DoubleArrView dist = static_cast<ArrOfDouble&>(distances).view_rw();
1522 IntArrView glob = static_cast<ArrOfInt&>(glob_idx).view_rw();
1523 int total_fe = nf + ne;
1524 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), total_fe, KOKKOS_LAMBDA(const int fe)
1525 {
1526 int ar = indices(fe);
1527 float d = 0;
1528 for (int i = 0; i < dim; i++)
1529 {
1530 float diff = query_points(fe)[i] - points(ar)[i];
1531 d += diff * diff;
1532 }
1533 if (d < dist(fe))
1534 {
1535 dist(fe) = (double)d;
1536 glob(fe) = ar + global_offset;
1537 }
1538 });
1539 end_gpu_timer(__KERNEL_NAME__);
1540 }
1541#else
1542 // MedCoupling implementation (C++14, soon deprecated):
1543 //indices des points de remote_xvs les plus proches de chaque point de local_xv
1544 MCAuto <DataArrayIdType> glob(DataArrayIdType::New());
1545 //DataArrayDoubles des xv locaux et de tous les remote_xv (a la suite)
1546 std::vector<MCAuto<DataArrayDouble> > vxv(parts);
1547 std::vector<const DataArrayDouble*> cvxv(parts);
1548 MCAuto<DataArrayDouble> remote_xvs(DataArrayDouble::New());
1549 for (int p = 0; p < parts; p++)
1550 {
1551 vxv[p] = DataArrayDouble::New();
1552 vxv[p]->useExternalArrayWithRWAccess(remote_xv[p].addr(), remote_xv[p].dimension(0), remote_xv[p].dimension(1));
1553 cvxv[p] = vxv[p];
1554 }
1555 remote_xvs = DataArrayDouble::Aggregate(cvxv);
1556 MCAuto<DataArrayDouble> local_xs(DataArrayDouble::New());
1557 local_xs->alloc(nf+ne, D);
1558 for (int f = 0; f < nf; f++)
1559 for (int d = 0; d < D; d++)
1560 local_xs->setIJ(f, d, local_xv(f, d));
1561 for (int e = 0; e < ne; e++)
1562 for (int d = 0; d < D; d++)
1563 local_xs->setIJ(nf+e, d, local_xp(e, d));
1564 glob = remote_xvs->findClosestTupleId(local_xs);
1565 for (int i=0; i<nf+ne; i++)
1566 glob_idx(i) = (int)glob->getIJ(i,0);
1567#endif
1568
1569 ToDo_Kokkos("critical");
1570//pour chaque element et face de local_xs : remplissage des tableaux
1571 for (int fe = 0; fe<nf+ne; fe++)
1572 {
1573 //retour de l'indice global (glob_idx(ind_face)) au couple (proc, ind_face2)
1574 int proc = 0;
1575 int fe2 = glob_idx(fe);
1576 while (fe2 >= remote_xv[proc].dimension(0))
1577 {
1578 fe2 -= remote_xv[proc].dimension(0);
1579 proc++;
1580 }
1581 double distance2 = 0;
1582 for (int d=0; d<D; d++)
1583 {
1584 double x1 = 0 ;
1585 if (fe<nf) x1=local_xv(fe,d);
1586 else if (fe<nf+ne) x1=local_xp(fe-nf,d);
1587 else { Cerr<<"Domaine_VF::init_dist_paroi_globale : problem in the ditance to the edge calculation. Contact TRUST support."<<finl; Process::exit();}
1588 double x2=remote_xv[proc](fe2,d);
1589 distance2 += (x1-x2)*(x1-x2);
1590 }
1591 if (fe<nf)
1592 {
1593 y_faces_(fe) = std::sqrt(distance2);
1595 for (int d = 0 ; d<D ; d++)
1596 n_y_faces_(fe, d) = ( local_xv(fe,d)-remote_xv[proc](fe2,d) )/ y_faces_(fe);
1597 }
1598 else
1599 {
1600 y_elem_(fe-nf) = std::sqrt(distance2);
1601 for (int d = 0 ; d<D ; d++)
1602 n_y_elem_(fe-nf, d) = ( local_xp(fe-nf,d)-remote_xv[proc](fe2,d) )/ y_elem_(fe-nf);
1603 }
1604 }
1605
1606// Pour les elems de bord, on calcule la distance de facon propre avec le produit scalaire
1607 for (int ind_cl = 0 ; ind_cl < conds_lim.size() ; ind_cl++)
1608 if ( sub_type(Dirichlet_paroi_defilante, conds_lim[ind_cl].valeur()) || sub_type(Dirichlet_homogene, conds_lim[ind_cl].valeur()) || (sub_type(Navier, conds_lim[ind_cl].valeur()) && !sub_type(Symetrie, conds_lim[ind_cl].valeur()) ))
1609 {
1610 int num_face_1_cl = conds_lim[ind_cl]->frontiere_dis().frontiere().num_premiere_face();
1611 int nb_faces_cl = conds_lim[ind_cl]->frontiere_dis().frontiere().nb_faces();
1612
1613 for (int f=num_face_1_cl ; f < nb_faces_cl+num_face_1_cl ; f++)
1614 {
1615 const int ind = (face_voisins(f,0)>=0) ? face_voisins(f,0) : face_voisins(f,1) ;
1616 const double dist_ef_loc = (face_voisins(f,0)>=0) ? dist_face_elem0(f, face_voisins(f,0)) : dist_face_elem1(f, face_voisins(f,1));
1617 if ( dist_ef_loc < y_elem_(ind) ) // Prise en compte du cas ou l'element a plusieurs faces de bord
1618 {
1619 y_elem_(ind) = dist_ef_loc ;
1620 for (int d = 0 ; d < D ; d++)
1621 n_y_elem_(ind, d) = -face_normales(f, d)/face_surfaces(f);
1622 }
1623 for (int d = 0 ; d<D ; d++)
1624 n_y_faces_(f, d) = -face_normales(f, d)/face_surfaces(f); // Coherent normal vector for border faces
1625 }
1626 }
1627
1628 n_y_faces_.echange_espace_virtuel();
1629 n_y_elem_.echange_espace_virtuel();
1630 y_faces_.echange_espace_virtuel();
1631 y_elem_.echange_espace_virtuel();
1633 Cerr << "Initialize the y table " << domaine_.domaine().le_nom() << finl;
1634}
1635
1636/*! @brief Build the MEDCoupling **face** mesh.
1637 * It is always made of polygons (in 3D) for simplicity purposes.
1638 * Face numbers (and node numbers) are the same as in TRUST.
1639 *
1640 * It unfortunately needs a Domaine_dis_base since this is at this level that the face_sommets relationship is held ...
1641 * As a consequence also the faces of a Domaine can not be postprocessed before discretisation.
1642 * Another consequence is that it is not available for 64 bits domains.
1643 */
1645{
1646#ifdef MEDCOUPLING_
1647 using MEDCoupling::DataArrayIdType;
1648 using MEDCoupling::DataArrayDouble;
1649
1650 using DAId = MCAuto<DataArrayIdType>;
1651
1652 const MEDCouplingUMesh* mc_mesh = domaine().get_mc_mesh();
1653
1654 // Build descending connectivity and convert it to polygons
1655 DAId desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
1656 mc_face_mesh_ = mc_mesh->buildDescendingConnectivity(desc, descIndx, revDesc, revDescIndx);
1657 if (Objet_U::dimension == 3) mc_face_mesh_->convertAllToPoly();
1658
1659 // Build second temporary mesh (with shared nodes!) having the TRUST connectivity
1660 MCAuto<MEDCouplingUMesh> faces_tmp = mc_face_mesh_->deepCopyConnectivityOnly();
1661 const IntTab& faces_sommets = face_sommets();
1662 int nb_fac = faces_sommets.dimension(0);
1663 int max_som_fac = faces_sommets.dimension_int(1);
1664 assert((int)mc_face_mesh_->getNumberOfCells() == nb_fac);
1665 DAId c(DataArrayIdType::New()), cI(DataArrayIdType::New());
1666 c->alloc(0,1);
1667 cI->alloc(nb_fac+1, 1);
1668 mcIdType *cIP = cI->getPointer();
1669 cIP[0] = 0; // better not forget this ...
1670 mcIdType typ = Objet_U::dimension == 3 ? INTERP_KERNEL::NormalizedCellType::NORM_POLYGON : INTERP_KERNEL::NormalizedCellType::NORM_SEG2;
1671
1672 for (int fac=0; fac<nb_fac; fac++) // Fills the two MC arrays c and cI describing the connectivity of the face mesh
1673 {
1674 c->pushBackSilent(typ);
1675 int i=0, s=-1;
1676 for (; i < max_som_fac && (s = faces_sommets(fac, i)) >= 0; i++)
1677 c->pushBackSilent(s);
1678 cIP[fac+1] = cIP[fac] + i + 1; // +1 because of type
1679 }
1680 faces_tmp->setConnectivity(c, cI);
1681
1682 // Then we can simply identify cells by their nodal connectivity:
1683 DataArrayIdType * mP;
1684 mc_face_mesh_->areCellsIncludedIn(faces_tmp,2, mP); // 2: same nodal connectivity
1685 // DAId renum(mP); //useful to automatically free memory allocated in mP
1686 DAId renum2(mP->invertArrayN2O2O2N(nb_fac));
1687#ifndef NDEBUG
1688 // All cells should be found:
1689 DAId outliers = renum2->findIdsNotInRange(0, nb_fac);
1690 if (outliers->getNumberOfTuples() != 0)
1691 Process::exit("Invalid renumbering arrays! Should not happen. Some faces could not be matched between the TRUST face domain and the buildDescendingConnectivity() version.");
1692#endif
1693
1694#ifdef NDEBUG
1695 bool check = false;
1696#else
1697 bool check = true;
1698#endif
1699 // Apply the renumbering so that final mc_face_mesh_ has the same face number as in TRUST
1700 mc_face_mesh_->renumberCells(renum2->begin(), check);
1701#ifndef NDEBUG
1702 mc_face_mesh_->checkConsistency();
1703#endif
1704 mP->decrRef();
1705
1706 mc_face_mesh_ready_ = true;
1707#endif // MEDCOUPLING_
1708}
1709
1710/** @brief Build the dual mesh of the domain for post-processing of face fields.
1711 *
1712 * For each face of each element, a polyhedron is built with faces being made of
1713 * - the original face
1714 * - triangles buit with the element center of mass and each of the segment of the original face
1715 * Thus an inner face of the domain has two associated dual polyhedral elements, and a boundary
1716 * face has only one associated dual element.
1717 * The member face_dual_ is also completed and has the same logic and exact same ordering as face_voisins_.
1718 */
1720{
1721#ifdef MEDCOUPLING_
1722 using DAId = MCAuto<DataArrayIdType>;
1723 using DAD = MCAuto<DataArrayDouble>;
1724
1725 const MEDCouplingUMesh* mc_face_mesh = get_mc_face_mesh();
1726 const int dim = Objet_U::dimension;
1727
1728 Cerr << " Domaine: Creating **dual** mesh as a MEDCouplingUMesh object for the domain '" << le_nom() << "'" << finl;
1729
1730 // Fills in connectivity for the dual mesh, and correspondance array 'face_dual_'
1731 int nb_fac = Process::check_int_overflow(mc_face_mesh->getNumberOfCells());
1732 int nb_elem = domaine().nb_elem(); // real only
1733 int nb_coo = domaine().nb_som();
1734 const mcIdType *fc = mc_face_mesh->getNodalConnectivity()->getConstPointer(),
1735 *fcI= mc_face_mesh->getNodalConnectivityIndex()->getConstPointer();
1736 // Init face_dual_
1737 face_dual_.resize(nb_fac, 2);
1738 face_dual_=-1;
1739 // Prepare raw MC connectivity of the dual mesh:
1740 DAId c(DataArrayIdType::New()), cI(DataArrayIdType::New());
1741 cI->alloc(nb_fac*2, 1); // Conservative pre-allocation (too large because of bound faces)
1742 c->alloc(0,1);
1743 mcIdType *cIP = cI->getPointer();
1744 cIP[0] = 0; // better not forget this ...
1745 int gi = 0; // global index of dual elements created
1746
1747 auto corrige_voisins_dual_perio = [&](int f, int &e1, int &e2)
1748 {
1749 assert (est_face_bord_[f] == 2);
1750 auto d2 = [&](int e) -> double
1751 {
1752 double s = 0.;
1753 for (int d = 0; d < dim; d++)
1754 {
1755 double dx = xp_(e, d) - xv_(f, d);
1756 s += dx * dx;
1757 }
1758 return s;
1759 };
1760
1761 if (e1 >= 0 && e2 >= 0)
1762 {
1763 // On garde l'element vraiment adjacent a la face geometrique
1764 if (d2(e1) <= d2(e2)) e2 = -1;
1765 else e1 = -1;
1766 }
1767 };
1768
1769 // Precompute needed size:
1770 mcIdType totSz = 0;
1771 for(int f=0; f<nb_fac; f++) // For all the (real) faces
1772 {
1773 int e1=face_voisins_(f, 0), e2=face_voisins_(f, 1);
1774
1775 // XXX Elie Saikali : face periodique : la traiter comme une face de bord geometrique ...
1776 if (est_face_bord_[f] == 2)
1777 corrige_voisins_dual_perio(f, e1, e2);
1778
1779 for (int e: {e1, e2})
1780 {
1781 if (e==-1 || e >= nb_elem) continue; // skip boundary or virtual
1782 if (dim == 2) // easy, just triangles to build
1783 totSz += 3 + 1; // will add a triangle = 1 (type) + 3 sommets
1784 else // 3D
1785 {
1786 mcIdType nb_pts = fcI[f+1]-fcI[f]-1; // nb of points in face f (-1 to skip type)
1787
1788 // Increase size of c to fit for the next poyhedron to be inserted:
1789 // +1 : for the type POLYHED
1790 // nb_pts : original face
1791 // nb_pts*(3+1) : nb_pts triangular lateral faces (3 sommets + separateur -1)
1792 totSz += 1 // type
1793 + nb_pts // original face
1794 + nb_pts*(3+1); // lateral faces
1795 }
1796 }
1797 }
1798
1799 c->reAlloc(totSz); // done only once ! otherwise very costly
1800 mcIdType *cP = c->getPointer();
1801 mcIdType c_sz = 0;
1802
1803 for(int f=0; f<nb_fac; f++) // For all the (real) faces
1804 {
1805 int e1 = face_voisins_(f, 0), e2 = face_voisins_(f, 1);
1806
1807 // XXX Elie Saikali : face periodique : la traiter comme une face de bord geometrique ...
1808 if (est_face_bord_[f] == 2)
1809 corrige_voisins_dual_perio(f, e1, e2);
1810
1811 for (int e: {e1, e2})
1812 {
1813 if (e==-1 || e >= nb_elem) continue; // skip boundary or virtual
1814 if (dim == 2) // easy, just triangles to build
1815 {
1816 cP[c_sz++] = INTERP_KERNEL::NormalizedCellType::NORM_TRI3;
1817 // Triangle connectivity:
1818 const mcIdType *p = fc + fcI[f] + 1;
1819 cP[c_sz++] = *p;
1820 cP[c_sz++] = *(p+1);
1821 cP[c_sz++] = e+nb_coo; // index of the barycenter in the final coord array
1822 }
1823 else // 3D
1824 {
1825 mcIdType nb_pts = fcI[f+1]-fcI[f]-1; // nb of points in face f (-1 to skip type)
1826 cP[c_sz++] = INTERP_KERNEL::NormalizedCellType::NORM_POLYHED;
1827
1828 // 1) Add the face itself: (original face)
1829 for(const mcIdType *p = fc + fcI[f] + 1; p < fc+fcI[f + 1]; p++)
1830 cP[c_sz++] = *p;
1831
1832 // 2) Add the new triangular lateral faces containing the barycenter:
1833 const mcIdType *p2 = fc + fcI[f] + 1;
1834 for (mcIdType i = 0; i<nb_pts; i++) // loop on all segs of the face - in 2D this will loop once only
1835 {
1836 cP[c_sz++] = -1; // -1 to separate from the prev face in the polyhedron
1837 cP[c_sz++] = e+nb_coo; // index of the barycenter in the final coord array
1838 cP[c_sz++] = *(p2+i);
1839 cP[c_sz++] = *(p2+(i+1)%nb_pts);
1840 }
1841 }
1842 cIP[gi+1] = c_sz;
1843 face_dual_(f, e==e1 ? 0:1) = gi;
1844 gi++; // next dual element
1845 }
1846 }
1847 assert(c_sz == totSz); // check the awful size computation from above ...
1848
1849 // Strip cI that might be too big - surely a down-sizing
1850 cI->reAlloc(gi+1);
1851 // Prepare final coords - no choice here (sticking coords and xp_ together on TRUST side is a bad idea because of virtuals)
1852 // TODO - save/use coords for other (primal) meshes too
1853 DAD coo2 = mc_face_mesh->getCoords()->deepCopy();
1854 coo2->reAlloc(nb_coo+nb_elem);
1855 std::copy(xp_.addr(), xp_.addr() + nb_elem*dim, coo2->getPointer()+nb_coo*dim);
1856
1857 const std::string dual_nam = domaine().get_mc_mesh()->getName() + "_dual";
1858 mc_dual_mesh_ = MEDCouplingUMesh::New(dual_nam, dim);
1859 mc_dual_mesh_->setCoords(coo2);
1860 mc_dual_mesh_->setConnectivity(c,cI);
1861 mc_dual_mesh_ready_ = true;
1862
1863#ifndef NDEBUG
1864 /*
1865 * Final testing : Only in debug mode
1866 *
1867 * - nb_faces_bords does not change between primal (TRUST) mesh and dual mesh
1868 * - nb_faces per polyedron has at least 4 faces (case of tetra) : Only 3D !
1869 */
1870 MCAuto<MEDCouplingUMesh> skin_dual = mc_dual_mesh_->computeSkin();
1871 mcIdType nb_faces_bd = skin_dual->getNumberOfCells();
1872
1873 if (nb_faces_bd != (domaine().nb_faces_bord() + domaine().nb_faces_joint()))
1874 Process::exit("Something wrong with dual mesh computation #1 -- boundary faces !!!! \n");
1875
1876 if (Objet_U::dimension == 3) /* Only polyhedron case !*/
1877 {
1878 DAId desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
1879 mc_dual_mesh_->buildDescendingConnectivity(desc, descIndx, revDesc, revDescIndx);
1880
1881 DAId dsi = descIndx->deltaShiftIndex();
1882 DAId res = dsi->findIdsLowerOrEqualTo(3) ;
1883 if (res->getNumberOfTuples() > 0)
1884 Process::exit("Something wrong with dual mesh computation #2 -- polyhedron faces !!!! \n");
1885 }
1886#endif
1887
1888#endif // MEDCOUPLING_
1889}
Empty class used as a base for all the arrays.
Definition Array_base.h:41
int nb_bords() const
Definition Bords.h:39
classe Cond_lim_base Classe de base pour la hierarchie des classes qui representent les differentes c...
virtual Frontiere_dis_base & frontiere_dis()
Renvoie la frontiere discretisee a laquelle les conditions aux limites s'appliquent.
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
Classe Dirichlet_homogene Cette classe est la classe de base de la hierarchie des conditions aux limi...
Classe Dirichlet_loi_paroi Classe de base pour les valeurs impose pour une condition aux limites des ...
classe Dirichlet_paroi_defilante Impose la vitesse de paroi dnas une equation de type Navier_Stokes.
void calculer_mon_centre_de_gravite(ArrOfDouble &c)
Calcule le centre de gravite du domaine.
Definition Domaine.cpp:736
const Sous_Domaine_t & ss_domaine(int i) const
Definition Domaine.h:290
int nb_front_Cl() const
Definition Domaine.h:236
Groupe_Faces_t & groupe_faces(int i)
Definition Domaine.h:221
Bord_Interne_t & bords_interne(int i)
Definition Domaine.h:208
virtual void creer_tableau_elements(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
creation d'un tableau parallele de valeurs aux elements.
Definition Domaine.cpp:851
void creer_mes_domaines_frontieres(const Domaine_VF &domaine_vf)
Definition Domaine.cpp:2176
Raccord_t & raccord(int i)
Definition Domaine.h:248
void calculer_centres_gravite(DoubleTab_t &xp) const
Calcule les centres de gravites des elements du domaine.
Definition Domaine.h:503
int_t nb_faces_frontiere() const
Renvoie le nombre de faces frontiere du domaine (somme des nombres de bords, de raccords et de bords ...
Definition Domaine.h:488
virtual void calculer_volumes(DoubleVect_t &volumes, DoubleVect_t &inv_volumes) const
Calcule les volumes des elements du domaine.
Definition Domaine.cpp:764
void init_faces_virt_bord(const MD_Vector &md_vect_faces, MD_Vector &md_vect_faces_bord)
Definition Domaine.cpp:1908
DoubleTab_t & les_sommets()
Definition Domaine.h:113
Bords_t & faces_bord()
Definition Domaine.h:198
const Frontiere_t & frontiere(int i) const
Definition Domaine.h:539
int nb_frontieres_internes() const
Definition Domaine.h:235
Raccords_t & faces_raccord()
Definition Domaine.h:253
IntTab_t & les_elems()
Definition Domaine.h:129
int_t nb_elem() const
Definition Domaine.h:131
Bord_t & bord(int i)
Definition Domaine.h:193
int nb_bords() const
Definition Domaine.h:192
const DoubleTab_t & coord_sommets() const
Definition Domaine.h:112
const ArrOfDouble & cg_moments() const
Definition Domaine.h:307
Joints_t & faces_joint()
Definition Domaine.h:265
int_t nb_som_tot() const
Renvoie le nombre total de sommets du domaine i.e. le nombre de sommets reels et virtuels sur le proc...
Definition Domaine.h:123
int_t nb_som() const
Renvoie le nombre de sommets du domaine.
Definition Domaine.h:121
int nb_groupes_faces() const
Definition Domaine.h:220
Groupes_Faces_t & groupes_faces()
Definition Domaine.h:224
void imprimer() const
Definition Domaine.cpp:1184
int nb_raccords() const
Definition Domaine.h:247
classe Domaine_Cl_dis_base Les objets Domaine_Cl_dis_base representent les conditions aux limites
class Domaine_VF
Definition Domaine_VF.h:44
IntTab face_virt_pe_num_
Definition Domaine_VF.h:245
void info_elem_som()
IntVect rang_elem_non_std_
Definition Domaine_VF.h:252
void creer_tableau_aretes(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
int nb_faces() const
renvoie le nombre global de faces.
Definition Domaine_VF.h:471
DoubleTab xp_
Definition Domaine_VF.h:218
virtual double compute_L1_norm(const DoubleVect &val_source, const bool basis_function, const int order) const
void build_mc_face_mesh() const
Build the MEDCoupling face mesh. It is always made of polygons (in 3D) for simplicity purposes....
void build_map_mc_Cmesh(const bool with_faces) override
IntTab & face_sommets() override
renvoie le tableau de connectivite faces/sommets.
Definition Domaine_VF.h:591
virtual const DoubleTab & xv_bord() const
virtual double dist_face_elem1(int, int) const
Definition Domaine_VF.h:183
virtual double compute_L2_norm(const DoubleVect &val_source, const bool basis_function, const int order) const
IntTab face_numero_bord_
Definition Domaine_VF.h:226
void init_dist_paroi_globale(const Conds_lim &conds_lim) override
DoubleVect volumes_entrelaces_
Definition Domaine_VF.h:210
void order_faces(Faces &les_faces)
This method (that may be overriden in various discretisations) is used to order faces according to th...
const MD_Vector & md_vector_aretes() const
Definition Domaine_VF.h:160
virtual void get_ind_integ_points(IntTab &nelem) const
int nb_faces_tot() const
renvoie le nombre total de faces.
Definition Domaine_VF.h:481
virtual Faces * creer_faces()
renvoie new(Faces) ! elle est surchargee par Domaine_VDF par ex.
void creer_tableau_faces(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
void sort_along_zcurve(const Faces &les_faces, IntTab &sort_key) const
Tweak the face sorting keys so that internal faces (=standard faces) follow a Z-curve indexing scheme...
IntTab face_dual_
For each face f, face_dual_(f, j) returns the element built on the left and right of the face in the ...
Definition Domaine_VF.h:267
DoubleTab xv_
Definition Domaine_VF.h:219
int nb_elem_std_
Definition Domaine_VF.h:250
IntTab face_sommets_
Definition Domaine_VF.h:223
double xv(int num_face, int k) const
Definition Domaine_VF.h:76
void infobord()
MD_Vector md_vector_faces_
Definition Domaine_VF.h:229
void discretiser_no_face() override
int nb_faces_std_
Definition Domaine_VF.h:251
virtual void prepare_elem_non_std(Faces &les_faces)
Identify non-standard elements (will be used later to identify non standard faces) Some discretisatio...
int nb_joints() const
Definition Domaine_VF.h:65
const Joint & joint(int i) const
Definition Domaine_VF.h:105
void remplir_face_numero_bord()
virtual void compute_sort_key(Faces &les_faces, IntTab &sort_key)
Generate an IntTab (sort_key) with two columns allowing to sort the faces along a specific order....
virtual int get_max_nb_integ_points() const
void creer_tableau_faces_bord(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
DoubleVect inverse_volumes_
Definition Domaine_VF.h:209
void discretiser() override
Genere les faces construits les frontieres.
void modifier_pour_Cl(const Conds_lim &) override
DoubleTab & xv()
Definition Domaine_VF.h:93
void build_mc_dual_mesh() const
Build the dual mesh of the domain for post-processing of face fields.
DoubleTab n_y_elem_
Definition Domaine_VF.h:247
DoubleTab n_y_faces_
Definition Domaine_VF.h:248
void construire_face_virt_pe_num()
Remplissage du tableau face_virt_pe_num_ (voir commentaire dans Domaine_VF.
IntTab & elem_faces()
renvoie le tableau de connectivite element/faces
Definition Domaine_VF.h:551
ArrOfInt est_face_bord_
Definition Domaine_VF.h:240
virtual void typer_elem(Domaine &)
Definition Domaine_VF.h:61
virtual void get_position(DoubleTab &positions) const
int numero_face_local(int face, int elem) const
IntTab num_fac_loc_
Definition Domaine_VF.h:237
int nb_som_face() const
renvoie le nombre de sommets par face.
Definition Domaine_VF.h:494
DoubleVect volumes_
Definition Domaine_VF.h:208
DoubleTab normalized_boundaries_outward_vector(int global_face_number, double scale_factor) const
Compute the normalized boundary outward vector associated to the face global_face_number and eventual...
virtual const IntVect & orientation() const
Definition Domaine_VF.h:646
IntTab face_voisins_
Definition Domaine_VF.h:216
const IntTab & face_virt_pe_num() const
IntTab elem_faces_
Definition Domaine_VF.h:222
DoubleTab xv_bord_
Definition Domaine_VF.h:220
double xp(int num_elem, int k) const
Definition Domaine_VF.h:77
DoubleVect & volumes()
Definition Domaine_VF.h:119
virtual void renumber_faces(Faces &les_faces, IntTab &sort_key)
Re-index faces according to the new order given by 'sort_key'.
virtual void remplir_face_voisins_fictifs(const Domaine_Cl_dis_base &)
void construire_num_fac_loc()
MD_Vector md_vector_faces_front_
Definition Domaine_VF.h:231
DoubleTab calculer_xgr() const
calcul le tableau xgr pour le calcul des moments des forces aux bords :
int premiere_face_int() const
une face est interne ssi elle separe deux elements.
Definition Domaine_VF.h:463
DoubleTab & xp()
Definition Domaine_VF.h:95
int nb_faces_bord() const
renvoie le nombre de faces sur lesquelles sont appliquees les conditions limites :
Definition Domaine_VF.h:513
virtual void compute_average_porosity(const DoubleVect &val_source, const DoubleVect &porosity, double &sum, double &volume, const bool basis_function, const int order) const
const MD_Vector & md_vector_faces_bord() const
Definition Domaine_VF.h:157
virtual void compute_average(const DoubleVect &val_source, double &sum, double &volume, const bool basis_function, const int order) const
virtual double dist_face_elem0(int, int) const
Definition Domaine_VF.h:182
DoubleVect & inverse_volumes()
Definition Domaine_VF.h:120
ArrOfInt faces_doubles_
Definition Domaine_VF.h:239
virtual DoubleTab & face_normales()
Definition Domaine_VF.h:48
virtual void get_nb_integ_points(IntTab &nelem) const
void typer_discretiser_ss_domaine(int i) override
IntTab & face_voisins() override
renvoie le tableaux des volumes des connectivites face elements cf au dessus.
Definition Domaine_VF.h:426
void marquer_faces_double_contrib(const Conds_lim &)
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.
int nb_front_Cl() const
virtual void discretiser()
const Domaine & domaine() const
TRUST_Vector< OWN_PTR(Sous_domaine_dis_base)> les_sous_domaines_dis_
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
void typer(const Motcle &)
Type les faces.
Definition Faces.cpp:390
void associer_domaine(const Domaine_t &z)
Definition Faces.h:94
IntTab_t & voisins()
Renvoie le tableau des voisins (des faces).
Definition Faces.h:89
void calculer_surfaces(DoubleVect_t &surf) const
Calcule la surface des faces.
Definition Faces.cpp:495
int_t nb_faces() const
Definition Faces.h:66
void calculer_centres_gravite(DoubleTab_t &xv) const
Calcule les centres de gravite de chaque face.
Definition Faces.cpp:776
int_t voisin(int_t, int) const
Renvoie le numero du i-ieme voisin de face.
Definition Faces.h:165
const IntTab_t & les_sommets() const
Renvoie le tableau des sommets de toutes les faces.
Definition Faces.h:74
void creer_faces_reeles(Domaine_t &domaine, const Static_Int_Lists_t &connect_som_elem, Faces_t &les_faces, IntTab_t &elem_faces)
A partir de la description des elements du domaine et des frontieres (bords, raccords,...
class Front_VF
Definition Front_VF.h:36
int nb_faces() const
Definition Front_VF.h:53
int num_premiere_face() const
Definition Front_VF.h:63
int nb_faces_tot() const
Definition Front_VF.h:58
int num_face(const int) const
Definition Front_VF.h:68
int_t num_premiere_face() const
Definition Frontiere.h:67
void fixer_num_premiere_face(int_t i)
Definition Frontiere.h:68
int_t nb_faces() const
Renvoie le nombre de faces de la frontiere.
Definition Frontiere.h:59
const Faces_t & faces() const
Definition Frontiere.h:54
void renumerote(ArrOfInt_t &reverse_index)
const Joint_Items_t & joint_item(JOINT_ITEM type) const
Renvoie les informations de joint pour le type demande.
Definition Joint.cpp:128
Joint_Items_t & set_joint_item(JOINT_ITEM type)
Renvoie les informations de joint pour un type d'item geometrique donne, pour remplissage des structu...
Definition Joint.cpp:103
const IntTab_t & renum_items_communs() const
Voir renum_items_communs_.
ArrOfInt_t & set_items_communs()
Renvoie le tableau items_communs_ pour le remplir.
virtual trustIdType nb_items_seq_tot() const
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.
: Cette classe est un OWN_PTR mais l'objet pointe est partage entre plusieurs
Definition MD_Vector.h:48
classe Navier Condition aux limites sur la vitesse de type "Navier" :
Definition Navier.h:31
static int dimension
Definition Objet_U.h:99
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
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 const Nom & le_nom() const
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Objet_U.cpp:319
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
classe Periodique Cette classe represente une condition aux limites periodique.
Definition Periodique.h:31
int face_associee(int i) const
Definition Periodique.h:35
static int check_int_overflow(trustIdType)
Definition Process.cpp:428
static double mp_max(double)
Definition Process.cpp:376
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
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 double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
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
int nb_raccords() const
Renvoie le nombre de raccords contenus dans la liste.
Definition Raccords.h:38
static void construire_espace_virtuel_traduction(const MD_Vector &md_indice, const MD_Vector &md_valeur, IntTab &tableau, const int error_is_fatal=1)
Construit la structure items_communs + espaces virtuels d'un tableau contenant des indices d'items ge...
Definition Scatter.cpp:1624
static void calculer_renum_items_communs(Joints &joints, const JOINT_ITEM type_item)
On suppose que chaque joint[i].joint_item(type_item).items_communs() contient les indices locaux des ...
Definition Scatter.cpp:1222
static void construire_md_vector(const Domaine &, int nb_items_reels, const JOINT_ITEM, MD_Vector &)
construction d'un MD_Vector_std a partir des informations de joint du domaine pour le type d'item dem...
Definition Scatter.cpp:1279
static void calculer_espace_distant_faces(Domaine &domaine, const int nb_faces_reelles, const IntTab &elem_faces)
Idem que Scatter::calculer_espace_distant_sommets pour les faces.
Definition Scatter.cpp:1182
Classe de base des flux de sortie.
Definition Sortie.h:52
classe Symetrie Sur les faces de symetrie on a les proprietes suivantes:
Definition Symetrie.h:37
_SIZE_ size_array() const
virtual void ref(const TRUSTTab &)
Definition TRUSTTab.tpp:308
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, View< _TYPE_, _SHAPE_ > > view_wo()
Definition TRUSTTab.h:276
int dimension_int(int d) const
Definition TRUSTTab.tpp:152
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, ConstView< _TYPE_, _SHAPE_ > > view_ro() const
Definition TRUSTTab.h:261
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
virtual const MD_Vector & get_md_vector() const
Definition TRUSTVect.h:123
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")
void resize(int i)
static trustIdType internal_items_size_