TrioCFD 1.9.9_beta
TrioCFD documentation
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 : TODO what to do here ???
90 // faces_doubles_.ecrit(os);
91
92 os << "face_sommets_ : " << finl; // PQ : 12/10/05 : TODO what to do here ???
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 : TODO what to do here ???
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 of rang_elem_non_std_ :
149 // It is a vector indexed by the domain elements.
150 // size() = nb_elem()
151 // size_tot() = nb_elem_tot()
152 // Values in the array:
153 // rang_elem_non_std_[i] = -1 if element i is standard,
154 // otherwise
155 // rang_elem_non_std_[i] = j, where j is the index of the element in
156 // the arrays indexed by non-standard elements (for example the array Domaine_Cl_EF::type_elem_Cl_).
157 //
158 // An element is non-standard if it is adjacent to a boundary face.
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 // First mark the non-standard elements with 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 // Replace the "0" marker with an incremental index.
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 of the face renumbering array. This array,
195 // once sorted in ascending order, gives the order of faces in
196 // the domain_VF. The sort key is built so as to be able to recover
197 // the face index from the key using the formula:
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 // Note: face_voisins_ is not yet initialized, we must use les_faces.voisins() instead:
205 const IntTab& facevoisins = les_faces.voisins();
206 // Place boundary faces first:
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 // These faces always have two neighbours.
218 assert(elem0 >= 0 && elem1 >= 0);
219 // If the face is adjacent to a non-standard element, it must be classified just after the boundary faces:
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 // Standard face: at the end of the array
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 // Reorder the 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 // Compute the inverse table: reverse_index[old_number] = new_number
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 // Renumbering of elem_faces:
337 // Number of face indices in the array
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 // Update of the joint face indices:
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 filled?
355 for (int i = 0; i < nbfaces2; i++)
356 {
357 const int old = indices_faces[i]; // old local index
358 indices_faces[i] = reverse_index[old];
359 }
360 // Joint faces are no longer consecutive in the
361 // array: num_premiere_face no longer makes sense
362 un_joint.fixer_num_premiere_face(-1);
363 }
364
365 // Update of the face group indices:
366 Groupes_Faces& groupes_faces = domaine().groupes_faces();
367 groupes_faces.renumerote(reverse_index);
368}
369
370/*! @brief Generates the faces and builds the boundaries
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 // The faces are in their final order, we can now fill
412 // renum_items_communs for the faces:
413 Scatter::calculer_renum_items_communs(ledomaine.faces_joint(), JOINT_ITEM::FACE);
414
415 // Filling of face_voisins for the boundaries:
416 // to be factored with 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 // After the following method, we will be allowed to use 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 of the virtual space of the face_sommets array
444
445 // Same for face_voisins_
446 // Some faces of the outermost virtual elements have no local neighbouring element => non-fatal errors
447 Scatter::construire_espace_virtuel_traduction(md_vector_faces_, md_vect_elements, les_faces.voisins(), 0 /* error not fatal */);
448
449 // Same for elem_faces_
451
453
454 // Assignment of face_voisins and face_sommets
455 face_voisins().ref(les_faces.voisins());
456 face_sommets().ref(les_faces.les_sommets());
457
458 // Computation of surfaces:
459 les_faces.calculer_surfaces(face_surfaces_);
460 // Computation of the surface of virtual faces
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); // Detach the parallel structure
465
466 // Change in v1.5.7 beta: xv_ now has a parallel descriptor: dimension(0)=nb_faces
467 les_faces.calculer_centres_gravite(xv_);
468
469 // Computation of 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 of gravity of elements (array xp_)
506 ledomaine.calculer_centres_gravite(xp_);
507 // Centre of gravity of the domain
508 ArrOfDouble c(dimension);
510
511 // Create the boundary domains
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 // Print some information
525 ///////////////////////
526 ledomaine.imprimer(); // Domain extrema and volumes
527 infobord(); // Boundary areas
528 info_elem_som(); // Number of elements and vertices
529 Cerr << "<<<<<< End of Discretization VF >>>>>>>>>>" << finl;
530}
531
533{
534 Domaine& dom = domaine();
535 typer_elem(dom);
536 // Compute the volume of the discretised domain
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 Returns new(Faces)! It is overridden by Domaine_VDF for example.
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 of the face_voisins array
580 // A periodic-type face must have the same neighbours as
581 // its associated face
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 : periodic faces having double contribution,
618 // the call to marquer_faces_double_contrib is done in this method
619 // in order to benefit from conds_lim.
620
621
623 // Construction of the num_fac_loc_ array
625}
626
627// Method for building the num_fac_loc_ array
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 // Periodic case
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// Returns the local face number from the global face and elem numbers
664// Use Domaine_VF::num_fac_loc(face,voisin) if possible because that method is
665// optimized, whereas this one is not.
666int Domaine_VF::numero_face_local(int face, int elem) const
667{
668 //int nfe=domaine().nb_faces_elem();
669 // GF for the case where there are multiple types of faces....
670 // nb_faces_elem() returns the number of vertices per face for the first face type
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 Fills in the face_virt_pe_num_ array (see comment in Domaine_VF.h).
679 *
680 */
682{
683 int i;
684
685 const int nf = nb_faces();
686 const int nf_tot = nb_faces_tot();
687 const int nb_faces_virt = nf_tot - nf;
688
689 IntTab tmp(0, 2);
690 creer_tableau_faces(tmp, RESIZE_OPTIONS::NOCOPY_NOINIT);
691 const int moi = me();
692 for (i = 0; i < nf; i++)
693 {
694 tmp(i, 0) = moi;
695 tmp(i, 1) = i;
696 }
698
699 face_virt_pe_num_.resize(nb_faces_virt, 2);
700 // Copy of the virtual part of tmp into face_virt_pe_num_
701 face_virt_pe_num_.inject_array(tmp, nb_faces_virt*2, 0 /* dest offset*/, nf * 2 /* source offset*/);
702}
703
704const IntTab& Domaine_VF::face_virt_pe_num() const
705{
706 // Verify that the array has been built (if it crashes, it means we
707 // forgot to call construire_face_virt_pe_num()).
708 assert(face_virt_pe_num_.dimension(1) == 2);
709 return face_virt_pe_num_;
710}
711
712/*! @brief Compute the normalized boundary outward vector associated to the face global_face_number and eventually scaled by scale_factor
713 *
714 */
715DoubleTab Domaine_VF::normalized_boundaries_outward_vector(int global_face_number, double scale_factor) const
716{
717 const IntTab& neighbor_faces = face_voisins();
718 DoubleTab normal_vector(dimension); //result
719 for (int d = 0; d < dimension; d++)
720 normal_vector(d) = face_normales(global_face_number, d) / face_surfaces(global_face_number);
721
722 //now we have a normalized normal vector
723 //but it remains to orient it correctly (outwards)
724 //for this we build a vector that links middle of the face to the center of the element
725 //and then we do the inner product between this new vector and normal vector
726 //So, if the result is positive, we change the sign of normal vector
727 //else we do nothing
728 int neighbor_elem=neighbor_faces(global_face_number,0);
729 if( neighbor_elem == -1 )
730 neighbor_elem = neighbor_faces(global_face_number,1);
731 //DoubleTab vector_face_elem(dimension);
732 double inner_product=0;
733 for(int i=0; i<dimension; i++)
734 {
735 //ith component of the vector
736 double vec_face_elem = xp(neighbor_elem,i)-xv(global_face_number,i);
737 inner_product+=vec_face_elem*normal_vector(i);
738 }
739
740 if( inner_product > 0 )
741 {
742 for(int i=0; i<dimension; i++)
743 {
744 normal_vector(i)*=-1;
745 }
746 }
747
748 //now the normal vector is well oriented (outwards)
749 //we can multiply it by a given scale factor
750 for(int i=0; i<dimension; i++)
751 {
752 normal_vector(i)*=scale_factor;
753 }
754
755 return normal_vector;
756}
757
759{
760 Journal() << " Domaine_VF::marquer_faces_double_contrib" << finl;
761 // marking periodic faces
762 ////////////////////////////////////////////////
763
764 est_face_bord_=0; // init for inner faces.
765 for (auto& itr : conds_lim)
766 {
767 const Cond_lim_base& cl=itr.valeur();
768 int flag = sub_type(Periodique, cl) ? 2 : 1;
769 const Front_VF& le_bord = ref_cast(Front_VF, cl.frontiere_dis());
770 for (int ind_face = 0; ind_face < le_bord.nb_faces_tot(); ind_face++)
771 {
772 int num_face = le_bord.num_face(ind_face);
773 est_face_bord_[num_face]=flag;
774 }
775 }
776 for (auto& itr : conds_lim)
777 {
778 const Cond_lim_base& cl=itr.valeur();
779 if (sub_type(Periodique, cl))
780 {
781 const Periodique& la_cl_period = ref_cast(Periodique,cl);
782 const Front_VF& frontieredis = ref_cast(Front_VF,la_cl_period.frontiere_dis());
783 int ndeb = frontieredis.num_premiere_face();
784 int nfin = ndeb + frontieredis.nb_faces();
785 for (int face=ndeb; face<nfin; face++)
786 faces_doubles_[face]=1;
787 }
788 }
789
790 // marking shared item faces
791 ////////////////////////////////////////////////
792 int nbjoints=nb_joints();
793
794 for(int njoint=0; njoint<nbjoints; njoint++)
795 {
796 const Joint& joint_temp = joint(njoint);
797 const IntTab& indices_faces_joint = joint_temp.joint_item(JOINT_ITEM::FACE).renum_items_communs();
798 const int nbfaces = indices_faces_joint.dimension(0);
799 for (int j = 0; j < nbfaces; j++)
800 {
801 // To access joint faces, there is now a dedicated array renum_items_communs()
802 // because the old way of accessing these faces was through
803 // joint.num_premiere_face() and joint.nb_faces() which is no longer valid!
804 // Indeed, the numbering of joint faces is no longer contiguous!
805 // joint.num_premiere_face() now returns -1 to detect old code patterns.
806 int face_de_joint = indices_faces_joint(j, 1);
807 faces_doubles_[face_de_joint] = 1;
808 }
809 }
810}
811
813{
814 Cerr << "==============================================" << finl;
815 Cerr << "The boundary areas of the domain " << domaine().le_nom() << " are:" << finl;
816 DoubleVect surfaces;
817
818 // Raccords
819 Raccords& raccords=domaine().faces_raccord();
820 for (int i=0; i<raccords.nb_raccords(); i++)
821 {
822 Faces& faces=raccords(i)->faces();
823 faces.associer_domaine(domaine());
824 faces.calculer_surfaces(surfaces);
825 double s=0;
826 for (int j=0; j<faces.nb_faces(); j++)
827 s=s+surfaces(j);
828 s=mp_sum(s);
829 raccords(i)->set_aire(s);
830 Cerr<<"Area of "<<raccords(i)->le_nom()<<" \t= "<<s<<finl;
831 }
832
833 // Bords
834 Bords& bords=domaine().faces_bord();
835 for (int i=0; i<bords.nb_bords(); i++)
836 {
837 Faces& faces=bords(i).faces();
838 faces.associer_domaine(domaine());
839 faces.calculer_surfaces(surfaces);
840 double s=0;
841 for (int j=0; j<faces.nb_faces(); j++)
842 s=s+surfaces(j);
843 s=mp_sum(s);
844 bords(i).set_aire(s);
845 Cerr<<"Area of "<<bords(i).le_nom()<<" \t= "<<s<<finl;
846 }
847 Cerr << "==============================================" << finl;
848}
849
851{
852 const trustIdType nbelem = domaine().les_elems().get_md_vector()->nb_items_seq_tot();
853 const trustIdType nbsom = domaine().les_sommets().get_md_vector()->nb_items_seq_tot();
854 const trustIdType nbfaces = face_voisins().get_md_vector()->nb_items_seq_tot();
855 Cerr<<"Calculation of elements and nodes on " << domaine().le_nom() << " :" << finl;
856 Cerr<<"Total number of elements = "<<nbelem<<finl;
857 Cerr<<"Total number of nodes = "<<nbsom<<finl;
858 Cerr<<"Total number of faces = "<<nbfaces<<finl;
859 Raccords& raccords=domaine().faces_raccord();
860 for (int i=0; i<raccords.nb_raccords(); i++)
861 {
862 trustIdType nb_boundary_faces = mp_sum(ref_cast(Frontiere,raccords(i).valeur()).nb_faces());
863 Cerr<< nb_boundary_faces << " of them on boundary "<<raccords(i)->le_nom()<<finl;
864
865 }
866 Bords& bords=domaine().faces_bord();
867 for (int i=0; i<bords.nb_bords(); i++)
868 {
869 trustIdType nb_boundary_faces = mp_sum(ref_cast(Frontiere,bords(i)).nb_faces());
870 Cerr<< nb_boundary_faces << " of them on boundary "<<bords(i).le_nom()<<finl;
871 }
872 Cerr<<"=============================================="<<finl;
873 trustIdType internal_item = std::min(nbelem, nbfaces);
874 internal_item = std::min(internal_item, nbsom);
875 // premiere_face_int()*dimension+1 to avoid alerting on vector fluxes at boundary faces:
876 DeviceMemory::internal_items_size_ = std::max((trustIdType)(premiere_face_int()*dimension+1),internal_item);
877}
878
883
884void Domaine_VF::creer_tableau_aretes(Array_base& t, RESIZE_OPTIONS opt) const
885{
886 const MD_Vector& md = md_vector_aretes();
888}
889
890void Domaine_VF::creer_tableau_faces_bord(Array_base& t, RESIZE_OPTIONS opt) const
891{
892 const MD_Vector& md = md_vector_faces_bord();
894}
895
897{
898 Cerr << "Domaine_VF::remplir_face_numero_bord" << finl;
899 face_numero_bord_.resize(nb_faces());
900 face_numero_bord_=-1; // init for inner faces.
901 Domaine& ledomaine=domaine();
902 int ndeb, nfin;
903 const int nb_bords = ledomaine.nb_bords();
904 for (int n_bord=0; n_bord<nb_bords; n_bord++)
905 {
906 const Bord& le_bord = ledomaine.bord(n_bord);
907 ndeb = le_bord.num_premiere_face();
908 nfin = ndeb + le_bord.nb_faces();
909 for (int num_face=ndeb; num_face<nfin; num_face++)
910 face_numero_bord_[num_face] = n_bord;
911 }
912
913 const int nb_raccords = ledomaine.nb_raccords() ;
914 for (int n_racc=0; n_racc<nb_raccords; n_racc++)
915 {
916 const Raccord& le_racc = ledomaine.raccord(n_racc);
917 ndeb = le_racc -> num_premiere_face();
918 nfin = ndeb + le_racc -> nb_faces();
919 for (int num_face=ndeb; num_face<nfin; num_face++)
920 face_numero_bord_[num_face] = n_racc + nb_bords;
921 }
922}
923
924const DoubleTab& Domaine_VF::xv_bord() const
925{
926 if (xv_bord_.get_md_vector() == md_vector_faces_bord()) return xv_bord_; //already created
928 std::copy(xv_.addr(), xv_.addr() + dimension * premiere_face_int(), xv_bord_.addr()); //real faces: the beginning of xv_
929 xv_bord_.echange_espace_virtuel();
930 return xv_bord_;
931}
932
933/*! @brief Computes the xgr array for the computation of moments of forces at boundaries.
934 *
935 *
936 */
938{
939 const DoubleTab& xgrav = xv();
940 const ArrOfDouble& c_grav=domaine().cg_moments();
942 DoubleTab xgr(nb_faces, dimension);
943 for (int num_face=0; num_face <nb_faces; num_face++)
944 for (int i=0; i<dimension; i++)
945 xgr(num_face,i)=xgrav(num_face,i)-c_grav[i];
946 return xgr;
947}
948
949/** Build internal MEDCoupling cartesian mesh and correspondances
950 *
951 */
952void Domaine_VF::build_map_mc_Cmesh(const bool with_faces)
953{
954#ifdef MEDCOUPLING_
955
956 if (domaine().type_elem()->que_suis_je() != "Quadrangle" && domaine().type_elem()->que_suis_je() != "Rectangle"
957 && domaine().type_elem()->que_suis_je() != "Hexaedre")
958 {
959 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;
960 Cerr << "This option is only available for Quadrangle/Rectangle/Hexaedre types !!! Remove this interpret from your data file." << finl;
962 }
963
964 Cerr << finl;
965 Cerr << "###########################################" << finl;
966 Cerr << "@@@@@@@@ Building Structured infos @@@@@@@@" << finl;
967 Cerr << "###########################################" << finl;
968
969 /* Step 1. build mesh */
970 build_mc_Cmesh();
971
972 /* Step 2. build nodes correspondance : indx is i + nx * (j + ny * k) */
973 build_mc_Cmesh_nodesCorrespondence();
974
975 /* Step 2. build elem and face correspondance : indx is i + (nx - 1) * (j + (ny - 1) * k) */
976 build_mc_Cmesh_correspondence(with_faces);
977
978 mc_Cmesh_with_faces_corr_ = with_faces;
979 mc_Cmesh_ready_ = true;
980
981 Cerr << "##################################################" << finl;
982 Cerr << "@@@@@@@@ End of Building Structured infos @@@@@@@@" << finl;
983 Cerr << "##################################################" << finl;
984 Cerr << finl;
985
986#else
987 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;
989#endif
990}
991
992#ifdef MEDCOUPLING_
993
994/** Build internal MEDCoupling cartesian mesh for various postprocessings.
995 */
996void Domaine_VF::build_mc_Cmesh()
997{
998 using DAD = MCAuto<DataArrayDouble>;
999
1000 Cerr << "Domaine_VF::build_mc_Cmesh() ... " << finl;
1001 const auto& u_mesh = domaine().get_mc_mesh(); // will be built
1002 const auto& coords = u_mesh->getCoords();
1003 trustIdType nb_soms_tmp = coords->getNumberOfTuples(), nb_elems_tmp = u_mesh->getNumberOfCells();
1004
1005 const int nb_soms = Process::check_int_overflow(nb_soms_tmp);
1006 const int nb_elems = Process::check_int_overflow(nb_elems_tmp);
1007 const int mesh_dim = u_mesh->getMeshDimension();
1008
1009 Cerr << "Domaine_VF: Creating a MEDCouplingCMesh object for the domaine_VF '" << que_suis_je() << "' & the domaine '" << domaine().le_nom() << "' ..." << finl;
1010 mc_Cmesh_ = MEDCouplingCMesh::New("TRUST_CMesh");
1011
1012 const double eps = Objet_U::precision_geom;
1013 DAD coo[3], uniq[3];
1014 for (unsigned d=0; d < (unsigned)mesh_dim; d++)
1015 {
1016 coo[d] = coords->keepSelectedComponents({d});
1017 uniq[d] = coo[d]->getDifferentValues(eps);
1018 std::sort(uniq[d]->rwBegin(), uniq[d]->rwEnd());
1019 }
1020 mc_Cmesh_x_coords_.resize(uniq[0]->getNumberOfTuples());
1021 std::copy(uniq[0]->begin(), uniq[0]->end(),mc_Cmesh_x_coords_.begin());
1022 mc_Cmesh_y_coords_.resize(uniq[1]->getNumberOfTuples());
1023 std::copy(uniq[1]->begin(), uniq[1]->end(),mc_Cmesh_y_coords_.begin());
1024 if (mesh_dim>2)
1025 {
1026 mc_Cmesh_z_coords_.resize(uniq[2]->getNumberOfTuples());
1027 std::copy(uniq[2]->begin(), uniq[2]->end(),mc_Cmesh_z_coords_.begin());
1028 }
1029
1030 const int nx = (int)mc_Cmesh_x_coords_.size(), ny = (int)mc_Cmesh_y_coords_.size();
1031 const int nz = (mesh_dim > 2) ? (int)mc_Cmesh_z_coords_.size() : 1;
1032
1033 const int nb_som_cart = nx * ny * nz;
1034 const int nb_elem_cart = (mesh_dim > 2) ? (nx - 1) * (ny - 1) * (nz - 1) : (nx - 1) * (ny - 1);
1035
1036 if (nb_som_cart != nb_soms || nb_elem_cart != nb_elems)
1037 {
1038 Cerr << "Issue in converting the TRUST mesh to MEDCouplingCMesh ... It seems that the mesh is not an IJK-like mesh !!!" << finl;
1039 Cerr << "Nb soms : " << nb_soms << " for TRUST mesh vs " << nb_som_cart << " for the MEDCouplingCMesh" << finl;
1040 Cerr << "Nb elems : " << nb_elems << " for TRUST mesh vs " << nb_elem_cart << " for the MEDCouplingCMesh" << finl;
1041 Process::exit();
1042 }
1043
1044 Cerr << "Structured mesh dimensions (nodes) : " << nx << " x " << ny;
1045 if (mesh_dim > 2) Cerr << " x " << nz;
1046 Cerr << finl;
1047
1048 if (mesh_dim > 2)
1049 mc_Cmesh_->setCoords(uniq[0], uniq[1], uniq[2]);
1050 else
1051 mc_Cmesh_->setCoords(uniq[0], uniq[1]);
1052
1053 Cerr << "Domaine_VF::build_mc_Cmesh() ... OK !" << finl;
1054}
1055
1056/** Correspondance between TRUST_CMesh elements (and faces) and TRUST
1057 *
1058 */
1059void Domaine_VF::build_mc_Cmesh_correspondence(bool withFace)
1060{
1061 using DAI = MCAuto<DataArrayIdType>;
1062 using DAD = MCAuto<DataArrayDouble>;
1063
1064 Cerr << "Domaine_VF::build_mc_Cmesh_correspondence() building elem (and potentially face) correspondence ... " << finl;
1065
1066 // Temporary unstruct version of the CMesh to establish correspondences
1067 // The exact same numbering as in the original CMesh is preserved:
1068 MCAuto<MEDCouplingUMesh> mc_unstr = mc_Cmesh_->buildUnstructured();
1069 const MEDCouplingUMesh * mc_mesh = domaine().get_mc_mesh();
1070
1071 // Renumber nodes of mc_unstr to use original TRUST node indices:
1072 mc_unstr->setCoords(mc_mesh->getCoords());
1073 DAI renumb(DataArrayIdType::New());
1074 mcIdType n_nod = mc_unstr->getCoords()->getNumberOfTuples();
1075 renumb->alloc(n_nod);
1076 std::copy(mc_Cmesh_nodesCorrespondence_.data(),mc_Cmesh_nodesCorrespondence_.data()+n_nod, renumb->rwBegin());
1077
1078 mc_unstr->renumberNodesInConn(renumb->begin()); // only in connectivity
1079
1080 // Identify elements
1081 DataArrayIdType * mP;
1082 mc_unstr->areCellsIncludedIn(mc_mesh, 2, mP); // 2: same nodal connectivity
1083
1084 // Check that we have covered all cells exactly once:
1085 DAI outliers = mP->findIdsNotInRange(0, mc_unstr->getNumberOfCells());
1086 if (outliers->getNumberOfTuples() != 0)
1087 Process::exit("ERROR: Issue in converting the TRUST mesh to MEDCouplingCMesh ... It seems that the mesh is not an IJK-like mesh!!!");
1088
1089 mc_Cmesh_elemCorrespondence_.resize(mP->getNumberOfTuples());
1090 std::copy(mP->begin(), mP->end(), mc_Cmesh_elemCorrespondence_.data());
1091
1092// // Debug
1093// Cerr << "ELEM CORRESPONDANCE" << finl;
1094// int elem_idx = 0;
1095// for (const auto& cor: mc_Cmesh_elemCorrespondence_)
1096// Cerr << "Elem struct. " << elem_idx++ << " --> Elem non struct (original TRUST) " << cor << finl;
1097
1098 if (withFace)
1099 {
1100 int mesh_dim = mc_unstr->getMeshDimension();
1101 get_mc_face_mesh();
1102
1103 DAI desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
1104 MCAuto<MEDCouplingUMesh> mc_unstr_fac(mc_unstr->buildDescendingConnectivity(desc, descIndx, revDesc, revDescIndx));
1105 mcIdType nb_fac = mc_unstr_fac->getNumberOfCells();
1106
1107 DataArrayIdType * mapFac;
1108 mc_unstr_fac->areCellsIncludedIn(mc_face_mesh_, 2, mapFac); // 2: same nodal connectivity
1109
1110 DAD faceBary = mc_face_mesh_->computeCellCenterOfMass();
1111 const double * faceBaryP = faceBary->getConstPointer();
1112 DAI permu(DataArrayIdType::New());
1113 permu->alloc(nb_fac);
1114 permu->iota();
1115
1116 auto comp_func_2d = [&](const int& i1, const int& i2) -> bool
1117 {
1118 std::array<double, 2> tup1 = { faceBaryP[i1*2+1], faceBaryP[i1*2+0] }; // Y, X
1119 std::array<double, 2> tup2 = { faceBaryP[i2*2+1], faceBaryP[i2*2+0] };
1120 return tup1 < tup2; // use **reverse** lexicographic ordering natively given by std::array
1121 };
1122
1123 auto comp_func_3d = [&](const int& i1, const int& i2) -> bool
1124 {
1125 std::array<double, 3> tup1 = { faceBaryP[i1*3+2], faceBaryP[i1*3+1], faceBaryP[i1*3+0] }; // Z, Y, X
1126 std::array<double, 3> tup2 = { faceBaryP[i2*3+2], faceBaryP[i2*3+1], faceBaryP[i2*3+0] }; // Z, Y, X
1127 return tup1 < tup2; // use **reverse** lexicographic ordering natively given by std::array
1128 };
1129
1130 if (mesh_dim == 2)
1131 std::sort(permu->rwBegin(), permu->rwEnd(), comp_func_2d);
1132 else
1133 std::sort(permu->rwBegin(), permu->rwEnd(), comp_func_3d);
1134 for (mcIdType pp: *permu) // loop on face following lexicographic ordering
1135 {
1136 int p = static_cast<int>(pp);
1137 const int ori = orientation(p); // normal
1138 if (ori == 0) mc_Cmesh_facesXCorrespondence_.push_back(p);
1139 if (ori == 1) mc_Cmesh_facesYCorrespondence_.push_back(p);
1140 if (mesh_dim > 2 && ori == 2) mc_Cmesh_facesZCorrespondence_.push_back(p);
1141 }
1142
1143 Cerr << " - Built mc_Cmesh_facesXCorrespondence_ with size " << (int)mc_Cmesh_facesXCorrespondence_.size() << finl;
1144 Cerr << " - Built mc_Cmesh_facesYCorrespondence_ with size " << (int)mc_Cmesh_facesYCorrespondence_.size() << finl;
1145 if (mesh_dim > 2)
1146 Cerr << " - Built mc_Cmesh_facesZCorrespondence_ with size " << (int)mc_Cmesh_facesZCorrespondence_.size() << finl;
1147 }
1148 Cerr << "Domaine_VF::build_mc_Cmesh_correspondence() - done!" << finl;
1149}
1150
1151
1152// magic !
1153static int findCartIndex(const std::vector<double>& vect, const double value)
1154{
1155 if (value < vect.front() || value > vect.back())
1156 return -1; // not inside
1157
1158 auto it = std::lower_bound(vect.begin(), vect.end(), value);
1159
1160 if (it == vect.end())
1161 return -1; // not inside
1162
1163 int index = static_cast<int>(std::distance(vect.begin(), it));
1164
1165 if (index > 0 && value < vect[index])
1166 index--; // just before!!
1167
1168 return index;
1169}
1170
1171/** Correspondance between TRUST_CMesh nodes and TRUST
1172 */
1173void Domaine_VF::build_mc_Cmesh_nodesCorrespondence()
1174{
1175 Cerr << "Domaine_VF::build_mc_Cmesh_nodesCorrespondence() ... " << finl;
1176 const auto& u_mesh = domaine().get_mc_mesh();
1177 const double* coordsP = u_mesh->getCoords()->getConstPointer();
1178 const int space_dim = static_cast<int>(u_mesh->getCoords()->getNumberOfComponents());
1179 const int nb_soms = static_cast<int>(u_mesh->getNumberOfNodes());
1180 const int mesh_dim = u_mesh->getMeshDimension();
1181 const int nx = (int)mc_Cmesh_x_coords_.size(), ny = (int)mc_Cmesh_y_coords_.size();
1182
1183 mc_Cmesh_nodesCorrespondence_.resize(nb_soms, -1);
1184
1185 for (int node = 0; node < nb_soms; ++node)
1186 {
1187 int i = findCartIndex(mc_Cmesh_x_coords_, coordsP[node*space_dim + 0]);
1188 int j = findCartIndex(mc_Cmesh_y_coords_, coordsP[node*space_dim + 1]);
1189 int k = (mesh_dim > 2) ? findCartIndex(mc_Cmesh_z_coords_, coordsP[node*space_dim + 2]) : 0;
1190
1191 if (i == -1 || j == -1 || (mesh_dim > 2 && k == -1))
1192 {
1193 Cerr << "Node " << node << " not contained in the structured mesh !!!" << finl;
1194 Process::exit();
1195 }
1196
1197 const int ijk_idx = i + nx * (j + ny * k); // Indexing for structured mesh nodes
1198 mc_Cmesh_nodesCorrespondence_[ijk_idx] = node;
1199// Cerr << "Noeud non struct. " << node << " --> Noeud struct. " << ijk_idx << finl;
1200 }
1201 Cerr << "Domaine_VF::build_mc_Cmesh_nodesCorrespondence() ... OK !" << finl;
1202}
1203
1204#endif
1205
1206void Domaine_VF::get_position(DoubleTab& positions) const
1207{
1208 positions.resize(nb_elem(), xp_.dimension(1));
1209 CDoubleTabView xp = xp_.view_ro();
1210 DoubleTabView positions_v = positions.view_wo();
1211 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)
1212 {
1213 positions_v(i,j) = xp(i,j);
1214 });
1215 end_gpu_timer(__KERNEL_NAME__);
1216 // Don't work with simply: ToDo fix
1217 // positions = zvf.xp();
1218}
1219
1220double Domaine_VF::compute_L1_norm(const DoubleVect& val_source, const bool basis_function, const int order) const
1221{
1222 double sum = 0.;
1223 const int ne = nb_elem();
1224 for (int i=0; i<ne; i++)
1225 {
1226 sum+=std::fabs(val_source(i))*volumes(i);
1227 }
1228 return sum;
1229}
1230
1231double Domaine_VF::compute_L2_norm(const DoubleVect& val_source, const bool basis_function, const int order) const
1232{
1233 double sum = 0.;
1234 const int ne = nb_elem();
1235 for (int i=0; i<ne; i++)
1236 {
1237 sum+=val_source(i)*val_source(i)*volumes(i);
1238 }
1239 return sum;
1240}
1241
1242void Domaine_VF::compute_average(const DoubleVect& val_source, double& sum, double& volume, const bool basis_function, const int order) const
1243{
1244 const int ne = nb_elem();
1245 CDoubleArrView vol = volumes().view_ro();
1246 CDoubleArrView val = val_source.view_ro();
1247 Kokkos::parallel_reduce(start_gpu_timer(__KERNEL_NAME__), ne, KOKKOS_LAMBDA(const int i, double & sum_tmp, double & volume_tmp)
1248 {
1249 double v = vol(i);
1250 sum_tmp += val(i) * v;
1251 volume_tmp += v;
1252 }, sum, volume);
1253 end_gpu_timer(__KERNEL_NAME__);
1254}
1255
1256void Domaine_VF::compute_average_porosity(const DoubleVect& val_source, const DoubleVect& porosity, double& sum, double& volume, const bool basis_function, const int order) const
1257{
1258 const int ne = nb_elem();
1259 CDoubleArrView vol = volumes().view_ro();
1260 CDoubleArrView poro = porosity.view_ro();
1261 CDoubleArrView val = val_source.view_ro();
1262 Kokkos::parallel_reduce(start_gpu_timer(__KERNEL_NAME__), ne, KOKKOS_LAMBDA(const int i, double & sum_tmp, double & volume_tmp)
1263 {
1264 double v = vol(i);
1265 double p = poro(i);
1266 sum_tmp += val(i) * v * p;
1267 volume_tmp += v * p;
1268 }, sum, volume);
1269 end_gpu_timer(__KERNEL_NAME__);
1270}
1271
1273{
1274 Process::exit("The function should not be used in domaine_VF, related to quadrature points (DG discretization)");
1275 //overridden in domaine_DG but not present in kernel
1276}
1277
1279{
1280 Process::exit("The function should not be used in domaine_VF, related to quadrature points (DG discretization)");
1281 //overridden in domaine_DG but not present in kernel
1282}
1283
1285{
1286 Process::exit("The function should not be used in domaine_VF, related to quadrature points (DG discretization)");
1287 return 0;
1288 //overridden in domaine_DG but not present in kernel
1289}
1290
1291#ifdef TRUST_USE_ARBORX
1292// Callback to store the result indices
1293struct ExtractIndex
1294{
1295 template <typename Query, typename Value, typename Output>
1296 KOKKOS_FUNCTION void operator()(Query const&, Value const& value, Output const& out) const
1297 {
1298 out(value.index);
1299 }
1300};
1301#endif
1302
1303/*! @brief Method inspired by Raccord_distant_homogene::initialise
1304 */
1306{
1307 if(dist_paroi_initialisee_) return;
1308 Cerr << "Domaine_VF::init_dist_paroi_globale..." << finl;
1309
1310 const Domaine_VF& domaine_ = *this;
1311 int D=Objet_U::dimension, nf = domaine_.nb_faces(), ne = domaine_.nb_elem();
1312 const IntTab& f_s = face_sommets();
1313 const DoubleTab& xs = domaine_.domaine().coord_sommets();
1314
1315 // Initialize the tables y_faces_ and y_elem_
1316 domaine_.creer_tableau_faces(y_faces_);
1318
1319 n_y_elem_.resize(0,D);
1320 n_y_faces_.resize(0,D);
1321
1324
1325 // Identify faces by their centres of gravity
1326 int parts = Process::nproc();
1327 int moi = Process::me();
1328 DoubleTabs remote_xv(parts);
1329
1330 // Initialize the local boundary face/vertex/edge table, create a local vertex table and count the edges
1331 int nb_faces_bord_ = 0;
1332 int nb_aretes = 0;
1333 std::set<int> soms;
1334 for (auto& itr : conds_lim)
1335 if ( sub_type(Dirichlet_paroi_defilante, itr.valeur()) || sub_type(Dirichlet_homogene, itr.valeur()) ||
1336 (sub_type(Navier, itr.valeur()) && !sub_type(Symetrie, itr.valeur()) ) || sub_type(Dirichlet_loi_paroi, itr.valeur()))
1337 {
1338 int num_face_1_cl = itr->frontiere_dis().frontiere().num_premiere_face();
1339 int nb_faces_cl = itr->frontiere_dis().frontiere().nb_faces();
1340
1341 nb_faces_bord_ += itr->frontiere_dis().frontiere().nb_faces();
1342
1343 for (int f=num_face_1_cl ; f < nb_faces_cl+num_face_1_cl ; f++)
1344 {
1345 int nb_som_loc = 0;
1346 while ( (nb_som_loc < nb_som_face()) && (f_s(f, nb_som_loc) != -1))
1347 {
1348 soms.insert(f_s(f, nb_som_loc));
1349 nb_som_loc++;
1350 }
1351 nb_aretes += (D == 3 ? nb_som_loc : 0) ; // As many edges around a face as there are vertices!
1352 }
1353 }
1354
1355 if (Process::mp_max(nb_faces_bord_) == 0) /* test all procs */
1356 Process::exit(que_suis_je() + " : at least one boundary must be solid for the distance to the edge to be calculated !!!");
1357
1358 remote_xv[moi].resize(nb_faces_bord_ + (int)soms.size() + nb_aretes,D);
1359 int index[5] = { -1, -1, -1, -1, -1 };
1360 bool Z_numbered = que_suis_je() == "Domaine_VDF" && dimension==3;
1361 if (Z_numbered) // Z-numbering of vertices in a face...
1362 {
1363 index[0] = 0;
1364 index[1] = 1;
1365 index[2] = 3;
1366 index[3] = 2;
1367 index[4] = 0;
1368 }
1369 // Fill in the coordinates of local boundary faces and edges
1370 int ind_tab = 0 ; // index of the face/vertex/edge in the array
1371 for (int ind_cl = 0 ; ind_cl < conds_lim.size() ; ind_cl++)
1372 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()) ) )
1373 {
1374 int num_face_1_cl = conds_lim[ind_cl]->frontiere_dis().frontiere().num_premiere_face();
1375 int nb_faces_cl = conds_lim[ind_cl]->frontiere_dis().frontiere().nb_faces();
1376
1377 for (int f=num_face_1_cl ; f < nb_faces_cl+num_face_1_cl ; f++)
1378 {
1379 for (int d=0 ; d<D ; d++)
1380 remote_xv[moi](ind_tab,d) = domaine_.xv(f, d); // Fill in face coordinates
1381 ind_tab++;
1382
1383 if (D==3) // Fill in edge coordinates
1384 {
1385 if (Z_numbered) // Z-numbering of vertices within a face...
1386 {
1387 for (int id_som=1; id_som<=nb_som_face(); id_som++)
1388 {
1389 for (int d = 0; d < D; d++)
1390 remote_xv[moi](ind_tab, d) =
1391 (xs(f_s(f, index[id_som]), d) + xs(f_s(f, index[id_som - 1]), d)) / 2;
1392 ind_tab++;
1393 }
1394 }
1395 else
1396 {
1397 int id_som = 1;
1398 while ((id_som < nb_som_face()) && (f_s(f, id_som) != -1))
1399 {
1400 for (int d = 0; d < D; d++)
1401 remote_xv[moi](ind_tab, d) = (xs(f_s(f, id_som), d) + xs(f_s(f, id_som - 1), d)) / 2;
1402 id_som++;
1403 ind_tab++;
1404 }
1405 for (int d = 0; d < D; d++)
1406 remote_xv[moi](ind_tab, d) = (xs(f_s(f, 0), d) + xs(f_s(f, id_som - 1), d)) / 2;
1407 ind_tab++;
1408 }
1409 }
1410 }
1411 }
1412
1413 for (auto som:soms) // Fill in vertex coordinates
1414 {
1415 for (int d=0 ; d<D ; d++)
1416 remote_xv[moi](ind_tab,d) = xs(som, d);
1417 ind_tab++;
1418 }
1419
1420
1421 // Exchange the arrays of centres of gravity
1422 // broadcast the arrays
1423 Cerr << "[MPI] Broadcasting remote_xv..." << finl;
1424 for (int p = 0; p < parts; p++)
1425 envoyer_broadcast(remote_xv[p], p);
1426
1427 int nb_total_points=0;
1428 for (int p = 0; p < parts; p++)
1429 nb_total_points+=remote_xv[p].dimension(0);
1430
1431 Cerr << "Number of boundary points: " << nb_total_points << finl;
1432 double GBytes = nb_total_points * 4.0 /* float */ * D / 1024.0 / 1024.0 / 1024.0;
1433 Cerr << "Estimated memory needed: " << GBytes << " GB" << finl;
1434
1435 // Process the information; each proc knows all the XV
1436
1437// Loop over all faces then all elements
1438 const DoubleTab& local_xv = domaine_.xv();
1439 const DoubleTab& local_xp = domaine_.xp();
1440 ArrOfInt glob_idx(Process::check_int_overflow(nf+ne));
1441#ifdef TRUST_USE_ARBORX
1442 // Use ArborX on GPU to compute the nearest points cause too slow on large meshes
1443 int dim = dimension;
1444 using ExecutionSpace = Kokkos::DefaultExecutionSpace;
1445 using MemorySpace = ExecutionSpace::memory_space;
1446 using Point = ArborX::Point<3>;
1447 ExecutionSpace space;
1448 Kokkos::View<Point *, MemorySpace> query_points("local_xs", nf + ne);
1449 CDoubleTabView xv = local_xv.view_ro();
1450 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nf, KOKKOS_LAMBDA(
1451 const int i)
1452 {
1453 query_points[i] = {(float) xv(i, 0), (float) xv(i, 1), dim == 3 ? (float) xv(i, 2) : 0.f};
1454 });
1455 end_gpu_timer(__KERNEL_NAME__);
1456 CDoubleTabView xp = local_xp.view_ro();
1457 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), ne, KOKKOS_LAMBDA(
1458 const int i)
1459 {
1460 query_points[nf + i] = {(float) xp(i, 0), (float) xp(i, 1), dim == 3 ? (float) xp(i, 2) : 0.f};
1461 });
1462 end_gpu_timer(__KERNEL_NAME__);
1463 // One BVH per batch of parts (slower but less memory expensive than single BVH)
1464 ArrOfDouble distances(nf+ne);
1465 distances=DMAXFLOAT;
1466 // Define batch_size (parts per batch) to not use more than 1GB per batch
1467 double target_GB = 1.0;
1468 int num_batches = std::max(1, (int)std::ceil(GBytes / target_GB));
1469 int batch_size = std::max(1, (parts + num_batches - 1) / num_batches); // ceil(parts / num_batches)
1470 Cerr << "Number of batches: " << num_batches << ", parts per batch: " << batch_size
1471 << ", points per batch: ~" << nb_total_points / num_batches << finl;
1472 for (int batch_start = 0; batch_start < parts; batch_start += batch_size)
1473 {
1474 int batch_end = std::min(batch_start + batch_size, parts);
1475
1476 // Compute total number of points in this batch
1477 int nb_points = 0;
1478 for (int part = batch_start; part < batch_end; part++)
1479 nb_points += remote_xv[part].dimension(0);
1480 if (nb_points == 0) continue;
1481
1482 // Fill points view with all parts in this batch
1483 Kokkos::View<Point *, MemorySpace> points("remote_xv", nb_points);
1484 int point_offset = 0;
1485 for (int part = batch_start; part < batch_end; part++)
1486 {
1487 int size = remote_xv[part].dimension(0);
1488 if (size > 0)
1489 {
1490 CDoubleTabView coord = remote_xv[part].view_ro();
1491 int local_offset = point_offset; // Capture for lambda
1492 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), size, KOKKOS_LAMBDA(const int i)
1493 {
1494 points[local_offset + i] = {(float) coord(i, 0), (float) coord(i, 1),
1495 dim == 3 ? (float) coord(i, 2) : 0.f
1496 };
1497 });
1498 end_gpu_timer(__KERNEL_NAME__);
1499 }
1500 point_offset += size;
1501 }
1502
1503 // BVH
1504 Cerr << "ArborX::BoundingVolumeHierarchy for parts " << batch_start << " to " << batch_end - 1;
1505 ArborX::BoundingVolumeHierarchy bvh(space, ArborX::Experimental::attach_indices(points));
1506 Cerr << " created!" << finl;
1507 Kokkos::View<int *, MemorySpace> offsets("Example::offsets", 0);
1508 Kokkos::View<int *, MemorySpace> indices("Example::indices", 0);
1509 Cerr << "ArborX query...";
1510 bvh.query(space, ArborX::Experimental::make_nearest(query_points, 1), ExtractIndex {}, indices, offsets);
1511 Cerr << " completed!" << finl;
1512 // Compute global offset to the start of this batch
1513 int global_offset = 0;
1514 for (int pp = 0; pp < batch_start; pp++)
1515 global_offset += remote_xv[pp].dimension(0);
1516
1517 // GPU kernel: compute distances and update best matches
1518 // Use points[ar] directly (already on device) instead of remote_xv[part](ar_local, i)
1519 DoubleArrView dist = static_cast<ArrOfDouble&>(distances).view_rw();
1520 IntArrView glob = static_cast<ArrOfInt&>(glob_idx).view_rw();
1521 int total_fe = nf + ne;
1522 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), total_fe, KOKKOS_LAMBDA(const int fe)
1523 {
1524 int ar = indices(fe);
1525 float d = 0;
1526 for (int i = 0; i < dim; i++)
1527 {
1528 float diff = query_points(fe)[i] - points(ar)[i];
1529 d += diff * diff;
1530 }
1531 if (d < dist(fe))
1532 {
1533 dist(fe) = (double)d;
1534 glob(fe) = ar + global_offset;
1535 }
1536 });
1537 end_gpu_timer(__KERNEL_NAME__);
1538 }
1539#else
1540 // MedCoupling implementation (C++14, soon deprecated):
1541 //indices of the remote_xvs points closest to each point of local_xv
1542 MCAuto <DataArrayIdType> glob(DataArrayIdType::New());
1543 //DataArrayDoubles of the local xv and all remote_xv (concatenated)
1544 std::vector<MCAuto<DataArrayDouble> > vxv(parts);
1545 std::vector<const DataArrayDouble*> cvxv(parts);
1546 MCAuto<DataArrayDouble> remote_xvs(DataArrayDouble::New());
1547 for (int p = 0; p < parts; p++)
1548 {
1549 vxv[p] = DataArrayDouble::New();
1550 vxv[p]->useExternalArrayWithRWAccess(remote_xv[p].addr(), remote_xv[p].dimension(0), remote_xv[p].dimension(1));
1551 cvxv[p] = vxv[p];
1552 }
1553 remote_xvs = DataArrayDouble::Aggregate(cvxv);
1554 MCAuto<DataArrayDouble> local_xs(DataArrayDouble::New());
1555 local_xs->alloc(nf+ne, D);
1556 for (int f = 0; f < nf; f++)
1557 for (int d = 0; d < D; d++)
1558 local_xs->setIJ(f, d, local_xv(f, d));
1559 for (int e = 0; e < ne; e++)
1560 for (int d = 0; d < D; d++)
1561 local_xs->setIJ(nf+e, d, local_xp(e, d));
1562 glob = remote_xvs->findClosestTupleId(local_xs);
1563 for (int i=0; i<nf+ne; i++)
1564 glob_idx(i) = (int)glob->getIJ(i,0);
1565#endif
1566
1567 ToDo_Kokkos("critical");
1568//for each element and face in local_xs: fill in the arrays
1569 for (int fe = 0; fe<nf+ne; fe++)
1570 {
1571 //convert global index (glob_idx(ind_face)) to the pair (proc, ind_face2)
1572 int proc = 0;
1573 int fe2 = glob_idx(fe);
1574 while (fe2 >= remote_xv[proc].dimension(0))
1575 {
1576 fe2 -= remote_xv[proc].dimension(0);
1577 proc++;
1578 }
1579 double distance2 = 0;
1580 for (int d=0; d<D; d++)
1581 {
1582 double x1 = 0 ;
1583 if (fe<nf) x1=local_xv(fe,d);
1584 else if (fe<nf+ne) x1=local_xp(fe-nf,d);
1585 else { Cerr<<"Domaine_VF::init_dist_paroi_globale : problem in the ditance to the edge calculation. Contact TRUST support."<<finl; Process::exit();}
1586 double x2=remote_xv[proc](fe2,d);
1587 distance2 += (x1-x2)*(x1-x2);
1588 }
1589 if (fe<nf)
1590 {
1591 y_faces_(fe) = std::sqrt(distance2);
1593 for (int d = 0 ; d<D ; d++)
1594 n_y_faces_(fe, d) = ( local_xv(fe,d)-remote_xv[proc](fe2,d) )/ y_faces_(fe);
1595 }
1596 else
1597 {
1598 y_elem_(fe-nf) = std::sqrt(distance2);
1599 for (int d = 0 ; d<D ; d++)
1600 n_y_elem_(fe-nf, d) = ( local_xp(fe-nf,d)-remote_xv[proc](fe2,d) )/ y_elem_(fe-nf);
1601 }
1602 }
1603
1604// For boundary elements, compute the distance properly using the dot product
1605 for (int ind_cl = 0 ; ind_cl < conds_lim.size() ; ind_cl++)
1606 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()) ))
1607 {
1608 int num_face_1_cl = conds_lim[ind_cl]->frontiere_dis().frontiere().num_premiere_face();
1609 int nb_faces_cl = conds_lim[ind_cl]->frontiere_dis().frontiere().nb_faces();
1610
1611 for (int f=num_face_1_cl ; f < nb_faces_cl+num_face_1_cl ; f++)
1612 {
1613 const int ind = (face_voisins(f,0)>=0) ? face_voisins(f,0) : face_voisins(f,1) ;
1614 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));
1615 if ( dist_ef_loc < y_elem_(ind) ) // Handle the case where the element has multiple boundary faces
1616 {
1617 y_elem_(ind) = dist_ef_loc ;
1618 for (int d = 0 ; d < D ; d++)
1619 n_y_elem_(ind, d) = -face_normales(f, d)/face_surfaces(f);
1620 }
1621 for (int d = 0 ; d<D ; d++)
1622 n_y_faces_(f, d) = -face_normales(f, d)/face_surfaces(f); // Coherent normal vector for border faces
1623 }
1624 }
1625
1626 n_y_faces_.echange_espace_virtuel();
1627 n_y_elem_.echange_espace_virtuel();
1628 y_faces_.echange_espace_virtuel();
1629 y_elem_.echange_espace_virtuel();
1631 Cerr << "Initialize the y table " << domaine_.domaine().le_nom() << finl;
1632}
1633
1634/*! @brief Build the MEDCoupling **face** mesh.
1635 * It is always made of polygons (in 3D) for simplicity purposes.
1636 * Face numbers (and node numbers) are the same as in TRUST.
1637 *
1638 * It unfortunately needs a Domaine_dis_base since this is at this level that the face_sommets relationship is held ...
1639 * As a consequence also the faces of a Domaine can not be postprocessed before discretisation.
1640 * Another consequence is that it is not available for 64 bits domains.
1641 */
1643{
1644#ifdef MEDCOUPLING_
1645 using MEDCoupling::DataArrayIdType;
1646 using MEDCoupling::DataArrayDouble;
1647
1648 using DAId = MCAuto<DataArrayIdType>;
1649
1650 const MEDCouplingUMesh* mc_mesh = domaine().get_mc_mesh();
1651
1652 // Build descending connectivity and convert it to polygons
1653 DAId desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
1654 mc_face_mesh_ = mc_mesh->buildDescendingConnectivity(desc, descIndx, revDesc, revDescIndx);
1655 if (Objet_U::dimension == 3) mc_face_mesh_->convertAllToPoly();
1656
1657 // Build second temporary mesh (with shared nodes!) having the TRUST connectivity
1658 MCAuto<MEDCouplingUMesh> faces_tmp = mc_face_mesh_->deepCopyConnectivityOnly();
1659 const IntTab& faces_sommets = face_sommets();
1660 int nb_fac = faces_sommets.dimension(0);
1661 int max_som_fac = faces_sommets.dimension_int(1);
1662 assert((int)mc_face_mesh_->getNumberOfCells() == nb_fac);
1663 DAId c(DataArrayIdType::New()), cI(DataArrayIdType::New());
1664 c->alloc(0,1);
1665 cI->alloc(nb_fac+1, 1);
1666 mcIdType *cIP = cI->getPointer();
1667 cIP[0] = 0; // better not forget this ...
1668 mcIdType typ = Objet_U::dimension == 3 ? INTERP_KERNEL::NormalizedCellType::NORM_POLYGON : INTERP_KERNEL::NormalizedCellType::NORM_SEG2;
1669
1670 for (int fac=0; fac<nb_fac; fac++) // Fills the two MC arrays c and cI describing the connectivity of the face mesh
1671 {
1672 c->pushBackSilent(typ);
1673 int i=0, s=-1;
1674 for (; i < max_som_fac && (s = faces_sommets(fac, i)) >= 0; i++)
1675 c->pushBackSilent(s);
1676 cIP[fac+1] = cIP[fac] + i + 1; // +1 because of type
1677 }
1678 faces_tmp->setConnectivity(c, cI);
1679
1680 // Then we can simply identify cells by their nodal connectivity:
1681 DataArrayIdType * mP;
1682 mc_face_mesh_->areCellsIncludedIn(faces_tmp,2, mP); // 2: same nodal connectivity
1683 // DAId renum(mP); //useful to automatically free memory allocated in mP
1684 DAId renum2(mP->invertArrayN2O2O2N(nb_fac));
1685#ifndef NDEBUG
1686 // All cells should be found:
1687 DAId outliers = renum2->findIdsNotInRange(0, nb_fac);
1688 if (outliers->getNumberOfTuples() != 0)
1689 Process::exit("Invalid renumbering arrays! Should not happen. Some faces could not be matched between the TRUST face domain and the buildDescendingConnectivity() version.");
1690#endif
1691
1692#ifdef NDEBUG
1693 bool check = false;
1694#else
1695 bool check = true;
1696#endif
1697 // Apply the renumbering so that final mc_face_mesh_ has the same face number as in TRUST
1698 mc_face_mesh_->renumberCells(renum2->begin(), check);
1699#ifndef NDEBUG
1700 mc_face_mesh_->checkConsistency();
1701#endif
1702 mP->decrRef();
1703
1704 mc_face_mesh_ready_ = true;
1705#endif // MEDCOUPLING_
1706}
1707
1708/** @brief Build the dual mesh of the domain for post-processing of face fields.
1709 *
1710 * For each face of each element, a polyhedron is built with faces being made of
1711 * - the original face
1712 * - triangles buit with the element center of mass and each of the segment of the original face
1713 * Thus an inner face of the domain has two associated dual polyhedral elements, and a boundary
1714 * face has only one associated dual element.
1715 * The member face_dual_ is also completed and has the same logic and exact same ordering as face_voisins_.
1716 */
1718{
1719#ifdef MEDCOUPLING_
1720 using DAId = MCAuto<DataArrayIdType>;
1721 using DAD = MCAuto<DataArrayDouble>;
1722
1723 const MEDCouplingUMesh* mc_face_mesh = get_mc_face_mesh();
1724 const int dim = Objet_U::dimension;
1725
1726 Cerr << " Domaine: Creating **dual** mesh as a MEDCouplingUMesh object for the domain '" << le_nom() << "'" << finl;
1727
1728 // Fills in connectivity for the dual mesh, and correspondance array 'face_dual_'
1729 int nb_fac = Process::check_int_overflow(mc_face_mesh->getNumberOfCells());
1730 int nb_elem = domaine().nb_elem(); // real only
1731 int nb_coo = domaine().nb_som();
1732 const mcIdType *fc = mc_face_mesh->getNodalConnectivity()->getConstPointer(),
1733 *fcI= mc_face_mesh->getNodalConnectivityIndex()->getConstPointer();
1734 // Init face_dual_
1735 face_dual_.resize(nb_fac, 2);
1736 face_dual_=-1;
1737 // Prepare raw MC connectivity of the dual mesh:
1738 DAId c(DataArrayIdType::New()), cI(DataArrayIdType::New());
1739 cI->alloc(nb_fac*2, 1); // Conservative pre-allocation (too large because of bound faces)
1740 c->alloc(0,1);
1741 mcIdType *cIP = cI->getPointer();
1742 cIP[0] = 0; // better not forget this ...
1743 int gi = 0; // global index of dual elements created
1744
1745 auto corrige_voisins_dual_perio = [&](int f, int &e1, int &e2)
1746 {
1747 assert (est_face_bord_[f] == 2);
1748 auto d2 = [&](int e) -> double
1749 {
1750 double s = 0.;
1751 for (int d = 0; d < dim; d++)
1752 {
1753 double dx = xp_(e, d) - xv_(f, d);
1754 s += dx * dx;
1755 }
1756 return s;
1757 };
1758
1759 if (e1 >= 0 && e2 >= 0)
1760 {
1761 // Keep only the element truly adjacent to the geometric face
1762 if (d2(e1) <= d2(e2)) e2 = -1;
1763 else e1 = -1;
1764 }
1765 };
1766
1767 // Precompute needed size:
1768 mcIdType totSz = 0;
1769 for(int f=0; f<nb_fac; f++) // For all the (real) faces
1770 {
1771 int e1=face_voisins_(f, 0), e2=face_voisins_(f, 1);
1772
1773 // XXX Elie Saikali : periodic face: treat it as a geometric boundary face ...
1774 if (est_face_bord_[f] == 2)
1775 corrige_voisins_dual_perio(f, e1, e2);
1776
1777 for (int e: {e1, e2})
1778 {
1779 if (e==-1 || e >= nb_elem) continue; // skip boundary or virtual
1780 if (dim == 2) // easy, just triangles to build
1781 totSz += 3 + 1; // will add a triangle = 1 (type) + 3 sommets
1782 else // 3D
1783 {
1784 mcIdType nb_pts = fcI[f+1]-fcI[f]-1; // nb of points in face f (-1 to skip type)
1785
1786 // Increase size of c to fit for the next poyhedron to be inserted:
1787 // +1 : for the type POLYHED
1788 // nb_pts : original face
1789 // nb_pts*(3+1) : nb_pts triangular lateral faces (3 sommets + separateur -1)
1790 totSz += 1 // type
1791 + nb_pts // original face
1792 + nb_pts*(3+1); // lateral faces
1793 }
1794 }
1795 }
1796
1797 c->reAlloc(totSz); // done only once ! otherwise very costly
1798 mcIdType *cP = c->getPointer();
1799 mcIdType c_sz = 0;
1800
1801 for(int f=0; f<nb_fac; f++) // For all the (real) faces
1802 {
1803 int e1 = face_voisins_(f, 0), e2 = face_voisins_(f, 1);
1804
1805 // XXX Elie Saikali : periodic face: treat it as a geometric boundary face ...
1806 if (est_face_bord_[f] == 2)
1807 corrige_voisins_dual_perio(f, e1, e2);
1808
1809 for (int e: {e1, e2})
1810 {
1811 if (e==-1 || e >= nb_elem) continue; // skip boundary or virtual
1812 if (dim == 2) // easy, just triangles to build
1813 {
1814 cP[c_sz++] = INTERP_KERNEL::NormalizedCellType::NORM_TRI3;
1815 // Triangle connectivity:
1816 const mcIdType *p = fc + fcI[f] + 1;
1817 cP[c_sz++] = *p;
1818 cP[c_sz++] = *(p+1);
1819 cP[c_sz++] = e+nb_coo; // index of the barycenter in the final coord array
1820 }
1821 else // 3D
1822 {
1823 mcIdType nb_pts = fcI[f+1]-fcI[f]-1; // nb of points in face f (-1 to skip type)
1824 cP[c_sz++] = INTERP_KERNEL::NormalizedCellType::NORM_POLYHED;
1825
1826 // 1) Add the face itself: (original face)
1827 for(const mcIdType *p = fc + fcI[f] + 1; p < fc+fcI[f + 1]; p++)
1828 cP[c_sz++] = *p;
1829
1830 // 2) Add the new triangular lateral faces containing the barycenter:
1831 const mcIdType *p2 = fc + fcI[f] + 1;
1832 for (mcIdType i = 0; i<nb_pts; i++) // loop on all segs of the face - in 2D this will loop once only
1833 {
1834 cP[c_sz++] = -1; // -1 to separate from the prev face in the polyhedron
1835 cP[c_sz++] = e+nb_coo; // index of the barycenter in the final coord array
1836 cP[c_sz++] = *(p2+i);
1837 cP[c_sz++] = *(p2+(i+1)%nb_pts);
1838 }
1839 }
1840 cIP[gi+1] = c_sz;
1841 face_dual_(f, e==e1 ? 0:1) = gi;
1842 gi++; // next dual element
1843 }
1844 }
1845 assert(c_sz == totSz); // check the awful size computation from above ...
1846
1847 // Strip cI that might be too big - surely a down-sizing
1848 cI->reAlloc(gi+1);
1849 // Prepare final coords - no choice here (sticking coords and xp_ together on TRUST side is a bad idea because of virtuals)
1850 // TODO - save/use coords for other (primal) meshes too
1851 DAD coo2 = mc_face_mesh->getCoords()->deepCopy();
1852 coo2->reAlloc(nb_coo+nb_elem);
1853 std::copy(xp_.addr(), xp_.addr() + nb_elem*dim, coo2->getPointer()+nb_coo*dim);
1854
1855 const std::string dual_nam = domaine().get_mc_mesh()->getName() + "_dual";
1856 mc_dual_mesh_ = MEDCouplingUMesh::New(dual_nam, dim);
1857 mc_dual_mesh_->setCoords(coo2);
1858 mc_dual_mesh_->setConnectivity(c,cI);
1859 mc_dual_mesh_ready_ = true;
1860
1861#ifndef NDEBUG
1862 /*
1863 * Final testing : Only in debug mode
1864 *
1865 * - nb_faces_bords does not change between primal (TRUST) mesh and dual mesh
1866 * - nb_faces per polyedron has at least 4 faces (case of tetra) : Only 3D !
1867 */
1868 MCAuto<MEDCouplingUMesh> skin_dual = mc_dual_mesh_->computeSkin();
1869 mcIdType nb_faces_bd = skin_dual->getNumberOfCells();
1870
1871 if (nb_faces_bd != (domaine().nb_faces_bord() + domaine().nb_faces_joint()))
1872 Process::exit("Something wrong with dual mesh computation #1 -- boundary faces !!!! \n");
1873
1874 if (Objet_U::dimension == 3) /* Only polyhedron case !*/
1875 {
1876 DAId desc(DataArrayIdType::New()), descIndx(DataArrayIdType::New()), revDesc(DataArrayIdType::New()), revDescIndx(DataArrayIdType::New());
1877 mc_dual_mesh_->buildDescendingConnectivity(desc, descIndx, revDesc, revDescIndx);
1878
1879 DAId dsi = descIndx->deltaShiftIndex();
1880 DAId res = dsi->findIdsLowerOrEqualTo(3) ;
1881 if (res->getNumberOfTuples() > 0)
1882 Process::exit("Something wrong with dual mesh computation #2 -- polyhedron faces !!!! \n");
1883 }
1884#endif
1885
1886#endif // MEDCOUPLING_
1887}
Empty class used as a base for all the arrays.
Definition Array_base.h:41
int nb_bords() const
Definition Bords.h:39
class Cond_lim_base Base class for the hierarchy of classes that represent the different boundary con...
virtual Frontiere_dis_base & frontiere_dis()
Returns the discretized boundary to which the boundary conditions apply.
class Conds_lim This class represents a vector of boundary conditions.
Definition Conds_lim.h:32
Classe Dirichlet_homogene This class is the base class of the hierarchy of homogeneous Dirichlet-type...
Classe Dirichlet_loi_paroi Base class for imposed values in a boundary condition of the turbulence eq...
Dirichlet_paroi_defilante Imposes the wall velocity in an equation of type Navier_Stokes.
void calculer_mon_centre_de_gravite(ArrOfDouble &c)
Computes the center of gravity of the domain.
Definition Domaine.cpp:735
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
Creates a parallel array of values at elements.
Definition Domaine.cpp:850
void creer_mes_domaines_frontieres(const Domaine_VF &domaine_vf)
Definition Domaine.cpp:2172
Raccord_t & raccord(int i)
Definition Domaine.h:248
void calculer_centres_gravite(DoubleTab_t &xp) const
Calculates the centers of gravity of the domain elements.
Definition Domaine.h:503
int_t nb_faces_frontiere() const
Returns the number of boundary faces of the domain (sum of boundaries, connections,...
Definition Domaine.h:488
virtual void calculer_volumes(DoubleVect_t &volumes, DoubleVect_t &inv_volumes) const
Computes the volumes of the domain elements.
Definition Domaine.cpp:763
void init_faces_virt_bord(const MD_Vector &md_vect_faces, MD_Vector &md_vect_faces_bord)
Definition Domaine.cpp:1904
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
Returns the total number of vertices of the domain i.e. the number of real and virtual vertices on th...
Definition Domaine.h:123
int_t nb_som() const
Returns the number of vertices of the domain.
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:1183
int nb_raccords() const
Definition Domaine.h:247
class Domaine_Cl_dis_base Domaine_Cl_dis_base objects represent discretized boundary conditions
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
Returns the total number of 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
Returns the face/vertex connectivity array.
Definition Domaine_VF.h:590
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
Method inspired by Raccord_distant_homogene::initialise.
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
Returns the total number of faces.
Definition Domaine_VF.h:481
virtual Faces * creer_faces()
Returns new(Faces)! It is overridden by Domaine_VDF for example.
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
Generates the faces and builds the boundaries.
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()
Fills in the face_virt_pe_num_ array (see comment in Domaine_VF.h).
IntTab & elem_faces()
Returns the element/face connectivity array.
Definition Domaine_VF.h:550
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
Returns the number of vertices per face.
Definition Domaine_VF.h:493
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:645
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
Computes the xgr array for the computation of moments of forces at boundaries.
int premiere_face_int() const
A face is internal if and only if it separates two elements.
Definition Domaine_VF.h:463
DoubleTab & xp()
Definition Domaine_VF.h:95
int nb_faces_bord() const
Returns the number of faces on which boundary conditions are applied:
Definition Domaine_VF.h:512
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
Returns the face-element connectivity array; see above.
Definition Domaine_VF.h:426
void marquer_faces_double_contrib(const Conds_lim &)
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.
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 &)
Sets the type of the faces.
Definition Faces.cpp:382
void associer_domaine(const Domaine_t &z)
Definition Faces.h:94
IntTab_t & voisins()
Returns the array of neighbors (of the faces).
Definition Faces.h:89
void calculer_surfaces(DoubleVect_t &surf) const
Computes the surface area of the faces.
Definition Faces.cpp:487
int_t nb_faces() const
Definition Faces.h:66
void calculer_centres_gravite(DoubleTab_t &xv) const
Computes the centers of gravity of each face.
Definition Faces.cpp:768
int_t voisin(int_t, int) const
Returns the number of the i-th neighbor of face.
Definition Faces.h:165
const IntTab_t & les_sommets() const
Returns the array of vertices of all 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)
From the description of the domain elements and boundaries (borders, connections, face groups,...
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
Returns the number of faces of the boundary.
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
Returns the joint information for the requested type (read-only).
Definition Joint.cpp:131
Joint_Items_t & set_joint_item(JOINT_ITEM type)
Returns the joint information for a given geometric item type, for filling the structures.
Definition Joint.cpp:104
const IntTab_t & renum_items_communs() const
Returns the renum_items_communs_ array (read-only). See renum_items_communs_.
ArrOfInt_t & set_items_communs()
Returns the items_communs_ array for filling.
virtual trustIdType nb_items_seq_tot() const
static void creer_tableau_distribue(const MD_Vector &, Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Transforms v into a parallel array having the structure md.
: This class is an OWN_PTR but the pointed object is shared among multiple
Definition MD_Vector.h:48
Navier Velocity boundary condition of type "Navier":
Definition Navier.h:31
static int dimension
Definition Objet_U.h:94
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
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 const Nom & le_nom() const
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
Definition Objet_U.cpp:317
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
class Periodique This class represents a periodic boundary condition.
Definition Periodique.h:31
int face_associee(int i) const
Definition Periodique.h:35
static int check_int_overflow(trustIdType)
Definition Process.cpp:437
static double mp_max(double)
Definition Process.cpp:379
static Sortie & Journal(int message_level=0)
Returns a static Sortie object used as an event journal.
Definition Process.cpp:592
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 double mp_sum(double)
Computes the sum of x over all processors in the current group.
Definition Process.cpp:145
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
int nb_raccords() const
Returns the number of connections contained in the list.
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)
Builds the items_communs + virtual space structure of an array containing indices of geometric items,...
Definition Scatter.cpp:1621
static void calculer_renum_items_communs(Joints &joints, const JOINT_ITEM type_item)
Assumes that each joint[i].joint_item(type_item).items_communs() contains the local indices of common...
Definition Scatter.cpp:1220
static void construire_md_vector(const Domaine &, int nb_items_reels, const JOINT_ITEM, MD_Vector &)
Builds an MD_Vector_std from the joint information of the domain for the requested item type.
Definition Scatter.cpp:1277
static void calculer_espace_distant_faces(Domaine &domaine, const int nb_faces_reelles, const IntTab &elem_faces)
Same as Scatter::calculer_espace_distant_sommets for faces.
Definition Scatter.cpp:1180
Base class for output streams.
Definition Sortie.h:52
Symetrie On symmetry faces, the following properties hold:
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_