TrioCFD 1.9.9_beta
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 call to: Interprete::printOn(Sortie&)
50 *
51 * @param os Output stream.
52 * @return The modified output stream.
53 */
55{
56 return Interprete::printOn(os);
57}
58
59
60/*! @brief Simple call to: Interprete::readOn(Entree&)
61 *
62 * @param is Input stream.
63 * @return The modified input stream.
64 */
66{
67 return Interprete::readOn(is);
68}
69
70/*! @brief Returns the associated domain.
71 *
72 * @return The associated domain.
73 */
75{
76 return le_domaine.valeur();
77}
78
79namespace
80{
81// For debug:
82void dump_lata(const Domaine& dom)
83{
84 Format_Post_Lata post; // Lata V2
85 Nom nom_fichier_lata("espaces_virtuels");
86
87 const int nb_joints = dom.nb_joints();
88 constexpr int IS_FIRST = 1;
89
91 post.ecrire_entete(0.0, 0, IS_FIRST);
92 post.ecrire_domaine(dom, IS_FIRST);
93 post.ecrire_temps(0.0);
94
95 Noms units, noms_compo;
96 units.add("");
97 noms_compo.add("I");
98 DoubleTab data(dom.nb_elem());
99 for(int ij = 0; ij < nb_joints; ij++)
100 {
101 const ArrOfInt& t1 = dom.joint(ij).joint_item(JOINT_ITEM::ELEMENT).items_distants();
102 data = 0.;
103 const int nt1 = t1.size_array();
104 for (int i = 0; i < nt1; i++) data[t1[i]] += 1;
105
106 post.ecrire_champ(dom,
107 units,
108 noms_compo,
109 1, // ncomp,
110 0.0, // time,
111 Nom("partition") + Nom(dom.joint(ij).PEvoisin()), // field_id,
112 dom.le_nom(), // domain_id
113 "ELEM", // localisation,
114 "scalar", // nature,
115 data // values
116 );
117 }
118}
119} // end anonymous namespace
120
121/*! @brief Reads and completes a parallel domain according to the keywords read in the data set.
122 *
123 * Format:
124 * Scatter [debug] file_name domain_name
125 * Reads the vertices, elements and joint vertices and faces,
126 * builds the distant and virtual spaces according to
127 * the joint layer thickness.
128 */
130{
131 // Name of partition files: nomentree.xxxx
132 Nom nomentree;
133 is >> nomentree;
135 {
136 Motcle n(nomentree);
137 if (n != ";" && n != "unlock;")
138 {
139 Cerr << "Error ! You ran a sequential calculation and can't use Scatter keyword here. Run a parallel calculation or remove this keyword." << finl;
140 exit();
141 }
142 Cerr << "Scatter: preparing domain structure\n"
143 << " (this is workaround for bugged domain operators that don't do it)" << finl;
144 Nom nomdomaine;
145 is >> nomdomaine;
146 Objet_U& obj = objet(nomdomaine);
147 if(!sub_type(Domaine, obj))
148 {
149 Cerr << "obj : " << obj << " is not an object of type Domain !" << finl;
150 exit();
151 }
152 Domaine& dom = ref_cast(Domaine, obj);
153 if (n == ";")
155 else
157 return is;
158 }
159 // For debugging on linux in parallel
160#ifdef linux
161 static int gdb_non_lance=1;
162 char* TRUST_GDB=getenv("TRUST_GDB");
163 if (gdb_non_lance && ((Motcle)nomentree=="DEBUG" || TRUST_GDB!=nullptr))
164 {
165 gdb_non_lance=0;
166 if ((Motcle)nomentree=="DEBUG") is >> nomentree;
167 if (je_suis_maitre())
168 {
169 Cerr << "Enter \"return\" to this window after" << finl;
170 Cerr << "typing \"cont\" in other gdb windows." << finl;
171 Cerr << (int)system ("sh -c read ok") << finl;
172 }
173 else
174 {
175 Nom getpidn((int)getpid());
176 Nom cmdfile=getpidn;
177 Nom command0="echo attach ";
178 command0+=getpidn;
179 command0+=" > ";
180 command0+=cmdfile;
181 Cerr << (int)system(command0) << finl;
182 command0=" ls -l /proc/";
183 command0+=getpidn;
184 command0+="/exe | awk '{print $NF}' > execname";
185 Cerr << (int)system(command0) << finl;
186 Nom command="[ -f /usr/X11R6/bin/xterm ] && x=\"/usr/X11R6/bin/xterm -exec gdb -x \";";
187 command+="[ -f /usr/bin/konsole ] && x=\"/usr/bin/konsole -e gdb -x \";";
188 command+="$x ";
189 command+=cmdfile;
190 command+=" `cat execname` ";
191 command+=" &";
192 Cerr<<"command: " <<command<<finl;
193 Cerr << (int)system(command) << finl;
194 }
195 }
196#endif
197 barrier();
198
200 Cerr << "Execution of the Scatter module." << finl;
201
202 statistics().begin_count(STD_COUNTERS::interprete_scatter,statistics().get_last_opened_counter_level()+1);
203 // Retrieve the domain:
204 Nom nomdomaine;
205 is >> nomdomaine;
206 Objet_U& obj = objet(nomdomaine);
207 if(!sub_type(Domaine, obj))
208 {
209 Cerr << "Error in Scatter: object of type '" << obj.que_suis_je() << "' when Domaine was expected!" << finl;
210 exit();
211 }
212 Domaine& dom = ref_cast(Domaine, obj);
213 le_domaine = dom;
214
215 // Read the partition files:
216 barrier();
218 Cerr << "Reading the domain" << finl;
219
220 lire_domaine(nomentree);
221
222 barrier();
223 Cerr << "Calculation of renum_items_communs for the nodes" << finl;
224 calculer_renum_items_communs(dom.faces_joint(), JOINT_ITEM::SOMMET);
225
226 // Not yet coded: verify that common vertices have identical coordinates
227 // on all processors.
228 // check_sommets_joints(dom);
229
230 barrier();
231 Cerr << "Construire_structures_paralleles" << finl;
233
234 if (0)
235 dump_lata(dom);
236
237 barrier();
238 Cerr << "End Distribue_domaines" << finl;
239
240 Cerr << "\nQuality of partitioning --------------------------------------------" << finl;
241 trustIdType total_nb_elem = Process::mp_sum(dom.nb_elem());
242 Cerr << "\nTotal nb of elements = " << total_nb_elem << finl;
243 Cerr << "Number of Domaines : " << Process::nproc() << finl;
244 double min_element_domaine = mp_min(dom.nb_elem());
245 double max_element_domaine = mp_max(dom.nb_elem());
246 double mean_element_domaine = (double)(total_nb_elem / Process::nproc());
247 Cerr << "Min number of elements on a Domaine = " << min_element_domaine << finl;
248 Cerr << "Max number of elements on a Domaine = " << max_element_domaine << finl;
249 Cerr << "Mean number of elements per Domaine = " << (int)(mean_element_domaine) << finl;
250 double load_imbalance = max_element_domaine / mean_element_domaine;
251 Cerr << "Load imbalance = " << load_imbalance << "\n" << finl;
252
253 Elem_geom_base& elem=dom.type_elem().valeur();
254 if (sub_type(Poly_geom_base,elem))
255 ref_cast(Poly_geom_base,elem).compute_virtual_index();
256 if(Process::me()==0)
257 {
258 double temps = statistics().get_time_since_last_open(STD_COUNTERS::interprete_scatter);
259 Cerr << "Scatter time : " << temps << finl;
260 }
261 statistics().end_count(STD_COUNTERS::interprete_scatter);
262 return is;
263}
264
265/*! @brief Merged domains receive joint information from their neighbours to ensure that their common items (vertices) appear in the same order
266 *
267 * If it's not the case, the merged domain reorders its common items so that it matches the neighbour's order
268 * When 2 neighbouring domains have each been merged,
269 * only the processor with the lowest rank proceeds to reordering
270 */
271void Scatter::check_consistancy_remote_items(Domaine& dom, const ArrOfInt& mergedDomaines)
272{
273 const Joints& joints = dom.faces_joint();
274 const int nb_joints = joints.size();
275
276 const DoubleTab& coords = dom.les_sommets();
277 ArrOfInt liste_send;
278 ArrOfInt liste_recv;
279
280
281
282 const int moi = Process::me();
283 const int myDomaineWasMerged = mergedDomaines[moi];
284
285 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
286 {
287
288 const int pe_voisin = joints[i_joint].PEvoisin();
289 const int neighbourDomaineWasMerged = mergedDomaines[pe_voisin];
290 if(myDomaineWasMerged && neighbourDomaineWasMerged)
291 {
292 if(pe_voisin < moi)
293 liste_recv.append_array(pe_voisin);
294 else
295 liste_send.append_array(pe_voisin);
296 }
297 else if(myDomaineWasMerged && !neighbourDomaineWasMerged)
298 liste_recv.append_array(pe_voisin);
299 else if(!myDomaineWasMerged && neighbourDomaineWasMerged)
300 liste_send.append_array(pe_voisin);
301 else
302 {
303 //nothing to exchange
304 }
305 }
306
307 DoubleTabs coord_items_locaux(nb_joints);
308 DoubleTabs coord_items_distants(nb_joints);
309 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
310 {
311 const Joint& joint = joints[i_joint];
312 const ArrOfInt& items_communs = joint.joint_item(JOINT_ITEM::SOMMET).items_communs();
313 const int nb_items_communs = items_communs.size_array();
314
315 DoubleTab& coord = coord_items_locaux[i_joint];
316 coord.resize(nb_items_communs, dimension);
317 for (int i = 0; i < nb_items_communs; i++)
318 for (int j = 0; j < dimension; j++)
319 coord(i,j) = coords(items_communs[i], j);
320 }
321
322 // Send local coordinates to the neighbouring processor
323 {
324 Schema_Comm schema_comm;
325 schema_comm.set_send_recv_pe_list(liste_send, liste_recv);
326 schema_comm.begin_comm();
327 for (int i = 0; i < nb_joints; i++)
328 {
329 const int pe_voisin = joints[i].PEvoisin();
330 const int neighbourDomaineWasMerged = mergedDomaines[pe_voisin];
331 if( neighbourDomaineWasMerged && !(myDomaineWasMerged && pe_voisin<moi) )
332 {
333 Sortie& buffer = schema_comm.send_buffer(pe_voisin);
334 buffer << coord_items_locaux[i];
335 }
336 }
337 schema_comm.echange_taille_et_messages();
338
339 if(myDomaineWasMerged)
340 {
341 for (int i = 0; i < nb_joints; i++)
342 {
343 const int pe_voisin = joints[i].PEvoisin();
344 const int neighbourDomaineWasMerged = mergedDomaines[pe_voisin];
345 if(!(neighbourDomaineWasMerged && pe_voisin>moi))
346 {
347 Entree& buffer = schema_comm.recv_buffer(pe_voisin);
348 buffer >> coord_items_distants[i];
349 }
350 }
351 }
352
353 schema_comm.end_comm();
354 }
355
356 // check if the vertices in my joints appear in the same order as my neighbour joint
357 if(myDomaineWasMerged)
358 {
359 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
360 {
361
362 const int pe_voisin = joints[i_joint].PEvoisin();
363 const int neighbourDomaineWasMerged = mergedDomaines[pe_voisin];
364 if(neighbourDomaineWasMerged && pe_voisin>moi)
365 continue;
366 ArrOfInt& items_communs = dom.faces_joint()[i_joint].set_joint_item(JOINT_ITEM::SOMMET).set_items_communs();
367 const ArrOfInt old_items_communs = joints[i_joint].joint_item(JOINT_ITEM::SOMMET).items_communs();
368 const int nb_items = items_communs.size_array();
369 const DoubleTab& coord_voisin = coord_items_distants[i_joint];
370 const DoubleTab& my_coord = coord_items_locaux[i_joint];
371 assert(my_coord.size_array() == coord_voisin.size_array());
372 for(int i=0; i<nb_items; i++)
373 {
374 for(int j=0; j<nb_items; j++)
375 {
376 int ok=1;
377 for (int dir=0; dir<Objet_U::dimension; dir++)
378 ok=ok&&(est_egal(coord_voisin(i,dir),my_coord(j,dir)));
379 if (ok)
380 {
381 items_communs[i] = old_items_communs[j];
382 break;
383 }
384 }
385 }
386 }
387 }
388}
389
390
391/*! @brief Does the exact same thing as the readOn of the class Domaine but without collective communication
392 *
393 * Necessary when the processors don't have the same numbers of file to read
394 */
395void Scatter::read_domain_no_comm(Entree& fic, bool& read_perio)
396{
397 Domaine& dom = le_domaine.valeur();
398
399 Cerr << "\treading vertices..." << finl;
400 Domaine dom_tmp_for_vertices;
401 dom_tmp_for_vertices.read_vertices(fic);
402
403 Cerr << "\tDone !\n\treading elem infos (domaines)..." << finl;
404
405 Nom accouverte="{";
406 Motcle nom;
407 fic >> nom;
408 Domaine domaine_read;
409 if(nom!=(const char*)"vide")
410 {
411 if (nom!=accouverte)
412 Process::exit("Error: Scatter::read_domain_no_comm() -- One expected an opened bracket { to start.");
413 domaine_read.read_former_domaine(fic, read_perio);
414 }
415 else
416 Process::exit("Error: Scatter::read_domain_no_comm() -- Empty list ?! Should not happen?");
417 Cerr << "Done!" << finl;
418
419 //
420 // Now merge the read domaine with the current domain
421 //
422 int nb_elems = dom.nb_elem();
423 IntVect nums;
425 // Complete domain with new nodes and/or renumber nodes when we have doublons
426 dom.ajouter(dom_tmp_for_vertices.les_sommets(), /*out*/ nums);
427 if (nb_elems > 0)
428 {
429 domaine_read.renum(nums);
430 domaine_read.renum_joint_common_items(nums, nb_elems);
431 }
432
433 // Merge domaine_read into current domain, w/o taking care of the joints.
434 dom.merge_wo_vertices_with(domaine_read);
435
436 if(nb_elems > 0) // Current domain already had something, so joints will need update
437 // Otherwise, joints were already read by "domaine_read.read_former_domaine(fic);" above and joints are OK.
438 {
439 //merging common vertices and remote items
440 const int nb_joints = domaine_read.nb_joints();
441 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
442 {
443 const Joint& joint_to_add = domaine_read.faces_joint()[i_joint];
444
445 int my_joint_index = 0;
446 while(joint_to_add.PEvoisin() != dom.faces_joint()[my_joint_index].PEvoisin())
447 my_joint_index++;
448
449 const ArrOfInt& sommets_to_add = joint_to_add.joint_item(JOINT_ITEM::SOMMET).items_communs();
450 ArrOfInt& items_communs = dom.faces_joint()[my_joint_index].set_joint_item(JOINT_ITEM::SOMMET).set_items_communs();
451
452 for(int index=0; index<sommets_to_add.size_array(); index++)
453 items_communs.append_array(sommets_to_add[index]); // sommets_to_add is already renumbered with 'nums' - see call to renum_joint_common_items above
454 array_trier_retirer_doublons(items_communs);
455
456 const ArrOfInt& elements_to_add = joint_to_add.joint_item(JOINT_ITEM::ELEMENT).items_distants();
457 ArrOfInt& items_distants = dom.faces_joint()[my_joint_index].set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants();
458
459 for(int index=0; index<elements_to_add.size_array(); index++)
460 items_distants.append_array(elements_to_add[index]); // idem
461 }
462 }
463}
464
465/*! @brief Reads the domain from the file named "nomentree", of type LecFicDistribueBin or LecFicDistribue
466 *
467 * Expected format: Domaine::ReadOn
468 */
470{
471 // Determine whether the file is in the new or old format
473 Cerr << "Reading geometry from .Zones file(s) ..." << finl;
474 barrier(); // Wait for the message to be displayed
475
476 Domaine& dom = domaine();
477 Noms& liste_bords_periodiques = dom.bords_perio();
478
479 // Just in case - some dataset improperly build a Domain and then try to Scatter on it ...:
480 dom.clear();
481
482 Nom copy(nomentree);
483 copy = copy.nom_me(Process::nproc(), "p", 1);
484
485 LecFicDiffuse test;
486 bool is_hdf = test.ouvrir(copy) && FichierHDF::is_hdf5(copy);
487 if (test.ouvrir(nomentree) && FichierHDF::is_hdf5(nomentree))
488 {
489 Cerr << "Error: You probably made a single_hdf partitioning and using the wrong name of .Zones files in the scatter" << finl;
490 Cerr << "You should remove '_p" << Process::nproc() << "' from the name of .Zones file (" << nomentree << ") in your datafile" << finl;
492 }
493
494 statistics().begin_count(STD_COUNTERS::read_scatter,statistics().get_last_opened_counter_level()+1);
495 ArrOfInt mergedDomaines(Process::nproc());
496 mergedDomaines = 0;
497 bool domain_not_built = true;
498 bool read_perio = false;
499 if (is_hdf)
500 {
501 FichierHDFPar fic_hdf;
502
503 nomentree = copy;
504 fic_hdf.open(nomentree, true);
505
506 std::string dname = "/zone_" + std::to_string(Process::me());
507 bool ok = fic_hdf.exists(dname.c_str());
508 if(!ok)
509 {
510 mergedDomaines = 1;
511 for(int i=0; i<Process::nproc(); i++)
512 {
513 Entree_Brute data_part;
514 std::string tmp = dname + "_" + std::to_string(i);
515
516 bool exists = fic_hdf.exists(tmp.c_str());
517 if(exists)
518 {
519 Nom dataset_name(dname);
520
521 fic_hdf.read_dataset(dataset_name, i, data_part);
522 read_domain_no_comm(data_part, read_perio);
523
524 // Record which file the domain was read from
525 dom.set_fichier_lu(nomentree);
526 if (!read_perio) // are the periodic boundaries read from the Domain (new format) or after it?
527 data_part >> liste_bords_periodiques;
528 domain_not_built = false;
529 }
530 else
531 break;
532
533 }
534 }
535 else
536 {
537 Entree_Brute data;
538 fic_hdf.read_dataset("/zone", Process::me(), data);
539
540 // Feed TRUST objects:
541 read_domain_no_comm(data, read_perio);
542 dom.set_fichier_lu(nomentree);
543 if (!read_perio) // are the periodic boundaries read from the Domain (new format) or after it?
544 data >> liste_bords_periodiques;
545 domain_not_built = false;
546 }
547
548 fic_hdf.close();
549 }
550 else // Not HDF
551 {
552 LecFicDistribueBin fichier_binaire;
553 int isSingleDomaine = fichier_binaire.ouvrir(nomentree);
554 if (!isSingleDomaine)
555 {
556 mergedDomaines = 1;
557 Nom nomentree_with_suffix=nomentree.nom_me(Process::me());
558 for(int i=0; i<Process::nproc(); i++)
559 {
560 EFichierBin fichier_binaire_part;
561 std::string tmp = nomentree_with_suffix.getPrefix(".Zones").getString();
562 tmp += "_";
563 tmp += std::to_string(i);
564 tmp += ".Zones";
565 Nom nomentree_part(tmp);
566 int ok = fichier_binaire_part.ouvrir(nomentree_part);
567 if(ok)
568 {
569 read_domain_no_comm(fichier_binaire_part, read_perio);
570
571 // Record which file the domain was read from
572 dom.set_fichier_lu(nomentree);
573 if (!read_perio) // are the periodic boundaries read from the Domain (new format) or after it?
574 fichier_binaire_part >> liste_bords_periodiques;
575 fichier_binaire_part.close();
576 domain_not_built = false;
577 }
578 else
579 break;
580 }
581 }
582 else
583 {
584 read_domain_no_comm(fichier_binaire, read_perio);
585
586 // Record which file the domain was read from
587 dom.set_fichier_lu(nomentree);
588 if (!read_perio) // are the periodic boundaries read from the Domain (new format) or after it?
589 fichier_binaire >> liste_bords_periodiques;
590 fichier_binaire.close();
591 domain_not_built = false;
592 }
593 }
594
595 if(domain_not_built)
596 {
597 Cerr << "Error in Scatter::lire_domaine\n";
598 Cerr << "The domain on the current process hasn't been built" << finl;
599 Cerr << "The number of processes you mentionned is probaly higher than the number of domaines" << finl;
601 }
602
603 // Sanity check: number of processors = number of domains
604 // (verify that there is no joint with a non-existent processor)
605 // (the previous check is insufficient:
606 // it only verifies that the number of processors does not exceed the number of domains)
607 {
608
609 const Joints& joints = dom.faces_joint();
610 const int nb_joints = joints.size();
611 int max_pe_voisin = 0;
612 for (int i = 0; i < nb_joints; i++)
613 {
614 const int pe_voisin = joints[i].PEvoisin();
615 if (pe_voisin >= max_pe_voisin)
616 max_pe_voisin = pe_voisin;
617 }
618
619 max_pe_voisin = (int) mp_max(max_pe_voisin);
620 double ok=1;
621 if (max_pe_voisin >= nproc()) ok=0;
622 if (!ok)
623 {
624 Cerr << "Error in Scatter::lire_domaine\n"
625 << "The domain has been partitioned with at least " << max_pe_voisin << " "
626 << "domaines whereas the number of processes asked is " << Process::nproc() << "." << finl;
627 Cerr << "The number of domaines and number of processes must match." << finl;
628 exit();
629 }
630 }
631
632 // sort joints in increasing processor order
633 Joints& joints = dom.faces_joint();
634 trier_les_joints(joints);
635 envoyer_all_to_all(mergedDomaines, mergedDomaines);
636 check_consistancy_remote_items( dom, mergedDomaines );
637 dom.check_domaine();
638
639 // PL: not entirely exact: the displayed vertex count counts joint vertices multiple times...
640 trustIdType nbsom = mp_sum(dom.les_sommets().dimension(0));
641 Cerr << " Number of nodes: " << nbsom << finl;
642
644
645 // merged domains need to reorder faces of periodic borders
646 const int myDomaineWasMerged = mergedDomaines[Process::me()];
647 if(myDomaineWasMerged)
648 {
649 for(auto& itr : liste_bords_periodiques)
650 {
651 Nom bp_nom = itr;
652 Bord& bord = dom.bord(bp_nom);
653 if(bord.nb_faces() == 0)
654 continue;
655
656 ArrOfDouble direction_perio(dimension);
657 Reordonner_faces_periodiques::chercher_direction_perio(direction_perio, dom, bp_nom);
658 IntTab& faces = bord.faces().les_sommets();
659 double epsilon = precision_geom;
660 Reordonner_faces_periodiques::reordonner_faces_periodiques(dom, faces, direction_perio, epsilon);
661 }
662 }
663 statistics().end_count(STD_COUNTERS::read_scatter);
664 barrier();
665}
666
667/*! @brief Builds the parallel structures of the domain (determination of distant elements as a function of joint thickness,
668 *
669 * determination of distant vertices,
670 * creation of virtual vertices and elements)
671 *
672 */
674{
675 // First: remove the "sequential" structures associated with vertices and elements during reading:
676 {
677 MD_Vector md_nul;
678 dom.les_sommets().set_md_vector(md_nul);
679 dom.les_elems().set_md_vector(md_nul);
680 }
681
682 const Noms& liste_bords_periodiques = dom.bords_perio();
683
684 // The call order is important:
686
687 if (liste_bords_periodiques.size() > 0)
689
690 calculer_nb_items_virtuels(dom.faces_joint(), JOINT_ITEM::ELEMENT);
691
692 // Determination of distant vertices from distant elements
694
695 // Creation of distant/virtual spaces and common items for vertex and element arrays:
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 // Reorder the joint faces (implicit correspondence with the neighboring pe)
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 // Copy the joint list
720 Joints anciens_joints(joints);
721 for (int i = 0; i < nb_joints; i++)
722 {
723 // Process the neighbor processor pe_voisin:
724 const int pe_voisin = pe_voisins[i];
725 // Where is the joint with this processor in the old list?
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// If a joint with "pe" exists, return its index,
736// otherwise create a new joint and return its index.
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 // Initialise all arrays of additional joints.
756 // Note BM: to be thorough, only
757 // certain arrays should be initialised (those already initialised for
758 // existing joints), but that is more complex to do...
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 // To avoid the following warning on 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 Determines the distant items from a list of items to send and lists of common items.
800 *
801 * Example:
802 * calculer_espace_distant_sommets
803 * calculer_espace_distant_faces
804 * For vertices: the "items_to_send" are the vertices of distant elements.
805 * If processor A wants processor B to know vertex i,
806 * the processor that owns the vertex must send it to B.
807 * The "owning" processor is the smallest among the PEs
808 * sharing this vertex (common item) (required to perform
809 * echange_item_commun and echange_espace_virtuel in a single pass).
810 * Furthermore, if several processors request that the same vertex
811 * be sent to the same processor, it must only be inserted once in the
812 * distant space.
813 *
814 * @param (joints) the joints in which the distant space is to be computed
815 * @param (nb_items_reels) the number of real items (vertices, faces, ...)
816 * @param (items_to_send) a vector of "nproc()" arrays, for each processor, the list of items to send (e.g. all vertices of distant elements, or all faces)
817 * @param (type_item) the items whose distant space is to be computed
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 // First, determine for all items the PE owner number:
832 // For each item of the domain:
833 // column 0: index of the item on the owning PE (index_on_pe_owner)
834 // column 1: number of the owning PE (the smallest PE sharing this 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 // First step: send to the owning processor of the items
869 // the list of items to be sent and to which processor they
870 // must be sent.
871 // If processor A must send element E to processor B,
872 // and that element uses item S belonging to processor C,
873 // then send to C the message:
874 // "put item S in the distant space of processor B"
875
876 // Prepare a communication scheme between neighbors:
877 // Sending processor: the processor that owns the distant element,
878 // Receiving processor: the processor that owns an item of the element.
879 // These processors are neighbors through existing joints.
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 // and for each item to be sent, send to the processor owning the item (pe_item_owner):
890 // - its local index on that processor (item_distant),
891 // - the number of the processor to which it must be sent (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 // Send the index of the distant item and which joint it
903 // must be placed in.
904 // If pe_joint == pe_destination, the item is necessarily already
905 // known by the other processor; no need to send it
906 if (pe_item_owner != pe_destination)
907 schema_comm.send_buffer(pe_item_owner) << item_distant << pe_destination;
908 }
909 }
910 }
911
912 // Exchange messages
913 schema_comm.echange_taille_et_messages();
914
915 // Receive the distant items. Read all buffers and
916 // store items in "items_distants" by destination processor.
917 // For each neighbor processor, the list of distant items to send:
918 ArrsOfInt items_distants(nproc);
919
920 // Loop over all processors (pe_source) that sent me messages:
921 // Loop over neighbor processors plus myself:
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 // Loop "while the buffer is not empty"
929 while(1)
930 {
931 int item_distant; // Index of the distant item
932 int pe_distant; // Number of the pe to which the item must be sent
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 // Remove duplicates and items already known by the neighbor processor:
944 {
945 // List of joints corresponding to each 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 // List of items already known by the neighbor processor (common items)
954 // sorted in increasing order
955 ArrOfInt items_communs_tri;
956
957 for (int pe = 0; pe < nproc; pe++)
958 {
959 ArrOfInt& items = items_distants[pe];
960 // Remove duplicates:
961 array_trier_retirer_doublons(items);
962 // Remove items already known:
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 // No common item with this pe.
974 }
975 }
976 }
977
978 // Distant spaces may be created on processors with
979 // which no joint exists yet. Add the new 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 // Add the new 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 // Fill the distant items arrays
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 // Fill the number of virtual items
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 Adds joints with all PEs in pe_voisins.
1019 *
1020 * To make the set of joints symmetric,
1021 * a joint is also created on the destination processor:
1022 * If A adds a joint with B, then B adds a joint with A.
1023 * Joints are sorted in ascending order of PE number.
1024 * WARNING: joints are therefore reordered!
1025 * pe_voisins is updated with the list of joints actually created.
1026 *
1027 */
1029 ArrOfInt& pe_voisins)
1030{
1031 Joints& joints = domaine.faces_joint();
1032 ArrOfInt liste_pe;
1033
1034
1035 // Make joints symmetric (if A->B then B->A):
1036 {
1037 // Put in liste_pe the "transpose" of the pe_voisins list:
1038 // list of processors that have my number in their "pe_voisins".
1039 reverse_send_recv_pe_list(pe_voisins, liste_pe);
1040 const int n = liste_pe.size_array();
1041 // Concatenate the two lists.
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 // Remove from pe_voisins the PEs for which a joint already exists
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 // Add new joints and sort in ascending order
1056 // As of 2/11/2005, Liste::inserer does not allow inserting
1057 // at the beginning of the list. Unusable. Brute-force method:
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 Generic method to compute the remote space of a geometric item type (vertex, face, edge) based on the remote space of elements:
1067 *
1068 * The remote "type_item" items (for type_item = vertex, face or edge) are
1069 * the "type_item" items attached to remote elements.
1070 * Example: remote vertices are all vertices of all remote elements.
1071 * @sa
1072 * Scatter::calculer_espace_distant_sommets
1073 * Scatter::calculer_espace_distant_faces
1074 *
1075 * @param (domaine) the domain
1076 * @param (type_item) the type of items whose remote space is to be computed
1077 * @param (connectivite_elem_item) the array giving for each domain element the indices of its items. Only the real part of the array is used (logically, the virtual part does not exist yet). (e.g. domaine().les_elems() for type_item==SOMMET or domaine_VF().face_sommets() for type_item==FACE)
1078 * @param (nb_items_reels) the number of real "type_item" items
1079 * @param (items_lies) if the array is non-empty, it must have size nb_items_reels. In that case, it enforces the property: "if item i is remote, then item items_lies[i] is remote too". This array is used to include associated virtual periodic vertices. (see calculer_espace_distant_sommets).
1080 */
1081static void calculer_espace_distant_item(Domaine& le_dom,
1082 const JOINT_ITEM type_item,
1083 const IntTab& connectivite_elem_item,
1084 const int nb_items_reels,
1085 const ArrOfInt& items_lies)
1086{
1088 return;
1089
1090 const Joints& joints = le_dom.faces_joint();
1091 const int nb_joints = joints.size();
1092 const int nproc = Process::nproc();
1093 const int nb_items_par_element = connectivite_elem_item.dimension(1);
1094 // The type_item items to send to each processor:
1095 ArrsOfInt items_to_send(nproc);
1096 // A temporary array;
1097 ArrOfInt liste_items;
1098
1099
1100 // Are there linked items?
1101 const int flag_items_lies = (items_lies.size_array() > 0);
1102 assert(flag_items_lies == 0 || items_lies.size_array() == nb_items_reels);
1103
1104
1105 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
1106 {
1107 const Joint& joint = joints[i_joint];
1108 const int pe_voisin = joint.PEvoisin();
1109 const ArrOfInt& esp_dist_elems = joint.joint_item(JOINT_ITEM::ELEMENT).items_distants();
1110 const int nb_elems_dist = esp_dist_elems.size_array();
1111 liste_items.resize_array(0);
1112 // Put in liste_items all items of all elements
1113 // that are in esp_dist_elems:
1114 for (int i_elem = 0; i_elem < nb_elems_dist; i_elem++)
1115 {
1116 const int elem = esp_dist_elems[i_elem];
1117 for (int i_item = 0; i_item < nb_items_par_element; i_item++)
1118 {
1119 const int item = connectivite_elem_item(elem, i_item);
1120 if (item>-1)
1121 {
1122 liste_items.append_array(item);
1123 // If an item is linked to the current item, also send the linked item.
1124 if (flag_items_lies)
1125 {
1126 const int item_lie = items_lies[item];
1127 if (item_lie != item)
1128 {
1129 assert(item_lie >= 0 && item_lie < nb_items_reels);
1130 assert(items_lies[item_lie] == item_lie); // chaining of links is forbidden
1131 liste_items.append_array(item_lie);
1132 }
1133 }
1134 }
1135 }
1136 }
1137 array_trier_retirer_doublons(liste_items);
1138 // These items must be sent to the neighboring processor:
1139 items_to_send[pe_voisin] = liste_items;
1140 }
1141 // Compute remote spaces based on "items_to_send"
1142 Scatter::calculer_espace_distant(le_dom, nb_items_reels, items_to_send, type_item);
1143}
1144
1145/*! @brief Based on the remote space of elements, computes the remote space of vertices.
1146 *
1147 * For each joint, the set of vertices of all joint elements is sent to the neighboring processor.
1148 * It is the processor that owns the vertex
1149 * (the smallest PE that holds it) that puts it in its remote space.
1150 * Warning: new joints are created.
1151 * The following arrays are filled:
1152 * dom.faces_joint(i).joint_item(JOINT_ITEM::SOMMET).items_distants();
1153 *
1154 */
1156{
1158 Cerr << "Scatter::calculer_espace_distant_sommets : start" << finl;
1159
1160 const IntTab& connectivite_elem_som = dom.les_elems();
1161 const int nb_sommets_reels = dom.nb_som();
1162
1163 ArrOfInt renum_som_perio(nb_sommets_reels);
1164 // Initialize the renum_som_perio array
1165 for (int i = 0; i < nb_sommets_reels; i++)
1166 renum_som_perio[i] = i;
1168 0 /* do not compute for virtual vertices */);
1169
1170 calculer_espace_distant_item(dom,
1171 JOINT_ITEM::SOMMET,
1172 connectivite_elem_som,
1173 nb_sommets_reels,
1174 renum_som_perio);
1175}
1176
1177/*! @brief Same as Scatter::calculer_espace_distant_sommets for faces.
1178 *
1179 */
1181 const int nb_faces_reelles,
1182 const IntTab& elem_faces)
1183{
1185 Cerr << "Scatter::calculer_espace_distant_faces : start" << finl;
1186
1187 ArrOfInt tableau_vide;
1188
1189 calculer_espace_distant_item(domaine,
1190 JOINT_ITEM::FACE,
1191 elem_faces,
1192 nb_faces_reelles,
1193 tableau_vide);
1194}
1195
1196/*! @brief Same as Scatter::calculer_espace_distant_sommets for edges.
1197 *
1198 */
1200 const int nb_aretes_reelles,
1201 const IntTab& elem_aretes)
1202{
1204 Cerr << "Scatter::calculer_espace_distant_aretes : start" << finl;
1205 ArrOfInt tableau_vide;
1206 calculer_espace_distant_item(domaine,
1207 JOINT_ITEM::ARETE,
1208 elem_aretes,
1209 nb_aretes_reelles,
1210 tableau_vide);
1211}
1212
1213/*! @brief Assumes that each joint[i].joint_item(type_item).items_communs() contains the local indices of common joint items in the same
1214 * order on both processors (local and neighbor).
1215 * Fills renum_items_communs:
1216 * column 0 = content of the items_communs array on the neighboring PE
1217 * column 1 = content of the items_communs array on the local PE
1218 *
1219 */
1221 const JOINT_ITEM type_item)
1222{
1223 // It suffices to send the _faces array to the neighbor in order
1224 // so it has the face indices on the other PE.
1225
1226 const int nb_joints = joints.size();
1227 int i_joint;
1228 Schema_Comm schema_comm;
1229 ArrOfInt liste_voisins(nb_joints);
1230 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1231 liste_voisins[i_joint] = joints[i_joint].PEvoisin();
1232 schema_comm.set_send_recv_pe_list(liste_voisins, liste_voisins);
1233
1234 schema_comm.begin_comm();
1235
1236 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1237 {
1238 const Joint& joint = joints[i_joint];
1239 const int pe_voisin = joint.PEvoisin();
1240 const ArrOfInt& items_communs =
1241 joint.joint_item(type_item).items_communs();
1242 schema_comm.send_buffer(pe_voisin) << items_communs;
1243 }
1244
1245 schema_comm.echange_taille_et_messages();
1246
1247 // The common items array received from the neighboring PE:
1248 ArrOfInt items_communs_voisin;
1249
1250
1251 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1252 {
1253 Joint& joint = joints[i_joint];
1254 const int pe_voisin = joint.PEvoisin();
1255 const ArrOfInt& items_communs = joint.joint_item(type_item).items_communs();
1256 const int nb_items = items_communs.size_array();
1257 schema_comm.recv_buffer(pe_voisin) >> items_communs_voisin;
1258
1259 assert(nb_items == items_communs_voisin.size_array());
1260
1261 IntTab& renum_items_communs = joint.set_joint_item(type_item).set_renum_items_communs();
1262 renum_items_communs.resize(nb_items, 2);
1263 // The index of the joint face on the other PE is in tmp(i,1)
1264 for (int i = 0; i < nb_items; i++)
1265 {
1266 renum_items_communs(i,0) = items_communs_voisin[i];
1267 renum_items_communs(i,1) = items_communs[i];
1268 }
1269 }
1270
1271 schema_comm.end_comm();
1272}
1273
1274/*! @brief Builds an MD_Vector_std from the joint information of the domain for the requested item type.
1275 *
1276 */
1277void Scatter::construire_md_vector(const Domaine& dom, int nb_items_reels, const JOINT_ITEM type_item, MD_Vector& md_vector)
1278{
1280 {
1281 MD_Vector_seq mdseq(nb_items_reels);
1282 md_vector.copy(mdseq);
1283 return;
1284 }
1285
1286 const Joints& joints = dom.faces_joint();
1287 const int nb_joints = joints.size();
1288
1289 ArrOfInt pe_voisins(nb_joints);
1290 ArrsOfInt items_to_send(nb_joints);
1291 ArrsOfInt items_to_recv(nb_joints);
1292 ArrsOfInt blocs_to_recv(nb_joints);
1293
1294 // flag indicating whether the (common) item is received from a processor
1295 ArrOfBit flags(nb_items_reels);
1296 flags = 0;
1297
1298 int nitems_tot = nb_items_reels;
1299 const int moi = me();
1300
1301 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
1302 {
1303 const int pe = joints[i_joint].PEvoisin();
1304 pe_voisins[i_joint] = pe;
1305 const Joint_Items& joint = joints[i_joint].joint_item(type_item);
1306 {
1307 // Processing common items
1308 const ArrOfInt& items_communs = joint.items_communs();
1309 const int n = items_communs.size_array();
1310
1311 // Joints must arrive in ascending PE number order,
1312 // otherwise the following algorithm does not work:
1313 assert((i_joint == 0) || (pe > joints[i_joint-1].PEvoisin()));
1314 if (pe > moi)
1315 {
1316 // I must send these items to the neighboring processor
1317 ArrOfInt& dest = items_to_send[i_joint];
1318
1319 for (int i = 0; i < n; i++)
1320 {
1321 const int item = items_communs[i];
1322 if (!flags[item])
1323 {
1324 // item not received from a processor
1325 dest.append_array(item);
1326 }
1327 }
1328 }
1329 else
1330 {
1331 // I receive this item from another processor
1332 ArrOfInt& dest = items_to_recv[i_joint];
1333
1334 for (int i = 0; i < n; i++)
1335 {
1336 const int item = items_communs[i];
1337 if (!flags.testsetbit(item))
1338 {
1339 // item not yet received from a processor
1340 dest.append_array(item);
1341 }
1342 }
1343 }
1344 }
1345 // Processing remote and virtual items
1346 {
1347 const int nitems_virt = joint.nb_items_virtuels();
1348 ArrOfInt& dest = blocs_to_recv[i_joint];
1349 if (nitems_virt > 0)
1350 {
1351 dest.resize_array(2, RESIZE_OPTIONS::NOCOPY_NOINIT);
1352 // Definition of the virtual items block for the neighboring processor
1353 dest[0] = nitems_tot;
1354 dest[1] = nitems_tot + nitems_virt;
1355 nitems_tot += nitems_virt;
1356 }
1357 }
1358 {
1359 const ArrOfInt& items_distants = joint.items_distants();
1360 const int n = items_distants.size_array();
1361 ArrOfInt& dest = items_to_send[i_joint];
1362 const int index = dest.size_array();
1363 dest.resize_array(index + n, RESIZE_OPTIONS::COPY_NOINIT); // copy the old values!
1364 dest.inject_array(items_distants, n, index /* dest index */, 0 /* src index */);
1365 }
1366 }
1367
1368 MD_Vector_std md(nitems_tot, nb_items_reels, pe_voisins, items_to_send, items_to_recv, blocs_to_recv);
1369 md_vector.copy(md);
1370
1371 // Verify that the md_vector is valid (send sizes match receive sizes)
1372 if (comm_check_enabled())
1373 {
1374 IntVect toto;
1376 toto = 0;
1378 }
1379}
1380
1381/*! @brief This class provides tools to build the virtual space of an array containing indices of geometric entities
1382 *
1383 * (vertices, elements, faces). It handles in particular the
1384 * renumbering of virtual elements.
1385 *
1386 */
1388{
1389public:
1391 void initialiser(const MD_Vector& md_items);
1392 void reset();
1393 void traduire_indice_local_vers_global(const ArrOfInt& indices_locaux, ArrOfTID& indices_globaux, int n) const;
1394 int traduire_indice_global_vers_local(const ArrOfTID& indices_globaux, ArrOfInt& indices_locaux) const;
1395 int traduire_espace_virtuel(IntTab& tableau) const;
1396
1397 int chercher_table_inverse(const trustIdType sommet_global) const;
1398
1399private:
1400 // Metadata of the indices to be renumbered:
1401 MD_Vector md_items_;
1402 trustIdType premier_indice_global_ = -100;
1403 // Distributed array (with virtual spaces and common items)
1404 // containing a global index for all entities to be indexed (real and virtual).
1405 // (if type_table_==SOMMETS, table_[i] is the global index of vertex i)
1406 TIDVect table_;
1407 // Table for inverting the numbering, sorted in ascending order
1408 // of the global index:
1409 // * column 0: the global index of the entity
1410 // * column 1: the local index of the entity
1411 TIDTab table_inverse_;
1412};
1413
1414/*! @brief Initializes the dictionary. Precondition:
1415 *
1416 * The remote spaces of the entities used must have been computed.
1417 *
1418 */
1420{
1421 md_items_ = md_items;
1422
1423 // Build "table": create a global number for real entities
1424 // (entity index + total number of entities on lower-rank processors)
1425 // then exchange the virtual space of this array, obtaining for each
1426 // real or virtual entity its global number.
1427
1428 table_.reset();
1430
1431 const int nb_entites = md_items->get_nb_items_tot();
1432 const trustIdType decal = Process::mppartial_sum(nb_entites);
1433 premier_indice_global_ = decal;
1434
1435 for (int i = 0; i < nb_entites; i++)
1436 table_[i] = i + decal;
1437 table_.echange_espace_virtuel();
1438
1439 // Build table_inverse containing non-trivial indices
1440 // (for which table_[i] != i + decal after the exchange)
1441 // sorted in ascending order of the global number.
1442 const int nb_entites_tot = table_.size_totale();
1443 table_inverse_.resize(0, 2);
1444
1445 for (int i = 0; i < nb_entites_tot; i++)
1446 {
1447 if (table_[i] != i + decal)
1448 table_inverse_.append_line(table_[i], i);
1449 }
1450 // insure complains.. check if it is right
1451 if (table_inverse_.size_array()>0)
1452 {
1453 tri_lexicographique_tableau(table_inverse_);
1454 }
1455}
1456
1458{
1459 md_items_.detach();
1460 table_.reset();
1461 table_inverse_.reset();
1462}
1463
1464/*! @brief Searches for i such that table_inverse(i, 0) == sommet_global, and returns table_inverse(i, 1) (the local index of the vertex).
1465 *
1466 * If the vertex is not found in the table, returns -1.
1467 * table_inverse must be sorted in ascending order of column 0.
1468 * table_inverse must not have a virtual space.
1469 *
1470 */
1471int Traduction_Indice_Global_Local::chercher_table_inverse(const trustIdType sommet_global) const
1472{
1473 // Algorithm: binary search:
1474 int imin = 0;
1475 int imax = table_inverse_.dimension(0) - 1;
1476 // If only one element in the table, the while loop is not entered
1477 // (so initialize to table_inverse(0, 0))
1478 // Otherwise, if no element, valeur must not equal sommet_global,
1479 // otherwise, any value will do as it will be overwritten in the while loop.
1480 trustIdType valeur;
1481 if (imax == 0)
1482 valeur = table_inverse_(0, 0);
1483 else
1484 valeur = sommet_global - 1;
1485
1486 while (imax > imin)
1487 {
1488 const int milieu = (imin + imax) >> 1; // (min+max)/2
1489 valeur = table_inverse_(milieu, 0);
1490 const trustIdType compare = valeur - sommet_global;
1491 if (compare < 0)
1492 imin = milieu + 1;
1493 else if (compare > 0)
1494 imax = milieu - 1;
1495 else
1496 imin = imax = milieu;
1497 }
1498 int resu = -1;
1499 valeur = table_inverse_(imin, 0);
1500 if (valeur == sommet_global)
1501 resu = static_cast<int>(table_inverse_(imin, 1)); // 2nd col always an int
1502 return resu;
1503}
1504
1505/*! @brief Transforms local indices into global indices using "table_" (see initialiser).
1506 *
1507 * Does:
1508 * For debut <= i < debut+nb
1509 * indices_globaux[i] = table_[indices_locaux[i]]
1510 * if indices_locaux[i] < 0 then indices_globaux[i] = -1
1511 *
1512 */
1514 ArrOfTID& indices_globaux, int nb_items_a_traiter) const
1515{
1516 for (int i = 0; i < nb_items_a_traiter; i++)
1517 {
1518 const int i_loc = indices_locaux[i];
1519 const trustIdType i_glob = (i_loc < 0) ? -1 : table_[i_loc];
1520 indices_globaux[i] = i_glob;
1521 }
1522}
1523
1524/*! @brief For debut <= i < debut+nb, indices_locaux[i] = look up the local index of "indices_globaux[i]"
1525 *
1526 * @param (indices_globaux) the array of global indices to translate
1527 * @param (indices_locaux) on output, the local indices or -1 if the global index was not found. Return value: number of indices not found (global indices that do not correspond to any local index).
1528 */
1530 ArrOfInt& indices_locaux) const
1531{
1532 assert(indices_globaux.size_array() == indices_locaux.size_array());
1533 int i;
1534 int nb_erreurs = 0;
1535 const int nb_indices = indices_globaux.size_array();
1536 const int size_table = table_.size_array();
1537 for (i = 0; i < nb_indices; i++)
1538 {
1539 const trustIdType i_glob = indices_globaux[i];
1540 int i_loc;
1541 if (i_glob < 0)
1542 {
1543 // Negative index, considered normal,
1544 // it is an "empty index" marker.
1545 i_loc = -1;
1546 }
1547 else
1548 {
1549 // Check whether the item is not renumbered
1550 i_loc = static_cast<int>(i_glob - premier_indice_global_); // the diff is local, hence small
1551 if (i_loc < 0 || i_loc >= size_table || table_[i_loc] != i_glob)
1552 {
1553 // no, need to invert the table:
1554 i_loc = chercher_table_inverse(i_glob);
1555 }
1556 if (i_loc < 0)
1557 nb_erreurs++;
1558 }
1559 indices_locaux[i] = i_loc;
1560 }
1561 return nb_erreurs;
1562}
1563
1564/*! @brief Starting from an array whose virtual space structure is initialized (remote and virtual element descriptors, common items)
1565 *
1566 * and containing indices compatible with the content of the tables
1567 * (vertex or element indices depending on type_table_),
1568 * fills the virtual elements of "tableau" based on remote elements
1569 * and translates the indices to local indices.
1570 * (example, see construire_espace_virtuel_elements and
1571 * construire_espace_virtuel_faces).
1572 * Return value: number of indices that could not be translated
1573 * (e.g. the referenced vertex does not exist on the neighboring processor)
1574 *
1575 */
1577{
1578 // Create a copy of the tab in which we will store global indices
1579 // Can not use 'copy' since value types are different (int vs TID), so this a bit clumsy:
1580 // (TODO provide 'from_int_to_tid' in TRUSTTab.h)
1581 TIDTab ind_glob_tab;
1582 ArrOfInt sz(tab.nb_dim());
1583 for (int i=0; i < tab.nb_dim(); i++) sz[i] = tab.dimension_tot(i);
1584 ind_glob_tab.resize(sz, RESIZE_OPTIONS::NOCOPY_NOINIT);
1585 ind_glob_tab.set_md_vector(tab.get_md_vector());
1586
1587 IntVect& tableau = tab; // tab seen as a Vect.
1588 TIDVect& indices_globaux = ind_glob_tab;
1589
1590 const int nb_items_reels = tableau.size_reelle();
1591 const int nb_items_tot = tableau.size_totale();
1592 const int nb_items_virtuels = nb_items_tot - nb_items_reels;
1593
1594 // Translate real items to global indices:
1595 traduire_indice_local_vers_global(tableau, indices_globaux, nb_items_reels);
1596 // Fill virtual slots
1597 indices_globaux.echange_espace_virtuel();
1598
1599 // Translate back only the virtual items of "tableau" to local indices:
1600 ArrOfTID src;
1601 ArrOfInt dest;
1602 src.ref_array(indices_globaux, nb_items_reels /*debut*/, nb_items_virtuels /*taille*/);
1603 dest.ref_array(tableau, nb_items_reels /*debut*/, nb_items_virtuels /*taille*/);
1604 const int nb_erreurs = traduire_indice_global_vers_local(src, dest);
1605 return nb_erreurs;
1606}
1607
1608/*! @brief Builds the items_communs + virtual space structure of an array containing indices of geometric items, indexed by another geometric item type.
1609 *
1610 * Example: array indexed by md_indice, containing indices of md_valeur:
1611 * type_indice type_valeur example array:
1612 * element vertex domaine.les_elems()
1613 * face vertex faces_sommets
1614 * element face elem_faces
1615 * face element faces_voisins
1616 * element element ?
1617 * element edge elem_aretes
1618 * Nb_valeurs_max is the number of real items of type "type_valeur".
1619 *
1620 */
1622 const MD_Vector& md_valeur,
1623 IntTab& tableau,
1624 const int error_is_fatal)
1625{
1627 {
1628 // MD_Vector is a MD_Vector_seq:
1629 assert( dynamic_cast<const MD_Vector_seq *>(&md_indice.valeur()) != nullptr);
1630 // The array should still get its (dummy sequential) MD_Vector, otherwise it will remain null.
1631 if (!(tableau.get_md_vector() == md_indice))
1632 tableau.set_md_vector(md_indice);
1633 return;
1634 }
1635
1636 if (tableau.dimension_tot(0) != md_indice->get_nb_items_reels()
1637 && (tableau.dimension_tot(0) != md_indice->get_nb_items_tot()))
1638 {
1639 Cerr << "[PE " << Process::me()
1640 << "] Error in Scatter::construire_espace_virtuel_traduction\n"
1641 << " the array does not have the good dimension on input" << finl;
1642 exit();
1643 }
1644 // Build the global/local index dictionary
1645 // for the values of the array
1646 Traduction_Indice_Global_Local dictionnaire_indices;
1647 dictionnaire_indices.initialiser(md_valeur);
1648
1649 // Build the virtual space structure of "tableau"
1650 if (!(tableau.get_md_vector() == md_indice))
1651 MD_Vector_tools::creer_tableau_distribue(md_indice, tableau, RESIZE_OPTIONS::COPY_NOINIT);
1652
1653 // Fill the virtual values of "tableau"
1654 const int nb_erreurs = dictionnaire_indices.traduire_espace_virtuel(tableau);
1655
1656 if (nb_erreurs > 0 && error_is_fatal)
1657 {
1658 Cerr << "[PE " << Process::me()
1659 << "] Error in Scatter::construire_espace_virtuel_traduction\n"
1660 << " some indices of values were not found in\n"
1661 << " the local area : it missing virtual items"
1662 << finl;
1663 exit();
1664 }
1665}
1666
1667
1668/*! @brief Reorders joint faces so that they appear in the same order on each pair of neighboring processors.
1669 *
1670 * In practice, for a pair
1671 * pe1 < pe2, pe1 sends its joint faces to pe2 and pe2 translates them to local
1672 * vertex indices. The joint faces of PE2 are therefore not used.
1673 *
1674 */
1676{
1677 // Build the global/local index dictionary
1678 // for the vertices of the domain:
1679 Traduction_Indice_Global_Local dictionnaire_indices;
1680 dictionnaire_indices.initialiser(dom.les_sommets().get_md_vector());
1681
1682 Schema_Comm schema_comm;
1683 Joints& joints = dom.faces_joint();
1684 const int nb_joints = joints.size();
1685 const int moi = Process::me();
1686 int i_joint;
1687
1688 // Fill the recipient lists:
1689 // send to higher-rank neighbors and receive from lower-rank neighbors.
1690 ArrOfInt send_list;
1691 ArrOfInt recv_list;
1692
1693
1694
1695 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1696 {
1697 const int pe_voisin = joints[i_joint].PEvoisin();
1698 if (pe_voisin > moi)
1699 send_list.append_array(pe_voisin);
1700 else
1701 recv_list.append_array(pe_voisin);
1702 }
1703
1704 schema_comm.set_send_recv_pe_list(send_list, recv_list);
1705
1706 schema_comm.begin_comm();
1707 // Send joint faces translated to global vertex indices
1708 TIDTab faces_num_global;
1709
1710 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1711 {
1712 const Joint& joint = joints[i_joint];
1713 const int pe_voisin = joint.PEvoisin();
1714 if (pe_voisin > moi)
1715 {
1716 const IntTab& faces_sommets = joint.faces().les_sommets();
1717 if (faces_sommets.dimension(0) > 0)
1718 {
1719 faces_num_global.resize(faces_sommets.dimension(0), faces_sommets.dimension(1));
1720 dictionnaire_indices.traduire_indice_local_vers_global(faces_sommets,
1721 faces_num_global,
1722 faces_sommets.size_array());
1723 }
1724 else
1725 faces_num_global.resize(0);
1726
1727 schema_comm.send_buffer(pe_voisin) << faces_num_global;
1728 }
1729 }
1730 schema_comm.echange_taille_et_messages();
1731 // Receive joint faces and translate to local indices
1732 for (i_joint = 0; i_joint < nb_joints; i_joint++)
1733 {
1734 Joint& joint = joints[i_joint];
1735 const int pe_voisin = joint.PEvoisin();
1736 if (pe_voisin < moi)
1737 {
1738 IntTab& faces_sommets = joint.faces().les_sommets();
1739 schema_comm.recv_buffer(pe_voisin) >> faces_num_global;
1740 if (faces_sommets.dimension(0) != faces_num_global.dimension(0))
1741 {
1742 Cerr << "[PE " << moi
1743 << "] Error in Scatter::reordonner_faces_de_joint:\n"
1744 << " the number of joint faces is not identical to the PE "
1745 << pe_voisin << finl;
1746 exit();
1747 }
1748 const int nb_erreurs =
1749 dictionnaire_indices.traduire_indice_global_vers_local(faces_num_global,
1750 faces_sommets);
1751 if (nb_erreurs > 0)
1752 {
1753 Cerr << "[PE " << moi
1754 << "] Error in Scatter::reordonner_faces_de_joint:\n"
1755 << " The faces of the joint with PE " << pe_voisin
1756 << " use of unknown nodes" << finl;
1757 exit();
1758 }
1759 }
1760 }
1761 schema_comm.end_comm();
1762}
1763
1764/*! @brief Utility method: returns a complete list of all joint vertices (face vertices + isolated vertices), sorted and
1765 *
1766 * without duplicates.
1767 *
1768 */
1769static void calculer_liste_complete_sommets_joint(const Joint& joint, ArrOfInt& liste_sommets)
1770{
1771 liste_sommets = joint.joint_item(JOINT_ITEM::SOMMET).items_communs();
1772#if 0
1773
1774 // Take all vertices of the joint faces:
1775 const IntTab& som_faces = joint.faces().les_sommets();
1776 liste_sommets = ref_cast(ArrOfInt,som_faces);
1777 // Add all isolated vertices:
1778 const ArrOfInt& som_isoles = joint.sommets();
1779 const int n = som_isoles.size_array();
1780 for (int i = 0; i < n; i++)
1781 liste_sommets.append_array(som_isoles[i]);
1782 // Remove duplicates from the list
1783 array_trier_retirer_doublons(liste_sommets);
1784#endif
1785}
1786
1787inline int arete_de_sommets_Si_et_Sj(const int Si, const int Sj, const int arete, const IntTab& aretes_som)
1788{
1789 if ( (aretes_som(arete,0) == Si && aretes_som(arete,1) == Sj)
1790 || (aretes_som(arete,1) == Si && aretes_som(arete,0) == Sj) )
1791 return 1;
1792 else
1793 return 0;
1794}
1795
1796/*! @brief Utility method: returns a complete list of all joint edges (face edges + isolated edges), sorted and
1797 *
1798 * without duplicates.
1799 *
1800 */
1801static void calculer_liste_complete_aretes_joint(const Joint& joint, ArrOfInt& liste_aretes)
1802{
1803 // Build the list of common edges liste_aretes
1804
1805 ///////////////////////////////////////////////////////
1806 // Search for joint edges on joint faces
1807 ///////////////////////////////////////////////////////
1808 int nb_faces_joint=joint.faces().nb_faces();
1809 int nb_som_faces=joint.faces().nb_som_faces();
1810 const IntTab& sommet=joint.faces().les_sommets();
1811 const Domaine& dom=joint.domaine();
1812 const DoubleTab& coord=dom.coord_sommets();
1813 const IntTab& aretes_som=joint.domaine().aretes_som();
1814 ArrOfInt aretes(1);
1815 int compteur=0;
1816 DoubleTab positions(1,Objet_U::dimension);
1817 ArrOfInt som_faces(nb_faces_joint*nb_som_faces);
1818 // Traverse vertices of each joint face pairwise
1819 for (int face=0; face<nb_faces_joint; face++)
1820 for (int i=0; i<nb_som_faces; i++)
1821 {
1822 int Si = sommet(face,i);
1823 som_faces[face*nb_som_faces+i]=Si;
1824 for (int j=i; j<nb_som_faces; j++)
1825 {
1826 int Sj = sommet(face,j);
1827 // Compute midpoint C between vertices Si and Sj
1828 for (int comp=0; comp<Objet_U::dimension; comp++)
1829 positions(0,comp)=0.5*(coord(Si,comp)+coord(Sj,comp));
1830 dom.chercher_aretes(positions,aretes);
1831 // If an edge is found whose center coincides with point C
1832 // and whose vertices are identical to Si and Sj, add the edge to the list
1833 if (aretes[0]>=0 && arete_de_sommets_Si_et_Sj(Si, Sj, aretes[0], aretes_som))
1834 {
1835 compteur++;
1836 liste_aretes.append_array(aretes[0]);
1837 }
1838 }
1839 }
1840 Process::Journal() << "common edges found on faces of joint with " << joint.PEvoisin() << " :" << compteur << finl;
1841 /////////////////////////////////////////////////////////////////////////
1842 // Search for isolated joint edges on isolated joint vertices
1843 /////////////////////////////////////////////////////////////////////////
1844 // joint.sommets() sometimes contains all vertices!
1845 // So we build a som_isoles array
1846 ArrOfInt som_isoles;
1847 // Put all vertices in som_isoles (isolated + from joint faces):
1848 calculer_liste_complete_sommets_joint(joint, som_isoles);
1849 // Sort som_faces and remove duplicates
1850 array_trier_retirer_doublons(som_faces);
1851 // Remove all vertices of som_isoles that are in som_faces
1852 array_retirer_elements(som_isoles, som_faces);
1853 // Remove joint face vertices
1854 const int n = som_isoles.size_array();
1855 Process::Journal() << "number of isolated nodes: " << n << finl;
1856 Process::Journal() << "number of nodes of faces of joint: " << 3*sommet.dimension(0) << finl;
1857
1858 compteur=0;
1859 // Traverse isolated vertices pairwise
1860 for (int i = 0; i < n; i++)
1861 for (int j = i; j < n; j++)
1862 {
1863 // Compute midpoint C between vertices Si and Sj
1864 int Si = som_isoles[i];
1865 int Sj = som_isoles[j];
1866 for (int comp=0; comp<Objet_U::dimension; comp++)
1867 positions(0,comp)=0.5*(coord(Si,comp)+coord(Sj,comp));
1868 dom.chercher_aretes(positions,aretes);
1869 // If an edge is found whose center coincides with point C
1870 // and whose vertices are identical to Si and Sj, add the edge to the list
1871 if (aretes[0]>=0 && arete_de_sommets_Si_et_Sj(Si, Sj, aretes[0], aretes_som))
1872 {
1873 compteur++;
1874 liste_aretes.append_array(aretes[0]);
1875 }
1876 }
1877 Process::Journal() << "common edges found isolated on joint with " << joint.PEvoisin() << " :" << compteur << finl;
1878 // Remove duplicates from the list
1879 array_trier_retirer_doublons(liste_aretes);
1880}
1881
1882static void calculer_liste_complete_items_joint(const Joint& joint, const JOINT_ITEM type_item, ArrOfInt& liste_items)
1883{
1884 switch(type_item)
1885 {
1886 case JOINT_ITEM::SOMMET:
1887 calculer_liste_complete_sommets_joint(joint, liste_items);
1888 break;
1889 case JOINT_ITEM::ARETE:
1890 calculer_liste_complete_aretes_joint(joint, liste_items);
1891 break;
1892 default:
1893 Cerr << "Error in Scatter::calculer_liste_complete_items_joint" << finl;
1894 Cerr << "Type of item not expected." << finl;
1895 Process::exit();
1896 }
1897}
1898
1899/*! @brief Current periodic algorithms (P1B assembler, OpDivElem P1B) require that for each virtual periodic face, the opposite face is
1900 *
1901 * also virtual. This is not guaranteed at the output of the
1902 * calculer_elements_distants method. This method adds the missing elements
1903 * to the remote spaces to ensure this condition:
1904 * If a remote element for a given PE is adjacent to a periodic face,
1905 * the element adjacent to the opposite face is added to the remote space.
1906 *
1907 */
1909{
1911 Cerr << "Correction of remote spaces of the elements for the periodic faces" << finl;
1912
1913 const Noms& liste_bords_periodiques = dom.bords_perio();
1914
1915 const int nb_elem = dom.nb_elem();
1916 const IntTab& les_elems = dom.les_elems();
1917
1918 // This array will contain, for a given periodic boundary:
1919 // if element i is adjacent to a face of this boundary,
1920 // element_oppose[i] is the number of the element adjacent to the
1921 // opposite face on this boundary.
1922 // -1 otherwise.
1923 ArrOfInt element_oppose(nb_elem);
1924
1925 Static_Int_Lists connectivite_som_elem;
1926 const int nb_sommets = dom.nb_som();
1927 construire_connectivite_som_elem(nb_sommets,
1928 les_elems,
1929 connectivite_som_elem,
1930 0 /* do not include virtual vertices */);
1931
1932 const int nb_som_face = dom.type_elem()->nb_som_face();
1933 ArrOfInt une_face(nb_som_face);
1934 ArrOfInt elems_voisins;
1935
1936
1937 const int nb_joints = dom.nb_joints();
1938
1939 // Markers for existing remote elements:
1940 ArrOfBit marqueurs_elements_distants(nb_elem);
1941 marqueurs_elements_distants = 0;
1942
1943 // Adding an element to a remote space for a given boundary
1944 // may cause a problem on another boundary (the opposite element of the
1945 // newly added element may be missing for another periodicity direction).
1946 // We must therefore iterate until nothing changes.
1947 int nb_elements_ajoutes = 0;
1948 do
1949 {
1950 nb_elements_ajoutes = 0;
1951 for (auto& itr : liste_bords_periodiques)
1952 {
1953 const Nom& nom_bord = itr;
1954 const Bord& bord = dom.bord(nom_bord);
1955 const IntTab& faces_sommets = bord.les_sommets_des_faces();
1956 const int nb_faces = bord.nb_faces();
1957
1958 // First step: identify the opposite elements for this periodic boundary.
1959 // Loop over the first half of the boundary.
1960 // WARNING: assumes that boundary faces are ordered: first all faces
1961 // on one side of the periodic domain, then, in the same order, the opposite faces.
1962 element_oppose = -1;
1963
1964 for (int i_face = 0; i_face < nb_faces / 2; i_face++)
1965 {
1966 // For each face, find the element adjacent to this face and to the opposite face.
1967 // Loop over the face and the opposite face.
1968 int elem0 = -1; // The two opposite elements of this periodic face
1969 int elem1 = -1;
1970 for (int quel_cote = 0; quel_cote < 2; quel_cote++)
1971 {
1972 const int face = i_face + quel_cote * nb_faces / 2;
1973 int i;
1974 for (i = 0; i < nb_som_face; i++)
1975 une_face[i] = faces_sommets(face, i);
1976 find_adjacent_elements(connectivite_som_elem, une_face, elems_voisins);
1977 const int n = elems_voisins.size_array();
1978 if (n != 1)
1979 {
1980 Cerr << "Error in Scatter::corriger_espace_distant_elements_perio: \n"
1981 << " The face " << i_face << " of boundary " << nom_bord << " has "
1982 << n << " neighbors." << finl;
1983 Process::exit();
1984 }
1985 if (quel_cote == 0)
1986 elem0 = elems_voisins[0];
1987 else
1988 elem1 = elems_voisins[0];
1989 }
1990 element_oppose[elem0] = elem1;
1991 element_oppose[elem1] = elem0;
1992 }
1993 // Second step: iterate over remote elements. If a remote element is
1994 // among the paired elements, add the other pair member to the remote elements.
1995 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
1996 {
1997 ArrOfInt& elements_distants = dom.joint(i_joint).set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants();
1998 int n = elements_distants.size_array();
1999 // Mark existing remote elements:
2000 int i;
2001 for (i = 0; i < n; i++)
2002 {
2003 const int elem = elements_distants[i];
2004 marqueurs_elements_distants.setbit(elem);
2005 }
2006
2007 for (i = 0; i < n; i++)
2008 {
2009 const int elem = elements_distants[i];
2010 const int elem_oppose = element_oppose[elem];
2011 if (elem_oppose >= 0 && (!marqueurs_elements_distants.testsetbit(elem_oppose)))
2012 {
2013 elements_distants.append_array(elem_oppose);
2014 nb_elements_ajoutes++;
2015 }
2016 }
2017 // Reset the markers array to zero:
2018 n = elements_distants.size_array();
2019 for (i = 0; i < n; i++)
2020 {
2021 const int elem = elements_distants[i];
2022 marqueurs_elements_distants.clearbit(elem);
2023 }
2024 }
2025 }
2026
2027 }
2028 while (nb_elements_ajoutes > 0);
2029 // Final sort of remote elements in ascending order
2030 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
2031 {
2032 ArrOfInt& elements_distants = dom.joint(i_joint).set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants();
2033
2034 elements_distants.ordonne_array();
2035 }
2036}
2037
2038/*! @brief Fills the "espace_distant()" array of elements in the joints.
2039 *
2040 * This is where joint elements are determined based on joint thickness.
2041 * The espace_distant array contains the
2042 * local indices of remote elements (to be sent to neighboring processors).
2043 * For a joint of thickness 1, these are all elements neighboring a
2044 * joint vertex (vertex on a joint face or isolated vertex).
2045 * For a joint of thickness n>1, these are all elements neighboring a
2046 * vertex of an element from the joint of thickness n-1.
2047 * Neighborhood is defined on the global domain (all subdomains combined).
2048 * History: first version by B.Mathieu on 16/01/2007.
2049 * A method that determines remote elements at partition time also exists
2050 * (DomaineCutter::construire_elements_distants_ssdom).
2051 * The method below has been validated by comparison with the partitioner method.
2052 * Outputs have been verified for thicknesses up to 5 on tetrahedral meshes.
2053 * The difficulty of the algorithm is to obtain virtual elements of thickness > 1 that
2054 * lie on subdomains not in direct contact with the local subdomain.
2055 * This difficulty is resolved by the algorithm below.
2056 *
2057 */
2059{
2060 const int nbjoints = dom.nb_joints();
2061 const int nb_som_elem = dom.nb_som_elem();
2062 const IntTab& les_elems = dom.les_elems();
2063 const int nproc = Process::nproc();
2064 // PL: all processors must have the same epaisseur_joint for the following algorithm
2065 // that uses data exchange with schema_comm.begin_comm() schema_comm.end_comm()
2066 // otherwise there is a deadlock in debug mode due to the exit at line 1866 (see case Quasi_Comp_Coupl_Incomp)
2067 //const int epaisseur_joint = (nb_joints > 0) ? domaine.joint(0).epaisseur() : 1;
2068 const int epaisseur_joint = (int) mp_max((nbjoints > 0) ? dom.joint(0).epaisseur() : 1);
2069
2071 Cerr << "Calculation of remote space of elements : thickness " << epaisseur_joint << finl;
2072
2073 // The algorithm is based on the progressive construction of the "liste_sommets" array.
2074 // liste_sommets(pe) contains at a given moment the list of vertices owned by me()
2075 // for which "pe" wants to know the neighboring elements.
2076 // Each PE starts by requesting its direct neighboring elements, i.e. the elements
2077 // neighboring joint vertices. Knowing that it will subsequently want the elements
2078 // neighboring those found, we add to the lists the vertices of the remote elements
2079 // found in the previous iteration.
2080 ArrsOfInt liste_sommets(nproc);
2081
2082 // For each processor, the list of local elements to send to it
2083 ArrsOfInt elements_distants(nproc);
2084 {
2085 // smart_resize because we will call append_array on these arrays
2086 for (int i = 0; i < nproc; i++)
2087 {
2088
2089
2090 }
2091 }
2092
2093 Static_Int_Lists som_elem;
2094 {
2096 Cerr << "Nodes-elements connectivity ..." << finl;
2097 const int nb_sommets = dom.nb_som();
2098 construire_connectivite_som_elem(nb_sommets,
2099 les_elems,
2100 som_elem,
2101 0 /* do not include virtual vertices */);
2102 }
2103
2104 ArrOfInt liste_pe_voisins(nbjoints);
2105
2106 // Initialize liste_pe_voisins and
2107 // initialize the vertex list: each processor requests all elements
2108 // neighboring its joint vertices. The local processor knows that for thickness 1,
2109 // each neighboring processor via a joint wants to know all elements neighboring
2110 // the joint vertices. So we put in liste_sommets(pe) the joint vertices with that PE,
2111 // so as to send it the local elements neighboring those vertices.
2112 {
2113 for (int i_joint = 0; i_joint < nbjoints; i_joint++)
2114 {
2115 const Joint& joint = dom.joint(i_joint);
2116 const int pe = joint.PEvoisin();
2117 liste_pe_voisins[i_joint] = pe;
2118 const ArrOfInt& sommets_joint = joint.joint_item(JOINT_ITEM::SOMMET).items_communs();
2119 liste_sommets[pe] = sommets_joint;
2120 }
2121 }
2122
2123 // We will need a communication scheme where each processor sends and receives
2124 // data to/from its direct neighbors (neighbors sharing a vertex)
2125 Schema_Comm schema_comm;
2126 schema_comm.set_send_recv_pe_list(liste_pe_voisins, liste_pe_voisins);
2127
2128 // We will need fast access to the list of processors that share a
2129 // vertex and the index of that vertex on each processor.
2130 // Structure content:
2131 // data_sommets_communs.get_list_size(sommet) = 2 * number of procs sharing the vertex
2132 // data_sommets_communs(sommet, 2*i) = neighboring PE number
2133 // data_sommets_communs(sommet, 2*i+1) = index of the vertex on that PE.
2134 Static_Int_Lists data_sommets_communs;
2135 // Filling: the structure is only used if joint thickness is > 1
2136 if (epaisseur_joint > 1)
2137 {
2138 ArrOfInt count(dom.nb_som());
2139 // Step 1: with how many processors is each vertex shared?
2140 for (int ijoint = 0; ijoint < nbjoints; ijoint++)
2141 {
2142 const Joint& joint = dom.joint(ijoint);
2143 const ArrOfInt& sommets_joint = joint.joint_item(JOINT_ITEM::SOMMET).items_communs();
2144 const int n = sommets_joint.size_array();
2145 for (int i = 0; i < n; i++)
2146 {
2147 const int som = sommets_joint[i];
2148 count[som] += 2; // 2 integers stored per common vertex
2149 }
2150 }
2151 data_sommets_communs.set_list_sizes(count);
2152 count = 0;
2153 // Step 2: fill the structure:
2154 for (int ijoint = 0; ijoint < nbjoints; ijoint++)
2155 {
2156 const Joint& joint = dom.joint(ijoint);
2157 const int pe = joint.PEvoisin();
2158 const IntTab& renum_sommets = joint.joint_item(JOINT_ITEM::SOMMET).renum_items_communs();
2159 const int n = renum_sommets.dimension(0);
2160 for (int i = 0; i < n; i++)
2161 {
2162 // Index of the shared vertex on the neighboring PE
2163 const int i_sommet_distant = renum_sommets(i, 0);
2164 // Index of the shared vertex on my local domain
2165 const int i_sommet_local = renum_sommets(i, 1);
2166 const int j = count[i_sommet_local]++;
2167 data_sommets_communs.set_value(i_sommet_local, j*2, pe);
2168 data_sommets_communs.set_value(i_sommet_local, j*2+1, i_sommet_distant);
2169 }
2170 }
2171 }
2172
2173 // Loop over joint thickness:
2174 // At the start of the loop, liste_sommets is assumed to contain, for each processor
2175 // requesting virtual elements, the list of vertices of me() whose neighbors it wants.
2176 for (int epaisseur = 1; ; epaisseur++)
2177 {
2179 Cerr << " Calculation of the thickness " << epaisseur << finl;
2180
2181 // For each vertex list, put in the remote elements of the same processor
2182 // the elements neighboring the vertices in the list.
2183 int pe;
2184 for (pe = 0; pe < nproc; pe++)
2185 {
2186 ArrOfInt& elems_dist = elements_distants[pe];
2187 const ArrOfInt& sommets = liste_sommets[pe];
2188 elems_dist.resize_array(0);
2189 const int nb_som_liste = sommets.size_array();
2190 for (int isom = 0; isom < nb_som_liste; isom++)
2191 {
2192 const int som = sommets[isom];
2193 if (som<0)
2194 continue;
2195 const int nb_elem_som = som_elem.get_list_size(som);
2196 for (int ielem = 0; ielem < nb_elem_som; ielem++)
2197 {
2198 const int elem = som_elem(som, ielem);
2199 elems_dist.append_array(elem);
2200 }
2201 }
2202 array_trier_retirer_doublons(elems_dist);
2203 }
2204
2205 // The following updates liste_sommets for the next iteration.
2206 // No need to do this if we are at the last iteration:
2207 if (epaisseur == epaisseur_joint)
2208 break;
2209
2210 // Put in the vertex lists the vertices of the remote elements found
2211 for (pe = 0; pe < nproc; pe++)
2212 {
2213 ArrOfInt& sommets = liste_sommets[pe];
2214 const ArrOfInt& elems_dist = elements_distants[pe];
2215 sommets.resize_array(0);
2216 const int nb_elems_dist = elems_dist.size_array();
2217 for (int ielem = 0; ielem < nb_elems_dist; ielem++)
2218 {
2219 const int elem = elems_dist[ielem];
2220 for (int isom = 0; isom < nb_som_elem; isom++)
2221 {
2222 const int som = les_elems(elem, isom);
2223 sommets.append_array(som);
2224 }
2225 }
2226 array_trier_retirer_doublons(sommets);
2227 }
2228 // Traverse the vertex lists. For each vertex, if it is a joint vertex,
2229 // send to the processors owning that vertex a request "processor i
2230 // wants all neighbors of this vertex".
2231 // Do not send the request to processor "i" for list "i": it already knows
2232 // its own elements!
2233 schema_comm.begin_comm();
2234 // First communication phase: stack data to send in buffers
2235 for (pe = 0; pe < nproc; pe++)
2236 {
2237 const ArrOfInt& sommets = liste_sommets[pe];
2238 const int nb_som_liste = sommets.size_array();
2239 for (int isom = 0; isom < nb_som_liste; isom++)
2240 {
2241 const int i_sommet_local = sommets[isom];
2242 if (i_sommet_local<0)
2243 continue;
2244 const int nb_pe_voisins = data_sommets_communs.get_list_size(i_sommet_local) / 2;
2245 for (int i = 0; i < nb_pe_voisins; i++)
2246 {
2247 const int pe_voisin = data_sommets_communs(i_sommet_local, i*2);
2248 // Index of the vertex on the neighboring processor.
2249 const int i_sommet_distant = data_sommets_communs(i_sommet_local, i*2+1);
2250 if (pe_voisin != pe)
2251 {
2252 // Send to processor "pe_voisin" the message: "processor PE needs
2253 // the elements neighboring vertex i_sommet_distant"
2254 schema_comm.send_buffer(pe_voisin) << pe << i_sommet_distant;
2255 }
2256 }
2257 }
2258 }
2259 schema_comm.echange_taille_et_messages();
2260 for (int i_pevoisin = 0; i_pevoisin < nbjoints; i_pevoisin++)
2261 {
2262 const int pe_voisin = liste_pe_voisins[i_pevoisin];
2263 Entree& buffer = schema_comm.recv_buffer(pe_voisin);
2264 for (;;)
2265 {
2266 int pe2, sommet;
2267 // Retrieve the message "processor PE needs the elements neighboring SOMMET".
2268 buffer >> pe2 >> sommet;
2269 if (buffer.eof())
2270 break;
2271 liste_sommets[pe2].append_array(sommet);
2272 }
2273 }
2274 schema_comm.end_comm();
2275 // Remove duplicates from the vertex lists
2276 for (pe = 0; pe < nproc; pe++)
2277 {
2278 ArrOfInt& sommets = liste_sommets[pe];
2279 array_trier_retirer_doublons(sommets);
2280 }
2281 }
2282
2283 // Create new joints if needed, and store remote elements in the joints
2284 {
2285 ArrOfInt voisins;
2286
2287
2288 for (int pe = 0; pe < nproc; pe++)
2289 if (elements_distants[pe].size_array() > 0)
2290 voisins.append_array(pe);
2291 ajouter_joints(dom, voisins);
2292
2293#ifdef CHECK_ALGO_ESPACE_VIRTUEL
2294 // We do not use the virtual spaces computed above; we only compare them
2295 // to the virtual spaces computed at partition time by the sequential algorithm.
2296 // For now, the parallel algorithm appears to work correctly;
2297 // this test is disabled. (Benoit Mathieu)
2298 bool erreur = false;
2299 const int nbjoints = dom.nbjoints();
2300 for (int i = 0; i < nbjoints; i++)
2301 {
2302 Joint& joint = dom.joint(i);
2303 const int pe = joint.PEvoisin();
2304 if (!(joint.joint_item(JOINT_ITEM::ELEMENT).items_distants() == elements_distants[pe]))
2305 {
2306 Cerr << "Error in Scatter, PE " << Process::me() << finl;
2307 Process::Journal() << "Error scatter, remote elements pe " << pe << finl
2308 << " Splitting algorithm: " << joint.joint_item(JOINT_ITEM::ELEMENT).items_distants()
2309 << " Scatter algorithm : " << elements_distants[pe] << finl;
2310
2311 erreur = true;
2312 }
2313 }
2314 if (mp_or(erreur))
2315 Process::exit();
2316#else
2317 // Store the result
2318 const int nb_joints = dom.nb_joints();
2319 for (int i = 0; i < nb_joints; i++)
2320 {
2321 Joint& joint = dom.joint(i);
2322 const int pe = joint.PEvoisin();
2323 joint.set_joint_item(JOINT_ITEM::ELEMENT).set_items_distants() = elements_distants[pe];
2324 }
2325#endif
2326 }
2327}
2328
2329static inline int fct_cmp_coordonnees(const double * s1, const double *s2, int dim, const double epsilon)
2330{
2331 assert(dim==2 || dim==3);
2332 if (s1[0] < s2[0] - epsilon)
2333 return -1;
2334 else if (s1[0] > s2[0] + epsilon)
2335 return 1;
2336 else if (s1[1] < s2[1] - epsilon)
2337 return -1;
2338 else if (s1[1] > s2[1] + epsilon)
2339 return 1;
2340 else if (dim<3)
2341 return 0;
2342 else if (s1[2] < s2[2] - epsilon)
2343 return -1;
2344 else if (s1[2] > s2[2] + epsilon)
2345 return 1;
2346 else
2347 return 0;
2348}
2349
2350/*! @brief Builds the "correspondance" array such that for 0 <= i < sommets2.
2351 *
2352 * size_array(),
2353 * If sommet2(i) exists in sommets1, then
2354 * sommets2(i, ...) == sommets1(correspondance[i], ...)
2355 * Otherwise
2356 * correspondance[i] = -1
2357 * Equality is checked to within epsilon in absolute value (i.e. abs(x1-x2) < epsilon)
2358 * The algorithm is generally O(n1*log(n1) + n2*log(n1))
2359 * (search based on quicksort).
2360 * If the sort fails, an O(n1*n2) algorithm is used.
2361 * Arrays sommets1 and sommets2 must be 2-dimensional.
2362 * The correspondance array must have size sommets2.size_array().
2363 * Return value: number of vertices of sommets2 not found in sommets1.
2364 *
2365 */
2366int Scatter::Chercher_Correspondance(const DoubleTab& sommets1, const DoubleTab& sommets2,
2367 ArrOfInt& correspondance, const double epsilon)
2368{
2369 const int nb_sommets1 = sommets1.dimension(0);
2370 const int nb_sommets2 = sommets2.dimension(0);
2371 // Precondition required for fct_cmp_index_coord
2372 assert(sommets1.nb_dim() == 2);
2373 assert(sommets2.nb_dim() == 2);
2374 assert(correspondance.size_array() == nb_sommets2);
2375 if (nb_sommets1 < 1)
2376 {
2377 correspondance = -1;
2378 return nb_sommets2;
2379 }
2380
2381 // Sorted indirection array such that coordinates sommets1(index[i], .) are
2382 // sorted in lexicographic order.
2383 ArrOfInt index(nb_sommets1);
2384 {
2385 int i;
2386 for (i = 0; i < nb_sommets1; i++)
2387 index[i] = i;
2388 }
2389
2390 // Sort the index array
2391 // Vertices are sorted in lexicographic coordinate order.
2392 // Since we test with a tolerance of epsilon, the sort may fail:
2393 // If x=1, y=1.01, z=1.02 and epsilon=0.01, we have
2394 // x==y (to within epsilon)
2395 // y==z (to within epsilon)
2396 // but x!=z
2397 // So the binary search may fail subsequently.
2398 tri_lexicographique_tableau_indirect(sommets1, index);
2399
2400 // Build the correspondance array such that
2401 // sommet1(correspondance[i], ...) == sommet2(i, ...)
2402 int nb_sommets_non_trouves = 0;
2403 int nb_echec_dichotomie = 0;
2404 {
2405 int i;
2406 int nb_dim = sommets1.dimension(1);
2407 for (i = 0; i < nb_sommets2; i++)
2408 {
2409 const double * s2 = & sommets2(i,0);
2410 int num_sommet = -1;
2411
2412 // First search for the vertex in sommets1 using binary search (bsearch)
2413 int imin = 0;
2414 int imax = nb_sommets1 - 1;
2415 int resu_cmp = -1;
2416 int k = -1;
2417 while (imax > imin)
2418 {
2419 const int milieu = (imin + imax) >> 1; // (min+max)/2
2420 k = index[milieu];
2421 const double * s1 = & sommets1(k, 0);
2422 resu_cmp = fct_cmp_coordonnees(s1, s2, nb_dim, epsilon);
2423 switch(resu_cmp)
2424 {
2425 case -1:
2426 imin = milieu + 1;
2427 break; // s1<s2
2428 case 1 :
2429 imax = milieu - 1;
2430 break; // s1>s2
2431 default:
2432 imin = imax = milieu;
2433 break; // s1==s2
2434 }
2435 }
2436 if (resu_cmp != 0)
2437 {
2438 k = index[imin];
2439 const double * s1 = & sommets1(k, 0);
2440 resu_cmp = fct_cmp_coordonnees(s1, s2, nb_dim, epsilon);
2441 }
2442 if (resu_cmp == 0)
2443 {
2444 num_sommet = k;
2445 }
2446 else
2447 {
2448 nb_echec_dichotomie++;
2449 // If failure, the array may not be correctly ordered
2450 // => search for the vertex by scanning the entire array
2451 int j;
2452 for (j = 0; j < nb_sommets1; j++)
2453 {
2454 const double * s1 = & sommets1(j,0);
2455 resu_cmp = fct_cmp_coordonnees(s1, s2, nb_dim, epsilon);
2456 if (resu_cmp == 0)
2457 break;
2458 }
2459 if (j < nb_sommets1)
2460 num_sommet = j;
2461 else
2462 nb_sommets_non_trouves++;
2463 }
2464
2465 correspondance[i] = num_sommet;
2466 }
2467 }
2468
2469 if (nb_echec_dichotomie > 0)
2470 Process::Journal() << "Chercher_Correspondance Dichotomy failure rate "
2471 << nb_echec_dichotomie << " / " << nb_sommets2 << finl;
2472
2473 return nb_sommets_non_trouves;
2474}
2475
2476/*! @brief Generic method to build geometrical item correspondance between the local and the remote processor
2477 * around a joint.
2478 *
2479 * See also construire_correspondance_sommets_par_coordonnees() for the very specific usage of allow_resize.
2480 *
2481 */
2482void Scatter::construire_correspondance_items_par_coordonnees(Joints& joints, const JOINT_ITEM type_item,
2483 const DoubleTab& coord_items, bool allow_resize)
2484{
2485 switch(type_item)
2486 {
2487 case JOINT_ITEM::SOMMET:
2488 break;
2489 case JOINT_ITEM::ARETE:
2490 break;
2491 default:
2492 Cerr << "Scatter::construire_correspondance_items_par_coordonnees unusable for item "
2493 << (int)type_item
2494 << finl;
2495 Process::exit();
2496 }
2497 const int dim = Objet_U::dimension;
2498 const int nb_joints = joints.size();
2499
2500 // Indices of joint items in the domain on my processor
2501 ArrsOfInt indices_items_locaux(nb_joints);
2502 // Indices of joint items in the domain on the neighboring processor
2503 ArrsOfInt indices_items_distants(nb_joints);
2504 // Coordinates of the corresponding items (in the same order as indices_items_xxx)
2505 DoubleTabs coord_items_locaux(nb_joints);
2506 DoubleTabs coord_items_distants(nb_joints);
2507
2508 // Fill indices_items_locaux
2509 // and coord_items_locaux
2510 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
2511 {
2512 const Joint& joint = joints[i_joint];
2513 ArrOfInt& items = indices_items_locaux[i_joint];
2514 // Note: **SORTED_LIST** indices_items_locaux are
2515 // sorted in ascending order:
2516 calculer_liste_complete_items_joint(joint, type_item, items);
2517
2518 const int n = items.size_array();
2519 DoubleTab& coord = coord_items_locaux[i_joint];
2520 coord.resize(n, dim);
2521 for (int i = 0; i < n; i++)
2522 for (int j = 0; j < dim; j++)
2523 coord(i,j) = coord_items(items[i], j);
2524 }
2525
2526 // Send local indices and coordinates to the neighboring processor
2527 {
2528 Schema_Comm schema_comm;
2529 ArrOfInt liste_pe_voisins(nb_joints);
2530 int i;
2531 for (i = 0; i < nb_joints; i++)
2532 liste_pe_voisins[i] = joints[i].PEvoisin();
2533 schema_comm.set_send_recv_pe_list(liste_pe_voisins, liste_pe_voisins);
2534 schema_comm.begin_comm();
2535 for (i = 0; i < nb_joints; i++)
2536 {
2537 const int pe = liste_pe_voisins[i];
2538 Sortie& buffer = schema_comm.send_buffer(pe);
2539 buffer << indices_items_locaux[i];
2540 buffer << coord_items_locaux[i];
2541 }
2542 schema_comm.echange_taille_et_messages();
2543 for (i = 0; i < nb_joints; i++)
2544 {
2545 const int pe = liste_pe_voisins[i];
2546 Entree& buffer = schema_comm.recv_buffer(pe);
2547 buffer >> indices_items_distants[i];
2548 buffer >> coord_items_distants[i];
2549 }
2550 schema_comm.end_comm();
2551 }
2552
2553 // Loop over joints
2554 // This time, joints are modified (filling renum_virt_loc)
2555 const int moi = Process::me();
2556 for (int i_joint = 0; i_joint < nb_joints; i_joint++)
2557 {
2558 Joint& joint = joints[i_joint];
2559 const int PEvoisin = joint.PEvoisin();
2560 const ArrOfInt& indices_locaux = indices_items_locaux[i_joint];
2561 const DoubleTab& coord_locaux = coord_items_locaux[i_joint];
2562 const DoubleTab& coord_distants = coord_items_distants[i_joint];
2563 const int n = indices_locaux.size_array();
2564
2565 // Search for correspondences between items
2566 ArrOfInt corresp(n);
2567 const double epsilon = Objet_U::precision_geom;
2568 Chercher_Correspondance(coord_distants, coord_locaux, corresp, epsilon);
2569
2570 int nb_items_communs_trouves=0;
2571 for (int k = 0; k < n; k++)
2572 if (corresp[k]>=0) nb_items_communs_trouves++;
2573
2574 ArrOfInt& items_communs = joint.set_joint_item(type_item).set_items_communs();
2575 if (allow_resize)
2576 items_communs.resize_array(nb_items_communs_trouves);
2577 else
2578 // If a resisze is not expected, everthing in items_communs should have been found:
2579 assert(items_communs.size_array() == nb_items_communs_trouves);
2580 items_communs = -1;
2581
2582 // If a resize is expected, we need to shift the indices in 'corresp' to fit into
2583 // a (smaller) array of size 'nb_items_communs_trouves', avoiding the non-matching indices
2584 int n_dist = coord_distants.dimension(0);
2585 std::vector<bool> corres_ok(n_dist, false);
2586 std::vector<int> offset(n_dist, 0);
2587 if(allow_resize)
2588 {
2589 // corres_ok[j] is true iif the (remote) item 'j' was matched with a local one
2590 for(int k = 0; k < n; k++)
2591 if (corresp[k] >= 0)
2592 corres_ok[corresp[k]] = true;
2593 // offset[k] is the shift to be substracted to the remote item index once the invalid (=non
2594 // matched) remote items have been removed:
2595 int nb_holes = 0; // nb of holes seen so far in corres_ok
2596 for(int k = 0; k < n_dist; k++)
2597 offset[k] = corres_ok[k] ? nb_holes : nb_holes++;
2598 }
2599
2600 int i=0;
2601 for (int k = 0; k < n; k++)
2602 {
2603 const int i_local = indices_locaux[k];
2604 // The j-th remote item is identical to the k-th local item
2605 const int j = corresp[k];
2606
2607 // Not found? Possible error
2608 if (j < 0)
2609 {
2610 if (!allow_resize)
2611 {
2612 Cerr << "Error in Scatter::remplir_renum_virt_loc on PE " << moi << finl
2613 << "The item of type " << (int)type_item << " number " << i_local << " with coordinates ";
2614 for (int k2 = 0; k2 < dim; k2++)
2615 Cerr << coord_locaux(i, k2) << " ";
2616 Cerr << finl << "was not found in the joint with the PE " << PEvoisin << finl;
2617 if (type_item==JOINT_ITEM::ARETE)
2618 {
2619 Cerr << "The searching algorithm of the isolated edges on a joint" << finl;
2620 Cerr << "does not work yet in some cases. Two isolated nodes of a joint (example below" << finl;
2621 Cerr << "joint between 0 and 2) can be those of an edge not belonging to this joint (below" << finl;
2622 Cerr << "the edge belongs to the joint 0-1 but not 0-2):" << finl;
2623 //Cerr << " ________ " << finl;
2624 //Cerr << "1\ 2/1\2 /1\ " << finl;
2625 //Cerr << "__\/___\/___\ " << finl;
2626 //Cerr << " 0/\ 0 /\ 0 " << finl;
2627 //Cerr << " / 0\ / 0\ " << finl;
2628 Cerr << " ________ " << finl;
2629 Cerr << "1\\ 2/1\\2 /1\\ " << finl;
2630 Cerr << "__\\/___\\/___\\" << finl;
2631 Cerr << " 0/\\ 0 /\\ 0 " << finl;
2632 Cerr << " / 0\\ / 0\\ " << finl;
2633 Cerr << finl;
2634 Cerr << "One way to by-pass this problem is to split again your domain with" << finl;
2635 Cerr << "different options of splitting or with another splitter to do not fall" << finl;
2636 Cerr << "on the same configuration." << finl;
2637 }
2638 exit();
2639 }
2640 }
2641 else
2642 {
2643 if (moi < PEvoisin)
2644 {
2645 // common items in the order of local joint items:
2646 items_communs[i] = i_local;
2647 // Verify that it is indeed in ascending order of the local index
2648 // (see **SORTED_LIST**)
2649 assert(i==0 || items_communs[i] > items_communs[i-1]);
2650 }
2651 else
2652 {
2653 int j2 = j - offset[j];
2654 // common items in the order of items on the neighbor:
2655 assert(items_communs[j2] < 0);
2656 items_communs[j2] = i_local;
2657 }
2658 i++;
2659 }
2660 }
2661 assert(i==nb_items_communs_trouves);
2662 }
2663 // Fill renum_items_communs:
2664 calculer_renum_items_communs(joints, type_item);
2665}
2666
2667/*! @brief Builds the joint_item(JOINT_ITEM::SOMMET).items_communs arrays for all joints of the domain dom.
2668 *
2669 * @param dom The domain to process.
2670 * @param allow_resize may be set to True in some rare case (see Raffiner_isotrope_parallele)
2671 * when we know that the current size of 'items_communs' is wrong because part of the domain
2672 * was resized / changed.
2673 */
2675{
2676 construire_correspondance_items_par_coordonnees(dom.faces_joint(), JOINT_ITEM::SOMMET, dom.coord_sommets(), allow_resize);
2677}
2678
2679/*! @brief Builds the joint_item(JOINT_ITEM::ARETE).items_communs arrays for all joints of the domain.
2680 *
2681 * @param zvf The VF domain to process.
2682 */
2687
2688/*! @brief For a geometric item "type_item", fills the nb_items_virtuels_ field of joints based on
2689 * the number of remote items:
2690 *
2691 * The number of virtual items on joint i of processor j is the
2692 * number of remote items of joint j on processor i.
2693 *
2694 */
2696 const JOINT_ITEM type_item)
2697{
2698 Schema_Comm schema_comm;
2699 const int nb_joints = joints.size();
2700 ArrOfInt liste_voisins(nb_joints);
2701 int i_joint;
2702 for (i_joint = 0; i_joint < nb_joints; i_joint++)
2703 liste_voisins[i_joint] = joints[i_joint].PEvoisin();
2704
2705 // Send the number of remote items to the neighboring PE
2706 schema_comm.set_send_recv_pe_list(liste_voisins, liste_voisins);
2707 schema_comm.begin_comm();
2708 for (i_joint = 0; i_joint < nb_joints; i_joint++)
2709 {
2710 const Joint& joint = joints[i_joint];
2711 const Joint_Items& items = joint.joint_item(type_item);
2712 const int n = items.items_distants().size_array();
2713 const int pe = joint.PEvoisin();
2714 schema_comm.send_buffer(pe) << n;
2715 }
2716 // Exchange messages
2717 schema_comm.echange_taille_et_messages();
2718 // The neighboring PE receives this number of items and stores it.
2719 for (i_joint = 0; i_joint < nb_joints; i_joint++)
2720 {
2721 Joint& joint = joints[i_joint];
2722 Joint_Items& items = joint.set_joint_item(type_item);
2723 const int pe = joint.PEvoisin();
2724 int n;
2725 schema_comm.recv_buffer(pe) >> n;
2726 items.set_nb_items_virtuels(n);
2727 }
2728 schema_comm.end_comm();
2729}
2730
2731/*! @brief Create parallel descriptors for the vertex and element arrays of the domain (necessary because Scatter is
2732 * never invoked in sequential).
2733 *
2734 * In 64bit the corresponding number of items might be big. This is here the main justification for the need of the class
2735 * MD_Vector_seq which unique useful argument is the total number of items (with type trustIdType).
2736 * Alternative would have been to make all members of MD_Vector_std compatible with trustIdType ...
2737 */
2738template <typename _SIZE_>
2740{
2741 MD_Vector_seq mdseq_som(dom.les_sommets().dimension(0));
2742 MD_Vector md;
2743 md.copy(mdseq_som);
2744 dom.les_sommets().set_md_vector(md);
2745 MD_Vector_seq mdseq_elem(dom.les_elems().dimension(0));
2746 md.copy(mdseq_elem);
2747 dom.les_elems().set_md_vector(md);
2748}
2749
2750/*! @brief Method used by interpreters that modify the domain (sequential), destroys the descriptors
2751 * of vertices and elements to allow modification of these arrays.
2752 */
2753template <typename _SIZE_>
2755{
2756 MD_Vector md; // null descriptor
2757 dom.les_sommets().set_md_vector(md);
2758 dom.les_elems().set_md_vector(md);
2759}
2760
2761
2762// Explicit instanciation
2765#if INT_is_64_ == 2
2768#endif
int testsetbit(int_t i) const
Returns the value of bit e, then sets bit e to 1.
Definition ArrOfBit.h:85
void setbit(int_t i) const
Set bit e to 1.
Definition ArrOfBit.h:73
void clearbit(int_t i) const
Set bit e to 0.
Definition ArrOfBit.h:100
class Domaine_32_64 A Domain is a mesh composed of a set of geometric elements of the same type.
Definition Domaine.h:62
virtual void clear()
Reset the Domaine completely except for its name.
Definition Domaine.cpp:108
int nb_som_elem() const
Returns the number of vertices of the geometric elements that make up the domain.
Definition Domaine.h:474
const IntTab_t & aretes_som() const
returns the connectivity array edges/vertices.
Definition Domaine.h:156
SmallArrOfTID_t & chercher_aretes(const DoubleTab &pos, SmallArrOfTID_t &arr, int reel=0) const
Definition Domaine.cpp:676
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:1236
void renum(const IntVect_t &nums)
Renumbering of nodes: node number k becomes node number Les_Nums[k].
Definition Domaine.cpp:2184
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:258
Bord_t & bord(int i)
Definition Domaine.h:193
void read_vertices(Entree &s)
only read vertices from the stream s
Definition Domaine.cpp:1009
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:340
void renum_joint_common_items(const IntVect_t &nums, const int_t elem_offset)
Renumbers the nodes and elements present in the common items of joints.
Definition Domaine.cpp:1548
Joints_t & faces_joint()
Definition Domaine.h:265
int_t nb_som() const
Returns the number of vertices of the domain.
Definition Domaine.h:121
void ajouter(const DoubleTab_t &soms)
Adds nodes (or vertices) to the domain (without checking for duplicates).
Definition Domaine.cpp:908
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
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
void set_fichier_lu(Nom &nom)
const Domaine & domaine() const
Reading from a file of objects written in binary format.
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
Returns the array of vertices of all faces.
Definition Faces.h:74
int nb_som_faces() const
Returns the number of vertices per 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()
: Post-processing class for Eulerian fields in LATA format.
int ecrire_entete(const double temps_courant, const int reprise, const int est_le_premier_post) override
Opens the master file in ERASE mode and writes the lata file header (on the master processor only).
virtual int initialize_lata(const Nom &file_basename, const Format format=ASCII, const Options_Para options_para=SINGLE_FILE)
Initializes the class, opens the file and writes the header.
@ BINAIRE
@ SINGLE_FILE
int ecrire_domaine(const Domaine &domaine, const int est_le_premier_post) override
See Format_Post_base::ecrire_domaine. Writing a domain within a time step is accepted,...
int ecrire_temps(const double temps) override
Starts writing a new time step. For the LATA format specifically:
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
Gives a name to the boundary.
Definition Frontiere.cpp:74
const Domaine_t & domaine() const
Returns the domain associated with the boundary (const version).
int_t nb_faces() const
Returns the number of faces of the boundary.
Definition Frontiere.h:59
void associer_domaine(const Domaine_t &)
Associates the boundary to the domain it belongs to.
Definition Frontiere.cpp:63
IntTab_t & les_sommets_des_faces()
Returns the vertices of the boundary faces.
const Faces_t & faces() const
Definition Frontiere.h:54
Base class for "interpreter" objects.
Definition Interprete.h:38
static Objet_U & objet(const Nom &)
See Interprete_bloc::objet_global(). BM: the Interprete class is not the best place for this.
void affecte_epaisseur(int ep)
Definition Joint.h:48
const Joint_Items_t & joint_item(JOINT_ITEM type) const
Returns the joint information for the requested type (read-only).
Definition Joint.cpp:131
void affecte_PEvoisin(int num)
Definition Joint.h:47
Joint_Items_t & set_joint_item(JOINT_ITEM type)
Returns the joint information for a given geometric item type, for filling the structures.
Definition Joint.cpp:104
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
Returns the renum_items_communs_ array (read-only). See renum_items_communs_.
IntTab_t & set_renum_items_communs()
Returns the renum_items_communs_ array for filling. See renum_items_communs_.
ArrOfInt_t & set_items_communs()
Returns the items_communs_ array for filling.
int nb_items_virtuels() const
Returns the number of virtual items. See nb_items_virtuels_.
void set_nb_items_virtuels(int n)
Sets the number of virtual items. See nb_items_virtuels_.
const ArrOfInt_t & items_distants() const
Returns the items_distants_ array (read-only). See items_distants_.
ArrOfInt_t & set_items_distants()
Returns the items_distants_ array for filling.
This class implements the operators and virtual methods of the EFichier class as follows: The file to...
int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::in) override
Opens the file.
Reading from a file in binary format.
int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::in) override
Opens the file with the given mode and prot parameters. These parameters are the parameters of the st...
virtual int get_nb_items_tot() const
virtual int get_nb_items_reels() const
Dummy parallel descriptor used for sequential computations.
This is the simplest descriptor, used for arrays of values at vertices, elements, faces,...
static void creer_tableau_distribue(const MD_Vector &, Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Transforms v into a parallel array having the structure md.
: This class is an OWN_PTR but the pointed object is shared among multiple
Definition MD_Vector.h:48
void copy(const MD_Vector_base &)
Constructs an MD_Vector object by copying an existing object.
Definition MD_Vector.cpp:26
const MD_Vector_base & valeur() const
Definition MD_Vector.h:77
A character string (Nom) in uppercase.
Definition Motcle.h:26
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
const Nom getPrefix(const char *const) const
Definition Nom.cpp:335
Nom nom_me(int, const char *prefix=0, int without_padding=0) const
Inserts _prefix000n (n=me() or nproc()) into a file name (e.g. toto.titi) to produce toto_prefix000n....
Definition Nom.cpp:380
const std::string & getString() const
Definition Nom.h:92
An array of character strings (VECT(Nom)).
Definition Noms.h:26
friend class Entree
Definition Objet_U.h:71
static int dimension
Definition Objet_U.h:94
friend class Sortie
Definition Objet_U.h:70
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
static double precision_geom
Definition Objet_U.h:81
Objet_U()
Default constructor: assigns a unique identifier to the object (object_id_) and registers the object ...
Definition Objet_U.cpp:54
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
static double mp_min(double)
Definition Process.cpp:391
static trustIdType mppartial_sum(trustIdType i)
Computes the partial sum of x over processors 0 to me()-1 (returns 0 on processor 0).
Definition Process.cpp:403
static double mp_max(double)
Definition Process.cpp:379
static bool mp_or(bool)
Definition Process.cpp:427
static Sortie & Journal(int message_level=0)
Returns a static Sortie object used as an event journal.
Definition Process.cpp:592
static int nproc()
Returns the number of processors in the current group. See Comm_Group::nproc() and PE_Groups::current...
Definition Process.cpp:102
static double mp_sum(double)
Computes the sum of x over all processors in the current group.
Definition Process.cpp:145
static void barrier()
Synchronizes all processors in the current group (waits until all processors have reached the barrier...
Definition Process.cpp:133
static int me()
Returns the rank of the local processor in the current communication group. See Comm_Group::rank() an...
Definition Process.cpp:122
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
static int je_suis_maitre()
Returns 1 if on the master processor of the current group (i.e. me() == 0), 0 otherwise.
Definition Process.cpp:82
static bool is_sequential()
Definition Process.cpp:113
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)
Reorders joint faces so that they appear in the same order on each pair of neighboring processors.
Definition Scatter.cpp:1675
static int Chercher_Correspondance(const DoubleTab &sommets1, const DoubleTab &sommets2, ArrOfInt &correspondance, const double epsilon)
Builds the "correspondance" array such that for 0 <= i < sommets2.
Definition Scatter.cpp:2366
static void ajouter_joints(Domaine &domaine, ArrOfInt &pe_voisins)
Adds joints with all PEs in 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:2739
static void construire_espace_virtuel_traduction(const MD_Vector &md_indice, const MD_Vector &md_valeur, IntTab &tableau, const int error_is_fatal=1)
Builds the items_communs + virtual space structure of an array containing indices of geometric items,...
Definition Scatter.cpp:1621
static void calculer_espace_distant_sommets(Domaine &dom)
Based on the remote space of elements, computes the remote space of vertices.
Definition Scatter.cpp:1155
Entree & interpreter(Entree &) override
Reads and completes a parallel domain according to the keywords read in the data set.
Definition Scatter.cpp:129
static void calculer_espace_distant_aretes(Domaine &domaine, const int nb_aretes_reelles, const IntTab &elem_aretes)
Same as Scatter::calculer_espace_distant_sommets for edges.
Definition Scatter.cpp:1199
static void calculer_espace_distant_elements(Domaine &dom)
Fills the "espace_distant()" array of elements in the joints.
Definition Scatter.cpp:2058
static void calculer_espace_distant(Domaine &domaine, const int nb_items_reels, const ArrsOfInt &items_to_send, const JOINT_ITEM type_item)
Determines the distant items from a list of items to send and lists of common items.
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:2482
static void construire_structures_paralleles(Domaine &dom)
Builds the parallel structures of the domain (determination of distant elements as a function of join...
Definition Scatter.cpp:673
static void calculer_nb_items_virtuels(Joints &joints, const JOINT_ITEM type_item)
For a geometric item "type_item", fills the nb_items_virtuels_ field of joints based on the number of...
Definition Scatter.cpp:2695
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:395
static void calculer_renum_items_communs(Joints &joints, const JOINT_ITEM type_item)
Assumes that each joint[i].joint_item(type_item).items_communs() contains the local indices of common...
Definition Scatter.cpp:1220
static void construire_correspondance_sommets_par_coordonnees(Domaine &dom, bool allow_resize=false)
Builds the joint_item(JOINT_ITEM::SOMMET).items_communs arrays for all joints of the domain dom.
Definition Scatter.cpp:2674
static void construire_md_vector(const Domaine &, int nb_items_reels, const JOINT_ITEM, MD_Vector &)
Builds an MD_Vector_std from the joint information of the domain for the requested item type.
Definition Scatter.cpp:1277
static void 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:271
static void corriger_espace_distant_elements_perio(Domaine &dom)
Current periodic algorithms (P1B assembler, OpDivElem P1B) require that for each virtual periodic fac...
Definition Scatter.cpp:1908
Domaine & domaine()
Returns the associated domain.
Definition Scatter.cpp:74
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)
Same as Scatter::calculer_espace_distant_sommets for faces.
Definition Scatter.cpp:1180
virtual void lire_domaine(Nom &fil)
Reads the domain from the file named "nomentree", of type LecFicDistribueBin or LecFicDistribue.
Definition Scatter.cpp:469
static void uninit_sequential_domain(Domaine_32_64< _SIZE_ > &dom)
Method used by interpreters that modify the domain (sequential), destroys the descriptors of vertices...
Definition Scatter.cpp:2754
static void construire_correspondance_aretes_par_coordonnees(Domaine_VF &zvf)
Builds the joint_item(JOINT_ITEM::ARETE).items_communs arrays for all joints of the domain.
Definition Scatter.cpp:2683
void echange_taille_et_messages() const
Launches the data exchange between all processors.
Sortie & send_buffer(int num_PE) const
Returns the buffer corresponding to processor num_PE to stack data to send.
void end_comm() const
Clears the buffers and releases resources: reading of received data from buffers is complete.
Entree & recv_buffer(int num_PE) const
Returns the buffer corresponding to processor num_PE to read received data.
void begin_comm() const
Reserves communication buffers for a new communication.
void set_send_recv_pe_list(const ArrOfInt &send_pe_list, const ArrOfInt &recv_pe_list, const int me_to_me=0)
Defines the list of processors to send data to and receive data from.
Base class for output streams.
Definition Sortie.h:52
void set_value(int_t i_liste, int_t i_element, int_t valeur)
Assigns "valeur" to the j-th element of the i-th list with 0 <= i < get_nb_lists() and 0 <= j < get_l...
int_t get_list_size(int_t i_liste) const
Returns the number of elements in list i.
void set_list_sizes(const ArrOfInt_t &sizes)
Destroys existing lists and creates new ones.
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
This class provides tools to build the virtual space of an array containing indices of geometric enti...
Definition Scatter.cpp:1388
int chercher_table_inverse(const trustIdType sommet_global) const
Searches for i such that table_inverse(i, 0) == sommet_global, and returns table_inverse(i,...
Definition Scatter.cpp:1471
int traduire_espace_virtuel(IntTab &tableau) const
Starting from an array whose virtual space structure is initialized (remote and virtual element descr...
Definition Scatter.cpp:1576
void traduire_indice_local_vers_global(const ArrOfInt &indices_locaux, ArrOfTID &indices_globaux, int n) const
Transforms local indices into global indices using "table_" (see initialiser).
Definition Scatter.cpp:1513
int traduire_indice_global_vers_local(const ArrOfTID &indices_globaux, ArrOfInt &indices_locaux) const
For debut <= i < debut+nb, indices_locaux[i] = look up the local index of "indices_globaux[i]".
Definition Scatter.cpp:1529
void initialiser(const MD_Vector &md_items)
Initializes the dictionary. Precondition:
Definition Scatter.cpp:1419