TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Faces_builder.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 <Connectivite_som_elem.h>
17#include <EcrFicCollecteBin.h>
18#include <Elem_geom_base.h>
19#include <Poly_geom_base.h>
20#include <communications.h>
21#include <NettoieNoeuds.h>
22#include <Faces_builder.h>
23#include <Domaine.h>
24#include <Scatter.h>
25#include <stdio.h>
26#include <vector>
27#include <array>
28#include <map>
29
30template <typename _SIZE_>
32 les_elements_ptr_(0),
33 connectivite_som_elem_ptr_(0),
34 is_polyedre_(-1)
35{
36}
37
38template <typename _SIZE_>
40{
41 les_elements_ptr_ = 0;
42 connectivite_som_elem_ptr_ = 0;
43 faces_element_reference_old_.reset();
44 ref_domaine_.reset();
45 faces_sommets_.reset();
46 face_elem_.reset();
47}
48
49/*! @brief From the description of the domain elements and boundaries (borders, connections, face groups, and joints):
50 *
51 * Fills the following structures:
52 * - for each domain boundary: fixer_num_premiere_face
53 * - les_faces.faces_sommets (real faces)
54 * - les_faces.faces_voisins (real faces)
55 * - elem_faces (for the real faces of real elements)
56 * (elem_faces is initialised with size nb_elem_reels x nb_faces_par_elem)
57 * - joints.items_communs(FACE)
58 *
59 * @param domaine The domain whose faces are being built.
60 * @param connect_som_elem Vertex-to-element connectivity.
61 * @param les_faces The faces object to fill.
62 * @param elem_faces The element-to-face connectivity array to fill.
63 */
64template <typename _SIZE_>
66 const Static_Int_Lists_t& connect_som_elem,
67 Faces_t& les_faces,
68 IntTab_t& elem_faces)
69{
70 les_elements_ptr_ = & domaine.les_elems();
71
72 connectivite_som_elem_ptr_ = & connect_som_elem;
73 // The connectivity must include virtual vertices
74 assert(connect_som_elem.get_nb_lists() == domaine.nb_som_tot());
75
76 // Fill the reference-element face table
77
78 is_polyedre_=0;
79 if (sub_type(Poly_geom_base,domaine.type_elem().valeur()))
80 {
81 is_polyedre_=1;
82 }
83 else
84 domaine.type_elem()->get_tab_faces_sommets_locaux(faces_element_reference_old_);
85 // Array of size (nb_faces, nb_vertices_per_face),
86 // giving for each face the indices of its vertices in the domain.
87 // Vertex ordering follows the reference element, for the neighboring
88 // element of the face with the smallest index.
89 IntTab_t& faces_sommets = les_faces.les_sommets();
90
91 // Array of size (nb_faces, 2) containing for each face
92 // the indices of the two neighboring elements. If "i_face" has only one neighbor,
93 // faces_voisins_(i_face, 1) = -1;
94 IntTab_t& faces_voisins = les_faces.voisins();
95
96 // Initialise references used in check_erreur_faces
97 faces_sommets_ = faces_sommets;
98 face_elem_ = faces_voisins;
99 ref_domaine_ = domaine;
100
101 // Element-to-face array:
102 // dimension(0) = number of elements,
103 // dimension(1) = number of faces per element
104 // elem_faces(i,j) = index of face j of element i in the
105 // faces_sommets and faces_voisins arrays
106 // (element faces are in the order given by faces_element_reference)
107 // appropriate remote and virtual spaces for elements
108 const int_t nb_elements = les_elements().dimension(0);
109 const int nb_faces_par_element = faces_element_reference(0).dimension(0);
110 elem_faces.resize(nb_elements, nb_faces_par_element);
111 elem_faces = -1;
112
113 const int nb_sommets_par_face = faces_element_reference(0).dimension(1);
114 // Each face is added with resize(n+1,...), so smart_resize is used:
115 // Compute the theoretical number of faces:
116 const int_t nb_faces_front = domaine.nb_faces_frontiere() + domaine.nb_faces_joint();
117 int_t nb_faces_prevision = (nb_elements * nb_faces_par_element + nb_faces_front) / 2;
118 if (is_polyedre_)
119 {
120 // all faces are already known....
121 const Poly_geom_base_t& poly=ref_cast(Poly_geom_base_t,ref_domaine_->type_elem().valeur());
122 nb_faces_prevision=(poly.get_somme_nb_faces_elem()+ nb_faces_front) / 2;;
123 }
124 // Pre-allocate memory for the expected number of faces to avoid repeated
125 // reallocations (see set_smart_resize)
126
127 faces_sommets.resize(nb_faces_prevision, nb_sommets_par_face);
128 faces_sommets.resize(0, nb_sommets_par_face);
129
130 faces_voisins.resize(nb_faces_prevision, 2);
131 faces_voisins.resize(0, 2);
132
133 // ******** Boundary processing **********
134 // note: "num_premiere_face" is initialised for boundaries here!
135
136 // Create boundary faces
137 {
138 Bords_t& bords = domaine.faces_bord();
139 const int n = bords.size();
140 for (int i = 0; i < n; i++)
141 {
142 Frontiere_t& frontiere = bords[i];
143
144 creer_faces_frontiere(1, /* one neighboring element per face */
145 frontiere,
146 faces_sommets,
147 faces_voisins,
148 elem_faces);
149 }
150 }
151// Connections (Raccords)
152 {
153 Raccords_t& raccords = domaine.faces_raccord();
154 const int n = raccords.size();
155 for (int i = 0; i < n; i++)
156 {
157 Frontiere_t& frontiere = raccords[i].valeur();
158 creer_faces_frontiere(1, /* one neighboring element per face */
159 frontiere,
160 faces_sommets,
161 faces_voisins,
162 elem_faces);
163 }
164 }
165
166// Internal boundary faces
167 {
168 Bords_Internes_t& faces_int = domaine.bords_int();
169 const int n = faces_int.size();
170 for (int i = 0; i < n; i++)
171 {
172 Frontiere_t& frontiere = faces_int[i];
173 creer_faces_frontiere(2, /* two neighboring elements per face */
174 frontiere,
175 faces_sommets,
176 faces_voisins,
177 elem_faces);
178 }
179
180 // Duplicate internal faces: for each face that has two neighbors,
181 // create a second identical face with the second neighbor,
182 // clear the second neighbor of the original face, and update
183 // the neighbor face of the second neighbor:
184 if (n > 0)
185 {
186 Cerr << "Faces_builder_32_64<_SIZE_>::creer_faces_reeles not coded for the internal faces of boundary" << finl;
188 // To be done based on the old version of domaine2... and needs testing!
189 }
190 }
191
192// Joint faces
193 {
194 Joints_t& joints = domaine.faces_joint();
195 const int n = joints.size();
196 for (int i = 0; i < n; i++)
197 {
198 Frontiere_t& frontiere = joints[i];
199 creer_faces_frontiere(2, /* neighboring elements per face */
200 frontiere,
201 faces_sommets,
202 faces_voisins,
203 elem_faces);
204 // Fill items_communs(FACE)
205 // Joint faces are in the same order locally and on the neighboring domain.
206 Joint_t& joint = joints[i];
207 ArrOfInt_t& indices_faces =
208 joint.set_joint_item(JOINT_ITEM::FACE).set_items_communs();
209 const int_t nb_faces = joint.nb_faces();
210 indices_faces.resize_array(nb_faces);
211 const int_t num_premiere_face = joint.num_premiere_face();
212 for (int_t i2 = 0; i2 < nb_faces; i2++)
213 indices_faces[i2] = num_premiere_face + i2;
214 }
215 }
216
217// *********************************************
218// Internal faces
219
220 creer_faces_internes(faces_sommets,
221 elem_faces,
222 faces_voisins);
223
224
225// Face group identification
226 {
227 Groupes_Faces_t& groupes_faces = domaine.groupes_faces();
228 const int n = groupes_faces.size();
229 for (int i = 0; i < n; i++)
230 {
231 Groupe_Faces_t& groupe_faces = groupes_faces[i];
232 identification_groupe_faces(groupe_faces,
233 elem_faces);
234 }
235 }
236// *********************************************
237// Done: verify that the actual number of faces matches the predicted number
238 if (faces_sommets.dimension(0) != nb_faces_prevision)
239 {
240 Cerr << "Error in Faces_builder_32_64<_SIZE_>::creer_faces_reeles:\n"
241 << " number of faces does not match predicted number of faces.\n"
242 << " (problem with faces_bords_internes ?)" << finl;
244 }
245
246// Reset the smart_resize attribute of the faces_sommets and faces_voisins arrays.
247
248
249// Reset class attributes
250 reset();
251}
252
253/*! @brief Helper method for creer_faces_frontiere and creer_faces_internes.
254 *
255 * If the list is non-empty on at least one processor, prints an error message and calls exit().
256 *
257 * @param message Error message to display.
258 * @param liste_faces List of faces that caused the error.
259 */
260template <typename _SIZE_>
261void Faces_builder_32_64<_SIZE_>::check_erreur_faces(const char * message,
262 const ArrOfInt_t& liste_faces) const
263{
264 const int nmax = 100;
265 int_t n = liste_faces.size_array();
266 if (n > 0)
267 {
268 Cerr << "==========================" << finl;
269 Cerr << "Error!" << finl << message
270 << "\nSee log file of this PE for detailed info."
271 << finl;
273 J << "Error in Faces_builder_32_64<_SIZE_>::creer_faces_*\n"
274 << message << finl;
275 if (n > nmax)
276 {
277 J << "Too many faces to display (" << n << ") display only " << nmax << " first faces" << finl;
278 n = nmax;
279 }
280 int_t i;
281 J << "Display format:\n"
282 << " facenumber = face index in faces_sommet array\n"
283 << " som1..som4 = node index\n"
284 << " elem1 elem2 = neighbouring element number\n"
285 << "facenumber som1 (x1 y1 z1) som2 (x2 y2 z2) [som3 (x3 y3 z3)...] elem1 elem2" << finl;
286 char s[1000];
287 const DoubleTab_t& coord = ref_domaine_->coord_sommets();
288 const IntTab_t& faces = faces_sommets_.valeur();
289 const IntTab_t& face_elem = face_elem_.valeur();
290 const int dim = Objet_U::dimension;
291 const int_t nb_som_faces = faces.dimension(1);
292 for (i = 0; i < n; i++)
293 {
294 char *sptr = s;
295 const int_t iface = liste_faces[i];
296 sptr += snprintf(sptr, 100, "%4ld ",(long) iface);
297 for (int j = 0; j < nb_som_faces; j++)
298 {
299 const int_t isom = faces(iface,j);
300 sptr += snprintf(sptr, 100, "%5ld(", (long)isom);
301 for (int k = 0; k < dim; k++)
302 if (isom!=-1)
303 sptr += snprintf(sptr, 100, "%10.6f", coord(isom, k));
304 sptr += snprintf(sptr, 100, ")");
305 }
306 sptr += snprintf(sptr, 100, "%4ld %4ld", (long)face_elem(iface,0),(long) face_elem(iface,1));
307 J << s << finl;
308 }
309 NettoieNoeuds_t::verifie_noeuds(ref_domaine_.valeur());
311 }
312}
313
314/*! @brief Adds a real face to faces_sommets and faces_voisins.
315 *
316 */
317template <typename _SIZE_>
318_SIZE_ Faces_builder_32_64<_SIZE_>::ajouter_une_face(const SmallArrOfTID_t& une_face,
319 const int_t elem0,
320 const int_t elem1,
321 IntTab_t& faces_sommets,
322 IntTab_t& faces_voisins)
323{
324 int i;
325 const int_t num_new_face = faces_sommets.dimension(0);
326 const int nb_sommets_par_face = (int)faces_sommets.dimension(1);
327 const int_t new_size = num_new_face + 1;
328
329 assert(une_face.size_array() == nb_sommets_par_face);
330 faces_sommets.resize(new_size, nb_sommets_par_face);
331 for (i = 0; i < nb_sommets_par_face; i++)
332 faces_sommets(num_new_face, i) = une_face[i];
333
334 faces_voisins.resize(new_size, 2);
335 faces_voisins(num_new_face, 0) = elem0;
336 faces_voisins(num_new_face, 1) = elem1;
337
338 return num_new_face;
339}
340
341template <typename _SIZE_>
343 const IntTab& faces_element_ref,
344 const SmallArrOfTID_t& une_face,
345 const int_t elem)
346{
347 const int nb_faces_element = (int)faces_element_ref.dimension(0);
348 const int nb_sommets_par_face = (int)faces_element_ref.dimension(1);
349
350 int i_face, i_som2, i_som;
351 for (i_face = 0; i_face < nb_faces_element; i_face++)
352 {
353 for (i_som = 0; i_som < nb_sommets_par_face; i_som++)
354 {
355 const int sommet_elem_ref = faces_element_ref(i_face, i_som);
356 int_t sommet_domaine ;
357 if (sommet_elem_ref==-1)
358 sommet_domaine=-1;
359 else
360 sommet_domaine = elem_som(elem, sommet_elem_ref);
361 for (i_som2 = 0; i_som2 < nb_sommets_par_face; i_som2++)
362 if (une_face[i_som2] == sommet_domaine) // if vertex found, stop
363 break;
364 if (i_som2 == nb_sommets_par_face) // if vertex not found, stop
365 break;
366 }
367 if (i_som == nb_sommets_par_face) // if all vertices have been found, stop
368 break;
369 }
370 if (i_face == nb_faces_element) // if face not found
371 return -1;
372 else
373 return i_face;
374}
375
376template <typename _SIZE_>
377const IntTab& Faces_builder_32_64<_SIZE_>::faces_element_reference(int_t elem) const
378{
379 if (is_polyedre_==1)
380 {
381 const Poly_geom_base_t& poly =ref_cast(Poly_geom_base_t,ref_domaine_->type_elem().valeur());
382 IntTab& elem_ref_mod=ref_cast_non_const(IntTab,faces_element_reference_old_);
383 poly.get_tab_faces_sommets_locaux(elem_ref_mod,elem);
384
385 //abort();
386 //return faces_element_reference(0);
387 }
388 return faces_element_reference_old_;
389}
390
391
392/*! @brief Helper method: assumes "une_face" contains the vertex indices of a face of the element with index "elem" in the domain.
393 *
394 * Searches for the number of this face on the reference element.
395 * If the vertices do not correspond to any face of the element, returns -1.
396 *
397 */
398template <typename _SIZE_>
399int Faces_builder_32_64<_SIZE_>::chercher_face_element(const SmallArrOfTID_t& une_face,
400 const int_t elem) const
401{
402 const IntTab_t& elem_som = les_elements();
403 const IntTab& faces_element_ref = faces_element_reference(elem);
404 int i_face = chercher_face_element(elem_som, faces_element_ref, une_face, elem);
405 return i_face;
406}
407
408/*! @brief Inserts the faces of the given boundary into the three arrays, after the faces already present in faces_sommets.
409 *
410 * Fills:
411 * frontiere.num_premiere_face
412 * Completes:
413 * faces_sommets
414 * elem_faces
415 * faces_voisins
416 *
417 */
418template <typename _SIZE_>
419void Faces_builder_32_64<_SIZE_>::creer_faces_frontiere(const int_t nb_voisins_attendus,
420 Frontiere_t& frontiere,
421 IntTab_t& faces_sommets,
422 IntTab_t& faces_voisins,
423 IntTab_t& elem_faces) const
424{
425 assert(nb_voisins_attendus == 1 || nb_voisins_attendus == 2);
426
427 const Static_Int_Lists_t& som_elem = connectivite_som_elem();
428 const int nb_sommets_par_face = faces_element_reference(0).dimension(0) ? faces_element_reference(0).dimension(1) : 3;
429 const int_t num_premiere_face = faces_sommets.dimension(0);
430 const int_t nb_elem_reels = elem_faces.dimension(0);
431 frontiere.fixer_num_premiere_face(num_premiere_face);
432
433 const Faces_t& faces_frontiere = frontiere.faces();
434 const IntTab_t& sommets_faces_fr = faces_frontiere.les_sommets();
435 const int_t nb_faces = faces_frontiere.nb_faces();
436 SmallArrOfTID_t une_face(nb_sommets_par_face);
437 SmallArrOfTID_t voisins;
438
439 ArrOfInt_t liste_faces_erreur0;
440
441 ArrOfInt_t liste_faces_erreur1;
442
443 ArrOfInt_t liste_faces_erreur2;
444
445 ArrOfInt_t liste_faces_erreur3;
446
447 constexpr bool STOP_FIRST_ERR = false; // set this to true in Debug to stop gdb at the right place.
448
449 int i_face;
450 for (i_face = 0; i_face < nb_faces; i_face++)
451 {
452 {
453 int nb_sommets_par_face_fr= (int)sommets_faces_fr.dimension(1);
454 for (int i = 0; i < std::min(nb_sommets_par_face, nb_sommets_par_face_fr); i++)
455 une_face[i] = sommets_faces_fr(i_face, i);
456 for (int i = std::min(nb_sommets_par_face, nb_sommets_par_face_fr); i < nb_sommets_par_face; i++)
457 une_face[i] = -1;
458 }
459 // What are the neighboring elements of this face?
460 find_adjacent_elements(som_elem, une_face, voisins);
461 const int_t nb_voisins = voisins.size_array();
462 const int_t elem0 = (nb_voisins > 0) ? voisins[0] : -1;
463 const int_t elem1 = (nb_voisins > 1) ? voisins[1] : -1;
464 const int_t indice_face =
465 ajouter_une_face(une_face, elem0, elem1, faces_sommets, faces_voisins);
466
467 switch(nb_voisins)
468 {
469 case 0:
470 {
471 // Error: the face has no neighbor
472 liste_faces_erreur0.append_array(indice_face);
473 if(STOP_FIRST_ERR) Process::exit("A least one face has no neighbor!");
474 break;
475 }
476 case 1:
477 case 2:
478 {
479 if (nb_voisins_attendus == nb_voisins)
480 {
481 int i_voisin;
482 for (i_voisin = 0; i_voisin < nb_voisins; i_voisin++)
483 {
484 const int_t elem = voisins[i_voisin];
485 // What is the face of the element?
486 const int i_face_elem = chercher_face_element(une_face, elem);
487 if (i_face_elem >= 0)
488 {
489 // If it is a real element, associate the face
490 if (elem < nb_elem_reels)
491 {
492 if (elem_faces(elem, i_face_elem) < 0)
493 elem_faces(elem, i_face_elem) = indice_face;
494 else
495 {
496 // Error: this face already exists (in this or another boundary)
497 liste_faces_erreur3.append_array(indice_face);
498 if(STOP_FIRST_ERR) Process::exit("A face already exists! Was found twice!");
499 }
500 }
501 }
502 else
503 {
504 // Error: the face does not belong to the element.
505 liste_faces_erreur0.append_array(indice_face);
506 if(STOP_FIRST_ERR) Process::exit("A face does not belong to any element!");
507 }
508 }
509 }
510 else
511 {
512 // Error: unexpected number of neighbors.
513 liste_faces_erreur1.append_array(indice_face);
514 if(STOP_FIRST_ERR) Process::exit("A face has an unexpected number of neighbors!");
515 }
516 break;
517 }
518 default:
519 // Error: more than two neighbors, which should not happen.
520 liste_faces_erreur2.append_array(indice_face);
521 if(STOP_FIRST_ERR) Process::exit("A face has more than 2 neighbors!");
522 }
523 }
524 Nom msg;
525 msg = "Boundary \"";
526 msg += frontiere.le_nom();
527 msg += "\" contains faces which do not belong to any element.";
528 check_erreur_faces(msg, liste_faces_erreur0);
529
530 msg = "Boundary \"";
531 msg += frontiere.le_nom();
532 msg += "\" contains faces that belong to ";
533 msg += Nom(3-nb_voisins_attendus);
534 msg += " elements.\n";
535 switch(nb_voisins_attendus)
536 {
537 case 1:
538 msg += "These faces should have only 1 neighbouring element.";
539 break;
540 case 2:
541 msg += "These faces should have 2 neighbouring elements.";
542 break;
543 default:
544 msg = "Internal error.";
545 }
546 if (sub_type(Joint, frontiere))
547 {
548 // Two possible error sources: the joint faces are incorrect,
549 // or the domain does not contain virtual elements (at a minimum the domain
550 // must contain the virtual elements neighboring the joint faces).
551 msg += "(Error in a Joint object: internal error in the mesh splitter or scatter ? )\n";
552 }
553 check_erreur_faces(msg, liste_faces_erreur1);
554
555 msg = "Boundary \"";
556 msg += frontiere.le_nom();
557 msg += "\" contains faces that belong to more than 2 elements.\n";
558 check_erreur_faces(msg, liste_faces_erreur2);
559
560 msg = "Boundary \"";
561 msg += frontiere.le_nom();
562 msg += "\" contains faces that already exist in another boundary or in this one.\n";
563 check_erreur_faces(msg, liste_faces_erreur3);
564}
565
566/*! @brief Construction of the internal faces of the domain (faces with two neighbors that are not "faces_bord_internes").
567 *
568 * Joint faces have already been created.
569 *
570 */
571template <typename _SIZE_>
572void Faces_builder_32_64<_SIZE_>::creer_faces_internes(IntTab_t& faces_sommets,
573 IntTab_t& elem_faces,
574 IntTab_t& faces_voisins) const
575{
576 const IntTab_t& elem_som = les_elements();
577 const Static_Int_Lists_t& som_elem = connectivite_som_elem();
578 // const IntTab_t & faces_elem_ref = faces_element_reference();
579 const int_t nb_elem = elem_som.dimension(0);
580 const int nb_faces_par_element = faces_element_reference(0).dimension(0);
581 const int nb_sommets_par_face = nb_faces_par_element ? faces_element_reference(0).dimension(1) : 3;
582
583 // Temporary array storing the vertex indices of the face being processed
584 SmallArrOfTID_t une_face(nb_sommets_par_face);
585 // Temporary array (list of neighboring elements of a face)
586 SmallArrOfTID_t voisins;
587
588 // List of faces with only one neighbor not listed in boundary faces (errors):
589 ArrOfInt_t liste_faces_frontiere_non_declarees;
590
591 ArrOfInt_t liste_faces_joint_non_declarees;
592
593 // List of faces with a connectivity error (more than
594 // two neighboring elements, or connection to vertices that are
595 // not on any face of the element:
596 ArrOfInt_t liste_faces_erreurs_connectivite;
597
598 constexpr bool STOP_FIRST_ERR = false; // set this to true in Debug to stop gdb at the right place.
599
600 // Loop over elements
601 int_t i_elem;
602 for (i_elem = 0; i_elem < nb_elem; i_elem++)
603 {
604 int i_face;
605 // Loop over the faces of the element
606 for (i_face = 0; i_face < nb_faces_par_element; i_face++)
607 {
608
609 // Index of this face in the faces_sommets array.
610 // It is -1 if the face has not yet been created.
611 int_t indice_face = elem_faces(i_elem, i_face);
612
613 // Compute the vertex indices of the face in the domain:
614 int i;
615 // Note: this call must stay here...
616 const IntTab& faces_elem_ref = faces_element_reference(i_elem);
617
618 for (i = 0; i < nb_sommets_par_face; i++)
619 {
620 // index of the vertex on the reference element
621 const int i_som_ref = faces_elem_ref(i_face, i);
622 // index of the vertex in the domain
623 if (i_som_ref==-1)
624 une_face[i] = -1;
625 else
626 {
627 const int_t i_som = elem_som(i_elem, i_som_ref);
628 une_face[i] = i_som;
629 }
630 }
631 if (une_face[0]==-1)
632 {
633 // dummy face, do nothing
634 elem_faces(i_elem, i_face) = -1;
635 }
636 else
637 {
638 // Search for neighboring elements of this face.
639 // The "voisins" array is sorted in ascending order.
640 find_adjacent_elements(som_elem, une_face, voisins);
641
642 const int_t nb_voisins = voisins.size_array();
643 assert (nb_voisins > 0); // There should be at least i_elem !!! (or else we have a face made of -1);
644
645 if (nb_voisins == 1) // ***** The face has 1 neighbor ********
646 {
647
648 assert(voisins[0] == i_elem); // The neighboring element must be i_elem
649 // A face with only one neighboring element is a boundary face.
650 if (indice_face >= 0)
651 {
652 // Ok, this is normal; boundary faces have already been processed
653 }
654 else
655 {
656 // Error: the face does not yet exist. It should have been
657 // created from the boundaries (creer_faces_frontiere)
658 indice_face = ajouter_une_face(une_face, i_elem, -1,
659 faces_sommets, faces_voisins);
660 liste_faces_frontiere_non_declarees.append_array(indice_face);
661 if(STOP_FIRST_ERR) Process::exit("Non declared face!");
662 }
663
664 }
665 else if (nb_voisins == 2) // ***** The face has 2 neighbors ********
666 {
667
668 const int_t elem0 = voisins[0];
669 const int_t elem1 = voisins[1];
670 assert(elem0 < elem1);
671 if (indice_face >= 0)
672 {
673 // The face has already been created.
674 }
675 else
676 {
677 // The face does not yet exist.
678 if (elem0 == i_elem)
679 {
680 // Neighbors are sorted: elem0 < elem1
681 // so this is the first time this face is encountered in the
682 // element loop.
683 indice_face = ajouter_une_face(une_face, elem0, elem1,
684 faces_sommets, faces_voisins);
685
686 // Where is this face on the neighboring element?
687 const int i_face_elem1 = chercher_face_element(une_face, elem1);
688 if (i_face_elem1 >= 0)
689 {
690 if (elem1 < nb_elem) // Is the neighboring element real?
691 elem_faces(elem1, i_face_elem1) = indice_face;
692 }
693 else
694 {
695 // Error: the face vertices belong to elem1
696 // but are not on any face of that element. Mesh connectivity error.
697 liste_faces_erreurs_connectivite.append_array(indice_face);
698 if(STOP_FIRST_ERR) Process::exit("Connectivity issue with face!");
699 }
700 if (elem1 >= nb_elem)
701 {
702 // Error: the neighbor is a virtual element; this face
703 // should be in the joint faces and thus already created.
704 liste_faces_joint_non_declarees.append_array(indice_face);
705 if(STOP_FIRST_ERR) Process::exit("Pb with face: its neighbor is virtual! Should not happen here.");
706 }
707 }
708 else
709 {
710 assert(elem1 == i_elem);
711 indice_face = ajouter_une_face(une_face, elem0, elem1,
712 faces_sommets, faces_voisins);
713 // We should have already created this face since it is a neighbor of elem0,
714 // which has already been processed (smaller index). If we reach here,
715 // the vertices of "une_face" belong to elem0 but are not on any face
716 // of that element. This is a connectivity error.
717 liste_faces_erreurs_connectivite.append_array(indice_face);
718 if(STOP_FIRST_ERR) Process::exit("Pb with face: connectivity error.");
719 }
720 }
721
722 }
723 else // ***** The face has > 2 neighbours ********
724 {
725 if (indice_face < 0)
726 {
727 const int_t elem0 = voisins[0];
728 const int_t elem1 = voisins[1];
729 indice_face = ajouter_une_face(une_face, elem0, elem1,
730 faces_sommets, faces_voisins);
731 }
732 liste_faces_erreurs_connectivite.append_array(indice_face);
733 if(STOP_FIRST_ERR) Process::exit("Pb with face: connectivity error 2.");
734 }
735
736 // If the face did not exist, it has been created and its index stored in indice_face.
737 // Otherwise, the index of the existing face has been found.
738 assert(indice_face >= 0);
739 elem_faces(i_elem, i_face) = indice_face; /* WRITE elem_faces */
740 }
741 }
742 }
743
744 // Error handling:
745 {
746 const char * const msg1 = "We found faces which belong to one element/cell only and are not declared in any boundary ! You forgot to define at least one boundary in your mesh. Fix your mesh.\n";
747 const char * const msg2 = "Joint faces are incomplete: internal error in the mesh splitter\n";
748 const char * const msg3 = "Connectivity error in the mesh elements. Possible errors:\n- one face of one element belongs to more than 2 elements\n- two element have at least 3 common nodes but these nodes are not faces of these elements\n";
749 check_erreur_faces(msg1, liste_faces_frontiere_non_declarees);
750 check_erreur_faces(msg2, liste_faces_joint_non_declarees);
751 check_erreur_faces(msg3, liste_faces_erreurs_connectivite);
752 }
753}
754
755/*! @brief Identification of the face groups specified in the domain.
756 *
757 * Fills the indices_faces array of a specific face group.
758 *
759 */
760template <typename _SIZE_>
761void Faces_builder_32_64<_SIZE_>::identification_groupe_faces(Groupe_Faces_t& groupe_faces,
762 const IntTab_t& elem_faces) const
763{
764 const Static_Int_Lists_t& som_elem = connectivite_som_elem();
765 const int nb_sommets_par_face = faces_element_reference(0).dimension(0) ? faces_element_reference(0).dimension(1) : 3;
766
767 const Faces_t& faces_specifiees = groupe_faces.faces();
768 const IntTab_t& sommets_faces_fr = faces_specifiees.les_sommets();
769 const int_t nb_faces = faces_specifiees.nb_faces();
770 ArrOfInt_t& indices_faces = groupe_faces.get_indices_faces();
771 indices_faces.resize_array(nb_faces);
772
773 SmallArrOfTID_t une_face(nb_sommets_par_face);
774 SmallArrOfTID_t voisins;
775
776 ArrOfInt_t liste_faces_erreur0;
777
778 ArrOfInt_t liste_faces_erreur1;
779
780
781 for (int i_face = 0; i_face < nb_faces; i_face++)
782 {
783 {
784 int nb_sommets_par_face_fr= (int)sommets_faces_fr.dimension(1);
785 for (int i = 0; i < std::min(nb_sommets_par_face, nb_sommets_par_face_fr); i++)
786 une_face[i] = sommets_faces_fr(i_face, i);
787 for (int i = std::min(nb_sommets_par_face, nb_sommets_par_face_fr); i < nb_sommets_par_face; i++)
788 une_face[i] = -1;
789 }
790 // What are the neighboring elements of this face?
791 find_adjacent_elements(som_elem, une_face, voisins);
792 const int_t nb_voisins = voisins.size_array();
793
794 switch(nb_voisins)
795 {
796 case 0:
797 {
798 // Error: the face has no neighbor
799 liste_faces_erreur0.append_array(i_face);
800 break;
801 }
802 case 1:
803 case 2:
804 {
805 const int_t elem = voisins[0];
806 // Which face of the element is it?
807 const int i_face_elem = chercher_face_element(une_face, elem);
808
809 if (i_face_elem >= 0)
810 // What is the index of the face
811 indices_faces[i_face] = elem_faces(elem,i_face_elem);
812 break;
813 }
814 default:
815 // Error: more than two neighbors, which should not happen.
816 liste_faces_erreur1.append_array(i_face);
817 }
818 }
819
820 Nom msg;
821 msg = "Group of Faces \"";
822 msg += groupe_faces.le_nom();
823 msg += "\" contains faces which do not belong to any element or not virtual element.";
824 check_erreur_faces(msg, liste_faces_erreur0);
825
826 msg = "Group of Faces \"";
827 msg += groupe_faces.le_nom();
828 msg += "\" contains faces that belong to more than 2 elements.\n";
829 check_erreur_faces(msg, liste_faces_erreur1);
830}
831
832template class Faces_builder_32_64<int>;
833//#if INT_is_64_ == 2
835//#endif
IntTab_t & voisins()
Returns the array of neighbors (of the faces).
Definition Faces.h:89
const IntTab_t & les_sommets() const
Returns the array of vertices of all faces.
Definition Faces.h:74
Helper class for building the faces of a domain. (used only to create the arrays of real faces).
Joints_32_64< _SIZE_ > Joints_t
IntTab_T< _SIZE_ > IntTab_t
Bords_32_64< _SIZE_ > Bords_t
Frontiere_32_64< _SIZE_ > Frontiere_t
SmallArrOfTID_T< _SIZE_ > SmallArrOfTID_t
Groupes_Faces_32_64< _SIZE_ > Groupes_Faces_t
static int chercher_face_element(const IntTab_t &elem_som, const IntTab &faces_element_ref, const SmallArrOfTID_t &une_face, const int_t elem)
Static_Int_Lists_32_64< _SIZE_ > Static_Int_Lists_t
Faces_32_64< _SIZE_ > Faces_t
Bords_Internes_32_64< _SIZE_ > Bords_Internes_t
ArrOfInt_T< _SIZE_ > ArrOfInt_t
Raccords_32_64< _SIZE_ > Raccords_t
Poly_geom_base_32_64< _SIZE_ > Poly_geom_base_t
Joint_32_64< _SIZE_ > Joint_t
Groupe_Faces_32_64< _SIZE_ > Groupe_Faces_t
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,...
Domaine_32_64< _SIZE_ > Domaine_t
int_t num_premiere_face() const
Definition Frontiere.h:67
int_t nb_faces() const
Returns the number of faces of the boundary.
Definition Frontiere.h:59
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
ArrOfInt_t & set_items_communs()
Returns the items_communs_ array for filling.
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
const Nom & le_nom() const override
Returns *this.
Definition Nom.cpp:555
static int dimension
Definition Objet_U.h:94
virtual int_t get_somme_nb_faces_elem() const =0
static Sortie & Journal(int message_level=0)
Returns a static Sortie object used as an event journal.
Definition Process.cpp:592
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
Base class for output streams.
Definition Sortie.h:52
int_t get_nb_lists() const
Returns the number of stored lists.
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133