TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Scatter.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
17#include <Scatter.h>
18#include <Domaine.h>
19#include <LecFicDistribueBin.h>
20#include <TRUSTTabs.h>
21#include <Connectivite_som_elem.h>
22#include <Schema_Comm.h>
23#include <Faces_builder.h>
24#include <Domaine_VF.h>
25#include <Reordonner_faces_periodiques.h>
26#include <communications.h>
27#include <MD_Vector_tools.h>
28#include <MD_Vector_std.h>
29#include <MD_Vector_seq.h>
30#include <unistd.h> // PGI
31#include <Poly_geom_base.h>
32#include <Entree_Brute.h>
33#include <Comm_Group_MPI.h>
34#include <FichierHDFPar.h>
35#include <LecFicDiffuse.h>
36#include <Format_Post_Lata.h>
37#include <EFichierBin.h>
38#include <Array_tools.h>
39#include <Perf_counters.h>
40#include <vector>
41#include <numeric>
42
43Implemente_instanciable(Scatter,"Scatter",Interprete);
44// XD scatter interprete scatter NO_BRACE Class to read a partionned mesh from the files during a parallel calculation.
45// XD_CONT The files are in binary format.
46// XD attr file chaine file REQ Name of file.
47// XD attr domaine ref_domaine domaine REQ Name of domain.
48
49/*! @brief Simple appel a: Interprete::printOn(Sortie&)
50 *
51 * @param (Sortie& os) un flot de sortie
52 * @return (Sortie&) le flot de sortie modifie
53 */
55{
56 return Interprete::printOn(os);
57}
58
59
60/*! @brief Simple appel a: Interprete::readOn(Entree&)
61 *
62 * @param (Entree& is) un flot d'entree
63 * @return (Entree&) le flot d'entree modifie
64 */
66{
67 return Interprete::readOn(is);
68}
69
70/*! @brief Renvoi le domaine associe
71 *
72 */
74{
75 return le_domaine.valeur();
76}
77
78namespace
79{
80// For debug:
81void dump_lata(const Domaine& dom)
82{
83 Format_Post_Lata post; // Lata V2
84 Nom nom_fichier_lata("espaces_virtuels");
85
86 const int nb_joints = dom.nb_joints();
87 constexpr int IS_FIRST = 1;
88
90 post.ecrire_entete(0.0, 0, IS_FIRST);
91 post.ecrire_domaine(dom, IS_FIRST);
92 post.ecrire_temps(0.0);
93
94 Noms units, noms_compo;
95 units.add("");
96 noms_compo.add("I");
97 DoubleTab data(dom.nb_elem());
98 for(int ij = 0; ij < nb_joints; ij++)
99 {
100 const ArrOfInt& t1 = dom.joint(ij).joint_item(JOINT_ITEM::ELEMENT).items_distants();
101 data = 0.;
102 const int nt1 = t1.size_array();
103 for (int i = 0; i < nt1; i++) data[t1[i]] += 1;
104
105 post.ecrire_champ(dom,
106 units,
107 noms_compo,
108 1, // ncomp,
109 0.0, // temps,
110 Nom("partition") + Nom(dom.joint(ij).PEvoisin()), // id_du_champ,
111 dom.le_nom(), // id_du_domaine
112 "ELEM", // localisation,
113 "scalar", // nature,
114 data // valeurs
115 );
116 }
117}
118} // end anonymous namespace
119
120/*! @brief Lit et complete un domaine parallele selon les motcles lus dans le jeu de donnees.
121 *
122 * Format:
123 * Scatter [debug] file_name domain_name
124 * On lit les sommets, les elements et les sommets et faces de joint,
125 * On construit les espaces distants et virtuels en fonction
126 * de l'epaisseur de joint.
127 */
129{
130 // Nom des fichiers de decoupage : nomentree.xxxx
131 Nom nomentree;
132 is >> nomentree;
134 {
135 Motcle n(nomentree);
136 if (n != ";" && n != "unlock;")
137 {
138 Cerr << "Error ! You ran a sequential calculation and can't use Scatter keyword here. Run a parallel calculation or remove this keyword." << finl;
139 exit();
140 }
141 Cerr << "Scatter: preparing domain structure\n"
142 << " (this is workaround for bugged domain operators that don't do it)" << finl;
143 Nom nomdomaine;
144 is >> nomdomaine;
145 Objet_U& obj = objet(nomdomaine);
146 if(!sub_type(Domaine, obj))
147 {
148 Cerr << "obj : " << obj << " is not an object of type Domain !" << finl;
149 exit();
150 }
151 Domaine& dom = ref_cast(Domaine, obj);
152 if (n == ";")
154 else
156 return is;
157 }
158 // Pour debugger sur linux en parallele
159#ifdef linux
160 static int gdb_non_lance=1;
161 char* TRUST_GDB=getenv("TRUST_GDB");
162 if (gdb_non_lance && ((Motcle)nomentree=="DEBUG" || TRUST_GDB!=nullptr))
163 {
164 gdb_non_lance=0;
165 if ((Motcle)nomentree=="DEBUG") is >> nomentree;
166 if (je_suis_maitre())
167 {
168 Cerr << "Enter \"return\" to this window after" << finl;
169 Cerr << "typing \"cont\" in other gdb windows." << finl;
170 Cerr << (int)system ("sh -c read ok") << finl;
171 }
172 else
173 {
174 Nom getpidn((int)getpid());
175 Nom cmdfile=getpidn;
176 Nom command0="echo attach ";
177 command0+=getpidn;
178 command0+=" > ";
179 command0+=cmdfile;
180 Cerr << (int)system(command0) << finl;
181 command0=" ls -l /proc/";
182 command0+=getpidn;
183 command0+="/exe | awk '{print $NF}' > execname";
184 Cerr << (int)system(command0) << finl;
185 Nom command="[ -f /usr/X11R6/bin/xterm ] && x=\"/usr/X11R6/bin/xterm -exec gdb -x \";";
186 command+="[ -f /usr/bin/konsole ] && x=\"/usr/bin/konsole -e gdb -x \";";
187 command+="$x ";
188 command+=cmdfile;
189 command+=" `cat execname` ";
190 command+=" &";
191 Cerr<<"command: " <<command<<finl;
192 Cerr << (int)system(command) << finl;
193 }
194 }
195#endif
196 barrier();
197
199 Cerr << "Execution of the Scatter module." << finl;
200
201 statistics().begin_count(STD_COUNTERS::interprete_scatter,statistics().get_last_opened_counter_level()+1);
202 // On recupere le domaine:
203 Nom nomdomaine;
204 is >> nomdomaine;
205 Objet_U& obj = objet(nomdomaine);
206 if(!sub_type(Domaine, obj))
207 {
208 Cerr << "Error in Scatter: object of type '" << obj.que_suis_je() << "' when Domaine was expected!" << finl;
209 exit();
210 }
211 Domaine& dom = ref_cast(Domaine, obj);
212 le_domaine = dom;
213
214 // Lecture des fichiers de decoupage :
215 barrier();
217 Cerr << "Reading the domain" << finl;
218
219 lire_domaine(nomentree);
220
221 barrier();
222 Cerr << "Calculation of renum_items_communs for the nodes" << finl;
223 calculer_renum_items_communs(dom.faces_joint(), JOINT_ITEM::SOMMET);
224
225 // Pas encore code: on verifie que les sommets communs ont des coordonnees identiques
226 // sur tous les processeurs.
227 // check_sommets_joints(dom);
228
229 barrier();
230 Cerr << "Construire_structures_paralleles" << finl;
232
233 if (0)
234 dump_lata(dom);
235
236 barrier();
237 Cerr << "End Distribue_domaines" << finl;
238
239 Cerr << "\nQuality of partitioning --------------------------------------------" << finl;
240 trustIdType total_nb_elem = Process::mp_sum(dom.nb_elem());
241 Cerr << "\nTotal nb of elements = " << total_nb_elem << finl;
242 Cerr << "Number of Domaines : " << Process::nproc() << finl;
243 double min_element_domaine = mp_min(dom.nb_elem());
244 double max_element_domaine = mp_max(dom.nb_elem());
245 double mean_element_domaine = (double)(total_nb_elem / Process::nproc());
246 Cerr << "Min number of elements on a Domaine = " << min_element_domaine << finl;
247 Cerr << "Max number of elements on a Domaine = " << max_element_domaine << finl;
248 Cerr << "Mean number of elements per Domaine = " << (int)(mean_element_domaine) << finl;
249 double load_imbalance = max_element_domaine / mean_element_domaine;
250 Cerr << "Load imbalance = " << load_imbalance << "\n" << finl;
251
252 Elem_geom_base& elem=dom.type_elem().valeur();
253 if (sub_type(Poly_geom_base,elem))
254 ref_cast(Poly_geom_base,elem).compute_virtual_index();
255 if(Process::me()==0)
256 {
257 double temps = statistics().get_time_since_last_open(STD_COUNTERS::interprete_scatter);
258 Cerr << "Scatter time : " << temps << finl;
259 }
260 statistics().end_count(STD_COUNTERS::interprete_scatter);
261 return is;
262}
263
264/*! @brief Merged domains receive joint information from their neighbours to ensure that their common items (vertices) appear in the same order
265 *
266 * If it's not the case, the merged domain reorders its common items so that it matches the neighbour's order
267 * When 2 neighbouring domains have each been merged,
268 * only the processor with the lowest rank proceeds to reordering
269 */
270void Scatter::check_consistancy_remote_items(Domaine& dom, const ArrOfInt& mergedDomaines)
271{
272 const Joints& joints = dom.faces_joint();
273 const int nb_joints = joints.size();
274
275 const DoubleTab& coords = dom.les_sommets();
276 ArrOfInt liste_send;
277 ArrOfInt liste_recv;
278
279
280
281 const int moi = Process::me();
282 const int myDomaineWasMerged = mergedDomaines[moi];
283
284 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
285 {
286
287 const int pe_voisin = joints[i_joint].PEvoisin();
288 const int neighbourDomaineWasMerged = mergedDomaines[pe_voisin];
289 if(myDomaineWasMerged && neighbourDomaineWasMerged)
290 {
291 if(pe_voisin < moi)
292 liste_recv.append_array(pe_voisin);
293 else
294 liste_send.append_array(pe_voisin);
295 }
296 else if(myDomaineWasMerged && !neighbourDomaineWasMerged)
297 liste_recv.append_array(pe_voisin);
298 else if(!myDomaineWasMerged && neighbourDomaineWasMerged)
299 liste_send.append_array(pe_voisin);
300 else
301 {
302 //nothing to exchange
303 }
304 }
305
306 DoubleTabs coord_items_locaux(nb_joints);
307 DoubleTabs coord_items_distants(nb_joints);
308 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
309 {
310 const Joint& joint = joints[i_joint];
311 const ArrOfInt& items_communs = joint.joint_item(JOINT_ITEM::SOMMET).items_communs();
312 const int nb_items_communs = items_communs.size_array();
313
314 DoubleTab& coord = coord_items_locaux[i_joint];
315 coord.resize(nb_items_communs, dimension);
316 for (int i = 0; i < nb_items_communs; i++)
317 for (int j = 0; j < dimension; j++)
318 coord(i,j) = coords(items_communs[i], j);
319 }
320
321 // Envoi des coordonnees locales au processeur voisin
322 {
323 Schema_Comm schema_comm;
324 schema_comm.set_send_recv_pe_list(liste_send, liste_recv);
325 schema_comm.begin_comm();
326 for (int i = 0; i < nb_joints; i++)
327 {
328 const int pe_voisin = joints[i].PEvoisin();
329 const int neighbourDomaineWasMerged = mergedDomaines[pe_voisin];
330 if( neighbourDomaineWasMerged && !(myDomaineWasMerged && pe_voisin<moi) )
331 {
332 Sortie& buffer = schema_comm.send_buffer(pe_voisin);
333 buffer << coord_items_locaux[i];
334 }
335 }
336 schema_comm.echange_taille_et_messages();
337
338 if(myDomaineWasMerged)
339 {
340 for (int i = 0; i < nb_joints; i++)
341 {
342 const int pe_voisin = joints[i].PEvoisin();
343 const int neighbourDomaineWasMerged = mergedDomaines[pe_voisin];
344 if(!(neighbourDomaineWasMerged && pe_voisin>moi))
345 {
346 Entree& buffer = schema_comm.recv_buffer(pe_voisin);
347 buffer >> coord_items_distants[i];
348 }
349 }
350 }
351
352 schema_comm.end_comm();
353 }
354
355 // check if the vertices in my joints appear in the same order as my neighbour joint
356 if(myDomaineWasMerged)
357 {
358 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
359 {
360
361 const int pe_voisin = joints[i_joint].PEvoisin();
362 const int neighbourDomaineWasMerged = mergedDomaines[pe_voisin];
363 if(neighbourDomaineWasMerged && pe_voisin>moi)
364 continue;
365 ArrOfInt& items_communs = dom.faces_joint()[i_joint].set_joint_item(JOINT_ITEM::SOMMET).set_items_communs();
366 const ArrOfInt old_items_communs = joints[i_joint].joint_item(JOINT_ITEM::SOMMET).items_communs();
367 const int nb_items = items_communs.size_array();
368 const DoubleTab& coord_voisin = coord_items_distants[i_joint];
369 const DoubleTab& my_coord = coord_items_locaux[i_joint];
370 assert(my_coord.size_array() == coord_voisin.size_array());
371 for(int i=0; i<nb_items; i++)
372 {
373 for(int j=0; j<nb_items; j++)
374 {
375 int ok=1;
376 for (int dir=0; dir<Objet_U::dimension; dir++)
377 ok=ok&&(est_egal(coord_voisin(i,dir),my_coord(j,dir)));
378 if (ok)
379 {
380 items_communs[i] = old_items_communs[j];
381 break;
382 }
383 }
384 }
385 }
386 }
387}
388
389
390/*! @brief Does the exact same thing as the readOn of the class Domaine but without collective communication
391 *
392 * Necessary when the processors don't have the same numbers of file to read
393 */
394void Scatter::read_domain_no_comm(Entree& fic, bool& read_perio)
395{
396 Domaine& dom = le_domaine.valeur();
397
398 Cerr << "\treading vertices..." << finl;
399 Domaine dom_tmp_for_vertices;
400 dom_tmp_for_vertices.read_vertices(fic);
401
402 Cerr << "\tDone !\n\treading elem infos (domaines)..." << finl;
403
404 Nom accouverte="{";
405 Motcle nom;
406 fic >> nom;
407 Domaine domaine_read;
408 if(nom!=(const char*)"vide")
409 {
410 if (nom!=accouverte)
411 Process::exit("Error: Scatter::read_domain_no_comm() -- One expected an opened bracket { to start.");
412 domaine_read.read_former_domaine(fic, read_perio);
413 }
414 else
415 Process::exit("Error: Scatter::read_domain_no_comm() -- Empty list ?! Should not happen?");
416 Cerr << "Done!" << finl;
417
418 //
419 // Now merge the read domaine with the current domain
420 //
421 int nb_elems = dom.nb_elem();
422 IntVect nums;
424 // Complete domain with new nodes and/or renumber nodes when we have doublons
425 dom.ajouter(dom_tmp_for_vertices.les_sommets(), /*out*/ nums);
426 if (nb_elems > 0)
427 {
428 domaine_read.renum(nums);
429 domaine_read.renum_joint_common_items(nums, nb_elems);
430 }
431
432 // Merge domaine_read into current domain, w/o taking care of the joints.
433 dom.merge_wo_vertices_with(domaine_read);
434
435 if(nb_elems > 0) // Current domain already had something, so joints will need update
436 // Otherwise, joints were already read by "domaine_read.read_former_domaine(fic);" above and joints are OK.
437 {
438 //merging common vertices and remote items
439 const int nb_joints = domaine_read.nb_joints();
440 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
441 {
442 const Joint& joint_to_add = domaine_read.faces_joint()[i_joint];
443
444 int my_joint_index = 0;
445 while(joint_to_add.PEvoisin() != dom.faces_joint()[my_joint_index].PEvoisin())
446 my_joint_index++;
447
448 const ArrOfInt& sommets_to_add = joint_to_add.joint_item(JOINT_ITEM::SOMMET).items_communs();
449 ArrOfInt& items_communs = dom.faces_joint()[my_joint_index].set_joint_item(JOINT_ITEM::SOMMET).set_items_communs();
450
451 for(int index=0; index<sommets_to_add.size_array(); index++)
452 items_communs.append_array(sommets_to_add[index]); // sommets_to_add is already renumbered with 'nums' - see call to renum_joint_common_items above
453 array_trier_retirer_doublons(items_communs);
454
455 const ArrOfInt& elements_to_add = joint_to_add.joint_item(JOINT_ITEM::ELEMENT).items_distants();
456 ArrOfInt& items_distants = dom.faces_joint()[my_joint_index].set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants();
457
458 for(int index=0; index<elements_to_add.size_array(); index++)
459 items_distants.append_array(elements_to_add[index]); // idem
460 }
461 }
462}
463
464/*! @brief Lit le domaine dans le fichier de nom "nomentree", de type LecFicDistribueBin ou LecFicDistribue
465 *
466 * Format attendu : Domaine::ReadOn
467 */
469{
470 // On determine si le fichier est au nouveau format ou a l'ancien
472 Cerr << "Reading geometry from .Zones file(s) ..." << finl;
473 barrier(); // Attendre que le message soit affiche
474
475 Domaine& dom = domaine();
476 Noms& liste_bords_periodiques = dom.bords_perio();
477
478 // Just in case - some dataset improperly build a Domain and then try to Scatter on it ...:
479 dom.clear();
480
481 Nom copy(nomentree);
482 copy = copy.nom_me(Process::nproc(), "p", 1);
483
484 LecFicDiffuse test;
485 bool is_hdf = test.ouvrir(copy) && FichierHDF::is_hdf5(copy);
486 if (test.ouvrir(nomentree) && FichierHDF::is_hdf5(nomentree))
487 {
488 Cerr << "Error: You probably made a single_hdf partitioning and using the wrong name of .Zones files in the scatter" << finl;
489 Cerr << "You should remove '_p" << Process::nproc() << "' from the name of .Zones file (" << nomentree << ") in your datafile" << finl;
491 }
492
493 statistics().begin_count(STD_COUNTERS::read_scatter,statistics().get_last_opened_counter_level()+1);
494 ArrOfInt mergedDomaines(Process::nproc());
495 mergedDomaines = 0;
496 bool domain_not_built = true;
497 bool read_perio = false;
498 if (is_hdf)
499 {
500 FichierHDFPar fic_hdf;
501
502 nomentree = copy;
503 fic_hdf.open(nomentree, true);
504
505 std::string dname = "/zone_" + std::to_string(Process::me());
506 bool ok = fic_hdf.exists(dname.c_str());
507 if(!ok)
508 {
509 mergedDomaines = 1;
510 for(int i=0; i<Process::nproc(); i++)
511 {
512 Entree_Brute data_part;
513 std::string tmp = dname + "_" + std::to_string(i);
514
515 bool exists = fic_hdf.exists(tmp.c_str());
516 if(exists)
517 {
518 Nom dataset_name(dname);
519
520 fic_hdf.read_dataset(dataset_name, i, data_part);
521 read_domain_no_comm(data_part, read_perio);
522
523 // Renseigne dans quel fichier le domaine a ete lu
524 dom.set_fichier_lu(nomentree);
525 if (!read_perio) // are the periodic boundaries read from the Domain (new format) or after it?
526 data_part >> liste_bords_periodiques;
527 domain_not_built = false;
528 }
529 else
530 break;
531
532 }
533 }
534 else
535 {
536 Entree_Brute data;
537 fic_hdf.read_dataset("/zone", Process::me(), data);
538
539 // Feed TRUST objects:
540 read_domain_no_comm(data, read_perio);
541 dom.set_fichier_lu(nomentree);
542 if (!read_perio) // are the periodic boundaries read from the Domain (new format) or after it?
543 data >> liste_bords_periodiques;
544 domain_not_built = false;
545 }
546
547 fic_hdf.close();
548 }
549 else // Not HDF
550 {
551 LecFicDistribueBin fichier_binaire;
552 int isSingleDomaine = fichier_binaire.ouvrir(nomentree);
553 if (!isSingleDomaine)
554 {
555 mergedDomaines = 1;
556 Nom nomentree_with_suffix=nomentree.nom_me(Process::me());
557 for(int i=0; i<Process::nproc(); i++)
558 {
559 EFichierBin fichier_binaire_part;
560 std::string tmp = nomentree_with_suffix.getPrefix(".Zones").getString();
561 tmp += "_";
562 tmp += std::to_string(i);
563 tmp += ".Zones";
564 Nom nomentree_part(tmp);
565 int ok = fichier_binaire_part.ouvrir(nomentree_part);
566 if(ok)
567 {
568 read_domain_no_comm(fichier_binaire_part, read_perio);
569
570 // Renseigne dans quel fichier le domaine a ete lu
571 dom.set_fichier_lu(nomentree);
572 if (!read_perio) // are the periodic boundaries read from the Domain (new format) or after it?
573 fichier_binaire_part >> liste_bords_periodiques;
574 fichier_binaire_part.close();
575 domain_not_built = false;
576 }
577 else
578 break;
579 }
580 }
581 else
582 {
583 read_domain_no_comm(fichier_binaire, read_perio);
584
585 // Renseigne dans quel fichier le domaine a ete lu
586 dom.set_fichier_lu(nomentree);
587 if (!read_perio) // are the periodic boundaries read from the Domain (new format) or after it?
588 fichier_binaire >> liste_bords_periodiques;
589 fichier_binaire.close();
590 domain_not_built = false;
591 }
592 }
593
594 if(domain_not_built)
595 {
596 Cerr << "Error in Scatter::lire_domaine\n";
597 Cerr << "The domain on the current process hasn't been built" << finl;
598 Cerr << "The number of processes you mentionned is probaly higher than the number of domaines" << finl;
600 }
601
602 // Verification sanitaire: nombre de processeurs = nombre de domaines
603 // (on verifie qu'il n'y a pas de joint avec un processeur inexistant)
604 // (le check precedent n'est pas suffisant:
605 // il verifie seulement que le nombre de processeurs n'est pas superieur au nombre de domaines)
606 {
607
608 const Joints& joints = dom.faces_joint();
609 const int nb_joints = joints.size();
610 int max_pe_voisin = 0;
611 for (int i = 0; i < nb_joints; i++)
612 {
613 const int pe_voisin = joints[i].PEvoisin();
614 if (pe_voisin >= max_pe_voisin)
615 max_pe_voisin = pe_voisin;
616 }
617
618 max_pe_voisin = (int) mp_max(max_pe_voisin);
619 double ok=1;
620 if (max_pe_voisin >= nproc()) ok=0;
621 if (!ok)
622 {
623 Cerr << "Error in Scatter::lire_domaine\n"
624 << "The domain has been partitioned with at least " << max_pe_voisin << " "
625 << "domaines whereas the number of processes asked is " << Process::nproc() << "." << finl;
626 Cerr << "The number of domaines and number of processes must match." << finl;
627 exit();
628 }
629 }
630
631 //tri des joints dans l'ordre croissant des procs
632 Joints& joints = dom.faces_joint();
633 trier_les_joints(joints);
634 envoyer_all_to_all(mergedDomaines, mergedDomaines);
635 check_consistancy_remote_items( dom, mergedDomaines );
636 dom.check_domaine();
637
638 // PL : pas tout a fait exact le nombre affiche de sommets, on compte plusieurs fois les sommets des joints...
639 trustIdType nbsom = mp_sum(dom.les_sommets().dimension(0));
640 Cerr << " Number of nodes: " << nbsom << finl;
641
643
644 // merged domains need to reorder faces of periodic borders
645 const int myDomaineWasMerged = mergedDomaines[Process::me()];
646 if(myDomaineWasMerged)
647 {
648 for(auto& itr : liste_bords_periodiques)
649 {
650 Nom bp_nom = itr;
651 Bord& bord = dom.bord(bp_nom);
652 if(bord.nb_faces() == 0)
653 continue;
654
655 ArrOfDouble direction_perio(dimension);
656 Reordonner_faces_periodiques::chercher_direction_perio(direction_perio, dom, bp_nom);
657 IntTab& faces = bord.faces().les_sommets();
658 double epsilon = precision_geom;
659 Reordonner_faces_periodiques::reordonner_faces_periodiques(dom, faces, direction_perio, epsilon);
660 }
661 }
662 statistics().end_count(STD_COUNTERS::read_scatter);
663 barrier();
664}
665
666/*! @brief Construction des structures paralleles du domaine et du domaine (determination des elements distants en fonction de l'epaisseur de joint,
667 *
668 * determination des sommets distants,
669 * creation des sommets et des elements virtuels)
670 *
671 */
673{
674 // D'abord: supprimer les structures "sequentielles" associees aux sommets et elements lors de la lecture:
675 {
676 MD_Vector md_nul;
677 dom.les_sommets().set_md_vector(md_nul);
678 dom.les_elems().set_md_vector(md_nul);
679 }
680
681 const Noms& liste_bords_periodiques = dom.bords_perio();
682
683 // L'ordre d'appel est important:
685
686 if (liste_bords_periodiques.size() > 0)
688
689 calculer_nb_items_virtuels(dom.faces_joint(), JOINT_ITEM::ELEMENT);
690
691 // Determination des sommets distants en fonction des elements distants
693
694 // Creation des espaces distants virtuels et items communs pour les tableaux
695 // sommets et elements:
696 DoubleTab& sommets = dom.les_sommets();
697 IntTab& elements = dom.les_elems();
698 MD_Vector md_sommets, md_elements;
699 construire_md_vector(dom, sommets.dimension(0), JOINT_ITEM::SOMMET, md_sommets);
700 construire_md_vector(dom, elements.dimension(0), JOINT_ITEM::ELEMENT, md_elements);
701 MD_Vector_tools::creer_tableau_distribue(md_sommets, sommets);
702 sommets.echange_espace_virtuel();
703 construire_espace_virtuel_traduction(md_elements /* type index */,
704 md_sommets /* type valeur */,
705 elements);
706 // Reordonner les faces de joint (correspondance implicite avec le pe voisin)
708}
709
710/*! @brief Sort joints by increasing neighbor proc number
711 */
712void Scatter::trier_les_joints(Joints& joints)
713{
714 const int nb_joints = joints.size();
715 ArrOfInt pe_voisins(nb_joints);
716 for (int i = 0; i < nb_joints; i++)
717 pe_voisins[i] = joints[i].PEvoisin();
718 pe_voisins.ordonne_array();
719 // Copie la liste des joints
720 Joints anciens_joints(joints);
721 for (int i = 0; i < nb_joints; i++)
722 {
723 // On traite le processeur pe_voisin:
724 const int pe_voisin = pe_voisins[i];
725 // Ou est le joint avec ce processeur dans l'ancienne liste ?
726 int i_old;
727 for (i_old = 0; i_old < nb_joints; i_old++)
728 if (anciens_joints[i_old].PEvoisin() == pe_voisin)
729 break;
730 assert(i_old < nb_joints);
731 joints[i] = anciens_joints[i_old];
732 }
733}
734
735// Si un joint avec le "pe" existe, renvoie son indice,
736// sion cree un nouveau joint et renvoie son indice.
737static int ajouter_joint(Domaine& domaine, int pe)
738{
739 Joints& joints = domaine.faces_joint();
740 const int i_joint = joints.size();
741
742 {
743 for (int i = 0; i < i_joint; i++)
744 if (joints[i].PEvoisin() == pe)
745 return i;
746 }
747
748 Joint& joint = joints.add(Joint());
749 joint.nommer(Nom("Joint_")+Nom(pe));
750 joint.associer_domaine(domaine);
751 int ep = (i_joint > 0) ? joints[0].epaisseur() : 1;
752 joint.affecte_epaisseur(ep);
753 joint.affecte_PEvoisin(pe);
754
755 // Initialiser tous les tableaux des joints supplementaires.
756 // Note BM: pour bien faire, il faudrait initialiser uniquement
757 // certains tableaux (ceux qui sont deja initialises pour les
758 // joints existants), mais c'est plus complique a faire...
759 {
760 for (int t = 0; t < 5; t++)
761 {
762 JOINT_ITEM type;
763 switch(t)
764 {
765 case 0:
766 type = JOINT_ITEM::SOMMET;
767 break;
768 case 1:
769 type = JOINT_ITEM::ELEMENT;
770 break;
771 case 2:
772 type = JOINT_ITEM::FACE;
773 break;
774 case 3:
775 type = JOINT_ITEM::ARETE;
776 break;
777 case 4:
778 type = JOINT_ITEM::FACE_FRONT;
779 break;
780 default:
781 Cerr << "Error in Scatter.cpp : ajouter_joint" << finl;
782 // Pour eviter le warning suivant sur gcc 3.4:
783 // Scatter.cpp:416: warning: 'type' might be used uninitialized in this function
784 type = JOINT_ITEM::SOMMET;
786 }
787 Joint_Items& data = joint.set_joint_item(type);
788 data.set_items_communs();
789 data.set_items_distants();
790 data.set_nb_items_virtuels(0);
792 }
793 }
794
795 return i_joint;
796}
797
798
799/*! @brief Determination des items distants en fonction d'une liste d'items a envoyer et de listes d'items communs.
800 *
801 * exemple:
802 * calculer_espace_distant_sommets
803 * calculer_espace_distant_faces
804 * Pour les sommets: les "items_to_send" sont les sommets des elements distants,
805 * Si le processeur A veut que le processeur B connaisse le sommet i,
806 * il faut que le processeur qui possede le sommet l'envoie a B.
807 * Le processeur qui "possede" le sommet est le plus petit parmi les PEs
808 * qui partagent ce sommet (item commun) (requis pour pouvoir faire
809 * echange_item_commun et echange_espace_virtuel en une seule passe).
810 * De plus, si plusieurs processeurs demandent a envoyer le meme sommet
811 * au meme processeur, il ne faut l'inserer qu'une seule fois dans l'espace
812 * distant.
813 *
814 * @param (joints) les joints dans lesquels on veut calculer un espace distant
815 * @param (nb_items_reels) le nombre d'items reels (sommets, faces, ...)
816 * @param (items_to_send) un vecteur de "nproc()" tableaux, pour chaque processeur, la liste des items qu'on veut lui envoyer (exemple:tous les sommets des elements distants, ou toutes les faces)
817 * @param (type_item) les items dont on veut calculer l'espace distant
818 */
820 const int nb_items_reels,
821 const ArrsOfInt& items_to_send,
822 const JOINT_ITEM type_item)
823{
824 assert(items_to_send.size() == Process::nproc());
825
826 Process::Journal() << "Scatter::calculer_espace_distant type_item="
827 << (int)type_item << finl;
828
829 Joints& joints = domaine.faces_joint();
830
831 // D'abord, on determine pour tous les items le numero du PE proprietaire:
832 // Pour chaque item du domaine:
833 // colonne 0 : indice du item sur le PE proprietaire (index_on_pe_owner)
834 // colonne 1 : numero du PE proprietaire (le plus petit pe qui partage l'item)
835 IntTab num_global_items(nb_items_reels, 2);
836 {
837 int i;
838 const int moi = Process::me();
839 for (i = 0; i < nb_items_reels; i++)
840 {
841 num_global_items(i, 0) = i;
842 num_global_items(i, 1) = moi;
843 }
844 const int nb_joints = joints.size();
845 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
846 {
847 const Joint& joint = joints[i_joint];
848 const int pe_voisin = joint.PEvoisin();
849 const IntTab& renum_items_communs= joint.joint_item(type_item).renum_items_communs();
850 const int nb_items_communs = renum_items_communs.dimension(0);
851 for (i = 0; i < nb_items_communs; i++)
852 {
853 const int num_item_distant = renum_items_communs(i, 0);
854 const int num_item_local = renum_items_communs(i, 1);
855 const int pe_actuel = num_global_items(num_item_local, 1);
856 if (pe_voisin < pe_actuel)
857 {
858 num_global_items(num_item_local, 0) = num_item_distant;
859 num_global_items(num_item_local, 1) = pe_voisin;
860 }
861 }
862 }
863 }
864
865 Schema_Comm schema_comm;
866 const int nproc = Process::nproc();
867
868 // Premiere etape : on envoie au processeur proprietaire des items
869 // la liste des items qu'il faut envoyer et a quel processeur il
870 // faut les envoyer.
871 // Si le processeur A doit envoyer l'element E au processeur B,
872 // et que cet element utilise un item S qui appartient au processeur C,
873 // alors on envoie a C le message :
874 // "tu dois mettre le item S dans l'espace distant du processeur B"
875
876 // On prepare un schema de communication entre les voisins:
877 // Processeur emetteur : le processeur qui possede l'element distant,
878 // Processeur recepteur: le processeur qui possede un item de l'element.
879 // Ces processeurs sont voisins par les joints existants.
880 const int nb_joints = joints.size();
881 ArrOfInt liste_voisins(nb_joints);
882 //int i_joint;
883 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
884 liste_voisins[i_joint] = joints[i_joint].PEvoisin();
885
886 schema_comm.set_send_recv_pe_list(liste_voisins, liste_voisins, 1 /* me_to_me */);
887 schema_comm.begin_comm();
888 {
889 // et pour chaque item a envoyer, on envoie au processeur qui possede l'item (pe_item_owner):
890 // - l'indice local du item chez lui (item_distant),
891 // - le numero du processeur a qui il doit l'envoyer (pe_destination)
892 const int nb_procs = Process::nproc();
893 for (int pe_destination = 0; pe_destination < nb_procs; pe_destination++)
894 {
895 const ArrOfInt& items = items_to_send[pe_destination];
896 const int nb_items = items.size_array();
897 for (int i_item = 0; i_item < nb_items; i_item++)
898 {
899 const int item = items[i_item];
900 const int item_distant = num_global_items(item, 0);
901 const int pe_item_owner = num_global_items(item, 1);
902 // On envoie le numero du item distant et dans quel joint il
903 // faut le mettre.
904 // Si pe_joint == pe_destination, litem est forcement deja
905 // connu par l'autre processeur, inutile de l'envoyer
906 if (pe_item_owner != pe_destination)
907 schema_comm.send_buffer(pe_item_owner) << item_distant << pe_destination;
908 }
909 }
910 }
911
912 // Echange des messages
913 schema_comm.echange_taille_et_messages();
914
915 // Reception des items distants. On lit tous les buffers et on
916 // range les items dans "items_distants" par processeur destination.
917 // Pour chaque processeur voisin, la liste des items distants a envoyer:
918 ArrsOfInt items_distants(nproc);
919
920 // Boucle sur tous les processeurs (pe_source) qui m'ont envoye des messages:
921 // On boucle sur les processeurs voisins, plus moi-meme:
922 for (int i_source = 0; i_source < nb_joints + 1; i_source++)
923 {
924 const int pe_source =
925 (i_source < nb_joints) ? liste_voisins[i_source] : Process::me();
926
927 Entree& buffer = schema_comm.recv_buffer(pe_source);
928 // Boucle "tant que le buffer n'est pas vide"
929 while(1)
930 {
931 int item_distant; // Indice du item distant
932 int pe_distant; // Numero du pe a qui il faut envoyer le item
933 buffer >> item_distant >> pe_distant;
934 if (buffer.eof())
935 break;
936 assert(pe_distant != Process::me());
937 ArrOfInt& array = items_distants[pe_distant];
938 array.append_array(item_distant);
939 }
940 }
941 schema_comm.end_comm();
942
943 // On retire les doublons et les items deja connus par le processeur voisin:
944 {
945 // Liste des joints correspondant a chaque pe
946 ArrOfInt joint_of_pe(nproc);
947 joint_of_pe = -1;
948 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
949 {
950 const int pe = joints[i_joint].PEvoisin();
951 joint_of_pe[pe] = i_joint;
952 }
953 // Liste des items deja connus par le processeur voisin (items communs)
954 // tries dans l'ordre croissant
955 ArrOfInt items_communs_tri;
956
957 for (int pe = 0; pe < nproc; pe++)
958 {
959 ArrOfInt& items = items_distants[pe];
960 // Retirer les doublons:
961 array_trier_retirer_doublons(items);
962 // Retirer les items deja connus:
963 const int i_joint = joint_of_pe[pe];
964 if (i_joint >= 0)
965 {
966 items_communs_tri =
967 joints[i_joint].joint_item(type_item).items_communs();
968 items_communs_tri.ordonne_array();
969 array_retirer_elements(items, items_communs_tri);
970 }
971 else
972 {
973 // Pas d'item commun avec ce pe.
974 }
975 }
976 }
977
978 // Des espaces distants peuvent etre crees sur des processeurs avec
979 // qui il n'existe pas encore de joint. On ajoute les nouveaux joints.
980 {
981 ArrOfInt nouveaux_voisins;
982
983 int i;
984 for (i = 0; i < nproc; i++)
985 if (items_distants[i].size_array() > 0)
986 nouveaux_voisins.append_array(i);
987
988 // On ajoute les nouveaux joints
989 ajouter_joints(domaine, nouveaux_voisins);
990 Process::Journal() << " News joints created : (ArrOfInt) "
991 << nouveaux_voisins << finl;
992 }
993
994 Joints& joints_non_const = domaine.faces_joint();
995 const int nb_new_joints = joints_non_const.size();
996 // Remplissage des tableaux d'items distants
997 for (int i_joint = 0; i_joint < nb_new_joints; i_joint++)
998 {
999 Joint& joint = joints_non_const[i_joint];
1000 const int pe = joint.PEvoisin();
1001 ArrOfInt& joint_items_distants = joint.set_joint_item(type_item).set_items_distants();
1002 joint_items_distants = items_distants[pe];
1003 Process::Journal() << " Joint with PE:" << pe
1004 << " Number of remote items : "
1005 << joint_items_distants.size_array() << finl;
1006 }
1007 // Remplissage du nombre d'items virtuels
1008 calculer_nb_items_virtuels(joints_non_const, type_item);
1009}
1010inline Nom endian()
1011{
1012 int x = 1;
1013 if(*(char *)&x == 1)
1014 return "little-endian";
1015 else
1016 return "big-endian";
1017}
1018/*! @brief Ajoute des joints avec tous les pe de pe_voisins.
1019 *
1020 * Pour que l'ensemble des joints soit symetrique,
1021 * on en cree aussi un joint sur le processeur destination:
1022 * Si A ajoute un joint avec B, alors B ajoute un joint avec A.
1023 * On trie les joints par ordre croissant du numero de PE.
1024 * ATTENTION: les joints sont donc reordonnes !
1025 * On met dans pe_voisins la liste des joints effectivement crees.
1026 *
1027 */
1029 ArrOfInt& pe_voisins)
1030{
1031 Joints& joints = domaine.faces_joint();
1032 ArrOfInt liste_pe;
1033
1034
1035 // Rendre les joints symetriques (si A->B alors B->A) :
1036 {
1037 // On met dans liste pe la "transposee" de la liste des pe_voisins:
1038 // liste des processeurs chez qui mon numero est dans "pe_voisins".
1039 reverse_send_recv_pe_list(pe_voisins, liste_pe);
1040 const int n = liste_pe.size_array();
1041 // On concatene les deux listes.
1042 for (int i = 0; i < n; i++)
1043 pe_voisins.append_array(liste_pe[i]);
1044 array_trier_retirer_doublons(pe_voisins);
1045 liste_pe.resize_array(0);
1046 }
1047 // On retire de pe_voisins les pe pour lesquels un joint existe deja
1048 {
1049 const int n = joints.size();
1050 liste_pe.resize_array(n);
1051 for (int i = 0; i < n; i++)
1052 liste_pe[i] = joints[i].PEvoisin();
1053 array_retirer_elements(pe_voisins, liste_pe);
1054 }
1055 // Ajouter les nouveaux joints et trier par ordre croissant
1056 // Aujourd'hui (2/11/2005) Liste::inserer ne permet pas d'inserer
1057 // en debut de liste. Donc inutilisable. Methode bourrin:
1058 {
1059 const int n = pe_voisins.size_array();
1060 for (int i = 0; i < n; i++)
1061 ajouter_joint(domaine, pe_voisins[i]);
1062 trier_les_joints(joints);
1063 }
1064}
1065
1066/*! @brief Methode generique pour calculer l'espace distant d'un type d'items geometrique (sommet, face, arete) en fonction de l'espace distant des elements:
1067 *
1068 * Les "type_item" distants (pour type_item = sommet face ou arete) sont
1069 * les "type_item" attaches aux elements distants.
1070 * Exemple : les sommets distants sont tous les sommets de tous les elements
1071 * distants.
1072 * @sa
1073 * Scatter::calculer_espace_distant_sommets
1074 * Scatter::calculer_espace_distant_faces
1075 *
1076 * @param (domaine) bah, le domaine quoi...
1077 * @param (type_item) le type des items dont on veut calculer l'espace distant
1078 * @param (connectivite_elem_item) le tableau qui donne pour chaque element du domaine les indices des items de cet element. On n'utilise que la partie reele du tableau (logiquement, la partie virtuelle n'existe pas encore). (exemple: domaine().les_elems() pour type_item==SOMMET ou domaine_VF().face_sommets() pour type_item==FACE)
1079 * @param (nb_items_reels) le nombre de "type_item" reels
1080 * @param (items_lies) si le tableau est non vide, il doit etre de taille nb_items_reels. Dans ce cas, il permet de forcer la propriete suivante : "si l'item i est distant, alors l'item items_lies[i] est distant aussi". Ce tableau est utilise pour inclure les sommets periodiques virtuels associes. (voir calculer_espace_distant_sommets).
1081 */
1082static void calculer_espace_distant_item(Domaine& le_dom,
1083 const JOINT_ITEM type_item,
1084 const IntTab& connectivite_elem_item,
1085 const int nb_items_reels,
1086 const ArrOfInt& items_lies)
1087{
1089 return;
1090
1091 const Joints& joints = le_dom.faces_joint();
1092 const int nb_joints = joints.size();
1093 const int nproc = Process::nproc();
1094 const int nb_items_par_element = connectivite_elem_item.dimension(1);
1095 // Les type_item a envoyer a chaque processeur:
1096 ArrsOfInt items_to_send(nproc);
1097 // Un tableau temporaire;
1098 ArrOfInt liste_items;
1099
1100
1101 // Est-ce qu'il y a des items lies ?
1102 const int flag_items_lies = (items_lies.size_array() > 0);
1103 assert(flag_items_lies == 0 || items_lies.size_array() == nb_items_reels);
1104
1105
1106 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
1107 {
1108 const Joint& joint = joints[i_joint];
1109 const int pe_voisin = joint.PEvoisin();
1110 const ArrOfInt& esp_dist_elems = joint.joint_item(JOINT_ITEM::ELEMENT).items_distants();
1111 const int nb_elems_dist = esp_dist_elems.size_array();
1112 liste_items.resize_array(0);
1113 // On met dans liste_items tous les items de tous les elements
1114 // qui sont dans esp_dist_elems:
1115 for (int i_elem = 0; i_elem < nb_elems_dist; i_elem++)
1116 {
1117 const int elem = esp_dist_elems[i_elem];
1118 for (int i_item = 0; i_item < nb_items_par_element; i_item++)
1119 {
1120 const int item = connectivite_elem_item(elem, i_item);
1121 if (item>-1)
1122 {
1123 liste_items.append_array(item);
1124 // Si un item est lie a l'item courant, on envoie aussi l'item lie.
1125 if (flag_items_lies)
1126 {
1127 const int item_lie = items_lies[item];
1128 if (item_lie != item)
1129 {
1130 assert(item_lie >= 0 && item_lie < nb_items_reels);
1131 assert(items_lies[item_lie] == item_lie); // chaine de liaisons interdite
1132 liste_items.append_array(item_lie);
1133 }
1134 }
1135 }
1136 }
1137 }
1138 array_trier_retirer_doublons(liste_items);
1139 // Ces items doivent etre envoyes au processeur voisin:
1140 items_to_send[pe_voisin] = liste_items;
1141 }
1142 // Calcul des espaces distants en fonction de "items_to_send"
1143 Scatter::calculer_espace_distant(le_dom, nb_items_reels, items_to_send, type_item);
1144}
1145
1146/*! @brief En fonction de l'espace distant des elements, calcule l'espace distant des sommets.
1147 *
1148 * Pour chaque joint, on envoie au processeur voisin
1149 * l'ensemble des sommets de tous les elements du joint.
1150 * C'est le processeur proprietaire du sommet
1151 * (plus petit pe qui le possede) qui le met dans son espace distant.
1152 * Attention, on cree de nouveaux joints.
1153 * On remplit les tableaux
1154 * dom.faces_joint(i).joint_item(JOINT_ITEM::SOMMET).items_distants();
1155 *
1156 */
1158{
1160 Cerr << "Scatter::calculer_espace_distant_sommets : start" << finl;
1161
1162 const IntTab& connectivite_elem_som = dom.les_elems();
1163 const int nb_sommets_reels = dom.nb_som();
1164
1165 ArrOfInt renum_som_perio(nb_sommets_reels);
1166 // Initialisation du tableau renum_som_perio
1167 for (int i = 0; i < nb_sommets_reels; i++)
1168 renum_som_perio[i] = i;
1170 0 /* ne pas calculer pour les sommets virtuels */);
1171
1172 calculer_espace_distant_item(dom,
1173 JOINT_ITEM::SOMMET,
1174 connectivite_elem_som,
1175 nb_sommets_reels,
1176 renum_som_perio);
1177}
1178
1179/*! @brief Idem que Scatter::calculer_espace_distant_sommets pour les faces
1180 *
1181 */
1183 const int nb_faces_reelles,
1184 const IntTab& elem_faces)
1185{
1187 Cerr << "Scatter::calculer_espace_distant_faces : start" << finl;
1188
1189 ArrOfInt tableau_vide;
1190
1191 calculer_espace_distant_item(domaine,
1192 JOINT_ITEM::FACE,
1193 elem_faces,
1194 nb_faces_reelles,
1195 tableau_vide);
1196}
1197
1198/*! @brief Idem que Scatter::calculer_espace_distant_sommets pour les aretes
1199 *
1200 */
1202 const int nb_aretes_reelles,
1203 const IntTab& elem_aretes)
1204{
1206 Cerr << "Scatter::calculer_espace_distant_aretes : start" << finl;
1207 ArrOfInt tableau_vide;
1208 calculer_espace_distant_item(domaine,
1209 JOINT_ITEM::ARETE,
1210 elem_aretes,
1211 nb_aretes_reelles,
1212 tableau_vide);
1213}
1214
1215/*! @brief On suppose que chaque joint[i].joint_item(type_item).items_communs() contient les indices locaux des items de joint communs dans le meme
1216 * ordre sur les deux processeurs (local et voisin)
1217 * On remplit renum_items_communs :
1218 * colonne 0=contenu du tableau items_communs sur le PE voisin
1219 * colonne 1=contenu du tableau items_communs sur le PE local
1220 *
1221 */
1223 const JOINT_ITEM type_item)
1224{
1225 // Il suffit d'envoyer au voisin le tableau _faces dans l'ordre
1226 // pour qu'il ait les indices des faces sur l'autre pe.
1227
1228 const int nb_joints = joints.size();
1229 int i_joint;
1230 Schema_Comm schema_comm;
1231 ArrOfInt liste_voisins(nb_joints);
1232 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1233 liste_voisins[i_joint] = joints[i_joint].PEvoisin();
1234 schema_comm.set_send_recv_pe_list(liste_voisins, liste_voisins);
1235
1236 schema_comm.begin_comm();
1237
1238 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1239 {
1240 const Joint& joint = joints[i_joint];
1241 const int pe_voisin = joint.PEvoisin();
1242 const ArrOfInt& items_communs =
1243 joint.joint_item(type_item).items_communs();
1244 schema_comm.send_buffer(pe_voisin) << items_communs;
1245 }
1246
1247 schema_comm.echange_taille_et_messages();
1248
1249 // Le tableau items communs recu du pe voisin:
1250 ArrOfInt items_communs_voisin;
1251
1252
1253 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1254 {
1255 Joint& joint = joints[i_joint];
1256 const int pe_voisin = joint.PEvoisin();
1257 const ArrOfInt& items_communs = joint.joint_item(type_item).items_communs();
1258 const int nb_items = items_communs.size_array();
1259 schema_comm.recv_buffer(pe_voisin) >> items_communs_voisin;
1260
1261 assert(nb_items == items_communs_voisin.size_array());
1262
1263 IntTab& renum_items_communs = joint.set_joint_item(type_item).set_renum_items_communs();
1264 renum_items_communs.resize(nb_items, 2);
1265 // L'indice de la face de joint sur l'autre PE est dans tmp(i,1)
1266 for (int i = 0; i < nb_items; i++)
1267 {
1268 renum_items_communs(i,0) = items_communs_voisin[i];
1269 renum_items_communs(i,1) = items_communs[i];
1270 }
1271 }
1272
1273 schema_comm.end_comm();
1274}
1275
1276/*! @brief construction d'un MD_Vector_std a partir des informations de joint du domaine pour le type d'item demande.
1277 *
1278 */
1279void Scatter::construire_md_vector(const Domaine& dom, int nb_items_reels, const JOINT_ITEM type_item, MD_Vector& md_vector)
1280{
1282 {
1283 MD_Vector_seq mdseq(nb_items_reels);
1284 md_vector.copy(mdseq);
1285 return;
1286 }
1287
1288 const Joints& joints = dom.faces_joint();
1289 const int nb_joints = joints.size();
1290
1291 ArrOfInt pe_voisins(nb_joints);
1292 ArrsOfInt items_to_send(nb_joints);
1293 ArrsOfInt items_to_recv(nb_joints);
1294 ArrsOfInt blocs_to_recv(nb_joints);
1295
1296 // drapeau indique si l'item (commun) est recu d'un processeur
1297 ArrOfBit flags(nb_items_reels);
1298 flags = 0;
1299
1300 int nitems_tot = nb_items_reels;
1301 const int moi = me();
1302
1303 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
1304 {
1305 const int pe = joints[i_joint].PEvoisin();
1306 pe_voisins[i_joint] = pe;
1307 const Joint_Items& joint = joints[i_joint].joint_item(type_item);
1308 {
1309 // Traitement des items communs
1310 const ArrOfInt& items_communs = joint.items_communs();
1311 const int n = items_communs.size_array();
1312
1313 // Les joints doivent arriver dans l'ordre croissant du numero de pe
1314 // sinon l'algo suivant ne marche pas:
1315 assert((i_joint == 0) || (pe > joints[i_joint-1].PEvoisin()));
1316 if (pe > moi)
1317 {
1318 // Je dois envoyer ces items au processeur voisin
1319 ArrOfInt& dest = items_to_send[i_joint];
1320
1321 for (int i = 0; i < n; i++)
1322 {
1323 const int item = items_communs[i];
1324 if (!flags[item])
1325 {
1326 // item pas recu d'un processeur
1327 dest.append_array(item);
1328 }
1329 }
1330 }
1331 else
1332 {
1333 // Je recois cet item d'un autre processeur
1334 ArrOfInt& dest = items_to_recv[i_joint];
1335
1336 for (int i = 0; i < n; i++)
1337 {
1338 const int item = items_communs[i];
1339 if (!flags.testsetbit(item))
1340 {
1341 // item pas encore recu d'un processeur
1342 dest.append_array(item);
1343 }
1344 }
1345 }
1346 }
1347 // Traitement des items distants et virtuels
1348 {
1349 const int nitems_virt = joint.nb_items_virtuels();
1350 ArrOfInt& dest = blocs_to_recv[i_joint];
1351 if (nitems_virt > 0)
1352 {
1353 dest.resize_array(2, RESIZE_OPTIONS::NOCOPY_NOINIT);
1354 // Definition du bloc d'items virtuels pour le processeur voisin
1355 dest[0] = nitems_tot;
1356 dest[1] = nitems_tot + nitems_virt;
1357 nitems_tot += nitems_virt;
1358 }
1359 }
1360 {
1361 const ArrOfInt& items_distants = joint.items_distants();
1362 const int n = items_distants.size_array();
1363 ArrOfInt& dest = items_to_send[i_joint];
1364 const int index = dest.size_array();
1365 dest.resize_array(index + n, RESIZE_OPTIONS::COPY_NOINIT); // copier les anciennes valeurs !
1366 dest.inject_array(items_distants, n, index /* dest index */, 0 /* src index */);
1367 }
1368 }
1369
1370 MD_Vector_std md(nitems_tot, nb_items_reels, pe_voisins, items_to_send, items_to_recv, blocs_to_recv);
1371 md_vector.copy(md);
1372
1373 // Verification que le md_vector est valide (tailles en send correspondant aux tailles en recv)
1374 if (comm_check_enabled())
1375 {
1376 IntVect toto;
1378 toto = 0;
1380 }
1381}
1382
1383/*! @brief Cette classe fournit les outils pour construire l'espace virtuel d'un tableau contenant des indices d'entites geometriques
1384 *
1385 * (sommets, elements, faces). Elle gere en particulier la
1386 * renumerotation des elements virtuels.
1387 *
1388 */
1390{
1391public:
1393 void initialiser(const MD_Vector& md_items);
1394 void reset();
1395 void traduire_indice_local_vers_global(const ArrOfInt& indices_locaux, ArrOfTID& indices_globaux, int n) const;
1396 int traduire_indice_global_vers_local(const ArrOfTID& indices_globaux, ArrOfInt& indices_locaux) const;
1397 int traduire_espace_virtuel(IntTab& tableau) const;
1398
1399 int chercher_table_inverse(const trustIdType sommet_global) const;
1400
1401private:
1402 // Metadata des indices qu'on va renumeroter :
1403 MD_Vector md_items_;
1404 trustIdType premier_indice_global_ = -100;
1405 // Tableau distribue (avec espaces virtuels et items communs)
1406 // contenant pour toutes les entites a indexer (reelles et virtuelles)
1407 // un indice global.
1408 // (si type_table_==SOMMETS, table_[i] est l'indice global du sommet i)
1409 TIDVect table_;
1410 // Table permettant d'inverser la numerotation, classee par ordre
1411 // croissant de l'indice global :
1412 // * colonne 0 : l'indice global de l'entite
1413 // * colonne 1 : l'indice local de l'entite
1414 TIDTab table_inverse_;
1415};
1416
1417/*! @brief Initialise le dictionnaire Precontition:
1418 *
1419 * Les espaces distants des entites utilisees doivent avoir ete calculees
1420 *
1421 */
1423{
1424 md_items_ = md_items;
1425
1426 // Construction de "table" : on cree un numero global pour les entites reelles
1427 // (indice de l'entite + nombre total d'entites sur les processeurs de rang inferieur)
1428 // puis on echange l'espace virtuel de ce tableau, on obtient pour chaque entite
1429 // reelle ou virtuelle son numero global.
1430
1431 table_.reset();
1433
1434 const int nb_entites = md_items->get_nb_items_tot();
1435 const trustIdType decal = Process::mppartial_sum(nb_entites);
1436 premier_indice_global_ = decal;
1437
1438 for (int i = 0; i < nb_entites; i++)
1439 table_[i] = i + decal;
1440 table_.echange_espace_virtuel();
1441
1442 // Construction de la table_inverse contenant les indices non triviaux
1443 // (pour lesquels table_[i] != i + decal apres l'echange)
1444 // tri par ordre croissant du numero global.
1445 const int nb_entites_tot = table_.size_totale();
1446 table_inverse_.resize(0, 2);
1447
1448 for (int i = 0; i < nb_entites_tot; i++)
1449 {
1450 if (table_[i] != i + decal)
1451 table_inverse_.append_line(table_[i], i);
1452 }
1453 // insure se plaint .. regarder si il a raison
1454 if (table_inverse_.size_array()>0)
1455 {
1456 tri_lexicographique_tableau(table_inverse_);
1457 }
1458}
1459
1461{
1462 md_items_.detach();
1463 table_.reset();
1464 table_inverse_.reset();
1465}
1466
1467/*! @brief Cherche i tel que table_inverse(i, 0) == sommet_global, et renvoie table_inverse(i, 1) (l'indice local du sommet).
1468 *
1469 * Si le sommet n'est pas trouve dans la table, renvoie -1.
1470 * La table_inverse doit etre triee par ordre croissant de la colonne 0.
1471 * La table_inverse ne doit pas avoir d'espace virtuel.
1472 *
1473 */
1474int Traduction_Indice_Global_Local::chercher_table_inverse(const trustIdType sommet_global) const
1475{
1476 // Algorithme : recherche par dichotomie:
1477 int imin = 0;
1478 int imax = table_inverse_.dimension(0) - 1;
1479 // Si un seul element dans la table, on ne passe pas dans while
1480 // (donc initialisation a table_inverse(0, 0))
1481 // Sinon, si aucun element, il ne faut pas que valeur == sommet_global,
1482 // sinon, valeur quelconque, elle sera ecrasee dans le while.
1483 trustIdType valeur;
1484 if (imax == 0)
1485 valeur = table_inverse_(0, 0);
1486 else
1487 valeur = sommet_global - 1;
1488
1489 while (imax > imin)
1490 {
1491 const int milieu = (imin + imax) >> 1; // (min+max)/2
1492 valeur = table_inverse_(milieu, 0);
1493 const trustIdType compare = valeur - sommet_global;
1494 if (compare < 0)
1495 imin = milieu + 1;
1496 else if (compare > 0)
1497 imax = milieu - 1;
1498 else
1499 imin = imax = milieu;
1500 }
1501 int resu = -1;
1502 valeur = table_inverse_(imin, 0);
1503 if (valeur == sommet_global)
1504 resu = static_cast<int>(table_inverse_(imin, 1)); // 2nd col always an int
1505 return resu;
1506}
1507
1508/*! @brief Transforme les indices locaux en indices globaux a l'aide la "table_" (voir initialiser).
1509 *
1510 * On fait :
1511 * Pour debut <= i < debut+nb
1512 * indices_globaux[i] = table_[indices_locaux[i]]
1513 * si indices_locaux[i] < 0 alors indices_globaux[i] = -1
1514 *
1515 */
1517 ArrOfTID& indices_globaux, int nb_items_a_traiter) const
1518{
1519 for (int i = 0; i < nb_items_a_traiter; i++)
1520 {
1521 const int i_loc = indices_locaux[i];
1522 const trustIdType i_glob = (i_loc < 0) ? -1 : table_[i_loc];
1523 indices_globaux[i] = i_glob;
1524 }
1525}
1526
1527/*! @brief Pour debut <= i < debut+nb indices_locaux[i] = chercher l'indice local de "indices_globaux[i]"
1528 *
1529 * @param (indices_globaux) le tableau des indices globaux a traduire
1530 * @param (indices_locaux) en sortie, les indices locaux ou -1 si l'indice global n'a pas ete trouve. Valeur de retour: nombre d'indices non trouves (indices globaux qui ne correspondent a aucun indice local).
1531 */
1533 ArrOfInt& indices_locaux) const
1534{
1535 assert(indices_globaux.size_array() == indices_locaux.size_array());
1536 int i;
1537 int nb_erreurs = 0;
1538 const int nb_indices = indices_globaux.size_array();
1539 const int size_table = table_.size_array();
1540 for (i = 0; i < nb_indices; i++)
1541 {
1542 const trustIdType i_glob = indices_globaux[i];
1543 int i_loc;
1544 if (i_glob < 0)
1545 {
1546 // Indice negatif, on considere que c'est normal,
1547 // c'est un marqueur "indice vide".
1548 i_loc = -1;
1549 }
1550 else
1551 {
1552 // On teste si l'item n'est pas renumerote
1553 i_loc = static_cast<int>(i_glob - premier_indice_global_); // the diff is local, hence small
1554 if (i_loc < 0 || i_loc >= size_table || table_[i_loc] != i_glob)
1555 {
1556 // non, il faut inverser la table:
1557 i_loc = chercher_table_inverse(i_glob);
1558 }
1559 if (i_loc < 0)
1560 nb_erreurs++;
1561 }
1562 indices_locaux[i] = i_loc;
1563 }
1564 return nb_erreurs;
1565}
1566
1567/*! @brief A partir d'un tableau dont la structure d'espace virtuel est initialisee (descripteurs elements distants et virtuels, items communs)
1568 *
1569 * et contenant des indices compatibles avec le contenu des tables
1570 * (indices de sommets ou d'elements selon type_table_),
1571 * on remplit les elements virtuels du "tableau" en fonction des elements
1572 * distants et on traduit les indices en indices locaux.
1573 * (exemple, voir construire_espace_virtuel_elements et
1574 * construire_espace_virtuel_faces).
1575 * Valeur de retour: nombre d'indices qui n'ont pas pu etre traduits
1576 * (par exemple, le sommet reference n'existe pas sur le processeur voisin)
1577 *
1578 */
1580{
1581 // Create a copy of the tab in which we will store global indices
1582 // Can not use 'copy' since value types are different (int vs TID), so this a bit clumsy:
1583 // (TODO provide 'from_int_to_tid' in TRUSTTab.h)
1584 TIDTab ind_glob_tab;
1585 ArrOfInt sz(tab.nb_dim());
1586 for (int i=0; i < tab.nb_dim(); i++) sz[i] = tab.dimension_tot(i);
1587 ind_glob_tab.resize(sz, RESIZE_OPTIONS::NOCOPY_NOINIT);
1588 ind_glob_tab.set_md_vector(tab.get_md_vector());
1589
1590 IntVect& tableau = tab; // tab seen as a Vect.
1591 TIDVect& indices_globaux = ind_glob_tab;
1592
1593 const int nb_items_reels = tableau.size_reelle();
1594 const int nb_items_tot = tableau.size_totale();
1595 const int nb_items_virtuels = nb_items_tot - nb_items_reels;
1596
1597 // On traduit les items reels en indices globaux:
1598 traduire_indice_local_vers_global(tableau, indices_globaux, nb_items_reels);
1599 // On remplit les cases virtuelles
1600 indices_globaux.echange_espace_virtuel();
1601
1602 // On retraduit uniquement les items virtuels du "tableau" en indices locaux:
1603 ArrOfTID src;
1604 ArrOfInt dest;
1605 src.ref_array(indices_globaux, nb_items_reels /*debut*/, nb_items_virtuels /*taille*/);
1606 dest.ref_array(tableau, nb_items_reels /*debut*/, nb_items_virtuels /*taille*/);
1607 const int nb_erreurs = traduire_indice_global_vers_local(src, dest);
1608 return nb_erreurs;
1609}
1610
1611/*! @brief Construit la structure items_communs + espaces virtuels d'un tableau contenant des indices d'items geometriques, indexe par un autre type d'item geometrique.
1612 *
1613 * Exemple: tableau indexe par md_indice, contenant des indices md_valeur:
1614 * type_indice type_valeur exemple de tableau:
1615 * element sommet domaine.les_elems()
1616 * face sommet faces_sommets
1617 * element face elem_faces
1618 * face element faces_voisins
1619 * element element ?
1620 * element arete elem_aretes
1621 * Nb_valeurs_max est le nombre d'items reels de type "type_valeur".
1622 *
1623 */
1625 const MD_Vector& md_valeur,
1626 IntTab& tableau,
1627 const int error_is_fatal)
1628{
1630 {
1631 // MD_Vector is a MD_Vector_seq:
1632 assert( dynamic_cast<const MD_Vector_seq *>(&md_indice.valeur()) != nullptr);
1633 // The array should still get its (dummy sequential) MD_Vector, otherwise it will remain null.
1634 if (!(tableau.get_md_vector() == md_indice))
1635 tableau.set_md_vector(md_indice);
1636 return;
1637 }
1638
1639 if (tableau.dimension_tot(0) != md_indice->get_nb_items_reels()
1640 && (tableau.dimension_tot(0) != md_indice->get_nb_items_tot()))
1641 {
1642 Cerr << "[PE " << Process::me()
1643 << "] Error in Scatter::construire_espace_virtuel_traduction\n"
1644 << " the array does not have the good dimension on input" << finl;
1645 exit();
1646 }
1647 // Construction du dictionnaire indice global/indice local
1648 // pour les valeurs du tableau
1649 Traduction_Indice_Global_Local dictionnaire_indices;
1650 dictionnaire_indices.initialiser(md_valeur);
1651
1652 // Construit la structure d'espaces virtuels du "tableau"
1653 if (!(tableau.get_md_vector() == md_indice))
1654 MD_Vector_tools::creer_tableau_distribue(md_indice, tableau, RESIZE_OPTIONS::COPY_NOINIT);
1655
1656 // Remplissage des valeurs vituelles du "tableau"
1657 const int nb_erreurs = dictionnaire_indices.traduire_espace_virtuel(tableau);
1658
1659 if (nb_erreurs > 0 && error_is_fatal)
1660 {
1661 Cerr << "[PE " << Process::me()
1662 << "] Error in Scatter::construire_espace_virtuel_traduction\n"
1663 << " some indices of values were not found in\n"
1664 << " the local area : it missing virtual items"
1665 << finl;
1666 exit();
1667 }
1668}
1669
1670
1671/*! @brief Reordonne les faces de joint de sorte qu'elles apparaissent dans le meme ordre sur chaque couple de processeur voisin.
1672 *
1673 * En pratique, pour un couple
1674 * pe1 < pe2, pe1 envoie ses faces de joint a pe2 et pe2 les traduit en indices
1675 * de sommets locaux. Les faces de joint du PE2 ne sont donc pas utilisees.
1676 *
1677 */
1679{
1680 // Construction du dictionnaire indice global/indice local
1681 // pour les sommets du domaine:
1682 Traduction_Indice_Global_Local dictionnaire_indices;
1683 dictionnaire_indices.initialiser(dom.les_sommets().get_md_vector());
1684
1685 Schema_Comm schema_comm;
1686 Joints& joints = dom.faces_joint();
1687 const int nb_joints = joints.size();
1688 const int moi = Process::me();
1689 int i_joint;
1690
1691 // Remplissage des listes de destinataires:
1692 // on envoie aux voisins de rang superieur et on recoit des voisins de rang inf.
1693 ArrOfInt send_list;
1694 ArrOfInt recv_list;
1695
1696
1697
1698 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1699 {
1700 const int pe_voisin = joints[i_joint].PEvoisin();
1701 if (pe_voisin > moi)
1702 send_list.append_array(pe_voisin);
1703 else
1704 recv_list.append_array(pe_voisin);
1705 }
1706
1707 schema_comm.set_send_recv_pe_list(send_list, recv_list);
1708
1709 schema_comm.begin_comm();
1710 // Envoi des faces de joint, traduites en indices de sommets globaux
1711 TIDTab faces_num_global;
1712
1713 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1714 {
1715 const Joint& joint = joints[i_joint];
1716 const int pe_voisin = joint.PEvoisin();
1717 if (pe_voisin > moi)
1718 {
1719 const IntTab& faces_sommets = joint.faces().les_sommets();
1720 if (faces_sommets.dimension(0) > 0)
1721 {
1722 faces_num_global.resize(faces_sommets.dimension(0), faces_sommets.dimension(1));
1723 dictionnaire_indices.traduire_indice_local_vers_global(faces_sommets,
1724 faces_num_global,
1725 faces_sommets.size_array());
1726 }
1727 else
1728 faces_num_global.resize(0);
1729
1730 schema_comm.send_buffer(pe_voisin) << faces_num_global;
1731 }
1732 }
1733 schema_comm.echange_taille_et_messages();
1734 // Reception des faces de joint et traduction en indices locaux
1735 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1736 {
1737 Joint& joint = joints[i_joint];
1738 const int pe_voisin = joint.PEvoisin();
1739 if (pe_voisin < moi)
1740 {
1741 IntTab& faces_sommets = joint.faces().les_sommets();
1742 schema_comm.recv_buffer(pe_voisin) >> faces_num_global;
1743 if (faces_sommets.dimension(0) != faces_num_global.dimension(0))
1744 {
1745 Cerr << "[PE " << moi
1746 << "] Error in Scatter::reordonner_faces_de_joint:\n"
1747 << " the number of joint faces is not identical to the PE "
1748 << pe_voisin << finl;
1749 exit();
1750 }
1751 const int nb_erreurs =
1752 dictionnaire_indices.traduire_indice_global_vers_local(faces_num_global,
1753 faces_sommets);
1754 if (nb_erreurs > 0)
1755 {
1756 Cerr << "[PE " << moi
1757 << "] Error in Scatter::reordonner_faces_de_joint:\n"
1758 << " The faces of the joint with PE " << pe_voisin
1759 << " use of unknown nodes" << finl;
1760 exit();
1761 }
1762 }
1763 }
1764 schema_comm.end_comm();
1765}
1766
1767/*! @brief Methode outil: renvoie une liste complete de tous les sommets de joint (sommets des faces + sommets isoles), triee et
1768 *
1769 * sans doublons
1770 *
1771 */
1772static void calculer_liste_complete_sommets_joint(const Joint& joint, ArrOfInt& liste_sommets)
1773{
1774 liste_sommets = joint.joint_item(JOINT_ITEM::SOMMET).items_communs();
1775#if 0
1776
1777 // On prend tous les sommets des faces de joint:
1778 const IntTab& som_faces = joint.faces().les_sommets();
1779 liste_sommets = ref_cast(ArrOfInt,som_faces);
1780 // On ajoute tous les sommets isoles :
1781 const ArrOfInt& som_isoles = joint.sommets();
1782 const int n = som_isoles.size_array();
1783 for (int i = 0; i < n; i++)
1784 liste_sommets.append_array(som_isoles[i]);
1785 // Retirer les doublons de la liste
1786 array_trier_retirer_doublons(liste_sommets);
1787#endif
1788}
1789
1790inline int arete_de_sommets_Si_et_Sj(const int Si, const int Sj, const int arete, const IntTab& aretes_som)
1791{
1792 if ( (aretes_som(arete,0) == Si && aretes_som(arete,1) == Sj)
1793 || (aretes_som(arete,1) == Si && aretes_som(arete,0) == Sj) )
1794 return 1;
1795 else
1796 return 0;
1797}
1798
1799/*! @brief Methode outil: renvoie une liste complete de tous les aretes de joint (aretes des faces + aretes isolees), triee et
1800 *
1801 * sans doublons
1802 *
1803 */
1804static void calculer_liste_complete_aretes_joint(const Joint& joint, ArrOfInt& liste_aretes)
1805{
1806 // Construction de la liste des aretes communes liste_aretes
1807
1808 ///////////////////////////////////////////////////////
1809 // Recherche des aretes de joint sur les faces de joint
1810 ///////////////////////////////////////////////////////
1811 int nb_faces_joint=joint.faces().nb_faces();
1812 int nb_som_faces=joint.faces().nb_som_faces();
1813 const IntTab& sommet=joint.faces().les_sommets();
1814 const Domaine& dom=joint.domaine();
1815 const DoubleTab& coord=dom.coord_sommets();
1816 const IntTab& aretes_som=joint.domaine().aretes_som();
1817 ArrOfInt aretes(1);
1818 int compteur=0;
1819 DoubleTab positions(1,Objet_U::dimension);
1820 ArrOfInt som_faces(nb_faces_joint*nb_som_faces);
1821 // On parcourt 2 a 2 les sommets de chaque face du joint
1822 for (int face=0; face<nb_faces_joint; face++)
1823 for (int i=0; i<nb_som_faces; i++)
1824 {
1825 int Si = sommet(face,i);
1826 som_faces[face*nb_som_faces+i]=Si;
1827 for (int j=i; j<nb_som_faces; j++)
1828 {
1829 int Sj = sommet(face,j);
1830 // Calcul du point C entre 2 sommets Si et Sj
1831 for (int comp=0; comp<Objet_U::dimension; comp++)
1832 positions(0,comp)=0.5*(coord(Si,comp)+coord(Sj,comp));
1833 dom.chercher_aretes(positions,aretes);
1834 // Si on trouve une arete dont le centre coincide avec le point C
1835 // et dont les sommets sont identiques a Si et Sj, on ajoute l'arete a la liste
1836 if (aretes[0]>=0 && arete_de_sommets_Si_et_Sj(Si, Sj, aretes[0], aretes_som))
1837 {
1838 compteur++;
1839 liste_aretes.append_array(aretes[0]);
1840 }
1841 }
1842 }
1843 Process::Journal() << "common edges found on faces of joint with " << joint.PEvoisin() << " :" << compteur << finl;
1844 /////////////////////////////////////////////////////////////////////////
1845 // Recherche des aretes de joint isolees sur les sommets de joints isoles
1846 /////////////////////////////////////////////////////////////////////////
1847 // joint.sommets() contient parfois tous les sommets !
1848 // Donc on construit un tableau som_isoles
1849 ArrOfInt som_isoles;
1850 // Met tous les sommets dans som_isoles (isoles+issus des faces de joint):
1851 calculer_liste_complete_sommets_joint(joint, som_isoles);
1852 // On trie som_faces et on supprime les doublons
1853 array_trier_retirer_doublons(som_faces);
1854 // Supprime tous les sommets de som_isoles contenus dans som_faces
1855 array_retirer_elements(som_isoles, som_faces);
1856 // Supprime les sommets des faces de joint
1857 const int n = som_isoles.size_array();
1858 Process::Journal() << "number of isolated nodes: " << n << finl;
1859 Process::Journal() << "number of nodes of faces of joint: " << 3*sommet.dimension(0) << finl;
1860
1861 compteur=0;
1862 // On parcourt 2 a 2 les sommets isoles
1863 for (int i = 0; i < n; i++)
1864 for (int j = i; j < n; j++)
1865 {
1866 // Calcul du point C entre 2 sommets Si et Sj
1867 int Si = som_isoles[i];
1868 int Sj = som_isoles[j];
1869 for (int comp=0; comp<Objet_U::dimension; comp++)
1870 positions(0,comp)=0.5*(coord(Si,comp)+coord(Sj,comp));
1871 dom.chercher_aretes(positions,aretes);
1872 // Si on trouve une arete dont le centre coincide avec le point C
1873 // et dont les sommets sont identiques a Si et Sj, on ajoute l'arete a la liste
1874 if (aretes[0]>=0 && arete_de_sommets_Si_et_Sj(Si, Sj, aretes[0], aretes_som))
1875 {
1876 compteur++;
1877 liste_aretes.append_array(aretes[0]);
1878 }
1879 }
1880 Process::Journal() << "common edges found isolated on joint with " << joint.PEvoisin() << " :" << compteur << finl;
1881 // Retirer les doublons de la liste
1882 array_trier_retirer_doublons(liste_aretes);
1883}
1884
1885static void calculer_liste_complete_items_joint(const Joint& joint, const JOINT_ITEM type_item, ArrOfInt& liste_items)
1886{
1887 switch(type_item)
1888 {
1889 case JOINT_ITEM::SOMMET:
1890 calculer_liste_complete_sommets_joint(joint, liste_items);
1891 break;
1892 case JOINT_ITEM::ARETE:
1893 calculer_liste_complete_aretes_joint(joint, liste_items);
1894 break;
1895 default:
1896 Cerr << "Error in Scatter::calculer_liste_complete_items_joint" << finl;
1897 Cerr << "Type of item not expected." << finl;
1898 Process::exit();
1899 }
1900}
1901
1902/*! @brief Les algorithmes actuels pour le periodique (assembleur P1B, OpDivElem P1B) ont besoin que pour chaque face virtuelle periodique, la face opposee soit
1903 *
1904 * aussi virtuelle. Ceci n'est pas assure a la sortie de la methode
1905 * calculer_elements_distants. Cette methode ajoute aux elements distants les
1906 * elements manquants pour assurer cette condition:
1907 * Si un element est distant pour un PE donne est voisin d'une face periodique,
1908 * on ajoute a l'espace distant l'element adjacent a la face opposee.
1909 *
1910 */
1912{
1914 Cerr << "Correction of remote spaces of the elements for the periodic faces" << finl;
1915
1916 const Noms& liste_bords_periodiques = dom.bords_perio();
1917
1918 const int nb_elem = dom.nb_elem();
1919 const IntTab& les_elems = dom.les_elems();
1920
1921 // Ce tableau contiendra pour un bord periodique donne:
1922 // si l'element i est adjacent a une face de ce bord,
1923 // element_oppose[i] est le numero de l'element adjacent a la face
1924 // opposee sur ce bord.
1925 // -1 sinon.
1926 ArrOfInt element_oppose(nb_elem);
1927
1928 Static_Int_Lists connectivite_som_elem;
1929 const int nb_sommets = dom.nb_som();
1930 construire_connectivite_som_elem(nb_sommets,
1931 les_elems,
1932 connectivite_som_elem,
1933 0 /* ne pas inclure les sommets virtuels */);
1934
1935 const int nb_som_face = dom.type_elem()->nb_som_face();
1936 ArrOfInt une_face(nb_som_face);
1937 ArrOfInt elems_voisins;
1938
1939
1940 const int nb_joints = dom.nb_joints();
1941
1942 // Marqueurs des elements distants existants:
1943 ArrOfBit marqueurs_elements_distants(nb_elem);
1944 marqueurs_elements_distants = 0;
1945
1946 // Le fait d'ajouter un element dans un espace distant pour un bord donne
1947 // peut entrainer un probleme sur un autre bord (l'element oppose de l'element
1948 // ainsi ajoute peut manquer pour une autre direction de periodicite).
1949 // Il faut dont iterer jusqu'a ce que plus rien ne bouge
1950 int nb_elements_ajoutes = 0;
1951 do
1952 {
1953 nb_elements_ajoutes = 0;
1954 for (auto& itr : liste_bords_periodiques)
1955 {
1956 const Nom& nom_bord = itr;
1957 const Bord& bord = dom.bord(nom_bord);
1958 const IntTab& faces_sommets = bord.les_sommets_des_faces();
1959 const int nb_faces = bord.nb_faces();
1960
1961 // Premiere etape, reperer les element opposes pour ce bord periodique
1962 // On boucle sur la premiere moitie de la frontiere.
1963 // ATTENTION: on suppose que les faces de bords sont ordonnees : d'abord toutes les faces
1964 // d'un cote du domaine periodique, puis, dans le meme ordre, les faces opposees.
1965 element_oppose = -1;
1966
1967 for (int i_face = 0; i_face < nb_faces / 2; i_face++)
1968 {
1969 // Pour chaque face, trouver l'element adjacent a cette face et a la face opposee
1970 // Boucle sur la face et la face opposee
1971 int elem0 = -1; // Les deux elements opposes de cette face periodique
1972 int elem1 = -1;
1973 for (int quel_cote = 0; quel_cote < 2; quel_cote++)
1974 {
1975 const int face = i_face + quel_cote * nb_faces / 2;
1976 int i;
1977 for (i = 0; i < nb_som_face; i++)
1978 une_face[i] = faces_sommets(face, i);
1979 find_adjacent_elements(connectivite_som_elem, une_face, elems_voisins);
1980 const int n = elems_voisins.size_array();
1981 if (n != 1)
1982 {
1983 Cerr << "Error in Scatter::corriger_espace_distant_elements_perio: \n"
1984 << " The face " << i_face << " of boundary " << nom_bord << " has "
1985 << n << " neighbors." << finl;
1986 Process::exit();
1987 }
1988 if (quel_cote == 0)
1989 elem0 = elems_voisins[0];
1990 else
1991 elem1 = elems_voisins[0];
1992 }
1993 element_oppose[elem0] = elem1;
1994 element_oppose[elem1] = elem0;
1995 }
1996 // Deuxieme etape: parcourir les elements distants. Si un element distant est
1997 // dans les elements jumeaux, ajouter l'autre jumeau dans les elements distants
1998 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
1999 {
2000 ArrOfInt& elements_distants = dom.joint(i_joint).set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants();
2001 int n = elements_distants.size_array();
2002 // Marquer les elements distants existants:
2003 int i;
2004 for (i = 0; i < n; i++)
2005 {
2006 const int elem = elements_distants[i];
2007 marqueurs_elements_distants.setbit(elem);
2008 }
2009
2010 for (i = 0; i < n; i++)
2011 {
2012 const int elem = elements_distants[i];
2013 const int elem_oppose = element_oppose[elem];
2014 if (elem_oppose >= 0 && (!marqueurs_elements_distants.testsetbit(elem_oppose)))
2015 {
2016 elements_distants.append_array(elem_oppose);
2017 nb_elements_ajoutes++;
2018 }
2019 }
2020 // Remettre a zero le tableau de marqueurs:
2021 n = elements_distants.size_array();
2022 for (i = 0; i < n; i++)
2023 {
2024 const int elem = elements_distants[i];
2025 marqueurs_elements_distants.clearbit(elem);
2026 }
2027 }
2028 }
2029
2030 }
2031 while (nb_elements_ajoutes > 0);
2032 // Dernier tri des elements distants dans l'ordre croissant
2033 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
2034 {
2035 ArrOfInt& elements_distants = dom.joint(i_joint).set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants();
2036
2037 elements_distants.ordonne_array();
2038 }
2039}
2040
2041/*! @brief Remplissage du tableau "espace_distant()" des elements dans les joints.
2042 *
2043 * C'est ici qu'on determine les elements de joint en fonction de l'epaisseur de joint.
2044 * Le tableau espace_distant contient les
2045 * indices locaux des elements distants (a envoyer aux processeurs voisins)
2046 * Pour un joint d'epaisseur 1, ce sont tous les elements voisins d'un
2047 * sommet de joint (sommet sur un face de joint ou sommet isole).
2048 * Pour un joint d'epaisseur n>1, ce sont tous les elements voisins d'un
2049 * sommet d'un element du joint d'epaisseur n-1.
2050 * Le voisinage s'entend sur le domaine global (toutes domaines confondues)
2051 * Historique: premiere version B.Mathieu le 16/01/2007.
2052 * Il existe une methode qui determine les elements distants au moment du decoupage
2053 * (DomaineCutter::construire_elements_distants_ssdom).
2054 * La methode ci-dessous a ete validee par comparaison avec la methode du decoupeur.
2055 * Les sorties ont ete verifiees pour des epaisseurs jusqu'a 5 sur des maillages tetra.
2056 * La difficulte de l'algorithme est d'obtenir les elements virtuels d'epaisseur > 1 qui se
2057 * trouvent sur des sous-domaines qui ne sont pas en contact direct avec le sous-domaine
2058 * local. Difficulte resolue par l'algorithme ci-dessous.
2059 *
2060 */
2062{
2063 const int nbjoints = dom.nb_joints();
2064 const int nb_som_elem = dom.nb_som_elem();
2065 const IntTab& les_elems = dom.les_elems();
2066 const int nproc = Process::nproc();
2067 // PL on doit avoir la meme epaisseur_joint sur chaque processeur pour l'algorithme suivant
2068 // utilisant un echange de donnees avec schema_comm.begin_comm() schema_comm.end_comm()
2069 // sinon il y'a un blocage en mode debug a cause de la sortie de la ligne 1866 (voir cas Quasi_Comp_Coupl_Incomp)
2070 //const int epaisseur_joint = (nb_joints > 0) ? domaine.joint(0).epaisseur() : 1;
2071 const int epaisseur_joint = (int) mp_max((nbjoints > 0) ? dom.joint(0).epaisseur() : 1);
2072
2074 Cerr << "Calculation of remote space of elements : thickness " << epaisseur_joint << finl;
2075
2076 // L'algorithme repose sur la construction progressive du tableau "liste_sommets".
2077 // liste_sommets(pe) contient a un instant donne la liste des sommets possedes par me()
2078 // dont le "pe" veut connaitre les elements voisins.
2079 // Chaque pe commence par reclamer ses elements voisins directs, c'est a dire les elements
2080 // voisins des sommets de joint. On sait qu'il voudra ensuite les elements voisins des elements
2081 // ainsi trouves, donc on ajoutera aux listes les sommets des elements distants trouves
2082 // a l'iteration precedente.
2083 ArrsOfInt liste_sommets(nproc);
2084
2085 // Pour chaque processeur, la liste des elements locaux qu'il faut lui envoyer
2086 ArrsOfInt elements_distants(nproc);
2087 {
2088 // smart_resize car on va faire append_array sur ces tableaux
2089 for (int i = 0; i < nproc; i++)
2090 {
2091
2092
2093 }
2094 }
2095
2096 Static_Int_Lists som_elem;
2097 {
2099 Cerr << "Nodes-elements connectivity ..." << finl;
2100 const int nb_sommets = dom.nb_som();
2101 construire_connectivite_som_elem(nb_sommets,
2102 les_elems,
2103 som_elem,
2104 0 /* ne pas inclure les sommets virtuels */);
2105 }
2106
2107 ArrOfInt liste_pe_voisins(nbjoints);
2108
2109 // Initialisation de liste_pe_voisins et
2110 // initialisation de la liste de sommets: chaque processeur requiert tous les elements
2111 // voisins de ses sommets de joint. Le processeur local sait que pour l'epaisseur 1,
2112 // chaque processeur voisin par un joint veut connaitre tous les elements voisins
2113 // des sommets de joint. Donc on met dans liste_sommets(pe) les sommets de joint avec ce pe,
2114 // se sorte a lui envoyer les elements locaux voisins de ces sommets.
2115 {
2116 for (int i_joint = 0; i_joint < nbjoints; i_joint++)
2117 {
2118 const Joint& joint = dom.joint(i_joint);
2119 const int pe = joint.PEvoisin();
2120 liste_pe_voisins[i_joint] = pe;
2121 const ArrOfInt& sommets_joint = joint.joint_item(JOINT_ITEM::SOMMET).items_communs();
2122 liste_sommets[pe] = sommets_joint;
2123 }
2124 }
2125
2126 // On va avoir besoin d'un schema de communication ou chaque processeur envoie et recoit
2127 // des donnees a ses voisins directs (voisins par un sommet)
2128 Schema_Comm schema_comm;
2129 schema_comm.set_send_recv_pe_list(liste_pe_voisins, liste_pe_voisins);
2130
2131 // On va avoir besoin d'un acces rapide a la liste des processeurs qui partagent un
2132 // sommet et a l'indice de ce sommet sur ce processeur.
2133 // Contenu de la structure:
2134 // data_sommets_communs.get_list_size(sommet) = 2*le nombre de procs qui partagent le sommet
2135 // data_sommets_communs(sommet, 2*i) = numero du pe voisin
2136 // data_sommets_communs(sommet, 2*i+1) = indice du sommet sur ce pe.
2137 Static_Int_Lists data_sommets_communs;
2138 // Remplissage : la structure n'est utilisee que si l'epaisseur de joint est > 1
2139 if (epaisseur_joint > 1)
2140 {
2141 ArrOfInt count(dom.nb_som());
2142 // Etape 1 : avec combien de processeurs chaque sommet est-il partage ?
2143 for (int ijoint = 0; ijoint < nbjoints; ijoint++)
2144 {
2145 const Joint& joint = dom.joint(ijoint);
2146 const ArrOfInt& sommets_joint = joint.joint_item(JOINT_ITEM::SOMMET).items_communs();
2147 const int n = sommets_joint.size_array();
2148 for (int i = 0; i < n; i++)
2149 {
2150 const int som = sommets_joint[i];
2151 count[som] += 2; // On stocke 2 entiers par sommets commun
2152 }
2153 }
2154 data_sommets_communs.set_list_sizes(count);
2155 count = 0;
2156 // Etape 2 : remplissage de la structure:
2157 for (int ijoint = 0; ijoint < nbjoints; ijoint++)
2158 {
2159 const Joint& joint = dom.joint(ijoint);
2160 const int pe = joint.PEvoisin();
2161 const IntTab& renum_sommets = joint.joint_item(JOINT_ITEM::SOMMET).renum_items_communs();
2162 const int n = renum_sommets.dimension(0);
2163 for (int i = 0; i < n; i++)
2164 {
2165 // Indice du sommet partage sur le pe voisin
2166 const int i_sommet_distant = renum_sommets(i, 0);
2167 // Indice du sommet partage sur ma domaine locale
2168 const int i_sommet_local = renum_sommets(i, 1);
2169 const int j = count[i_sommet_local]++;
2170 data_sommets_communs.set_value(i_sommet_local, j*2, pe);
2171 data_sommets_communs.set_value(i_sommet_local, j*2+1, i_sommet_distant);
2172 }
2173 }
2174 }
2175
2176 // Boucle sur l'epaisseur de joint:
2177 // A l'entree de la boucle, on suppose que liste_sommets contient, pour chaque processeur
2178 // qui requiert des elements virtuels, la liste des sommets de me() dont il veut les voisins.
2179 for (int epaisseur = 1; ; epaisseur++)
2180 {
2182 Cerr << " Calculation of the thickness " << epaisseur << finl;
2183
2184 // Pour chaque liste de sommets, mettre dans les elements distants du meme processeur
2185 // les elements voisins des sommets de la liste.
2186 int pe;
2187 for (pe = 0; pe < nproc; pe++)
2188 {
2189 ArrOfInt& elems_dist = elements_distants[pe];
2190 const ArrOfInt& sommets = liste_sommets[pe];
2191 elems_dist.resize_array(0);
2192 const int nb_som_liste = sommets.size_array();
2193 for (int isom = 0; isom < nb_som_liste; isom++)
2194 {
2195 const int som = sommets[isom];
2196 if (som<0)
2197 continue;
2198 const int nb_elem_som = som_elem.get_list_size(som);
2199 for (int ielem = 0; ielem < nb_elem_som; ielem++)
2200 {
2201 const int elem = som_elem(som, ielem);
2202 elems_dist.append_array(elem);
2203 }
2204 }
2205 array_trier_retirer_doublons(elems_dist);
2206 }
2207
2208 // La suite est la mise a jour de liste_sommets pour l'iteration suivante.
2209 // Inutile de le faire si on est a la derniere iteration:
2210 if (epaisseur == epaisseur_joint)
2211 break;
2212
2213 // Mettre dans les listes de sommets les sommets des elements distants trouves
2214 for (pe = 0; pe < nproc; pe++)
2215 {
2216 ArrOfInt& sommets = liste_sommets[pe];
2217 const ArrOfInt& elems_dist = elements_distants[pe];
2218 sommets.resize_array(0);
2219 const int nb_elems_dist = elems_dist.size_array();
2220 for (int ielem = 0; ielem < nb_elems_dist; ielem++)
2221 {
2222 const int elem = elems_dist[ielem];
2223 for (int isom = 0; isom < nb_som_elem; isom++)
2224 {
2225 const int som = les_elems(elem, isom);
2226 sommets.append_array(som);
2227 }
2228 }
2229 array_trier_retirer_doublons(sommets);
2230 }
2231 // Parcourir les listes de sommets. Pour chaque sommet, s'il est de joint,
2232 // envoyer aux processeurs possedant ce sommet une requete "le processeur i
2233 // veut tous les voisins de ce sommet".
2234 // Ne pas envoyer la requete au processeur "i" pour la liste "i": il connait
2235 // deja ses propres elements !
2236 schema_comm.begin_comm();
2237 // Premiere phase de communication: empiler les donnees a envoyer dans des buffers
2238 for (pe = 0; pe < nproc; pe++)
2239 {
2240 const ArrOfInt& sommets = liste_sommets[pe];
2241 const int nb_som_liste = sommets.size_array();
2242 for (int isom = 0; isom < nb_som_liste; isom++)
2243 {
2244 const int i_sommet_local = sommets[isom];
2245 if (i_sommet_local<0)
2246 continue;
2247 const int nb_pe_voisins = data_sommets_communs.get_list_size(i_sommet_local) / 2;
2248 for (int i = 0; i < nb_pe_voisins; i++)
2249 {
2250 const int pe_voisin = data_sommets_communs(i_sommet_local, i*2);
2251 // Indice du sommet sur le processeur voisin.
2252 const int i_sommet_distant = data_sommets_communs(i_sommet_local, i*2+1);
2253 if (pe_voisin != pe)
2254 {
2255 // Envoyer au processeur "pe_voisin" le message : "le processeur PE a besoin
2256 // des elements voisins du sommet i_sommet_distant"
2257 schema_comm.send_buffer(pe_voisin) << pe << i_sommet_distant;
2258 }
2259 }
2260 }
2261 }
2262 schema_comm.echange_taille_et_messages();
2263 for (int i_pevoisin = 0; i_pevoisin < nbjoints; i_pevoisin++)
2264 {
2265 const int pe_voisin = liste_pe_voisins[i_pevoisin];
2266 Entree& buffer = schema_comm.recv_buffer(pe_voisin);
2267 for (;;)
2268 {
2269 int pe2, sommet;
2270 // On recupere le message "le processeur PE a besoin des elements voisins de SOMMET".
2271 buffer >> pe2 >> sommet;
2272 if (buffer.eof())
2273 break;
2274 liste_sommets[pe2].append_array(sommet);
2275 }
2276 }
2277 schema_comm.end_comm();
2278 // Supprimer les doublons dans les listes de sommets
2279 for (pe = 0; pe < nproc; pe++)
2280 {
2281 ArrOfInt& sommets = liste_sommets[pe];
2282 array_trier_retirer_doublons(sommets);
2283 }
2284 }
2285
2286 // Creation des nouveaux joints si besoin, et stockage des elements distants dans les joints
2287 {
2288 ArrOfInt voisins;
2289
2290
2291 for (int pe = 0; pe < nproc; pe++)
2292 if (elements_distants[pe].size_array() > 0)
2293 voisins.append_array(pe);
2294 ajouter_joints(dom, voisins);
2295
2296#ifdef CHECK_ALGO_ESPACE_VIRTUEL
2297 // On n'utilise pas les espaces virtuels calcules ci-dessus, on se
2298 // contente de les comparer aux espaces virtuels calcules lors du decoupage
2299 // par l'algorithme sequentiel.
2300 // Pour l'instant, l'algorithme parallele a l'air de fonctionner sans probleme
2301 // je desactive ce test. (Benoit Mathieu)
2302 bool erreur = false;
2303 const int nbjoints = dom.nbjoints();
2304 for (int i = 0; i < nbjoints; i++)
2305 {
2306 Joint& joint = dom.joint(i);
2307 const int pe = joint.PEvoisin();
2308 if (!(joint.joint_item(JOINT_ITEM::ELEMENT).items_distants() == elements_distants[pe]))
2309 {
2310 Cerr << "Error in Scatter, PE " << Process::me() << finl;
2311 Process::Journal() << "Error scatter, remote elements pe " << pe << finl
2312 << " Splitting algorithm: " << joint.joint_item(JOINT_ITEM::ELEMENT).items_distants()
2313 << " Scatter algorithm : " << elements_distants[pe] << finl;
2314
2315 erreur = true;
2316 }
2317 }
2318 if (mp_or(erreur))
2319 Process::exit();
2320#else
2321 // Stockage du resultat
2322 const int nb_joints = dom.nb_joints();
2323 for (int i = 0; i < nb_joints; i++)
2324 {
2325 Joint& joint = dom.joint(i);
2326 const int pe = joint.PEvoisin();
2327 joint.set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants() = elements_distants[pe];
2328 }
2329#endif
2330 }
2331}
2332
2333static inline int fct_cmp_coordonnees(const double * s1, const double *s2, int dim, const double epsilon)
2334{
2335 assert(dim==2 || dim==3);
2336 if (s1[0] < s2[0] - epsilon)
2337 return -1;
2338 else if (s1[0] > s2[0] + epsilon)
2339 return 1;
2340 else if (s1[1] < s2[1] - epsilon)
2341 return -1;
2342 else if (s1[1] > s2[1] + epsilon)
2343 return 1;
2344 else if (dim<3)
2345 return 0;
2346 else if (s1[2] < s2[2] - epsilon)
2347 return -1;
2348 else if (s1[2] > s2[2] + epsilon)
2349 return 1;
2350 else
2351 return 0;
2352}
2353
2354/*! @brief Construit le tableau "correspondance" tel que Pour 0 <= i < sommets2.
2355 *
2356 * size_array(),
2357 * Si sommet2(i) existe dans le tableau sommet1, alors
2358 * sommets2(i, ...) == sommets1(correspondance[i], ...)
2359 * Sinon
2360 * correspondance[i] = -1
2361 * L'egalite est verifiee a epsilon pres en absolu (soit abs(x1-x2)<epsilon)
2362 * L'algorithme est generalement en n1*log(n1) + n2*log(n1)
2363 * (recherche basee sur un quicksort).
2364 * En cas d'echec du tri, on utilise un algorithme en n1*n2.
2365 * Les tableaux sommets1 et sommets2 doivent etre de dimension 2
2366 * Le tableau correspondance doit etre de taille sommets2.size_array().
2367 * Valeur de retour: nombre de sommets de sommets2 non trouves dans le tableau sommets1.
2368 *
2369 */
2370int Scatter::Chercher_Correspondance(const DoubleTab& sommets1, const DoubleTab& sommets2,
2371 ArrOfInt& correspondance, const double epsilon)
2372{
2373 const int nb_sommets1 = sommets1.dimension(0);
2374 const int nb_sommets2 = sommets2.dimension(0);
2375 // Precondition necessaire pour fct_cmp_index_coord
2376 assert(sommets1.nb_dim() == 2);
2377 assert(sommets2.nb_dim() == 2);
2378 assert(correspondance.size_array() == nb_sommets2);
2379 if (nb_sommets1 < 1)
2380 {
2381 correspondance = -1;
2382 return nb_sommets2;
2383 }
2384
2385 // Tableau d'indirection trie, tel que les coordonnees sommets1(index[i], .) soient
2386 // tiees dans l'ordre lexicographique.
2387 ArrOfInt index(nb_sommets1);
2388 {
2389 int i;
2390 for (i = 0; i < nb_sommets1; i++)
2391 index[i] = i;
2392 }
2393
2394 // Tri du tableau d'index
2395 // On trie les sommets par ordre lexicographique des coordonnees.
2396 // Comme on fait un test a epsilon pres, le tri peut echouer:
2397 // Si x=1, y=1.01, z=1.02 et epsilon=0.01, on a
2398 // x==y (a epsilon pres)
2399 // y==z (a epsilon pres)
2400 // mais x!=z
2401 // Donc la recherche par dichotomie peut echouer par la suite.
2402 tri_lexicographique_tableau_indirect(sommets1, index);
2403
2404 // Construction du tableau de correspondance tel que
2405 // sommet1(correspondance[i], ...) == sommet2(i, ...)
2406 int nb_sommets_non_trouves = 0;
2407 int nb_echec_dichotomie = 0;
2408 {
2409 int i;
2410 int nb_dim = sommets1.dimension(1);
2411 for (i = 0; i < nb_sommets2; i++)
2412 {
2413 const double * s2 = & sommets2(i,0);
2414 int num_sommet = -1;
2415
2416 // D'abord recherche du sommet dans le tableau sommets1 par dichotomie (bsearch)
2417 int imin = 0;
2418 int imax = nb_sommets1 - 1;
2419 int resu_cmp = -1;
2420 int k = -1;
2421 while (imax > imin)
2422 {
2423 const int milieu = (imin + imax) >> 1; // (min+max)/2
2424 k = index[milieu];
2425 const double * s1 = & sommets1(k, 0);
2426 resu_cmp = fct_cmp_coordonnees(s1, s2, nb_dim, epsilon);
2427 switch(resu_cmp)
2428 {
2429 case -1:
2430 imin = milieu + 1;
2431 break; // s1<s2
2432 case 1 :
2433 imax = milieu - 1;
2434 break; // s1>s2
2435 default:
2436 imin = imax = milieu;
2437 break; // s1==s2
2438 }
2439 }
2440 if (resu_cmp != 0)
2441 {
2442 k = index[imin];
2443 const double * s1 = & sommets1(k, 0);
2444 resu_cmp = fct_cmp_coordonnees(s1, s2, nb_dim, epsilon);
2445 }
2446 if (resu_cmp == 0)
2447 {
2448 num_sommet = k;
2449 }
2450 else
2451 {
2452 nb_echec_dichotomie++;
2453 // Si echec, c'est peut-etre que le tableau n'est pas ordonne correctement
2454 // => recherche du sommet en parcourant tout le tableau
2455 int j;
2456 for (j = 0; j < nb_sommets1; j++)
2457 {
2458 const double * s1 = & sommets1(j,0);
2459 resu_cmp = fct_cmp_coordonnees(s1, s2, nb_dim, epsilon);
2460 if (resu_cmp == 0)
2461 break;
2462 }
2463 if (j < nb_sommets1)
2464 num_sommet = j;
2465 else
2466 nb_sommets_non_trouves++;
2467 }
2468
2469 correspondance[i] = num_sommet;
2470 }
2471 }
2472
2473 if (nb_echec_dichotomie > 0)
2474 Process::Journal() << "Chercher_Correspondance Dichotomy failure rate "
2475 << nb_echec_dichotomie << " / " << nb_sommets2 << finl;
2476
2477 return nb_sommets_non_trouves;
2478}
2479
2480/*! @brief Generic method to build geometrical item correspondance between the local and the remote processor
2481 * around a joint.
2482 *
2483 * See also construire_correspondance_sommets_par_coordonnees() for the very specific usage of allow_resize.
2484 *
2485 */
2486void Scatter::construire_correspondance_items_par_coordonnees(Joints& joints, const JOINT_ITEM type_item,
2487 const DoubleTab& coord_items, bool allow_resize)
2488{
2489 switch(type_item)
2490 {
2491 case JOINT_ITEM::SOMMET:
2492 break;
2493 case JOINT_ITEM::ARETE:
2494 break;
2495 default:
2496 Cerr << "Scatter::construire_correspondance_items_par_coordonnees unusable for item "
2497 << (int)type_item
2498 << finl;
2499 Process::exit();
2500 }
2501 const int dim = Objet_U::dimension;
2502 const int nb_joints = joints.size();
2503
2504 // Indices des items de joints dans le domaine sur mon processeur
2505 ArrsOfInt indices_items_locaux(nb_joints);
2506 // Indices des items de joints dans le domaine sur le processeur voisin
2507 ArrsOfInt indices_items_distants(nb_joints);
2508 // Coordonnees des items correspondants (dans le meme ordre que indices_items_xxx)
2509 DoubleTabs coord_items_locaux(nb_joints);
2510 DoubleTabs coord_items_distants(nb_joints);
2511
2512 // Remplissage des tableaux indices_items_locaux
2513 // et coord_items_locaux
2514 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
2515 {
2516 const Joint& joint = joints[i_joint];
2517 ArrOfInt& items = indices_items_locaux[i_joint];
2518 // Remarque: **LISTE_TRI** les indices_items_locaux sont
2519 // tries dans l'ordre croissant:
2520 calculer_liste_complete_items_joint(joint, type_item, items);
2521
2522 const int n = items.size_array();
2523 DoubleTab& coord = coord_items_locaux[i_joint];
2524 coord.resize(n, dim);
2525 for (int i = 0; i < n; i++)
2526 for (int j = 0; j < dim; j++)
2527 coord(i,j) = coord_items(items[i], j);
2528 }
2529
2530 // Envoi des indices et coordonnees locaux au processeur voisin
2531 {
2532 Schema_Comm schema_comm;
2533 ArrOfInt liste_pe_voisins(nb_joints);
2534 int i;
2535 for (i = 0; i < nb_joints; i++)
2536 liste_pe_voisins[i] = joints[i].PEvoisin();
2537 schema_comm.set_send_recv_pe_list(liste_pe_voisins, liste_pe_voisins);
2538 schema_comm.begin_comm();
2539 for (i = 0; i < nb_joints; i++)
2540 {
2541 const int pe = liste_pe_voisins[i];
2542 Sortie& buffer = schema_comm.send_buffer(pe);
2543 buffer << indices_items_locaux[i];
2544 buffer << coord_items_locaux[i];
2545 }
2546 schema_comm.echange_taille_et_messages();
2547 for (i = 0; i < nb_joints; i++)
2548 {
2549 const int pe = liste_pe_voisins[i];
2550 Entree& buffer = schema_comm.recv_buffer(pe);
2551 buffer >> indices_items_distants[i];
2552 buffer >> coord_items_distants[i];
2553 }
2554 schema_comm.end_comm();
2555 }
2556
2557 // Boucle sur les joints
2558 // Cette fois, on modifie les joints (remplissage de renum_virt_loc)
2559 const int moi = Process::me();
2560 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
2561 {
2562 Joint& joint = joints[i_joint];
2563 const int PEvoisin = joint.PEvoisin();
2564 const ArrOfInt& indices_locaux = indices_items_locaux[i_joint];
2565 const DoubleTab& coord_locaux = coord_items_locaux[i_joint];
2566 const DoubleTab& coord_distants = coord_items_distants[i_joint];
2567 const int n = indices_locaux.size_array();
2568
2569 // Recherche des correspondances entre items
2570 ArrOfInt corresp(n);
2571 const double epsilon = Objet_U::precision_geom;
2572 Chercher_Correspondance(coord_distants, coord_locaux, corresp, epsilon);
2573
2574 int nb_items_communs_trouves=0;
2575 for (int k = 0; k < n; k++)
2576 if (corresp[k]>=0) nb_items_communs_trouves++;
2577
2578 ArrOfInt& items_communs = joint.set_joint_item(type_item).set_items_communs();
2579 if (allow_resize)
2580 items_communs.resize_array(nb_items_communs_trouves);
2581 else
2582 // If a resisze is not expected, everthing in items_communs should have been found:
2583 assert(items_communs.size_array() == nb_items_communs_trouves);
2584 items_communs = -1;
2585
2586 // If a resize is expected, we need to shift the indices in 'corresp' to fit into
2587 // a (smaller) array of size 'nb_items_communs_trouves', avoiding the non-matching indices
2588 int n_dist = coord_distants.dimension(0);
2589 std::vector<bool> corres_ok(n_dist, false);
2590 std::vector<int> offset(n_dist, 0);
2591 if(allow_resize)
2592 {
2593 // corres_ok[j] is true iif the (remote) item 'j' was matched with a local one
2594 for(int k = 0; k < n; k++)
2595 if (corresp[k] >= 0)
2596 corres_ok[corresp[k]] = true;
2597 // offset[k] is the shift to be substracted to the remote item index once the invalid (=non
2598 // matched) remote items have been removed:
2599 int nb_holes = 0; // nb of holes seen so far in corres_ok
2600 for(int k = 0; k < n_dist; k++)
2601 offset[k] = corres_ok[k] ? nb_holes : nb_holes++;
2602 }
2603
2604 int i=0;
2605 for (int k = 0; k < n; k++)
2606 {
2607 const int i_local = indices_locaux[k];
2608 // Le j-ieme item distant est identique au k-ieme item local
2609 const int j = corresp[k];
2610
2611 // Pas trouve ? Erreur possible
2612 if (j < 0)
2613 {
2614 if (!allow_resize)
2615 {
2616 Cerr << "Error in Scatter::remplir_renum_virt_loc on PE " << moi << finl
2617 << "The item of type " << (int)type_item << " number " << i_local << " with coordinates ";
2618 for (int k2 = 0; k2 < dim; k2++)
2619 Cerr << coord_locaux(i, k2) << " ";
2620 Cerr << finl << "was not found in the joint with the PE " << PEvoisin << finl;
2621 if (type_item==JOINT_ITEM::ARETE)
2622 {
2623 Cerr << "The searching algorithm of the isolated edges on a joint" << finl;
2624 Cerr << "does not work yet in some cases. Two isolated nodes of a joint (example below" << finl;
2625 Cerr << "joint between 0 and 2) can be those of an edge not belonging to this joint (below" << finl;
2626 Cerr << "the edge belongs to the joint 0-1 but not 0-2):" << finl;
2627 //Cerr << " ________ " << finl;
2628 //Cerr << "1\ 2/1\2 /1\ " << finl;
2629 //Cerr << "__\/___\/___\ " << finl;
2630 //Cerr << " 0/\ 0 /\ 0 " << finl;
2631 //Cerr << " / 0\ / 0\ " << finl;
2632 Cerr << " ________ " << finl;
2633 Cerr << "1\\ 2/1\\2 /1\\ " << finl;
2634 Cerr << "__\\/___\\/___\\" << finl;
2635 Cerr << " 0/\\ 0 /\\ 0 " << finl;
2636 Cerr << " / 0\\ / 0\\ " << finl;
2637 Cerr << finl;
2638 Cerr << "One way to by-pass this problem is to split again your domain with" << finl;
2639 Cerr << "different options of splitting or with another splitter to do not fall" << finl;
2640 Cerr << "on the same configuration." << finl;
2641 }
2642 exit();
2643 }
2644 }
2645 else
2646 {
2647 if (moi < PEvoisin)
2648 {
2649 // items communs dans l'ordre des items de joint locaux:
2650 items_communs[i] = i_local;
2651 // On verifie que c'est bien l'ordre croissant de l'indice local
2652 // (voir **LISTE_TRI**)
2653 assert(i==0 || items_communs[i] > items_communs[i-1]);
2654 }
2655 else
2656 {
2657 int j2 = j - offset[j];
2658 // items communs dans l'ordre des items sur le voisin:
2659 assert(items_communs[j2] < 0);
2660 items_communs[j2] = i_local;
2661 }
2662 i++;
2663 }
2664 }
2665 assert(i==nb_items_communs_trouves);
2666 }
2667 // Remplissage de renum_items_communs:
2668 calculer_renum_items_communs(joints, type_item);
2669}
2670
2671/*! @brief Construction des tableaux joint_item(JOINT_ITEM::SOMMET).items_communs de
2672 * tous les joints du domaine(0) du domaine dom.
2673 *
2674 * @param allow_resize may be set to True in some rare case (see Raffiner_isotrope_parallele)
2675 * when we know that the current size of 'items_communs' is wrong because part of the domain
2676 * was reszed / changed.
2677 */
2679{
2680 construire_correspondance_items_par_coordonnees(dom.faces_joint(), JOINT_ITEM::SOMMET, dom.coord_sommets(), allow_resize);
2681}
2682
2683/*! @brief Construction des tableaux joint_item(JOINT_ITEM::ARETE).items_communs de tous les joints du domaine
2684 *
2685 */
2690
2691/*! @brief Pour un item geometrique "type_item", remplit le champ nb_items_virtuels_ des joints en fonction
2692 * du nombre d'items distants :
2693 *
2694 * Le nombre d'items virtuels sur un joint i du processeur j est le
2695 * nombre d'items distants du joint j sur le processeur i.
2696 *
2697 */
2699 const JOINT_ITEM type_item)
2700{
2701 Schema_Comm schema_comm;
2702 const int nb_joints = joints.size();
2703 ArrOfInt liste_voisins(nb_joints);
2704 int i_joint;
2705 for (i_joint = 0; i_joint < nb_joints; i_joint++)
2706 liste_voisins[i_joint] = joints[i_joint].PEvoisin();
2707
2708 // On envoie le nombre d'items distants au PE voisin
2709 schema_comm.set_send_recv_pe_list(liste_voisins, liste_voisins);
2710 schema_comm.begin_comm();
2711 for (i_joint = 0; i_joint < nb_joints; i_joint++)
2712 {
2713 const Joint& joint = joints[i_joint];
2714 const Joint_Items& items = joint.joint_item(type_item);
2715 const int n = items.items_distants().size_array();
2716 const int pe = joint.PEvoisin();
2717 schema_comm.send_buffer(pe) << n;
2718 }
2719 // Echange des messages
2720 schema_comm.echange_taille_et_messages();
2721 // Le PE voisin recoit ce nombre d'items et le stocke.
2722 for (i_joint = 0; i_joint < nb_joints; i_joint++)
2723 {
2724 Joint& joint = joints[i_joint];
2725 Joint_Items& items = joint.set_joint_item(type_item);
2726 const int pe = joint.PEvoisin();
2727 int n;
2728 schema_comm.recv_buffer(pe) >> n;
2729 items.set_nb_items_virtuels(n);
2730 }
2731 schema_comm.end_comm();
2732}
2733
2734/*! @brief Create parallel descriptors for the vertex and element arrays of the domain (necessary because Scatter is
2735 * never invoked in sequential).
2736 *
2737 * In 64bit the corresponding number of items might be big. This is here the main justification for the need of the class
2738 * MD_Vector_seq which unique useful argument is the total number of items (with type trustIdType).
2739 * Alternative would have been to make all members of MD_Vector_std compatible with trustIdType ...
2740 */
2741template <typename _SIZE_>
2743{
2744 MD_Vector_seq mdseq_som(dom.les_sommets().dimension(0));
2745 MD_Vector md;
2746 md.copy(mdseq_som);
2747 dom.les_sommets().set_md_vector(md);
2748 MD_Vector_seq mdseq_elem(dom.les_elems().dimension(0));
2749 md.copy(mdseq_elem);
2750 dom.les_elems().set_md_vector(md);
2751}
2752
2753/*! @brief methode utilisee par les interpretes qui modifient le domaine (sequentiel), detruit les descripteurs
2754 * des sommets et elements pour permettre la modification de ces tableaux.
2755 */
2756template <typename _SIZE_>
2758{
2759 MD_Vector md; // descripteur nul
2760 dom.les_sommets().set_md_vector(md);
2761 dom.les_elems().set_md_vector(md);
2762}
2763
2764
2765// Explicit instanciation
2768#if INT_is_64_ == 2
2771#endif
int testsetbit(int_t i) const
Renvoie la valeur du bit e, puis met le bit e a 1.
Definition ArrOfBit.h:85
void setbit(int_t i) const
Met le bit e a 1.
Definition ArrOfBit.h:73
void clearbit(int_t i) const
Met le bit e a 0.
Definition ArrOfBit.h:100
classe Domaine_32_64 un Domaine est un maillage compose d'un ensemble d'elements geometriques de meme...
Definition Domaine.h:62
virtual void clear()
Reset the Domaine completely except for its name.
Definition Domaine.cpp:108
int nb_som_elem() const
Renvoie le nombre de sommets des elements geometriques constituants le domaine.
Definition Domaine.h:474
const IntTab_t & aretes_som() const
renvoie le tableau de connectivite aretes/sommets.
Definition Domaine.h:156
SmallArrOfTID_t & chercher_aretes(const DoubleTab &pos, SmallArrOfTID_t &arr, int reel=0) const
Definition Domaine.cpp:677
DoubleTab_t & les_sommets()
Definition Domaine.h:113
int nb_joints() const
Definition Domaine.h:259
IntTab_t & les_elems()
Definition Domaine.h:129
int_t nb_elem() const
Definition Domaine.h:131
void merge_wo_vertices_with(Domaine_32_64 &z)
Merge another Domaine into this, without considering vertices which are handled separately.
Definition Domaine.cpp:1237
void renum(const IntVect_t &nums)
Renumerotation des noeuds: Le noeud de numero k devient le noeud de numero Les_Nums[k].
Definition Domaine.cpp:2188
void read_former_domaine(Entree &s, bool &read_perio)
read what was (before TRUST 1.9.2) the "domaine" part from the input stream i.e. (roughly) the elemen...
Definition Domaine.cpp:259
Bord_t & bord(int i)
Definition Domaine.h:193
void read_vertices(Entree &s)
only read vertices from the stream s
Definition Domaine.cpp:1010
Joint_t & joint(int i)
Definition Domaine.h:261
const DoubleTab_t & coord_sommets() const
Definition Domaine.h:112
void check_domaine()
associate the read objects to the domaine and check that the reading objects are coherent
Definition Domaine.cpp:341
void renum_joint_common_items(const IntVect_t &nums, const int_t elem_offset)
Renumerotation des noeuds et des elements presents dans les items communs des joints.
Definition Domaine.cpp:1551
Joints_t & faces_joint()
Definition Domaine.h:265
int_t nb_som() const
Renvoie le nombre de sommets du domaine.
Definition Domaine.h:121
void ajouter(const DoubleTab_t &soms)
Ajoute des noeuds (ou sommets) au domaine (sans verifier les doublons).
Definition Domaine.cpp:909
const Noms & bords_perio() const
Definition Domaine.h:278
class Domaine_VF
Definition Domaine_VF.h:44
double xa(int num_arete, int k) const
Definition Domaine_VF.h:78
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
void set_fichier_lu(Nom &nom)
const Domaine & domaine() const
Lecture dans un fichier d'objets ecrits au format binaire.
Definition EFichierBin.h:30
An Entree whose main source of data is an arbitrary binary buffer set using the set_data() method.
virtual int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::in)
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
int_t nb_faces() const
Definition Faces.h:66
const IntTab_t & les_sommets() const
Renvoie le tableau des sommets de toutes les faces.
Definition Faces.h:74
int nb_som_faces() const
Renvoie le nombre de sommet par face.
Definition Faces.h:149
Parallel collective version of FichierHDF, to be used for all concurrent reading/writing on HDF files...
static bool is_hdf5(const char *file_name)
virtual void read_dataset(Nom dataset_basename, int proc_rank, Entree_Brute &entree)
virtual void open(Nom filename, bool readOnly)
virtual bool exists(const char *dataset_name)
virtual void close()
: Classe de postraitement des champs euleriens au format lata
int ecrire_entete(const double temps_courant, const int reprise, const int est_le_premier_post) override
Ouvre le fichier maitre en mode ERASE et ecrit l'entete du fichier lata (sur le processeur maitre seu...
virtual int initialize_lata(const Nom &file_basename, const Format format=ASCII, const Options_Para options_para=SINGLE_FILE)
Initialisation de la classe, ouverture du fichier et ecriture de l'entete.
@ BINAIRE
@ SINGLE_FILE
int ecrire_domaine(const Domaine &domaine, const int est_le_premier_post) override
voir Format_Post_base::ecrire_domaine On accepte l'ecriture d'un domaine dans un pas de temps,...
int ecrire_temps(const double temps) override
commence l'ecriture d'un nouveau pas de temps En l'occurence pour le format LATA:
int ecrire_champ(const Domaine &domaine, const Noms &unite_, const Noms &noms_compo, int ncomp, double temps_, const Nom &id_du_champ, const Nom &id_du_domaine, const Nom &localisation, const Nom &nature, const DoubleTab &data) override
voir Format_Post_base::ecrire_champ
void nommer(const Nom &) override
Donne un nom a la frontiere.
Definition Frontiere.cpp:74
const Domaine_t & domaine() const
Renvoie le domaine associe a la frontiere.
int_t nb_faces() const
Renvoie le nombre de faces de la frontiere.
Definition Frontiere.h:59
void associer_domaine(const Domaine_t &)
Associe la frontiere au domaine dont elle depend.
Definition Frontiere.cpp:63
IntTab_t & les_sommets_des_faces()
Renvoie les sommets des faces de la frontiere.
const Faces_t & faces() const
Definition Frontiere.h:54
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
const Joint_Items_t & joint_item(JOINT_ITEM type) const
Renvoie les informations de joint pour le type demande.
Definition Joint.cpp:128
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 epaisseur() const
Definition Joint.h:50
int PEvoisin() const
Definition Joint.h:49
const ArrOfInt_t & items_communs() const
Definition Joint_Items.h:44
const IntTab_t & renum_items_communs() const
Voir renum_items_communs_.
IntTab_t & set_renum_items_communs()
Voir renum_items_communs_ Voir Scatter::calculer_colonne0_renum_faces_communes.
ArrOfInt_t & set_items_communs()
Renvoie le tableau items_communs_ pour le remplir.
int nb_items_virtuels() const
Voir nb_items_virtuels_.
void set_nb_items_virtuels(int n)
Voir nb_items_virtuels_ Voir Scatter::calculer_nb_items_virtuels.
const ArrOfInt_t & items_distants() const
Voir items_distants_.
ArrOfInt_t & set_items_distants()
Renvoie le tableau items_distants_ pour le remplir Voir Scatter::calculer_espace_distant,...
Cette classe implemente les operateurs et les methodes virtuelles de la classe EFichier de la facon s...
int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::in) override
Ouverture du fichier.
Lecture dans un fichier au format binaire.
int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::in) override
Ouvre le fichier avec les parametres mode et prot donnes Ces parametres sont les parametres de la met...
virtual int get_nb_items_tot() const
virtual int get_nb_items_reels() const
Dummy parallel descriptor used for sequential computations.
C'est le plus simple des descripteurs, utilise pour les tableaux de valeurs aux sommets,...
static void creer_tableau_distribue(const MD_Vector &, Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
transforme v en un tableau parallele ayant la structure md.
: Cette classe est un OWN_PTR mais l'objet pointe est partage entre plusieurs
Definition MD_Vector.h:48
void copy(const MD_Vector_base &)
construction d'un objet MD_Vector par copie d'un objet existant.
Definition MD_Vector.cpp:26
const MD_Vector_base & valeur() const
Definition MD_Vector.h:77
Une chaine de caractere (Nom) en majuscules.
Definition Motcle.h:26
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
const Nom getPrefix(const char *const) const
Definition Nom.cpp:340
Nom nom_me(int, const char *prefix=0, int without_padding=0) const
Insere _prefix000n (n=me() ou nproc()) dans un nom de fichier (par ex:toto.
Definition Nom.cpp:387
const std::string & getString() const
Definition Nom.h:92
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
friend class Sortie
Definition Objet_U.h:75
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 double mp_min(double)
Definition Process.cpp:386
static trustIdType mppartial_sum(trustIdType i)
Calul de la somme partielle de i sur les processeurs 0 a me()-1 (renvoie 0 sur le processeur 0).
Definition Process.cpp:396
static double mp_max(double)
Definition Process.cpp:376
static bool mp_or(bool)
Definition Process.cpp:418
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
static double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
static 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 bool is_sequential()
Definition Process.cpp:115
static void chercher_direction_perio(ArrOfDouble &direction_perio, const Domaine_32_64< int > &dom, const Nom &bord)
static int reordonner_faces_periodiques(const Domaine_32_64< int > &domaine, IntTab_T< int > &faces, const ArrOfDouble &direction_perio, const double epsilon)
static void renum_som_perio(const Domaine_32_64< int > &dom, ArrOfInt_T< int > &renum_som_perio, bool calculer_espace_virtuel)
static void reordonner_faces_de_joint(Domaine &dom)
Reordonne les faces de joint de sorte qu'elles apparaissent dans le meme ordre sur chaque couple de p...
Definition Scatter.cpp:1678
static int Chercher_Correspondance(const DoubleTab &sommets1, const DoubleTab &sommets2, ArrOfInt &correspondance, const double epsilon)
Construit le tableau "correspondance" tel que Pour 0 <= i < sommets2.
Definition Scatter.cpp:2370
static void ajouter_joints(Domaine &domaine, ArrOfInt &pe_voisins)
Ajoute des joints avec tous les pe de pe_voisins.
Definition Scatter.cpp:1028
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_espace_virtuel_traduction(const MD_Vector &md_indice, const MD_Vector &md_valeur, IntTab &tableau, const int error_is_fatal=1)
Construit la structure items_communs + espaces virtuels d'un tableau contenant des indices d'items ge...
Definition Scatter.cpp:1624
static void calculer_espace_distant_sommets(Domaine &dom)
En fonction de l'espace distant des elements, calcule l'espace distant des sommets.
Definition Scatter.cpp:1157
Entree & interpreter(Entree &) override
Lit et complete un domaine parallele selon les motcles lus dans le jeu de donnees.
Definition Scatter.cpp:128
static void calculer_espace_distant_aretes(Domaine &domaine, const int nb_aretes_reelles, const IntTab &elem_aretes)
Idem que Scatter::calculer_espace_distant_sommets pour les aretes.
Definition Scatter.cpp:1201
static void calculer_espace_distant_elements(Domaine &dom)
Remplissage du tableau "espace_distant()" des elements dans les joints.
Definition Scatter.cpp:2061
static void calculer_espace_distant(Domaine &domaine, const int nb_items_reels, const ArrsOfInt &items_to_send, const JOINT_ITEM type_item)
Determination des items distants en fonction d'une liste d'items a envoyer et de listes d'items commu...
Definition Scatter.cpp:819
static void construire_correspondance_items_par_coordonnees(Joints &joints, const JOINT_ITEM type_item, const DoubleTab &coord_items, bool allow_resize=false)
Generic method to build geometrical item correspondance between the local and the remote processor ar...
Definition Scatter.cpp:2486
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_nb_items_virtuels(Joints &joints, const JOINT_ITEM type_item)
Pour un item geometrique "type_item", remplit le champ nb_items_virtuels_ des joints en fonction du n...
Definition Scatter.cpp:2698
void read_domain_no_comm(Entree &fic, bool &read_perio)
Does the exact same thing as the readOn of the class Domaine but without collective communication.
Definition Scatter.cpp:394
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 construire_md_vector(const Domaine &, int nb_items_reels, const JOINT_ITEM, MD_Vector &)
construction d'un MD_Vector_std a partir des informations de joint du domaine pour le type d'item dem...
Definition Scatter.cpp:1279
static void check_consistancy_remote_items(Domaine &dom, const ArrOfInt &mergedDomaines)
Merged domains receive joint information from their neighbours to ensure that their common items (ver...
Definition Scatter.cpp:270
static void corriger_espace_distant_elements_perio(Domaine &dom)
Les algorithmes actuels pour le periodique (assembleur P1B, OpDivElem P1B) ont besoin que pour chaque...
Definition Scatter.cpp:1911
Domaine & domaine()
Renvoi le domaine associe.
Definition Scatter.cpp:73
static void trier_les_joints(Joints &joints)
Sort joints by increasing neighbor proc number.
Definition Scatter.cpp:712
static void calculer_espace_distant_faces(Domaine &domaine, const int nb_faces_reelles, const IntTab &elem_faces)
Idem que Scatter::calculer_espace_distant_sommets pour les faces.
Definition Scatter.cpp:1182
virtual void lire_domaine(Nom &fil)
Lit le domaine dans le fichier de nom "nomentree", de type LecFicDistribueBin ou LecFicDistribue.
Definition Scatter.cpp:468
static void uninit_sequential_domain(Domaine_32_64< _SIZE_ > &dom)
methode utilisee par les interpretes qui modifient le domaine (sequentiel), detruit les descripteurs ...
Definition Scatter.cpp:2757
static void construire_correspondance_aretes_par_coordonnees(Domaine_VF &zvf)
Construction des tableaux joint_item(JOINT_ITEM::ARETE).items_communs de tous les joints du domaine.
Definition Scatter.cpp:2686
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 set_value(int_t i_liste, int_t i_element, int_t valeur)
affecte la "valeur" au j-ieme element de la i-ieme liste avec 0 <= i < get_nb_lists() et 0 <= j < get...
int_t get_list_size(int_t i_liste) const
renvoie le nombre d'elements de la liste i
void set_list_sizes(const ArrOfInt_t &sizes)
detruit les listes existantes et en cree de nouvelles.
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
virtual void ref_array(TRUSTArray &, _SIZE_ start=0, _SIZE_ sz=-1)
TRUSTArray & inject_array(const TRUSTArray &source, _SIZE_ nb_elements=-1, _SIZE_ first_element_dest=0, _SIZE_ first_element_source=0)
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
void ordonne_array()
void set_md_vector(const MD_Vector &) override
Definition TRUSTTab.tpp:673
int nb_dim() const
Definition TRUSTTab.h:199
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension_tot(int) const override
Definition TRUSTTab.tpp:160
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
_SIZE_ size_reelle() const
Definition TRUSTVect.tpp:27
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")
int size() const
Cette classe fournit les outils pour construire l'espace virtuel d'un tableau contenant des indices d...
Definition Scatter.cpp:1390
int chercher_table_inverse(const trustIdType sommet_global) const
Cherche i tel que table_inverse(i, 0) == sommet_global, et renvoie table_inverse(i,...
Definition Scatter.cpp:1474
int traduire_espace_virtuel(IntTab &tableau) const
A partir d'un tableau dont la structure d'espace virtuel est initialisee (descripteurs elements dista...
Definition Scatter.cpp:1579
void traduire_indice_local_vers_global(const ArrOfInt &indices_locaux, ArrOfTID &indices_globaux, int n) const
Transforme les indices locaux en indices globaux a l'aide la "table_" (voir initialiser).
Definition Scatter.cpp:1516
int traduire_indice_global_vers_local(const ArrOfTID &indices_globaux, ArrOfInt &indices_locaux) const
Pour debut <= i < debut+nb indices_locaux[i] = chercher l'indice local de "indices_globaux[i]".
Definition Scatter.cpp:1532
void initialiser(const MD_Vector &md_items)
Initialise le dictionnaire Precontition:
Definition Scatter.cpp:1422