15#include <MaillerParallel.h>
20#include <TRUSTArrays.h>
22#include <Reordonner_faces_periodiques.h>
24#include <Schema_Comm.h>
25#include <Octree_Double.h>
26#include <Faces_builder.h>
27#include <Connectivite_som_elem.h>
28#include <Static_Int_Lists.h>
29#include <communications.h>
31#include <Array_tools.h>
34#include <Perf_counters.h>
54 void add_bloc(Domaine& domaine,
const ArrsOfDouble& coord_ijk)
const;
70 void add_faces(Domaine& domaine,
const Nom& nombord,
int offset_sommets,
int dir,
int cote_max)
const;
77 Cerr <<
"Error : not enough nodes in a block, increase mesh size or decrease processor count" << finl;
82 const int old_nb_som = domaine.les_sommets().dimension(0);
84 DoubleTab& sommets = domaine.les_sommets();
86 sommets.
resize(old_nb_som + nsom, dim);
88 int index = old_nb_som;
96 sommets(index, 0) = coord_ijk[0][i];
97 sommets(index, 1) = coord_ijk[1][j];
99 sommets(index, 2) = coord_ijk[2][k];
108 IntTab& elements = domaine.les_elems();
109 const int nb_som_par_element = 8;
114 const int dz = dy *
nb_som(1);
119 const int nb_elem_old = domaine.les_elems().dimension(0);
120 const int nbelem = nx * ny * nz;
121 elements.
resize(nb_elem_old + nbelem, nb_som_par_element);
123 int index = nb_elem_old;
125 for (k = 0; k < nz; k++)
127 for (j = 0; j < ny; j++)
129 for (i = 0; i < nx; i++)
131 int n = old_nb_som + k * dz + j * dy + i * dx;
132 elements(index, 0) = n;
133 elements(index, 1) = n + dx;
134 elements(index, 2) = n + dy;
135 elements(index, 3) = n + dx + dy;
136 elements(index, 4) = n + dz;
137 elements(index, 5) = n + dz + dx;
138 elements(index, 6) = n + dz + dy;
139 elements(index, 7) = n + dz + dx + dy;
146 for (
int dir = 0; dir < 3; dir++)
157 int nfaces1, nfaces2;
158 int increment1, increment2;
174 increment_dir =
nb_som(0);
185 offset_sommets += increment_dir * (
nb_som(dir)-1);
187 IntTab& faces = domaine.frontiere(nombord).faces().les_sommets();
188 int count = faces.dimension(0);
189 domaine.frontiere(nombord).faces().dimensionner(count + nfaces1 * nfaces2);
190 for (
int i = 0; i < nfaces2; i++)
192 int sommet = offset_sommets;
193 for (
int j = 0; j < nfaces1; j++)
195 faces(count, 0) = sommet;
196 faces(count, 1) = sommet + increment1;
197 faces(count, 2) = sommet + increment2;
198 faces(count, 3) = sommet + increment1 + increment2;
199 sommet += increment1;
202 offset_sommets += increment2;
206static int bbox_intersection(
const DoubleTab& bboxes,
int i,
int j,
double epsilon)
209 for (
int k = 0; k < dim; k++)
211 double min1 = bboxes(i, k) - epsilon;
212 double max1 = bboxes(i, dim+k) + epsilon;
213 double min2 = bboxes(j, k);
214 double max2 = bboxes(j, dim+k);
215 if (min1 > max2 || max1 < min2)
229void find_matching_coordinates(
const DoubleTab& coords,
239 DoubleTab bounding_boxes(nproc, dim*2);
241 const double big_val = 1.e36;
242 ArrOfDouble min_coord(dim);
244 ArrOfDouble max_coord(dim);
247 for (i = 0; i < ncoord; i++)
249 for (j = 0; j < dim; j++)
251 const double x = coords(i, j);
252 if (x > max_coord[j])
254 if (x < min_coord[j])
259 for (i = 0; i < nproc; i++)
261 for (j = 0; j < dim; j++)
263 bounding_boxes(i, j) = min_coord[j];
264 bounding_boxes(i, j+dim) = max_coord[j];
267 envoyer_all_to_all(bounding_boxes, bounding_boxes);
272 for (i = 0; i < nproc; i++)
273 if (i != moi && bbox_intersection(bounding_boxes, moi, i, epsilon))
279 Octree_Double octree;
287 for (ipe = 0; ipe < all_pe.
size_array(); ipe++)
290 const int pe = all_pe[ipe];
291 const double xmin = bounding_boxes(pe, 0) - epsilon;
292 const double ymin = bounding_boxes(pe, 1) - epsilon;
293 const double zmin = (dim == 3) ? bounding_boxes(pe, 2) - epsilon : -epsilon;
294 const double xmax = bounding_boxes(pe, dim) + epsilon;
295 const double ymax = bounding_boxes(pe, dim+1) + epsilon;
296 const double zmax = (dim == 3) ? bounding_boxes(pe, dim+2) + epsilon : epsilon;
301 for (i = 0; i < n; i++)
303 const int som = nodes_list[i];
304 const double x = coords(som, 0);
305 const double y = coords(som, 1);
306 const double z = (dim==3) ? coords(som, 2) : 0;
308 if (x>=xmin && x<=xmax && y>=ymin && y<=ymax && z>=zmin && z<=zmax)
310 buffer << x << y << z;
315 for (ipe = 0; ipe < all_pe.
size_array(); ipe++)
317 const int pe = all_pe[ipe];
319 ArrOfInt& resu = match[pe];
325 buffer >> x >> y >> z;
330 x+epsilon, y+epsilon, z+epsilon, nodes_list);
336 Cerr <<
"Error in automatic joint builder: more than one node within epsilon tolerance\n"
337 <<
" node coord = " << x <<
" " << y <<
" " << z <<
" tolerance= " << epsilon << finl;
354static void find_joint_faces(
const Domaine& domaine, IntTab& faces)
356 Static_Int_Lists som_elem;
357 const IntTab& elements = domaine.les_elems();
358 const int nb_som = domaine.nb_som();
359 construire_connectivite_som_elem(nb_som, elements, som_elem, 0 );
360 const int nb_som_faces = domaine.type_elem()->nb_som_face();
361 faces.
resize(0, nb_som_faces);
363 IntTab faces_element_reference;
364 domaine.type_elem()->get_tab_faces_sommets_locaux(faces_element_reference);
365 const int nb_faces_elem = faces_element_reference.
dimension(0);
367 const int nb_elem = elements.
dimension(0);
368 ArrOfBit boundary_faces(nb_elem * nb_faces_elem);
370 ArrOfInt une_face(nb_som_faces);
371 ArrOfInt liste_elements;
373 const int nb_boundaries = domaine.nb_front_Cl();
374 for (
int i_boundary = 0; i_boundary < nb_boundaries; i_boundary++)
376 const IntTab& faces_front = domaine.frontiere(i_boundary).faces().les_sommets();
377 const int nb_faces_bord = faces_front.
dimension(0);
378 for (
int j = 0; j < nb_faces_bord; j++)
380 for (
int k = 0; k < nb_som_faces; k++)
381 une_face[k] = faces_front(j, k);
382 find_adjacent_elements(som_elem, une_face, liste_elements);
385 Cerr <<
"Error in MaillerParallel::find_joint_faces: boundary face ArrOfInt=" << une_face
386 <<
" does not have exactly 1 neighbour element: " << liste_elements;
389 const int elem = liste_elements[0];
391 boundary_faces.setbit(elem * nb_faces_elem + face_locale);
395 for (
int elem = 0; elem < nb_elem; elem++)
397 for (
int face_locale = 0; face_locale < nb_faces_elem; face_locale++)
399 if (boundary_faces[elem * nb_faces_elem + face_locale])
402 for (i = 0; i < nb_som_faces; i++)
404 const int sommet_local = faces_element_reference(face_locale, i);
405 une_face[i] = elements(elem, sommet_local);
407 find_adjacent_elements(som_elem, une_face, liste_elements);
412 for (i = 0; i < nb_som_faces; i++)
413 faces(n, i) = une_face[i];
417 Process::Journal() <<
"Domain " << domaine.le_nom() <<
" has " << faces.
dimension(0) <<
" undeclared boundary faces candidates for joint faces" << finl;
420static void auto_build_joints(Domaine& domaine,
const int epaisseur_joint)
422 const double epsilon = 1e-10;
426 find_joint_faces(domaine, faces);
428 const DoubleTab& sommets = domaine.les_sommets();
433 ArrOfInt boundary_nodes_index;
434 boundary_nodes_index = faces;
435 array_trier_retirer_doublons(boundary_nodes_index);
436 const int ncoord = boundary_nodes_index.
size_array();
439 coord.
resize(ncoord, dim, RESIZE_OPTIONS::NOCOPY_NOINIT);
440 for (i = 0; i < ncoord; i++)
442 const int som = boundary_nodes_index[i];
443 for (j = 0; j < dim; j++)
444 coord(i, j) = sommets(som, j);
447 find_matching_coordinates(coord, match, epsilon);
449 for (
int pe = 0; pe < match.
size(); pe++)
451 const ArrOfInt& list = match[pe];
455 Joint& joint = domaine.faces_joint().add(Joint());
460 joint.
faces().
typer(domaine.type_elem()->type_face());
462 sommets_joint.
resize_array(n, RESIZE_OPTIONS::NOCOPY_NOINIT);
463 for (i = 0; i < n; i++)
464 sommets_joint[i] = boundary_nodes_index[list[i]];
466 Process::Journal() <<
"Joint sommets with pe " << pe <<
" has " << n <<
" nodes" << finl;
474 const int nb_som_faces = faces.
dimension(1);
475 DoubleTab coord(nfaces, dim);
476 const double facteur = 1. / (double)nb_som_faces;
477 for (i = 0; i < nfaces; i++)
479 for (j = 0; j < nb_som_faces; j++)
481 const int som = faces(i,j);
482 for (
int k = 0; k < dim; k++)
483 coord(i, k) += sommets(som, k) * facteur;
487 find_matching_coordinates(coord, match, epsilon);
489 for (
int pe = 0; pe < match.
size(); pe++)
491 const ArrOfInt& list = match[pe];
495 OBS_PTR(Joint) ref_joint;
497 for (ii = 0; ii < domaine.faces_joint().size(); ii++)
499 Joint& joint = domaine.faces_joint()[ii];
508 Joint& joint = domaine.faces_joint().
add(Joint());
513 joint.
faces().
typer(domaine.type_elem()->type_face());
516 Faces& les_faces = ref_joint->faces();
519 for (ii = 0; ii < n; ii++)
521 const int num_face = list[ii];
522 for (j = 0; j < nb_som_faces; j++)
523 faces_sommets(ii, j) = faces(num_face, j);
525 Process::Journal() <<
"Joint faces with pe " << pe <<
" has " << n <<
" faces" << finl;
537 Cerr <<
"Error: MaillerParallel is only coded for dimension 3" << finl;
545 int epaisseur_joint = -1;
546 bool perio[3] = {
false,
false,
false};
547 Noms fonctions_coord(3);
548 Noms nom_bords_min(3);
549 Noms nom_bords_max(3);
550 nom_bords_min[0] =
"xmin";
551 nom_bords_min[1] =
"ymin";
552 nom_bords_min[2] =
"zmin";
553 nom_bords_max[0] =
"xmax";
554 nom_bords_max[1] =
"ymax";
555 nom_bords_max[2] =
"zmax";
556 Noms fichier_coord(3);
579 param.
ajouter(
"function_coord_x", &fonctions_coord[0]);
583 param.
ajouter(
"function_coord_y", &fonctions_coord[1]);
585 param.
ajouter(
"function_coord_z", &fonctions_coord[2]);
587 param.
ajouter(
"file_coord_x", &fichier_coord[0]);
589 param.
ajouter(
"file_coord_y", &fichier_coord[1]);
591 param.
ajouter(
"file_coord_z", &fichier_coord[2]);
593 param.
ajouter(
"boundary_xmin", &nom_bords_min[0]);
597 param.
ajouter(
"boundary_xmax", &nom_bords_max[0]);
599 param.
ajouter(
"boundary_ymin", &nom_bords_min[1]);
601 param.
ajouter(
"boundary_ymax", &nom_bords_max[1]);
603 param.
ajouter(
"boundary_zmin", &nom_bords_min[2]);
605 param.
ajouter(
"boundary_zmax", &nom_bords_max[2]);
607 param.
ajouter(
"mapping", &mapping);
611 ArrsOfDouble coord_ijk(3);
612 for (
int dir=0; dir<3; dir++)
614 const int n = nb_noeuds[dir];
615 ArrOfDouble& coord = coord_ijk[dir];
617 Cerr <<
"Building coordinates for direction " << dir << finl;
618 if (fonctions_coord[dir] !=
"??")
620 Nom chaine = fonctions_coord[dir];
621 Cerr <<
" Interpreting expression " << chaine << finl;
631 for (
int i = 0; i < n; i++)
633 p.
setVar(0, (
double) i / (
double) (nb_noeuds[dir]-1));
635 if (i > 0 && coord[i] <= coord[i-1])
637 Cerr <<
"Error in fonctions_coord parameter " << chaine <<
" : must be strictly increasing" << finl;
641 Cerr <<
" Build mesh covering [ " << coord[0] <<
" , " << coord[n-1] <<
" ]" << finl;
643 else if (fichier_coord[dir] !=
"??")
645 Cerr <<
" Reading file " << fichier_coord[dir] << finl;
649 for (
int i = 0; i < n; i++)
652 envoyer_broadcast(coord, 0);
653 Cerr <<
" Found mesh covering [ " << coord[0] <<
" , " << coord[n-1] <<
" ]" << finl;
657 Cerr <<
" Uniform mesh covering [0,1]" << finl;
658 for (
int i = 0; i < n; i++)
660 coord[i] = (double) i / (
double)(n-1);
666 if(!sub_type(Domaine, obj))
668 Cerr <<
"obj : " << nom_domaine <<
" is not an object of type Domaine !" << finl;
672 Domaine& domaine = ref_cast(Domaine, obj);
679 Cerr <<
"MaillerParallel::construire_domaine wrong dimension for nb_noeuds : nb_noeuds=" << nb_noeuds << finl;
686 Cerr <<
"MaillerParallel::construire_domaine wrong dimension for nb_noeuds : nb_noeuds=" << nb_noeuds << finl;
693 for (
int i = 0; i < dim; i++)
697 Cerr <<
"MaillerParallel::construire_domaine decoupage does not match nproc" << finl;
702 statistics().begin_count(STD_COUNTERS::parallel_meshing,statistics().get_last_opened_counter_level()+1);
704 ArrOfInt i_proc(dim);
711 for (i = 0; i < dim; i++)
714 const int n_parties = decoupage[i];
716 i_proc[i] = reste % n_parties;
717 reste = reste / n_parties;
724 Cerr <<
"Error: processor mapping should be of dimension " <<
Process::nproc() <<
" x 3" << finl;
727 i_proc[0] = mapping(numproc,0);
728 i_proc[1] = mapping(numproc,1);
729 i_proc[2] = mapping(numproc,2);
733 ArrOfInt i_premier_element(dim);
735 ArrOfInt nb_elements(dim);
738 for (i = 0; i < dim; i++)
740 const int nb_elem_tot = nb_noeuds[i] - 1;
741 i_premier_element[i] = nb_elem_tot * i_proc[i] / decoupage[i];
742 const int i_dernier_element = nb_elem_tot * (i_proc[i] + 1) / decoupage[i] - 1;
743 nb_elements[i] = i_dernier_element - i_premier_element[i] + 1;
745 if (perio[i] && decoupage[i] > 1)
747 int decalage = nb_elem_tot / decoupage[i] / 2;
748 i_premier_element[i] -= decalage;
753 Elem_geom& elem = domaine.type_elem();
757 elem.typer(
"Hexaedre");
760 Cerr <<
"MaillerParallel::construire_domaine erreur" << finl;
763 elem->associer_domaine(domaine);
766 Bords& bords = domaine.faces_bord();
769 for (
int dir = 0; dir < 3; dir++)
772 if (dir == 0) nomdir =
"x";
773 else if (dir == 1) nomdir =
"y";
779 bords.add(Bord()).nommer(data.
bord_xmin_[dir]);
781 domaine.bords_perio().add(data.
bord_xmin_[dir]);
785 bords.add(Bord()).nommer(data.
bord_xmin_[dir]);
786 bords.add(Bord()).nommer(data.
bord_xmax_[dir]);
793 for (
int i = 0; i < 3; i++)
795 if (i_premier_element[i] < 0)
800 for (num_bord = 0; num_bord < bords.size(); num_bord++)
802 Bord& bord = bords[num_bord];
804 bord.
faces().
typer(domaine.type_elem()->type_face());
810 for (ibloc[0] = 0; ibloc[0] < nblocs[0]; ibloc[0]++)
812 for (ibloc[1] = 0; ibloc[1] < nblocs[1]; ibloc[1]++)
814 for (ibloc[2] = 0; ibloc[2] < nblocs[2]; ibloc[2]++)
819 for (
int dir = 0; dir < 3; dir++)
821 data.
xmin_[dir] = i_premier_element[dir];
822 data.
xmax_[dir] = i_premier_element[dir] + nb_elements[dir] + 1;
842 for (
int d = 0; d < 3; d++)
847 dir[d] = coord_ijk[d][nb_noeuds[d]-1] - coord_ijk[d][0];
848 IntTab& faces = domaine.bord(nom_bords_min[d]).faces().les_sommets();
856 auto_build_joints(domaine, epaisseur_joint);
858 double maxtime =
mp_max(statistics().get_time_since_last_open(STD_COUNTERS::parallel_meshing));
859 statistics().end_count(STD_COUNTERS::parallel_meshing);
861 Cerr <<
"Ending of the construction of the domaines, time:" << maxtime << finl;
865 statistics().begin_count(STD_COUNTERS::parallel_meshing,statistics().get_last_opened_counter_level()+1);
868 maxtime =
mp_max(statistics().get_time_since_last_open(STD_COUNTERS::parallel_meshing));
869 statistics().end_count(STD_COUNTERS::parallel_meshing);
870 Cerr <<
"Scatter::construire_correspondance_sommets_par_coordonnees fin, time:"
872 statistics().begin_count(STD_COUNTERS::parallel_meshing,statistics().get_last_opened_counter_level()+1);
875 maxtime =
mp_max(statistics().get_time_since_last_open(STD_COUNTERS::parallel_meshing));
876 statistics().end_count(STD_COUNTERS::parallel_meshing);
877 Cerr <<
"Scatter::construire_structures_paralleles, time:" << maxtime << finl;
884 domaine.nommer(domaine.le_nom());
886 Cerr <<
"MaillerParallel::construire_domaine : end" << finl;
Fichier en lecture Cette classe est a la classe C++ ifstream ce que la classe Entree est a la.
Class defining operators and methods for all reading operation in an input flow (file,...
void typer(const Motcle &)
Type les faces.
int_t dimensionner(int_t)
(Re-)dimensionne les faces On redimensionne les voisins en consequence.
const IntTab_t & les_sommets() const
Renvoie le tableau des sommets de toutes les faces.
static int chercher_face_element(const IntTab_t &elem_som, const IntTab &faces_element_ref, const SmallArrOfTID_t &une_face, const int_t elem)
void nommer(const Nom &) override
Donne un nom a la frontiere.
void associer_domaine(const Domaine_t &)
Associe la frontiere au domaine dont elle depend.
const Faces_t & faces() const
void add(const Frontiere_32_64 &)
Ajoute les sommets (et faces) de la frontiere passee en parametre a l'objet (Frontiere_32_64).
Classe de base des objets "interprete".
static Objet_U & objet(const Nom &)
Voir Interprete_bloc::objet_global() BM: la classe Interprete n'est pas le meilleur endroit pour cett...
void affecte_epaisseur(int ep)
void affecte_PEvoisin(int num)
Joint_Items_t & set_joint_item(JOINT_ITEM type)
Renvoie les informations de joint pour un type d'item geometrique donne, pour remplissage des structu...
ArrOfInt_t & set_items_communs()
Renvoie le tableau items_communs_ pour le remplir.
Entree & interpreter(Entree &is) override
class Nom Une chaine de caractere pour nommer les objets de TRUST
Un tableau de chaine de caracteres (VECT(Nom)).
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
static double precision_geom
Objet_U()
Constructeur par defaut : attribue un numero d'identifiant unique a l'objet (object_id_),...
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
static int_t search_nodes_close_to(double x, double y, double z, const DoubleTab_t &coords, ArrOfInt_t &node_list, double epsilon)
Methode hors classe Cherche parmi les sommets de la liste node_list ceux qui sont a une.
void build_nodes(const DoubleTab_t &coords, const bool include_virtual, const double epsilon=0.)
construit un octree contenant les points de coordonnees coords.
int_t search_elements_box(double xmin, double ymin, double zmin, double xmax, double ymax, double zmax, ArrOfInt_t &elements) const
cherche tous les elements ou points ayant potentiellement une intersection non vide avec la boite don...
Helper class to factorize the readOn method of Objet_U classes.
void ajouter_flag(const char *keyword, const bool *value)
Register a boolean flag whose mere presence switches it to true.
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
int lire_avec_accolades(Entree &is)
Alias of lire_avec_accolades_depuis.
classe Parser_U Version de la classe Parser, derivant de Objet_U.
void setVar(const char *sv, double val)
void setString(const std::string &s)
void addVar(const char *v)
static double mp_max(double)
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
static void barrier()
Synchronise tous les processeurs du groupe courant (attend que tous les processeurs soient arrives a ...
static int me()
renvoie mon rang dans le groupe de communication courant.
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
static int reordonner_faces_periodiques(const Domaine_32_64< int > &domaine, IntTab_T< int > &faces, const ArrOfDouble &direction_perio, const double epsilon)
static void init_sequential_domain(Domaine_32_64< _SIZE_ > &dom)
Create parallel descriptors for the vertex and element arrays of the domain (necessary because Scatte...
static void construire_structures_paralleles(Domaine &dom)
Construction des structures paralleles du domaine et du domaine (determination des elements distants ...
static void calculer_renum_items_communs(Joints &joints, const JOINT_ITEM type_item)
On suppose que chaque joint[i].joint_item(type_item).items_communs() contient les indices locaux des ...
static void construire_correspondance_sommets_par_coordonnees(Domaine &dom, bool allow_resize=false)
Construction des tableaux joint_item(JOINT_ITEM::SOMMET).items_communs de tous les joints du domaine(...
static void trier_les_joints(Joints &joints)
Sort joints by increasing neighbor proc number.
void echange_taille_et_messages() const
Cette methode lance l'echange de donnees entre tous les processeurs.
Sortie & send_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y entasser des donnees a envoyer.
void end_comm() const
Vide les buffers et libere les ressources: on a fini de lire les donnees recues dans les buffers.
Entree & recv_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y lire les donnees recues.
void begin_comm() const
Reserve les buffers de comm pour une nouvelle communication.
void set_send_recv_pe_list(const ArrOfInt &send_pe_list, const ArrOfInt &recv_pe_list, const int me_to_me=0)
Definit la liste des processeurs a qui on va envoyer et de qui on va recevoir des donnees.
Classe de base des flux de sortie.
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
void resize_dim0(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
_SIZE_ dimension(int d) const
void add_faces(Domaine &domaine, const Nom &nombord, int offset_sommets, int dir, int cote_max) const
void add_bloc(Domaine &domaine, const ArrsOfDouble &coord_ijk) const