TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
MaillerParallel.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#include <MaillerParallel.h>
16#include <Domaine.h>
17#include <Motcle.h>
18#include <Scatter.h>
19#include <Param.h>
20#include <TRUSTArrays.h>
21#include <Parser_U.h>
22#include <Reordonner_faces_periodiques.h>
23#include <EFichier.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>
30#include <ArrOfBit.h>
31#include <Array_tools.h>
32#include <TRUST_Ref.h>
33#include <Joint.h>
34#include <Perf_counters.h>
35
36Implemente_instanciable(MaillerParallel, "MaillerParallel", Interprete);
37// XD maillerparallel interprete maillerparallel BRACE creates a parallel distributed hexaedral mesh of a
38// XD_CONT parallelipipedic box. It is equivalent to creating a mesh with a single Pave, splitting it with Decouper and
39// XD_CONT reloading it in parallel with Scatter. It only works in 3D at this time. It can also be used for a sequential
40// XD_CONT computation (with all NPARTS=1)}
41
43{
44 return is;
45}
46
48{
49 return os;
50}
51
53{
54 void add_bloc(Domaine& domaine, const ArrsOfDouble& coord_ijk) const;
55 // xmin_tot = 0 implicitement
56 // xmax_tot = nombre total de sommets dans le maillage
57 // xmax = indice du dernier sommet + 1
58 // xmin = indice du premier sommet (donc xmax - xmin = nombre de sommets du bloc courant)
59 ArrOfInt xmax_tot_;
60 ArrOfInt xmin_, xmax_;
62 inline int nb_som(int i) const
63 {
64 return xmax_[i] - xmin_[i];
65 }
66 inline int nb_elem(int i) const
67 {
68 return xmax_[i] - xmin_[i] - 1;
69 }
70 void add_faces(Domaine& domaine, const Nom& nombord, int offset_sommets, int dir, int cote_max) const;
71};
72
73void BlocData::add_bloc(Domaine& domaine, const ArrsOfDouble& coord_ijk) const
74{
75 if (nb_elem(0) < 1 || nb_elem(1) < 1 || nb_elem(2) < 1)
76 {
77 Cerr << "Error : not enough nodes in a block, increase mesh size or decrease processor count" << finl;
79 }
80 const int dim = 3;
81 // Les sommets
82 const int old_nb_som = domaine.les_sommets().dimension(0);
83 {
84 DoubleTab& sommets = domaine.les_sommets();
85 const int nsom = nb_som(0) * nb_som(1) * nb_som(2);
86 sommets.resize(old_nb_som + nsom, dim);
87
88 int index = old_nb_som;
89 int i, j, k;
90 for (k = xmin_[2]; k < xmax_[2]; k++)
91 {
92 for (j = xmin_[1]; j < xmax_[1]; j++)
93 {
94 for (i = xmin_[0]; i < xmax_[0]; i++)
95 {
96 sommets(index, 0) = coord_ijk[0][i];
97 sommets(index, 1) = coord_ijk[1][j];
98 if (dim==3)
99 sommets(index, 2) = coord_ijk[2][k];
100 index++;
101 }
102 }
103 }
104 }
105 // Les elements
106 {
107 assert(dim==3);
108 IntTab& elements = domaine.les_elems();
109 const int nb_som_par_element = 8;
110
111 // stride des indices de sommets:
112 const int dx = 1;
113 const int dy = nb_som(0);
114 const int dz = dy * nb_som(1);
115 // nombre d'elements dans chaque direction
116 const int nx = nb_elem(0);
117 const int ny = nb_elem(1);
118 const int nz = nb_elem(2);
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);
122
123 int index = nb_elem_old;
124 int i, j, k;
125 for (k = 0; k < nz; k++)
126 {
127 for (j = 0; j < ny; j++)
128 {
129 for (i = 0; i < nx; i++)
130 {
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;
140 index++;
141 }
142 }
143 }
144 }
145 // Les bords
146 for (int dir = 0; dir < 3; dir++)
147 {
148 if (xmin_[dir] == 0)
149 add_faces(domaine, bord_xmin_[dir], old_nb_som, dir, 0);
150 if (xmax_[dir] == xmax_tot_[dir])
151 add_faces(domaine, bord_xmax_[dir], old_nb_som, dir, 1);
152 }
153}
154
155void BlocData::add_faces(Domaine& domaine, const Nom& nombord, int offset_sommets, int dir, int cote_max) const
156{
157 int nfaces1, nfaces2;
158 int increment1, increment2;
159 int increment_dir;
160 switch(dir)
161 {
162 case 0:
163 nfaces1 = nb_elem(1);
164 nfaces2 = nb_elem(2);
165 increment1 = nb_som(0);
166 increment2 = nb_som(0) * nb_som(1);
167 increment_dir = 1;
168 break;
169 case 1:
170 nfaces1 = nb_elem(0);
171 nfaces2 = nb_elem(2);
172 increment1 = 1;
173 increment2 = nb_som(0) * nb_som(1);
174 increment_dir = nb_som(0);
175 break;
176 default:
177 nfaces1 = nb_elem(0);
178 nfaces2 = nb_elem(1);
179 increment1 = 1;
180 increment2 = nb_som(0);
181 increment_dir = nb_som(0)*nb_som(1);
182 break;
183 }
184 if (cote_max)
185 offset_sommets += increment_dir * (nb_som(dir)-1);
186
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++)
191 {
192 int sommet = offset_sommets;
193 for (int j = 0; j < nfaces1; j++)
194 {
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;
200 count++;
201 }
202 offset_sommets += increment2;
203 }
204}
205
206static int bbox_intersection(const DoubleTab& bboxes, int i, int j, double epsilon)
207{
208 const int dim = bboxes.dimension(1) / 2;
209 for (int k = 0; k < dim; k++)
210 {
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)
216 return 0;
217 }
218 return 1;
219}
220
221/*! @brief for a given set of local coordinates, finds which other processors share the same nodes.
222 *
223 * match must be sized to Process::nproc() and will be filled with, for each processor,
224 * the indexes of coordinates that the corresponding processor shares with me.
225 * Nodes are listed in the same order on couples of processors sharing a list of nodes
226 * match[Process::me()] will be left empty.
227 *
228 */
229void find_matching_coordinates(const DoubleTab& coords,
230 ArrsOfInt& match,
231 double epsilon)
232{
233 int i, j;
234 const int dim = coords.dimension(1);
235 const int ncoord = coords.dimension(0);
236 const int nproc = Process::nproc();
237 const int moi = Process::me();
238 // Fill nodes coordinates and bounding boxes
239 DoubleTab bounding_boxes(nproc, dim*2);
240 {
241 const double big_val = 1.e36;
242 ArrOfDouble min_coord(dim);
243 min_coord= big_val;
244 ArrOfDouble max_coord(dim);
245 max_coord= -big_val;
246
247 for (i = 0; i < ncoord; i++)
248 {
249 for (j = 0; j < dim; j++)
250 {
251 const double x = coords(i, j);
252 if (x > max_coord[j])
253 max_coord[j] = x;
254 if (x < min_coord[j])
255 min_coord[j] = x;
256 }
257 }
258 // broadcast a tous les processeurs
259 for (i = 0; i < nproc; i++)
260 {
261 for (j = 0; j < dim; j++)
262 {
263 bounding_boxes(i, j) = min_coord[j];
264 bounding_boxes(i, j+dim) = max_coord[j];
265 }
266 }
267 envoyer_all_to_all(bounding_boxes, bounding_boxes);
268 }
269 // Exchange boundary nodes coordinates with other processors
270 ArrOfInt all_pe;
271
272 for (i = 0; i < nproc; i++)
273 if (i != moi && bbox_intersection(bounding_boxes, moi, i, epsilon))
274 all_pe.append_array(i);
275
276 Schema_Comm schema;
277 schema.set_send_recv_pe_list(all_pe, all_pe);
278 schema.begin_comm();
279 Octree_Double octree;
280 octree.build_nodes(coords, 0 /* do not include virtual nodes */);
281
282 // Send nodes coordinates to processors with non empty intersection
283 // temporary array for octree functions:
284 ArrOfInt nodes_list;
285
286 int ipe;
287 for (ipe = 0; ipe < all_pe.size_array(); ipe++)
288 {
289 // Search nodes within the bounding box of the other processor:
290 const int pe = all_pe[ipe]; // processor number
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;
297 octree.search_elements_box(xmin, ymin, zmin, xmax, ymax, zmax, nodes_list);
298
299 Sortie& buffer = schema.send_buffer(pe);
300 const int n = nodes_list.size_array();
301 for (i = 0; i < n; i++)
302 {
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;
307 // test again if inside bounding box (octree test gives more nodes)
308 if (x>=xmin && x<=xmax && y>=ymin && y<=ymax && z>=zmin && z<=zmax)
309 {
310 buffer << x << y << z;
311 }
312 }
313 }
315 for (ipe = 0; ipe < all_pe.size_array(); ipe++)
316 {
317 const int pe = all_pe[ipe]; // processor number
318 Entree& buffer = schema.recv_buffer(pe);
319 ArrOfInt& resu = match[pe];
320
321 resu.resize_array(0);
322 while(1)
323 {
324 double x, y, z;
325 buffer >> x >> y >> z;
326 if (buffer.eof())
327 break;
328 // Seach for this node in my list
329 octree.search_elements_box(x-epsilon, y-epsilon, z-epsilon,
330 x+epsilon, y+epsilon, z+epsilon, nodes_list);
331 // Refine search to keep only matching nodes:
332 octree.search_nodes_close_to(x, y, z, coords, nodes_list, epsilon);
333 const int n = nodes_list.size_array();
334 if (n > 1)
335 {
336 Cerr << "Error in automatic joint builder: more than one node within epsilon tolerance\n"
337 << " node coord = " << x << " " << y << " " << z << " tolerance= " << epsilon << finl;
339 }
340 if (n == 1)
341 resu.append_array(nodes_list[0]);
342 }
343 }
344 schema.end_comm();
345}
346
347/*! @brief finds all faces of all elements that - have only one neighbour elements
348 *
349 * - and do not belong to a boundary
350 * (these are joint faces)
351 * Fills "faces" with the local node numbers of the faces that have been found.
352 *
353 */
354static void find_joint_faces(const Domaine& domaine, IntTab& faces)
355{
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 /* do not include virtual elements */);
360 const int nb_som_faces = domaine.type_elem()->nb_som_face();
361 faces.resize(0, nb_som_faces);
362
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);
366 // Mark faces of elements that are on a boundary
367 const int nb_elem = elements.dimension(0);
368 ArrOfBit boundary_faces(nb_elem * nb_faces_elem);
369 boundary_faces = 0;
370 ArrOfInt une_face(nb_som_faces);
371 ArrOfInt liste_elements;
372
373 const int nb_boundaries = domaine.nb_front_Cl();
374 for (int i_boundary = 0; i_boundary < nb_boundaries; i_boundary++)
375 {
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++)
379 {
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);
383 if (liste_elements.size_array() != 1)
384 {
385 Cerr << "Error in MaillerParallel::find_joint_faces: boundary face ArrOfInt=" << une_face
386 << " does not have exactly 1 neighbour element: " << liste_elements;
388 }
389 const int elem = liste_elements[0];
390 const int face_locale = Faces_builder::chercher_face_element(elements, faces_element_reference, une_face, elem);
391 boundary_faces.setbit(elem * nb_faces_elem + face_locale);
392 }
393 }
394 // Browse all faces of all elements, find faces with only one neighbour
395 for (int elem = 0; elem < nb_elem; elem++)
396 {
397 for (int face_locale = 0; face_locale < nb_faces_elem; face_locale++)
398 {
399 if (boundary_faces[elem * nb_faces_elem + face_locale])
400 continue;
401 int i;
402 for (i = 0; i < nb_som_faces; i++)
403 {
404 const int sommet_local = faces_element_reference(face_locale, i);
405 une_face[i] = elements(elem, sommet_local);
406 }
407 find_adjacent_elements(som_elem, une_face, liste_elements);
408 if (liste_elements.size_array() == 1)
409 {
410 const int n = faces.dimension(0);
411 faces.resize_dim0(n+1);
412 for (i = 0; i < nb_som_faces; i++)
413 faces(n, i) = une_face[i];
414 }
415 }
416 }
417 Process::Journal() << "Domain " << domaine.le_nom() << " has " << faces.dimension(0) << " undeclared boundary faces candidates for joint faces" << finl;
418}
419
420static void auto_build_joints(Domaine& domaine, const int epaisseur_joint)
421{
422 const double epsilon = 1e-10;
423 int i, j;
424 // Find joint faces (faces with 1 neighbour element not registered in boundary faces)
425 IntTab faces;
426 find_joint_faces(domaine, faces);
427
428 const DoubleTab& sommets = domaine.les_sommets();
429 // List of unique local boundary node numbers
430 const int dim = sommets.dimension(1);
431
432 {
433 ArrOfInt boundary_nodes_index;
434 boundary_nodes_index = faces; // copie du tableau
435 array_trier_retirer_doublons(boundary_nodes_index);
436 const int ncoord = boundary_nodes_index.size_array();
437 // Fill nodes coordinates and bounding boxes
438 DoubleTab coord;
439 coord.resize(ncoord, dim, RESIZE_OPTIONS::NOCOPY_NOINIT);
440 for (i = 0; i < ncoord; i++)
441 {
442 const int som = boundary_nodes_index[i];
443 for (j = 0; j < dim; j++)
444 coord(i, j) = sommets(som, j);
445 }
446 ArrsOfInt match(Process::nproc());
447 find_matching_coordinates(coord, match, epsilon);
448
449 for (int pe = 0; pe < match.size(); pe++)
450 {
451 const ArrOfInt& list = match[pe];
452 const int n = list.size_array();
453 if (n > 0)
454 {
455 Joint& joint = domaine.faces_joint().add(Joint());
456 joint.nommer("Joint_i");
457 joint.associer_domaine(domaine);
458 joint.affecte_epaisseur(epaisseur_joint);
459 joint.affecte_PEvoisin(pe);
460 joint.faces().typer(domaine.type_elem()->type_face());
461 ArrOfInt& sommets_joint = joint.set_joint_item(JOINT_ITEM::SOMMET).set_items_communs();
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]];
465 sommets_joint.ordonne_array();
466 Process::Journal() << "Joint sommets with pe " << pe << " has " << n << " nodes" << finl;
467 }
468 }
469 }
470
471 {
472 // Find matching faces (match the coordinates of the centers)
473 const int nfaces = faces.dimension(0);
474 const int nb_som_faces = faces.dimension(1);
475 DoubleTab coord(nfaces, dim); // init with 0.
476 const double facteur = 1. / (double)nb_som_faces;
477 for (i = 0; i < nfaces; i++)
478 {
479 for (j = 0; j < nb_som_faces; j++)
480 {
481 const int som = faces(i,j);
482 for (int k = 0; k < dim; k++)
483 coord(i, k) += sommets(som, k) * facteur;
484 }
485 }
486 ArrsOfInt match(Process::nproc());
487 find_matching_coordinates(coord, match, epsilon);
488
489 for (int pe = 0; pe < match.size(); pe++)
490 {
491 const ArrOfInt& list = match[pe];
492 const int n = list.size_array();
493 if (n > 0)
494 {
495 OBS_PTR(Joint) ref_joint;
496 int ii;
497 for (ii = 0; ii < domaine.faces_joint().size(); ii++)
498 {
499 Joint& joint = domaine.faces_joint()[ii];
500 if (joint.PEvoisin() == pe)
501 {
502 ref_joint = joint;
503 break;
504 }
505 }
506 if (!ref_joint)
507 {
508 Joint& joint = domaine.faces_joint().add(Joint());
509 joint.nommer("Joint_i");
510 joint.associer_domaine(domaine);
511 joint.affecte_epaisseur(epaisseur_joint);
512 joint.affecte_PEvoisin(pe);
513 joint.faces().typer(domaine.type_elem()->type_face());
514 ref_joint = joint;
515 }
516 Faces& les_faces = ref_joint->faces();
517 les_faces.dimensionner(n);
518 IntTab& faces_sommets = les_faces.les_sommets();
519 for (ii = 0; ii < n; ii++)
520 {
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);
524 }
525 Process::Journal() << "Joint faces with pe " << pe << " has " << n << " faces" << finl;
526 }
527 }
528 }
529 // Tri des joints dans l'ordre croissant des processeurs
530 Scatter::trier_les_joints(domaine.faces_joint());
531}
532
534{
535 if (dimension != 3)
536 {
537 Cerr << "Error: MaillerParallel is only coded for dimension 3" << finl;
538 barrier();
539 exit();
540 }
541
542 Nom nom_domaine;
543 ArrOfInt nb_noeuds;
544 ArrOfInt decoupage;
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);
557 IntTab mapping;
558
559 Param param(que_suis_je());
560 param.ajouter("domain", &nom_domaine, Param::REQUIRED); // XD_ADD_P ref_domaine
561 // XD_CONT the name of the domain to mesh (it must be an empty domain object).
562 param.ajouter("nb_nodes", &nb_noeuds, Param::REQUIRED); // XD_ADD_P listentier
563 // XD_CONT dimension defines the spatial dimension (currently only dimension=3 is supported), and nX, nY and nZ
564 // XD_CONT defines the total number of nodes in the mesh in each direction.
565 param.ajouter("splitting", &decoupage, Param::REQUIRED); // XD_ADD_P listentier
566 // XD_CONT dimension is the spatial dimension and npartsX, npartsY and npartsZ are the number of parts created. The
567 // XD_CONT product of the number of parts must be equal to the number of processors used for the computation.
568 param.ajouter("ghost_thickness", &epaisseur_joint, Param::REQUIRED); // XD_ADD_P entier
569 // XD_CONT the number of ghost cells (equivalent to the epaisseur_joint parameter of Decouper.
570 param.ajouter_flag("perio_x", &perio[0]); // XD_ADD_P rien
571 // XD_CONT change the splitting method to provide a valid mesh for periodic boundary conditions. Register the
572 // XD_CONT corresponding boundary in the list of periodic boundaries for the domain.
573 param.ajouter_flag("perio_y", &perio[1]); // XD_ADD_P rien
574 // XD_CONT change the splitting method to provide a valid mesh for periodic boundary conditions. Register the
575 // XD_CONT corresponding boundary in the list of periodic boundaries for the domain.
576 param.ajouter_flag("perio_z", &perio[2]); // XD_ADD_P rien
577 // XD_CONT change the splitting method to provide a valid mesh for periodic boundary conditions. Register the
578 // XD_CONT corresponding boundary in the list of periodic boundaries for the domain.
579 param.ajouter("function_coord_x", &fonctions_coord[0]); // XD_ADD_P chaine
580 // XD_CONT By default, the meshing algorithm creates nX nY nZ coordinates ranging between 0 and 1 (eg a unity size
581 // XD_CONT box). If function_coord_x} is specified, it is used to transform the [0,1] segment to the coordinates of
582 // XD_CONT the nodes. funcX must be a function of the x variable only.
583 param.ajouter("function_coord_y", &fonctions_coord[1]); // XD_ADD_P chaine
584 // XD_CONT like function_coord_x for y
585 param.ajouter("function_coord_z", &fonctions_coord[2]); // XD_ADD_P chaine
586 // XD_CONT like function_coord_x for z
587 param.ajouter("file_coord_x", &fichier_coord[0]); // XD_ADD_P chaine
588 // XD_CONT Keyword to read the Nx floating point values used as nodes coordinates in the file.
589 param.ajouter("file_coord_y", &fichier_coord[1]); // XD_ADD_P chaine
590 // XD_CONT idem file_coord_x for y
591 param.ajouter("file_coord_z", &fichier_coord[2]); // XD_ADD_P chaine
592 // XD_CONT idem file_coord_x for z
593 param.ajouter("boundary_xmin", &nom_bords_min[0]); // XD_ADD_P chaine
594 // XD_CONT the name of the boundary at the minimum X direction. If it not provided, the default boundary names are
595 // XD_CONT xmin, xmax, ymin, ymax, zmin and zmax. If the mesh is periodic in a given direction, only the MIN boundary
596 // XD_CONT name is used, for both sides of the box.
597 param.ajouter("boundary_xmax", &nom_bords_max[0]); // XD_ADD_P chaine
598 // XD_CONT not_set
599 param.ajouter("boundary_ymin", &nom_bords_min[1]); // XD_ADD_P chaine
600 // XD_CONT not_set
601 param.ajouter("boundary_ymax", &nom_bords_max[1]); // XD_ADD_P chaine
602 // XD_CONT not_set
603 param.ajouter("boundary_zmin", &nom_bords_min[2]); // XD_ADD_P chaine
604 // XD_CONT not_set
605 param.ajouter("boundary_zmax", &nom_bords_max[2]); // XD_ADD_P chaine
606 // XD_CONT not_set
607 param.ajouter("mapping", &mapping);
608 param.lire_avec_accolades(is);
609
610
611 ArrsOfDouble coord_ijk(3);
612 for (int dir=0; dir<3; dir++)
613 {
614 const int n = nb_noeuds[dir];
615 ArrOfDouble& coord = coord_ijk[dir];
616 coord.resize_array(n);
617 Cerr << "Building coordinates for direction " << dir << finl;
618 if (fonctions_coord[dir] != "??")
619 {
620 Nom chaine = fonctions_coord[dir];
621 Cerr << " Interpreting expression " << chaine << finl;
622 Parser_U p;
623 Noms noms_dir(3);
624 noms_dir[0]="X";
625 noms_dir[1]="Y";
626 noms_dir[2]="Z";
627 p.setNbVar(1);
628 p.setString(chaine);
629 p.addVar(noms_dir[dir]);
630 p.parseString();
631 for (int i = 0; i < n; i++)
632 {
633 p.setVar(0, (double) i / (double) (nb_noeuds[dir]-1));
634 coord[i] = p.eval();
635 if (i > 0 && coord[i] <= coord[i-1])
636 {
637 Cerr << "Error in fonctions_coord parameter " << chaine << " : must be strictly increasing" << finl;
639 }
640 }
641 Cerr << " Build mesh covering [ " << coord[0] << " , " << coord[n-1] << " ]" << finl;
642 }
643 else if (fichier_coord[dir] != "??")
644 {
645 Cerr << " Reading file " << fichier_coord[dir] << finl;
647 {
648 EFichier f(fichier_coord[dir]);
649 for (int i = 0; i < n; i++)
650 f >> coord[i];
651 }
652 envoyer_broadcast(coord, 0);
653 Cerr << " Found mesh covering [ " << coord[0] << " , " << coord[n-1] << " ]" << finl;
654 }
655 else
656 {
657 Cerr << " Uniform mesh covering [0,1]" << finl;
658 for (int i = 0; i < n; i++)
659 {
660 coord[i] = (double) i / (double)(n-1);
661 }
662 }
663 }
664
665 Objet_U& obj = objet(nom_domaine);
666 if(!sub_type(Domaine, obj))
667 {
668 Cerr << "obj : " << nom_domaine << " is not an object of type Domaine !" << finl;
669 exit();
670 }
671
672 Domaine& domaine = ref_cast(Domaine, obj);
673
674 const int numproc = Process::me();
675
676 const int dim = Objet_U::dimension;
677 if (nb_noeuds.size_array() != dim)
678 {
679 Cerr << "MaillerParallel::construire_domaine wrong dimension for nb_noeuds : nb_noeuds=" << nb_noeuds << finl;
680 barrier();
681 exit();
682 }
683
684 if (decoupage.size_array() != dim)
685 {
686 Cerr << "MaillerParallel::construire_domaine wrong dimension for nb_noeuds : nb_noeuds=" << nb_noeuds << finl;
687 barrier();
688 exit();
689 }
690
691 {
692 int n = 1;
693 for (int i = 0; i < dim; i++)
694 n *= decoupage[i];
695 if (n != Process::nproc())
696 {
697 Cerr << "MaillerParallel::construire_domaine decoupage does not match nproc" << finl;
698 barrier();
699 exit();
700 }
701 }
702 statistics().begin_count(STD_COUNTERS::parallel_meshing,statistics().get_last_opened_counter_level()+1);
703 // Position du bloc correspondant a numproc dans le decoupage i,j,k:
704 ArrOfInt i_proc(dim);
705 if (mapping.dimension(0) == 0)
706 {
707 // Pas de mapping fourni, on prend decoupe par defaut
708 int i;
709 int reste = numproc;
710
711 for (i = 0; i < dim; i++)
712 {
713 // Nombre de parties dans la direction dim_2:
714 const int n_parties = decoupage[i];
715 // Position du processeur courant dans cette direction:
716 i_proc[i] = reste % n_parties;
717 reste = reste / n_parties;
718 }
719 }
720 else
721 {
722 if (mapping.dimension(0) != Process::nproc() || mapping.dimension(1) != 3)
723 {
724 Cerr << "Error: processor mapping should be of dimension " << Process::nproc() << " x 3" << finl;
726 }
727 i_proc[0] = mapping(numproc,0);
728 i_proc[1] = mapping(numproc,1);
729 i_proc[2] = mapping(numproc,2);
730 }
731 // Indice du premier element du bloc associe au processeur dans la direction i:
732 // Attention, en cas de periodique, i_premier_element sera negatif.
733 ArrOfInt i_premier_element(dim);
734 // Taille du bloc associe au processeur
735 ArrOfInt nb_elements(dim);
736 {
737 int i;
738 for (i = 0; i < dim; i++)
739 {
740 const int nb_elem_tot = nb_noeuds[i] - 1; // Nb total de noeuds dans la direction i
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;
744
745 if (perio[i] && decoupage[i] > 1)
746 {
747 int decalage = nb_elem_tot / decoupage[i] / 2;
748 i_premier_element[i] -= decalage;
749 }
750 }
751 }
752
753 Elem_geom& elem = domaine.type_elem();
754 switch(dim)
755 {
756 case 3:
757 elem.typer("Hexaedre");
758 break;
759 default:
760 Cerr << "MaillerParallel::construire_domaine erreur" << finl;
761 exit();
762 }
763 elem->associer_domaine(domaine);
764
765 BlocData data;
766 Bords& bords = domaine.faces_bord();
767 data.bord_xmin_ = nom_bords_min;
768 data.bord_xmax_ = nom_bords_max;
769 for (int dir = 0; dir < 3; dir++)
770 {
771 Nom nomdir;
772 if (dir == 0) nomdir = "x";
773 else if (dir == 1) nomdir = "y";
774 else nomdir = "z";
775 if (perio[dir])
776 {
777 // In case of a periodic boundary only 'min' should be named:
778 data.bord_xmax_[dir] = data.bord_xmin_[dir];
779 bords.add(Bord()).nommer(data.bord_xmin_[dir]);
780 // And the name is added to the list of periodic boundaries in the domain:
781 domaine.bords_perio().add(data.bord_xmin_[dir]);
782 }
783 else
784 {
785 bords.add(Bord()).nommer(data.bord_xmin_[dir]);
786 bords.add(Bord()).nommer(data.bord_xmax_[dir]);
787 }
788 }
789 data.xmax_tot_ = nb_noeuds;
790
791 ArrOfInt nblocs(3);
792 nblocs= 1;
793 for (int i = 0; i < 3; i++)
794 {
795 if (i_premier_element[i] < 0)
796 nblocs[i] = 2;
797 }
798
799 int num_bord;
800 for (num_bord = 0; num_bord < bords.size(); num_bord++)
801 {
802 Bord& bord = bords[num_bord];
803 bord.associer_domaine(domaine);
804 bord.faces().typer(domaine.type_elem()->type_face());
805 // important pour dimensionner le linesize du tableau des faces pour les frontieres vides
806 bord.faces().dimensionner(0);
807 }
808
809 ArrOfInt ibloc(3);
810 for (ibloc[0] = 0; ibloc[0] < nblocs[0]; ibloc[0]++)
811 {
812 for (ibloc[1] = 0; ibloc[1] < nblocs[1]; ibloc[1]++)
813 {
814 for (ibloc[2] = 0; ibloc[2] < nblocs[2]; ibloc[2]++)
815 {
816
817 data.xmin_.resize_array(3);
818 data.xmax_.resize_array(3);
819 for (int dir = 0; dir < 3; dir++)
820 {
821 data.xmin_[dir] = i_premier_element[dir];
822 data.xmax_[dir] = i_premier_element[dir] + nb_elements[dir] + 1;
823
824 if (nblocs[dir] > 1)
825 {
826 if (ibloc[dir] == 0)
827 data.xmin_[dir] = 0;
828 else
829 {
830 data.xmin_[dir] += data.xmax_tot_[dir] - 1;
831 data.xmax_[dir] = data.xmax_tot_[dir];
832 }
833 }
834 }
835 Process::Journal() << "add bloc xmin=" << data.xmin_ << "xmax=" << data.xmax_ << "xtot=" << data.xmax_tot_;
836 data.add_bloc(domaine, coord_ijk);
837 }
838 }
839 }
840
841 {
842 for (int d = 0; d < 3; d++)
843 {
844 if (perio[d])
845 {
846 ArrOfDouble dir(3);
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();
849 double epsilon = precision_geom;
851 }
852 }
853 }
854
855
856 auto_build_joints(domaine, epaisseur_joint);
857
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;
862
863 if (nproc() > 1)
864 {
865 statistics().begin_count(STD_COUNTERS::parallel_meshing,statistics().get_last_opened_counter_level()+1);
867 Scatter::calculer_renum_items_communs(domaine.faces_joint(), JOINT_ITEM::SOMMET);
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:"
871 << maxtime << finl;
872 statistics().begin_count(STD_COUNTERS::parallel_meshing,statistics().get_last_opened_counter_level()+1);
874
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;
878 }
879 else
880 {
882 }
883
884 domaine.nommer(domaine.le_nom());
885
886 Cerr << "MaillerParallel::construire_domaine : end" << finl;
887
888 return is;
889}
Fichier en lecture Cette classe est a la classe C++ ifstream ce que la classe Entree est a la.
Definition EFichier.h:29
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual int eof()
Definition Entree.cpp:256
void typer(const Motcle &)
Type les faces.
Definition Faces.cpp:390
int_t dimensionner(int_t)
(Re-)dimensionne les faces On redimensionne les voisins en consequence.
Definition Faces.cpp:344
const IntTab_t & les_sommets() const
Renvoie le tableau des sommets de toutes les faces.
Definition Faces.h:74
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.
Definition Frontiere.cpp:74
void associer_domaine(const Domaine_t &)
Associe la frontiere au domaine dont elle depend.
Definition Frontiere.cpp:63
const Faces_t & faces() const
Definition Frontiere.h:54
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".
Definition Interprete.h:38
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)
Definition Joint.h:48
void affecte_PEvoisin(int num)
Definition Joint.h:47
Joint_Items_t & set_joint_item(JOINT_ITEM type)
Renvoie les informations de joint pour un type d'item geometrique donne, pour remplissage des structu...
Definition Joint.cpp:103
int PEvoisin() const
Definition Joint.h:49
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
Definition Nom.h:31
Un tableau de chaine de caracteres (VECT(Nom)).
Definition Noms.h:26
friend class Entree
Definition Objet_U.h:76
static int dimension
Definition Objet_U.h:99
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
static double precision_geom
Definition Objet_U.h:86
Objet_U()
Constructeur par defaut : attribue un numero d'identifiant unique a l'objet (object_id_),...
Definition Objet_U.cpp:55
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
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.
Definition Param.h:112
void ajouter_flag(const char *keyword, const bool *value)
Register a boolean flag whose mere presence switches it to true.
Definition Param.cpp:474
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
@ REQUIRED
Definition Param.h:115
int lire_avec_accolades(Entree &is)
Alias of lire_avec_accolades_depuis.
Definition Param.h:577
classe Parser_U Version de la classe Parser, derivant de Objet_U.
Definition Parser_U.h:32
void setVar(const char *sv, double val)
Definition Parser_U.h:149
void setString(const std::string &s)
Definition Parser_U.h:194
void setNbVar(int nvar)
Definition Parser_U.h:174
void parseString()
Definition Parser_U.h:116
double eval()
Definition Parser_U.h:125
void addVar(const char *v)
Definition Parser_U.h:183
static double mp_max(double)
Definition Process.cpp:376
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
static void barrier()
Synchronise tous les processeurs du groupe courant (attend que tous les processeurs soient arrives a ...
Definition Process.cpp:136
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
Definition Process.cpp:86
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...
Definition Scatter.cpp:2742
static void construire_structures_paralleles(Domaine &dom)
Construction des structures paralleles du domaine et du domaine (determination des elements distants ...
Definition Scatter.cpp:672
static void calculer_renum_items_communs(Joints &joints, const JOINT_ITEM type_item)
On suppose que chaque joint[i].joint_item(type_item).items_communs() contient les indices locaux des ...
Definition Scatter.cpp:1222
static void construire_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(...
Definition Scatter.cpp:2678
static void trier_les_joints(Joints &joints)
Sort joints by increasing neighbor proc number.
Definition Scatter.cpp:712
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.
Definition Sortie.h:52
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
void ordonne_array()
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
void resize_dim0(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:459
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
int size() const
int nb_elem(int i) const
void add_faces(Domaine &domaine, const Nom &nombord, int offset_sommets, int dir, int cote_max) const
ArrOfInt xmin_
void add_bloc(Domaine &domaine, const ArrsOfDouble &coord_ijk) const
int nb_som(int i) const
ArrOfInt xmax_tot_
ArrOfInt xmax_