TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
IJK_Interfaces.cpp
1/****************************************************************************
2* Copyright (c) 2015 - 2016, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <Connex_components.h>
17#include <IJK_Field_vector.h>
18#include <Connex_components_FT.h>
19#include <EcrFicPartageBin.h>
20#include <Probleme_FTD_IJK_base.h>
21#include <Probleme_FTD_IJK_cut_cell.h>
22#include <Cut_cell_tools.h>
23#include <IJK_Interfaces.h>
24#include <IJK_Lata_writer.h>
25#include <IJK_Navier_Stokes_tools.h>
26#include <Cut_cell_tools.h>
27#include <LataDB.h>
28#include <LecFicDiffuse_JDD.h>
29#include <Linear_algebra_tools.h>
30#include <Octree_Double.h>
31#include <Ouvrir_fichier.h>
32#include <Param.h>
33#include <SFichier.h>
34#include <Domaine_VF.h>
35#include <algorithm>
36#include <communications.h>
37#include <iostream>
38#include <memory>
39#include <Perf_counters.h>
40#include <Cut_field.h>
41#include <Transport_Interfaces_FT_Disc.h>
42#include <Navier_Stokes_FTD_IJK.h>
43#include <vector>
44#include <map>
45
46// #define GB_VERBOSE
47
48// permet de preciser la methode utilisee pour mettre a jour l'indicatrice
49// 0: methode classique avec recherche des composantes connexes
50// 1: methode optimisee
51#define CLASSIC_METHOD 1
52#define BORD -10000
53
54Implemente_instanciable_sans_constructeur(IJK_Interfaces, "IJK_Interfaces", Equation_base);
55
56IJK_Interfaces::IJK_Interfaces()
57{
58 positions_reference_.resize(0); // Par defaut, a dimensionner ensuite
59 mean_force_.resize(0); // Par defaut, a dimensionner ensuite
60 compo_to_group_.resize(0); // Par defaut, a dimensionner ensuite par nb_bulles
61}
62
63static void FixedVector_to_DoubleTab(const FixedVector<ArrOfDouble,3> fixed_arr, DoubleTab& tab)
64{
65 int size_fixed_arr[3] = {0,0,0};
66 for (int c=0; c<3; c++)
67 size_fixed_arr[c] = fixed_arr[c].size_array();
68 assert(size_fixed_arr[0] == size_fixed_arr[1]);
69 assert(size_fixed_arr[0] == size_fixed_arr[2]);
70 tab.reset();
71 tab.resize(size_fixed_arr[0],3);
72 for (int c=0; c<3; c++)
73 for (int l=0; l<size_fixed_arr[0]; l++)
74 tab(l,c) = fixed_arr[c](l);
75}
76
78{
79 param.ajouter("interfaces", &(probleme_ijk().get_interface())); // on lit dans l'eq les params reprise
80}
81
82/*! Output the FT mesh information in the master LATA file.
83 *
84 * ASSUMPTION: for now the FT mesh always fits within 32b (in terms of nb of elems / vertices). This is checked.
85 *
86 * Ajoute ceci dans le fichier lata maitre:
87 * GEOM meshname type_elem=TRIANGLE_3D
88 * CHAMP SOMMETS filename.step.meshname.SOMMETS geometry=meshname size=... composantes=3
89 * CHAMP ELEMENTS filename.step.meshname.ELEMENTS geometry=meshname size=... composantes=3 format=INT32|64
90 */
91void IJK_Interfaces::dumplata_ft_mesh(const char *filename, const char *meshname, int step) const
92{
94 Nom prefix = Nom(filename) + Nom(".") + Nom(step) + Nom(".") + Nom(meshname) + Nom(".");
95 Nom fdsom = prefix + Nom("SOMMETS");
96 Nom fdelem = prefix + Nom("ELEMENTS");
97 Nom fdpelocal = prefix + Nom("FACETTE_PE_LOCAL");
98 Nom fdpeowner = prefix + Nom("FACETTE_PE_OWNER");
99 Nom fd_sommet_reel = prefix + Nom("INDEX_SOMMET_REEL");
100
101 const int nb_som = mesh.nb_sommets();
102 const int nb_elem = mesh.nb_facettes();
103 // Reduce 2 mp_sum calls to 1 by using mp_sum_for_each
104 int nsomtot = nb_som;
105 int nelemtot = nb_elem;
106 Process::mp_sum_for_each(nsomtot, nelemtot);
107 nsomtot = Process::check_int_overflow(nsomtot);
108 nelemtot = Process::check_int_overflow(nelemtot);
109 // valeur a ajouter a un indice local de sommet pour obtenir un indice global
110 // de sommet
111 const int offset_sommet = Process::check_int_overflow(Process::mppartial_sum(nb_som));
112 FloatTab tmp(nb_som, 3);
113 const DoubleTab& sommets = mesh.sommets();
114
115 for (int i = 0; i < nb_som; i++)
116 for (int j = 0; j < 3; j++)
117 tmp(i, j) = (float)sommets(i, j);
118 EcrFicPartageBin file;
119
120 // See top doc above, we do everything in 32b
121 file.set_64b(false);
122
123 file.ouvrir(fdsom);
124 file.put(tmp.addr(), tmp.size_array(), 3);
125 file.syncfile();
126 file.close();
127
128 // Tableau des facettes locales ecrites dans le fichier: contient les indices
129 // globaux des sommets
130 // (ajout de offset_sommet a l'indice du sommet local)
131 IntTab tmp_facettes_renum(nb_elem, 3);
132 const IntTab& facettes = mesh.facettes();
133 for (int i = 0; i < nb_elem; i++)
134 for (int j = 0; j < 3; j++)
135 tmp_facettes_renum(i, j) = facettes(i, j) + offset_sommet;
136 file.ouvrir(fdelem);
137 file.put(tmp_facettes_renum.addr(), tmp_facettes_renum.size_array(), 3);
138 file.syncfile();
139 file.close();
140
141 // Postraitement du numero du processeur local
142 file.ouvrir(fdpelocal);
143 ArrOfInt tmp2(nb_elem);
144 tmp2 = Process::me();
145 file.put(tmp2.addr(), nb_elem, 1);
146 file.syncfile();
147 file.close();
148
149 // Postraitement du numero du processeur proprietaire
150 file.ouvrir(fdpeowner);
151 mesh.facette_PE_owner(tmp2);
152 file.put(tmp2.addr(), nb_elem, 1);
153 file.syncfile();
154 file.close();
155
156 // Postraitement de l'indice global du sommet reel associe a chaque sommet
157 // postraite
158 {
159 ArrOfInt indice_global(nb_som);
160 const int np = Process::nproc();
161 // Pour chaque processeur, quel est l'offset des sommets de ce processeur:
162 ArrOfInt offset_received(np);
163 ArrOfInt offset_to_send(np);
164 // On va faire un echange: chaque proc envoye a tous les processeurs sont
165 // offset Je remplis le tableau avec ma valeur:
166 offset_to_send = offset_sommet;
167 // Je l'envoie a tout le monde:
168 envoyer_all_to_all(offset_to_send, offset_received);
169 // Maintenant offset_received[i] contient la valeur offset_sommet du
170 // processeur i
171 const ArrOfInt& sommet_num_owner = mesh.sommet_num_owner();
172 const ArrOfInt& sommet_PE_owner = mesh.sommet_PE_owner();
173 // Calcul de l'indice global du sommet reel correspondant a chaque sommet
174 // local:
175 for (int i = 0; i < nb_som; i++)
176 {
177 const int indice_local_sur_proc_proprietaire = sommet_num_owner[i];
178 const int proc_proprietaire = sommet_PE_owner[i];
179 const int offset_proc_proprietaire = offset_received[proc_proprietaire];
180 indice_global[i] = indice_local_sur_proc_proprietaire + offset_proc_proprietaire;
181 }
182 file.ouvrir(fd_sommet_reel);
183 file.put(indice_global.addr(), indice_global.size_array(), 1);
184 file.syncfile();
185 file.close();
186 }
187
188 const Nom format = "INT32";
190 {
191 SFichier master_file;
192 master_file.ouvrir(filename, ios::app);
193 master_file << "Geom " << meshname << " type_elem=TRIANGLE_3D" << finl;
194
195 master_file << "Champ SOMMETS " << basename(fdsom) << " geometrie=" << meshname;
196 master_file << " size=" << nsomtot << " composantes=3" << finl;
197
198 master_file << "Champ ELEMENTS " << basename(fdelem) << " geometrie=" << meshname;
199 master_file << " size=" << nelemtot << " composantes=3 format=" << format << finl;
200
201 master_file << "Champ FACETTE_PE_LOCAL " << basename(fdpelocal) << " geometrie=" << meshname;
202 master_file << " size=" << nelemtot << " composantes=1 format=" << format << " localisation=ELEM" << finl;
203
204 master_file << "Champ FACETTE_PE_OWNER " << basename(fdpeowner) << " geometrie=" << meshname;
205 master_file << " size=" << nelemtot << " composantes=1 format=" << format << " localisation=ELEM" << finl;
206
207 master_file << "Champ INDEX_SOMMET_REEL " << basename(fd_sommet_reel) << " geometrie=" << meshname;
208 master_file << " size=" << nsomtot << " composantes=1 format=" << format << " localisation=SOM" << finl;
209 }
210}
211
212// Copie de la methode precedente mais pour les DoubleTab aux sommets :
213void runge_kutta3_update(const DoubleTab& dvi, DoubleTab& G, DoubleTab& l, const int step, const double dt_tot,
214 const Maillage_FT_IJK& maillage)
215{
216 const double coeff_a[3] = {0., -5. / 9., -153. / 128.};
217 // Gk[0] = 1; Gk[i+1] = Gk[i] * a[i+1] + 1
218 const double coeff_Gk[3] = {1., 4. / 9., 15. / 32.};
219
220 const double facteurG = coeff_a[step];
221 const double intermediate_dt = compute_fractionnal_timestep_rk3(dt_tot, step);
222 const double delta_t_divided_by_Gk = intermediate_dt / coeff_Gk[step];
223 const int nbsom = maillage.nb_sommets();
224
225 // Resize du tableau
226 G.resize(nbsom, 3);
227
228 switch (step)
229 {
230 case 0:
231 // don't read initial value of G (no performance benefit because write to G
232 // causes the processor to fetch the cache line, but we don't wand to use a
233 // potentially uninitialized value
234 for (int isom = 0; isom < nbsom; isom++)
235 {
236 for (int dir = 0; dir < 3; dir++)
237 {
238 if (maillage.sommet_virtuel(isom))
239 {
240 G(isom, dir) = 111. / intermediate_dt;
241 l(isom, dir) = 111. / intermediate_dt;
242 }
243 double x = dvi(isom, dir);
244 G(isom, dir) = x;
245 l(isom, dir) += x * delta_t_divided_by_Gk;
246 }
247 }
248 break;
249 case 1:
250 // general case, read and write G
251 for (int isom = 0; isom < nbsom; isom++)
252 {
253 for (int dir = 0; dir < 3; dir++)
254 {
255 if (maillage.sommet_virtuel(isom))
256 {
257 G(isom, dir) = 111. / intermediate_dt;
258 l(isom, dir) = 111. / intermediate_dt;
259 }
260 double x = G(isom, dir) * facteurG + dvi(isom, dir);
261 G(isom, dir) = x;
262 l(isom, dir) += x * delta_t_divided_by_Gk;
263 }
264 }
265 break;
266 case 2:
267 // do not write G
268 for (int isom = 0; isom < nbsom; isom++)
269 {
270 for (int dir = 0; dir < 3; dir++)
271 {
272 if (maillage.sommet_virtuel(isom))
273 {
274 G(isom, dir) = 111. / intermediate_dt;
275 l(isom, dir) = 111. / intermediate_dt;
276 }
277 double x = G(isom, dir) * facteurG + dvi(isom, dir);
278 l(isom, dir) += x * delta_t_divided_by_Gk;
279 }
280 }
281 break;
282 default:
283 Cerr << "Error in runge_kutta_update: wrong step" << finl;
285 };
286}
287
289{
290 os << "{\n"
291 << " fichier_reprise_interface " << basename(fichier_sauvegarde_interface_) << "\n"
292 << " timestep_reprise_interface " << timestep_sauvegarde_interface_
293 << "\n"
294 // << " lata_meshname " << nom_par_defaut_interfaces << "\n"
295 << " remaillage_ft_ijk " << remaillage_ft_ijk_;
297 os << " terme_gravite rho_g \n";
298 else
299 os << " terme_gravite grad_i \n";
300
302 os << " correction_gradient_potentiel \n";
303 if (delta_p_max_repulsion_ > 0.)
304 {
305 os << " portee_force_repulsion " << portee_force_repulsion_ << "\n"
306 << " delta_p_max_repulsion " << delta_p_max_repulsion_ << "\n";
307 }
309 {
310 os << " portee_wall_repulsion " << portee_wall_repulsion_ << "\n"
311 << " delta_p_wall_max_repulsion " << delta_p_wall_max_repulsion_ << "\n";
312 }
314 os << " active_repulsion_paroi \n";
315 if (frozen_)
316 os << " frozen \n" ;
317 if (follow_colors_)
318 {
319 // Sauvegarde des couleurs des bulles (on imprime le tableau) :
320 Cerr << "IJK_Interfaces::printOn -- couleurs des bulles stockees " << finl;
321 os << " follow_colors " << "\n"
322 << " reprise_colors " << through_yminus_ ;
323 }
324 if (compo_to_group_.size_array()>0)
325 {
326 Cerr << "IJK_Interfaces::printOn -- Groupes d'appartenance stockes " << finl;
327 os << " bubble_groups " << compo_to_group_;
328 }
330 os << " positions_reference " << positions_reference_;
331
332 if (parcours_.get_correction_parcours_thomas())
333 os << " parcours_interface { correction_parcours_thomas } " << "\n";
334 if (parcours_.get_parcours_sans_tolerance())
335 os << " parcours_interface { parcours_sans_tolerance } " << "\n";
336
338 os << "use_barycentres_velocity" << "\n";
340 os << "use_barycentres_velocity" << "\n";
341
342 double max_force_compo = 0.;
343 if (mean_force_.size_array() > 0)
344 max_force_compo = max_abs_array(mean_force_);
345 if (max_force_compo > 1.e-16)
346 {
347 // On a quelque part une force
348 Cerr << "IJK_Interfaces::printOn -- Storing mean into sauv for future "
349 "restart. (max_force_compo= "
350 << max_force_compo << " )." << finl;
351 os << " mean_force " << mean_force_;
352 }
353 os << " }\n";
354
355 return os;
356}
357// XD interfaces interprete nul BRACE not_set
359{
360 Param param(que_suis_je());
361 lata_interfaces_meshname_ = "INTERFACES"; // This line is necessary for reprendre_probleme in Probleme_FTD_IJK_base
362
363 param.ajouter("bubble_groups", &compo_to_group_);
364 param.ajouter("fichier_reprise_interface", &fichier_reprise_interface_, Param::REQUIRED); // XD_ADD_P chaine
365 // XD_CONT not_set
366 param.ajouter("timestep_reprise_interface", &timestep_reprise_interface_); // XD_ADD_P entier
367 // XD_CONT not_set
368 param.ajouter("lata_meshname", &lata_interfaces_meshname_); // XD_ADD_P chaine
369 // XD_CONT not_set
370 param.ajouter("remaillage_ft_ijk", &remaillage_ft_ijk_); // XD_ADD_P remaillage_ft_ijk
371 // XD_CONT not_set
372 param.ajouter_flag("use_tryggvason_interfacial_source", &use_tryggvason_interfacial_source_); // XD_ADD_P remaillage_ft_ijk
373 // XD_CONT not_set
374 param.ajouter("portee_force_repulsion", &portee_force_repulsion_);
375 param.ajouter("delta_p_max_repulsion", &delta_p_max_repulsion_);
376 param.ajouter("portee_wall_repulsion", &portee_wall_repulsion_);
377 param.ajouter("delta_p_wall_max_repulsion", &delta_p_wall_max_repulsion_);
378 param.ajouter_flag("active_repulsion_paroi", &active_repulsion_paroi_);
379 param.ajouter("no_octree_method", &no_octree_method_); // XD_ADD_P entier
380 // XD_CONT if the bubbles repel each other, what method should be used to compute relative velocities? Octree method
381 // XD_CONT by default, otherwise we used the IJK discretization
382 param.ajouter_flag("follow_colors", &follow_colors_);
384 {
385 param.ajouter_flag("compute_distance_autres_interfaces", &compute_distance_autres_interfaces_); // XD_ADD_P rien
386 // XD_CONT not_set
387 }
388 param.ajouter("reprise_colors", &through_yminus_);
389 param.ajouter_flag("correction_gradient_potentiel", &correction_gradient_potentiel_);
390 param.ajouter_flag("avoid_duplicata", &avoid_duplicata_);
391 param.ajouter("factor_length_duplicata", &factor_length_duplicata_);
392 param.ajouter("ncells_forbidden", &ncells_forbidden_);
393 param.ajouter("ncells_deleted", &ncells_deleted_);
394 param.ajouter_flag("frozen", &frozen_);
395 param.ajouter("positions_reference", &positions_reference_);
396 param.ajouter("mean_force", &mean_force_);
397 param.ajouter("parcours_interface",&parcours_);
398 param.ajouter("dt_impression_bilan_indicatrice", &dt_impression_bilan_indicatrice_);
399 param.ajouter("verbosite_surface_efficace_face", &verbosite_surface_efficace_face_);
400 param.ajouter("verbosite_surface_efficace_interface", &verbosite_surface_efficace_interface_);
401 param.ajouter("seuil_indicatrice_negligeable", &seuil_indicatrice_negligeable_);
402
403 param.ajouter_flag("use_barycentres_velocity", &use_barycentres_velocity_);
404 param.ajouter_flag("read_barycentres_velocity", &read_barycentres_velocity_);
405 param.ajouter("maillage_ft_ijk", &maillage_ft_ijk_);
406
407
408 // param.ajouter_non_std("terme_gravite",(this));
409 param.ajouter("terme_gravite", &terme_gravite_); // XD_ADD_P chaine(into=["rho_g","grad_i"])
410 // XD_CONT not_set
411 param.dictionnaire("rho_g", GRAVITE_RHO_G);
412 param.dictionnaire("grad_i", GRAVITE_GRAD_I);
413
414 param.lire_avec_accolades(is);
415
416 Cout << "IJK_Interfaces::readOn : Option gravite : " << terme_gravite_
417 << " { " << (int)GRAVITE_RHO_G << " : GRAVITE_RHO_G, "
418 << (int)GRAVITE_GRAD_I << " : GRAVITE_GRAD_I} "
419 << finl;
420
421 // Cout << "IJK_Interfaces::readOn : Les options lues sont : " << finl;
422 // param.print(Cout);
423
424 if (compo_to_group_.size_array() != 0)
425 {
426 nb_groups_ = max_array(compo_to_group_) + 1;
427 }
428 Cout << "IJK_Interfaces::readOn : il y a : " << nb_groups_
429 << " classes/groupes de bulles suivis " << finl;
430
431 if (positions_reference_.size_array() != 0)
432 {
434 Cout << "IJK_Interfaces::readOn : " << positions_reference_.dimension(0)
435 << " bulles reelles reprises avec une position de reference. " << finl;
436 }
437 if (mean_force_.size_array() != 0)
438 {
439 Cout << "IJK_Interfaces::readOn : " << mean_force_.dimension(0)
440 << " bulles reelles reprises avec une force_moyenne imposee. " << finl;
441 }
442 return is;
443}
444
446{
447 if (un_mot=="parcours_interface")
448 {
449 is >> parcours_;
450 return 1;
451 }
452 else
453 {
454 Cerr << "Unknown Keyword " << un_mot << " in IJK_Interfaces::lire_motcle_non_standard" << finl;
456 }
457 return 1;
458}
459
461{
463 indicatrice_surfacique_efficace_face_.associer_ephemere(*ref_ijk_ft_->get_cut_cell_disc());
464 indicatrice_surfacique_efficace_face_initial_.associer_ephemere(*ref_ijk_ft_->get_cut_cell_disc());
465 indicatrice_surfacique_efficace_face_correction_.associer_ephemere(*ref_ijk_ft_->get_cut_cell_disc());
466 indicatrice_surfacique_efficace_face_absolute_error_.associer_ephemere(*ref_ijk_ft_->get_cut_cell_disc());
467 surface_efficace_interface_.associer_ephemere(*ref_ijk_ft_->get_cut_cell_disc());
468 surface_efficace_interface_initial_.associer_ephemere(*ref_ijk_ft_->get_cut_cell_disc());
469 coord_deplacement_interface_.associer_ephemere(*ref_ijk_ft_->get_cut_cell_disc());
470 vitesse_deplacement_interface_.associer_ephemere(*ref_ijk_ft_->get_cut_cell_disc());
471 normale_deplacement_interface_.associer_ephemere(*ref_ijk_ft_->get_cut_cell_disc());
472
473 if (!parcours_.get_correction_parcours_thomas())
474 {
475 Cerr << "Warning: The cut-cell method overrides default or user parameters to force the use of correction_parcours_thomas in parcours_interface." << finl;
476 parcours_.set_correction_parcours_thomas();
477 }
478
479 if (!parcours_.get_parcours_sans_tolerance())
480 {
481 Cerr << "Warning: The cut-cell method overrides default or user parameters to force the use of parcours_sans_tolerance in parcours_interface." << finl;
482 parcours_.set_parcours_sans_tolerance();
483 }
484}
485
487{
488 int count_total = 0;
489 int count_40pct = 0;
490 int count_30pct = 0;
491 int count_20pct = 0;
492 int count_10pct = 0;
493 int count_5pct = 0;
494 int count_1pct = 0;
495 int count_0pct = 0;
496 int count_pure = 0;
497
498 double min_indicatrice = 1.;
499
500 const Cut_cell_FT_Disc& cut_cell_disc = surface_efficace_interface_.get_cut_cell_disc();
501 for (int n = 0; n < cut_cell_disc.get_n_loc(); n++)
502 {
503 Int3 ijk = cut_cell_disc.get_ijk(n);
504 int i = ijk[0];
505 int j = ijk[1];
506 int k = ijk[2];
507
508 count_total += 1;
509
510 double indicatrice = std::min(indicatrice_ns_[next()](i,j,k), 1 - indicatrice_ns_[next()](i,j,k));
511 if (indicatrice > 0.)
512 min_indicatrice = std::min(min_indicatrice, indicatrice);
513
514 if (indicatrice <= .5 && indicatrice > .4)
515 count_40pct += 1;
516 else if (indicatrice <= .4 && indicatrice > .3)
517 count_30pct += 1;
518 else if (indicatrice <= .3 && indicatrice > .2)
519 count_20pct += 1;
520 else if (indicatrice <= .2 && indicatrice > .1)
521 count_10pct += 1;
522 else if (indicatrice <= .1 && indicatrice > .05)
523 count_5pct += 1;
524 else if (indicatrice <= .05 && indicatrice > .01)
525 count_1pct += 1;
526 else if (indicatrice <= .01 && indicatrice > .0)
527 count_0pct += 1;
528 else
529 {
530 assert(indicatrice == 0.);
531 count_pure += 1;
532 }
533 }
534 // Reduce 9 mp_sum calls to 2 by using mp_sum_for_each twice
535 mp_sum_for_each(count_total, count_40pct, count_30pct, count_20pct, count_10pct);
536 mp_sum_for_each(count_5pct, count_1pct, count_0pct, count_pure);
537 count_total = Process::check_int_overflow(count_total);
538 count_40pct = Process::check_int_overflow(count_40pct);
539 count_30pct = Process::check_int_overflow(count_30pct);
540 count_20pct = Process::check_int_overflow(count_20pct);
541 count_10pct = Process::check_int_overflow(count_10pct);
542 count_5pct = Process::check_int_overflow(count_5pct);
543 count_1pct = Process::check_int_overflow(count_1pct);
544 count_0pct = Process::check_int_overflow(count_0pct);
545 count_pure = Process::check_int_overflow(count_pure);
546
547 min_indicatrice = Process::mp_min(min_indicatrice);
548
549 Cerr << "Bilan de l'indicatrice:" << finl;
550 Cerr << " Valeur minimale: " << min_indicatrice << finl;
551 Cerr << " Compte sur les cellules de la structure diphasique:" << finl;
552 Cerr << " 40-50% " << count_40pct << finl;
553 Cerr << " 30-40% " << count_30pct << finl;
554 Cerr << " 20-30% " << count_20pct << finl;
555 Cerr << " 10-20% " << count_10pct << finl;
556 Cerr << " 5-10% " << count_5pct << finl;
557 Cerr << " 1-5% " << count_1pct << finl;
558 Cerr << " 0-1% " << count_0pct << finl;
559 Cerr << " pure " << count_pure << finl;
560 Cerr << " ------ " << finl;
561 Cerr << " total " << count_total << finl;
562}
563
564void IJK_Interfaces::calcul_surface_efficace_face(TYPE_SURFACE_EFFICACE_FACE type_surface_efficace_face, double timestep, const Cut_field_vector3_double& total_velocity)
565{
566 // Attention : suppose que indicatrice_surfacique_efficace_face_/initial_ est correctement initialisee.
567 // (Appel prealable a calcul_surface_efficace_face_initial())
568
569 int iteration_solver_surface_efficace_face = 0;
570
571 if (type_surface_efficace_face == TYPE_SURFACE_EFFICACE_FACE::CONSERVATION_VOLUME_ITERATIF)
572 {
573 // Raffinement de l'estimation initiale la surface efficace des faces
576 timestep,
577 total_velocity,
578 iteration_solver_surface_efficace_face,
587 }
590 iteration_solver_surface_efficace_face,
591 timestep,
592 total_velocity,
597}
598
599void IJK_Interfaces::calcul_surface_efficace_interface(TYPE_SURFACE_EFFICACE_INTERFACE type_surface_efficace_interface, double timestep, const Cut_field_vector3_double& velocity)
600{
601 // Attention : suppose que indicatrice_surfacique_efficace_interface_/initial_ est correctement initialisee.
602 // (Appel prealable a calcul_surface_efficace_interface_initial())
603
605 (type_surface_efficace_interface == TYPE_SURFACE_EFFICACE_INTERFACE::EXPLICITE),
615
617 velocity,
624
625 if (type_surface_efficace_interface == TYPE_SURFACE_EFFICACE_INTERFACE::CONSERVATION_VOLUME)
626 {
627 // Raffinement de l'estimation initiale la surface efficace de l'interface
629 timestep,
630 velocity,
636 }
639 timestep,
640 velocity,
647}
648
649void IJK_Interfaces::calcul_surface_efficace_face_initial(TYPE_SURFACE_EFFICACE_FACE type_surface_efficace_face)
650{
652 (type_surface_efficace_face == TYPE_SURFACE_EFFICACE_FACE::EXPLICITE),
657}
658
659void IJK_Interfaces::calcul_surface_efficace_interface_initial(TYPE_SURFACE_EFFICACE_INTERFACE type_surface_efficace_interface)
660{
662 (type_surface_efficace_interface == TYPE_SURFACE_EFFICACE_INTERFACE::EXPLICITE),
672}
673
675{
676 const IJK_Field_vector3_double& velocity_ft = ref_ijk_ft_->eq_ns().get_velocity_ft();
678 const DoubleTab& sommets = mesh.sommets(); // Tableau des coordonnees des marqueurs.
679 int nbsom = sommets.dimension(0);
680 ArrOfDouble vinterp_component(nbsom);
681 vinterp_.resize(nbsom, 3);
682 for (int direction = 0; direction < 3; direction++)
683 {
684 // Interpolate the "field" at the requested "coordinates" (array with 3
685 // columns), and stores into "result" void ijk_interpolate(const
686 // IJK_Field_double & field, const DoubleTab &coordinates, ArrOfDouble &
687 // result)
688 ijk_interpolate_skip_unknown_points(velocity_ft[direction], sommets, vinterp_component,
689 1.e5 /* value for unknown points */);
690 for (int i = 0; i < nbsom; i++)
691 vinterp_(i, direction) = vinterp_component[i];
692 }
693}
694
696{
697 return ref_cast(Probleme_FTD_IJK_base, mon_probleme.valeur());
698}
699
701{
702 return ref_cast(Probleme_FTD_IJK_base, mon_probleme.valeur());
703}
704
705const IJK_Field_double& IJK_Interfaces::get_IJK_field(const Motcle& nom)
706{
707 if (nom=="COURBURE")
708 {
709 // TODO ABN may use ref_array to avoid copy ??
710 IJK_Field_double& courb = scalar_post_fields_.at("COURBURE");
711 courb.data() = maillage_ft_ijk_.get_update_courbure_sommets();
712 }
713 if (nom=="CONCENTRATION_INTERFACE")
714 {
715 IJK_Field_double& conc_interf = scalar_post_fields_.at("CONCENTRATION_INTERFACE");
716 conc_interf.data() = maillage_ft_ijk_.Surfactant_facettes().get_FT_field_Array();
717 }
718 if (nom=="GRADX_CONCENTRATION_INTERFACE")
719 {
720 IJK_Field_double& dconc_interf_x = scalar_post_fields_.at("GRADX_CONCENTRATION_INTERFACE");
721 dconc_interf_x.data() = maillage_ft_ijk_.Surfactant_facettes().get_Grad_FT_field_Array(0);
722 }
723 if (nom=="GRADY_CONCENTRATION_INTERFACE")
724 {
725 IJK_Field_double& dconc_interf_y = scalar_post_fields_.at("GRADY_CONCENTRATION_INTERFACE");
726 dconc_interf_y.data() = maillage_ft_ijk_.Surfactant_facettes().get_Grad_FT_field_Array(1);
727 }
728 if (nom=="GRADZ_CONCENTRATION_INTERFACE")
729 {
730 IJK_Field_double& dconc_interf_z = scalar_post_fields_.at("GRADZ_CONCENTRATION_INTERFACE");
731 dconc_interf_z.data() = maillage_ft_ijk_.Surfactant_facettes().get_Grad_FT_field_Array(2);
732 }
733 if (nom=="LAPLACIAN_CONCENTRATION_INTERFACE")
734 {
735 IJK_Field_double& lapla_interf = scalar_post_fields_.at("LAPLACIAN_CONCENTRATION_INTERFACE");
736 lapla_interf.data() = maillage_ft_ijk_.Surfactant_facettes().get_Laplacian_FT_field_Array();
737 }
738 if (nom=="SIGMA")
739 {
740 IJK_Field_double& sigma = scalar_post_fields_.at("SIGMA");
741 sigma.data() = maillage_ft_ijk_.Surfactant_facettes().get_sigma_sommets();
742 }
743 if (nom=="GRADX_SIGMA")
744 {
745 IJK_Field_double& dsigma_x = scalar_post_fields_.at("GRADX_SIGMA");
746 dsigma_x.data() = maillage_ft_ijk_.Surfactant_facettes().get_interfacial_source_term_sommets(0);
747 }
748 if (nom=="GRADY_SIGMA")
749 {
750 IJK_Field_double& dsigma_y = scalar_post_fields_.at("GRADY_SIGMA");
751 dsigma_y.data() = maillage_ft_ijk_.Surfactant_facettes().get_interfacial_source_term_sommets(1);
752 }
753 if (nom=="GRADZ_SIGMA")
754 {
755 IJK_Field_double& dsigma_z = scalar_post_fields_.at("GRADZ_SIGMA");
756 dsigma_z.data() = maillage_ft_ijk_.Surfactant_facettes().get_interfacial_source_term_sommets(2);
757 }
758 if (nom=="DISTANCE_AUTRES_INTERFACES")
759 {
760 DoubleTab vr_to_closer; // The velocity of the closest neighbour
761 IJK_Field_double& d = scalar_post_fields_.at("DISTANCE_AUTRES_INTERFACES");
763 }
764
765 if(has_champ(nom))
766 return champs_compris_.get_champ(nom);
767
768 Cerr << "ERROR in IJK_Interfaces::get_IJK_field_vector : " << finl;
769 Cerr << "Requested field '" << nom << "' is not recognized by IJK_Interfaces::get_IJK_field_vector()." << finl;
770 throw;
771}
772
773const IJK_Field_vector3_double& IJK_Interfaces::get_IJK_field_vector(const Motcle& nom)
774{
775 if(has_champ_vectoriel(nom))
776 return champs_compris_.get_champ_vectoriel(nom);
777
778 Cerr << "ERROR in IJK_Interfaces::get_IJK_field_vector : " << finl;
779 Cerr << "Requested field '" << nom << "' is not recognized by IJK_Interfaces::get_IJK_field_vector()." << finl;
780 throw;
781}
782
783void IJK_Interfaces::Fill_postprocessable_fields(std::vector<FieldInfo_t>& chps)
784{
785 std::vector<FieldInfo_t> c =
786 {
787 // Name / Localisation (elem, face, ...) / Nature (scalare, vector) / Located on interface?
788 { "INDICATRICE", Entity::ELEMENT, Nature_du_champ::scalaire, false },
789 { "INDICATRICE_FT", Entity::ELEMENT, Nature_du_champ::scalaire, false },
790 { "OLD_INDICATRICE", Entity::ELEMENT, Nature_du_champ::scalaire, false },
791 { "OLD_INDICATRICE_FT", Entity::ELEMENT, Nature_du_champ::scalaire, false },
792 { "REPULSION_FT", Entity::ELEMENT, Nature_du_champ::scalaire, false },
793 { "CUT_FIELDS_BARY_L", Entity::ELEMENT, Nature_du_champ::vectoriel, false },
794
795 { "COURBURE", Entity::NODE, Nature_du_champ::scalaire, true },
796 { "CONCENTRATION_INTERFACE", Entity::ELEMENT, Nature_du_champ::scalaire, true },
797 { "GRADX_CONCENTRATION_INTERFACE", Entity::NODE, Nature_du_champ::scalaire, true },
798 { "GRADY_CONCENTRATION_INTERFACE", Entity::NODE, Nature_du_champ::scalaire, true },
799 { "GRADZ_CONCENTRATION_INTERFACE", Entity::NODE, Nature_du_champ::scalaire, true },
800 { "SIGMA", Entity::NODE, Nature_du_champ::scalaire, true },
801 { "GRADX_SIGMA", Entity::NODE, Nature_du_champ::scalaire, true },
802 { "GRADY_SIGMA", Entity::NODE, Nature_du_champ::scalaire, true },
803 { "GRADZ_SIGMA", Entity::NODE, Nature_du_champ::scalaire, true },
804 { "LAPLACIAN_CONCENTRATION_INTERFACE", Entity::ELEMENT, Nature_du_champ::scalaire, true },
805 { "DISTANCE_AUTRES_INTERFACES", Entity::NODE, Nature_du_champ::scalaire, true }
806 };
807
808 chps.insert(chps.end(), c.begin(), c.end());
809}
810
812{
813 for (const auto& n : champs_compris_.liste_noms_compris())
814 noms.add(n);
815 for (const auto& n : champs_compris_.liste_noms_compris_vectoriel())
816 noms.add(n);
817}
818
820{
821 Cerr << "Reset bubble rising velocity calculations" << finl;
823 Cerr << "Compute compo_connex from bounding box" << finl;
825 Cerr << "Compute compo_connex from interface compo in mixed cells" << finl;
827 Cerr << "Compute rising velocity from compo connex (barycentre calc)" << finl;
829}
830
832 const Domaine_IJK& domaine_NS,
834 const int thermal_probes_ghost_cells,
835 const bool compute_vint,
836 const bool is_switch)
837{
838 Cerr << "Entree dans IJK_Interfaces::initialize" << finl;
839 set_recompute_indicator(CLASSIC_METHOD);
840
841 ref_domaine_ = domaine_FT;
842
843 surface_vapeur_par_face_computation_.initialize(domaine_FT);
845
846 field_repulsion_.allocate(ref_domaine_, Domaine_IJK::ELEM, 0, "REPULSION_FT");
847 champs_compris_.ajoute_champ(field_repulsion_);
848
849 if ((not is_switch) || cut_cell_activated_)
850 {
851 const int nb_ghost_cells = std::max(thermal_probes_ghost_cells, (int) 4);
852
853
854 // IMPORTANT
855 // fields using the old/next syntax must be given a name each
856 // starting with OLD_ for the one at old(). Same name after that
857 // then these pointers are switched in champ_compris_ when old and next are swapped
858 // see method Champs_compris_IJK::switch_ft_fields()
859
860 indicatrice_ft_[old()].allocate(domaine_FT, Domaine_IJK::ELEM, 2, "OLD_INDICATRICE_FT");
861 indicatrice_ft_[old()].data() = 1.;
862 indicatrice_ft_[old()].echange_espace_virtuel(indicatrice_ft_[old()].ghost());
863 indicatrice_ft_[next()].allocate(domaine_FT, Domaine_IJK::ELEM, 2, "INDICATRICE_FT");
864 indicatrice_ft_[next()].data() = 1.;
865 indicatrice_ft_[next()].echange_espace_virtuel(indicatrice_ft_[next()].ghost());
866 // Register INDICATRICE_FT:
867 champs_compris_.ajoute_champ(indicatrice_ft_[old()]);
868 champs_compris_.ajoute_champ(indicatrice_ft_[next()]);
869
870 indicatrice_ns_[old()].allocate(domaine_NS, Domaine_IJK::ELEM, nb_ghost_cells, "OLD_INDICATRICE");
871 indicatrice_ns_[old()].data() = 1.;
872 allocate_cell_vector(groups_indicatrice_ns_[old()], domaine_NS, 1);
873 allocate_cell_vector(groups_indicatrice_ns_[next()], domaine_NS, 1);
874 indicatrice_ns_[old()].echange_espace_virtuel(indicatrice_ns_[old()].ghost());
875 indicatrice_ns_[next()].allocate(domaine_NS, Domaine_IJK::ELEM, nb_ghost_cells, "INDICATRICE");
876 indicatrice_ns_[next()].data() = 1.;
877 indicatrice_ns_[next()].echange_espace_virtuel(indicatrice_ns_[next()].ghost());
878 // Register INDICATRICE:
879 champs_compris_.ajoute_champ(indicatrice_ns_[old()]);
880 champs_compris_.ajoute_champ(indicatrice_ns_[next()]);
881
885 indicatrice_avant_remaillage_ns_.allocate(domaine_NS, Domaine_IJK::ELEM, nb_ghost_cells);
891 indicatrice_apres_remaillage_ns_.allocate(domaine_NS, Domaine_IJK::ELEM, nb_ghost_cells);
894 delta_volume_theorique_bilan_ns_.allocate(domaine_NS, Domaine_IJK::ELEM, nb_ghost_cells);
897 allocate_cell_vector(groups_indicatrice_ft_[old()], domaine_FT, 1);
898 allocate_cell_vector(groups_indicatrice_ft_[next()], domaine_FT, 1);
899#if VERIF_INDIC
900 indicatrice_ft_test_.allocate(domaine_FT, Domaine_IJK::ELEM, 1);
901 allocate_cell_vector(groups_indicatrice_ft_test_, domaine_FT, 1);
902 allocate_cell_vector(groups_indicatrice_ft_test_, domaine_FT, 1);
903#endif
904 nb_compo_traversante_[old()].allocate(domaine_FT, Domaine_IJK::ELEM, 0);
905 nb_compo_traversante_[next()].allocate(domaine_FT, Domaine_IJK::ELEM, 0);
906 for (int i = 0; i < max_authorized_nb_of_components_; i++)
907 {
908 compos_traversantes_[old()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
909 surface_par_compo_[old()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
910 indicatrice_par_compo_[old()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
911 courbure_par_compo_[old()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
912 phi_par_compo_[old()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
913 surf_par_compo_[old()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
914 for (int dir = 0; dir < 3; dir++)
915 source_interf_par_compo_[old()][dir][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
916 repuls_par_compo_[old()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
917 compos_traversantes_[next()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
918 surface_par_compo_[next()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
919 indicatrice_par_compo_[next()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
920 phi_par_compo_[next()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
921 surf_par_compo_[next()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
922 for (int dir = 0; dir < 3; dir++)
923 source_interf_par_compo_[next()][dir][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
924 repuls_par_compo_[next()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
925 courbure_par_compo_[next()][i].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
926 // Et pour les vecteurs :
927 for (int dir = 0; dir < 3; dir++)
928 {
929 const int idx = i * 3 + dir;
930 normale_par_compo_[old()][idx].allocate(domaine_FT, Domaine_IJK::ELEM, 2);
931 bary_par_compo_[old()][idx].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
932 normale_par_compo_[next()][idx].allocate(domaine_FT, Domaine_IJK::ELEM, 2);
933 bary_par_compo_[next()][idx].allocate(domaine_FT, Domaine_IJK::ELEM, 1);
934 }
935 }
936
937 surface_interface_ft_[old()].allocate(domaine_FT, Domaine_IJK::ELEM, 2);
938 surface_interface_ft_[next()].allocate(domaine_FT, Domaine_IJK::ELEM, 2);
939 surface_interface_ns_[old()].allocate(domaine_NS, Domaine_IJK::ELEM, nb_ghost_cells);
940 surface_interface_ns_[next()].allocate(domaine_NS, Domaine_IJK::ELEM, nb_ghost_cells);
941
942 surface_interface_ft_[old()].data() = 0.;
943 surface_interface_ft_[next()].data() = 0.;
944 surface_interface_ns_[old()].data() = 0.;
945 surface_interface_ns_[next()].data() = 0.;
946
947 allocate_cell_vector(barycentre_phase1_ft_[old()], domaine_FT, 2);
948 allocate_cell_vector(barycentre_phase1_ft_[next()], domaine_FT, 2);
949 allocate_cell_vector(barycentre_phase1_ns_[old()], domaine_NS, nb_ghost_cells, "OLD_CUT_FIELDS_BARY_L");
950 allocate_cell_vector(barycentre_phase1_ns_[next()], domaine_NS, nb_ghost_cells, "CUT_FIELDS_BARY_L");
951 champs_compris_.ajoute_champ_vectoriel(barycentre_phase1_ns_[old()]);
952 champs_compris_.ajoute_champ_vectoriel(barycentre_phase1_ns_[next()]);
953
954 for (int bary_compo = 0; bary_compo < 3; bary_compo++)
955 {
956 barycentre_phase1_ft_[old()][bary_compo].data() = 0.;
957 barycentre_phase1_ft_[next()][bary_compo].data() = 0.;
958 barycentre_phase1_ns_[old()][bary_compo].data() = 0.;
959 barycentre_phase1_ns_[next()][bary_compo].data() = 0.;
960 }
961
962 allocate_velocity(indicatrice_surfacique_face_ft_[old()], domaine_FT, 2);
963 allocate_velocity(indicatrice_surfacique_face_ft_[next()], domaine_FT, 2);
964 allocate_velocity(indicatrice_surfacique_face_ns_[old()], domaine_NS, nb_ghost_cells);
965 allocate_velocity(indicatrice_surfacique_face_ns_[next()], domaine_NS, nb_ghost_cells);
966
967 for (int face_dir = 0; face_dir < 3; face_dir++)
968 {
969 indicatrice_surfacique_face_ft_[old()][face_dir].data() = 0.;
970 indicatrice_surfacique_face_ft_[next()][face_dir].data() = 0.;
971 indicatrice_surfacique_face_ns_[old()][face_dir].data() = 0.;
972 indicatrice_surfacique_face_ns_[next()][face_dir].data() = 0.;
973 }
974
975 allocate_velocity(indicatrice_surfacique_avant_remaillage_face_ft_, domaine_FT, 2);
976 allocate_velocity(indicatrice_surfacique_avant_remaillage_face_ns_, domaine_NS, nb_ghost_cells);
977 allocate_velocity(indicatrice_surfacique_apres_remaillage_face_ft_, domaine_FT, 2);
978 allocate_velocity(indicatrice_surfacique_apres_remaillage_face_ns_, domaine_NS, nb_ghost_cells);
979
980 for (int face_dir = 0; face_dir < 3; face_dir++)
981 {
986 }
987
988 for (int face_dir = 0; face_dir < 3; face_dir++)
989 {
990 for (int bary_compo = 0; bary_compo < 2; bary_compo++)
991 {
992 barycentre_phase1_face_ft_[old()][face_dir][bary_compo].allocate(domaine_FT, Domaine_IJK::ELEM, 2);
993 barycentre_phase1_face_ft_[next()][face_dir][bary_compo].allocate(domaine_FT, Domaine_IJK::ELEM, 2);
994 barycentre_phase1_face_ns_[old()][face_dir][bary_compo].allocate(domaine_NS, Domaine_IJK::ELEM, nb_ghost_cells);
995 barycentre_phase1_face_ns_[next()][face_dir][bary_compo].allocate(domaine_NS, Domaine_IJK::ELEM, nb_ghost_cells);
996 }
997 }
998
999 for (int face_dir = 0; face_dir < 3; face_dir++)
1000 {
1001 for (int bary_compo = 0; bary_compo < 2; bary_compo++)
1002 {
1003 barycentre_phase1_face_ft_[old()][face_dir][bary_compo].data() = 0.;
1004 barycentre_phase1_face_ft_[next()][face_dir][bary_compo].data() = 0.;
1005 barycentre_phase1_face_ns_[old()][face_dir][bary_compo].data() = 0.;
1006 barycentre_phase1_face_ns_[next()][face_dir][bary_compo].data() = 0.;
1007 }
1008 }
1009
1010 allocate_velocity(normal_of_interf_[old()], domaine_FT, 2);
1011 allocate_velocity(normal_of_interf_[next()], domaine_FT, 2);
1012 allocate_velocity(normal_of_interf_ns_[old()], domaine_NS, nb_ghost_cells);
1013 allocate_velocity(normal_of_interf_ns_[next()], domaine_NS, nb_ghost_cells);
1014
1015 allocate_velocity(bary_of_interf_[old()], domaine_FT, 1);
1016 allocate_velocity(bary_of_interf_[next()], domaine_FT, 1);
1017 allocate_velocity(bary_of_interf_ns_[old()], domaine_NS, 1);
1018 allocate_velocity(bary_of_interf_ns_[next()], domaine_NS, 1);
1019
1020 allocate_velocity(surface_vapeur_par_face_[old()], domaine_FT, 1);
1021 allocate_velocity(surface_vapeur_par_face_[next()], domaine_FT, 1);
1022 allocate_velocity(surface_vapeur_par_face_ns_[old()], domaine_NS, 1);
1023 allocate_velocity(surface_vapeur_par_face_ns_[next()], domaine_NS, 1);
1024
1025 for (int d = 0; d < 3; d++)
1026 {
1027 surface_vapeur_par_face_[old()][d].data() = 0.;
1028 surface_vapeur_par_face_[next()][d].data() = 0.;
1029 allocate_velocity(barycentre_vapeur_par_face_[old()][d], domaine_FT, 1);
1030 allocate_velocity(barycentre_vapeur_par_face_[next()][d], domaine_FT, 1);
1031 surface_vapeur_par_face_ns_[old()][d].data() = 0.;
1032 surface_vapeur_par_face_ns_[next()][d].data() = 0.;
1033 allocate_velocity(barycentre_vapeur_par_face_ns_[old()][d], domaine_NS, 1);
1034 allocate_velocity(barycentre_vapeur_par_face_ns_[next()][d], domaine_NS, 1);
1035 }
1036
1038 {
1039 Cut_field_vector3_double& cut_field_deformation_velocity = static_cast<Cut_field_vector3_double&>(deformation_velocity_);
1040 allocate_velocity_ephemere(*ref_ijk_ft_->get_cut_cell_disc(), cut_field_deformation_velocity, domaine_NS, 2);
1041 }
1042
1043 allocate_velocity(indicatrice_surfacique_efficace_deformation_face_, domaine_NS, nb_ghost_cells);
1044 }
1045
1047 return;
1048
1049 refdomaine_dis_ = domaine_dis;
1050
1051 // Calcul de la bounding box de Navier Stokes et stockage en memoire de la
1052 // perio.
1053 bounding_box_NS_domain_.resize(3, 2);
1054 // Calcul du domaine au-dela duquel une bulle doit etre repliquee.
1055 // Cette domaine est une peu plus petite que le domaine NS_domain, si la bulle
1056 // depasse de cette domaine elle est dupliquee.
1058 // Calcul du domaine au-dela duquel une bulle est detruite et remplacee
1059 // par son duplicata a l'autre extremite du domaine.
1060 // Cette domaine est un peu plus petite que le domaine etendu ou evolue le
1061 // maillage FT.
1063 for (int direction = 0; direction < 3; direction++)
1064 {
1065 const double ori = domaine_NS.get_origin(direction);
1066 const double len = domaine_NS.get_domain_length(direction);
1067 bounding_box_NS_domain_(direction, 0) = ori;
1068 bounding_box_NS_domain_(direction, 1) = ori + len;
1069 bool perio = domaine_NS.get_periodic_flag(direction);
1070 perio_NS_[direction] = perio;
1071 if (perio && !avoid_duplicata_)
1072 {
1073 // Les bulles qui entre dans les ncells_forbidden_ dernieres mailles
1074 // doivent etre deplacees.
1075 const double oriFT = domaine_FT.get_origin(direction);
1076 const double lenFT = domaine_FT.get_domain_length(direction);
1077 const double delta = domaine_FT.get_constant_delta(direction);
1078 // largeur du domaine, au bord du domaine navier stokes, au sein de
1079 // laquelle on declanche la duplication des bulles (si une bulle depasse a
1080 // l'exterieur du domaine, on duplique) Cette domaine tient compte du stencil
1081 // des forces de tension superficielle et de repulsion
1082 //duCluz : 2 cest mieux pour les echanges espaces virtuels pour la condition de shear-periodicite
1083 double duplicate_stencil_width ;
1084
1086 duplicate_stencil_width =
1087 std::max(2 * delta,
1089 else
1090 duplicate_stencil_width =
1091 std::max(delta,
1093
1094 // GB2020.12.20 : avant c'etait 2. Est-ce
1095 // que la precaution etait necessaire? Elle
1096 // conduit a de plus gros cas tests comme
1097 // interfacial_temperature_and_flux
1098 bounding_box_duplicate_criteria_(direction, 0) = ori + duplicate_stencil_width;
1099 bounding_box_duplicate_criteria_(direction, 1) = ori + len - duplicate_stencil_width;
1100 bounding_box_forbidden_criteria_(direction, 0) = oriFT + ncells_forbidden_ * delta;
1101 bounding_box_forbidden_criteria_(direction, 1) = oriFT + lenFT - ncells_forbidden_ * delta;
1102 }
1103 else
1104 {
1105 if (avoid_duplicata_)
1106 {
1108 bounding_box_duplicate_criteria_(direction, 1) = ori + (factor_length_duplicata_ + 1.)*len;
1109 // Les bulles ne sont pas limitees au domaine NS :
1112 }
1113 else
1114 {
1115 bounding_box_duplicate_criteria_(direction, 0) = bounding_box_NS_domain_(direction, 0);
1116 bounding_box_duplicate_criteria_(direction, 1) = bounding_box_NS_domain_(direction, 1);
1117 // Les bulles sont limitees au domaine NS :
1118 bounding_box_forbidden_criteria_(direction, 0) = bounding_box_NS_domain_(direction, 0);
1119 bounding_box_forbidden_criteria_(direction, 1) = bounding_box_NS_domain_(direction, 1);
1120 }
1121 }
1122 }
1123
1124 parcours_.associer_domaine_dis(domaine_dis);
1125 Domaine_VF& domaine_vf = ref_cast_non_const(Domaine_VF, domaine_dis);
1126 connectivite_frontieres_.associer_domaine_vf(domaine_vf);
1127 parcours_.associer_connectivite_frontieres(connectivite_frontieres_);
1128
1131 {
1132 old_maillage_ft_ijk_.initialize(domaine_FT, domaine_dis, parcours_);
1133 }
1134
1135 // Lecture du maillage initial:
1136 maillage_ft_ijk_.lire_maillage_ft_dans_lata(fichier_reprise_interface_,
1139
1140 remaillage_ft_ijk_.associer_domaine(domaine_dis);
1141
1142 // Si des bulles ghost sont lues, on les detruit
1143 // pour etre sur de les creer toutes.
1144 // Le compteur nb_bulles_ghost_ est remis a zero.
1146
1147 // Initialisation du nombre de bulles :
1148 int loc_max;
1149 if (maillage_ft_ijk_.compo_connexe_facettes().size_array())
1150 loc_max = max_array(maillage_ft_ijk_.compo_connexe_facettes());
1151 else
1152 // on n'a pas une seule facette dans cette partie du decoupage :
1153 loc_max = -1; // Invalid value... Comme ca si on a -1 partout, on a 0 bulle.
1154 // ::mp_max force l'appel a la methode hors classe (version pour les ints)
1155 nb_bulles_reelles_ = Process::mp_max(loc_max) + 1; // car les composantes connexes commencent a 0.
1156 // On est en mesure de redimensionner le tableau (uniquement s'il n'est pas lu
1157 // en param:
1158 if (compo_to_group_.size_array() == 0)
1159 {
1161 compo_to_group_ = 0;
1162 }
1163 assert(compo_to_group_.size_array() == nb_bulles_reelles_);
1164
1165 // Si on commence de suivre les couleurs mais qu'on ne les reprends pas d'un
1166 // calcul precedent, il faut dimensionner le tableau et l'initaliser a 0 :
1167 if ((follow_colors_) && (through_yminus_.size_array() == 0))
1169
1170 DoubleTab centre_gravite;
1171 ArrOfDouble volume_bulles;
1172 calculer_volume_bulles(volume_bulles, centre_gravite);
1173 maillage_ft_ijk_.Surfactant_facettes_non_const().initialize(maillage_ft_ijk_, centre_gravite);
1174
1176 // Si des interfaces sont lues en dehors du domaine de NS, il faut re-creer
1177 // leur ghost.
1179
1180 // Initialisation du tableau de stockage des vitesses aux sommets en RK3 :
1181 RK3_G_store_vi_.resize(0, 3);
1182 distance_autres_interfaces_.resize_array(0);
1183
1184// Maybe needed to post-pro initial condition :
1185 if (compute_vint)
1186 {
1188 {
1189 DoubleTab vr_to_closer; // The velocity of the closest neighbour
1190 // Also calls to compute_vinterp.
1192 }
1193 else
1195 }
1196 // Mise en place des compteurs :
1197
1199 force_time_n_ = 0.;
1200 if (mean_force_.size_array() == 0)
1201 {
1203 mean_force_ = 0.;
1204 }
1205
1206 nb_compo_in_num_compo_ = 0; // initially, waiting for the update when table is completed.
1207 if ((parser_ == 0) && (recompute_indicator_ == 0))
1208 {
1209 Cerr << "Error in option combination: invalid choice of optimized methods "
1210 << "for both the color_function in the forces computation "
1211 << "(parser_=0) and the indicator function calculation "
1212 << "(recompute_indicator_=0)"
1213 << finl;
1214 Cerr << "Maybe you are not using the forces computation?" << finl;
1215 Process::exit();
1216 }
1217 else if ((recompute_indicator_ == 1) || (parser_ == 0))
1218 {
1219 // Pour la methode historique (non-optim) de calcul de l'indicatrice ou pour
1220 // le calcul optimise de la force de rappel. Cree un tableau parallele
1221 // structure comme un tableau aux elements du maillage vdf, initialise a
1222 // zero.
1223 const Domaine& domaine = domaine_vf.domaine();
1225 }
1226
1228 intersection_ijk_cell_.initialize(domaine_NS, *this);
1229 intersection_ijk_face_.initialize(domaine_NS, *this);
1230 ijk_compo_connex_.initialize(*this, is_switch);
1231}
1232
1234{
1235 // Register fields:
1236 scalar_post_fields_["COURBURE"] = IJK_Field_double();
1237 auto& courb = scalar_post_fields_.at("COURBURE");
1238 courb.nommer("COURBURE");
1239 champs_compris_.ajoute_champ(courb);
1240
1241 scalar_post_fields_["CONCENTRATION_INTERFACE"] = IJK_Field_double();
1242 auto& conc_interf = scalar_post_fields_.at("CONCENTRATION_INTERFACE");
1243 conc_interf.nommer("CONCENTRATION_INTERFACE");
1244 champs_compris_.ajoute_champ(conc_interf);
1245
1246 scalar_post_fields_["GRADX_CONCENTRATION_INTERFACE"] = IJK_Field_double();
1247 auto& dconc_interf_x = scalar_post_fields_.at("GRADX_CONCENTRATION_INTERFACE");
1248 dconc_interf_x.nommer("GRADX_CONCENTRATION_INTERFACE");
1249 champs_compris_.ajoute_champ(dconc_interf_x);
1250
1251 scalar_post_fields_["GRADY_CONCENTRATION_INTERFACE"] = IJK_Field_double();
1252 auto& dconc_interf_y = scalar_post_fields_.at("GRADY_CONCENTRATION_INTERFACE");
1253 dconc_interf_y.nommer("GRADY_CONCENTRATION_INTERFACE");
1254 champs_compris_.ajoute_champ(dconc_interf_y);
1255
1256 scalar_post_fields_["GRADZ_CONCENTRATION_INTERFACE"] = IJK_Field_double();
1257 auto& dconc_interf_z = scalar_post_fields_.at("GRADZ_CONCENTRATION_INTERFACE");
1258 dconc_interf_z.nommer("GRADZ_CONCENTRATION_INTERFACE");
1259 champs_compris_.ajoute_champ(dconc_interf_z);
1260
1261 scalar_post_fields_["SIGMA"] = IJK_Field_double();
1262 auto& sigma = scalar_post_fields_.at("SIGMA");
1263 sigma.nommer("SIGMA");
1264 champs_compris_.ajoute_champ(sigma);
1265
1266 scalar_post_fields_["GRADX_SIGMA"] = IJK_Field_double();
1267 auto& dsigma_x = scalar_post_fields_.at("GRADX_SIGMA");
1268 dsigma_x.nommer("GRADX_SIGMA");
1269 champs_compris_.ajoute_champ(dsigma_x);
1270
1271 scalar_post_fields_["GRADY_SIGMA"] = IJK_Field_double();
1272 auto& dsigma_y = scalar_post_fields_.at("GRADY_SIGMA");
1273 dsigma_y.nommer("GRADY_SIGMA");
1274 champs_compris_.ajoute_champ(dsigma_y);
1275
1276 scalar_post_fields_["GRADZ_SIGMA"] = IJK_Field_double();
1277 auto& dsigma_z = scalar_post_fields_.at("GRADZ_SIGMA");
1278 dsigma_z.nommer("GRADZ_SIGMA");
1279 champs_compris_.ajoute_champ(dsigma_z);
1280
1281 scalar_post_fields_["LAPLACIAN_CONCENTRATION_INTERFACE"] = IJK_Field_double();
1282 auto& lapla_interf = scalar_post_fields_.at("LAPLACIAN_CONCENTRATION_INTERFACE");
1283 lapla_interf.nommer("LAPLACIAN_CONCENTRATION_INTERFACE");
1284 champs_compris_.ajoute_champ(lapla_interf);
1285
1286 scalar_post_fields_["DISTANCE_AUTRES_INTERFACES"] = IJK_Field_double();
1287 auto& d = scalar_post_fields_.at("DISTANCE_AUTRES_INTERFACES");
1288 d.nommer("DISTANCE_AUTRES_INTERFACES");
1289 champs_compris_.ajoute_champ(d);
1290}
1291
1293{
1294 Cerr << "IJK_Interfaces::milieu not coded ! access it from NS. " << finl;
1295 throw;
1296}
1297
1299{
1300 Cerr << "IJK_Interfaces::milieu not coded ! access it from NS. " << finl;
1301 throw;
1302}
1303
1305{
1306 if (!sub_type(Probleme_FTD_IJK_base, pb))
1307 {
1308 Cerr << "Error for the method IJK_Interfaces::associer_pb_base\n";
1309 Cerr << " IJK_Interfaces equation must be associated to\n";
1310 Cerr << " a Probleme_FTD_IJK_base problem type\n";
1311 Process::exit();
1312 }
1313 mon_probleme = pb;
1314 if (nom_ == "??")
1315 {
1316 nom_ = pb.le_nom();
1317 nom_ += que_suis_je();
1318 }
1319
1320 ref_ijk_ft_ = ref_cast(Probleme_FTD_IJK_base, pb);
1321 ijk_compo_connex_.associer(ref_ijk_ft_.valeur());
1322 // liste_post_instantanes_ = ijk_ft.post_.get_liste_post_instantanes();
1323}
1324
1326{
1327 ref_ijk_ft_switch_ = ijk_ft_switch;
1328}
1329
1330/*! Methode appelee lorsqu'on a mis "TOUS" dans la liste des champs a postraiter.
1331 * Elle ajoute a la liste tous les noms de champs postraitables par
1332 * IJK_Interfaces
1333 */
1335{
1336 liste.add("INTERFACES");
1337 liste.add("COMPO_CONNEXE");
1338 liste.add("DISTANCE_AUTRES_INTERFACES");
1339 if (follow_colors_)
1340 liste.add("COLOR_Y");
1341 trustIdType size = RK3_G_store_vi_.size_array();
1342 size = Process::mp_sum(size);
1343 if (size)
1344 {
1345 liste.add("RK3_STORE_VI");
1346 liste.add("VI");
1347 }
1348 // liste.add("NORMALE");
1349}
1350
1352 const char *lata_name,
1353 const int lata_step) const
1354{
1355 throw; // THIS METHOD SHOULD NOT BE CALLED ANYMORE
1356
1357 int n = 0; // nombre de champs postraites
1358 if (liste_post_instantanes.contient_("INTERFACES"))
1359 n++, dumplata_ft_mesh(lata_name, "INTERFACES", lata_step);
1360// if (liste_post_instantanes.contient_("COMPO_CONNEXE"))
1361// n++, dumplata_ft_field(lata_name, "INTERFACES", "COMPO_CONNEXE", "ELEM", maillage_ft_ijk_.compo_connexe_facettes(), lata_step);
1362 if (liste_post_instantanes.contient_("COLOR_Y"))
1363 {
1364 if (!follow_colors_)
1365 {
1366 Cerr << "On demande le post-traitement du champ COLOR_Y alors que le flag follow_colors "
1367 << "n'a pas ete active... Ce champ est donc inconnu. Post-traitement refuse. " << finl;
1368 Process::exit();
1369 }
1370 ArrOfInt color;
1371 calculer_color(color);
1372 n++, dumplata_ft_field(lata_name, "INTERFACES", "COLOR_Y", "ELEM", color, lata_step);
1373 }
1374 if (liste_post_instantanes.contient_("VINTERP"))
1375 {
1376 n++, dumplata_ft_field(lata_name, "INTERFACES", "VINTERP", "SOM", RK3_G_store_vi_, lata_step);
1377 }
1378 if (liste_post_instantanes.contient_("VI"))
1379 {
1380 ArrOfDoubleFT vi;
1381 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
1382 int nbsom = mesh.sommets().dimension(0);
1383 vi.resize_array(nbsom);
1384 // La methode est const! Un calcul de vinterp ici changerait l'objet interfaces_
1385 //compute_vinterp(); // Pour s'assurer que vinterp soit a jour avec le maillage (bon nb_som)
1386 // Ce n'est pas exactement celui utilise pour le transport puisqu'ici, la compo tangeante n'est pas retiree.
1387 for (int dir= 0; dir < 3; dir++)
1388 {
1389 if (vinterp_.dimension(0) == 0)
1390 {
1391 Cerr << "Posttraitement du champ VI vide : on stocke 0." << finl;
1392 vi = 0.;
1393 }
1394 else
1395 for (int i = 0; i < nbsom; i++)
1396 vi[i] = vinterp_(i,dir);
1397
1398 if (dir==0)
1399 n++, dumplata_ft_field(lata_name, "INTERFACES", "VI_X", "SOM", vi, lata_step);
1400 if (dir==1)
1401 n++, dumplata_ft_field(lata_name, "INTERFACES", "VI_Y", "SOM", vi, lata_step);
1402 if (dir==2)
1403 n++, dumplata_ft_field(lata_name, "INTERFACES", "VI_Z", "SOM", vi, lata_step);
1404 }
1405
1406 }
1407
1408 if (liste_post_instantanes.contient_("RK3_STORE_VI"))
1409 {
1410 ArrOfDoubleFT store_vi_compo;
1411 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
1412 int nbsom = mesh.sommets().dimension(0);
1413 store_vi_compo.resize_array(nbsom);
1414
1415 // int size = RK3_G_store_vi_.size_array();
1416 // size = Process::mp_sum(size);
1417 for (int dir= 0; dir < 3; dir++)
1418 {
1419 // Si le tableau n'est pas rempli, on retourne 0
1420 if (RK3_G_store_vi_.dimension(0) == 0)
1421 {
1422 Cerr << "Posttraitement du champ RK3_STORE_VI vide : on stocke 0." << finl;
1423 store_vi_compo = 0.;
1424 }
1425 else
1426 {
1427 for (int i = 0; i < nbsom; i++)
1428 {
1429 const double val = RK3_G_store_vi_(i,dir);
1430 store_vi_compo[i] = val;
1431 }
1432 }
1433 if (dir==0)
1434 n++, dumplata_ft_field(lata_name, "INTERFACES", "RK3_STORE_VI_X", "SOM", store_vi_compo, lata_step);
1435 if (dir==1)
1436 n++, dumplata_ft_field(lata_name, "INTERFACES", "RK3_STORE_VI_Y", "SOM", store_vi_compo, lata_step);
1437 if (dir==2)
1438 n++, dumplata_ft_field(lata_name, "INTERFACES", "RK3_STORE_VI_Z", "SOM", store_vi_compo, lata_step);
1439 }
1440 }
1441 return n;
1442}
1443
1444// Suppression des bulles dans le domaine a eliminer pres des bords periodiques
1445// definie par ncells_deleted_ Dans ce cas, le maillage est modifie:
1446// o Les ghosts sont supprimes de la sauvegarde.
1447// o Les bulles qui sortent du domaine defini via ncells_deleted_ sont
1448// supprimees aussi. o Le numero des autres bulles est re-attribue pour creer
1449// une liste contigue (0, 1, 2, ...)
1450// et supprimer les trous
1452{
1454 int flag = 0;
1456 {
1457 // Calcul du domaine dans lequelle une bulle est supprimee:
1458 bounding_box_delete_criteria_.resize(3, 2);
1459 const Domaine_IJK& geom_FT = ref_domaine_.valeur();
1460 for (int direction = 0; direction < 3; direction++)
1461 {
1462 if (perio_NS_[direction])
1463 {
1464 // Les bulles qui entre dans les ncells_forbidden_ dernieres mailles
1465 // doivent etre deplacees.
1466 const double oriFT = geom_FT.get_origin(direction);
1467 const double lenFT = geom_FT.get_domain_length(direction);
1468 const double delta = geom_FT.get_constant_delta(direction);
1469 bounding_box_delete_criteria_(direction, 0) = oriFT + ncells_deleted_ * delta;
1470 bounding_box_delete_criteria_(direction, 1) = oriFT + lenFT - ncells_deleted_ * delta;
1471 }
1472 else
1473 {
1474 // Les bulles sont limitees au domaine NS :
1475 bounding_box_delete_criteria_(direction, 0) = bounding_box_NS_domain_(direction, 0);
1476 bounding_box_delete_criteria_(direction, 1) = bounding_box_NS_domain_(direction, 1);
1477 }
1478 }
1479 }
1480 // broadcast to all mpi processes:
1481 envoyer_broadcast(bounding_box_delete_criteria_, 0);
1482
1483 // Evaluation du cube contenant chaque bulle :
1484 DoubleTab bounding_box;
1485 calculer_bounding_box_bulles(bounding_box);
1486
1487 // Pour chaque compo_connexe, remplir dans le tableau
1488 // masque_duplicata_pour_compo un encodage du deplacement maximal pour toutes
1489 // les bulles qui sortent de delete_criteria:
1490 ArrOfInt masque_delete_pour_compo;
1491 preparer_duplicata_bulles_masque_6bit(bounding_box, bounding_box_delete_criteria_, masque_delete_pour_compo);
1492 // Le masque reste a zero pour les bulles qui sont dans la
1493 // box_delete_criteria. Il faut donc supprimer les bulles en dehors, dont le
1494 // masque est different de 0.
1495
1496 // Duplique et deplace les bulles de la liste :
1497 // dupliquer_bulle_perio(masque_delete_pour_compo);
1498
1499 int nb_bulles_reelles_futur = nb_bulles_reelles_;
1500 int nb_bulles_reelles_deleted = 0;
1501 ArrOfInt old_to_new_compo;
1502 old_to_new_compo.resize_array(nb_bulles_reelles_);
1504 {
1505 int count = 0;
1506 for (int i = 0; i < masque_delete_pour_compo.size_array(); i++)
1507 {
1508 if (masque_delete_pour_compo[i] != 0)
1509 {
1510 flag = 1;
1511 nb_bulles_reelles_futur -= 1;
1512 nb_bulles_reelles_deleted += 1;
1513 old_to_new_compo[i] = -1;
1514 }
1515 else
1516 {
1517 old_to_new_compo[i] = count;
1518 count++;
1519 }
1520 }
1521 nb_bulles_reelles_futur = count;
1522 }
1523 // broadcast to all mpi processes:
1524 envoyer_broadcast(old_to_new_compo, 0);
1525 envoyer_broadcast(nb_bulles_reelles_futur, 0);
1526 envoyer_broadcast(flag, 0);
1527 envoyer_broadcast(nb_bulles_reelles_deleted, 0);
1528
1529 if (flag)
1530 {
1531 Cerr << nb_bulles_reelles_deleted << " marked for deletion out of " << nb_bulles_reelles_
1532 << " so that only " << nb_bulles_reelles_futur << " will remain." << finl;
1533 const ArrOfInt& compo_connexe_facettes = mesh.compo_connexe_facettes();
1534 int icompo;
1535 // on remplace les compo a supprimer par -1
1536 for (int fa7 = 0; fa7 < mesh.nb_facettes(); fa7++)
1537 {
1538 icompo = compo_connexe_facettes[fa7];
1539 assert(icompo >= 0); // les duplicatas ne sont pas la.
1540 // imasque = masque_delete_pour_compo[icompo];
1541 // On lui donne son nouveau numero ou on met '-1' pour la marquer pour
1542 // suppression
1543 mesh.set_composante_connexe(fa7, old_to_new_compo[icompo]);
1544 }
1545
1546 // On supprime les bulles que l'on vient de renumeroter -1:
1547 // (les duplicatas n'etaient pas presents).
1549 Cerr << "The number of bubbles has been reduced from " << nb_bulles_reelles_
1550 << " to " << nb_bulles_reelles_futur << finl;
1551
1553
1555 {
1556 for (icompo = 0; icompo < nb_bulles_reelles_; icompo++)
1557 {
1558 int inew = old_to_new_compo[icompo];
1559 assert(inew <= icompo);
1560 // On ne fait quelque chose que pour les bulles conservees (pas marquees
1561 // -1)
1562 if (inew > -1)
1563 {
1564 compo_to_group_[inew] = compo_to_group_[icompo];
1565 if (through_yminus_.size_array())
1566 through_yminus_[inew] = through_yminus_[icompo];
1567 if (positions_reference_.size_array())
1569 }
1570 }
1571 compo_to_group_.resize_array(nb_bulles_reelles_futur);
1572 if (through_yminus_.size_array())
1573 through_yminus_.resize_array(nb_bulles_reelles_futur);
1574 if (positions_reference_.size_array())
1575 positions_reference_.resize_array(nb_bulles_reelles_futur);
1576 Cerr << "The table of bubbles groups (compo_to_group_), "
1577 << " (as well as possibly through_yminus_ and positions_reference_ "
1578 << "if needed)" << " have been updated in accordance." << finl;
1579 }
1580 envoyer_broadcast(compo_to_group_, 0);
1581 envoyer_broadcast(through_yminus_, 0);
1582 envoyer_broadcast(positions_reference_, 0);
1583 nb_bulles_reelles_ = nb_bulles_reelles_futur;
1584 }
1585}
1586
1587// Attention a l'usage du mot cle 'ncells_deleted_' qui conduit a la suppression
1588// de bulles (reelles) et pas uniquement des ghosts.
1589void IJK_Interfaces::sauvegarder_interfaces(const char *lata_name, const Nom& interf_name) // const
1590{
1593 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
1594
1595 store_bubbles_barycentres(interf_name);
1596
1597 // Suppression des bulles dans le domaine a eliminer pres des bords periodiques
1598 // lors de la sauvegarde.
1599 if (ncells_deleted_ > 0)
1601
1602 dumplata_ft_mesh(lata_name, "INTERFACES", 0);
1603 dumplata_ft_field(lata_name, "INTERFACES", "COMPO_CONNEXE", "ELEM", mesh.compo_connexe_facettes(), 0);
1604}
1605
1606void IJK_Interfaces::postraiter_colors(Sortie& os, const double current_time) const
1607{
1609 return;
1610
1611 os << "# Impression des couleurs de bulles" << finl;
1612 os << "# colonne 1 : temps" << finl;
1613 os << "# colonne K : Couleur de la bulle K-2" << finl;
1614 const int n = through_yminus_.size_array();
1615 os << current_time << " ";
1616 for (int j = 0; j < n; j++)
1617 os << through_yminus_[j] << " ";
1618 os << finl;
1619}
1620
1621void IJK_Interfaces::calculer_color(ArrOfInt& color) const
1622{
1623 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
1624 const int n = mesh.nb_facettes();
1625 color.resize_array(n);
1626 const ArrOfInt& compo_facettes = mesh.compo_connexe_facettes();
1627 for (int i = 0; i < n; i++)
1628 {
1629 // if (mesh.facette_virtuelle(i)) {
1630 // color[i] = -1000; // Valeur invalide pour les facettes virtuelles.
1631 // continue;
1632 // }
1633 const int compo = compo_facettes[i];
1634 // ignorer les bulles dupliquees
1635 if (compo < 0)
1636 {
1637 color[i] = -1000; // Valeur invalide pour les duplicatatas.
1638 continue;
1639 }
1640 const int value = through_yminus_[compo];
1641 color[i] = value;
1642 }
1643 // mp_max_for_each_item(color);
1644}
1645
1646// Sorte de dico renversant le tableau ghost_compo_converter_
1647// Cherche dans le tableau ghost_compo_converter_ la case qui a la composante
1648// fournie en argument.
1649// Retourne le numero de bulle ghost construit comme :
1650// -1 - idx_case
1651// L'entier retourner prend donc une valeur entre -1 et -nb_bulles_ghost
1652// (inclus)
1654{
1655 const int n = ghost_compo_converter_.size_array();
1656 for (int i = 0; i < n; i++)
1657 {
1658 if (ghost_compo_converter_[i] == compo)
1659 {
1660 return -1 - i;
1661 }
1662 }
1663
1664 Cerr << "Exception dans IJK_Interfaces::get_ghost_number_from_compo(). "
1665 << " Compo demandee " << compo << " introuvable...";
1666 Process::exit();
1667 return -1000000;
1668}
1669
1670void IJK_Interfaces::calculer_surface_bulles(ArrOfDouble& surfaces) const
1671{
1672 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
1673 const int n = mesh.nb_facettes();
1674 const int nbulles_reelles = get_nb_bulles_reelles();
1675 const int nbulles_ghost = get_nb_bulles_ghost();
1676 surfaces.resize_array(nbulles_reelles + nbulles_ghost, RESIZE_OPTIONS::NOCOPY_NOINIT);
1677 surfaces = 0.;
1678 const ArrOfDouble& surfaces_facettes = mesh.get_update_surface_facettes();
1679 const ArrOfInt& compo_facettes = mesh.compo_connexe_facettes();
1680 for (int i = 0; i < n; i++)
1681 {
1682 if (mesh.facette_virtuelle(i))
1683 continue;
1684 int compo = compo_facettes[i];
1685 // les bulles dupliquees a la fin :
1686 if (compo < 0)
1687 {
1688 // L'index de la bulle ghost est (entre -1 et -nbulles_ghost):
1689 const int idx_ghost = get_ghost_number_from_compo(compo);
1690 // On la place en fin de tableau :
1691 compo = nbulles_reelles - 1 - idx_ghost;
1692 }
1693
1694 const double s = surfaces_facettes[i];
1695 surfaces[compo] += s;
1696 }
1697 mp_sum_for_each_item(surfaces);
1698}
1699
1700// in : should be an array of field [Unit] for each facette, with value
1701// field*area [Unit*m2]
1702// For instance, fields can be :
1703// interfacial_temperature(fa7) = Ti*surf;
1704// interfacial_phin_ai[fa7] += phin*surf;
1705void IJK_Interfaces::compute_surface_average_per_bubble(const ArrOfDouble& surfaces, const ArrOfDouble& in,
1706 ArrOfDouble& out) const
1707{
1708 const int nbulles = get_nb_bulles_reelles();
1709 out.resize_array(nbulles);
1710 out = 0.;
1711 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
1712 const int n = mesh.nb_facettes();
1713 const ArrOfInt& compo_facettes = mesh.compo_connexe_facettes();
1714 for (int i = 0; i < n; i++)
1715 {
1716 if (mesh.facette_virtuelle(i))
1717 continue;
1718 int compo = compo_facettes[i];
1719 // On passe les bulles ghosts...
1720 if (compo < 0)
1721 continue;
1722
1723 const double s = in[i];
1724 out[compo] += s;
1725 }
1727
1728 for (int c = 0; c < nbulles; c++)
1729 out[c] /= surfaces[c];
1730}
1732{
1733 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
1734 const ArrOfDouble& surfaces_facettes = mesh.get_update_surface_facettes();
1735 const DoubleTab& normales_facettes = mesh.get_update_normale_facettes();
1736 if (surfaces_facettes.size_array() * normales_facettes.size_array() > 0)
1737 {
1738 // juste pour bien qu'elles soient utilisees
1739 Cerr << "interfacial surface and normale are sure to be up-to-date" << finl;
1740 return;
1741 }
1742 return;
1743}
1744
1749
1751{
1755 {
1757 bool tmp_readen_flag = false;
1758 Nom suffix_tmp = ".old";
1759 FixedVector<ArrOfDouble,3> bubbles_bary_old;
1760 tmp_readen_flag = read_bubbles_barycentres(interf_name, suffix_tmp, bubbles_bary_old);
1761 if (tmp_readen_flag)
1762 FixedVector_to_DoubleTab(bubbles_bary_old, bubbles_bary_old_);
1764
1765 suffix_tmp = ".new";
1766 FixedVector<ArrOfDouble,3> bubbles_bary_new;
1767 tmp_readen_flag = read_bubbles_barycentres(interf_name, suffix_tmp, bubbles_bary_new);
1768 if (tmp_readen_flag)
1769 FixedVector_to_DoubleTab(bubbles_bary_new, bubbles_bary_new_);
1771
1772 FixedVector<ArrOfDouble,3> bubbles_rising_dir;
1773 FixedVector<ArrOfDouble,3> bubbles_rising_vel;
1774 tmp_readen_flag = read_bubbles_barycentres_vel(interf_name, bubbles_rising_dir, bubbles_rising_vel, bubbles_velocities_bary_magnitude_);
1775 if (tmp_readen_flag)
1776 {
1777 FixedVector_to_DoubleTab(bubbles_rising_dir, bubbles_rising_vectors_bary_);
1778 FixedVector_to_DoubleTab(bubbles_rising_vel, bubbles_velocities_bary_);
1779 }
1781 }
1782}
1783
1785 FixedVector<ArrOfDouble,3>& bubbles_rising_dir,
1786 FixedVector<ArrOfDouble,3>& bubbles_rising_vel,
1787 ArrOfDouble& bubbles_rising_vel_mag)
1788{
1789 bool is_readen = false;
1790 int bubbles_bary_computed = ijk_compo_connex_.get_compute_compo_fields();
1791 bubbles_bary_computed = bubbles_bary_computed || use_barycentres_velocity_;
1792 bubbles_rising_vel_mag.reset();
1793 for (int c=0; c<3; c++)
1794 {
1795 bubbles_rising_dir[c].reset();
1796 bubbles_rising_vel[c].reset();
1797 }
1798 if (bubbles_bary_computed)
1799 {
1800 int line_counter = 0;
1801 int var_index = 0;
1802 int dir = 0;
1803 std::string line;
1804 const Nom interf_dir = dirname(interf_name);
1805 const Nom case_name = (Objet_U::nom_du_cas());
1806 const Nom suffix_bary = ".sauv.barycentres";
1807 const Nom file_folder = interf_dir + case_name + suffix_bary + ".vel";
1808 // creating an ifstream object named file
1809 ifstream read_tmp;
1810 read_tmp.open(file_folder);
1811 const bool read_file = read_tmp ? true : false;
1812 read_tmp.close();
1813 if (read_file)
1814 {
1815 EFichier fic_bary_vel(file_folder);
1816 ifstream& ifstream_bary_vel = fic_bary_vel.get_ifstream();
1817 const char delimiter = ' ';
1818 Cerr << "Read coordinates of bubbles barycentres from: " << file_folder << finl;
1819 while (std::getline(ifstream_bary_vel, line))
1820 {
1821 std::stringstream ssline(line);
1822 Cerr << "Line number: " << line_counter << finl;
1823 while (std::getline(ssline, line, delimiter))
1824 {
1825 if(line_counter)
1826 {
1827 Cerr << "Param: " << line << finl;
1828 switch(var_index)
1829 {
1830 case 0:
1831 break;
1832 case 1:
1833 case 2:
1834 case 3:
1835 dir = var_index - 1;
1836 bubbles_rising_vel[dir].append_array(std::stod(line));
1837 break;
1838 case 4:
1839 case 5:
1840 case 6:
1841 dir = var_index - 4;
1842 bubbles_rising_dir[dir].append_array(std::stod(line));
1843 break;
1844 case 7:
1845 bubbles_rising_vel_mag.append_array(std::stod(line));
1846 break;
1847 default:
1848 break;
1849 }
1850 var_index++;
1851 }
1852 }
1853 var_index = 0;
1854 line_counter++;
1855 }
1856 fic_bary_vel.close();
1857 is_readen = true;
1858 }
1859 }
1860 return is_readen;
1861}
1862
1863bool IJK_Interfaces::read_bubbles_barycentres(const Nom& interf_name, const Nom& suffix, FixedVector<ArrOfDouble,3>& bubbles_bary)
1864{
1865 bool is_readen = false;
1866 int bubbles_bary_computed = ijk_compo_connex_.get_compute_compo_fields();
1867 bubbles_bary_computed = bubbles_bary_computed || use_barycentres_velocity_;
1868 for (int c=0; c<3; c++)
1869 {
1870 bubbles_bary[c].reset();
1871 }
1872 if (bubbles_bary_computed)
1873 {
1874 int line_counter = 0;
1875 int var_index = 0;
1876 int dir = 0;
1877 std::string line;
1878 const Nom interf_dir = dirname(interf_name);
1879 const Nom case_name = (Objet_U::nom_du_cas());
1880 const Nom suffix_bary = ".sauv.barycentres";
1881 const Nom file_folder = interf_dir + case_name + suffix_bary + suffix;
1882 ifstream read_tmp;
1883 read_tmp.open(file_folder);
1884 const bool read_file = read_tmp ? true : false;
1885 read_tmp.close();
1886 if (read_file)
1887 {
1888 EFichier fic_bary(file_folder);
1889 ifstream& ifstream_bary_old = fic_bary.get_ifstream();
1890 const char delimiter = ' ';
1891 Cerr << "Read coordinates of bubbles barycentres from: " << file_folder << finl;
1892 while (std::getline(ifstream_bary_old, line))
1893 {
1894 std::stringstream ssline(line);
1895 Cerr << "Line number: " << line_counter << finl;
1896 while (std::getline(ssline, line, delimiter))
1897 {
1898 if(line_counter)
1899 {
1900 Cerr << "Param: " << line << finl;
1901 switch(var_index)
1902 {
1903 case 0:
1904 break;
1905 case 1:
1906 case 2:
1907 case 3:
1908 dir = var_index - 1;
1909 bubbles_bary[dir].append_array(std::stod(line));
1910 break;
1911 default:
1912 break;
1913 }
1914 var_index++;
1915 }
1916 }
1917 var_index = 0;
1918 line_counter++;
1919 }
1920 fic_bary.close();
1921 is_readen = true;
1922 }
1923 }
1924 return is_readen;
1925}
1926
1928{
1929 const Nom end_space = " ";
1930 const Nom escape = "\n";
1931 int bubbles_bary_computed = ijk_compo_connex_.get_compute_compo_fields();
1932 bubbles_bary_computed = bubbles_bary_computed || use_barycentres_velocity_;
1933 if (Process::je_suis_maitre() && bubbles_bary_computed)
1934 {
1935 const Nom interf_dir = dirname(interf_name);
1936 const Nom suffix = ".sauv.barycentres";
1937 const int reset = 1;
1938 const Nom bary_header_old = "ibubble bary_old_x bary_old_y bary_old_z";
1939 const Nom bary_header_new = "ibubble bary_new_x bary_new_y bary_new_z";
1940 const Nom bary_vel_header = "ibubble bary_vel_x bary_vel_y bary_vel_z bary_vect_x bary_vect_y bary_vect_z bary_vel_val";
1941 const int nbulles_reelles = get_nb_bulles_reelles();
1942 SFichier fic_bary_old = Open_file_folder(interf_dir, suffix + ".old", bary_header_old, reset, 0);
1943 for (int ibubble=0; ibubble<nbulles_reelles; ibubble++)
1944 {
1945 fic_bary_old << ibubble << end_space;
1946 fic_bary_old << bubbles_bary_old_(ibubble, 0) << end_space;
1947 fic_bary_old << bubbles_bary_old_(ibubble, 1) << end_space;
1948 fic_bary_old << bubbles_bary_old_(ibubble, 2) << escape;
1949 }
1950 fic_bary_old.close();
1951 SFichier fic_bary_new = Open_file_folder(interf_dir, suffix + ".new", bary_header_new, reset, 0);
1952 for (int ibubble=0; ibubble<nbulles_reelles; ibubble++)
1953 {
1954 fic_bary_new << ibubble << end_space;
1955 fic_bary_new << bubbles_bary_new_(ibubble, 0) << end_space;
1956 fic_bary_new << bubbles_bary_new_(ibubble, 1) << end_space;
1957 fic_bary_new << bubbles_bary_new_(ibubble, 2) << escape;
1958 }
1959 fic_bary_new.close();
1960 SFichier fic_bary_vel = Open_file_folder(interf_dir, suffix + ".vel", bary_vel_header, reset, 0);
1961 for (int ibubble=0; ibubble<nbulles_reelles; ibubble++)
1962 {
1963 fic_bary_vel << ibubble << end_space;
1964 fic_bary_vel << bubbles_velocities_bary_(ibubble, 0) << end_space;
1965 fic_bary_vel << bubbles_velocities_bary_(ibubble, 1) << end_space;
1966 fic_bary_vel << bubbles_velocities_bary_(ibubble, 2) << end_space;
1967 fic_bary_vel << bubbles_rising_vectors_bary_(ibubble, 0) << end_space;
1968 fic_bary_vel << bubbles_rising_vectors_bary_(ibubble, 1) << end_space;
1969 fic_bary_vel << bubbles_rising_vectors_bary_(ibubble, 2) << end_space;
1970 fic_bary_vel << bubbles_velocities_bary_magnitude_(ibubble) << escape;
1971 }
1972 fic_bary_vel.close();
1973 }
1974}
1975
1977 DoubleTab& barycentres,
1978 const int& store_values)
1979{
1980 calculer_volume_bulles(volumes, barycentres);
1981 const Domaine_IJK& geom = I().get_domaine();
1982 if (store_values && !has_computed_bubble_barycentres_)
1983 {
1984 if (ref_ijk_ft_->schema_temps_ijk().get_tstep() == 0)
1985 {
1987 bubbles_bary_old_ = barycentres;
1988 else
1990 }
1991 else
1993 bubbles_bary_new_ = barycentres;
1994 const int nbulles_reelles = get_nb_bulles_reelles();
1995 bubbles_velocities_bary_magnitude_.resize(nbulles_reelles);
1997 for (int i = 0; i < nbulles_reelles; i++)
1998 {
2000 for (int dir=0; dir<3; dir++)
2001 {
2002 const double ldir = geom.get_domain_length(dir);
2003 const double pos_old = bubbles_bary_old_(i, dir);
2004 const double pos_new = bubbles_bary_new_(i, dir);
2005 const int old_new_up_down = (pos_new - pos_old) < (-ldir / 2.);
2006 const int old_new_down_up = (pos_new - pos_old) > (ldir / 2.);
2007 if (old_new_up_down || old_new_down_up)
2008 {
2009 if (old_new_up_down)
2010 bubbles_bary_old_(i, dir) += (-ldir);
2011 else
2012 bubbles_bary_old_(i, dir) += (ldir);
2013 }
2015 const double vel_old = bubbles_velocities_bary_(i, dir);
2016 bubbles_velocities_bary_(i, dir) = bubbles_bary_new_(i, dir) - vel_old;
2017 bubbles_velocities_bary_(i, dir) *= (1 / ref_ijk_ft_->schema_temps_ijk().get_timestep());
2019 }
2022 for (int dir=0; dir<3; dir++)
2023 {
2024 if (abs(bubbles_velocities_bary_magnitude_(i)) > DMINFLOAT)
2026 else
2027 bubbles_rising_vectors_bary_(i, dir) = 0.;
2028 }
2029 }
2031 }
2032}
2033
2035 DoubleTab& centre_gravite) const
2036{
2037 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
2038 const int n = mesh.nb_facettes();
2039 const int nbulles_reelles = get_nb_bulles_reelles();
2040 const int nbulles_ghost = get_nb_bulles_ghost();
2041 const int nbulles_tot = nbulles_reelles + nbulles_ghost;
2042 volumes.resize_array(nbulles_tot, RESIZE_OPTIONS::NOCOPY_NOINIT);
2043 volumes = 0.;
2044 centre_gravite.resize(nbulles_tot, 3, RESIZE_OPTIONS::NOCOPY_NOINIT);
2045 centre_gravite = 0.;
2046 const ArrOfDouble& surfaces_facettes = mesh.get_update_surface_facettes();
2047 const DoubleTab& normales_facettes = mesh.get_update_normale_facettes();
2048 const IntTab& facettes = mesh.facettes();
2049 const DoubleTab& sommets = mesh.sommets();
2050 const ArrOfInt& compo_facettes = mesh.compo_connexe_facettes();
2051 for (int i = 0; i < n; i++)
2052 {
2053 if (mesh.facette_virtuelle(i))
2054 continue;
2055 int compo = compo_facettes[i];
2056 // les bulles dupliquees a la fin :
2057 if (compo < 0)
2058 {
2059 // L'index de la bulle ghost est (entre -1 et -nbulles_ghost):
2060 const int idx_ghost = get_ghost_number_from_compo(compo);
2061 // On la place en fin de tableau :
2062 compo = nbulles_reelles - 1 - idx_ghost;
2063 }
2064 const double s = surfaces_facettes[i];
2065 const double normale_scalaire_direction = normales_facettes(i, 0); // On projette sur x
2066 // Coordonnee du centre de gravite de la facette
2067 const int i0 = facettes(i, 0);
2068 const int i1 = facettes(i, 1);
2069 const int i2 = facettes(i, 2);
2070 const double coord_centre_gravite_i = (sommets(i0, 0) + sommets(i1, 0) + sommets(i2, 0)) / 3.;
2071 const double coord_centre_gravite_j = (sommets(i0, 1) + sommets(i1, 1) + sommets(i2, 1)) / 3.;
2072 const double coord_centre_gravite_k = (sommets(i0, 2) + sommets(i1, 2) + sommets(i2, 2)) / 3.;
2073 const double volume_prisme = coord_centre_gravite_i * s * normale_scalaire_direction;
2074 // centre de gravite du prisme pondere par son volume avec signe
2075 centre_gravite(compo, 0) += volume_prisme * (coord_centre_gravite_i * 0.5);
2076 centre_gravite(compo, 1) += volume_prisme * coord_centre_gravite_j;
2077 centre_gravite(compo, 2) += volume_prisme * coord_centre_gravite_k;
2078 volumes[compo] += volume_prisme;
2079 }
2080 mp_sum_for_each_item(volumes);
2081 mp_sum_for_each_item(centre_gravite);
2082 //Cerr << "volumes : " << volumes << finl;
2083 for (int i = 0; i < nbulles_tot; i++)
2084 {
2085 // const double x = 1./volumes[i];
2086 const double x = (volumes[i] == 0.) ? 0. : 1. / volumes[i];
2087 centre_gravite(i, 0) *= x;
2088 centre_gravite(i, 1) *= x;
2089 centre_gravite(i, 2) *= x;
2090 }
2091}
2092
2093
2094void IJK_Interfaces::calculer_aspect_ratio(ArrOfDouble& aspect_ratio) const
2095{
2096 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
2097 const int n = mesh.nb_facettes();
2098 const int nbulles_reelles = get_nb_bulles_reelles();
2099 const int nbulles_ghost = get_nb_bulles_ghost();
2100 const int nbulles_tot = nbulles_reelles + nbulles_ghost;
2101 const IntTab& facettes = mesh.facettes();
2102 const DoubleTab& sommets = mesh.sommets();
2103 const ArrOfInt& compo_facettes = mesh.compo_connexe_facettes();
2104 aspect_ratio.resize_array(nbulles_tot);
2105
2106 ArrOfDouble volumes;
2107 DoubleTab centre_gravite;
2108 this->calculer_volume_bulles(volumes,centre_gravite);
2109
2110 DoubleTab d_max(nbulles_tot);
2111 d_max = -1;
2112 DoubleTab d_min(nbulles_tot);
2113 d_min = 300;
2114
2115 double d_imax;
2116 double d_imin;
2117
2118 for (int i = 0; i < n; i++)
2119 {
2120 if (mesh.facette_virtuelle(i))
2121 continue;
2122 int compo = compo_facettes[i];
2123 // les bulles dupliquees a la fin :
2124 if (compo < 0)
2125 {
2126 // L'index de la bulle ghost est (entre -1 et -nbulles_ghost):
2127 const int idx_ghost = get_ghost_number_from_compo(compo);
2128 // On la place en fin de tableau :
2129 compo = nbulles_reelles - 1 - idx_ghost;
2130 }
2131 // Calcul des distances entre sommet_i et le centre de gravite
2132 const int i0 = facettes(i, 0);
2133 const int i1 = facettes(i, 1);
2134 const int i2 = facettes(i, 2);
2135 const double d_i_0 = sqrt( (sommets(i0, 0)-centre_gravite(compo,0))*(sommets(i0, 0)-centre_gravite(compo,0)) + (sommets(i0, 1)-centre_gravite(compo,1))*(sommets(i0, 1)-centre_gravite(compo,1)) + (sommets(i0, 2)-centre_gravite(compo,2))*(sommets(i0, 2)-centre_gravite(compo,2)) );
2136 const double d_i_1 = sqrt( (sommets(i1, 0)-centre_gravite(compo,0))*(sommets(i1, 0)-centre_gravite(compo,0)) + (sommets(i1, 1)-centre_gravite(compo,1))*(sommets(i1, 1)-centre_gravite(compo,1)) + (sommets(i1, 2)-centre_gravite(compo,2))*(sommets(i1, 2)-centre_gravite(compo,2)) );
2137 const double d_i_2 = sqrt( (sommets(i2, 0)-centre_gravite(compo,0))*(sommets(i2, 0)-centre_gravite(compo,0)) + (sommets(i2, 1)-centre_gravite(compo,1))*(sommets(i2, 1)-centre_gravite(compo,1)) + (sommets(i2, 2)-centre_gravite(compo,2))*(sommets(i2, 2)-centre_gravite(compo,2)) );
2138
2139 // On recupere la plus grande distance et la plus petite distance parmi les 3 calculees
2140 d_imax = std::max(d_i_0,std::max(d_i_1,d_i_2));
2141 d_imin = std::min(d_i_0,std::min(d_i_1,d_i_2));
2142
2143 // On met a jour le grand axe et le petit axe
2144 if (d_imax > d_max[compo])
2145 d_max[compo] = d_imax;
2146
2147 if (d_imin < d_min[compo])
2148 d_min[compo] = d_imin;
2149 }
2150
2151 mp_min_for_each_item(d_min);
2152 mp_max_for_each_item(d_max);
2153 for (int i = 0; i < nbulles_tot; i++)
2154 {
2155 aspect_ratio[i] = d_max[i]/d_min[i];
2156 }
2157}
2158
2159void IJK_Interfaces::calculer_surfactant(ArrOfDouble& surfactant,ArrOfDouble& surfactant_min,ArrOfDouble& surfactant_max) const
2160{
2161 if (maillage_ft_ijk_.Surfactant_facettes().get_disable_surfactant())
2162 {
2163 return ;
2164 }
2165 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
2166 const int n = mesh.nb_facettes();
2167 const int nbulles_reelles = get_nb_bulles_reelles();
2168 const ArrOfInt& compo_facettes = mesh.compo_connexe_facettes();
2169 const ArrOfDouble& Surf = mesh.Surfactant_facettes().get_FT_field_Array();
2170 const ArrOfDouble& Sfa7 = mesh.get_update_surface_facettes();
2171 surfactant.resize_array(nbulles_reelles);
2172 surfactant_max.resize_array(nbulles_reelles);
2173 surfactant_min.resize_array(nbulles_reelles);
2174 for (int bulle = 0; bulle < nbulles_reelles; bulle++)
2175 {
2176 surfactant_min(bulle) = 1.e10;
2177 surfactant_max(bulle) = -1.e10;
2178 }
2179 for (int i = 0; i < n; i++)
2180 {
2181 if (mesh.facette_virtuelle(i) or compo_facettes(i)<0)
2182 continue;
2183 surfactant(compo_facettes(i))+=Surf(i)*Sfa7(i);
2184 if(Surf(i)>surfactant_max(compo_facettes(i)))
2185 {
2186 surfactant_max(compo_facettes(i)) = Surf(i);
2187 }
2188 if(Surf(i)<surfactant_min(compo_facettes(i)))
2189 {
2190 surfactant_min(compo_facettes(i)) = Surf(i);
2191 }
2192 }
2193
2194 // Reduce nbulles_reelles * 3 MPI calls to 3 by batching all bubbles together
2195 mp_sum_for_each_item(surfactant);
2196 mp_max_for_each_item(surfactant_max);
2197 mp_min_for_each_item(surfactant_min);
2198}
2199
2200
2202 DoubleTab& poussee) const
2203{
2204 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
2205 const int n = mesh.nb_facettes();
2206 const int nbulles_reelles = get_nb_bulles_reelles();
2207 const int nbulles_ghost = get_nb_bulles_ghost();
2208 const int nbulles_tot = nbulles_reelles + nbulles_ghost;
2209 poussee.resize(nbulles_tot, 3, RESIZE_OPTIONS::NOCOPY_NOINIT);
2210 poussee = 0.;
2211 const ArrOfDouble& surfaces_facettes = mesh.get_update_surface_facettes();
2212 const DoubleTab& normales_facettes = mesh.get_update_normale_facettes();
2213 const IntTab& facettes = mesh.facettes();
2214 const DoubleTab& sommets = mesh.sommets();
2215 const ArrOfInt& compo_facettes = mesh.compo_connexe_facettes();
2216 for (int i = 0; i < n; i++)
2217 {
2218 if (mesh.facette_virtuelle(i))
2219 continue;
2220 int compo = compo_facettes[i];
2221 // les bulles dupliquees a la fin :
2222 if (compo < 0)
2223 {
2224 // L'index de la bulle ghost est (entre -1 et -nbulles_ghost):
2225 const int idx_ghost = get_ghost_number_from_compo(compo);
2226 // On la place en fin de tableau :
2227 compo = nbulles_reelles - 1 - idx_ghost;
2228 }
2229 const double s = surfaces_facettes[i];
2230 // Coordonnee du centre de gravite de la facette
2231 const int i0 = facettes(i, 0);
2232 const int i1 = facettes(i, 1);
2233 const int i2 = facettes(i, 2);
2234 const double coord_centre_gravite_i = (sommets(i0, 0) + sommets(i1, 0) + sommets(i2, 0)) / 3.;
2235 const double coord_centre_gravite_j = (sommets(i0, 1) + sommets(i1, 1) + sommets(i2, 1)) / 3.;
2236 const double coord_centre_gravite_k = (sommets(i0, 2) + sommets(i1, 2) + sommets(i2, 2)) / 3.;
2237 const double grav_scalaire_position_fois_s =
2238 (grav(0,0) * coord_centre_gravite_i + grav(0,1) * coord_centre_gravite_j + grav(0,2) * coord_centre_gravite_k) * s;
2239 for (int dir = 0; dir < 3; dir++)
2240 poussee(compo, dir) += grav_scalaire_position_fois_s * normales_facettes(i, dir);
2241 }
2242 mp_sum_for_each_item(poussee);
2243}
2244
2245void IJK_Interfaces::calculer_aire_interfaciale(IJK_Field_double& ai) const
2246{
2247
2248 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
2249 const Intersections_Elem_Facettes& intersections = mesh.intersections_elem_facettes();
2250 const ArrOfDouble& surface_facettes = mesh.get_update_surface_facettes();
2251
2252 const int n = mesh.nb_facettes();
2253 const Domaine_IJK& geom = ai.get_domaine();
2254 const double dxi = geom.get_constant_delta(DIRECTION_I);
2255 const double dxj = geom.get_constant_delta(DIRECTION_J);
2256 const double dxk = geom.get_constant_delta(DIRECTION_K);
2257 const double vol = dxi * dxj * dxk;
2258
2259 // Remise a zero du champ.
2260 ai.data() = 0;
2261
2262 for (int fa7 = 0; fa7 < n; fa7++)
2263 {
2264
2265 // On compte aussi les facettes_virtuelles
2266 // if (maillage.facette_virtuelle(fa7))
2267 // continue;
2268
2269 const double sf = surface_facettes[fa7];
2270 int index = intersections.index_facette()[fa7];
2271 while (index >= 0)
2272 {
2273 const Intersections_Elem_Facettes_Data& data = intersections.data_intersection(index);
2274 const int num_elem = data.numero_element_;
2275 // Anciennement la methode etait portee par le mesh :
2276 // const Int3 ijk = mesh.convert_packed_to_ijk_cell(num_elem);
2277 // A present, elle est dans le splitting :
2278 const Int3 ijk = geom.convert_packed_to_ijk_cell(num_elem);
2279 const double surf = data.fraction_surface_intersection_ * sf;
2280 ai(ijk[0], ijk[1], ijk[2]) += surf / vol;
2281 index = data.index_element_suivant_;
2282 }
2283 }
2284}
2285
2286void IJK_Interfaces::calculer_aire_interfaciale_for_compo(IJK_Field_double& ai, const int compo) const
2287{
2288
2289 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
2290 const Intersections_Elem_Facettes& intersections = mesh.intersections_elem_facettes();
2291 const ArrOfDouble& surface_facettes = mesh.get_update_surface_facettes();
2292 const ArrOfInt& compo_connex = mesh.compo_connexe_facettes();
2293
2294 const int n = mesh.nb_facettes();
2295 const Domaine_IJK& geom = ai.get_domaine();
2296 const double dxi = geom.get_constant_delta(DIRECTION_I);
2297 const double dxj = geom.get_constant_delta(DIRECTION_J);
2298 const double dxk = geom.get_constant_delta(DIRECTION_K);
2299 const double vol = dxi * dxj * dxk;
2300
2301 // Remise a zero du champ.
2302 ai.data() = 0;
2303
2304 for (int fa7 = 0; fa7 < n; fa7++)
2305 {
2306
2307 // On compte aussi les facettes_virtuelles
2308 // if (maillage.facette_virtuelle(fa7))
2309 // continue;
2310 int compo_fa7 = compo_connex[fa7];
2311
2312 // if compo reelle, on fait rien
2313 // si compo virtuelle, on stocke les ai des bulles virtuelles a la fin du tableau
2314 //if (compo_fa7 < 0)
2315 // compo_fa7 = - compo_fa7 + nb_bulles_reelles_ - 1 ;
2316
2317 if (compo_fa7 != compo)
2318 continue;
2319
2320
2321 const double sf = surface_facettes[fa7];
2322 int index = intersections.index_facette()[fa7];
2323 while (index >= 0)
2324 {
2325 const Intersections_Elem_Facettes_Data& data = intersections.data_intersection(index);
2326 const int num_elem = data.numero_element_;
2327 // Anciennement la methode etait portee par le mesh :
2328 // const Int3 ijk = mesh.convert_packed_to_ijk_cell(num_elem);
2329 // A present, elle est dans le splitting :
2330 const Int3 ijk = geom.convert_packed_to_ijk_cell(num_elem);
2331 const double surf = data.fraction_surface_intersection_ * sf;
2332 ai(ijk[0], ijk[1], ijk[2]) += surf / vol;
2333 index = data.index_element_suivant_;
2334 }
2335 }
2336}
2337
2338double IJK_Interfaces::calculer_aire_interfaciale_for_compo(const int compo, const int i_ref, const int j_ref, const int k_ref) const
2339{
2340
2341 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
2342 const Intersections_Elem_Facettes& intersections = mesh.intersections_elem_facettes();
2343 const ArrOfDouble& surface_facettes = mesh.get_update_surface_facettes();
2344 const ArrOfInt& compo_connex = mesh.compo_connexe_facettes();
2345
2346 const int n = mesh.nb_facettes();
2347 const Domaine_IJK& geom = mesh.get_domaine();
2348 const double dxi = geom.get_constant_delta(DIRECTION_I);
2349 const double dxj = geom.get_constant_delta(DIRECTION_J);
2350 const double dxk = geom.get_constant_delta(DIRECTION_K);
2351 const double vol = dxi * dxj * dxk;
2352 double ai = 0 ;
2353 for (int fa7 = 0; fa7 < n; fa7++)
2354 {
2355
2356 // On compte aussi les facettes_virtuelles
2357 // if (maillage.facette_virtuelle(fa7))
2358 // continue;
2359
2360 const double sf = surface_facettes[fa7];
2361 const int compo_fa7 = compo_connex[fa7];
2362
2363 if (compo_fa7 != compo)
2364 continue;
2365
2366 int index = intersections.index_facette()[fa7];
2367 while (index >= 0)
2368 {
2369 const Intersections_Elem_Facettes_Data& data = intersections.data_intersection(index);
2370 const int num_elem = data.numero_element_;
2371 // Anciennement la methode etait portee par le mesh :
2372 // const Int3 ijk = mesh.convert_packed_to_ijk_cell(num_elem);
2373 // A present, elle est dans le splitting :
2374 const Int3 ijk = geom.convert_packed_to_ijk_cell(num_elem);
2375 const double surf = data.fraction_surface_intersection_ * sf;
2376 if (ijk[0]==i_ref and ijk[1]==j_ref and ijk[2]==k_ref)
2377 {
2378 ai += surf / vol;
2379 }
2380 index = data.index_element_suivant_;
2381 }
2382 }
2383 return ai;
2384}
2385
2386// Retourne le code contenant a la fois le numero de bulle et le code de
2387// deplacement.
2388static int encoder_compo(int num_bulle, int code_deplacement)
2389{
2390 // zzzzzzzzzzzzzzxxxyyy :
2391 // z = Numero de compo connexe.
2392 // x = bit de signe par direction (0: negatif ou 1:positif).
2393 // y = bit de mouvement par direction (0:pas mouvement ou 1: mouvement)
2394 return (num_bulle << 6) | (code_deplacement);
2395}
2396
2397static int decoder_numero_bulle(const int code)
2398{
2399 const int num_bulle = code >> 6;
2400 return num_bulle;
2401}
2402
2403// Calcule le champ de courbure moyenne sur le domaine etendu IJK_ft
2404// Utile pour gerer les conditions de shear-periodicite :: interpolation de la pression monofluide
2405void IJK_Interfaces::calculer_kappa_ft(IJK_Field_double& kappa_ft)
2406{
2407 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
2408 const Intersections_Elem_Facettes& intersections = mesh.intersections_elem_facettes();
2409 const ArrOfDouble& surface_facettes = mesh.get_update_surface_facettes();
2410 const IntTab& facettes = mesh.facettes();
2411 const ArrOfDouble& courbure = maillage_ft_ijk_.get_update_courbure_sommets();
2412
2413 const int n = mesh.nb_facettes();
2414 const Domaine_IJK& s = kappa_ft.get_domaine();
2415
2416
2417 IJK_Field_double SI_ft;
2418 SI_ft.allocate(s, Domaine_IJK::ELEM, 0);
2419 SI_ft.data() = 0.;
2420
2421 kappa_ft.data() = 0.;
2422
2423 for (int fa7 = 0; fa7 < n; fa7++)
2424 {
2425
2426 // On compte aussi les facettes_virtuelles
2427 //if (mesh.facette_virtuelle(fa7))
2428 // continue;
2429 const double sf=surface_facettes[fa7];
2430 int index=intersections.index_facette()[fa7];
2431 while (index >= 0)
2432 {
2433 const Intersections_Elem_Facettes_Data& data = intersections.data_intersection(index);
2434 const int num_elem = data.numero_element_;
2435 const Int3 ijk = s.convert_packed_to_ijk_cell(num_elem);
2436 const double surf = data.fraction_surface_intersection_ * sf;
2437 for (int isom = 0; isom< 3; isom++)
2438 {
2439 const int num_som = facettes(fa7, isom);
2440 const double kappa = courbure[num_som];
2441 kappa_ft(ijk[0],ijk[1],ijk[2]) += kappa*surf/3.;
2442 }
2443 SI_ft(ijk[0],ijk[1],ijk[2]) += surf;
2444 index = data.index_element_suivant_;
2445 }
2446 }
2447
2448
2449 const int nx = kappa_ft.ni();
2450 const int ny = kappa_ft.nj();
2451 const int nz = kappa_ft.nk();
2452
2453 for (int k = 0; k < nz; k++)
2454 for (int j = 0; j < ny; j++)
2455 for (int i = 0; i < nx; i++)
2456 {
2457 if (kappa_ft(i,j,k)!=0.)
2458 kappa_ft(i,j,k)/=SI_ft(i,j,k);
2459 }
2460}
2461
2462
2463/** Le champ de normale n'est pas sur une grille decallee.
2464 * Il doit etre a la meme localisation que "ai" : Domaine_IJK::ELEM
2465 * Le champ kappa_ai contient le produit de la courbure moyenne sur la cellule
2466 * eulerienne par l'aire interfaciale dans cette cellule,
2467 * divisee par le volume de la cellule.
2468
2469 * Le calcul repose sur la conversion vdf -> ijk du numero : num_elem
2470 * Pour que cette conversion soit valide, il faut que le champ soit sur le
2471 * splitting_ft_ car le dom_vdf n'est pas construit pour le splitting ns. Par
2472 * definition, mettre igroup a -1 pour inclure toutes les bulles
2473 */
2474void IJK_Interfaces::calculer_normales_et_aires_interfaciales(IJK_Field_double& ai, IJK_Field_double& kappa_ai,
2475 IJK_Field_vector3_double& normale_cell,
2476 const int igroup) const
2477{
2478 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
2479 const Intersections_Elem_Facettes& intersections = mesh.intersections_elem_facettes();
2480 const ArrOfDouble& surface_facettes = mesh.get_update_surface_facettes();
2481 const DoubleTab& normale_facettes = mesh.get_update_normale_facettes();
2482 const IntTab& facettes = mesh.facettes();
2483 const ArrOfDouble& courbure = maillage_ft_ijk_.get_update_courbure_sommets();
2484
2485 const int n = mesh.nb_facettes();
2486 const Domaine_IJK& geom = ai.get_domaine();
2487 const double dxi = geom.get_constant_delta(DIRECTION_I);
2488 const double dxj = geom.get_constant_delta(DIRECTION_J);
2489 const double dxk = geom.get_constant_delta(DIRECTION_K);
2490 const double vol = dxi * dxj * dxk;
2491
2492 // Remise a zero du champ.
2493 ai.data() = 0.;
2494 kappa_ai.data() = 0.;
2495 for (int dir = 0; dir < 3; dir++)
2496 normale_cell[dir].data() = 0.;
2497
2498 const ArrOfInt& compo_facette = mesh.compo_connexe_facettes();
2499 for (int fa7 = 0; fa7 < n; fa7++)
2500 {
2501
2502 // On compte aussi les facettes_virtuelles
2503 //if (mesh.facette_virtuelle(fa7))
2504 // continue;
2505
2506 // On ne veut comptabiliser que les facettes des compo appartenant a igroup
2507 // (ou toutes les compo si igroup == -1)
2508 int icompo = compo_facette[fa7];
2509 if (icompo<0)
2510 {
2511 // Portion d'interface ghost. On recherche le vrai numero
2512 icompo = decoder_numero_bulle(-icompo);
2513 }
2514 if ((compo_to_group_[icompo] != igroup) && (igroup != -1))
2515 continue;
2516
2517 const double sf=surface_facettes[fa7];
2518 // double surface_tot = 0.;
2519 int index=intersections.index_facette()[fa7];
2520 while (index >= 0)
2521 {
2522 const Intersections_Elem_Facettes_Data& data = intersections.data_intersection(index);
2523 const int num_elem = data.numero_element_;
2524 const Int3 ijk = geom.convert_packed_to_ijk_cell(num_elem);
2525 const double surf = data.fraction_surface_intersection_ * sf;
2526 for (int dir = 0; dir< 3; dir++)
2527 {
2528 const double nx = normale_facettes(fa7,dir);
2529 normale_cell[dir](ijk[0],ijk[1],ijk[2]) += nx * surf;
2530 }
2531 const double fac = surf/(3.*vol);
2532 for (int isom = 0; isom< 3; isom++)
2533 {
2534 const int num_som = facettes(fa7, isom);
2535 const double kappa = courbure[num_som];
2536 kappa_ai(ijk[0],ijk[1],ijk[2]) += kappa*fac;
2537 }
2538 // surface_tot +=surf;
2539 ai(ijk[0],ijk[1],ijk[2]) += surf/vol;
2540 index = data.index_element_suivant_;
2541 }
2542 }
2543
2544 // Nombre de mailles du domaine NS :
2545 // Quelle que soit la compo, le champ normale_cell a le meme nombre de mailles
2546 // qu'ai puisqu'il est localise entierement a ::ELEM
2547 const int nx = ai.ni();
2548 const int ny = ai.nj();
2549 const int nz = ai.nk();
2550
2551 for (int k = 0; k < nz; k++)
2552 for (int j = 0; j < ny; j++)
2553 for (int i = 0; i < nx; i++)
2554 {
2555 double norme_carre = 0.;
2556 for (int dir = 0; dir < 3; dir++)
2557 {
2558 const double dnx = normale_cell[dir](i, j, k);
2559 norme_carre += dnx * dnx;
2560 }
2561
2562 if (norme_carre > 0.)
2563 for (int dir = 0; dir < 3; dir++)
2564 normale_cell[dir](i, j, k) *= 1. / sqrt(norme_carre);
2565 }
2566}
2567
2568// Je ne peux plus conserver cette methode statique a cause de l'utilisation de
2569// get_ghost_number_from_compo
2571 const ArrOfDouble& surface_facette,
2572 const ArrOfDouble& surface_par_bulle,
2573 const ArrOfInt& compo_connexes_facettes,
2574 const int nbulles_reelles,
2575 const int nbulles_ghost,
2576 const DoubleTab& vitesse_sommets,
2577 DoubleTab& vitesses_translation_bulles) const
2578{
2579 const int nbulles_tot = nbulles_reelles + nbulles_ghost;
2580 assert(vitesses_translation_bulles.dimension(0) == nbulles_tot);
2581 assert(surface_par_bulle.size_array() == nbulles_tot);
2582 assert(vitesses_translation_bulles.dimension(1) == 3);
2583
2584 const IntTab& facettes = maillage.facettes();
2585 // Calcul de la vitesse de deplacement moyenne
2586 vitesses_translation_bulles = 0.;
2587
2588 // Cette option supprime la partie translation du mouvement rigide
2590 return;
2591
2592
2593 // calcul de la vitesse moyenne de deplacement de l'interface
2594 for (int fa7 = 0; fa7 < maillage.nb_facettes(); fa7++)
2595 {
2596
2597 // Ne prendre que les facettes reelles (sinon on les compte plusieurs fois)
2598 if (maillage.facette_virtuelle(fa7))
2599 continue;
2600
2601 int compo = compo_connexes_facettes[fa7];
2602 // On met les bulles dupliquees a la fin
2603 // La premiere (numero -1) est a la position nbulles_reelles :
2604 if (compo < 0)
2605 {
2606 // L'index de la bulle ghost est (entre -1 et -nbulles_ghost):
2607 const int idx_ghost = get_ghost_number_from_compo(compo);
2608 // On la place en fin de tableau :
2609 compo = nbulles_reelles - 1 - idx_ghost;
2610 }
2611 assert(compo >= 0);
2612 assert(compo < nbulles_tot);
2613
2614 const double sf = surface_facette[fa7];
2615
2616 // Boucle sur les directions :
2617 for (int dir = 0; dir < 3; dir++)
2618 {
2619 double v = 0.;
2620 // Boucle sur les sommets
2621 for (int j = 0; j < 3; j++)
2622 {
2623 const int isom = facettes(fa7, j);
2624 v += vitesse_sommets(isom, dir);
2625 }
2626 vitesses_translation_bulles(compo, dir) += v * sf / 3.; // il y a 3 sommets.
2627 }
2628 }
2629
2630 mp_sum_for_each_item(vitesses_translation_bulles);
2631
2632 for (int icompo = 0; icompo < nbulles_tot; icompo++)
2633 if (surface_par_bulle[icompo] > 0.)
2634 for (int dir = 0; dir < 3; dir++)
2635 vitesses_translation_bulles(icompo, dir) /= surface_par_bulle[icompo];
2636}
2637
2639 const ArrOfDouble& surface_facette,
2640 const ArrOfDouble& surface_par_bulle,
2641 const ArrOfInt& compo_connexes_facettes,
2642 const int nbulles_reelles,
2643 const int nbulles_ghost,
2644 const DoubleTab& centre_gravite,
2645 const DoubleTab& vitesse_sommets,
2646 const DoubleTab& vitesse_translation_sommets,
2647 DoubleTab& mean_bubble_rotation_vector) const
2648{
2649 const int nbulles_tot = nbulles_reelles + nbulles_ghost;
2650 assert(mean_bubble_rotation_vector.dimension(0) == nbulles_tot);
2651 assert(surface_par_bulle.size_array() == nbulles_tot);
2652 assert(mean_bubble_rotation_vector.dimension(1) == 3);
2653
2654 const IntTab& facettes = maillage.facettes();
2655 const DoubleTab& sommets = maillage.sommets();
2656 // Calcul de la vitesse de deplacement moyenne
2657 mean_bubble_rotation_vector = 0.;
2658
2659 // Cette option supprime la partie rotation du mouvement rigide
2661 return;
2662
2663 // calcul de la vitesse moyenne de deplacement de l'interface
2664 for (int fa7 = 0; fa7 < maillage.nb_facettes(); fa7++)
2665 {
2666 // Ne prendre que les facettes reelles (sinon on les compte plusieurs fois)
2667 if (maillage.facette_virtuelle(fa7))
2668 continue;
2669
2670 int compo = compo_connexes_facettes[fa7];
2671 // On met les bulles dupliquees a la fin
2672 // La premiere (numero -1) est a la position nbulles_reelles :
2673 if (compo < 0)
2674 {
2675 // L'index de la bulle ghost est (entre -1 et -nbulles_ghost):
2676 const int idx_ghost = get_ghost_number_from_compo(compo);
2677 // On la place en fin de tableau :
2678 compo = nbulles_reelles - 1 - idx_ghost;
2679 }
2680 assert(compo >= 0);
2681 assert(compo < nbulles_tot);
2682
2683 const double sf = surface_facette[fa7];
2684
2685 // Boucle sur les sommets
2686 for (int j = 0; j < 3; j++)
2687 {
2688 const int isom = facettes(fa7, j);
2689
2690 double vit_x = vitesse_sommets(isom, 0) - vitesse_translation_sommets(compo, 0);
2691 double vit_y = vitesse_sommets(isom, 1) - vitesse_translation_sommets(compo, 1);
2692 double vit_z = vitesse_sommets(isom, 2) - vitesse_translation_sommets(compo, 2);
2693 Vecteur3 vit = {vit_x, vit_y, vit_z};
2694
2695 double x = sommets(isom, 0);
2696 double y = sommets(isom, 1);
2697 double z = sommets(isom, 2);
2698 Vecteur3 coord_sommet = {x, y, z};
2699
2700 Vecteur3 coord_centre = {centre_gravite(compo,0), centre_gravite(compo,1), centre_gravite(compo,2)};
2701
2702 Vecteur3 radial_position = coord_sommet - coord_centre;
2703
2704 Vecteur3 rotation_vector;
2705 Vecteur3::produit_vectoriel(radial_position, vit, rotation_vector);
2706
2707 // Boucle sur les directions :
2708 for (int dir = 0; dir < 3; dir++)
2709 {
2710 rotation_vector[dir] /= Vecteur3::produit_scalaire(radial_position, radial_position);
2711
2712 mean_bubble_rotation_vector(compo, dir) += rotation_vector[dir] * sf / 3.; // il y a 3 sommets.
2713 }
2714 }
2715 }
2716
2717 mp_sum_for_each_item(mean_bubble_rotation_vector);
2718
2719 for (int icompo = 0; icompo < nbulles_tot; icompo++)
2720 if (surface_par_bulle[icompo] > 0.)
2721 for (int dir = 0; dir < 3; dir++)
2722 mean_bubble_rotation_vector(icompo, dir) /= surface_par_bulle[icompo];
2723}
2724
2725/*! @brief calcul du vecteur normal a l'interface, aux sommets du maillage d'interface.
2726 *
2727 * Le tableau "normale" est efface et resize.
2728 * La normale est la moyenne des normales des facettes voisines, ponderees par
2729 * la surface de la facette.
2730 * La norme du vecteur normal n'est pas unitaire !
2731 * L'espace virtuel n'est pas a jour !
2732 *
2733 */
2734static void calculer_normale_sommets_interface(const Maillage_FT_IJK& maillage,
2735 DoubleTab& normale)
2736{
2737 const int nsom = maillage.nb_sommets();
2738 const int nfaces = maillage.nb_facettes();
2739 const int dim = maillage.sommets().dimension(1);
2740
2741 const ArrOfDouble& surface_facettes = maillage.get_update_surface_facettes();
2742 const DoubleTab& normale_facettes = maillage.get_update_normale_facettes();
2743 const IntTab& facettes = maillage.facettes();
2744 const int nsommets_faces = facettes.dimension(1);
2745
2746 normale.resize(nsom, dim);
2747 normale = 0.;
2748 double n[3] = {0., 0. , 0.};
2749 // La surface autour d'un sommet :
2750 ArrOfDouble surface_environnante(nsom);
2751 surface_environnante = 0.;
2752
2753 for (int i = 0; i < nfaces; i++)
2754 {
2755
2756 // Somme pour les faces reelles:
2757 if (maillage.facette_virtuelle(i))
2758 continue;
2759
2760 const double surface = surface_facettes[i];
2761
2762 for (int k = 0; k < dim; k++)
2763 n[k] = normale_facettes(i, k) * surface;
2764
2765 for (int j = 0; j < nsommets_faces; j++)
2766 {
2767 const int sommet = facettes(i, j);
2768 surface_environnante[sommet] += surface;
2769 for (int k = 0; k < dim; k++)
2770 normale(sommet, k) += n[k];
2771 }
2772 }
2773
2774 // Sommer les contributions pour les sommets partages par plusieurs
2775 // processeurs:
2777 maillage.desc_sommets().collecter_espace_virtuel(surface_environnante, MD_Vector_tools::EV_SOMME);
2778
2779 double norme;
2780 int print = 0;
2781 int count[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
2782 for (int isom = 0; isom < nsom; isom++)
2783 if (!maillage.sommet_virtuel(isom))
2784 {
2785 for (int dir = 0; dir < 3; dir++)
2786 {
2787 if (surface_environnante[isom])
2788 normale(isom, dir) /= surface_environnante[isom];
2789 else
2790 normale(isom, dir) = 0.;
2791 }
2792
2793 norme = normale(isom, 0) * normale(isom, 0) + normale(isom, 1) * normale(isom, 1) +
2794 normale(isom, 2) * normale(isom, 2);
2795 if (norme < 0.9)
2796 {
2797 print = 1;
2798 if (norme < 0.8)
2799 {
2800 if (norme < 0.7)
2801 {
2802 if (norme < 0.6)
2803 {
2804 if (norme < 0.5)
2805 {
2806 if (norme < 0.4)
2807 {
2808 if (norme < 0.3)
2809 {
2810 if (norme < 0.2)
2811 {
2812 if (norme < 0.1)
2813 {
2814 count[0]++;
2815 }
2816 else
2817 {
2818 count[1]++;
2819 }
2820 }
2821 else
2822 {
2823 count[2]++;
2824 }
2825 }
2826 else
2827 {
2828 count[3]++;
2829 }
2830 }
2831 else
2832 {
2833 count[4]++;
2834 }
2835 }
2836 else
2837 {
2838 count[5]++;
2839 }
2840 }
2841 else
2842 {
2843 count[6]++;
2844 }
2845 }
2846 else
2847 {
2848 count[7]++;
2849 }
2850 }
2851 else
2852 {
2853 count[8]++;
2854 }
2855 }
2856 // Cerr << "Som " << isom << " norme " << norme << finl;
2857 }
2858 if (print)
2859 {
2860 Cerr << "IJK_Interfaces.cpp:calculer_normale_sommets_interface : Calcul "
2861 "normale non-unitaire : ";
2862 double sum = 0;
2863 for (int i = 0; i < 9; i++)
2864 {
2865 sum += count[i];
2866 Cerr << " " << count[i] / nsom;
2867 }
2868 Cerr << " " << 1 - sum / nsom << " (nsom = " << nsom << finl;
2869 }
2870}
2871
2873 const DoubleTab& vitesses_translation_bulles,
2874 const DoubleTab& mean_bubble_rotation_vector,
2875 const DoubleTab& centre_gravite,
2876 ArrOfDouble& var_volume)
2877{
2878 Cut_field_vector3_double& cut_field_deformation_velocity = static_cast<Cut_field_vector3_double&>(deformation_velocity_);
2879
2881 const DoubleTab& sommets = mesh.sommets(); // Tableau des coordonnees des marqueurs.
2882 int nbsom = sommets.dimension(0);
2883
2884 const int nbulles_reelles = get_nb_bulles_reelles();
2885 const int nbulles_ghost = get_nb_bulles_ghost();
2886 const int nbulles_tot = nbulles_reelles + nbulles_ghost;
2887
2888 // Initialisations
2889 var_volume.resize(nbsom);
2890 var_volume = 0.;
2891
2893
2895 false,
2896 indicatrice_surfacique_face_ns_[next()], // Pour l'instant, next() est la fin du pas de temps precedent
2900
2901 for (int dir = 0 ; dir < 3 ; dir++)
2902 {
2903 cut_field_deformation_velocity[dir].set_to_uniform_value(6.3e32); // Valeur absurde pour assurer que la valeur par defaut n'est jamais utilisee
2904 }
2905
2906 DoubleTab bounding_box;
2907 calculer_bounding_box_bulles(bounding_box);
2908
2909 // Calcul de la variation de volume cible separement pour chaque bulle.
2910 // En effet, chaque bulle produit une vitesse de deformation differente sur le maillage eulerien.
2911 // Calculer un champ de vitesse de deformation unique devrait restreindre le rapprochement des bulles.
2912 for (int icompo = 0; icompo < nbulles_tot; icompo++)
2913 {
2914 const Probleme_FTD_IJK_cut_cell& ref_ijk_ft_cut_cell_ = ref_cast(Probleme_FTD_IJK_cut_cell, ref_ijk_ft_.valeur());
2915 calculer_vitesse_de_deformation(icompo, bounding_box, ref_ijk_ft_cut_cell_.get_cut_field_velocity(), vitesses_translation_bulles, mean_bubble_rotation_vector, centre_gravite);
2916 //cut_field_deformation_velocity.echange_espace_virtuel(ghost);
2917
2922 cut_field_deformation_velocity,
2924 }
2925
2926 // Transfert des donnees sur la variation de volume cible, du maillage eulerien vers le maillage lagrangien.
2927 // On converti d'abord les donnees sur un DoubleVect du maillage VDF, pour pouvoir utiliser la fonction Transport_Interfaces_FT_Disc::transfert_conservatif_eulerien_vers_lagrangien_sommets.
2928 DoubleVect delta_volume_theorique_bilan_ns_vdf;
2929
2930 {
2931 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, refdomaine_dis_.valeur());
2932 const Domaine& domaine = domaine_vf.domaine();
2933 domaine.creer_tableau_elements(delta_volume_theorique_bilan_ns_vdf);
2934
2935 const int ni = delta_volume_theorique_bilan_ns_.ni();
2936 const int nj = delta_volume_theorique_bilan_ns_.nj();
2937 const int nk = delta_volume_theorique_bilan_ns_.nk();
2938 assert(ni == I_ft().ni());
2939 assert(nj == I_ft().nj());
2940 assert(nk == I_ft().nk());
2941
2942 for (int k = 0; k < nk; k++)
2943 {
2944 for (int j = 0; j < nj; j++)
2945 {
2946 for (int i = 0; i < ni; i++)
2947 {
2948 const int num_elem = ref_domaine_->convert_ijk_cell_to_packed(i, j, k); // Note: ref_domaine_ is a ft_splitting
2949 delta_volume_theorique_bilan_ns_vdf[num_elem] = delta_volume_theorique_bilan_ns_(i,j,k);
2950 }
2951 }
2952 }
2953 }
2954
2955 Transport_Interfaces_FT_Disc::transfert_conservatif_eulerien_vers_lagrangien_sommets(mesh, delta_volume_theorique_bilan_ns_vdf, var_volume);
2956}
2957
2958void IJK_Interfaces::calculer_vecteurs_de_deplacement_rigide(DoubleTab& vitesses_translation_bulles,
2959 DoubleTab& mean_bubble_rotation_vector,
2960 DoubleTab& centre_gravite,
2961 const int first_step_interface_smoothing)
2962{
2964
2965 // compute_vinterp(); // to resize and fill vinterp_
2967 if (first_step_interface_smoothing)
2968 vinterp_ = 0.;
2969
2970 // Les sommets virtuels sont peut-etre trop loin pour pouvoir interpoler leur
2971 // vitesse, il faut faire un echange espace virtuel pour avoir leur vitesse.
2973
2974 // Calcul d'un deplacement preservant la distribution des noeuds sur les
2975 // bulles: Inspiree de :
2976 // Transport_Interfaces_FT_Disc::calculer_vitesse_repere_local
2977
2978 const int nbulles_reelles = get_nb_bulles_reelles();
2979 const int nbulles_ghost = get_nb_bulles_ghost();
2980 const int nbulles_tot = nbulles_reelles + nbulles_ghost;
2981 // dvol.resize_array(nbulles_tot);
2982 // dvol = 0.;
2983 const ArrOfInt& compo_connex = mesh.compo_connexe_facettes();
2984 // assert(compo_connex.size_array() == 0 || min_array(compo_connex) >=0); //
2985 // Les duplicatas ne sont pas presents pendant le transport.
2986 // Nouveau depuis le 13/03/2014 : Les bulles ghost sont autorisees lors du
2987 // transport...
2988 ArrOfDouble surface_par_bulle;
2989 calculer_surface_bulles(surface_par_bulle);
2990 const ArrOfDouble& surface_facette = mesh.get_update_surface_facettes();
2991 // const DoubleTab& normale_facettes = mesh.get_update_normale_facettes();
2992 ArrOfDouble volume_par_bulle(nbulles_tot);
2993 vitesses_translation_bulles.resize(nbulles_tot, 3);
2994 mean_bubble_rotation_vector.resize(nbulles_tot, 3);
2995 centre_gravite.resize(nbulles_tot, 3);
2997 compute_bubbles_volume_and_barycentres(volume_par_bulle, centre_gravite, 1);
2998 else
2999 calculer_volume_bulles(volume_par_bulle, centre_gravite);
3000
3001
3002 // Calcul de la vitesse moyenne de chaque composante connexe :
3004 surface_facette,
3005 surface_par_bulle,
3006 compo_connex,
3007 nbulles_reelles,
3008 nbulles_ghost,
3009 vinterp_,
3010 vitesses_translation_bulles);
3011 bubbles_velocities_ = vitesses_translation_bulles;
3012
3013 if (use_barycentres_velocity_ && ref_ijk_ft_->schema_temps_ijk().get_tstep())
3014 vitesses_translation_bulles = bubbles_velocities_bary_;
3015
3016 // Calcul de la vitesse due a la rotation de chaque composante connexe :
3018 surface_facette,
3019 surface_par_bulle,
3020 compo_connex,
3021 nbulles_reelles,
3022 nbulles_ghost,
3023 centre_gravite,
3024 vinterp_,
3025 vitesses_translation_bulles,
3026 mean_bubble_rotation_vector);
3027
3028 if (first_step_interface_smoothing)
3029 {
3030 vitesses_translation_bulles = 0.;
3031 mean_bubble_rotation_vector = 0.;
3032 }
3033
3034#ifdef GB_VERBOSE
3036 {
3037 // ofstream fout;
3038 // fout.open("composantes_connexes.txt",ios::app);
3039 // fout << "TEMPS: " << "xxxxtempsxxxxx" << endl;
3040 for (int bulle = 0; bulle < nbulles_tot; bulle++)
3041 {
3042 Cerr << "composante " << bulle << " vitesse_translation ";
3043 for (int i = 0; i < 3; i++)
3044 Cerr << " " << vitesses_translation_bulles(bulle, i);
3045 Cerr << " rotation_vector ";
3046 for (int i = 0; i < 3; i++)
3047 Cerr << " " << mean_bubble_rotation_vector(bulle, i);
3048 Cerr << endl;
3049 }
3050 // fout.close();
3051 }
3052#endif
3053}
3054
3055// Valeur par defaut : rk_step = -1 si schema temps different de rk3.
3056// dvol : la variation de volume par bulle au cours du pas de temps.
3057// Cette methode est a present capable de transporter aussi les bulles ghost.
3058// Pre-requis : il faut que le tableau dvol soit bien dimensionne a nbulles_tot
3059// La fonction transporter_maillage a ete separee en trois pour inserer un
3060// calcul de l'indicatrice entre les differentes etapes.
3061// Cette fonction realise la partie deformation uniquement, ou dans ce cadre
3062// la deformation est la partie residuelle du mouvement lorsque translation
3063// et rotation solide sont retranchees au mouvement total.
3064void IJK_Interfaces::transporter_maillage_deformation(const int correction_semi_locale_volume_bulle,
3065 const DoubleTab& vitesses_translation_bulles,
3066 const DoubleTab& mean_bubble_rotation_vector,
3067 const DoubleTab& centre_gravite,
3068 const double dt_tot,
3069 ArrOfDouble& dvol,
3070 const int rk_step = -1,
3071 const int first_step_interface_smoothing)
3072{
3073 // nouvelle version:
3075 const DoubleTab& sommets = mesh.sommets(); // Tableau des coordonnees des marqueurs.
3076 int nbsom = sommets.dimension(0);
3077 DoubleTab deplacement(nbsom, 3);
3078
3079 // On suppose que vinterp_ est deja rempli
3080
3081 // Calcul d'un deplacement preservant la distribution des noeuds sur les
3082 // bulles: Inspiree de :
3083 // Transport_Interfaces_FT_Disc::calculer_vitesse_repere_local
3084
3085 const int nbulles_reelles = get_nb_bulles_reelles();
3086 const int nbulles_ghost = get_nb_bulles_ghost();
3087 const int nbulles_tot = nbulles_reelles + nbulles_ghost;
3088 // dvol.resize_array(nbulles_tot);
3089 // dvol = 0.;
3090 // assert(compo_connex.size_array() == 0 || min_array(compo_connex) >=0); //
3091 // Les duplicatas ne sont pas presents pendant le transport.
3092 // Nouveau depuis le 13/03/2014 : Les bulles ghost sont autorisees lors du
3093 // transport...
3094 // const DoubleTab& normale_facettes = mesh.get_update_normale_facettes();
3095 ArrOfIntFT compo_connex_som;
3096 mesh.calculer_compo_connexe_sommets(compo_connex_som);
3097
3098
3099 // Calcul des normales (non-unitaire, espace virtuel pas a jour) aux sommets :
3100 DoubleTabFT normale_sommet;
3101 calculer_normale_sommets_interface(mesh, normale_sommet);
3102
3103 for (int som = 0; som < nbsom; som++)
3104 {
3105 if (mesh.sommet_virtuel(som))
3106 {
3107 // Valeur pipo pour dire qu'on n'initialise pas
3108 deplacement(som, 0) = 100.;
3109 deplacement(som, 1) = 100.;
3110 deplacement(som, 2) = 100.;
3111 vinterp_(som, 0) = 100. / dt_tot;
3112 vinterp_(som, 1) = 100. / dt_tot;
3113 vinterp_(som, 2) = 100. / dt_tot;
3114 continue;
3115 }
3116
3117 int icompo = compo_connex_som[som];
3118 // Les bulles dupliquees sont a la fin
3119 // La premiere (numero -1) est a la position nbulles_reelles :
3120 if (icompo < 0)
3121 {
3122 // L'index de la bulle ghost est (entre -1 et -nbulles_ghost):
3123 const int idx_ghost = get_ghost_number_from_compo(icompo);
3124 // On la place en fin de tableau :
3125 icompo = nbulles_reelles - 1 - idx_ghost;
3126 }
3127 assert(icompo >= 0);
3128 assert(icompo < nbulles_tot);
3129
3130 // (v-vmoy) doit etre normal a l'interface
3131 // Donc on fait v_corrige = v_initial -
3132 // composante_tangentielle_de(v_initial-vmoy) Demonstration que (v_corrige -
3133 // vmoy) est normal a l'interface : On note ct() =
3134 // composante_tangentielle_de() ct(v_corrige - vmoy)
3135 // = ct(v_corrige) - ct(vmoy) car ct est lineaire
3136 // = ct(v_initial - ct(v_initial) + ct(vmoy)) - ct(vmoy) car ct
3137 // est lineaire = ct(v_initial) - ct(v_initial) + ct(vmoy) - ct(vmoy) cat
3138 // ct(ct(x)) = ct(x) et linearite = 0
3139
3140 // v_corrige = cn(v_initial - vmoy) + vmoy
3141 // v_corrige = cn(v_initial) - cn(vmoy) + vmoy
3142 // v_corrige = cn(v_initial) + ct(vmoy)
3143 // v_corrige = v_initial - ct(v_inital) + ct(vmoy)
3144 // v_corrige = v_initial - ct(v_initial - vmoy)
3145
3146 double rot_x = mean_bubble_rotation_vector(icompo, 0);
3147 double rot_y = mean_bubble_rotation_vector(icompo, 1);
3148 double rot_z = mean_bubble_rotation_vector(icompo, 2);
3149 Vecteur3 rot = {rot_x, rot_y, rot_z};
3150
3151 double x = sommets(som, 0);
3152 double y = sommets(som, 1);
3153 double z = sommets(som, 2);
3154 Vecteur3 coord_sommet = {x, y, z};
3155
3156 Vecteur3 coord_centre = {centre_gravite(icompo,0), centre_gravite(icompo,1), centre_gravite(icompo,2)};
3157
3158 Vecteur3 radial_position = coord_sommet - coord_centre;
3159
3160 Vecteur3 tangential_velocity;
3161 Vecteur3::produit_vectoriel(rot, radial_position, tangential_velocity);
3162
3163 double prodscal = 0.;
3164 double norme_carre = 0.;
3165 for (int direction = 0; direction < 3; direction++)
3166 {
3167 double vi = vinterp_(som, direction);
3168 double vcompo = vitesses_translation_bulles(icompo, direction) + tangential_velocity[direction];
3169 double n = normale_sommet(som, direction);
3170 prodscal += (vi - vcompo) * n;
3171 norme_carre += n * n;
3172 }
3173 if (norme_carre)
3174 prodscal /= norme_carre;
3175 else
3176 prodscal = 0.;
3177
3178 for (int direction = 0; direction < 3; direction++)
3179 {
3180 double n = normale_sommet(som, direction);
3181 // On enregirste la vitesse avec laquelle on souhaite deplacer les
3182 // marqueurs :
3183
3184 if (correction_semi_locale_volume_bulle)
3185 {
3186 // Correction semi-locale du volume : on effectue une deformation de la bulle uniquement (la partie rigide du deplacement est realisee apres le remaillage).
3187 vinterp_(som, direction) = n * prodscal;
3188 }
3189 else
3190 {
3191 // Comportement par defaut (sans la correction semi-locale du volume) : on effectue un deplacement complet des marqueurs lagrangiens.
3192 vinterp_(som, direction) = n * prodscal + vitesses_translation_bulles(icompo, direction);
3193 }
3194 }
3195 }
3196
3197 // Transport conservant le volume des bulles:
3198 // On va transporter avec la vitesse interpolee,
3199 // calculer la variation de volume de chaque bulle engendree par le
3200 // deplacement, calculer une correction de volume a appliquer a chaque sommet
3201 // pour retrouver le volume initial appeler le barycentrage_lissage avec la
3202 // correction de volume a appliquer
3203
3204 // On met zero dans le tableau RK3_G_store_vi_
3205 if (rk_step == 0)
3206 {
3207 RK3_G_store_vi_.resize(nbsom, 3);
3208 RK3_G_store_vi_ *= 0.;
3210 }
3211
3212 // On remplit le tableau de deplacement
3213 if (rk_step >= 0)
3214 {
3215 // Attention vinterp_ n'est pas a jour sur les sommets virtuels car il y a
3216 // un continue dans la boucle precedente
3217 // Ce n'est pas grave pour le tableau deplacement car il ne sert qu'aux
3218 // sommets reels... Par contre, vinterp peut etre stockee dans
3219 // RK3_G_store_vi_ qui ne sera donc pas a jour pour les sommets virtuels.
3220#ifdef GB_VERBOSE
3221 Journal() << "RKSTEP " << rk_step << finl;
3222 for (int i = 0; i < nbsom; i++)
3223 {
3224 Journal() << " Som " << i << " virt " << mesh.sommet_virtuel(i) << " depl ";
3225 for (int direction = 0; direction < 3; direction++)
3226 {
3227 Journal() << vinterp(i, direction) << " ";
3228 }
3229 Journal() << " RK3_G_store_vi_ ";
3230 for (int direction = 0; direction < 3; direction++)
3231 {
3232 Journal() << RK3_G_store_vi_(i, direction) << " ";
3233 }
3234 Journal() << finl;
3235 }
3236#endif
3237 // Pas necessaire de mettre a jour l'EV car le transport n'utilise pas les
3238 // sommets virt :
3239 // mesh.desc_sommets().echange_espace_virtuel(vinterp);
3240 runge_kutta3_update(vinterp_, RK3_G_store_vi_, deplacement, rk_step, dt_tot, mesh);
3241
3242 // La mise a jour de l'espace virt me semble inutile car mesh.transporter ne
3243 // deplace que les sommets reels
3244 // mesh.desc_sommets().echange_espace_virtuel(RK3_G_store_vi_);
3245
3246 // On vide l'espace virtuel avant le transport :
3248 }
3249 else
3250 {
3251 // Schema Euler :
3252 for (int som = 0; som < nbsom; som++)
3253 for (int direction = 0; direction < 3; direction++)
3254 deplacement(som, direction) = vinterp_(som, direction) * dt_tot;
3255 }
3256
3257 // MaJ de l'EV par precaution pour le post-pro (et peut-etre calcul distance?)
3259
3260 // Copie des coordonnees des sommets avant deplacement
3261 DoubleTab coord_sommets_avant_deplacement(mesh.sommets());
3262 mesh.preparer_tableau_avant_transport(coord_sommets_avant_deplacement, mesh.desc_sommets());
3264
3266 {
3267 //supprimer_duplicata_bulles();
3268 //maillage_ft_ijk_.parcourir_maillage();
3269 FT_Field& Surfactant = mesh.Surfactant_facettes_non_const();
3270 ArrOfDouble surfactant_avant_remaillage = Surfactant.check_conservation(mesh);
3271 Surfactant.passer_variable_intensive(mesh);
3272
3273 mesh.transporter(deplacement);
3274 double dt = dt_tot;
3275 if (rk_step >= 0)
3276 {
3277 dt = compute_fractionnal_timestep_rk3(dt_tot, rk_step);
3278 }
3279 Surfactant.avancer_en_temps(mesh, dt);
3280 Surfactant.passer_variable_extensive(mesh);
3281 ArrOfDouble surfactant_apres_remaillage = Surfactant.check_conservation(mesh);
3282 Surfactant.correction_conservation_globale(mesh, surfactant_avant_remaillage, surfactant_apres_remaillage);
3283 //transferer_bulle_perio();
3284 //creer_duplicata_bulles();
3285 //maillage_ft_ijk_.parcourir_maillage();
3286 }
3287 else
3288 {
3289 mesh.transporter(deplacement);
3290 }
3291
3292
3293 nbsom = sommets.dimension(0); // Le deplacement a peut-etre cree des sommets...
3294 mesh.update_tableau_apres_transport(coord_sommets_avant_deplacement, nbsom, mesh.desc_sommets());
3296
3297 if (rk_step >= 0)
3298 {
3299 // on fait du RK3 :
3301 // L'update fini par l'echange EV
3302 // mesh.desc_sommets().echange_espace_virtuel(RK3_G_store_vi_);
3303 }
3304
3306 {
3307 //mesh.nettoyer_maillage();
3308 //supprimer_duplicata_bulles();
3309 //mesh.parcourir_maillage();
3310 nbsom = sommets.dimension(0); // Le deplacement a peut-etre cree des sommets...
3311 }
3312
3313 // Tableau aux sommets :
3314 var_volume_deformation_.resize(nbsom);
3316 remaillage_ft_ijk_.calculer_variation_volume(mesh, coord_sommets_avant_deplacement, var_volume_deformation_);
3317
3318 // Comportement par defaut (sans la correction semi-locale du volume) :
3319 // L'effet du transport sur le volume des bulles est ajoute a dvol, ce qui sera pris en compte lors de la correction globale du volume (au remaillage)
3320 // Avec la correction semi-locale du volume, seul la variation par sommet est utile (var_volume_deformation_), et ce bloc n'est donc pas execute.
3321 if (!correction_semi_locale_volume_bulle)
3322 {
3323 // Tableau par compo connexe (integrale sur chaque bulle de la var volume au
3324 // cours du sous pas de temps : (la variation totale integree au cours du pas
3325 // de temps est dans dvol)
3326 ArrOfDouble var_volume_par_bulle(nbulles_tot);
3327
3328 // On recalcule certaines grandeurs apres le deplacement :
3329 mesh.calculer_compo_connexe_sommets(compo_connex_som);
3330
3331 for (int isom = 0; isom < nbsom; isom++)
3332 {
3333 // Ne prendre que les sommets reels (sinon on les compte plusieurs fois)
3334 if (mesh.sommet_virtuel(isom))
3335 continue;
3336
3337 int compo = compo_connex_som[isom];
3338 // Les bulles dupliquees sont a la fin
3339 // La premiere (numero -1) est a la position nbulles_reelles :
3340 if (compo < 0)
3341 {
3342 // L'index de la bulle ghost est (entre -1 et -nbulles_ghost):
3343 const int idx_ghost = get_ghost_number_from_compo(compo);
3344 // On la place en fin de tableau :
3345 compo = nbulles_reelles - 1 - idx_ghost;
3346 }
3347 assert(compo >= 0);
3348 assert(compo < nbulles_tot);
3349
3350 const double v = var_volume_deformation_[isom];
3351 var_volume_par_bulle[compo] += v;
3352 }
3353 mp_sum_for_each_item(var_volume_par_bulle);
3354 // Mise a jour de la variation totale de volume au cours du pas de temps :
3355 // (necessaire meme en euler. Si euler, on y passe qu'une fois)
3356 // if (rk_step >=0) {
3357 for (int icompo = 0; icompo < nbulles_tot; icompo++)
3358 {
3359 dvol[icompo] += var_volume_par_bulle[icompo];
3360 }
3361 // }
3362 }
3363}
3364
3365// La fonction transporter_maillage a ete separee en trois pour inserer un
3366// calcul de l'indicatrice entre les differentes etapes.
3367// Cette fonction realise le remaillage uniquement. Elle suppose que la
3368// fonction transporter_maillage_deformation a ete precedemment appelee pour
3369// realiser le deplacement et remplir dvol en entree.
3370void IJK_Interfaces::transporter_maillage_remaillage(int correction_semi_locale_volume_bulle,
3371 const DoubleTab& vitesses_translation_bulles,
3372 const DoubleTab& mean_bubble_rotation_vector,
3373 const DoubleTab& centre_gravite,
3374 double dt_tot,
3375 ArrOfDouble& dvol,
3376 const int rk_step = -1,
3377 const double temps = -1 /*pas de remaillage*/)
3378{
3380 const DoubleTab& sommets = mesh.sommets(); // Tableau des coordonnees des marqueurs.
3381 int nbsom = sommets.dimension(0);
3382
3383 if (correction_semi_locale_volume_bulle)
3384 {
3385 const double fractionnal_timestep = (rk_step == -1) ? dt_tot : compute_fractionnal_timestep_rk3(dt_tot, rk_step);
3386 calculer_var_volume_remaillage(fractionnal_timestep, vitesses_translation_bulles, mean_bubble_rotation_vector, centre_gravite, var_volume_remaillage_);
3387
3388 // Peut-etre que des sommets virtuels ont ete ajoutees (par le parcours de l'interface), mais je pense que le nombre de sommets reels n'a pas change.
3389 // Mise-a-jour du tableau var_volume_deformation_ pour cette eventualite :
3390 var_volume_deformation_.resize(nbsom);
3391 maillage_ft_ijk_.desc_sommets().echange_espace_virtuel(var_volume_deformation_);
3392
3394 }
3395 else
3396 {
3397 var_volume_remaillage_.resize(nbsom);
3399 }
3400
3401 var_volume_correction_globale_.resize(nbsom);
3403
3404 ArrOfDouble surface_par_bulle;
3405
3406 const int nbulles_reelles = get_nb_bulles_reelles();
3407
3408 const ArrOfInt& compo_connex_apres_transport = mesh.compo_connexe_facettes();
3409 calculer_surface_bulles(surface_par_bulle);
3410 const ArrOfDouble& surface_facette_apres_transport = mesh.get_update_surface_facettes();
3411
3412 // Calculer une variation de volume a imposer sur chaque sommet pour conserver
3413 // le volume des bulles (necessaire si euler, cad rk_step = -1 ou si dernier
3414 // sous pas de rk3) On ne fait la correction qu'au dernier sous pas de temps
3415 // car on ne veut pas appliquer le lissage
3416 // au cours des sous pas de temps intermediaires car cela detruirait
3417 // RK3_G_store_vi_. En effet, le lissage barycentrage deplace les sommets,
3418 // donc en parallele il y a des sommets qui changent de proc, donc creation
3419 // destruction d'entrees dans les tableaux
3420 if ((rk_step == -1) || (rk_step == 2))
3421 {
3422 const int nb_facettes = mesh.nb_facettes();
3423 const IntTab& facettes = mesh.facettes();
3424 for (int i = 0; i < nb_facettes; i++)
3425 {
3426 // Ignorer les facettes virtuelles
3427 if (mesh.facette_virtuelle(i))
3428 continue;
3429 int compo = compo_connex_apres_transport[i];
3430 // Les bulles dupliquees sont a la fin
3431 if (compo < 0)
3432 {
3433 // L'index de la bulle ghost est (entre -1 et -nbulles_ghost):
3434 const int idx_ghost = get_ghost_number_from_compo(compo);
3435 // On la place en fin de tableau :
3436 compo = nbulles_reelles - 1 - idx_ghost;
3437 }
3438 const double var_volume_tot = dvol[compo];
3439 const double surface_bulle = surface_par_bulle[compo];
3440 const double s = surface_facette_apres_transport[i];
3441 const double dv = var_volume_tot * s / (surface_bulle * 3.);
3442 for (int j = 0; j < 3; j++)
3443 {
3444 const int isom = facettes(i, j);
3445 var_volume_correction_globale_[isom] -= dv; // Signe negatif car on veut annuler la variation de volume
3446 // engendree par le transport
3447 }
3448 }
3449 // Sommer les contributions mises sur les sommets virtuels:
3452 }
3453
3454 RK3_G_store_vi_.resize(mesh.nb_sommets(), 3);
3455
3457
3458 // Au dernier pas de temps rk3 ou au pas de temps euler : on lisse et on
3459 // nettoie :
3460 if ((rk_step == -1) || (rk_step == 2))
3461 {
3462 // ca passe meme en laissant les ghost_bulles lors du lissage...car le
3463 // Domaine_VF sous-jacent est sur DOM_EXT.
3464 // Attention : s'il faut les supprimer, le tableau var_volume_remaillage_ n'est alors
3465 // plus valide (nombre de sommet a change).
3467 // remaillage_ft_ijk_.barycentrer_lisser_systematique_ijk(mesh, var_volume_remaillage_);
3468 mesh.nettoyer_maillage();
3469 // A partir d'ici, le tableau n'est plus valide donc on le reduit a 0 :
3470 RK3_G_store_vi_.resize(0, 3);
3471 }
3472
3474 {
3475 //Apres remaillage, recalculer les gradient, laplacien FT
3476 //mesh.nettoyer_maillage();
3477 //creer_duplicata_bulles();
3478 //mesh.parcourir_maillage();
3481
3482 }
3483
3484
3485
3486 const int nbsom_end_transport = mesh.nb_sommets();
3487 const int size_store = RK3_G_store_vi_.dimension(0);
3488 if (!((nbsom_end_transport == size_store) || (0 == size_store)))
3489 {
3490 Cerr << "Une des tailles de tableau n'est pas bonne... "
3491 << " size_store = " << size_store
3492 << " nbsom_end_transport = " << nbsom_end_transport
3493 << finl;
3494 Process::exit();
3495 }
3496
3497 assert((mesh.nb_sommets() == RK3_G_store_vi_.dimension(0)) || (0 == RK3_G_store_vi_.dimension(0)));
3498}
3499
3500// La fonction transporter_maillage a ete separee en trois pour inserer un
3501// calcul de l'indicatrice entre les differentes etapes.
3502// Cette fonction realise le deplacement rigide (indeformable) uniquement.
3503// Il est normalement effectue en dernier, apres la deformation et le remaillage
3504// de la bulle.
3506 const DoubleTab& vitesses_translation_bulles,
3507 const DoubleTab& mean_bubble_rotation_vector,
3508 const DoubleTab& centre_gravite,
3509 const int rk_step,
3510 const int first_step_interface_smoothing)
3511{
3512 // nouvelle version:
3514 const DoubleTab& sommets = mesh.sommets(); // Tableau des coordonnees des marqueurs.
3515 int nbsom = sommets.dimension(0);
3516 DoubleTab deplacement(nbsom, 3);
3517
3518 const int nbulles_reelles = get_nb_bulles_reelles();
3519
3520 ArrOfIntFT compo_connex_som;
3521 mesh.calculer_compo_connexe_sommets(compo_connex_som);
3522
3523 for (int som = 0; som < nbsom; som++)
3524 {
3525 if (mesh.sommet_virtuel(som))
3526 {
3527 // Valeur pipo pour dire qu'on n'initialise pas
3528 deplacement(som, 0) = 100.;
3529 deplacement(som, 1) = 100.;
3530 deplacement(som, 2) = 100.;
3531 continue;
3532 }
3533
3534 int icompo = compo_connex_som[som];
3535 // Les bulles dupliquees sont a la fin
3536 // La premiere (numero -1) est a la position nbulles_reelles :
3537 if (icompo < 0)
3538 {
3539 // L'index de la bulle ghost est (entre -1 et -nbulles_ghost):
3540 const int idx_ghost = get_ghost_number_from_compo(icompo);
3541 // On la place en fin de tableau :
3542 icompo = nbulles_reelles - 1 - idx_ghost;
3543 }
3544 assert(icompo >= 0);
3545 assert(icompo < nbulles_reelles + get_nb_bulles_ghost());
3546
3547 double rot_x = mean_bubble_rotation_vector(icompo, 0);
3548 double rot_y = mean_bubble_rotation_vector(icompo, 1);
3549 double rot_z = mean_bubble_rotation_vector(icompo, 2);
3550 Vecteur3 rot = {rot_x, rot_y, rot_z};
3551
3552 double x = sommets(som, 0);
3553 double y = sommets(som, 1);
3554 double z = sommets(som, 2);
3555 Vecteur3 coord_sommet = {x, y, z};
3556
3557 Vecteur3 coord_centre = {centre_gravite(icompo,0), centre_gravite(icompo,1), centre_gravite(icompo,2)};
3558
3559 Vecteur3 radial_position = coord_sommet - coord_centre;
3560
3561 Vecteur3 tangential_velocity;
3562 Vecteur3::produit_vectoriel(rot, radial_position, tangential_velocity);
3563
3564 for (int direction = 0; direction < 3; direction++)
3565 {
3566 const double fractionnal_timestep = (rk_step == -1) ? dt_tot : compute_fractionnal_timestep_rk3(dt_tot, rk_step);
3567 deplacement(som, direction) = (vitesses_translation_bulles(icompo, direction) + tangential_velocity[direction]) * fractionnal_timestep;
3568 }
3569 }
3570
3571 mesh.transporter(deplacement);
3572}
3573
3574// Voir Topologie_Maillage_FT::remailler_interface pour l'original.
3576 Maillage_FT_IJK& maillage,
3577 ArrOfDouble& var_volume,
3578 Remaillage_FT_IJK& algo_remaillage_local)
3579{
3580 // Le remaillage qui suit le traitement des coalescences peut a nouveau
3581 // produire un maillage impropre (avec des facettes qui se coupent).
3582 // Dans ce cas, on s'arrete apres le traitement des coalescences.
3583
3584 // Note B.M. : le remaillag systematique peut retarder la necessite de
3585 // remailler localement (apparition de grandes ou petites aretes). Donc
3586 // je le fais d'abord, et ensuite je teste s'il faut faire un remaillage
3587 // local.
3588 // L'intervalle de temps entre deux lissages est-il ecoule ?
3589 // if (algo_remaillage_local.a_lisser(temps))
3590 // {
3591 // On a choisi de lisser systematique :
3592 if (!maillage_ft_ijk_.Surfactant_facettes().get_only_remaillage())
3593 algo_remaillage_local.barycentrer_lisser_systematique_ijk(maillage, var_volume);
3594
3595 // L'intervalle de temps entre deux remaillages locaux est-il ecoule:
3596 if (algo_remaillage_local.a_remailler(temps, maillage))
3597 {
3598 // Declanchement d'un remaillage local.
3599 // Pour que ca marche bien, les parametres de barycentrage et lissage
3600 // "apres_remaillage" doivent etre suffisants pour ramener le maillage dans
3601 // un etat correct sans appliquer de lissage systematique apres
3602 algo_remaillage_local.remaillage_local_interface(temps, maillage);
3603 }
3604}
3605
3607 int compo,
3608 const DoubleTab& bounding_box_bulles,
3609 const Cut_field_vector3_double& cut_field_velocity,
3610 const DoubleTab& vitesses_translation_bulles,
3611 const DoubleTab& mean_bubble_rotation_vector,
3612 const DoubleTab& positions_bulles)
3613{
3614 Cut_field_vector3_double& cut_field_deformation_velocity = static_cast<Cut_field_vector3_double&>(deformation_velocity_);
3615 assert(&cut_field_deformation_velocity[0].get_cut_cell_disc() == &cut_field_deformation_velocity[1].get_cut_cell_disc());
3616 assert(&cut_field_deformation_velocity[0].get_cut_cell_disc() == &cut_field_deformation_velocity[2].get_cut_cell_disc());
3617 const Cut_cell_FT_Disc& cut_cell_disc = cut_field_deformation_velocity[0].get_cut_cell_disc();
3618
3619 const int ni = cut_field_deformation_velocity[0].ni();
3620 const int nj = cut_field_deformation_velocity[0].nj();
3621 const int nk = cut_field_deformation_velocity[0].nk();
3622 const int ghost = cut_field_deformation_velocity[0].ghost();
3623
3624 const Domaine_IJK& geom = cut_field_deformation_velocity[0].get_domaine();
3625 assert(geom.is_uniform(0));
3626 assert(geom.is_uniform(1));
3627 assert(geom.is_uniform(2));
3628
3629 const double dx = geom.get_constant_delta(DIRECTION_I);
3630 const double dy = geom.get_constant_delta(DIRECTION_J);
3631 const double dz = geom.get_constant_delta(DIRECTION_K);
3632
3633 double origin_x = geom.get_origin(DIRECTION_I);
3634 double origin_y = geom.get_origin(DIRECTION_J);
3635 double origin_z = geom.get_origin(DIRECTION_K);
3636
3637 const int offset_x = geom.get_offset_local(DIRECTION_I);
3638 const int offset_y = geom.get_offset_local(DIRECTION_J);
3639 const int offset_z = geom.get_offset_local(DIRECTION_K);
3640
3641 int imin = std::max(-ghost, (int)((bounding_box_bulles(compo, 0, 0) - origin_x)/dx - offset_x - 2));
3642 int imax = std::min(ni + ghost, (int)((bounding_box_bulles(compo, 0, 1) - origin_x)/dx - offset_x + 2));
3643 int jmin = std::max(-ghost, (int)((bounding_box_bulles(compo, 1, 0) - origin_y)/dy - offset_y - 2));
3644 int jmax = std::min(nj + ghost, (int)((bounding_box_bulles(compo, 1, 1) - origin_y)/dy - offset_y + 2));
3645 int kmin = std::max(-ghost, (int)((bounding_box_bulles(compo, 2, 0) - origin_z)/dz - offset_z - 2));
3646 int kmax = std::min(nk + ghost, (int)((bounding_box_bulles(compo, 2, 1) - origin_z)/dz - offset_z + 2));
3647 for (int k = kmin; k < kmax; k++)
3648 {
3649 for (int j = jmin; j < jmax; j++)
3650 {
3651 for (int i = imin; i < imax; i++)
3652 {
3653 const double x_centre_cell = (i + offset_x + .5)*dx + origin_x;
3654 const double y_centre_cell = (j + offset_y + .5)*dy + origin_y;
3655 const double z_centre_cell = (k + offset_z + .5)*dz + origin_z;
3656
3657 double rot_x = mean_bubble_rotation_vector(compo, 0);
3658 double rot_y = mean_bubble_rotation_vector(compo, 1);
3659 double rot_z = mean_bubble_rotation_vector(compo, 2);
3660 Vecteur3 rot = {rot_x, rot_y, rot_z};
3661
3662 int n = cut_cell_disc.get_n(i,j,k);
3663 if (n >= 0)
3664 {
3665 for (int phase = 0 ; phase < 2 ; phase++)
3666 {
3667 double x_cut_cell = x_centre_cell - .5*dx + dx*cut_cell_disc.get_interfaces().get_barycentre(1, 0, phase, i,j,k);
3668 double y_cut_cell = y_centre_cell - .5*dy + dy*cut_cell_disc.get_interfaces().get_barycentre(1, 1, phase, i,j,k);
3669 double z_cut_cell = z_centre_cell - .5*dz + dz*cut_cell_disc.get_interfaces().get_barycentre(1, 2, phase, i,j,k);
3670
3671 Vecteur3 coord = {x_cut_cell, y_cut_cell, z_cut_cell};
3672
3673 Vecteur3 coord_centre = {positions_bulles(compo,0), positions_bulles(compo,1), positions_bulles(compo,2)};
3674
3675 Vecteur3 radial_position = coord - coord_centre;
3676
3677 Vecteur3 tangential_velocity;
3678 Vecteur3::produit_vectoriel(rot, radial_position, tangential_velocity);
3679
3680 for (int direction = 0; direction < 3; direction++)
3681 {
3682 const DoubleTabFT_cut_cell& diph_velocity = (phase == 0) ? cut_field_velocity[direction].diph_v_ : cut_field_velocity[direction].diph_l_;
3683 DoubleTabFT_cut_cell& deformation_diph_velocity = (phase == 0) ? cut_field_deformation_velocity[direction].diph_v_ : cut_field_deformation_velocity[direction].diph_l_;
3684 deformation_diph_velocity(n) = diph_velocity(n) - vitesses_translation_bulles(compo, direction) - tangential_velocity[direction];
3685 }
3686 }
3687 }
3688 else
3689 {
3690 Vecteur3 coord = {x_centre_cell, y_centre_cell, z_centre_cell};
3691
3692 Vecteur3 coord_centre = {positions_bulles(compo,0), positions_bulles(compo,1), positions_bulles(compo,2)};
3693
3694 Vecteur3 radial_position = coord - coord_centre;
3695
3696 Vecteur3 tangential_velocity;
3697 Vecteur3::produit_vectoriel(rot, radial_position, tangential_velocity);
3698
3699 for (int direction = 0; direction < 3; direction++)
3700 {
3701 cut_field_deformation_velocity[direction].pure_(i,j,k) = cut_field_velocity[direction].pure_(i,j,k) - vitesses_translation_bulles(compo, direction) - tangential_velocity[direction];
3702 }
3703 }
3704 }
3705 }
3706 }
3707}
3708
3709// bounding_box(b,dir,m) :
3710// b -> Numero de la composante connexe de la bulle.
3711// dir -> Direction i,j ou k.
3712// m -> min (0) ou max (1)
3713void IJK_Interfaces::calculer_bounding_box_bulles(DoubleTab& bounding_box, int option_shear) const
3714{
3715 const int nbulles = get_nb_bulles_reelles();
3716 bounding_box.resize(nbulles, 3, 2);
3717
3718 int direction;
3719 // Initialisation avec des valeurs inatteignables :
3720 const double inval = 1.e20;
3721 bounding_box = inval;
3722
3723 // Puis on parcours le maillage :
3724 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
3725 ArrOfIntFT compo_connex_som;
3726 mesh.calculer_compo_connexe_sommets(compo_connex_som);
3727 const DoubleTab& sommets = mesh.sommets(); // Tableau des coordonnees des marqueurs.
3728 const int nbsom = sommets.dimension(0);
3729 ArrOfDouble volume_reel;
3730 DoubleTab position;
3731 calculer_volume_bulles(volume_reel, position);
3732
3733 ArrOfDouble position_xmax_compo;
3734 ArrOfDouble position_xmin_compo;
3735 if (option_shear != 0 && IJK_Shear_Periodic_helpler::defilement_ == 1)
3736 {
3737 position_xmax_compo.resize_array(nbulles, RESIZE_OPTIONS::NOCOPY_NOINIT);
3738 position_xmin_compo.resize_array(nbulles, RESIZE_OPTIONS::NOCOPY_NOINIT);
3739 position_xmax_compo = -10000.;
3740 position_xmin_compo = 10000.;
3741
3742 for (int i_sommet2 = 0; i_sommet2 < nbsom; i_sommet2++)
3743 {
3744 int iconnex = compo_connex_som[i_sommet2];
3745 double coord = sommets(i_sommet2, 0);
3746 if (coord>position_xmax_compo[iconnex])
3747 position_xmax_compo[iconnex] = coord;
3748 if (coord<position_xmin_compo[iconnex])
3749 position_xmin_compo[iconnex] = coord;
3750 }
3751 mp_min_for_each_item(position_xmin_compo);
3752 mp_max_for_each_item(position_xmax_compo);
3753 }
3754
3755 for (int i_sommet = 0; i_sommet < nbsom; i_sommet++)
3756 {
3757 for (direction=0; direction<3; direction++)
3758 {
3759 double coord = sommets(i_sommet, direction);
3760 int iconnex = compo_connex_som[i_sommet];
3761
3762 if (direction==0 && option_shear != 0 && IJK_Shear_Periodic_helpler::defilement_ == 1)
3763 {
3764 // position du barycentre de la bulle de reference a laquelle appartient le sommet
3765 double pos_ref = position(iconnex,0);
3766 //const Domaine_IJK& split = ref_domaine_.valeur();
3768 //double Lx = split.get_domain_length(0) - (position_xmax_compo(iconnex)-pos_ref);
3769 double offset = option_shear * IJK_Shear_Periodic_helpler::shear_x_time_;
3770 // le barycentre de la bulle reelle (compo >0) est situe entre db et Lx + db (pas entre 0 et Lx)
3771 // vrai uniquement pour des bulles qui montent.
3772 // Ne fonctionnera pas pour des bulles descendantes...
3773 // Idem donc pour la bulle ghost
3774 double decallage_bulle_reel_ext_domaine_reel = 1.*(position_xmax_compo[iconnex]-position_xmin_compo[iconnex]); // verifier si cest ca la valeur
3775 // assure une position entre db et Lx + db --> vrai que pour une bulle qui monte....
3776 // Si la bulle descend, risque de ne pas fonctionner --> il faudrait assurer une position entre -db et Lx+db ?
3777 double pos = std::fmod(std::fmod(pos_ref + offset - decallage_bulle_reel_ext_domaine_reel, Lx) + Lx, Lx) + decallage_bulle_reel_ext_domaine_reel;
3778 // Tous les sommets d'une meme bulle deplaces de la meme maniere sur x
3779 coord += (pos - pos_ref);
3780 }
3781
3782
3783
3784 if (iconnex >= 0)
3785 {
3786 double mmin = bounding_box(iconnex, direction, 0);
3787 double mmax = -bounding_box(iconnex, direction, 1);
3788 if (coord < mmin)
3789 bounding_box(iconnex, direction, 0) = coord; // Un nouveau min est trouve.
3790 if (coord > mmax)
3791 bounding_box(iconnex, direction, 1) = -coord; // Un nouveau max est trouve. On stock son oppose
3792 }
3793 else
3794 {
3795 // le sommet n'appartient a aucune facette sur ce processeur, il est pris en compte sur un autre proc,
3796 // on ne fait rien.
3797 }
3798 }
3799 }
3800 // Communication inter-proc pour trouver les vrais limites :
3801 mp_min_for_each_item(bounding_box);
3802 for (int ibulle = 0; ibulle < nbulles; ibulle++)
3803 for (direction = 0; direction < 3; direction++)
3804 bounding_box(ibulle, direction, 1) = -bounding_box(ibulle, direction, 1); // a present on a le max.
3805
3806}
3807
3808// Methode pour creer les duplication de bulles lorsquelles sorte du
3809// domaine NS et entrent dans le domaine geom_FT...
3811{
3812 // Evaluation du cube contenant chaque bulle :
3813 DoubleTab bounding_box;
3814 calculer_bounding_box_bulles(bounding_box);
3815 ArrOfInt masque_duplicata_pour_compo_reel;
3816
3817 // Pour chaque compo_connexe, remplir dans le tableau
3818 // masque_duplicata_pour_compo_reel un encodage du deplacement maximal pour toutes
3819 // les bulles reelles qui sortent de NS: Le critere pour declancher la duplication des
3820 // bulles est bounding_box_duplicate_criteria_
3821 // Pour les conditions shear-periodic, besoin d'un autre
3822 // masque_duplicata_pour_compo_ghost, un encodage du deplacement maximal pour toutes
3823 // les bulles duplique/decalle par le cisaillement qui sortent de NS: Le critere pour declancher la duplication des
3824 // bulles est le meme que pour les bulles reelles.
3826 {
3827 // Evaluation du cube contenant chaque bulle offset par le shear positif
3828 DoubleTab bounding_box_offsetp;
3829 calculer_bounding_box_bulles(bounding_box_offsetp, 1);
3830 // Evaluation du cube contenant chaque bulle offset par le shear negatif
3831 DoubleTab bounding_box_offsetm;
3832 calculer_bounding_box_bulles(bounding_box_offsetm, -1);
3833 preparer_duplicata_bulles(bounding_box, bounding_box_offsetp, bounding_box_offsetm, bounding_box_duplicate_criteria_, masque_duplicata_pour_compo_reel);
3834 }
3835 else
3836 {
3837 preparer_duplicata_bulles_masque_6bit(bounding_box, bounding_box_duplicate_criteria_, masque_duplicata_pour_compo_reel);
3838 }
3839
3840 // Duplique et deplace les bulles de la liste :
3841 dupliquer_bulle_perio(masque_duplicata_pour_compo_reel);
3842}
3843
3844// Input :
3845// - code : contient soit seulement l'encodage du deplacement, soit aussi
3846// celui du numero de bulle.
3847// Dans les 2 cas, on ne retiendra dans code_deplacement que
3848// l'encodage pure du deplacement.
3849// Retourne 0, -1 ou +1 selon le deplacement necessaire dans la direction dir :
3850static int decoder_deplacement(const int code, const int dir, int& compo_bulle_reel)
3851{
3852 // decodage du deplacement :
3853 const int code_deplacement = code & 63; // 63 = 111111b est le masque ne conservant que les 6 derniers bits.
3854 int tmp = code_deplacement & (1 << (3 + dir)); // l'operateur & permet de ne reveler
3855 // que le bit en face de 3+dir
3856 // cad le code (0 ou 1) pour le signe (resp. negatif ou
3857 // positif) dans la direction dir.
3858 // Si tmp == 0, c'est que le code signe pour la direction 'dir' etait 0, donc
3859 // que le deplacement est negatif.
3860 int signe = (tmp == 0) ? -1 /*deplacement negatif*/ : 1 /*deplacement positif*/;
3861 tmp = code_deplacement & (1 << dir); // retourne le code deplacement pour la direction consideree
3862 // (sur le 'dir'ieme bit)
3863 int index = tmp >> dir; // ramene ce bit en derniere position.
3864 // index = 0 si pas de deplacement, 1 sinon.
3865
3866
3867 compo_bulle_reel = code >> 6;
3868 // Cerr << "Deplacer bulle " << num_bulle << " Direction: " << dir
3869 // << " Code_deplacement : " << code_deplacement
3870 // << " Move : " << signe*index << finl;
3871 return signe * index;
3872}
3873
3874// Le code pour le deplacement est code dans la compo connexe. Il faut le
3875// recuperer et le decoder. Le maillage transmis doit avoir son tableau des
3876// composantes connexes a jour.
3877static void calculer_deplacement_from_code_compo_connexe(const Maillage_FT_IJK& m, const Domaine_IJK& split,
3878 DoubleTab& deplacement,
3879 DoubleTab& bounding_box_NS, DoubleTab position,
3880 const int nbulles, const Maillage_FT_IJK& mesh)
3881{
3882 // Creation du tableau deplacement pour le maillage m :
3883 const int nbsom = m.nb_sommets();
3884 deplacement.resize(nbsom, 3);
3885 // sommets du maillage temporaire (avec les ghosts a deplacer)
3886 ArrOfIntFT compo_sommets;
3887 m.calculer_compo_connexe_sommets(compo_sommets);
3888
3889 // sommets du maillage initial (avec juste les bulles reelles)
3890 ArrOfIntFT compo_sommets_init;
3891 mesh.calculer_compo_connexe_sommets(compo_sommets_init);
3892 const int nbsomreel = mesh.nb_sommets();
3893
3894 ArrOfDouble position_xmax_compo;
3895 ArrOfDouble position_xmin_compo;
3897 {
3898 position_xmax_compo.resize_array(nbulles, RESIZE_OPTIONS::NOCOPY_NOINIT);
3899 position_xmin_compo.resize_array(nbulles, RESIZE_OPTIONS::NOCOPY_NOINIT);
3900 position_xmax_compo = -10000.;
3901 position_xmin_compo = 10000.;
3902
3903 const DoubleTab& sommets = mesh.sommets(); // Tableau des coordonnees des marqueurs.
3904
3905 for (int i_sommet = 0; i_sommet < nbsomreel; i_sommet++)
3906 {
3907 // decodage du deplacement :
3908 //const int code = compo_sommets[i_sommet];
3909 int iconnex = compo_sommets_init[i_sommet];
3910 //std::cout << " coord = " << sommets(i_sommet, 0) << "compo_sommets" << iconnex << std::endl;
3911 double coord = sommets(i_sommet, 0);
3912 if (coord>position_xmax_compo[iconnex])
3913 position_xmax_compo[iconnex] = coord;
3914 if (coord<position_xmin_compo[iconnex])
3915 position_xmin_compo[iconnex] = coord;
3916 }
3917 Process::mp_min_for_each_item(position_xmin_compo);
3918 Process::mp_max_for_each_item(position_xmax_compo);
3919 }
3920
3921 for (int dir = 0; dir < 3; dir++)
3922 {
3923 for (int i_sommet = 0; i_sommet < nbsom; i_sommet++)
3924 {
3925 // On relit le code pour le deplacement :
3926 const int code = compo_sommets[i_sommet];
3927 // On remplit le deplacement des sommets de la facette:
3928
3929 // decodage du deplacement
3930 // le vrai compo_bulle_reel est lu par decoder_deplacement
3931 int compo_bulle_reel = 0;
3932 //int iconnex = compo_connex_som[i_sommet];
3933 int decode = decoder_deplacement(code, dir, compo_bulle_reel);
3934
3935 double depl = decode * (bounding_box_NS(dir, 1) - bounding_box_NS(dir, 0));
3936 deplacement(i_sommet, dir) = depl;
3937 double pos_ref = 0 ;
3938 double pos = 0;
3939 double decallage_bulle_reel_ext_domaine_reel = 0.;
3940 // si seulement on a traverser une frontiere shear periodique
3941 if (dir==2 && depl != 0. && IJK_Shear_Periodic_helpler::defilement_ == 1)
3942 {
3944 double offset = decode * IJK_Shear_Periodic_helpler::shear_x_time_;
3945 // position du barycentre de la bulle de reference a laquelle appartient le sommet
3946 pos_ref = position(compo_bulle_reel,0);
3947 // on veut le barycentre de la bulle decallee dans le domaine reel
3948 decallage_bulle_reel_ext_domaine_reel = 1.*(position_xmax_compo[compo_bulle_reel]-position_xmin_compo[compo_bulle_reel]); // verifier si cest ca la valeur
3949 pos = std::fmod(std::fmod(deplacement(i_sommet, 0) + pos_ref + offset - decallage_bulle_reel_ext_domaine_reel, Lx) + Lx, Lx) + decallage_bulle_reel_ext_domaine_reel;
3950 // Tous les sommets d'une meme bulle deplaces de la meme maniere sur x
3951 deplacement(i_sommet, 0) += (pos - pos_ref);
3952 }
3953
3954
3955 }
3956 }
3957}
3958
3959// Le code pour le deplacement est code dans la compo connexe. Il faut le
3960// recuperer et le decoder. Le maillage transmis doit avoir son tableau des
3961// composantes connexes a jour. cette methode ..._negatif est a utiliser dans
3962// l'algo lorsque le code des bulles ghost est negatif
3963static void calculer_deplacement_from_code_compo_connexe_negatif(const Maillage_FT_IJK& m,
3964 DoubleTab& deplacement,
3965 DoubleTab& bounding_box_NS)
3966{
3967 // Creation du tableau deplacement pour le maillage m :
3968 const int nbsom = m.nb_sommets();
3969 deplacement.resize(nbsom, 3);
3970 ArrOfIntFT compo_sommets;
3971 m.calculer_compo_connexe_sommets(compo_sommets);
3972
3973 for (int i_sommet = 0; i_sommet < nbsom; i_sommet++)
3974 {
3975 // On relit le code pour le deplacement :
3976 int code = compo_sommets[i_sommet];
3977 if (code >= 0)
3978 {
3979 // La bulle est reelle. Code est son numero. Il n'y a pas de deplacement a
3980 // prevoir. On force la reinit du tableau :
3981 for (int dir = 0; dir < 3; dir++)
3982 deplacement(i_sommet, dir) = 0.;
3983 }
3984 else
3985 {
3986 // La bulle est ghost. Il faut l'oppose de code pour decoder son
3987 // deplacement.
3988 code *= -1;
3989 // On remplit le deplacement des sommets de la facette:
3990 for (int dir = 0; dir < 3; dir++)
3991 {
3992 // decodage du deplacement :
3993 int unused_variable = 0 ;
3994 int decode = decoder_deplacement(code, dir, unused_variable);
3995 double depl = decode * (bounding_box_NS(dir, 1) - bounding_box_NS(dir, 0));
3996 deplacement(i_sommet, dir) = depl;
3997 }
3998 }
3999 }
4000}
4001
4002// Input :
4003// - m : Le maillage_ft doit contenir dans la compo_connexe les numeros de
4004// bulles reeles.
4005// - masque_array[icompo] : Contient le code_deplacement de la ieme bulle.
4006static void calculer_deplacement_from_masque_in_array(const Maillage_FT_IJK& m,
4007 DoubleTab& deplacement,
4008 const ArrOfInt& masque_array,
4009 DoubleTab& bounding_box_NS, DoubleTab position, const int nbulles)
4010{
4011 // Creation du tableau deplacement pour le maillage m :
4012 const int nbsom = m.nb_sommets();
4013 deplacement.resize(nbsom,3);
4014 ArrOfIntFT compo_connexe_som;
4015 m.calculer_compo_connexe_sommets(compo_connexe_som);
4016
4017 ArrOfDouble position_xmax_compo;
4018 ArrOfDouble position_xmin_compo;
4020 {
4021 position_xmax_compo.resize_array(nbulles, RESIZE_OPTIONS::NOCOPY_NOINIT);
4022 position_xmin_compo.resize_array(nbulles, RESIZE_OPTIONS::NOCOPY_NOINIT);
4023 position_xmax_compo = -10000.;
4024 position_xmin_compo = 10000.;
4025
4026 const DoubleTab& sommets = m.sommets(); // Tableau des coordonnees des marqueurs.
4027
4028 for (int i_sommet = 0; i_sommet < nbsom; i_sommet++)
4029 {
4030 int iconnex = compo_connexe_som[i_sommet];
4031 double coord = sommets(i_sommet, 0);
4032 if (coord>position_xmax_compo[iconnex])
4033 position_xmax_compo[iconnex] = coord;
4034 if (coord<position_xmin_compo[iconnex])
4035 position_xmin_compo[iconnex] = coord;
4036 }
4037 Process::mp_min_for_each_item(position_xmin_compo);
4038 Process::mp_max_for_each_item(position_xmax_compo);
4039 }
4040
4041 for (int i_sommet = 0; i_sommet < nbsom; i_sommet++)
4042 {
4043 // On relit le code pour le deplacement :
4044 const int icompo = compo_connexe_som[i_sommet];
4045 const int code = masque_array[icompo];
4046 // On remplit le deplacement des sommets de la facette:
4047 for (int dir = 0; dir < 3; dir++)
4048 {
4049 // decodage du deplacement :
4050 int compo_bulle_reel = 0;
4051 //int iconnex = compo_connex_som[i_sommet];
4052 int decode = decoder_deplacement(code, dir, compo_bulle_reel);
4053
4054 double depl = decode * (bounding_box_NS(dir, 1) - bounding_box_NS(dir, 0));
4055 deplacement(i_sommet, dir) = depl;
4056 double pos_ref = 0 ;
4057 double pos = 0;
4058 double decallage_bulle_reel_ext_domaine_reel = 0.;
4059 // si seulement on a traverser une frontiere shear periodique
4060 if (dir==2 && depl != 0. && IJK_Shear_Periodic_helpler::defilement_ == 1)
4061 {
4063 double offset = decode * IJK_Shear_Periodic_helpler::shear_x_time_;
4064 // position du barycentre de la bulle de reference a laquelle appartient le sommet
4065 pos_ref = position(compo_bulle_reel,0);
4066 // on veut le barycentre de la bulle decallee dans le domaine reel
4067 decallage_bulle_reel_ext_domaine_reel = 1.*(position_xmax_compo[compo_bulle_reel]-position_xmin_compo[compo_bulle_reel]); // verifier si cest ca la valeur
4068 pos = std::fmod(std::fmod(deplacement(i_sommet, 0) + pos_ref + offset - decallage_bulle_reel_ext_domaine_reel, Lx) + Lx, Lx) + decallage_bulle_reel_ext_domaine_reel;
4069
4070 deplacement(i_sommet, 0) += (pos - pos_ref);
4071 }
4072
4073
4074 }
4075 }
4076}
4077
4078
4079// Duplique les bulles a partir du masque_duplicata_pour_compo.
4080// Ce masque contient pour chaque bulle reelle un encodage du deplacement
4081// maximal a partir duquel :
4082// o On calcul toutes les copies a creer (jusqu'a 7 par bulle).
4083// o on ajoute les duplicatas dans un nouveau maillage,
4084// o on les deplace
4085// o on met -(code) dans la composante connexe
4086// (ou code contient l'info du numero de bulle et du deplacement
4087// realise a ce moment)
4088// o on ajoute les duplicatas au maillage actuel.
4089void IJK_Interfaces::dupliquer_bulle_perio(ArrOfInt& masque_duplicata_pour_compo)
4090{
4091 // Algorithme alternatif: optimise pour eviter de copier le maillage tout int.
4093 Maillage_FT_IJK maillage_temporaire; // Maillage ou on va cumuler les bulles
4094 // dupliquees deplacees.
4095 maillage_temporaire.initialize(ref_domaine_.valeur(), refdomaine_dis_.valeur(), parcours_);
4096 // dupliquer tout le maillage:
4097 Maillage_FT_IJK a_dupliquer;
4098 // On recopie tout le maillage dans a_dupliquer:
4099 a_dupliquer.recopie(mesh, Maillage_FT_Disc::MINIMAL); // copie l'etat MINIMAL du maillage et
4100 // initialise la compo_connexe a partir
4101 // du mesh fourni.
4102
4103 // Transforme le numero de composante en encodage numero composante +
4104 // deplacement:
4105 const ArrOfInt& compo_connexe_facettes = a_dupliquer.compo_connexe_facettes();
4106 int icompo, index, signe;
4107 for (int i_facette = 0; i_facette < a_dupliquer.nb_facettes(); i_facette++)
4108 {
4109 icompo = compo_connexe_facettes[i_facette];
4110 a_dupliquer.set_composante_connexe(i_facette, encoder_compo(icompo /*numero bulle*/, 0 /* pas de deplacement */));
4111 }
4112 // Boucle sur les duplications:
4113 // Exemple :
4114 // Composante connexe 0 : masque sans les bit de signes = 001 : sortie sur z --> 1 ghost (pas vrai en shear-perio)
4115 // Composante connexe 1 : masque sans les bit de signes = 010 : sortie sur y --> 1 ghost (pas vrai en shear-perio)
4116 // Composante connexe 2 : masque sans les bit de signes = 011 : sortie sur z et z --> 3 ghost (pas vrai en shear-perio)
4117 // pour shear_periodic_conditions : si sortie en z --> nb de ghost depend de la position du point periodique en face
4118 // Premiere iteration, je vais dupliquer les compo
4119 // 0 -> direction 001
4120 // 1 -> direction 010
4121 // 2 -> direction 001
4122 // Deuxieme iteration:
4123 // 2 -> direction 010
4124 // Troisieme iteration:
4125 // 2 -> direction 011
4126 ArrOfInt liste_bulles_crees;
4127 const int nbulles = get_nb_bulles_reelles();
4128 int nbulles_crees = 0;
4129 for (int mon_numero_iteration = 1; ; mon_numero_iteration++)
4130 {
4131 // Determine les composantes connexes a copier et quelle copie est a faire
4132 // lors de cette iteration:
4133 ArrOfInt index_copie(nbulles);
4134 ArrOfInt index_signe(nbulles);
4135 // On determine aussi les composantes connexe dont on a plus besoin
4136 // et on les supprime...
4137 ArrOfInt liste_facettes_pour_suppression;
4138 int reste_a_faire = 0;
4139
4140
4141 //ducluzeau : determination de index_copie a modifier (boucle ci-dessous) pour le shear-perio
4142 for (icompo = 0; icompo < nbulles; icompo++)
4143 {
4144 // Si on a epuise toutes les copies a faire pour cette composante,
4145 // index_copie restera a -1:
4146 index_copie[icompo] = -1;
4148 {
4149 int compteur = 0;
4150 const int masque = masque_duplicata_pour_compo[icompo] & 7; // masque sans les bits de signe
4151 for (index = 1; index <= 7; index++)
4152 {
4153 if ((masque & index) == index)
4154 compteur++; // Cette copie est a creer
4155
4156 if (compteur == mon_numero_iteration)
4157 {
4158 // Ok, c'est cette copie qu'il faut faire lors de cette iteration
4159 nbulles_crees++;
4160 index_copie[icompo] = index;
4161 // Journal() << "IJK_Interfaces::dupliquer_bulle_perio : Duplication de la composante " << icompo << finl;
4162 // Journal() << "vers le domaine FT index=" << index << " a l'iteration " << mon_numero_iteration << finl;
4163 // Il reste au moins une bulle a copier donc on continuera la boucle...
4164 reste_a_faire = 1;
4165 break;
4166 }
4167 }
4168 }
4169 else
4170 {
4171 index_signe[icompo] = -1;
4172 ArrOfInt index_bulle(7);
4173 ArrOfInt signe_bulle(7);
4174 // perio_xxx dit si il y periodicite ou non
4175 const int perio_x_reel = masque_duplicata_pour_compo[icompo] & 1;
4176 const int perio_y_reel = masque_duplicata_pour_compo[icompo] & (1 << 1);
4177 const int perio_z_reel = masque_duplicata_pour_compo[icompo] & (1 << 2);
4178 const int perio_x_ghost = masque_duplicata_pour_compo[icompo] & (1 << 3);
4179 // signe_xx dit si cette periodicite est de droite ou de gauche
4180// int signe_4bit = masque_duplicata_pour_compo[icompo] & (15 << 4);
4181 int signe_3bit = (masque_duplicata_pour_compo[icompo] & (7 << 4)) >> 1;
4182// int signe_x = masque_duplicata_pour_compo[icompo] & 16;
4183// int signe_y = masque_duplicata_pour_compo[icompo] & (16 << 1);
4184// int signe_z = masque_duplicata_pour_compo[icompo] & (16 << 2);
4185
4186 int bit_position_x_signe_6bit = 3;
4187 int bit_position_x_ghost_8bit = 7;
4188 int signe_x_ghost = (masque_duplicata_pour_compo[icompo] & (1 << bit_position_x_ghost_8bit)) >> bit_position_x_ghost_8bit;
4189 int mask = 1<<bit_position_x_signe_6bit;
4190
4191 for (int nb_bulle_duplique = 0; nb_bulle_duplique < 7; nb_bulle_duplique++)
4192 {
4193 index_bulle[nb_bulle_duplique] = -1;
4194 signe_bulle[nb_bulle_duplique] = signe_3bit;
4195 }
4196
4197 // condition perio classique
4198 //index_reel = 1 --> direction x : bit 0001 --> 1 ghost
4199 //index_reel = 2 --> direction y : bit 0010 --> 1 ghost
4200 //index_reel = 3 --> direction x & y : bit 0011 --> 3 ghost
4201 //index_reel = 4 --> direction z : bit 0100 --> 1 ghost
4202 //index_reel = 5 --> direction z & x : bit 0101 --> 2 ghost (au lieu de 3 en perio classique)
4203 //index_reel = 6 --> direction z & y : bit 0110 --> 3 ghost
4204 //index_reel = 7 --> direction z & y & x : bit 0111 --> 5 ghost (au lieu de 7 en perio classique)
4205
4206 // condition supplementaire pour perio shear
4207 //index_reel = 8 --> impossible (pas de ghost sans direction z) : bit 1000
4208 //index_reel = 9 --> impossible (pas de ghost sans direction z) : bit 1001
4209 //index_reel = 10 --> impossible (pas de ghost sans direction z): bit 1010
4210 //index_reel = 11 --> impossible (pas de ghost sans direction z): bit 1011
4211 //index_reel = 12 --> direction z & x ghost : bit 1100 --> 2 ghost (et pas 3)
4212 //index_reel = 13 --> direction z & x & x ghost : bit 1101 --> 3 ghost (et pas 7)
4213 //index_reel = 14 --> direction z & y & x ghost : bit 1110 --> 5 ghost (et pas 7)
4214 //index_reel = 15 --> direction z & y & x & x ghost : bit 1111 --> 7 ghost (et pas 14)
4215
4216 if (perio_z_reel == 4) // possible shear-perio a gerer, pas le meme nombre de ghost a droite et a gauche
4217 {
4218 if (perio_y_reel == 2 && perio_x_reel == 1 && perio_x_ghost == 8 )
4219 {
4220 // l index bulle na plus que 3 bit lui (pour les 3 dimensions despace)
4221 index_bulle[0] = 1;
4222 index_bulle[1] = 2;
4223 index_bulle[2] = 3;
4224 index_bulle[3] = 4;
4225 index_bulle[4] = 5;
4226 signe_bulle[4] &= (~mask);
4227 signe_bulle[4] |= (signe_x_ghost << bit_position_x_signe_6bit); // change le signe pour les bulles ghost de bulle ghost
4228 index_bulle[5] = 6;
4229 index_bulle[6] = 7;
4230 signe_bulle[6] &= (~mask);
4231 signe_bulle[6] |= (signe_x_ghost << bit_position_x_signe_6bit);
4232 }
4233 else if (perio_y_reel == 2 && perio_x_reel == 1 && perio_x_ghost != 8 )
4234 {
4235 index_bulle[0] = 1;
4236 index_bulle[1] = 2;
4237 index_bulle[2] = 3;
4238 index_bulle[3] = 4;
4239 index_bulle[4] = 6;
4240 }
4241 else if (perio_y_reel == 2 && perio_x_reel != 1 && perio_x_ghost == 8 )
4242 {
4243 index_bulle[0] = 5;
4244 signe_bulle[0] &= (~mask);
4245 signe_bulle[0] |= (signe_x_ghost << bit_position_x_signe_6bit);
4246 index_bulle[1] = 6;
4247 index_bulle[2] = 7;
4248 signe_bulle[2] &= (~mask);
4249 signe_bulle[2] |= (signe_x_ghost << bit_position_x_signe_6bit);
4250 index_bulle[3] = 4;
4251 index_bulle[4] = 2;
4252 }
4253 else if (perio_y_reel != 2 && perio_x_reel == 1 && perio_x_ghost == 8 )
4254 {
4255 index_bulle[0] = 1;
4256 index_bulle[1] = 4;
4257 index_bulle[2] = 5;
4258 signe_bulle[2] &= (~mask);
4259 signe_bulle[2] |= (signe_x_ghost << bit_position_x_signe_6bit);
4260
4261 }
4262 else if (perio_y_reel != 2 && perio_x_reel != 1 && perio_x_ghost != 8 )
4263 {
4264 index_bulle[0] = 4;
4265 }
4266 else if (perio_y_reel != 2 && perio_x_reel != 1 && perio_x_ghost == 8 )
4267 {
4268 index_bulle[0] = 5;
4269 signe_bulle[0] &= (~mask);
4270 signe_bulle[0] |= (signe_x_ghost << bit_position_x_signe_6bit);
4271 index_bulle[1] = 4;
4272 }
4273 else if (perio_y_reel != 2 && perio_x_reel == 1 && perio_x_ghost != 8 )
4274 {
4275 index_bulle[0] = 4;
4276 index_bulle[1] = 1;
4277 }
4278 else if (perio_y_reel == 2 && perio_x_reel != 1 && perio_x_ghost != 8 )
4279 {
4280 index_bulle[0] = 4;
4281 index_bulle[1] = 2;
4282 index_bulle[2] = 6;
4283 }
4284 else
4285 {
4286 Cerr << "Erreur dans la gestion des bulles ghost" << finl;
4287 Process::exit();
4288 }
4289 }
4290 else // pas de probleme a gerer avec le shear-perio
4291 {
4292 if (perio_y_reel == 2 && perio_x_reel == 1)
4293 {
4294 index_bulle[0] = 1;
4295 index_bulle[1] = 2;
4296 index_bulle[2] = 3;
4297 }
4298 else if (perio_y_reel == 2 && perio_x_reel != 1)
4299 {
4300 index_bulle[0] = 2;
4301 }
4302 else if (perio_y_reel != 2 && perio_x_reel == 1)
4303 {
4304 index_bulle[0] = 1;
4305 }
4306 else if (perio_y_reel != 2 && perio_x_reel != 1)
4307 {
4308 index_bulle[0] = -1;
4309 }
4310 else
4311 {
4312 Cerr << "Erreur dans la gestion des bulles ghost" << finl;
4313 Process::exit();
4314 }
4315 }
4316
4317 if (index_bulle[mon_numero_iteration-1] != -1 && mon_numero_iteration-1 <= 6)
4318 {
4319 // alors il reste au moins une bulle a cree pour cette compo dont on stocke le deplacement dans index_copie
4320 index_copie[icompo] = index_bulle[mon_numero_iteration-1];
4321 index_signe[icompo] = signe_bulle[mon_numero_iteration-1];
4322 nbulles_crees++;
4323 reste_a_faire = 1;
4324 }
4325 }
4326 }
4327 reste_a_faire = Process::mp_max(reste_a_faire);
4328 if (reste_a_faire == 0)
4329 {
4330 // plus aucune bulle a dupliquer, on sort de la boucle
4331 // mon_numero_iteration
4332 break;
4333 }
4334 // Supprime les facettes qui ne sont plus a dupliquer
4335 const int nf = a_dupliquer.nb_facettes();
4336 for (int i_facette = 0; i_facette < nf; i_facette++)
4337 {
4338 icompo = decoder_numero_bulle(compo_connexe_facettes[i_facette]);
4339 // Pour cette composante, quelle est la prochaine copie a faire ?
4340 index = index_copie[icompo];
4342 signe = index_signe[icompo];
4343
4344 if (index > 0)
4345 {
4346 // Cette facette est a copier. on encode le deplacement dans la
4347 // composante connexe: xxxyyy -> Code binaire. x = 0 pour un deplacement
4348 // negatif, 1 pour un deplacement positif.
4349 // y = 0 : pas de deplacement dans cette
4350 // direction, 1 : deplacement.
4351 // code_deplacement : de 1 a 63 : mais il n'y a que 26 possibilite.
4352 // Pour chaque y = 0, x n'a pas d'influence; Par
4353 // convention, on met x=0
4354 // Exemple dans le plan xy :
4355 // ________________
4356 // | 21 | 20 | 27 |
4357 // |___|_____|____|
4358 // | | | |
4359 // | 1 | NS | 9 |
4360 // |___|_____|____|
4361 // | 3 | 2 | 11 |
4362 // |___|_____|____|
4363 // Calcul du deplacement a faire,
4365 signe = masque_duplicata_pour_compo[icompo] & (7 << 3); // Recupere seulement le signe.
4366 const int code_deplacement = signe | index; // l'index donne les directions a deplacer lors de
4367 // cette iteration.
4368 // Le signe donne le sens.
4369 // On change la valeur de la composante connexe associee a la facette
4370 // pour memoriser le deplacement qu'elle subira ensuite.
4371 a_dupliquer.set_composante_connexe(i_facette, encoder_compo(icompo, code_deplacement));
4372 }
4373 else
4374 {
4375 if (index == 0)
4376 {
4377 Cerr << "Comment est-ce possible? " << finl;
4378 Process::exit();
4379 }
4380 // index est reste a sa valeur initiale de -1. Cette facette est donc a
4381 // effacer:
4382 liste_facettes_pour_suppression.append_array(i_facette);
4383 }
4384 }
4385 // La suppression gere les compo_connex (surcharge dans
4386 // Maillage_FT_IJK::nettoyer_maillage)
4387 a_dupliquer.supprimer_facettes(liste_facettes_pour_suppression);
4388
4389 // La methode Maillage_FT_IJK::ajouter_maillage gere aussi les
4390 // compo_connexe_facettes
4392 maillage_temporaire.ajouter_maillage_IJK(a_dupliquer);
4393
4394 // fin de l'iteration mon_numero_iteration.
4395 }
4396
4397 // ducluzeau
4398 // a ce niveau, maillage_temporaire contient toutes les facettes duplique, mais pas transportee.
4399 // Le numero de composante connexe de chaque facette contient l information sur son deplacement (encode)
4400
4401 // Si le maillage temporaire contient des facettes, on les deplace :
4402 int nbf = maillage_temporaire.nb_facettes();
4403 const int max_nbf = Process::mp_max(nbf);
4404 if (max_nbf)
4405 {
4406 DoubleTab deplacement;
4407 // Le maillage_temporaire transmis a son tableau des composantes connexes a
4408 // jour. le tableau contient l'encodage pour le deplacement que l'on va
4409 // decoder :
4410 const Domaine_IJK& split = ref_domaine_.valeur();
4411 ArrOfDouble volume_reel;
4412 DoubleTab position;
4413 calculer_volume_bulles(volume_reel, position);
4414
4415 calculer_deplacement_from_code_compo_connexe(maillage_temporaire, split,
4416 deplacement,
4417 bounding_box_NS_domain_, position, nbulles, mesh);
4418 // La methode transporter gere les compo connexes.
4419 maillage_temporaire.transporter(deplacement);
4420 maillage_temporaire.nettoyer_maillage();
4421
4422 // Lors du transport, des sommets peuvent changer de processeur.
4423 // Le nombre de facette peut varier (eg de 0 a qqch...) :
4424 nbf = maillage_temporaire.nb_facettes();
4425 // forcer les composantes connexes du maillage temporaire a -code
4426 const ArrOfInt& compo_connexe_facettes_tempo = maillage_temporaire.compo_connexe_facettes();
4427 for (int iface = 0; iface < nbf; iface++)
4428 {
4429 const int code_negatif = -compo_connexe_facettes_tempo[iface];
4430 maillage_temporaire.set_composante_connexe(iface, code_negatif);
4431 liste_bulles_crees.append_array(code_negatif);
4432 }
4433 // ajouter_maillage_IJK gere la compo_connexe correctement.
4434 // On pourrait aussi appeler Maillage_FT_IJK::ajouter_maillage.
4435 mesh.ajouter_maillage_IJK(maillage_temporaire);
4436 }
4437
4438 // On allege chaque liste, mais il faut de toute facon le refaire a la fin :
4439 array_trier_retirer_doublons(liste_bulles_crees);
4440 assert(ghost_compo_converter_.size_array() == nb_bulles_ghost_);
4441 // Si moi ou un autre proc a cree des bulles, il faut mettre a jour
4442 // nb_bulles_ghost_ et ghost_compo_converter_ :
4443 if (Process::mp_sum(nbulles_crees))
4444 {
4446 {
4447 ArrOfInt prov;
4448 int nbproc = Process::nproc();
4449 int taille;
4450 for (int p = 1; p < nbproc; p++)
4451 {
4452 recevoir(prov, p, 0, 2001 + p);
4453 taille = liste_bulles_crees.size_array();
4454 // On injecte le tableau prov a partir de la case taille :
4455 liste_bulles_crees.resize_array(taille + prov.size_array());
4456 liste_bulles_crees.inject_array(prov, -1 /* tout*/,
4457 taille /* first_element_dest */,
4458 0 /* first_element_source */);
4459 }
4460
4461 // On retire les doublons (duplicatas trouves sur plusieurs procs...);
4462 array_trier_retirer_doublons(liste_bulles_crees);
4463
4464 // On a cree des bulles ghost :
4465 nbulles_crees = liste_bulles_crees.size_array();
4466 nb_bulles_ghost_ += nbulles_crees;
4469
4470 if (ghost_compo_converter_.size_array())
4471 {
4472 Cerr << " On vient de creer des bulles ghost alors qu'il y en avait "
4473 "deja car le "
4474 << " tableau ghost_compo_converter_ n'est pas de taille nulle! " << finl;
4475 Process::exit();
4476 // On append le tableau liste_bulles_crees a la fin de
4477 // ghost_compo_converter_ :
4478 const int nb_ghost_before = ghost_compo_converter_.size_array();
4479 ghost_compo_converter_.resize_array(nb_ghost_before + nbulles_crees);
4480 ghost_compo_converter_.inject_array(liste_bulles_crees, -1 /* tout*/, nb_ghost_before /* first_element_dest */,
4481 0 /* first_element_source */);
4482 }
4483 else
4484 {
4485 ghost_compo_converter_.copy_array(liste_bulles_crees); // L'oparateur "=" existe aussi. Je ne sais pas
4486 // ce qui est mieux.
4487 }
4488
4489#ifdef GB_VERBOSE
4490 // Tests et commentaires :
4491 Cerr << "IJK_Interfaces.cpp::dupliquer_bulle_perio liste_bulles_crees : "
4492 << liste_bulles_crees << finl;
4493 const int old_size = ghost_compo_converter_.size_array();
4494 ghost_compo_converter_.array_trier_retirer_doublons();
4495 const int new_size = ghost_compo_converter_.size_array();
4496 if (new_size != old_size)
4497 {
4498 Cerr << "On dirait que des doublons etaient presents dans la liste ghost_compo_converter_ ... "
4499 << "Ca signifie peut-etre que l'on vient de creer des bulles qui existaient deja..."
4500 << "C'est etrange... on s'arrete... ";
4501 Process::exit();
4502 }
4503#endif
4504
4505 }
4506 else
4507 {
4508 // Tous les proc envoient au maitre :
4509 envoyer(liste_bulles_crees, Process::me(), 0, 2001 + Process::me());
4510 }
4511
4512 // Le proc maitre a fini de remplir le tableau. Il communique a tous les
4513 // procs :
4514 envoyer_broadcast(nb_bulles_ghost_, 0);
4515 envoyer_broadcast(ghost_compo_converter_, 0);
4516 envoyer_broadcast(recompute_indicator_, 0);
4517 }
4518
4519 assert(ghost_compo_converter_.size_array() == nb_bulles_ghost_);
4520}
4521
4522// Methode pour remplir le masque codant les duplications a creer
4523// a partir des bounding box de chaques bulles.
4524// La methode dupliquer_bulle_perio construira les maillages et les vecteurs deplacement
4525// a partir du masque.
4526// Parametres :
4527// - bounding_box : Tableau des coordonnees limites des cubes contenant chaques bulles.
4528// - authorized_bounding_box : Tableau des coordonnees limites a ne pas depasser
4529// (eg, le domaine NS ou le domaine_(FT - ncells_forbidden_)...
4530// Resultat :
4531// - masque_duplicata_pour_compo : Encodage du deplacement a appliquer aux bulles sortant
4532// du domaine autorise.
4533void IJK_Interfaces::preparer_duplicata_bulles(const DoubleTab& bounding_box,
4534 const DoubleTab& bounding_box_offsetp,
4535 const DoubleTab& bounding_box_offsetm,
4536 const DoubleTab& authorized_bounding_box,
4537 ArrOfInt& masque_duplicata_pour_compo)
4538{
4539
4541 {
4542 const int nbulles = get_nb_bulles_reelles();
4543 masque_duplicata_pour_compo.resize_array(nbulles);
4544 for (int icompo = 0; icompo < nbulles; icompo++)
4545 {
4546 int masque_sortie_domaine_reel = 0;
4547 // Masque sortie est un chiffre binaire qui dit dans quelles directions
4548 // la bulle sort du domaine (et le domaine est periodique)
4549
4550 // pour le shear_periodic,
4551 // on passe d'une variable 6 bit, a 8 bit, puisqu on a un degres de liberte supplementaire sur les ghost
4552 for (int direction = 0; direction < 3; direction++)
4553 {
4554 if (perio_NS_[direction])
4555 {
4556 // Est-ce qu'on sort par la gauche ?
4557 if (bounding_box(icompo, direction, 0) < authorized_bounding_box(direction, 0))
4558 {
4559 masque_sortie_domaine_reel |= (1 << direction); // met le bit "direction" a 1 dans le masque
4560 masque_sortie_domaine_reel |= (16 << direction); // met le bit de signe a 1 dans le masque
4561 // il faudra deplacer la copie vers la droite
4562 if(direction==2 && IJK_Shear_Periodic_helpler::defilement_ == 1)
4563 // on est sorti en z, est-ce que la bulle ghost depasse en x ? pour condition perio shear
4564 // si sortie de la bulle en z, verifier la sortie en x de la bulle ghost
4565 // ici, sortie par la gauche, donc shear positif dans bounding_box_offsetp
4566 {
4567 if (bounding_box_offsetp(icompo, 0, 0) < authorized_bounding_box(0, 0))
4568 {
4569 masque_sortie_domaine_reel |= (1 << 3); // met le bit "direction" a 1 dans le masque
4570 masque_sortie_domaine_reel |= (16 << 3); // met le bit de signe a 1 dans le masque
4571 }
4572 if (bounding_box_offsetp(icompo, 0, 1) > authorized_bounding_box(0, 1))
4573 {
4574 masque_sortie_domaine_reel |= (1 << 3); // met le bit "direction" a 1 dans le masque
4575 // le bit de signe reste a zero, qui signifie un deplacement vers
4576 // les coord negatives.
4577 }
4578 }
4579 }
4580 if (bounding_box(icompo, direction, 1) > authorized_bounding_box(direction, 1))
4581 {
4582 // On sort par la droite, il faudra deplacer la copie vers la
4583 // gauche.
4584 masque_sortie_domaine_reel |= (1 << direction); // met le bit "direction" a 1 dans le masque
4585 // le bit de signe reste a zero, qui signifie un deplacement vers
4586 // les coord negatives.
4587 if(direction==2 && IJK_Shear_Periodic_helpler::defilement_ == 1)
4588 // on est sorti en z, est-ce que la bulle ghost depasse en x ? pour condition perio shear
4589 // si sortie de la bulle en z, verifier la sortie en x de la bulle ghost
4590 // ici, sortie par la droite, donc shear negatif dans bounding_box_offsetm
4591 {
4592 if (bounding_box_offsetm(icompo, 0, 0) < authorized_bounding_box(0, 0))
4593 {
4594 masque_sortie_domaine_reel |= (1 << 3); // met le bit "direction" a 1 dans le masque
4595 masque_sortie_domaine_reel |= (16 << 3); // met le bit de signe a 1 dans le masque
4596 }
4597 if (bounding_box_offsetm(icompo, 0, 1) > authorized_bounding_box(0, 1))
4598 {
4599 masque_sortie_domaine_reel |= (1 << 3); // met le bit "direction" a 1 dans le masque
4600 // le bit de signe reste a zero, qui signifie un deplacement vers
4601 // les coord negatives.
4602 }
4603 }
4604 }
4605 }
4606 }
4607
4608 // Stocke le masque dans le tableau resultat :
4609 masque_duplicata_pour_compo[icompo] = masque_sortie_domaine_reel;
4610 // duCluzeau : pour shear-perio, il faut stocker un autre tableau avec le nombre de duplicata par bulles.
4611 // pour ca, il faut tester la position de la bulle ghost en z, et verifier si elle sort en x
4612 }
4613 }
4614 envoyer_broadcast(masque_duplicata_pour_compo, 0);
4615
4616}
4617
4619 const DoubleTab& authorized_bounding_box,
4620 ArrOfInt& masque_duplicata_pour_compo)
4621{
4622
4624 {
4625 const int nbulles = get_nb_bulles_reelles();
4626 masque_duplicata_pour_compo.resize_array(nbulles);
4627 for (int icompo = 0; icompo < nbulles; icompo++)
4628 {
4629 int masque_sortie_domaine_reel = 0;
4630 // Masque sortie est un chiffre binaire qui dit dans quelles directions
4631 // la bulle sort du domaine (et le domaine est periodique)
4632
4633 // pour le shear_periodic,
4634 // on passe d'une variable 6 bit, a 8 bit, puisqu on a un degres de liberte supplementaire sur les ghost
4635 for (int direction = 0; direction < 3; direction++)
4636 {
4637 if (perio_NS_[direction])
4638 {
4639 // Est-ce qu'on sort par la gauche ?
4640 if (bounding_box(icompo, direction, 0) < authorized_bounding_box(direction, 0))
4641 {
4642 masque_sortie_domaine_reel |= (1 << direction); // met le bit "direction" a 1 dans le masque
4643 masque_sortie_domaine_reel |= (8 << direction); // met le bit de signe a 1 dans le masque
4644 // il faudra deplacer la copie vers la droite
4645 }
4646 if (bounding_box(icompo, direction, 1) > authorized_bounding_box(direction, 1))
4647 {
4648 masque_sortie_domaine_reel |= (1 << direction); // met le bit "direction" a 1 dans le masque
4649 }
4650 }
4651 }
4652
4653 // Stocke le masque dans le tableau resultat :
4654 masque_duplicata_pour_compo[icompo] = masque_sortie_domaine_reel;
4655 }
4656 }
4657 // Le proc maitre a fini de remplir le tableau de masque.
4658 // Il les communiques a tous les procs.
4659 // broadcast to all mpi processes:
4660 envoyer_broadcast(masque_duplicata_pour_compo, 0);
4661}
4662
4663// Methode supprimant toutes les bulles dupliquees (reconnues par compo_connex <
4664// 0);
4666{
4668 const ArrOfInt& compo_connex = mesh.compo_connexe_facettes();
4669 const int nbfacettes = mesh.nb_facettes();
4670
4671 // On parcours toutes les facettes du maillage.
4672 // On marque celles dont la compo_connexe est negative:
4673 ArrOfInt liste_facettes_pour_suppression;
4674 for (int iface = 0; iface < nbfacettes; iface++)
4675 {
4676 const int icompo = compo_connex[iface];
4677 // if ((icompo < 0) or (icompo>70)) // Pour ne recuperer que les 70
4678 // premieres bulles.
4679 if (icompo < 0)
4680 liste_facettes_pour_suppression.append_array(iface);
4681 }
4682
4683 mesh.supprimer_facettes(liste_facettes_pour_suppression);
4684 // A partir d'ici, le tableau n'est plus valide donc on le reduit a 0 :
4685 RK3_G_store_vi_.resize(0, 3);
4686
4687 // On remet le nombre de bulles ghost a 0 :
4689 nb_bulles_ghost_ = 0;
4690 ghost_compo_converter_.resize_array(0);
4691}
4692
4694{
4695 // Evaluation du cube contenant chaque bulle :
4696 DoubleTab bounding_box;
4697 calculer_bounding_box_bulles(bounding_box);
4698
4699 // Pour chaque compo_connexe, remplir dans le tableau
4700 // masque_duplicata_pour_compo un encodage du deplacement maximal :
4701 ArrOfInt masque;
4702 // Recherche des bulles qui sortent du domaine authorise et remplit
4703 // dans le tableau masque un encodage du deplacement :
4705
4706 // Deplace les bulles de la liste :
4707 deplacer_bulle_perio(masque);
4708
4710 {
4711 const int nbulles = get_nb_bulles_reelles();
4712 assert(through_yminus_.size_array() == nbulles);
4713 assert(perio_NS_[DIRECTION_J]);
4714 for (int icompo = 0; icompo < nbulles; icompo++)
4715 {
4716 const int masque_sortie = masque[icompo];
4717 if (masque_sortie & 2)
4718 {
4719 // La bulle icompo contient 1 sur le bit de deplacement selon y (bit 2^1
4720 // = 2) Il faut donc changer la valeur stockee dans through_yminus :
4721 if (masque_sortie & 16)
4722 {
4723 // La bulle icompo contient 1 sur le bit de sign du deplacement selon
4724 // y (bit 2^(3+1)=16) On sort par la gauche et la bulle va etre
4725 // deplacer vers la droite :
4726 // donc on traverse yminus et rentre par la droite.
4727 through_yminus_[icompo] = -1;
4728 }
4729 else
4730 {
4731 // On traverse yplus et rentre par la gauche.
4732 through_yminus_[icompo] = 1;
4733 }
4734 }
4735 }
4736 }
4737 // Le maitre informe les autres des nouvelles valeurs :
4738 if (follow_colors_)
4739 envoyer_broadcast(through_yminus_, 0);
4740}
4741
4742// Deplace les bulles a travers la frontiere perio a partir du masque.
4743// Ce masque contient pour chaque bulle reelle un encodage du deplacement
4744// maximal.
4745// - On marque les facettes a deplacer.
4746// - On les transporte.
4747// ducluzeau : deplace la bulle reelle quand elle est sortie de domain_ns
4748void IJK_Interfaces::deplacer_bulle_perio(const ArrOfInt& masque_deplacement_par_compo)
4749{
4750 // ducluzeau : masque_deplacement_par_compo doit etre en 6 bit, pas 8 !
4752 DoubleTab deplacement;
4753 const int nbulles = get_nb_bulles_reelles();
4754 ArrOfDouble volume_reel;
4755 DoubleTab position;
4756 calculer_volume_bulles(volume_reel, position);
4757 calculer_deplacement_from_masque_in_array(mesh, deplacement, masque_deplacement_par_compo, bounding_box_NS_domain_, position, nbulles);
4758
4759 // On transporte le maillage :
4760 mesh.transporter(deplacement);
4761 // Un petit message si on transporte :
4762
4763 for (int ib = 0; ib < nbulles; ib++)
4764 {
4765 const int code_deplacement = masque_deplacement_par_compo[ib];
4766 if (code_deplacement != 0)
4767 {
4768 Journal() << "IJK_Interfaces::deplacer_bulle_perio : Un deplacement a eu "
4769 << "lieu pour la composante " << ib << finl;
4770 Journal() << "Deplacement x y z : ";
4771 for (int dir = 0; dir < 3; dir++)
4772 {
4773 int unused_variable = 0 ;
4774 const int decode = decoder_deplacement(code_deplacement, dir, unused_variable);
4775 Journal() << decode << " ";
4776 }
4777 Journal() << finl;
4778
4780 envoyer_broadcast(recompute_indicator_, 0);
4781 }
4782 }
4783}
4784
4785// retourne le nombre de compo_connexe presentes dans l'element.
4786// Pour cela, la methode utilise les Intersections_Elem_Facettes_Data
4787// Or, il est possible qu'on n'ait des facettes reconnues comme intersectant un
4788// element avec une surface vide (en fait, elles ne le coupent pas). C'est une
4789// astuce du parcours pour ne pas les parcourir plusieurs fois... Voir
4790// Parcours_interface::calcul_intersection_facelem_3D pour explication :
4791// // Intersection de surface nulle. On l'enregistre pour ne pas traiter
4792// // cette facette a nouveau lors du parcours.
4793// maillage.intersections_elem_facettes_.ajoute_intersection(num_facette,
4794// num_element,
4795// 0.,
4796// 0.,
4797// 0., 0., 0.);
4798//
4799//
4800
4801// The method have to receive the extended field indic_ft because
4802// the splitting and the conversion "num_elem = s.convert_ijk_cell_to_packed(i,
4803// j, k);" are required for num_compo_ which is on domaineVDF which is on the
4804// extended domain
4805void IJK_Interfaces::calculer_indicatrice(IJK_Field_double& indic)
4806{
4807 statistics().create_custom_counter("Calcul rho mu indicatrice: calcul de l'indicatrice",2,"IJK");
4808 statistics().begin_count("Calcul rho mu indicatrice: calcul de l'indicatrice",statistics().get_last_opened_counter_level()+1);
4809
4810 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, refdomaine_dis_.valeur());
4811 const IntTab& elem_faces = domaine_vf.elem_faces();
4812 const IntTab& faces_voisins = domaine_vf.face_voisins();
4813 const Intersections_Elem_Facettes& intersec = maillage_ft_ijk_.intersections_elem_facettes();
4814 const Domaine_IJK& s = indic.get_domaine();
4815
4816 indic.data() = 1.; // Tout liquide pour commencer
4817 num_compo_ = 0; // Re-initialize the table...
4818 const int ni = indic.ni();
4819 const int nj = indic.nj();
4820 const int nk = indic.nk();
4821
4822 // La methode de maillage_ft_disc utilise l'equation de transport pour
4823 // recuperer la fonction distance et un bricolage pour trouver l'indicatrice
4824 // au voisinage de l'interface. On va faire autrement. Debut identique a la
4825 // methode VDF: calcul des fractions de volume de phase 1 dans les mailles
4826 // traversees par des interfaces:
4827 {
4828 const ArrOfInt& index_elem = intersec.index_elem();
4829 // const int nb_elem = index_elem.size_array();
4830 // Boucle sur les elements euleriens
4831 for (int k = 0; k < nk; k++)
4832 {
4833 for (int j = 0; j < nj; j++)
4834 {
4835 for (int i = 0; i < ni; i++)
4836 {
4837 // Anciennement la methode etait portee par le mesh :
4838 // const int num_elem =
4839 // maillage_ft_ijk_.convert_ijk_cell_to_packed(i, j, k);
4840 // A present, elle est dans le splitting :
4841 const int num_elem = s.convert_ijk_cell_to_packed(i, j, k);
4842 int index = index_elem[num_elem];
4843 double somme_contrib = 0.;
4844 // Boucle sur les facettes qui traversent cet element
4845 while (index >= 0)
4846 {
4847 const Intersections_Elem_Facettes_Data& data = intersec.data_intersection(index);
4848 somme_contrib += data.contrib_volume_phase1_;
4849 index = data.index_facette_suivante_;
4850 };
4851
4852 int nb_increment_somme_contrib = 0;
4853 while (somme_contrib > 1.)
4854 {
4855 somme_contrib -= 1.;
4856 nb_increment_somme_contrib++;
4857 }
4858 while (somme_contrib < 0.)
4859 {
4860 somme_contrib += 1.;
4861 nb_increment_somme_contrib++;
4862 }
4863
4864 if (nb_increment_somme_contrib > 1)
4865 {
4866 Cerr << "nb_increment_somme_contrib= " << nb_increment_somme_contrib << finl;
4867 // Process::exit("Error in IJK_Interfaces::calculer_indicatrice !");
4868 }
4869 // GB Fix 2022: tolerance play:
4870 // Si l'on est proche de 0 ou de 1, on ne sait pas vraiment si on a bien fait nos calculs
4871 // (les modulos et les sommes peuvent avoir conduit a une imprecision).
4872 // On fait le choix de le considerer comme non-traverser, et on laisse le soin au calcul
4873 // des compos connexes de determiner si c'est 0 ou 1 :
4874 if ((somme_contrib < seuil_indicatrice_negligeable_) || ((1.-somme_contrib) < seuil_indicatrice_negligeable_))
4875 {
4876 somme_contrib = 0.; // L'elem retourne dans la liste des elements "non traverses"
4877 }
4878 if (somme_contrib > 0.)
4879 {
4880 // if(somme_contrib == 1.)
4881 // somme_contrib -= 1e-3;
4882
4883 indic(i, j, k) = somme_contrib;
4884 num_compo_[num_elem] = -1; // marque l'element pour apres
4885 }
4886 }
4887 }
4888 }
4889 }
4890
4891 statistics().create_custom_counter("Calcul de l'indicatrice : recherche compo connexes",2,"IJK");
4892 statistics().begin_count("Calcul de l'indicatrice : recherche compo connexes",statistics().get_last_opened_counter_level()+1);
4893 num_compo_.echange_espace_virtuel();
4894 // Recherche des composantes connexes sur le maillage eulerien
4895 int nb_compo_locales = search_connex_components_local(elem_faces, faces_voisins, num_compo_);
4896 nb_compo_in_num_compo_ = compute_global_connex_components(num_compo_, nb_compo_locales);
4897 // num_compo_.echange_espace_virtuel(); // On n'aura pas besoin de son ev a
4898 // jour.
4899
4900 // Il y a au moins une phase continue :
4902 statistics().end_count("Calcul de l'indicatrice : recherche compo connexes");
4903
4904 // Calcul des drapeaux selon la methode la plus robuste :
4905 ArrOfInt drapeau(nb_compo_in_num_compo_);
4907
4908#ifdef GB_VERBOSE
4909 Cerr << "GB-check-interf nb_compo_in_num_compo_ - (nb_reelles + nb_ghost)= " << nb_compo_in_num_compo_ << " - "
4912 Cerr << "nb_compo_in_num_compo_= " << nb_compo_in_num_compo_ << finl;
4913 Cerr << "IJK_Interfaces::calculer_indicatrice Evaluations drapeau vapeur " << drapeau << finl;
4914#endif
4915
4916#define VERIF_DRAPEAU 0
4917#if VERIF_DRAPEAU
4918 // Calcul des drapeaux selon les autres methodes :
4919 {
4920 // Pour debug :
4921 // maillage_ft_ijk_.nettoyer_maillage();
4922 // maillage_ft_ijk_.parcourir_maillage();
4923
4924 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
4925 ArrOfInt drapeau1(nb_compo_in_num_compo_);
4926 ArrOfInt drapeau1b(nb_compo_in_num_compo_);
4927 ArrOfInt drapeau2(nb_compo_in_num_compo_);
4928 ArrOfInt drapeau3(nb_compo_in_num_compo_);
4929
4930 // marquer les composantes interieures aux bulles:
4931 compute_drapeaux_vapeur_v1(mesh, elem_faces, faces_voisins, num_compo, true, drapeau1);
4932 compute_drapeaux_vapeur_v1(mesh, elem_faces, faces_voisins, num_compo, false, drapeau1b);
4933 compute_drapeaux_vapeur_v2(num_compo, drapeau2);
4934
4935 const Domaine_IJK& split = ref_domaine_.valeur();
4936 compute_drapeaux_vapeur_v3(mesh, split, num_compo, drapeau3);
4937
4938 // HACKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
4939 drapeau = drapeau3;
4940
4941 Cerr << "IJK_Interfaces::calculer_indicatrice Evaluations drapeaux" << finl;
4942 Cerr << "nb_compo_in_num_compo_= " << nb_compo_in_num_compo_ << finl;
4943 Cerr << "drapeau v1 towards_liquid=true : " << drapeau1 << finl;
4944 Cerr << "drapeau v1 towards_liquid=false : " << drapeau1b << finl;
4945 Cerr << "drapeau v2 : " << drapeau2 << finl;
4946 Cerr << "drapeau v3 : " << drapeau3 << finl;
4947 Cerr << "drapeau v4 : " << drapeau << finl;
4948
4949 for (int idx = 0; idx < nb_compo_in_num_compo_; idx++)
4950 {
4951 int sum = drapeau[idx] + drapeau1[idx] + drapeau1b[idx] + drapeau2[idx] + drapeau3[idx];
4952 if ((drapeau[idx] != drapeau1[idx]) || (drapeau[idx] != drapeau1b[idx]) || (drapeau[idx] != drapeau2[idx]) ||
4953 (drapeau[idx] != drapeau3[idx]))
4954 Cerr << "Les methodes different... "
4955 << "valeurs donnees par les methodes : " << drapeau[idx] << drapeau1[idx] << drapeau1b[idx]
4956 << drapeau2[idx] << drapeau3[idx] << " pour idx = " << idx << finl;
4957
4958 if ((sum != 0) && (sum != 5))
4959 {
4960 Cerr << "Les methodes different... "
4961 << "sum = " << sum << " pour idx = " << idx << finl;
4962 // Process::exit();
4963 }
4964 }
4965 assert(drapeau == drapeau1);
4966 assert(drapeau == drapeau1b);
4967 assert(drapeau == drapeau2);
4968 assert(drapeau == drapeau3);
4969
4970 // Verifie qu'il n'y a qu'une phase liquide :
4971 check_somme_drapeau(drapeau);
4972 check_somme_drapeau(drapeau1);
4973 check_somme_drapeau(drapeau1b);
4974 check_somme_drapeau(drapeau2);
4975 check_somme_drapeau(drapeau3);
4976 }
4977#endif
4978
4979#define DEBUG_INDIC 0
4980#if DEBUG_INDIC
4981 // Pour debugger: on met dans l'indicatrice le numero de la compo connexe
4982 // globale:
4983 {
4984 for (int k = 0; k < nk; k++)
4985 {
4986 for (int j = 0; j < nj; j++)
4987 {
4988 for (int i = 0; i < ni; i++)
4989 {
4990 const int num_elem = s.convert_ijk_cell_to_packed(i, j, k);
4991 int compo = num_compo[num_elem];
4992 // Element dans une bulle:
4993 indic(i, j, k) = compo;
4994 }
4995 }
4996 }
4997 }
4998#else
4999 {
5000 // Mettre a zero l'indicatrice pour les elements qui sont dans des
5001 // composantes marquees:
5002 for (int k = 0; k < nk; k++)
5003 {
5004 for (int j = 0; j < nj; j++)
5005 {
5006 for (int i = 0; i < ni; i++)
5007 {
5008 const int num_elem = s.convert_ijk_cell_to_packed(i, j, k);
5009 int compo = num_compo_[num_elem];
5010 // color(i,j,k) = compo;
5011 if (compo >= 0 && drapeau[compo] == 0)
5012 {
5013 // Element dans une bulle:
5014 indic(i, j, k) = 0.;
5015 }
5016 }
5017 }
5018 }
5019 }
5020#endif
5021 statistics().end_count("Calcul rho mu indicatrice: calcul de l'indicatrice");
5022}
5023
5025{
5026 statistics().create_custom_counter("Calcul rho mu indicatrice: calcul de l'indicatrice",2,"IJK");
5027 statistics().begin_count("Calcul rho mu indicatrice: calcul de l'indicatrice",statistics().get_last_opened_counter_level()+1);
5028
5029 const Intersections_Elem_Facettes& intersec = maillage_ft_ijk_.intersections_elem_facettes();
5030 const Domaine_IJK& s = indic.get_domaine();
5031
5032 const int ni = indic.ni();
5033 const int nj = indic.nj();
5034 const int nk = indic.nk();
5035
5036 // calcul des fractions de volume de phase 1 dans les mailles traversees par
5037 // des interfaces:
5038 {
5039 const ArrOfInt& index_elem = intersec.index_elem();
5040 // Boucle sur les elements euleriens
5041 for (int k = 0; k < nk; k++)
5042 {
5043 for (int j = 0; j < nj; j++)
5044 {
5045 for (int i = 0; i < ni; i++)
5046 {
5047 const int num_elem = s.convert_ijk_cell_to_packed(i, j, k);
5048 int index = index_elem[num_elem];
5049
5050 if (0. < indic(i, j, k) && indic(i, j, k) < 1.) // element traverse par l'interface
5051 indic(i, j, k) = 2.;
5052
5053 double somme_contrib = 0.;
5054 // Boucle sur les facettes qui traversent cet element
5055 while (index >= 0)
5056 {
5057 const Intersections_Elem_Facettes_Data& data = intersec.data_intersection(index);
5058 somme_contrib += data.contrib_volume_phase1_;
5059 index = data.index_facette_suivante_;
5060 };
5061
5062 int nb_increment_somme_contrib = 0;
5063 while (somme_contrib > 1.)
5064 {
5065 somme_contrib -= 1.;
5066 nb_increment_somme_contrib++;
5067 }
5068 while (somme_contrib < 0.)
5069 {
5070 somme_contrib += 1.;
5071 nb_increment_somme_contrib++;
5072 }
5073
5074 if (nb_increment_somme_contrib > 1)
5075 Process::exit("Error in IJK_Interfaces::calculer_indicatrice_optim !");
5076
5077 if (somme_contrib > 0.)
5078 {
5079 // if(somme_contrib == 1.)
5080 // somme_contrib -= 1e-3;
5081 indic(i, j, k) = somme_contrib;
5082 }
5083 }
5084 }
5085 }
5086 }
5087
5088 update_indicatrice(indic);
5089 statistics().end_count("Calcul rho mu indicatrice: calcul de l'indicatrice");
5090}
5091
5092void IJK_Interfaces::calculer_indicatrices(IJK_Field_vector3_double& indic)
5093{
5094 statistics().create_custom_counter("Calcul rho mu indicatrice: calcul des indicatrices",2,"IJK");
5095 statistics().begin_count("Calcul rho mu indicatrice: calcul des indicatrices",statistics().get_last_opened_counter_level()+1);
5096 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, refdomaine_dis_.valeur());
5097 const Domaine& domaine = domaine_vf.domaine();
5098 const IntTab& elem_faces = domaine_vf.elem_faces();
5099 const IntTab& faces_voisins = domaine_vf.face_voisins();
5100 const Intersections_Elem_Facettes& intersec = maillage_ft_ijk_.intersections_elem_facettes();
5101 const Domaine_IJK& s = indic.get_domaine();
5102
5103 for (int igroup = 0; igroup < nb_groups_; igroup++)
5104 {
5105 indic[igroup].data() = 1.; // Tout liquide pour commencer
5106 }
5107 if (parser_ == 0)
5108 {
5109 Cerr << "This choice of options has to be validated. "
5110 << "It seems you are using a multi-groups of bubbles "
5111 << "and the forcing method with the color_function "
5112 << "which has not been tested yet!"
5113 << finl;
5114 Process::exit();
5115 }
5116 // ISO C++ forbids variable length array : IntVect num_compo[nb_groups_];
5117 IntVect num_compo[max_authorized_nb_of_groups_];
5118
5119 // Cree un tableau parallele structure comme un tableau aux elements
5120 // du maillage vdf, initialise a zero.
5121 for (int i = 0; i < nb_groups_; i++)
5122 domaine.creer_tableau_elements(num_compo[i]);
5123
5124 const int ni = indic[0].ni();
5125 const int nj = indic[0].nj();
5126 const int nk = indic[0].nk();
5127
5128 assert(nb_groups_ <= max_authorized_nb_of_groups_);
5129 const ArrOfInt& compo_connexe = maillage_ft_ijk_.compo_connexe_facettes();
5130
5131 // La methode de maillage_ft_disc utilise l'equation de transport pour
5132 // recuperer la fonction distance et un bricolage pour trouver l'indicatrice
5133 // au voisinage de l'interface. On va faire autrement. Debut identique a la
5134 // methode VDF: calcul des fractions de volume de phase 1 dans les mailles
5135 // traversees par des interfaces:
5136 {
5137 const ArrOfInt& index_elem = intersec.index_elem();
5138 // Boucle sur les elements euleriens
5139
5140 for (int k = 0; k < nk; k++)
5141 {
5142 for (int j = 0; j < nj; j++)
5143 {
5144 for (int i = 0; i < ni; i++)
5145 {
5146 // Anciennement la methode etait portee par le mesh :
5147 // const int num_elem =
5148 // maillage_ft_ijk_.convert_ijk_cell_to_packed(i, j, k);
5149 // A present, elle est dans le splitting :
5150 const int num_elem = s.convert_ijk_cell_to_packed(i, j, k);
5151 int index = index_elem[num_elem];
5152 double somme_contrib[max_authorized_nb_of_groups_] = {0.};
5153 // Boucle sur les facettes qui traversent cet element
5154 while (index >= 0)
5155 {
5156 const Intersections_Elem_Facettes_Data& data = intersec.data_intersection(index);
5157 const int facette = data.numero_facette_;
5158 int icompo = compo_connexe[facette];
5159 int m = icompo;
5160 if (icompo < 0)
5161 {
5162 // Portion d'interface ghost.
5163 // On recherche le vrai numero
5164 m = decoder_numero_bulle(-icompo);
5165 }
5166 assert(0 <= m && m < nb_bulles_reelles_);
5167 const int igroup = compo_to_group_[m];
5168 somme_contrib[igroup] += data.contrib_volume_phase1_;
5169
5170 index = data.index_facette_suivante_;
5171 };
5172 for (int igroup = 0; igroup < nb_groups_; igroup++)
5173 {
5174 while (somme_contrib[igroup] > 1.)
5175 somme_contrib[igroup] -= 1.;
5176 while (somme_contrib[igroup] < 0.)
5177 somme_contrib[igroup] += 1.;
5178 if (somme_contrib[igroup] > 0.)
5179 {
5180 // if(somme_contrib[igroup] == 1.)
5181 // somme_contrib[igroup] -= 1e-3;
5182 indic[igroup](i, j, k) = somme_contrib[igroup];
5183 num_compo[igroup][num_elem] = -1; // marque l'element pour apres
5184 }
5185 }
5186 }
5187 }
5188 }
5189 }
5190
5191 ArrOfInt drapeau[max_authorized_nb_of_groups_];
5192 statistics().create_custom_counter("Calcul de l'indicatrice : recherche compo connexes",2,"IJK");
5193 for (int i = 0; i < nb_groups_; i++)
5194 {
5195 statistics().begin_count("Calcul de l'indicatrice : recherche compo connexes",statistics().get_last_opened_counter_level()+1);
5196 num_compo[i].echange_espace_virtuel();
5197 // Recherche des composantes connexes sur le maillage eulerien
5198 int nb_compo_locales = search_connex_components_local(elem_faces, faces_voisins, num_compo[i]);
5199 nb_compo_in_num_compo_ = compute_global_connex_components(num_compo[i], nb_compo_locales);
5200 num_compo[i].echange_espace_virtuel();
5201 statistics().end_count("Calcul de l'indicatrice : recherche compo connexes");
5202
5203 // Calcul des drapeaux selon la methode la plus robuste :
5205 compute_drapeaux_vapeur_v4(num_compo[i], drapeau[i]);
5206 }
5207
5208 {
5209 // Mettre a zero l'indicatrice pour les elements qui sont dans des
5210 // composantes marquees:
5211 for (int k = 0; k < nk; k++)
5212 {
5213 for (int j = 0; j < nj; j++)
5214 {
5215 for (int i = 0; i < ni; i++)
5216 {
5217 const int num_elem = s.convert_ijk_cell_to_packed(i, j, k);
5218 for (int igroup = 0; igroup < nb_groups_; igroup++)
5219 {
5220 int compo = num_compo[igroup][num_elem];
5221 if (compo >= 0 && drapeau[igroup][compo] == 0)
5222 {
5223 // Element dans une bulle:
5224 indic[igroup](i, j, k) = 0.;
5225 }
5226 }
5227 }
5228 }
5229 }
5230 }
5231
5232 statistics().end_count("Calcul rho mu indicatrice: calcul des indicatrices");
5233}
5234
5235void IJK_Interfaces::calculer_indicatrices_optim(IJK_Field_vector3_double& indic)
5236{
5237 statistics().create_custom_counter("Calcul rho mu indicatrice: calcul des indicatrices",2,"IJK");
5238 statistics().begin_count("Calcul rho mu indicatrice: calcul des indicatrices",statistics().get_last_opened_counter_level()+1);
5239
5240 const Intersections_Elem_Facettes& intersec = maillage_ft_ijk_.intersections_elem_facettes();
5241 const Domaine_IJK& s = indic.get_domaine();
5242
5243 const int ni = indic[0].ni();
5244 const int nj = indic[0].nj();
5245 const int nk = indic[0].nk();
5246
5247 assert(nb_groups_ <= max_authorized_nb_of_groups_);
5248 const ArrOfInt& compo_connexe = maillage_ft_ijk_.compo_connexe_facettes();
5249
5250 // calcul des fractions de volume de phase 1 dans les mailles traversees par
5251 // des interfaces:
5252 {
5253 const ArrOfInt& index_elem = intersec.index_elem();
5254 // Boucle sur les elements euleriens
5255
5256 for (int k = 0; k < nk; k++)
5257 {
5258 for (int j = 0; j < nj; j++)
5259 {
5260 for (int i = 0; i < ni; i++)
5261 {
5262 const int num_elem = s.convert_ijk_cell_to_packed(i, j, k);
5263 int index = index_elem[num_elem];
5264 double somme_contrib[max_authorized_nb_of_groups_] = {0.};
5265
5266 for (int igroup = 0; igroup < nb_groups_; igroup++)
5267 {
5268 if (0. < indic[igroup](i, j, k) && indic[igroup](i, j, k) < 1.) // element traverse par l'indicatrice
5269 indic[igroup](i, j, k) = 2.;
5270 }
5271
5272 // Boucle sur les facettes qui traversent cet element
5273 while (index >= 0)
5274 {
5275 const Intersections_Elem_Facettes_Data& data = intersec.data_intersection(index);
5276 const int facette = data.numero_facette_;
5277 int icompo = compo_connexe[facette];
5278 int m = icompo;
5279 if (icompo < 0)
5280 {
5281 // Portion d'interface ghost.
5282 // On recherche le vrai numero
5283 m = decoder_numero_bulle(-icompo);
5284 }
5285 assert(0 <= m && m < nb_bulles_reelles_);
5286 const int igroup = compo_to_group_[m];
5287 somme_contrib[igroup] += data.contrib_volume_phase1_;
5288 index = data.index_facette_suivante_;
5289 };
5290 for (int igroup = 0; igroup < nb_groups_; igroup++)
5291 {
5292 while (somme_contrib[igroup] > 1.)
5293 somme_contrib[igroup] -= 1.;
5294 while (somme_contrib[igroup] < 0.)
5295 somme_contrib[igroup] += 1.;
5296 if (somme_contrib[igroup] > 0.)
5297 {
5298 indic[igroup](i, j, k) = somme_contrib[igroup];
5299 }
5300 }
5301 }
5302 }
5303 }
5304 }
5305
5306 for (int igroup = 0; igroup < nb_groups_; igroup++)
5307 {
5308 update_indicatrice(indic[igroup]);
5309 }
5310 statistics().end_count("Calcul rho mu indicatrice: calcul des indicatrices");
5311}
5312
5313int IJK_Interfaces::update_indicatrice(IJK_Field_double& indic)
5314{
5315 const int ni = indic.ni();
5316 const int nj = indic.nj();
5317 const int nk = indic.nk();
5318
5319 const Domaine_IJK& s = indic.get_domaine();
5320 const int imin = s.get_offset_local(DIRECTION_I);
5321 const int jmin = s.get_offset_local(DIRECTION_J);
5322 const int kmin = s.get_offset_local(DIRECTION_K);
5323
5324 const Domaine_IJK::Localisation loc = indic.get_localisation();
5325 const int nitot = s.get_nb_items_global(loc, DIRECTION_I);
5326 const int njtot = s.get_nb_items_global(loc, DIRECTION_J);
5327 const int nktot = s.get_nb_items_global(loc, DIRECTION_K);
5328
5329 indic.echange_espace_virtuel(indic.ghost());
5330
5331 //(l'algo peut etre optimise si on stocke les elements a phase indeterminee
5332 // plutot que de parcourir tous les elements du processeur a chaque passe)
5333 int continuer;
5334 do
5335 {
5336 continuer = 0;
5337 for (int k = 0; k < nk; k++)
5338 {
5339 for (int j = 0; j < nj; j++)
5340 {
5341 for (int i = 0; i < ni; i++)
5342 {
5343 if (indic(i, j, k) == 2.) // element a phase indeterminee: on doit le mettre a jour
5344 {
5345 ArrOfInt voisins_num(6);
5346 voisins_num[0] = i == 0 ? BORD : s.convert_ijk_cell_to_packed(i - 1, j, k);
5347 voisins_num[1] = j == 0 ? BORD : s.convert_ijk_cell_to_packed(i, j - 1, k);
5348 voisins_num[2] = k == 0 ? BORD : s.convert_ijk_cell_to_packed(i, j, k - 1);
5349 voisins_num[3] = i == ni - 1 ? BORD : s.convert_ijk_cell_to_packed(i + 1, j, k);
5350 voisins_num[4] = j == nj - 1 ? BORD : s.convert_ijk_cell_to_packed(i, j + 1, k);
5351 voisins_num[5] = k == nk - 1 ? BORD : s.convert_ijk_cell_to_packed(i, j, k + 1);
5352
5353 ArrOfDouble voisins_valeur(6);
5354 voisins_valeur[0] = imin + i == 0 ? BORD : indic(i - 1, j, k);
5355 voisins_valeur[1] = jmin + j == 0 ? BORD : indic(i, j - 1, k);
5356 voisins_valeur[2] = kmin + k == 0 ? BORD : indic(i, j, k - 1);
5357 voisins_valeur[3] = imin + i == nitot ? BORD : indic(i + 1, j, k);
5358 voisins_valeur[4] = jmin + j == njtot ? BORD : indic(i, j + 1, k);
5359 voisins_valeur[5] = kmin + k == nktot ? BORD : indic(i, j, k + 1);
5360
5361 int found = 0; // indique si on a trouve la phase de l'element ijk
5362
5363 // on regarde si parmi nos voisins, il y en a un qui est liquide ou
5364 // gazeux on regarde meme les voisins virtuels si oui, on adopte la
5365 // meme phase que lui
5366 for (int v = 0; v < 6; v++)
5367 {
5368 double valeur_indic_voisin = voisins_valeur[v];
5369 if (valeur_indic_voisin == 0. || valeur_indic_voisin == 1.)
5370 {
5371 indic(i, j, k) = valeur_indic_voisin;
5372 found = 1;
5373 break;
5374 }
5375 }
5376
5377 // sinon, on regarde si parmi nos voisins, il y a des cellules
5378 // coupees par l'interface on ne regarde que les voisins reels,
5379 // parce qu'on aura ensuite besoin de regarder les facettes qui les
5380 // traversent (pas possible avec les elements virtuels ? a voir...)
5381 if (!found)
5382 {
5383 for (int v = 0; v < 6; v++)
5384 {
5385 double valeur_indic_voisin = voisins_valeur[v];
5386 const int direction = v % 3;
5387 const int face_plus = (v > 2) ? 1 : -1; // +1 si c'est notre voisin de droite
5388
5389 if (0. < valeur_indic_voisin && valeur_indic_voisin < 1.)
5390 {
5391 int num_elem = voisins_num[v];
5392 if (num_elem != BORD)
5393 indic(i, j, k) =
5395 direction,
5396 -face_plus /* si le voisin courant est mon voisin de droite, alors notre face commune se trouve a sa gauche */);
5397 if (indic(i, j, k) != -1)
5398 {
5399 found = 1;
5400 break;
5401 }
5402 }
5403 }
5404 }
5405
5406 if (!found)
5407 {
5408 // element sur le bord entoure uniquement de cellules a phase
5409 // indeterminee ses voisins a phase indeterminee ont forcement des
5410 // cellules voisines traversees par l'interface ils pourront donc
5411 // trouver la valeur de leur indicatrice lors de la passe courante
5412 // la phase de l'element actuel pourra donc aussi etre trouvee
5413 // lors de la prochaine passe
5414 continuer = 1;
5415 }
5416 }
5417 }
5418 }
5419 }
5420 }
5421 while (continuer);
5422
5423 return 0;
5424}
5425
5426// Calcul de l'indicatrice surfacique et du barycentre de la phase sur les faces euleriennes
5427void IJK_Interfaces::calculer_indicatrice_surfacique_barycentre_face(IJK_Field_vector3_double& indic_surfacique_face, FixedVector<FixedVector<IJK_Field_double, 2>, 3>& baric_face, IJK_Field_double& indic, IJK_Field_vector3_double& norme)
5428{
5429 statistics().create_custom_counter("Calcul rho mu indicatrice: calcul de l'indicatrice surface face",2,"IJK");
5430 statistics().begin_count("Calcul rho mu indicatrice: calcul de l'indicatrice surface face",statistics().get_last_opened_counter_level()+1);
5431
5432 const Intersections_Elem_Facettes& intersec = maillage_ft_ijk_.intersections_elem_facettes();
5433 const Domaine_IJK& s = indic_surfacique_face.get_domaine();
5434
5435 const int ni = indic_surfacique_face[0].ni();
5436 const int nj = indic_surfacique_face[0].nj();
5437 const int nk = indic_surfacique_face[0].nk();
5438
5439 // Initialisation
5440 {
5441 for (int k = 0; k < nk; k++)
5442 {
5443 for (int j = 0; j < nj; j++)
5444 {
5445 for (int i = 0; i < ni; i++)
5446 {
5447 if (est_pure(indic(i, j, k)))
5448 {
5449 // Dans les cellules pures, on utilise l'indicatrice pour determiner la phase
5450 indic_surfacique_face[0](i, j, k) = indic(i, j, k);
5451 indic_surfacique_face[1](i, j, k) = indic(i, j, k);
5452 indic_surfacique_face[2](i, j, k) = indic(i, j, k);
5453 }
5454 else
5455 {
5456 // Dans les cellules diphasiques, on determine la phase a partir de la normale a l'interface
5457 // Ce calcul est important si la maille est diphasique mais que l'interface ne coupe pas la face
5458 indic_surfacique_face[0](i, j, k) = norme[0](i, j, k) == 0. ? 0. : (norme[0](i, j, k) > 0. ? 0. : 1.);
5459 indic_surfacique_face[1](i, j, k) = norme[1](i, j, k) == 0. ? 0. : (norme[1](i, j, k) > 0. ? 0. : 1.);
5460 indic_surfacique_face[2](i, j, k) = norme[2](i, j, k) == 0. ? 0. : (norme[2](i, j, k) > 0. ? 0. : 1.);
5461
5462 // Ce n'est pas toujours vrai, on corrige le cas ou une des cellules adjacentes est pure
5463 // Note : Cette methode pourrait ne pas toujours fonctionner ?
5464 if (est_pure(indic(i-1,j,k)))
5465 {
5466 indic_surfacique_face[0](i, j, k) = indic(i-1, j, k);
5467 }
5468 if (est_pure(indic(i,j-1,k)))
5469 {
5470 indic_surfacique_face[1](i, j, k) = indic(i, j-1, k);
5471 }
5472 if (est_pure(indic(i,j,k-1)))
5473 {
5474 indic_surfacique_face[2](i, j, k) = indic(i, j, k-1);
5475 }
5476 }
5477
5478 // Le barycentre est par defaut au milieu de la maille
5479 baric_face[0][0](i, j, k) = 0.5;
5480 baric_face[0][1](i, j, k) = 0.5;
5481 baric_face[1][0](i, j, k) = 0.5;
5482 baric_face[1][1](i, j, k) = 0.5;
5483 baric_face[2][0](i, j, k) = 0.5;
5484 baric_face[2][1](i, j, k) = 0.5;
5485 }
5486 }
5487 }
5488 }
5489
5490 // Correction pour les faces coupees par l'interface
5491 // Note : methode similaire a calculer_indicatrice
5492 {
5493 const ArrOfInt& index_elem = intersec.index_elem();
5494 // const int nb_elem = index_elem.size_array();
5495 // Boucle sur les elements euleriens
5496 for (int k = 0; k < nk; k++)
5497 {
5498 for (int j = 0; j < nj; j++)
5499 {
5500 for (int i = 0; i < ni; i++)
5501 {
5502 // Puisqu'il y a une tolerance sur le calcul de l'indicatrice, il se peut
5503 // qu'une cellule consideree pure soit traversee par l'interface.
5504 // Pour coherence, on considere les faces non coupees dans ce cas.
5505 if (!est_pure(indic(i, j, k)))
5506 {
5507 // Anciennement la methode etait portee par le mesh :
5508 // const int num_elem =
5509 // maillage_ft_ijk_.convert_ijk_cell_to_packed(i, j, k);
5510 // A present, elle est dans le splitting :
5511 const int num_elem = s.convert_ijk_cell_to_packed(i, j, k);
5512 int index = index_elem[num_elem];
5513 double somme_contrib[3] = {0., 0., 0.};
5514 double somme_contrib_baryc[3][2] = {{0., 0.}, {0., 0.}, {0., 0.}};
5515 // Boucle sur les facettes qui traversent cet element
5516 while (index >= 0)
5517 {
5518 const Intersections_Elem_Facettes_Data& data = intersec.data_intersection(index);
5519 somme_contrib[0] += data.contrib_aire_faces_phase1_[0];
5520 somme_contrib[1] += data.contrib_aire_faces_phase1_[1];
5521 somme_contrib[2] += data.contrib_aire_faces_phase1_[2];
5522
5523 somme_contrib_baryc[0][0] += data.contrib_barycentre_faces_phase1_[0][0]*abs(data.contrib_aire_faces_phase1_[0]);
5524 somme_contrib_baryc[0][1] += data.contrib_barycentre_faces_phase1_[0][1]*abs(data.contrib_aire_faces_phase1_[0]);
5525 somme_contrib_baryc[1][0] += data.contrib_barycentre_faces_phase1_[1][0]*abs(data.contrib_aire_faces_phase1_[1]);
5526 somme_contrib_baryc[1][1] += data.contrib_barycentre_faces_phase1_[1][1]*abs(data.contrib_aire_faces_phase1_[1]);
5527 somme_contrib_baryc[2][0] += data.contrib_barycentre_faces_phase1_[2][0]*abs(data.contrib_aire_faces_phase1_[2]);
5528 somme_contrib_baryc[2][1] += data.contrib_barycentre_faces_phase1_[2][1]*abs(data.contrib_aire_faces_phase1_[2]);
5529
5530 index = data.index_facette_suivante_;
5531 };
5532
5533 for (int dir=0; dir<3; dir++)
5534 {
5535 const int dir_i = (dir == 0);
5536 const int dir_j = (dir == 1);
5537 const int dir_k = (dir == 2);
5538
5539 if (est_pure(indic(i-dir_i,j-dir_j,k-dir_k)))
5540 {
5541 // Une cellule adjacente pure suggere ou bien qu'il n'y a pas d'intersections
5542 // ou bien qu'il y a des intersections mais que l'indicatrice resultante est
5543 // trop faible et en dessous du seuil dans calculer_indicatrice.
5544 // Pour coherence, on neglige la coupure de la surface egalement.
5545 }
5546 else
5547 {
5548 // Dans chaque direction, on ne touche qu'aux faces coupees
5549 if (somme_contrib[dir]*somme_contrib[dir] > 0)
5550 {
5551 while (somme_contrib[dir] > 1.)
5552 {
5553 somme_contrib[dir] -= 1.;
5554 somme_contrib_baryc[dir][0] -= 1./2.;
5555 somme_contrib_baryc[dir][1] -= 1./2.;
5556 }
5557 while (somme_contrib[dir] < 0.)
5558 {
5559 somme_contrib[dir] += 1.;
5560 somme_contrib_baryc[dir][0] += 1./2.;
5561 somme_contrib_baryc[dir][1] += 1./2.;
5562 }
5563
5564 indic_surfacique_face[dir](i, j, k) = somme_contrib[dir];
5565
5566 if (est_pure(somme_contrib[dir]))
5567 {
5568 baric_face[dir][0](i, j, k) = 1./2.;
5569 baric_face[dir][1](i, j, k) = 1./2.;
5570 }
5571 else
5572 {
5573 baric_face[dir][0](i, j, k) = somme_contrib_baryc[dir][0]/abs(somme_contrib[dir]);
5574 baric_face[dir][1](i, j, k) = somme_contrib_baryc[dir][1]/abs(somme_contrib[dir]);
5575
5576 // Un barycentre legerement negatif ou superieur a un est indicatif
5577 // d'une imprecision dans le calcul du barycentre.
5578 if ((baric_face[dir][0](i, j, k) <= 0) && (baric_face[dir][0](i, j, k) >= -1e-12 || somme_contrib[dir] < 1e-8))
5579 {
5580 baric_face[dir][0](i, j, k) = 1e-12;
5581 }
5582 else if ((baric_face[dir][0](i, j, k) >= 1) && (baric_face[dir][0](i, j, k) <= 1+1e-12 || somme_contrib[dir] < 1e-8))
5583 {
5584 baric_face[dir][0](i, j, k) = 1 - 1e-12;
5585 }
5586 if ((baric_face[dir][1](i, j, k) <= 0) && (baric_face[dir][1](i, j, k) >= -1e-12 || somme_contrib[dir] < 1e-8))
5587 {
5588 baric_face[dir][1](i, j, k) = 1e-12;
5589 }
5590 else if ((baric_face[dir][1](i, j, k) >= 1) && (baric_face[dir][1](i, j, k) <= 1+1e-12 || somme_contrib[dir] < 1e-8))
5591 {
5592 baric_face[dir][1](i, j, k) = 1 - 1e-12;
5593 }
5594
5595 assert((baric_face[dir][0](i, j, k) >= 0) && (baric_face[dir][0](i, j, k) <= 1));
5596 assert((baric_face[dir][1](i, j, k) >= 0) && (baric_face[dir][1](i, j, k) <= 1));
5597 assert(((indic_surfacique_face[dir](i, j, k) < 0.) && (baric_face[dir][0](i, j, k) < 0.)) || ((indic_surfacique_face[dir](i, j, k) > 0.) && (baric_face[dir][0](i, j, k) > 0.)));
5598 assert(((indic_surfacique_face[dir](i, j, k) < 0.) && (baric_face[dir][1](i, j, k) < 0.)) || ((indic_surfacique_face[dir](i, j, k) > 0.) && (baric_face[dir][1](i, j, k) > 0.)));
5599 }
5600 }
5601 }
5602 }
5603 }
5604 }
5605 }
5606 }
5607 }
5608 statistics().end_count("Calcul rho mu indicatrice: calcul de l'indicatrice surface face");
5609}
5610
5611// Calcul de l'indicatrice surfacique sur les faces euleriennes (sans le barycentre)
5612void IJK_Interfaces::calculer_indicatrice_surfacique_face(IJK_Field_vector3_double& indic_surfacique_face, IJK_Field_double& indic, IJK_Field_vector3_double& norme)
5613{
5614 statistics().create_custom_counter("Calcul rho mu indicatrice: calcul de l'indicatrice surface face",2,"IJK");
5615 statistics().begin_count("Calcul rho mu indicatrice: calcul de l'indicatrice surface face",statistics().get_last_opened_counter_level()+1);
5616
5617 const Intersections_Elem_Facettes& intersec = maillage_ft_ijk_.intersections_elem_facettes();
5618 const Domaine_IJK& s = indic_surfacique_face.get_domaine();
5619
5620 const int ni = indic_surfacique_face[0].ni();
5621 const int nj = indic_surfacique_face[0].nj();
5622 const int nk = indic_surfacique_face[0].nk();
5623
5624 // Initialisation
5625 {
5626 for (int k = 0; k < nk; k++)
5627 {
5628 for (int j = 0; j < nj; j++)
5629 {
5630 for (int i = 0; i < ni; i++)
5631 {
5632 if (est_pure(indic(i, j, k)))
5633 {
5634 // Dans les cellules pures, on utilise l'indicatrice pour determiner la phase
5635 indic_surfacique_face[0](i, j, k) = indic(i, j, k);
5636 indic_surfacique_face[1](i, j, k) = indic(i, j, k);
5637 indic_surfacique_face[2](i, j, k) = indic(i, j, k);
5638 }
5639 else
5640 {
5641 // Dans les cellules diphasiques, on determine la phase a partir de la normale a l'interface
5642 // Ce calcul est important si la maille est diphasique mais que l'interface ne coupe pas la face
5643 indic_surfacique_face[0](i, j, k) = norme[0](i, j, k) == 0. ? 0. : (norme[0](i, j, k) > 0. ? 0. : 1.);
5644 indic_surfacique_face[1](i, j, k) = norme[1](i, j, k) == 0. ? 0. : (norme[1](i, j, k) > 0. ? 0. : 1.);
5645 indic_surfacique_face[2](i, j, k) = norme[2](i, j, k) == 0. ? 0. : (norme[2](i, j, k) > 0. ? 0. : 1.);
5646
5647 // Ce n'est pas toujours vrai, on corrige le cas ou une des cellules adjacentes est pure
5648 // Note : Cette methode pourrait ne pas toujours fonctionner ?
5649 if (est_pure(indic(i-1,j,k)))
5650 {
5651 indic_surfacique_face[0](i, j, k) = indic(i-1, j, k);
5652 }
5653 if (est_pure(indic(i,j-1,k)))
5654 {
5655 indic_surfacique_face[1](i, j, k) = indic(i, j-1, k);
5656 }
5657 if (est_pure(indic(i,j,k-1)))
5658 {
5659 indic_surfacique_face[2](i, j, k) = indic(i, j, k-1);
5660 }
5661 }
5662 }
5663 }
5664 }
5665 }
5666
5667 // Correction pour les faces coupees par l'interface
5668 // Note : methode similaire a calculer_indicatrice
5669 {
5670 const ArrOfInt& index_elem = intersec.index_elem();
5671 // const int nb_elem = index_elem.size_array();
5672 // Boucle sur les elements euleriens
5673 for (int k = 0; k < nk; k++)
5674 {
5675 for (int j = 0; j < nj; j++)
5676 {
5677 for (int i = 0; i < ni; i++)
5678 {
5679 // Puisqu'il y a une tolerance sur le calcul de l'indicatrice, il se peut
5680 // qu'une cellule consideree pure soit traversee par l'interface.
5681 // Pour coherence, on considere les faces non coupees dans ce cas.
5682 if (!est_pure(indic(i, j, k)))
5683 {
5684 // Anciennement la methode etait portee par le mesh :
5685 // const int num_elem =
5686 // maillage_ft_ijk_.convert_ijk_cell_to_packed(i, j, k);
5687 // A present, elle est dans le splitting :
5688 const int num_elem = s.convert_ijk_cell_to_packed(i, j, k);
5689 int index = index_elem[num_elem];
5690 double somme_contrib[3] = {0., 0., 0.};
5691 // Boucle sur les facettes qui traversent cet element
5692 while (index >= 0)
5693 {
5694 const Intersections_Elem_Facettes_Data& data = intersec.data_intersection(index);
5695 somme_contrib[0] += data.contrib_aire_faces_phase1_[0];
5696 somme_contrib[1] += data.contrib_aire_faces_phase1_[1];
5697 somme_contrib[2] += data.contrib_aire_faces_phase1_[2];
5698
5699 index = data.index_facette_suivante_;
5700 };
5701
5702 for (int dir=0; dir<3; dir++)
5703 {
5704 const int dir_i = (dir == 0);
5705 const int dir_j = (dir == 1);
5706 const int dir_k = (dir == 2);
5707
5708 if (est_pure(indic(i-dir_i,j-dir_j,k-dir_k)))
5709 {
5710 // Une cellule adjacente pure suggere ou bien qu'il n'y a pas d'intersections
5711 // ou bien qu'il y a des intersections mais que l'indicatrice resultante est
5712 // trop faible et en dessous du seuil dans calculer_indicatrice.
5713 // Pour coherence, on neglige la coupure de la surface egalement.
5714 }
5715 else
5716 {
5717 // Dans chaque direction, on ne touche qu'aux faces coupees
5718 if (somme_contrib[dir]*somme_contrib[dir] > 0)
5719 {
5720 while (somme_contrib[dir] > 1.)
5721 {
5722 somme_contrib[dir] -= 1.;
5723 }
5724 while (somme_contrib[dir] < 0.)
5725 {
5726 somme_contrib[dir] += 1.;
5727 }
5728
5729 indic_surfacique_face[dir](i, j, k) = somme_contrib[dir];
5730 }
5731 }
5732 }
5733 }
5734 }
5735 }
5736 }
5737 }
5738 statistics().end_count("Calcul rho mu indicatrice: calcul de l'indicatrice surface face");
5739}
5740
5741
5742void IJK_Interfaces::calculer_surface_interface(IJK_Field_double& surf_interface, IJK_Field_double& indic)
5743{
5744 statistics().create_custom_counter("Calcul rho mu indicatrice: calcul de la surface interfaciale",2,"IJK");
5745 statistics().begin_count("Calcul rho mu indicatrice: calcul de la surface interfaciale",statistics().get_last_opened_counter_level()+1);
5746 const Intersections_Elem_Facettes& intersec = maillage_ft_ijk_.intersections_elem_facettes();
5747 const Domaine_IJK& s = surf_interface.get_domaine();
5748
5749 const ArrOfDouble& surface_facettes = maillage_ft_ijk_.get_update_surface_facettes();
5750
5751 const int ni = surf_interface.ni();
5752 const int nj = surf_interface.nj();
5753 const int nk = surf_interface.nk();
5754
5755 // Initialisation
5756 {
5757 for (int k = 0; k < nk; k++)
5758 {
5759 for (int j = 0; j < nj; j++)
5760 {
5761 for (int i = 0; i < ni; i++)
5762 {
5763 surf_interface(i, j, k) = 0.;
5764 }
5765 }
5766 }
5767 }
5768
5769 // Correction pour les faces coupees par l'interface
5770 // Note : methode similaire a calculer_indicatrice
5771 {
5772 const ArrOfInt& index_elem = intersec.index_elem();
5773 // const int nb_elem = index_elem.size_array();
5774 // Boucle sur les elements euleriens
5775 for (int k = 0; k < nk; k++)
5776 {
5777 for (int j = 0; j < nj; j++)
5778 {
5779 for (int i = 0; i < ni; i++)
5780 {
5781 // Puisqu'il y a une tolerance sur le calcul de l'indicatrice, il se peut
5782 // qu'une cellule consideree pure soit traversee par l'interface.
5783 if (!est_pure(indic(i, j, k)))
5784 {
5785 // Anciennement la methode etait portee par le mesh :
5786 // const int num_elem =
5787 // maillage_ft_ijk_.convert_ijk_cell_to_packed(i, j, k);
5788 // A present, elle est dans le splitting :
5789 const int num_elem = s.convert_ijk_cell_to_packed(i, j, k);
5790 int index = index_elem[num_elem];
5791 double somme_contrib_surf = 0.;
5792 // Boucle sur les facettes qui traversent cet element
5793 while (index >= 0)
5794 {
5795 const Intersections_Elem_Facettes_Data& data = intersec.data_intersection(index);
5796 const int fa7 = data.numero_facette_;
5797 somme_contrib_surf += data.fraction_surface_intersection_ * surface_facettes[fa7];
5798
5799 index = data.index_facette_suivante_;
5800 };
5801
5802 surf_interface(i, j, k) = somme_contrib_surf;
5803 assert(somme_contrib_surf >= 0.);
5804 }
5805 }
5806 }
5807 }
5808 }
5809 statistics().end_count("Calcul rho mu indicatrice: calcul de la surface interfaciale");
5810}
5811
5812void IJK_Interfaces::calculer_barycentre(IJK_Field_vector3_double& baric, IJK_Field_double& indic)
5813{
5814 statistics().create_custom_counter("Calcul rho mu indicatrice: calcul du barycentre",2,"IJK");
5815 statistics().begin_count("Calcul rho mu indicatrice: calcul du barycentre",statistics().get_last_opened_counter_level()+1);
5816 const Intersections_Elem_Facettes& intersec = maillage_ft_ijk_.intersections_elem_facettes();
5817 const Domaine_IJK& s = baric.get_domaine();
5818
5819 const int ni = baric[0].ni();
5820 const int nj = baric[0].nj();
5821 const int nk = baric[0].nk();
5822
5823 // Initialisation
5824 {
5825 for (int k = 0; k < nk; k++)
5826 {
5827 for (int j = 0; j < nj; j++)
5828 {
5829 for (int i = 0; i < ni; i++)
5830 {
5831 // Le barycentre est par defaut au milieu de la maille
5832 baric[0](i, j, k) = 0.5;
5833 baric[1](i, j, k) = 0.5;
5834 baric[2](i, j, k) = 0.5;
5835 }
5836 }
5837 }
5838 }
5839
5840 // Correction pour les faces coupees par l'interface
5841 // Note : methode similaire a calculer_indicatrice
5842 {
5843 const ArrOfInt& index_elem = intersec.index_elem();
5844 // const int nb_elem = index_elem.size_array();
5845 // Boucle sur les elements euleriens
5846 for (int k = 0; k < nk; k++)
5847 {
5848 for (int j = 0; j < nj; j++)
5849 {
5850 for (int i = 0; i < ni; i++)
5851 {
5852 // Puisqu'il y a une tolerance sur le calcul de l'indicatrice, il se peut
5853 // qu'une cellule consideree pure soit traversee par l'interface.
5854 if (!est_pure(indic(i, j, k)))
5855 {
5856 // Anciennement la methode etait portee par le mesh :
5857 // const int num_elem =
5858 // maillage_ft_ijk_.convert_ijk_cell_to_packed(i, j, k);
5859 // A present, elle est dans le splitting :
5860 const int num_elem = s.convert_ijk_cell_to_packed(i, j, k);
5861 int index = index_elem[num_elem];
5862 double somme_contrib = 0.;
5863 double somme_contrib_baryc[3] = {0., 0., 0.};
5864 // Boucle sur les facettes qui traversent cet element
5865 while (index >= 0)
5866 {
5867 const Intersections_Elem_Facettes_Data& data = intersec.data_intersection(index);
5868 somme_contrib += data.contrib_volume_phase1_;
5869
5870 somme_contrib_baryc[0] += data.contrib_barycentre_phase1_[0]*abs(data.contrib_volume_phase1_);
5871 somme_contrib_baryc[1] += data.contrib_barycentre_phase1_[1]*abs(data.contrib_volume_phase1_);
5872 somme_contrib_baryc[2] += data.contrib_barycentre_phase1_[2]*abs(data.contrib_volume_phase1_);
5873
5874 index = data.index_facette_suivante_;
5875 };
5876
5877 // int nb_increment_somme_contrib = 0;
5878 while (somme_contrib > 1.)
5879 {
5880 somme_contrib -= 1.;
5881 somme_contrib_baryc[0] -= 1./2.;
5882 somme_contrib_baryc[1] -= 1./2.;
5883 somme_contrib_baryc[2] -= 1./2.;
5884 // nb_increment_somme_contrib++;
5885 }
5886 while (somme_contrib < 0.)
5887 {
5888 somme_contrib += 1.;
5889 somme_contrib_baryc[0] += 1./2.;
5890 somme_contrib_baryc[1] += 1./2.;
5891 somme_contrib_baryc[2] += 1./2.;
5892 // nb_increment_somme_contrib++;
5893 }
5894
5895 // Note : On recalcule l'indicatrice, c'est un peu dommage
5896 assert(indic(i, j, k) == somme_contrib);
5897
5898 baric[0](i, j, k) = somme_contrib_baryc[0]/abs(somme_contrib);
5899 baric[1](i, j, k) = somme_contrib_baryc[1]/abs(somme_contrib);
5900 baric[2](i, j, k) = somme_contrib_baryc[2]/abs(somme_contrib);
5901
5902 // Un barycentre legerement negatif ou superieur a un est indicatif
5903 // d'une imprecision dans le calcul du barycentre.
5904 if ((baric[0](i, j, k) <= 0) && (baric[0](i, j, k) >= -1e-12 || somme_contrib < 1e-8))
5905 {
5906 baric[0](i, j, k) = 1e-12;
5907 }
5908 else if ((baric[0](i, j, k) >= 1) && (baric[0](i, j, k) <= 1+1e-12 || somme_contrib < 1e-8))
5909 {
5910 baric[0](i, j, k) = 1 - 1e-12;
5911 }
5912 if ((baric[1](i, j, k) <= 0) && (baric[1](i, j, k) >= -1e-12 || somme_contrib < 1e-8))
5913 {
5914 baric[1](i, j, k) = 1e-12;
5915 }
5916 else if ((baric[1](i, j, k) >= 1) && (baric[1](i, j, k) <= 1+1e-12 || somme_contrib < 1e-8))
5917 {
5918 baric[1](i, j, k) = 1 - 1e-12;
5919 }
5920 if ((baric[2](i, j, k) <= 0) && (baric[2](i, j, k) >= -1e-12 || somme_contrib < 1e-8))
5921 {
5922 baric[2](i, j, k) = 1e-12;
5923 }
5924 else if ((baric[2](i, j, k) >= 1) && (baric[2](i, j, k) <= 1+1e-12 || somme_contrib < 1e-8))
5925 {
5926 baric[2](i, j, k) = 1 - 1e-12;
5927 }
5928
5929 assert((baric[0](i, j, k) >= 0) && (baric[0](i, j, k) <= 1));
5930 assert((baric[1](i, j, k) >= 0) && (baric[1](i, j, k) <= 1));
5931 assert((baric[2](i, j, k) >= 0) && (baric[2](i, j, k) <= 1));
5932 assert(((indic(i, j, k) < 0.) && (baric[0](i, j, k) < 0.)) || ((indic(i, j, k) > 0.) && (baric[0](i, j, k) > 0.)));
5933 assert(((indic(i, j, k) < 0.) && (baric[1](i, j, k) < 0.)) || ((indic(i, j, k) > 0.) && (baric[1](i, j, k) > 0.)));
5934 assert(((indic(i, j, k) < 0.) && (baric[2](i, j, k) < 0.)) || ((indic(i, j, k) > 0.) && (baric[2](i, j, k) > 0.)));
5935 }
5936 }
5937 }
5938 }
5939 }
5940 statistics().end_count("Calcul rho mu indicatrice: calcul du barycentre");
5941}
5942
5943////////////////////////////////////////////////////////////////////////////////
5944
5945void IJK_Interfaces::convert_to_IntVect(const ArrOfInt& in, IntVect& out) const
5946{
5947 // Cree un tableau parallele structure comme un tableau aux elements
5948 // du maillage vdf, initialise a zero.
5949
5950 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, refdomaine_dis_.valeur());
5951 const Domaine& domaine = domaine_vf.domaine();
5952 domaine.creer_tableau_elements(out);
5953
5954 const int nb_elem = domaine.nb_elem();
5955 const int nb_elem_tot = domaine.nb_elem_tot();
5956 Cerr << "nb_elem= " << nb_elem << " nb_elem_tot= " << nb_elem_tot;
5957
5958 // Pour s'assurer que les tableaux ont la meme taille :
5959 assert(in.size_array() == out.size());
5960
5961 // La copie veut un pointeur vers le md_vector non initialise.
5962 // out.copy(in, /*RESIZE_OPTIONS opt*/ RESIZE_OPTIONS::COPY_INIT);
5963
5964 // On utilise dont le inject_array
5965 // mais comment s'assurer qu'on a mis le tableau au bon endroit? et pas un peu
5966 // dans l'espace virt?
5967 out.inject_array(in);
5969}
5970
5971#define NUM_COMPO_INVALID (-2000000000)
5972
5973// Ajout d'un terme en d(rho*v)/dt
5974// delta_rho = rho_liq - rho_vap
5975// la variable vpoint correspond a d(v)/dt, ou v correspond a nptquel valeur
5976// vrepul : OWN_PTR(Champ_base) etendu de potentiel de repulsion seul
5977// vabsrepul : OWN_PTR(Champ_base) etendu de la valeur absolue des repulsions.
5979 IJK_Field_vector3_double& vpoint,
5980 IJK_Field_vector3_double& vrepul,
5981 IJK_Field_vector3_double& vabsrepul
5982) const
5983{
5984 statistics().begin_count(STD_COUNTERS::source_terms,statistics().get_last_opened_counter_level()+1);
5985
5986 const Domaine_IJK& geom = ref_domaine_.valeur();
5987
5988 // deux options pour le calcul du terme source interfacial
5989 // 1 : use_tryggvason_interfacial_source --> Voir Muradoglu et Tryggvason
5990 // 2 : !use_tryggvason_interfacial_source --> Discretisation originale de B.Mathieu pour les cas sigma = cte (p.92 et suivantes de sa thèse)
5991 // on peut aussi faire des mixte : B.Mathieu pour la partie en sigma + terme source de Marangoni avec la formulation de Tryggvason
5992 // Le terme source de Marangoni nest code que dans lapproche de tryggvason pour le moment
5993
5994 if (use_tryggvason_interfacial_source_ or !maillage_ft_ijk_.Surfactant_facettes().get_disable_marangoni_source_term())
5995 {
5996 double interf1, interf2 ;
5997 double s1, s2 ;
5998 Int3 ijk_other_elem;
5999 for (int icol1 = 0; icol1 < max_authorized_nb_of_components_; icol1++)
6000 {
6001 for (int direction = 0; direction < 3; direction++)
6002 {
6003 for (int k = 0; k < vpoint[direction].nk(); k++)
6004 {
6005 for (int j = 0; j < vpoint[direction].nj(); j++)
6006 {
6007 for (int i = 0; i < vpoint[direction].ni(); i++)
6008 {
6009 // le traitement du terme source de tension de surface doit etre entierement explicit
6010 // on a donc besoin de tout stocker au pas de temps precedent dans next() avant le deplacement de linterface
6011 // on utilise alors les champ old n (avant deplacement).
6012 // les champs _par_compo sont calcules aux elements
6013 // on interpole aux faces pour ajouter à vpoint
6014 ijk_other_elem[0] = i;
6015 ijk_other_elem[1] = j;
6016 ijk_other_elem[2] = k;
6017 ijk_other_elem[direction] -= 1;
6018 s1 = surf_par_compo_[old()][icol1](i,j,k);
6019 s2 = surf_par_compo_[old()][icol1](ijk_other_elem[0],ijk_other_elem[1],ijk_other_elem[2]);
6020 interf1 = source_interf_par_compo_[old()][direction][icol1](i, j, k);
6021 interf2 = source_interf_par_compo_[old()][direction][icol1](ijk_other_elem[0],ijk_other_elem[1],ijk_other_elem[2]);
6022 vpoint[direction](i, j, k) += 1./2. * (s1 * interf1 + s2 * interf2);
6023 }
6024 }
6025 }
6026 }
6027 }
6028 }
6030 {
6031 // calculer la courbure et le terme de gravite aux sommets du maillage
6032 // lagrangien On appelle ce terme "phi", potentiel aux sommets
6033 // ducluz : voir p.93 et suivantes dans MathieuPhD
6034 Int3 ijk_face;
6035 const int nkmax = std::max(vpoint[DIRECTION_I].nk(), std::max(vpoint[DIRECTION_J].nk(), vpoint[DIRECTION_K].nk()));
6036 for (int k = 0; k < nkmax; k++)
6037 {
6038 for (int direction = 0; direction < 3; direction++)
6039 {
6040 if (k >= vpoint[direction].nk())
6041 continue;
6042
6043 const double delta_dir = geom.get_constant_delta(direction);
6044 const int offset = geom.get_offset_local(direction);
6045 const bool perio = geom.get_periodic_flag(direction);
6046 Domaine_IJK::Localisation loc = vpoint[direction].get_localisation();
6047 const int nb_items_tot = geom.get_nb_items_global(loc, direction);
6048 for (int j = 0; j < vpoint[direction].nj(); j++)
6049 {
6050 for (int i = 0; i < vpoint[direction].ni(); i++)
6051 {
6052 ijk_face[0] = i;
6053 ijk_face[1] = j;
6054 ijk_face[2] = k;
6055 const int global_face_position = ijk_face[direction] + offset;
6056 if (!perio && (global_face_position == 0 || global_face_position == nb_items_tot))
6057 continue; // on a wall...
6058
6059 Int3 ijk_droite = ijk_face; // l'element de droite a le meme num que la face
6060 Int3 ijk_gauche = ijk_face; // l'element de gauche est a l'indice - 1 ...
6061 ijk_gauche[direction]--;
6062
6063 // Boucle sur les elements a gauche et a droite de la face.
6064 // Selon le tour, on appelle un des elem : elem1
6065 for (int gauche_droite = 0; gauche_droite <= 1; gauche_droite++)
6066 {
6067 // Boucle sur les colonnes de l'elem1 :
6068 for (int icol1 = 0; icol1 < max_authorized_nb_of_components_; icol1++)
6069 {
6070 const Int3& elem1 = gauche_droite ? ijk_droite : ijk_gauche;
6071 const Int3& elem2 = gauche_droite ? ijk_gauche : ijk_droite;
6072 // Le signe pour le gradient :
6073 int signe = gauche_droite ? -1 : 1;
6074 int num_compo = compos_traversantes_[old()][icol1](elem1[0], elem1[1], elem1[2]);
6075 if (num_compo == NUM_COMPO_INVALID)
6076 break;
6077 // cette composante est-elle presente sur elem2 et a quelle
6078 // colonne ?
6079 int icol2;
6080 for (icol2 = 0; icol2 < max_authorized_nb_of_components_; icol2++)
6081 if (compos_traversantes_[old()][icol2](elem2[0], elem2[1], elem2[2]) == num_compo)
6082 break;
6083
6084 if (icol2 < max_authorized_nb_of_components_ && gauche_droite == 1)
6085 {
6086 // on a deja traite cette composante lorsqu'on a fait la boucle
6087 // pour gauche_droite = 0
6088 continue;
6089 }
6090
6091 const double indic = indicatrice_par_compo_[old()][icol1](elem1[0], elem1[1], elem1[2]);
6092
6093
6094 const double phi = phi_par_compo_[old()][icol1](elem1[0], elem1[1], elem1[2]);
6095
6096 const double surface = surface_par_compo_[old()][icol1](
6097 elem1[0], elem1[1], elem1[2]
6098 ); // la compo dans l'elem c'est icol1.
6099
6100 const double repul = repuls_par_compo_[old()][icol1](elem1[0], elem1[1], elem1[2]);
6102 {
6103 double indic_voisin = 0., phi_voisin = 0.;
6104 double repul_voisin = 0.;
6105 if (icol2 == max_authorized_nb_of_components_)
6106 {
6107 // il n'y a aucune intersection (reelle) par num_compo dans
6108 // l'elem voisin (elem2).
6109
6110 // Determine l'indicatrice dans l'element voisin lorsqu'il
6111 // n'est pas traverse. Pour cela, on se base sur une
6112 // comparaison de la position du centre de la face au plan
6113 // moyen defini par les facettes presentes dans l'element
6114 // elem.
6115 // Point du plan : bary_facettes_dans_elem
6116 // Normale au plan : normale (non-unitaire)
6117 //
6118 // Equation du plan :
6119 // F(X,Y,Z)=X*NX+Y*NY+Z*NZ+ CONSTANTE
6120 // CONSTANTE = -(NX*PX+NY*PY+NZ*PZ) ou P est un point du
6121 // plan,
6122 // ici, c'est le cdg des
6123 // facettes dans l'elem.
6124 //
6125 // F(X,Y,Z) = (X-PX)*NX + (Y-PY)*NY + (Z-PZ)*NZ
6126
6127 // F n'est pas une distance car normale non-unitaire.
6128 // Mais F est signee (positive si on va dans le sens de N, cad
6129 // vers le liquide)
6130
6131 // Coordonnees centre face :
6132 Vecteur3 centre_face = geom.get_coords_of_dof(ijk_face[0], ijk_face[1], ijk_face[2], loc);
6133
6134 Vecteur3 normale;
6135 Vecteur3 bary_facettes_dans_elem;
6136 for (int dir = 0; dir < 3; dir++)
6137 {
6138 const int idx = icol1 * 3 + dir;
6139 // TODO: aym attention, il a des chances que
6140 // normale_par_compo et bary_par_compo_[old()] ne soient pas
6141 // calcules au meme moment que indic_par_compo par exemple.
6142 // Ca risque de poser pb. Il faudra donc sirtir le calcul de
6143 // indic_par_compo de cette methode.
6144 normale[dir] = normale_par_compo_[old()][idx](elem1[0], elem1[1], elem1[2]);
6145 bary_facettes_dans_elem[dir] = bary_par_compo_[old()][idx](elem1[0], elem1[1], elem1[2]);
6146 }
6147 // Calcul du produit scalaire pour savoir de quel cote on est
6148 // :
6149 const double ps = Vecteur3::produit_scalaire(centre_face - bary_facettes_dans_elem, normale);
6150
6151 // Si la fonction F est positive, le voisin est liquide :
6152 indic_voisin = (ps > 0 ? 1. : 0.);
6153 phi_voisin = phi; // On prend le phi de l'elem1 puisque le
6154 // voisin (elem2) n'est pas traverse.
6155 repul_voisin = repul;
6156 }
6157 else
6158 {
6159 // la composante est presente dans l'element voisin
6160 // Le voisin est aussi traverse par num_compo.
6161 phi_voisin = phi_par_compo_[old()][icol2](elem2[0], elem2[1],
6162 elem2[2]); // la compo dans le voisin c'est icol2
6163 repul_voisin = repuls_par_compo_[old()][icol2](elem2[0], elem2[1],
6164 elem2[2]); // la compo dans le voisin c'est icol2
6165 indic_voisin = indicatrice_par_compo_[old()][icol2](elem2[0], elem2[1], elem2[2]);
6166 }
6167
6168 // Calcul du gradient a la face :
6169 double gradient_phi_indic = (phi_voisin * indic_voisin - phi * indic) / delta_dir * signe;
6170
6171 vpoint[direction](i, j, k) += gradient_phi_indic;
6172 double gradient_repul_indic = (repul_voisin * indic_voisin - repul * indic) / delta_dir * signe;
6173 vrepul[direction](i, j, k) += gradient_repul_indic;
6174 vabsrepul[direction](i, j, k) += fabs(gradient_repul_indic);
6175 }
6176 else
6177 {
6178 double indic_voisin = 0., phi_face = 0.;
6179 double repul_face = 0.;
6180 if (icol2 == max_authorized_nb_of_components_)
6181 {
6182 // il n'y a aucune intersection (reelle) par num_compo dans
6183 // l'elem voisin (elem2).
6184
6185 // Determine l'indicatrice dans l'element voisin lorsqu'il
6186 // n'est pas traverse. Pour cela, on se base sur une
6187 // comparaison de la position du centre de la face au plan
6188 // moyen defini par les facettes presentes dans l'element
6189 // elem.
6190 // Point du plan : bary_facettes_dans_elem
6191 // Normale au plan : normale (non-unitaire)
6192 //
6193 // Equation du plan :
6194 // F(X,Y,Z)=X*NX+Y*NY+Z*NZ+ CONSTANTE
6195 // CONSTANTE = -(NX*PX+NY*PY+NZ*PZ) ou P est un point du
6196 // plan,
6197 // ici, c'est le cdg des
6198 // facettes dans l'elem.
6199 //
6200 // F(X,Y,Z) = (X-PX)*NX + (Y-PY)*NY + (Z-PZ)*NZ
6201
6202 // F n'est pas une distance car normale non-unitaire.
6203 // Mais F est signee (positive si on va dans le sens de N, cad
6204 // vers le liquide)
6205
6206 // Coordonnees centre face :
6207 Vecteur3 centre_face = geom.get_coords_of_dof(ijk_face[0], ijk_face[1], ijk_face[2], loc);
6208
6209 Vecteur3 normale;
6210 Vecteur3 bary_facettes_dans_elem;
6211 for (int dir = 0; dir < 3; dir++)
6212 {
6213 const int idx = icol1 * 3 + dir;
6214 // TODO: AYM pareil attention a la synchro avec le maillage.
6215 normale[dir] = normale_par_compo_[old()][idx](elem1[0], elem1[1], elem1[2]);
6216 bary_facettes_dans_elem[dir] = bary_par_compo_[old()][idx](elem1[0], elem1[1], elem1[2]);
6217 }
6218 // Calcul du produit scalaire pour savoir de quel cote on est
6219 // :
6220 const double ps = Vecteur3::produit_scalaire(centre_face - bary_facettes_dans_elem, normale);
6221
6222 // Si la fonction F est positive, le voisin est liquide :
6223 indic_voisin = (ps > 0 ? 1. : 0.);
6224 phi_face = phi; // On prend le phi de l'elem1 puisque le
6225 // voisin (elem2) n'est pas traverse.
6226 repul_face = repul;
6227
6228 }
6229 else
6230 {
6231 // la composante est presente dans l'element voisin
6232 // Le voisin est aussi traverse par num_compo.
6233 const double phi_voisin = phi_par_compo_[old()][icol2](elem2[0], elem2[1],
6234 elem2[2]); // la compo dans le voisin c'est icol2
6235
6236 const double repul_voisin = repuls_par_compo_[old()][icol2](elem2[0], elem2[1],
6237 elem2[2]); // la compo dans le voisin c'est icol2
6238 indic_voisin = indicatrice_par_compo_[old()][icol2](elem2[0], elem2[1], elem2[2]);
6239
6240 const double surface_voisin = surface_par_compo_[old()][icol2](
6241 elem2[0], elem2[1], elem2[2]
6242 ); // la compo dans le voisin c'est icol2
6243 // assert provisoir :
6244
6245 assert(compos_traversantes_[old()][icol2](elem2[0], elem2[1], elem2[2]) == num_compo);
6246 assert(indic_voisin > -0.5);
6247 if (est_egal(surface+surface_voisin,0.))
6248 {
6249 phi_face = 0.;
6250 repul_face = 0.;
6251 }
6252 else
6253 {
6254 // Il faut calculer le phi moyen a la face :
6255 phi_face = (phi * surface + phi_voisin * surface_voisin) / (surface + surface_voisin);
6256 repul_face = (repul * surface + repul_voisin * surface_voisin) / (surface + surface_voisin);
6257 }
6258 }
6259 // Calcul du gradient a la face :
6260 double gradient_indic = (indic_voisin - indic) / delta_dir * signe;
6261
6262
6263 // terme de repulsion
6264 // parcourir les elements voisins jusqu'a une distance d (en
6265 // mailles) si un element voisin contient une composante connexe
6266 // differente, trouver la plus petite distance a cette
6267 // composante
6268
6269
6270 vpoint[direction](i, j, k) += phi_face * gradient_indic ;
6271 vrepul[direction](i, j, k) += repul_face * gradient_indic;
6272 vabsrepul[direction](i, j, k) += fabs(repul_face * gradient_indic);
6273 }
6274 }
6275 }
6276 }
6277 }
6278 }
6279 }
6280 }
6281 statistics().end_count(STD_COUNTERS::source_terms);
6282}
6283
6284static inline double determinant(const Vecteur3& v1, const Vecteur3& v2, const Vecteur3& v3)
6285{
6286 Vecteur3 tmp;
6287 Vecteur3::produit_vectoriel(v1, v2, tmp);
6288 return Vecteur3::produit_scalaire(tmp, v3);
6289}
6290// A et B sont les points du segment.
6291// C, D et E les sommets du triangle.
6292// Retourne false dans les cas pathologiques ou un determinant est nul.
6293static bool intersection_segment_triangle(const Vecteur3& A,
6294 const Vecteur3& B,
6295 const Vecteur3& C,
6296 const Vecteur3& D,
6297 const Vecteur3& E)
6298{
6299 // A et B sont-ils de part et d'autre du plan?
6300 // Le produit vectoriel det(CD, CE, CA) ne doit pas avoir le meme signe que
6301 // det(CD, CE, CB)
6302 Vecteur3 CD, CE, CA, CB;
6303 CD = D - C;
6304 CE = E - C;
6305 CA = A - C;
6306 CB = B - C;
6307 const double det1 = determinant(CD, CE, CA);
6308 const double det2 = determinant(CD, CE, CB);
6309
6310 if (det1 * det2 >= 0)
6311 return false; // Le segment ne coupe pas le plan ABC.
6312
6313 // L'intersection est-elle dans le triangle?
6314 // Tous les determinants pris dans le meme ordre doivent etre de meme signe :
6315 Vecteur3 AB, AC, AD, AE;
6316 AB = B - A;
6317 AC = C - A;
6318 AD = D - A;
6319 AE = E - A;
6320 const double det3 = determinant(AC, AD, AB);
6321 const double det4 = determinant(AD, AE, AB);
6322 const double det5 = determinant(AE, AC, AB);
6323
6324 if ((det3 * det4 <= 0) || (det3 * det5 <= 0))
6325 return false; // Le segment coupe le plan ABC mais en dehors du triangle.
6326
6327 return true;
6328}
6329
6330int IJK_Interfaces::compute_cell_phase_with_interface_normal(int num_elem, int direction, int face_plus)
6331{
6332 const Domaine_IJK& split = ref_domaine_.valeur();
6333 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
6334 const Intersections_Elem_Facettes& intersections = mesh.intersections_elem_facettes();
6335
6336 const IntTab& facettes = mesh.facettes();
6337 const DoubleTab& sommets = mesh.sommets();
6338 const Vecteur3 cell_size(split.get_constant_delta(DIRECTION_I),
6339 split.get_constant_delta(DIRECTION_J),
6340 split.get_constant_delta(DIRECTION_K));
6341
6342 ArrOfInt facettes_traversantes;
6343 intersections.get_liste_facettes_traversantes(num_elem, facettes_traversantes);
6344 const int N = facettes_traversantes.size_array();
6345
6346 if (N == 0)
6347 return -1;
6348
6349 // on parcourt les facettes qui traversent l'element num_elem
6350 int index = 0;
6351 while (1)
6352 {
6353 int fa7 = facettes_traversantes[index];
6354 const Intersections_Elem_Facettes_Data& data = intersections.data_intersection(fa7);
6355
6356 // Comme dans compute_list_compo_connex_in_element, on ne parcourt pas les
6357 // facettes de fraction surface nulle. Note BM: je suis tombe sur un cas ou
6358 // l'interface a une fraction de 1e-9 dans la facette,
6359 // ca produit une erreur ensuite a cause des arrondis, le resultat est
6360 // faux, donc je mets
6361 // une limite a 1e3 pour ne pas utiliser les facettes qui ont une fraction
6362 // d'intersection trop faible
6363 if (data.fraction_surface_intersection_ < 1e-2)
6364 {
6365 index++;
6366 if (index == N) // on a parcouru toutes les facettes et aucune ne
6367 // convient: echec de la methode
6368 return -1;
6369 continue;
6370 }
6371
6372 FixedVector<Vecteur3, 3> sommets_facette;
6373 for (int i = 0; i < 3; i++)
6374 sommets_facette[i] = Vecteur3(sommets, facettes(fa7, i));
6375
6376 /* calcule du segment AB partant du centre de gravite
6377 * de l'intersection facette elem (A) vers la projection orthogonale de A
6378 * sur la face commune avec le voisin qu'on cherche a evaluer (B) */
6379
6380 // Coordonnees de A (pas barycentriques) :
6381 Vecteur3 coordA(0., 0., 0.);
6382 for (int isom = 0; isom < 3; isom++)
6383 {
6384 const double bary_som = data.barycentre_[isom];
6385 for (int dir = 0; dir < 3; dir++)
6386 coordA[dir] += bary_som * sommets_facette[isom][dir];
6387 }
6388 // Coordonnees de B, au lieu de prendre la coordonnee du centre de la face,
6389 // on prend un point un peu plus loin dans l'element voisin, de toutes
6390 // facons l'element voisin n'est pas traverse par l'interface donc si on
6391 // trouve une intersection c'est forcement dans l'element courant.
6392 Vecteur3 coordB = coordA;
6393 coordB[direction] += cell_size[direction] * face_plus;
6394
6395 // on parcourt toutes les facettes de l'element pour voir si l'une d'entre
6396 // elles intersecte le segment AB
6397 bool coupe = false;
6398 for (int index2 = intersections.index_elem()[num_elem]; index2 >= 0;
6399 index2 = intersections.data_intersection(index2).index_facette_suivante_)
6400 {
6401 const Intersections_Elem_Facettes_Data& data2 = intersections.data_intersection(index2);
6402 const int nvl_fa7 = data2.numero_facette_;
6403 if ((nvl_fa7 == fa7) || (data2.fraction_surface_intersection_ == 0))
6404 continue;
6405 // Les Coords des 3 sommets de la nouvelle facette :
6406 const Vecteur3 s0(sommets, facettes(nvl_fa7, 0));
6407 const Vecteur3 s1(sommets, facettes(nvl_fa7, 1));
6408 const Vecteur3 s2(sommets, facettes(nvl_fa7, 2));
6409
6410 // Y-a-t-il interstion entre AB et cette facette?
6411 coupe = intersection_segment_triangle(coordA, coordB, s0, s1, s2);
6412
6413 if (coupe)
6414 {
6415 // il y a une facette entre fa7 et la face de l'elem qui nous interesse
6416 // on saute toutes les fa7 jusqu'a nvl_fa7
6417 for (int j = 0; j < N; j++)
6418 {
6419 if (facettes_traversantes[j] == nvl_fa7)
6420 index = j;
6421 }
6422 break;
6423 }
6424 }
6425 // pas de coupe : on peut determiner la phase de l'element voisin
6426 // car il n'y a aucun obstacle entre la facete fa7 et l'element voisin
6427 // on evalue pour cela le vecteur normal a la facette
6428 if (!coupe)
6429 {
6430 Vecteur3 normale_facette;
6431 Vecteur3::produit_vectoriel(sommets_facette[1] - sommets_facette[0], sommets_facette[2] - sommets_facette[0],
6432 normale_facette);
6433
6434 if (normale_facette[direction] * face_plus > 0.) // cellule liquide
6435 return 1;
6436 else // cellule gazeuse
6437 return 0;
6438 }
6439 }
6440}
6441
6442// Ce define active une validation complete:
6443// pour chaque element pour lequel on peut determiner s'il est liquide ou
6444// vapeur, on incremente un compteur et on verifie a la fin que tous les
6445// compteurs sont coherents.
6446
6447#define COMPUTE_DRAPEAUX_VALIDATION
6448
6449void IJK_Interfaces::compute_drapeaux_vapeur_v4(const IntVect& vecteur_composantes,
6450 ArrOfInt& drapeau_vapeur) const
6451{
6452 statistics().create_custom_counter("Calcul de l'indicatrice: calculs des drapeaux",2,"IJK");
6453 statistics().begin_count("Calcul de l'indicatrice: calculs des drapeaux",statistics().get_last_opened_counter_level()+1);
6454
6455 const Domaine_IJK& split = ref_domaine_.valeur();
6456 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
6457 const Intersections_Elem_Facettes& intersections = mesh.intersections_elem_facettes();
6458 const ArrOfInt& index_elem = maillage_ft_ijk_.intersections_elem_facettes().index_elem();
6459 const ArrOfInt& index_facette = maillage_ft_ijk_.intersections_elem_facettes().index_facette();
6460
6461 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, refdomaine_dis_.valeur());
6462 const IntTab& elem_faces = domaine_vf.elem_faces();
6463 const IntTab& faces_voisins = domaine_vf.face_voisins();
6464
6465#ifdef COMPUTE_DRAPEAUX_VALIDATION
6466 ArrOfInt composantes_comptage_phase0(drapeau_vapeur.size_array());
6467 ArrOfInt composantes_comptage_phase1(drapeau_vapeur.size_array());
6468#endif
6469
6470 drapeau_vapeur = 0; // Tout vapeur
6471 const Vecteur3 cell_size(split.get_constant_delta(DIRECTION_I),
6472 split.get_constant_delta(DIRECTION_J),
6473 split.get_constant_delta(DIRECTION_K));
6474
6475 const int nb_facettes = mesh.nb_facettes();
6476 const IntTab& facettes = mesh.facettes();
6477 const DoubleTab& sommets = mesh.sommets();
6478 for (int fa7 = 0; fa7 < nb_facettes; fa7++)
6479 {
6480 // On parcourt aussi les facettes virtuelles
6481 // mais on ne parcourt pas les facettes de
6482 // data.fraction_surface_intersection_ == 0.
6483 FixedVector<Vecteur3, 3> sommets_facette;
6484 {
6485 for (int i = 0; i < 3; i++)
6486 sommets_facette[i] = Vecteur3(sommets, facettes(fa7, i));
6487 }
6488 int index = index_facette[fa7];
6489 while (index >= 0)
6490 {
6491 const Intersections_Elem_Facettes_Data& data = intersections.data_intersection(index);
6492
6493 // Comme dans compute_list_compo_connex_in_element, on ne parcours pas les
6494 // facettes de fraction surface nulle. Note BM: je suis tombe sur un cas
6495 // ou l'interface a une fraction de 1e-9 dans la facette,
6496 // ca produit une erreur ensuite a cause des arrondis, le resultat est
6497 // faux, donc je mets
6498 // une limite a 1e3 pour ne pas utiliser les facettes qui ont une fraction
6499 // d'intersection trop faible
6500 if (data.fraction_surface_intersection_ < 1e-2)
6501 {
6502 /* Cerr << "compute_drapeaux_vapeur_v4 : elem= " <<
6503 data.numero_element_
6504 << " Intersection issue du parcours : numero_facette_= " <<
6505 data.numero_facette_
6506 << " numero_element_= " << data.numero_element_
6507 << " fraction= " << data.fraction_surface_intersection_ << finl;
6508 */
6509 index = data.index_element_suivant_;
6510 continue; // On zappe cette facette...
6511 }
6512
6513 const int elem = data.numero_element_;
6514 /* boucle sur les faces de cet element */
6515
6516 for (int iface = 0; iface < 6; iface++)
6517 {
6518 const int direction = iface % 3;
6519 const int face_plus = (iface > 2) ? 1 : -1; // +1 si on est sur la face de droite de l'element
6520
6521 const int num_face = elem_faces(elem, iface);
6522 const int elem_voisin = faces_voisins(num_face, 0) + faces_voisins(num_face, 1) - elem;
6523 // Si on est au bord du domaine, ne pas faire la suite:
6524 if (elem_voisin < 0)
6525 {
6526 continue;
6527 }
6528 // Si l'element voisin n'est pas traverse par une facette (sinon,
6529 // global_compo=-1) et que sa compo n'est pas deja marquee :
6530 const int global_compo_voisin = vecteur_composantes[elem_voisin];
6531
6532 // Si l'element voisin est traverse par une interface, ne pas faire la
6533 // suite
6534 if (global_compo_voisin < 0)
6535 continue;
6536
6537#ifndef COMPUTE_DRAPEAUX_VALIDATION
6538 // s'il est deja marque "1" ne pas faire la suite (sauf si validation de
6539 // l'algorihme)
6540 if (drapeau_vapeur[global_compo_voisin] == 1)
6541 continue;
6542#endif
6543 Vecteur3 normale_facette;
6544 Vecteur3::produit_vectoriel(sommets_facette[1] - sommets_facette[0],
6545 sommets_facette[2] - sommets_facette[0],
6546 normale_facette);
6547
6548#ifndef COMPUTE_DRAPEAUX_VALIDATION
6549 // Si la normale a la facette est telle que l'element voisin doit etre
6550 // d'indicatrice 0, ne pas faire la suite (sauf si validation de
6551 // l'algorithme)
6552 if (normale_facette[direction] * face_plus <= 0.)
6553 continue;
6554#endif
6555 /* calcule du segment AB partant du centre de gravite
6556 de l'intersection facette elem (A) vers la projection de A
6557 sur la face orthogonalement a la face (B) */
6558
6559 // Coordonnees de A (pas barycentriques) :
6560 Vecteur3 coordA(0., 0., 0.);
6561 for (int isom = 0; isom < 3; isom++)
6562 {
6563 const double bary_som = data.barycentre_[isom];
6564 for (int dir = 0; dir < 3; dir++)
6565 coordA[dir] += bary_som * sommets_facette[isom][dir];
6566 }
6567
6568 // Coordonnees de B, au lieu de prendre la coordonnee du centre de la
6569 // face, on prend un point un peu plus loin dans l'element voisin, de
6570 // toutes facons l'element voisin n'est pas traverse par l'interface
6571 // donc si on trouve une intersection c'est forcement dans l'element
6572 // courant.
6573 Vecteur3 coordB = coordA;
6574 coordB[direction] += cell_size[direction] * face_plus;
6575
6576 /* si le segment AB coupe une autre facette dans l'element
6577 ou s'il y a une ambiguite (un determinant nul dans le calcul)
6578 on ne peut pas determiner le signe de l'indicatrice chez le voisin */
6579 // Boucle sur les facettes dans l'element :
6580 bool coupe = false;
6581 // Une facon differente d'ecrire la boucle while, permet de ne pas
6582 // dupliquer la ligne data2.index_facette_suivante_
6583 for (int index2 = index_elem[elem]; index2 >= 0;
6584 index2 = intersections.data_intersection(index2).index_facette_suivante_)
6585 {
6586 const Intersections_Elem_Facettes_Data& data2 = intersections.data_intersection(index2);
6587 const int nvl_fa7 = data2.numero_facette_;
6588 if ((nvl_fa7 == fa7) || (data2.fraction_surface_intersection_ == 0))
6589 continue;
6590 // Les Coords des 3 sommets de la nouvelle facette :
6591 const Vecteur3 s0(sommets, facettes(nvl_fa7, 0));
6592 const Vecteur3 s1(sommets, facettes(nvl_fa7, 1));
6593 const Vecteur3 s2(sommets, facettes(nvl_fa7, 2));
6594
6595 // Y-a-t-il interstion entre AB et cette facette?
6596 coupe = intersection_segment_triangle(coordA, coordB, s0, s1, s2);
6597
6598 if (coupe)
6599 break; // Il y a une facette (nvl_fa7) entre fa7 et l'element
6600 // voisin, on ne pourra pas determiner l'indicatrice
6601 }
6602
6603 // Il n'y a pas d'autre facette entre "fa7" et l'element voisin, on peut
6604 // donc determiner le signe de l'indicatrice dans l'element voisin
6605 if (!coupe)
6606 {
6607 if (normale_facette[direction] * face_plus > 0.)
6608 drapeau_vapeur[global_compo_voisin] = 1;
6609#ifdef COMPUTE_DRAPEAUX_VALIDATION
6610 // Incremente les compteurs pour la phase trouvee:
6611 if (normale_facette[direction] * face_plus > 0.)
6612 {
6613 composantes_comptage_phase1[global_compo_voisin]++;
6614 // Arrete tout de suite si c'est incoherent (on a trouve
6615 // precedemment que ca doit etre phase 0)
6616 // if (composantes_comptage_phase0[global_compo_voisin]>0) {
6617 // Cerr << "Erreur ! " << finl;
6618 //}
6619 // assert(composantes_comptage_phase0[global_compo_voisin] == 0);
6620 }
6621 if (normale_facette[direction] * face_plus < 0.)
6622 {
6623 composantes_comptage_phase0[global_compo_voisin]++;
6624 // Arrete tout de suite si c'est incoherent (on a trouve
6625 // precedemment que ca doit etre phase 1)
6626 // if (composantes_comptage_phase1[global_compo_voisin]>0) {
6627 // Cerr << "Erreur ! " << finl;
6628 //}
6629 // assert(composantes_comptage_phase1[global_compo_voisin] == 0);
6630 }
6631#endif
6632 }
6633 }
6634 // Boucle while externe.
6635 index = data.index_element_suivant_;
6636 }
6637 }
6638
6639 // Synchroniser les marqueurs sur tous les processeurs
6640 mp_max_for_each_item(drapeau_vapeur);
6641
6642 // Verifier que les comptages sont coherents entre les differents processeurs:
6643#ifdef COMPUTE_DRAPEAUX_VALIDATION
6644 {
6645 const int n = composantes_comptage_phase0.size_array();
6646 mp_sum_for_each_item(composantes_comptage_phase0);
6647 mp_sum_for_each_item(composantes_comptage_phase1);
6649 {
6650 int problem = 0;
6651 for (int i = 0; i < n; i++)
6652 {
6653 // si on a trouve a la fois phase 0 et phase 1 pour une composante:
6654 // probleme si on a trouve aucune phase pour une composante: probleme,
6655 // phase indeterminee
6656 if ((composantes_comptage_phase0[i] > 0 && composantes_comptage_phase1[i] > 0) ||
6657 (composantes_comptage_phase0[i] == 0 && composantes_comptage_phase1[i] == 0))
6658 {
6659 problem += 1;
6660 if (problem == 1)
6661 {
6662 Cerr << "[WARNING-Indic-Vote] compo/#phase0/#phase1 ";
6663 }
6664 Cerr << i
6665 << "/" << composantes_comptage_phase0[i]
6666 << "/" << composantes_comptage_phase1[i]
6667 << " ";
6668
6669 // vote majoritaire:
6670 if (composantes_comptage_phase0[i] > composantes_comptage_phase1[i])
6671 drapeau_vapeur[i] = 0;
6672 else
6673 drapeau_vapeur[i] = 1;
6674 }
6675 }
6676 if (problem > 0)
6677 Cerr << "End." << finl;
6678 }
6679 envoyer_broadcast(drapeau_vapeur, 0);
6680 }
6681#endif
6682
6683 statistics().end_count("Calcul de l'indicatrice: calculs des drapeaux");
6684}
6685
6686static inline double norme_carre(const Vecteur3& x)
6687{
6688 return x[0] * x[0] + x[1] * x[1] + x[2] * x[2];
6689}
6690
6691inline Vecteur3 operator*(double x, const Vecteur3& v)
6692{
6693 return Vecteur3(x * v[0], x * v[1], x * v[2]);
6694}
6695inline Vecteur3 operator+(const Vecteur3& v, const Vecteur3& w)
6696{
6697 return Vecteur3(v[0] + w[0], v[1] + w[1], v[2] + w[2]);
6698}
6699
6700static inline double calculer_carre_distance_sommet_facette(const Vecteur3& coord,
6701 const Maillage_FT_IJK& mesh,
6702 int num_facette)
6703{
6704 const IntTab& facettes = mesh.facettes();
6705 const DoubleTab& sommets = mesh.sommets();
6706 Vecteur3 s0(sommets, facettes(num_facette, 0));
6707 Vecteur3 s1(sommets, facettes(num_facette, 1));
6708 Vecteur3 s2(sommets, facettes(num_facette, 2));
6709
6710 // Il faut coder une algorithme d'Uzawa.
6711 // Met de cote, pour l'instant, je prends juste la distance min
6712 // entre coord et les trois sommets.
6713
6714 double d = 1e10;
6715 for (double x = 0.; x < 1.01; x += 0.2)
6716 for (double y = 0.; y < 1. - x + 0.01; y += 0.2)
6717 {
6718 Vecteur3 s = s0 + x * (s1 - s0) + y * (s2 - s0);
6719 d = std::min(d, norme_carre(s - coord));
6720 }
6721 return d;
6722}
6723
6724static void fill_relative_velocity(const DoubleTab& vinterp_tmp, const DoubleTab& vinterp, const IntTab& facettes, int id_facette, int som, DoubleTab& vr_to_other)
6725{
6726 const double un_tiers = 1. / 3.;
6727 if (id_facette == -1)
6728 {
6729 // Noone else is found in the given neighbourhood... default value for vr
6730 // is set to zero... why not?
6731 for (int idir = 0; idir < 3; idir++)
6732 vr_to_other(som, idir) = 0.;
6733 }
6734 else
6735 {
6736 // indexes of the 3 vertices of the facette:
6737 const int isom0 = facettes(id_facette, 0);
6738 const int isom1 = facettes(id_facette, 1);
6739 const int isom2 = facettes(id_facette, 2);
6740 for (int idir = 0; idir < 3; idir++)
6741 {
6742 // Carreful, one is an index in the list (i), whereas "isomN" are
6743 // indexes in the mesh!
6744 const double velocity_me = vinterp_tmp(som, idir);
6745 const double velocity_other =
6746 un_tiers * (vinterp(isom0, idir) + vinterp(isom1, idir) + vinterp(isom2, idir));
6747 vr_to_other(som, idir) = velocity_me - velocity_other;
6748 }
6749 }
6750}
6751
6752// Warning : sizes are for nb_sommets in the list sommets_a_tester, not for
6753// mesh!! vr_to_other : the relative velocity to the closest marker.
6755 const ArrOfInt& compo_connexe_sommets,
6756 const DoubleTab& vinterp_tmp,
6757 const Maillage_FT_IJK& mesh,
6758 ArrOfDouble& distance,
6759 DoubleTab& vr_to_other,
6760 const double distmax)
6761{
6762 // Construction d'un octree avec les facettes du maillage
6763 Octree_Double octree;
6764 const IntTab& facettes = mesh.facettes();
6765 octree.build_elements(mesh.sommets(), facettes,
6766 0. /* epsilon */, 0 /* utiliser dimension(0) pas dimension_tot(0),
6767 ca n'a pas d'importance ici */);
6768
6769 ArrOfInt liste_facettes;
6770 const ArrOfInt& compo_connexe_facettes = mesh.compo_connexe_facettes();
6771
6772 const int nb_som = sommets_a_tester.dimension(0);
6773 distance.resize_array(nb_som, RESIZE_OPTIONS::NOCOPY_NOINIT);
6774 distance = distmax;
6775 vr_to_other.resize(nb_som, 3, RESIZE_OPTIONS::NOCOPY_NOINIT);
6776 vr_to_other = -1e5; // Invalid value
6777 assert(vinterp_tmp.dimension(0) == nb_som);
6778 for (int i = 0; i < nb_som; i++)
6779 {
6780 Vecteur3 coord(sommets_a_tester, i);
6781 const int compo_connexe_som = compo_connexe_sommets[i];
6782
6783 double dmin = distmax * distmax;
6784
6785 // Recherche dans l'octree des facettes proches de ce point:
6786 octree.search_elements_box(coord[0] - distmax, coord[1] - distmax, coord[2] - distmax, coord[0] + distmax,
6787 coord[1] + distmax, coord[2] + distmax, liste_facettes);
6788
6789 // pour chaque facette, calcule la distance entre la facette et coord, puis
6790 // prend le min:
6791 const int nliste = liste_facettes.size_array();
6792 int idx_facette = -1;
6793 for (int j = 0; j < nliste; j++)
6794 {
6795 const int num_facette = liste_facettes[j];
6796 const int compo = compo_connexe_facettes[num_facette];
6797 if (compo == compo_connexe_som)
6798 continue; // cette facette appartient a la meme compo connexe que le
6799 // sommet,
6800 // ne m'interesse pas
6801 const double d = calculer_carre_distance_sommet_facette(coord, mesh, num_facette);
6802 if (d < dmin)
6803 {
6804 dmin = d;
6805 idx_facette = num_facette; // On retient le numero de la facette
6806 }
6807 // dmin = std::min(d, dmin);
6808 }
6809 distance[i] = std::min(distance[i], sqrt(dmin));
6810 fill_relative_velocity(vinterp_tmp,vinterp_, facettes, idx_facette, i, vr_to_other);
6811
6812 }
6813}
6814
6815
6816// search for the center of mass of a neighbouring face among all cells at distance n from the current cell IJK (in a given direction)
6817static void check_neighbouring_layer_in_one_direction(int dir0, int dir1, int dir2, int n,
6818 const Int3& nb_elem_loc, const Int3& ijk,
6819 const std::map<std::array<int,3>, std::set<int>>& bary_ijk_loc, const DoubleTab& bary,
6820 const ArrOfInt& compo_connexe_facettes, const int compo_connexe_som,
6821 const double x, const double y, const double z,
6822 double& distance, int& id_facette )
6823{
6824
6825 for(int sens=0; sens<2; sens++)
6826 {
6827 int zero = 0;
6828 int a = sens == 0 ? std::max(ijk[dir0]-n,zero) : std::min(ijk[dir0]+n,nb_elem_loc[dir0]);
6829 for(int b=std::max(ijk[dir1]-n,zero); b<std::min(ijk[dir1]+n,nb_elem_loc[dir1]); b++)
6830 for(int c=std::max(ijk[dir2]-n,zero); c<std::min(ijk[dir2]+n,nb_elem_loc[dir2]); c++)
6831 {
6832 std::array<int,3> current_ijk;
6833 current_ijk[0] = a;
6834 current_ijk[1] = b;
6835 current_ijk[2] = c;
6836 if(bary_ijk_loc.find(current_ijk)!=bary_ijk_loc.end())
6837 {
6838 std::set<int> bary_in_current_ijk = bary_ijk_loc.at(current_ijk);
6839 for(const auto b_fa7: bary_in_current_ijk)
6840 {
6841 if(compo_connexe_facettes[b_fa7] != compo_connexe_som)
6842 {
6843 //computing distance between the center of mass of this face and the vertice I'm searching the closest neighbour of
6844 double dist = (bary(b_fa7,0)-x)*(bary(b_fa7,0)-x) + (bary(b_fa7,1)-y)*(bary(b_fa7,1)-y) + (bary(b_fa7,2)-z)*(bary(b_fa7,2)-z);
6845 distance = std::min(sqrt(dist),distance);
6846 id_facette = b_fa7;
6847 }
6848 }
6849 }
6850 }
6851 }
6852
6853}
6854
6855/* @brief For each vertex of the front mesh, compute the distance and the relative velocity to the nearest face belonging to another bubble based on the IJK discretization :
6856 * starting from the IJK-cell containing my vertex, we progressively search the neighbouring layers until we find the center of mass of a face of another bubble
6857 * (or we reach the border of the domain)
6858 * Exemple :
6859 * checking layer 1: checking layer 2: checking layer 3 (and we stop here, as we found the barycenter of a neighbouring face)
6860 * |x|x|x|x|x|x|x|
6861 * |x|x|x|x|x| |x|_|_|_|_|_|x|
6862 * |x|x|x| |x|_|_|_|x| |x|_|_|_|_|_|x|
6863 * |x|o|x| |x|_|o|_|x| |x|_|_|o|_|_|x|
6864 * |x|x|x| |x|_|_|_|x| |x|_|_|_|_|_|x|
6865 * |x|x|x|x|x| |x|x|x|x|x|x|b|
6866 *
6867 * WARNING: here, we compute the distance between a vertice and a face as the distance between the vertice and the center of mass of the face.
6868 * In the method calculer_distance_autres_compo_connexe_octree, the distance taken into account is the shortest distance between the vertex
6869 * and a set of points on the surface of the face. So the results of the two algorithms may differ
6870 * WARNING: this algorithm is not validated and is slower than calculer_distance_autres_compo_connexe_octree. To be used only if you encounter a memory problem with the other method
6871 */
6873 const ArrOfInt& compo_connexe_sommets,
6874 const DoubleTab& vinterp_tmp,
6875 const Maillage_FT_IJK& mesh,
6876 ArrOfDouble& distance,
6877 DoubleTab& vr_to_other,
6878 const double distmax)
6879{
6880 const IntTab& facettes = mesh.facettes();
6881 const ArrOfInt& compo_connexe_facettes = mesh.compo_connexe_facettes();
6882 const int nb_som = sommets_a_tester.dimension(0);
6883 const int nb_fa7 = facettes.dimension(0);
6884
6885 const Domaine_IJK& splitting = I_ft().get_domaine();
6886 Int3 ijk_glob, ijk_loc, useless;
6887 Int3 nb_elem_loc;
6888 for(int dir=0; dir<3; dir++)
6889 nb_elem_loc[dir] = splitting.get_nb_elem_local(dir);
6890
6891 distance.resize_array(nb_som, RESIZE_OPTIONS::NOCOPY_NOINIT);
6892 distance = distmax;
6893 vr_to_other.resize(nb_som, 3, RESIZE_OPTIONS::NOCOPY_NOINIT);
6894 vr_to_other = -1e5; // Invalid value
6895 assert(vinterp_tmp.dimension(0) == nb_som);
6896
6897 DoubleTab bary(nb_fa7,3);
6898 // for each i,j,k cell of my local domain, list of all the centers of mass that it contains
6899 std::map<std::array<int,3>, std::set<int>> bary_ijk_loc;
6900 for (int fa7=0; fa7<nb_fa7; fa7++)
6901 {
6902 // computing simple center of mass for each faces
6903 int s0 = facettes(fa7,0), s1 = facettes(fa7,1), s2 = facettes(fa7,2);
6904 for(int dir=0; dir<3; dir++)
6905 bary(fa7,dir) = (sommets_a_tester(s0,dir) + sommets_a_tester(s1,dir) + sommets_a_tester(s2,dir)) / 3.;
6906
6907 splitting.search_elem(bary(fa7,0), bary(fa7,1), bary(fa7,2), ijk_glob, ijk_loc, useless);
6908 std::array<int,3> ijk;
6909 for(int dir=0; dir<3; dir++) ijk[dir] = ijk_loc[dir];
6910 bary_ijk_loc[ijk].insert(fa7);
6911 }
6912
6913 for (int som=0; som<nb_som; som++)
6914 {
6915 double x=sommets_a_tester(som,0), y=sommets_a_tester(som,1), z=sommets_a_tester(som,2);
6916 splitting.search_elem(x, y, z, ijk_glob, ijk_loc, useless);
6917 const int compo_connexe_som = compo_connexe_sommets[som];
6918
6919 bool local_domain_checked = false;
6920 int n_layer = 0;
6921 int id_facette = -1; //id of the closest face found
6922 double& dist = distance[som];
6923
6924 // we stop searching for the closest neighbour if we found one, or if the entire local domain has been covered
6925 while(!local_domain_checked && id_facette==-1)
6926 {
6927 // checking left and right neighbourhood of my cell
6928 check_neighbouring_layer_in_one_direction(0 /*fixed dir*/, 1, 2, n_layer,
6929 nb_elem_loc, ijk_loc,
6930 bary_ijk_loc, bary,
6931 compo_connexe_facettes, compo_connexe_som,
6932 x, y, z,
6933 dist, id_facette );
6934
6935 // check for up and down neighbourhood
6936 check_neighbouring_layer_in_one_direction(1 /*fixed dir*/, 0, 2, n_layer,
6937 nb_elem_loc, ijk_loc,
6938 bary_ijk_loc, bary,
6939 compo_connexe_facettes, compo_connexe_som,
6940 x, y, z,
6941 dist, id_facette );
6942
6943
6944
6945 // check for front and back neighbourhood
6946 check_neighbouring_layer_in_one_direction(2 /*fixed dir*/, 0, 1, n_layer,
6947 nb_elem_loc, ijk_loc,
6948 bary_ijk_loc, bary,
6949 compo_connexe_facettes, compo_connexe_som,
6950 x, y, z,
6951 dist, id_facette );
6952
6953
6954 // have we checked the whole local domain yet ?
6955 int i=ijk_loc[0], j=ijk_loc[1], k=ijk_loc[2];
6956 local_domain_checked = i-n_layer <= 0 && i+n_layer>= nb_elem_loc[0]
6957 && j-n_layer <= 0 && j+n_layer>= nb_elem_loc[1]
6958 && k-n_layer <= 0 && k+n_layer>= nb_elem_loc[2];
6959
6960 // next layer
6961 n_layer++;
6962 }
6963
6964 // Once the closest neighbour is found, fill velocity
6965 fill_relative_velocity(vinterp_tmp,vinterp_, facettes, id_facette, som, vr_to_other);
6966
6967 }
6968}
6969
6970// Cette fonction cherche dans les coordonnees les sommets qui sont au bord du
6971// domaine dans les directions
6972// >= dir, les envoie aux voisins concernes et recupere la distance.
6973// Pour cela on
6974// cherche les sommets a envoyer aux voisins, qu'on envoir et qu'on ajoute a la
6975// liste coord_sommets appelle recursivement la fonction avec dir+1 recupere
6976// les resultats des sommets envoyes aux voisins, et remet coord_sommets dans
6977// son etat initial
6978// Si dir=3, on calcule la distance avec la liste de sommets coord_sommets, fin
6979// de la recursion Attention, recursion inhabituelle: la methode modifie le
6980// parametre passe par adresse et ajoute
6981// des sommets a chaque appel recursif. Elle les retire a nouveau avant de
6982// sortir.
6983// (on aurait pu passer un tableau "const" et le dupliquer pour avoir une copie
6984// de travail).
6985//
6986// Cette facon de faire permet de faire tous les echanges avec seulement 12
6987// messages echanges (6 a l'aller et 6 au retour). Si on veut envoyer
6988// directement tous les sommets a tous les processeurs, il y a 26 voisins
6989// (coins) donc 52 messages (aller et retour).
6991 const Maillage_FT_IJK& mesh, DoubleTab& coord_sommets,
6992 ArrOfInt& compo_sommet, ArrOfDouble& distance,
6993 DoubleTab& vr_to_other, double distmax)
6994{
6995 const Domaine_IJK& splitting = ref_domaine_.valeur();
6996 if (dir == 3)
6997 {
6999 calculer_distance_autres_compo_connexe_octree(coord_sommets, compo_sommet, vinterp_tmp, mesh, distance, vr_to_other, distmax);
7000 else
7001 calculer_distance_autres_compo_connexe_ijk(coord_sommets, compo_sommet, vinterp_tmp, mesh, distance, vr_to_other, distmax);
7002 }
7003 else
7004 {
7005 // schema pour envoyer recevoir des donnees de mes voisins gauche droite
7006 Schema_Comm schema;
7007 ArrOfInt pe_list;
7008 ArrOfInt flags(Process::nproc());
7009 flags = 0;
7010 double min_coord, max_coord;
7011 const int processor_at_left = splitting.get_neighbour_processor(0 /* previous */, dir);
7012 if (processor_at_left < 0)
7013 {
7014 min_coord = -1e10;
7015 }
7016 else
7017 {
7018 const ArrOfDouble& coord_nodes = splitting.get_node_coordinates(dir);
7019 const int offset = splitting.get_offset_local(dir);
7020 const double left_node = coord_nodes[offset];
7021 min_coord = left_node + distmax;
7022 if(!flags[processor_at_left])
7023 {
7024 flags[processor_at_left] = 1;
7025 pe_list.append_array(processor_at_left);
7026 }
7027 }
7028 const int processor_at_right = splitting.get_neighbour_processor(1 /* next */, dir);
7029 if (processor_at_right < 0)
7030 {
7031 max_coord = 1e10;
7032 }
7033 else
7034 {
7035 const ArrOfDouble& coord_nodes = splitting.get_node_coordinates(dir);
7036 const int offset = splitting.get_offset_local(dir);
7037 const int i_last_node = offset + splitting.get_nb_elem_local(dir);
7038 const double right_node = coord_nodes[i_last_node];
7039 max_coord = right_node - distmax;
7040 if(!flags[processor_at_right])
7041 {
7042 flags[processor_at_right] = 1;
7043 pe_list.append_array(processor_at_right);
7044 }
7045 }
7046 schema.set_send_recv_pe_list(pe_list, pe_list);
7047
7048 schema.begin_comm();
7049 ArrOfInt index_sent_to_left;
7050 ArrOfInt index_sent_to_right;
7051 if (processor_at_left >= 0 || processor_at_right >= 0)
7052 {
7053 // Bypass in sequential or if no splitting in this direction
7054 const int nb_som = coord_sommets.dimension(0);
7055 for (int i_som = 0; i_som < nb_som; i_som++)
7056 {
7057 Vecteur3 coord(coord_sommets, i_som);
7058 if (coord[dir] < min_coord)
7059 {
7060 // envoyer ce sommet au voisin de gauche
7061 // je stocke en meme temps l'indice i_som de ce sommet dans le tableau d'origine
7062 // (pour mettre a jour la distance avec ce que m'aura envoye le processeur voisin)
7063 index_sent_to_left.append_array(i_som);
7064 schema.send_buffer(processor_at_left) << compo_sommet[i_som]
7065 << coord_sommets(i_som, 0)
7066 << coord_sommets(i_som, 1)
7067 << coord_sommets(i_som, 2)
7068 << vinterp_tmp(i_som, 0)
7069 << vinterp_tmp(i_som, 1)
7070 << vinterp_tmp(i_som, 2);
7071 }
7072 if (coord[dir] > max_coord)
7073 {
7074 // envoyer ce sommet au voisin de droite
7075 index_sent_to_right.append_array(i_som);
7076 schema.send_buffer(processor_at_right) << compo_sommet[i_som]
7077 << coord_sommets(i_som, 0)
7078 << coord_sommets(i_som, 1)
7079 << coord_sommets(i_som, 2)
7080 << vinterp_tmp(i_som, 0)
7081 << vinterp_tmp(i_som, 1)
7082 << vinterp_tmp(i_som, 2);
7083 }
7084 }
7085 }
7086
7088
7089 const int init_count = coord_sommets.dimension(0); // Nombre de sommets initialement recus par la fonction
7090 int count_left = 0; // nb sommets recus de gauche et de droite
7091 int count_right = 0;
7092 for (int left_right = 0; left_right < 2; left_right++)
7093 {
7094 const int pe_voisin = (left_right==0) ? processor_at_left : processor_at_right;
7095 int& count = (left_right==0) ? count_left : count_right; // attention, c'est une reference, on va modifier la var.
7096 if (pe_voisin >= 0)
7097 {
7098 Entree& buf = schema.recv_buffer(pe_voisin);
7099 while(1)
7100 {
7101 int num_compo;
7102 buf >> num_compo;
7103 if (buf.eof())
7104 break;
7105 double x, y, z, vx, vy, vz;
7106 buf >> x >> y >> z >> vx >> vy >> vz;
7107 coord_sommets.append_line(x, y, z);
7108 vinterp_tmp.append_line(vx, vy, vz);
7109 compo_sommet.append_array(num_compo);
7110 count++;
7111 }
7112 }
7113 }
7114 // dans les tableaux on a maintenant init_count sommets venant de la fonction qui m'a appelee,
7115 // plus count_left sommets qui viennent de ma gauche, plus count_right sommets qui viennent de ma droite
7116 schema.end_comm();
7117
7118 // appel recursif avec la direction suivante
7119 recursive_calcul_distance_chez_voisin(vinterp_tmp, dir + 1, mesh, coord_sommets, compo_sommet, distance, vr_to_other, distmax);
7120
7121 // on recupere la distance pour tous les sommets du tableau,
7122 // il faut envoyer la distance aux voisins pour les sommets apres init_count:
7123
7124 int index = init_count; // indice du premier sommet qui a ete recu d'un voisin
7125 schema.begin_comm();
7126 for (int left_right = 0; left_right < 2; left_right++)
7127 {
7128 const int pe_voisin = (left_right==0) ? processor_at_left : processor_at_right;
7129 const int count = (left_right==0) ? count_left : count_right;
7130 if (pe_voisin >= 0)
7131 {
7132 Sortie& buf = schema.send_buffer(pe_voisin);
7133 for (int i = 0; i < count; i++)
7134 buf << distance[index+i]
7135 << vr_to_other(index+i,0)
7136 << vr_to_other(index+i,1)
7137 << vr_to_other(index+i,2);
7138 index += count;
7139 }
7140 }
7142 for (int left_right = 0; left_right < 2; left_right++)
7143 {
7144 int pe_voisin = (left_right==0) ? processor_at_left : processor_at_right;
7145 const ArrOfInt indices_sommets = (left_right==0) ? index_sent_to_left : index_sent_to_right;
7146 if (pe_voisin >= 0)
7147 {
7148 Entree& buf = schema.recv_buffer(pe_voisin);
7149 const int count = indices_sommets.size_array();
7150 for (int i = 0; i < count; i++)
7151 {
7152 double d;
7153 buf >> d;
7154 double vx, vy, vz;
7155 buf >> vx >> vy >> vz;
7156 int idx = indices_sommets[i];
7157 distance[idx] = std::min(distance[idx], d);
7158 vr_to_other(idx,0) = vx;
7159 vr_to_other(idx,1) = vy;
7160 vr_to_other(idx,2) = vz;
7161 }
7162 }
7163 }
7164 schema.end_comm();
7165
7166 // Remet les tableaux dans leur etat d'origine
7167 coord_sommets.resize(init_count, 3);
7168 vinterp_tmp.resize(init_count, 3); // GB. Heu.. je ne comprends pas l'utilite avec ma comprehension limitee de l'octree, mais bon.
7169 compo_sommet.resize_array(init_count);
7170 // On pourrait verifier avec un assert que coord_sommets est identique a la valeur qu'il avait a l'entree.
7171 distance.resize_array(init_count);
7172 vr_to_other.resize(init_count, 3); // GB. Heu..
7173 }
7174}
7175
7176// Remplit le tableau distance qui, pour chaque sommet du maillage mesh,
7177// donne la distance entre le point et la composante connexe differente la plus proche
7178// Si cette distance est superieure a distmax, on ne cherche pas, on prend distmax.
7179
7181 DoubleTab& v_closer)
7182{
7183 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
7184 const double distmax= portee_force_repulsion_;
7185 ArrOfIntFT compo_connexe_sommets;
7186 mesh.calculer_compo_connexe_sommets(compo_connexe_sommets);
7187 DoubleTab tmp_sommets = mesh.sommets();
7188 compute_vinterp(); // To be sure the velocity of markers is up-to-date
7189
7190 // vinterp_tmp is a resizable list that will be as tmp_sommets, but containing velocities.
7191 DoubleTab vinterp_tmp(vinterp_);
7192 // Calcul de la distance avec les interfaces locales et autres processeurs
7194 0, /* direction I, premiere etape de la recursion */
7195 mesh,
7196 tmp_sommets,
7197 compo_connexe_sommets,
7198 distance,
7199 v_closer,
7200 distmax);
7201}
7202
7203// Methodes outils permettant depuis GDB d'ecrire des fichiers tracables dans gnuplot
7204// Le nom du fichier de sortie est mis en dur dans le code:
7205void dump_facette(const Maillage_FT_Disc& mesh, int fa7, int append = 0)
7206{
7207 SFichier f;
7208 if (append)
7209 {
7210 f.ouvrir("dump_facette.txt", ios::app);
7211 f << finl << finl;
7212 }
7213 else
7214 {
7215 f.ouvrir("dump_facette.txt");
7216 }
7217 for (int i = 0; i < 4; i++)
7218 {
7219 int som = mesh.facettes()(fa7, i%3);
7220 f << mesh.sommets()(som, 0) << " " << mesh.sommets()(som, 1) << " " << mesh.sommets()(som, 2) << finl;
7221 }
7222}
7223
7224void dump_elem(const Domaine_IJK& split, int ii, int jj, int kk, int append = 0)
7225{
7226 SFichier f;
7227 if (append)
7228 {
7229 f.ouvrir("dump_elem.txt", ios::app);
7230 f << finl << finl;
7231 }
7232 else
7233 {
7234 f.ouvrir("dump_elem.txt");
7235 }
7236 Vecteur3 p[2];
7237 Int3 ijk;
7238 ijk[0] = ii;
7239 ijk[1] = jj;
7240 ijk[2] = kk;
7241 for (int i = 0; i < 3; i++)
7242 {
7243 int j = split.get_offset_local(i) + ijk[i];
7244 p[0][i] = split.get_node_coordinates(i)[j];
7245 p[1][i] = split.get_node_coordinates(i)[j+1];
7246 }
7247 for (int dir = 0; dir < 3; dir++)
7248 {
7249 for (int seg = 0; seg < 8; seg++)
7250 {
7251 int pstart = seg;
7252 int pend = seg + (1 << dir);
7253 if (pend < 8)
7254 {
7255 f << p[pstart & 1][0] << " " << p[(pstart >> 1) & 1][1] << " " << p[(pstart >> 2) & 1][2] << finl;
7256 f << p[pend & 1][0] << " " << p[(pend >> 1) & 1][1] << " " << p[(pend >> 2) & 1][2] << finl;
7257 f << finl << finl;
7258 }
7259 }
7260 }
7261}
7262
7263void dump_elem(const Domaine_VF& domaine, int elem, int append = 0)
7264{
7265 SFichier f;
7266 if (append)
7267 {
7268 f.ouvrir("dump_elem.txt", ios::app);
7269 f << finl << finl;
7270 }
7271 else
7272 {
7273 f.ouvrir("dump_elem.txt");
7274 }
7275 Vecteur3 p[2];
7276 for (int i = 0; i < 3; i++)
7277 {
7278 p[0][i] = domaine.xv(domaine.elem_faces(elem, i), i);
7279 p[1][i] = domaine.xv(domaine.elem_faces(elem, i+3), i);
7280 }
7281 for (int dir = 0; dir < 3; dir++)
7282 {
7283 for (int seg = 0; seg < 8; seg++)
7284 {
7285 int pstart = seg;
7286 int pend = seg + (1 << dir);
7287 if (pend < 8)
7288 {
7289 f << p[pstart & 1][0] << " " << p[(pstart >> 1) & 1][1] << " " << p[(pstart >> 2) & 1][2] << finl;
7290 f << p[pend & 1][0] << " " << p[(pend >> 1) & 1][1] << " " << p[(pend >> 2) & 1][2] << finl;
7291 f << finl << finl;
7292 }
7293 }
7294 }
7295}
7296
7297
7298//Renvoie 1 si l option GRAVITE_RHO_G est activee 0 sinon
7300{
7302 return 1;
7303 else
7304 return 0;
7305}
7306
7307void IJK_Interfaces::detecter_et_supprimer_rejeton(bool duplicatas_etaient_presents)
7308{
7309 // Selon ou cette methode est appelee, il faut qu'elle recree les duplicatas.
7310
7311 if (duplicatas_etaient_presents)
7312 {
7314 maillage_ft_ijk_.parcourir_maillage();
7315 }
7317 const ArrOfInt& compo_std = maillage.compo_connexe_facettes();
7318 const ArrOfDouble& surface_facettes = maillage.get_update_surface_facettes();
7319 const int nb_facettes=maillage.nb_facettes();
7320 //dumplata_newtime("DNS2.lata",0.);
7321 //dumplata_ft_mesh("DNS2.lata", "INTERFACES", maillage_ft_ijk_, 0);
7322 //dumplata_ft_field("DNS2.lata", "INTERFACES", "COMPO_CONNEXE_AVT", "ELEM", maillage_ft_ijk_.compo_connexe_facettes(), 0);
7323 ArrOfInt compo_new(nb_facettes); // Init a zero
7324 int n = search_connex_components_local_FT(maillage, compo_new);
7325 //dumplata_ft_field("DNS2.lata", "INTERFACES", "COMPO_CONNEXE_MLX", "ELEM", compo_new, 0);
7326 int nb_compo_tot=compute_global_connex_components_FT(maillage, compo_new, n);
7327 //dumplata_ft_field("DNS2.lata", "INTERFACES", "COMPO_CONNEXE_FIN", "ELEM", compo_new, 0);
7328 if (nb_compo_tot>nb_bulles_reelles_)
7329 {
7330 int nb_rejeton = nb_compo_tot-nb_bulles_reelles_;
7331 ArrOfInt rejeton(nb_rejeton);
7332 DoubleTab rejetonArea(nb_bulles_reelles_, nb_compo_tot);
7333 // initialisation
7334 rejetonArea=0.0;
7335 rejeton=-1 ;
7336
7337 // remplissage de la matrice
7338 for (int fa7 = 0; fa7 < nb_facettes; fa7++)
7339 rejetonArea(compo_std[fa7], compo_new[fa7])+=surface_facettes[fa7];
7340
7341 // On somme les contributions de chaque processeur
7342 mp_sum_for_each_item(rejetonArea);
7343
7344 // On parcoure la matrice pour connaitre les compo_new a supprimer
7345 for (int ibul = 0 ; ibul<nb_bulles_reelles_ ; ibul++)
7346 {
7347 // pour chaque compo on repere celle qui va rester
7348 int ibul_stay = 0 ;
7349 for (int ibul_new = 0 ; ibul_new<nb_compo_tot ; ibul_new++)
7350 if (rejetonArea(ibul, ibul_new)!=0.0 && rejetonArea(ibul, ibul_stay)<rejetonArea(ibul, ibul_new))
7351 {
7352 ibul_stay=ibul_new ;
7353 break;
7354 }
7355
7356 // On envoie les autres dans rejetons a supprimer
7357 for (int ibul_new = 0 ; ibul_new<nb_compo_tot ; ibul_new++)
7358 if (rejetonArea(ibul, ibul_new)!=0.0 && ibul_new!=ibul_stay)
7359 for (int ii = 0; ii<nb_rejeton ; ii++)
7360 if (rejeton[ii]==-1)
7361 {
7362 rejeton[ii]=ibul_new;
7363 break;
7364 }
7365 }
7366 Cerr << "matrice de surface des compo" << finl;
7367 Cerr << rejetonArea << finl;
7368 Cerr << "Les rejetons a supprimer sont" << finl;
7369 Cerr << rejeton << finl;
7370
7371 // on remplace les compo a supprimer par -1
7372 for (int fa7 = 0; fa7 < nb_facettes; fa7++)
7373 for (int ii = 0; ii<nb_rejeton ; ii++)
7374 if (compo_new[fa7] == rejeton[ii])
7375 maillage.set_composante_connexe(fa7, -1);
7376
7377 // On supprime la bulle que l'on vient de renumeroter -1:
7379 }
7380
7381 //Selon ou cette methode est appelee, il faut qu'elle recree les duplicatas.
7382 if (duplicatas_etaient_presents)
7383 {
7385 maillage_ft_ijk_.parcourir_maillage();
7386 }
7387
7388//dumplata_newtime("DNS3.lata",0.);
7389//dumplata_ft_mesh("DNS3.lata", "INTERFACES", maillage_ft_ijk_, 0);
7390//dumplata_ft_field("DNS3.lata", "INTERFACES", "COMPO_CONNEXE_AVT", "ELEM", maillage_ft_ijk_.compo_connexe_facettes(), 0);
7391}
7392
7393// Rempli le champ de force de rappel pour les bulles fixes.
7394// coef_rayon_force_rappel : coef de taille du domaine de rappel const (attention aux superposition de bulles)
7395void IJK_Interfaces::compute_external_forces_(IJK_Field_vector3_double& rappel_ft,
7396 IJK_Field_vector3_double& rappel,
7397 const IJK_Field_vector3_double& vitesse,
7398 const IJK_Field_double& indic/*_ns*/,
7399 const IJK_Field_double& indic_ft,
7400 const double coef_immo,
7401 const int tstep,
7402 const double current_time,
7403 const double coef_ammortissement,
7404 const double coef_rayon_force_rappel,
7405 const double integration_time,
7406 const double coef_mean_force,
7407 const double coef_force_time_n)
7408{
7409 //////////////////////////////////// CALCUL DES VITESSE MOYENNE PAR BULLES ///////////////////////////////////////
7410 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
7411 //const DoubleTab& sommets = mesh.sommets() ; // Tableau des coordonnees des marqueurs.
7412 //int nbsom = sommets.dimension(0);
7413 //DoubleTab deplacement(nbsom,3);
7414
7415 compute_vinterp(); // to resize and fill vinterp_
7416
7417 // Les sommets virtuels sont peut-etre trop loin pour pouvoir interpoler leur vitesse,
7418 // il faut faire un echange espace virtuel pour avoir leur vitesse.
7420
7421 // Calcul d'un deplacement preservant la distribution des noeuds sur les bulles:
7422 // Inspiree de : Transport_Interfaces_FT_Disc::calculer_vitesse_repere_local
7423
7424 const int nbulles_reelles = get_nb_bulles_reelles();
7425 const int nbulles_ghost = get_nb_bulles_ghost();
7426 const int nbulles_tot = nbulles_reelles + nbulles_ghost;
7427 const ArrOfInt& compo_connex = mesh.compo_connexe_facettes();
7428 // assert(compo_connex.size_array() == 0 || min_array(compo_connex) >=0); // Les duplicatas ne sont pas presents pendant le transport.
7429 // Nouveau depuis le 13/03/2014 : Les bulles ghost sont autorisees lors du transport...
7430 ArrOfDouble surface_par_bulle;
7431 calculer_surface_bulles(surface_par_bulle);
7432 const ArrOfDouble& surface_facette = mesh.get_update_surface_facettes();
7433 ArrOfIntFT compo_connex_som;
7434 mesh.calculer_compo_connexe_sommets(compo_connex_som);
7435
7436 DoubleTab vitesses_translation_bulles(nbulles_tot,3);
7438 surface_facette,
7439 surface_par_bulle,
7440 compo_connex,
7441 nbulles_reelles,
7442 nbulles_ghost,
7443 vinterp_,
7444 vitesses_translation_bulles);
7445
7446 //////////////////////////////////// FIN CALCUL DES VITESSE MOYENNE PAR BULLES ///////////////////////////////////////
7447
7448 //////////////////////////////// CALCUL DES FORCES (algo inspired by Thomas & Bolotnov) ///////////////////////////////////
7449 ArrOfDouble volume_reel;
7450 DoubleTab position;
7451 calculer_volume_bulles(volume_reel, position);
7452
7453 const double deltat = 1.; // Dirty code... but it's actually a time integral...
7454 DoubleTab individual_forces(nb_bulles_reelles_,3);
7455 for (int idir=0; idir < 3; idir++)
7456 {
7457 const double ldom = rappel.get_domaine().get_domain_length(idir);
7458 for (int ib=0; ib < nb_bulles_reelles_; ib++)
7459 {
7461 {
7462 double dx = positions_reference_(ib,idir)-position(ib,idir);
7463 // sort of modulo of domain length:
7464 while (dx> 0.8*ldom)
7465 dx -=ldom;
7466
7467 while (dx< -0.8*ldom)
7468 dx +=ldom;
7469
7470 individual_forces(ib,idir) = coef_mean_force*mean_force_(ib,idir);
7471 individual_forces(ib,idir) += (1.-coef_mean_force)*coef_immo*(dx);
7472 individual_forces(ib,idir) += (1.-coef_mean_force)*coef_ammortissement*vitesses_translation_bulles(ib,idir);
7473 individual_forces(ib,idir) += (1.-coef_mean_force)*coef_force_time_n*force_time_n_(ib,idir);
7474 /*
7475 mean_force_(ib,idir)*=integration_time;
7476 mean_force_(ib,idir)+=individual_forces(ib,idir)*deltat;
7477 mean_force_(ib,idir)/=(integration_time+deltat);
7478 force_time_n_(ib,idir)=individual_forces(ib,idir);
7479 */
7480 }
7481 }
7482 }
7484 {
7485 for (int idir=0; idir < 3; idir++)
7486 for (int ib = 0; ib < nb_bulles_reelles_; ib++)
7487 {
7488 mean_force_(ib,idir)*=integration_time;
7489 mean_force_(ib,idir)+=individual_forces(ib,idir)*deltat;
7490 mean_force_(ib,idir)/=(integration_time+deltat);
7491 force_time_n_(ib,idir)=individual_forces(ib,idir);
7492 }
7493 }
7494 envoyer_broadcast(individual_forces, 0);
7495 // envoyer_broadcast(mean_force_, 0); Normally, only proc 0 needs the mean_force_
7496
7497 ////////////////////////////// FIN CALCUL DES FORCES (algo inspired by Thomas & Bolotnov) ////////////////////////////////
7498
7499 // Choix de la methode implementee :
7500 const int parser = parser_;
7501 if (parser)
7502 {
7503 compute_external_forces_parser(rappel, indic, individual_forces, volume_reel, position, coef_rayon_force_rappel);
7504 }
7505 else
7506 {
7507 // The table "individual_forces" enters with the value for each force and is modified to contain
7508 // the integral of F over the volume where the bubble force is applied. And is finally divided by that volume.
7509 // Then, the value (that would be applied over the whole volume) is in the table
7510 compute_external_forces_color_function(rappel_ft,indic/*_ns*/, indic_ft,individual_forces, volume_reel, position);
7511 //Cerr << "t= "<< current_time << " Max-abs(individual_forces)= "<< max_abs_array(individual_forces) << finl;
7512 }
7513
7514 // In the current state, every time-step is post-processed.
7516 {
7517 char s[1000];
7518 const char *nomcas = nom_du_cas();
7519 SFichier fic;
7520 int reset = (!reprise_) && (tstep==0);
7521 IOS_OPEN_MODE mode = (reset) ? ios::out : ios::app;
7522 for (int idir=0; idir < 3; idir++)
7523 {
7524 snprintf(s, 1000, "%s_bulles_external_force_every_%d.out", nomcas, idir);
7525 // Cerr << "Ecriture des donnees par bulles: fichier " << s << finl;
7526 fic.ouvrir(s, mode);
7527 if (reset)
7528 {
7529 // Header in the file:
7530 snprintf(s, 1000, "# Individual forces applied inside chiv[bubble_i]=1.\n# value=1./Vol_bubble \\int F_j(bubble_i) dv");
7531 fic << s;
7532 fic << finl;
7533 }
7534 snprintf(s, 1000, "%.16e ", current_time);
7535 fic << s;
7536 for (int ib = 0; ib < nb_bulles_reelles_; ib++)
7537 {
7538 snprintf(s, 1000, "%.16e ", individual_forces(ib,idir));
7539 fic << s;
7540 }
7541 fic << finl;
7542 fic.close();
7543 }
7544 }
7545}
7546
7547// The method is based on an eulerian color function refering to each bubble
7548// BEWARE : individual_forces should contain the value of each force in inlet and
7549// modify it to return the integrated value (homogeneous to "F*vol") at the end of the function
7550void IJK_Interfaces::compute_external_forces_color_function(IJK_Field_vector3_double& rappel_ft,
7551 const IJK_Field_double& indic_ns,
7552 const IJK_Field_double& indic_ft,
7553 DoubleTab& individual_forces,
7554 const ArrOfDouble& volume_reel,
7555 const DoubleTab& position)
7556{
7557 assert(ghost_compo_converter_.size_array() == nb_bulles_ghost_);
7558 // Step 1. Conversion table.
7559 ArrOfInt decodeur_num_compo(nb_compo_in_num_compo_);
7560 decodeur_num_compo=NUM_COMPO_INVALID; // invalid value is large and negative.
7561 // The values in num_compo are not related to the compo numbers of the bubbles.
7562 // Some reordering is required.
7563
7564 // Carefull : domaine_vdf is built on splitting_ft_, so num_compo_ refers to these numbers
7565 const Domaine_IJK& s_ft =indic_ft.get_domaine();
7566 Int3 ijk_global, ijk_local, ijk_processeur;
7567 for (int ib=0; ib < nb_bulles_reelles_+nb_bulles_ghost_; ib++)
7568 {
7569 //int num_proc = -1; // invalid initialization.
7570 double x = position(ib,0);
7571 double y = position(ib,1);
7572 double z = position(ib,2);
7573 ijk_processeur[0]=0;
7574 ijk_processeur[1]=0;
7575 ijk_processeur[2]=0;
7576 // Le centre des bulles est forcement dans le domaine ft (etendu) sur lequel est construit num_compo_
7577 // Donc les indices retournes doivent etre dans les bornes.
7578 s_ft.search_elem(x,y,z, ijk_global, ijk_local, ijk_processeur);
7579
7580 if (ijk_processeur[0] * ijk_processeur[1] * ijk_processeur[2] == 1)
7581 {
7582 // num_elem_zvdf contient le numero de l'elem dans sa Domaine_VF sur le proc num_proc.
7583 // Normalement, c'est cette cellule qui est au centre de la bulle ib.
7584 const int num_elem_zvdf = s_ft.convert_ijk_cell_to_packed(ijk_local);
7585 const int icompo = num_compo_[num_elem_zvdf]; // la valeur dans le tableau eulerien (Domaine i,j,k ecrit en non structure VDF)
7586 assert(icompo>=0);
7587 decodeur_num_compo[icompo] = ib; // On remplit le decodeur avec le numero de la bulle.
7588 //Cerr << "Decodeur : ib=" << ib << " in icompo= " << icompo << " on proc: " << Process::me() << finl;
7589 //Journal() << "Decodeur : ib=" << ib << " in icompo= " << icompo << " on proc: " << Process::me() << finl;
7590 }
7591 }
7592 // To put every process with the correct information for de-cryption
7593 mp_max_for_each_item(decodeur_num_compo);
7594
7595 ArrOfInt list_continuous_phase;
7596 list_continuous_phase.resize_array(0);
7597 int phase_continue1=-1000;
7598 int phase_continue2=-1000;
7599 int phase_continue3=-1000;
7600 int phase_continue4=-1000;
7601 int phase_continue5=-1000;
7602 int phase_continue6=-1000;
7603 {
7604 for (int i=0; i<nb_compo_in_num_compo_; i++)
7605 {
7606 if (decodeur_num_compo[i] == NUM_COMPO_INVALID)
7607 {
7608 list_continuous_phase.append_array(i);
7609 if (phase_continue1<0)
7610 {
7611 phase_continue1 = i;
7612 }
7613 else if (phase_continue2<0)
7614 {
7615 phase_continue2 = i;
7616 }
7617 else if (phase_continue3<0)
7618 {
7619 phase_continue3 = i;
7620 }
7621 else if (phase_continue4<0)
7622 {
7623 phase_continue4 = i;
7624 }
7625 else if (phase_continue5<0)
7626 {
7627 phase_continue5 = i;
7628 }
7629 else if (phase_continue6<0)
7630 {
7631 phase_continue6 = i;
7632 }
7633 }
7634 }
7635 }
7636 const int nb_parts_continuous = list_continuous_phase.size_array();
7637 Cerr << "nb parts continuous phase : " << list_continuous_phase.size_array()
7638 << " continuous phases are : " << phase_continue1 << " " << phase_continue2 << " "
7639 << phase_continue3 << " " << phase_continue4 << " " << phase_continue5 << " " << phase_continue6 << finl;
7640 Cerr << "GB-check nb_compo - nb_continuous phase - nb_bulles_tot = "
7641 << nb_compo_in_num_compo_<< " - " << nb_parts_continuous << " - " << nb_bulles_reelles_+nb_bulles_ghost_
7642 << " = " << nb_compo_in_num_compo_ - (nb_parts_continuous +nb_bulles_reelles_+nb_bulles_ghost_)<< finl;
7643 assert(nb_compo_in_num_compo_ - (nb_parts_continuous +nb_bulles_reelles_+nb_bulles_ghost_)==0);
7644
7645 if (nb_parts_continuous == 0)
7646 {
7647 Cerr << "No continuous phase found. " << finl;
7648 Process::exit();
7649 }
7650 // Step 2. On all processors.
7651 // Par pure commodite, on travaille sur les champs aux elements num_compo_ et indic pour decider si
7652 // si on applique la force de rappel sur la face (i,j,k) "de gauche". C'est donc legerement biaise.
7653 // Mais on n'a pas besoin d'une immense rigueur non-plus... donc on s'en accomode.
7654 //
7655 // Cette partie doit etre faite sur le domaine FT pour pouvoir interroger num_compo_[num_elem_zvdf]
7656 // qui doit etre construit sur le FT!
7657
7658 DoubleTab integrated_forces(nb_bulles_reelles_/* For real bubbles only*/, 3/*dims*/);
7659 const double vol = s_ft.get_constant_delta(0)
7660 * s_ft.get_constant_delta(1)
7661 * s_ft.get_constant_delta(2);
7662 IntTab integration_cells_per_bubble(nb_bulles_reelles_/* For real bubbles only*/, 3/*dims because can be different due to MAC scheme */);
7663 integration_cells_per_bubble=0;
7664 integrated_forces =0.;
7665 for (int idir=0; idir < 3; idir++)
7666 {
7667 const int nx = rappel_ft[idir].ni();
7668 const int ny = rappel_ft[idir].nj();
7669 int nzdeb = 0;
7670 int nz = rappel_ft[idir].nk();
7671 if ((!s_ft.get_periodic_flag(DIRECTION_K)) &&
7672 (idir==DIRECTION_K))
7673 {
7674 force_zero_on_walls(rappel_ft[DIRECTION_K]);
7675 const int kmin = s_ft.get_offset_local(DIRECTION_K);
7676 const int nktot = s_ft.get_nb_items_global(Domaine_IJK::FACES_K, DIRECTION_K);
7677 if (kmin + nz == nktot)
7678 {
7679 // On the "last" proc (in dir==2), there is a last layer of faces in this direction. We cannot do convert_ijk_cell_to_packed
7680 // for them, so we should skip them (and set them to 0.
7681 nz-=1;
7682 }
7683
7684 if (kmin == 0)
7685 {
7686 // On the "first" (in dir==2), we should skip the wall to the left...
7687 nzdeb = 1;
7688 }
7689 }
7690 for (int k=nzdeb; k < nz; k++)
7691 for (int j=0; j< ny; j++)
7692 for (int i=0; i < nx; i++)
7693 {
7694 // Probleme : s_ft est etendu, il faut fonc etre sur rappel_ft pour les indices (i,j,k).
7695 const int num_elem_zvdf = s_ft.convert_ijk_cell_to_packed(i,j,k);
7696 const int icompo = num_compo_[num_elem_zvdf]; // Ce ne sont pas les numeros qu'a le FT sur lui.
7697 bool continuous = false;
7698 for (int c=0; c<nb_parts_continuous; c++)
7699 {
7700 if (icompo == list_continuous_phase[c])
7701 {
7702 continuous = true;
7703 break;
7704 }
7705 }
7706 if ((icompo==-1) || (continuous) )
7707 {
7708 rappel_ft[idir](i,j,k) = 0.; // pas de force dans la phase continue, ni dans les mailles interfaciales.
7709 }
7710 else
7711 {
7712 int id_bulle = decodeur_num_compo[icompo]; // On relit le numero de la bulle grace au decodeur.
7713 // Si on obtient une bulle ghost, on cherche l'indice reel correspondant
7714 // afin de trouver la valeur de la force que l'on doit y imposer
7715 if (id_bulle>=nb_bulles_reelles_)
7716 {
7717 // Dealing with a ghost bubble:
7718 const int ighost = ghost_compo_converter(id_bulle-nb_bulles_reelles_);
7719 const int ibulle_reelle = decoder_numero_bulle(-ighost);
7720 //Cerr <<"id_bulle vs ibulle_reelle : " << id_bulle << " " <<ibulle_reelle << finl;
7721 //Cerr << "decodeur_num_compo : " << decodeur_num_compo << finl;
7722 id_bulle = ibulle_reelle;
7723 }
7724 else
7725 {
7726 // There should not be negative indices here.
7727 assert(id_bulle>=0);
7728 // For real bubbles, we compute the integral over the extended domain:
7729 const double f = individual_forces(id_bulle,idir);
7730 integrated_forces(id_bulle,idir) += vol*f;
7731 integration_cells_per_bubble(id_bulle,idir) +=1;
7732 }
7733 // We have taken necessary precautions for id_bulle to be the index of the real bubble:
7734 assert((id_bulle<nb_bulles_reelles_) &&(id_bulle>=0));
7735
7736 // For all bubbles (real or ghost), we apply the force to their volume
7737 // (it will truely be effective in NS only, were velocity is really solved!)
7738 const double f = individual_forces(id_bulle,idir);
7739 rappel_ft[idir](i,j,k) = f;
7740 }
7741 }
7742 }
7743 mp_sum_for_each_item(integrated_forces);
7744 mp_sum_for_each_item(integration_cells_per_bubble);
7745
7746 for (int idir=0; idir < 3; idir++)
7747 for (int ib = 0; ib < nb_bulles_reelles_; ib++)
7748 {
7749 // individual_forces(ib, idir) = integrated_forces(ib, idir) / volume_reel(ib); // WRONG : the force is not applied to the rigorous bubble volume..
7750 individual_forces(ib, idir) = integrated_forces(ib, idir) / (vol*integration_cells_per_bubble(ib,idir));
7751 }
7752}
7753
7754// individual_forces : The instantaneous value of the force for each bubble.
7755// force_time_n_ : The same, but stored in the class for later use (only on master process).
7756// mean_force_ : Time average of the force for each bubble (only on master process).
7757void IJK_Interfaces::compute_external_forces_parser(IJK_Field_vector3_double& rappel,
7758 const IJK_Field_double& indic, // ns
7759 const DoubleTab& individual_forces,
7760 const ArrOfDouble& volume_reel,
7761 const DoubleTab& position,
7762 const double coef_rayon_force_rappel)
7763{
7764 Noms noms_forces; // on attend trois expressions
7765 noms_forces.dimensionner_force(3);
7766 for (int idir=0; idir < 3; idir++)
7767 {
7768 noms_forces[idir] = "";
7769 for (int ib=0; ib < nb_bulles_reelles_; ib++)
7770 {
7771 double xir = position(ib,0);
7772 double yir = position(ib,1);
7773 double zir = position(ib,2);
7774 double r2 = coef_rayon_force_rappel*coef_rayon_force_rappel*pow((volume_reel[ib]*3)/(4.*M_PI), 2./3.);
7775 noms_forces[idir] += "+((";
7776 noms_forces[idir] += Nom("(X-(")+Nom(xir, "%g")+Nom("))*(X-(")+Nom(xir, "%g")+Nom("))");
7777 noms_forces[idir] += Nom("+(Y-(")+Nom(yir, "%g")+Nom("))*(Y-(")+Nom(yir, "%g")+Nom("))");
7778 noms_forces[idir] += Nom("+(Z-(")+Nom(zir, "%g")+Nom("))*(Z-(")+Nom(zir, "%g")+Nom("))");
7779 noms_forces[idir] += Nom("-")+Nom(r2, "%g");
7780 // 1-ff is the code name for chi_v in our case :
7781 // on veut > 0.9999 pour ne pas changer la gravite dans les mailles ou il y a une interface, ce qui rend la methode instable
7782 // d'apres Thomas & Bolotnov.
7783 noms_forces[idir] += ")_LT_0.)*(1.-ff)*((1.-ff)_GT_0.000001)*(" ;
7784 noms_forces[idir] += Nom(individual_forces(ib,idir), "%g");
7785 noms_forces[idir] += ")" ;
7786 }
7787 }
7788
7789 for (int idir=0; idir < 3; idir++)
7790 {
7791 // Pour les bulles ghosts
7792 //Cerr << "Ghost_compo_converter : " << ghost_compo_converter_ << finl;
7793 assert(ghost_compo_converter_.size_array() == nb_bulles_ghost_);
7794 for (int ibg=0; ibg < nb_bulles_ghost_; ibg++)
7795 {
7796 const int ighost = ghost_compo_converter(ibg);
7797 const int ibulle_reelle = decoder_numero_bulle(-ighost);
7798
7799 double xir = position(nb_bulles_reelles_+ibg,0);
7800 double yir = position(nb_bulles_reelles_+ibg,1);
7801 double zir = position(nb_bulles_reelles_+ibg,2);
7802 double r2 = coef_rayon_force_rappel*coef_rayon_force_rappel*pow((volume_reel[ibg]*3)/(4.*M_PI), 2./3.);
7803 noms_forces[idir] += "+((";
7804 noms_forces[idir] += Nom("(X-(")+Nom(xir, "%g")+Nom("))*(X-(")+Nom(xir, "%g")+Nom("))");
7805 noms_forces[idir] += Nom("+(Y-(")+Nom(yir, "%g")+Nom("))*(Y-(")+Nom(yir, "%g")+Nom("))");
7806 noms_forces[idir] += Nom("+(Z-(")+Nom(zir, "%g")+Nom("))*(Z-(")+Nom(zir, "%g")+Nom("))");
7807 noms_forces[idir] += Nom("-")+Nom(r2, "%g");
7808 // 1-ff is the code name for chi_v in our case :
7809 // on veut > 0.9999 pour ne pas changer la gravite dans les mailles ou il y a une interface, ce qui rend la methode instable
7810 noms_forces[idir] += ")_LT_0.)*(1.-ff)*((1.-ff)_GT_0.000001)*(" ;
7811 noms_forces[idir] += Nom(individual_forces(ibulle_reelle,idir), "%g");
7812 noms_forces[idir] += ")" ;
7813 }
7814 set_field_data(rappel[idir], noms_forces[idir], indic, 0. /* could be time... */ );
7815 }
7816}
7817
7819 const IJK_Field_double& indic,
7820 const ArrOfDouble& volume_reel,
7821 const DoubleTab& position) const
7822{
7823 Nom nom_indicatrices_np;
7824 nom_indicatrices_np = "";
7825 for (int ib=0; ib < nb_bulles_reelles_; ib++)
7826 {
7827 double xir = positions_reference_(ib,0);
7828 double yir = positions_reference_(ib,1);
7829 double zir = positions_reference_(ib,2);
7830 // Une ellipse autour de la bulle :
7831 double r=pow((volume_reel[ib]*3)/(4.*M_PI), 1./3.);
7832 double a=5.0*r;
7833 double b=2.5*r;
7834 double c=b;
7835 double x0=xir-2*r;
7836 double y0=yir;
7837 double z0=zir;
7838
7839 nom_indicatrices_np += "+((";
7840 nom_indicatrices_np += Nom("((X-(")+Nom(x0, "%g")+Nom("))*(X-(")+Nom(x0, "%g")+Nom("))/(")+Nom(a, "%g")+Nom("*")+Nom(a, "%g")+Nom("))");
7841 nom_indicatrices_np += Nom("+((Y-(")+Nom(y0, "%g")+Nom("))*(Y-(")+Nom(y0, "%g")+Nom("))/(")+Nom(b, "%g")+Nom("*")+Nom(b, "%g")+Nom("))");
7842 nom_indicatrices_np += Nom("+((Z-(")+Nom(z0, "%g")+Nom("))*(Z-(")+Nom(z0, "%g")+Nom("))/(")+Nom(c, "%g")+Nom("*")+Nom(c, "%g")+Nom("))");
7843 nom_indicatrices_np += Nom("-1.0");
7844 // 1-ff is the code name for chi_v in our case :
7845 nom_indicatrices_np += ")_LT_0.)*(1.0)" ;
7846 }
7847 // Pour les bulles ghosts
7848
7849 assert(ghost_compo_converter_.size_array() == nb_bulles_ghost_);
7850 for (int ibg=0; ibg < nb_bulles_ghost_; ibg++)
7851 {
7852
7853 double xir = position(nb_bulles_reelles_+ibg,0);
7854 double yir = position(nb_bulles_reelles_+ibg,1);
7855 double zir = position(nb_bulles_reelles_+ibg,2);
7856 double r=pow((volume_reel[ibg]*3)/(4.*M_PI), 1./3.);
7857 double a=5*r;
7858 double b=2.5*r;
7859 double c=b;
7860 double x0=xir-2*r;
7861 double y0=yir;
7862 double z0=zir;
7863
7864 nom_indicatrices_np += "+((";
7865 nom_indicatrices_np += Nom("((X-(")+Nom(x0, "%g")+Nom("))*(X-(")+Nom(x0, "%g")+Nom("))/(")+Nom(a, "%g")+Nom("*")+Nom(a, "%g")+Nom("))");
7866 nom_indicatrices_np += Nom("+((Y-(")+Nom(y0, "%g")+Nom("))*(Y-(")+Nom(y0, "%g")+Nom("))/(")+Nom(b, "%g")+Nom("*")+Nom(b, "%g")+Nom("))");
7867 nom_indicatrices_np += Nom("+((Z-(")+Nom(z0, "%g")+Nom("))*(Z-(")+Nom(z0, "%g")+Nom("))/(")+Nom(c, "%g")+Nom("*")+Nom(c, "%g")+Nom("))");
7868 nom_indicatrices_np += Nom("-1.0");
7869 // 1-ff is the code name for chi_v in our case :
7870 nom_indicatrices_np += ")_LT_0.)*(1.0)" ;
7871
7872 }
7873 Cerr << "Setting indicatrice_non_perturbe :" << nom_indicatrices_np << finl;
7874 // Cette methode parcours ni(), nj() et nk() et donc pas les ghost...
7875 set_field_data(indic_np, nom_indicatrices_np, indic, 0. /* could be time... */ );
7876}
7877
7878// Dans cette methode on calcule l'indicatrice_next_ en fonction de
7879// la variable interfaces_.
7880// /!\ Si l'interface n'a pas ete deplacee on recalcule la mm chose.
7881// A n'appeler qu'apres un deplacement d'interface donc ou pour
7882// initialisation.
7884 const DoubleTab& gravite,
7885 const double delta_rho,
7886 const double sigma,
7887 const double time,
7888 const int itstep,
7889 const bool parcourir
7890)
7891{
7892 // En monophasique, les champs sont a jours donc on zap :
7894 return;
7895
7896 Navier_Stokes_FTD_IJK& ns = ref_ijk_ft_->eq_ns();
7897
7898 statistics().create_custom_counter("Calcul Indicatrice Next",2,"IJK");
7899 statistics().begin_count("Calcul Indicatrice Next",statistics().get_last_opened_counter_level()+1);
7900 // En diphasique sans bulle (pour cas tests), on met tout a 1.
7901 if (get_nb_bulles_reelles() == 0)
7902 {
7903 indicatrice_ft_[next()].data() = 1.;
7904 indicatrice_ns_[next()].data() = 1.;
7905 indicatrice_ft_[next()].echange_espace_virtuel(indicatrice_ft_[next()].ghost());
7906 indicatrice_ns_[next()].echange_espace_virtuel(indicatrice_ns_[next()].ghost());
7907
7908 if (parcourir)
7910 statistics().end_count("Calcul Indicatrice Next");
7911 return;
7912 }
7913
7914 if (parcourir)
7916
7917 // Calcul de l'indicatrice sur le domaine etendu :
7918 // faut-il calculer les valeurs de l'indicatrice from scratch ? (avec methode
7919 // des composantes connexes)
7922 else
7924
7925 indicatrice_ft_[next()].echange_espace_virtuel(indicatrice_ft_[next()].ghost());
7926
7927 // Calcul de l'indicatrice sur le domaine NS :
7930 indicatrice_ns_[next()].echange_espace_virtuel(indicatrice_ns_[next()].ghost());
7931
7932 // Calcul des indicatrices s'il y a des groupes :
7933 const int nb_grps = IJK_Interfaces::nb_groups();
7934 if (nb_grps > 1)
7935 {
7938 else
7940
7941 groups_indicatrice_ft_[next()].echange_espace_virtuel();
7942
7943 // Calcul de l'indicatrice sur le domaine NS :
7945 groups_indicatrice_ns_[next()].echange_espace_virtuel();
7946 }
7947
7948 // Aux cellules diphasiques, calcule toutes les moyennes de l'interface
7949 // dans les cellules pour chaque compo. Le but est de le faire une fois
7950 // pour toute de maniere synchronisee (et pas au moment ou on calcule la
7951 // force par exemple).
7952
7953 val_par_compo_in_cell_computation_.calculer_valeur_par_compo(
7954 time, itstep,
7962
7963 // calcul de la force de repulsion
7969 gravite,
7970 delta_rho,
7971 sigma,
7972 time,
7973 itstep
7974 );
7975
7976#if VERIF_INDIC
7977 verif_indic();
7978#endif
7979
7980 // Calcul normale_of_interf_ bary_of_interf_ et passage a NS
7983
7984 for (int c=0; c < 3; c++)
7985 {
7987 normal_of_interf_[next()][c],
7990 bary_of_interf_[next()][c],
7991 bary_of_interf_ns_[next()][c]);
7992 }
7993 normal_of_interf_ns_[next()].echange_espace_virtuel();
7994 bary_of_interf_ns_[next()].echange_espace_virtuel();
7995
7996 // Aux faces mouillees
8003 // Passage au domaine NS
8007 for (int c=0; c<3; c++)
8011
8012
8013 // Calcul de la surface interfaciale
8015 surface_interface_ft_[next()].echange_espace_virtuel(surface_interface_ft_[next()].ghost());
8016
8017 // Calcul du barycentre de la phase
8019 for (int bary_compo = 0; bary_compo < 3; bary_compo++)
8020 {
8021 barycentre_phase1_ft_[next()][bary_compo].echange_espace_virtuel(barycentre_phase1_ft_[next()][bary_compo].ghost());
8022 }
8023
8024 // Calcul de l'indicatrice surfacique et du barycentre correspondant
8026 indicatrice_surfacique_face_ft_[next()].echange_espace_virtuel();
8027
8028 for (int face_dir = 0; face_dir < 3; face_dir++)
8029 {
8030 for (int bary_compo = 0; bary_compo < 2; bary_compo++)
8031 {
8032 barycentre_phase1_face_ft_[next()][face_dir][bary_compo].echange_espace_virtuel(barycentre_phase1_face_ft_[next()][face_dir][bary_compo].ghost());
8033 }
8034 }
8035
8036 // Passage au domaine NS
8038 surface_interface_ns_[next()].echange_espace_virtuel(surface_interface_ns_[next()].ghost());
8039
8040 for (int d = 0; d < 3; d++)
8041 {
8043 barycentre_phase1_ns_[next()][d].echange_espace_virtuel(barycentre_phase1_ns_[next()][d].ghost());
8044 }
8045
8049 indicatrice_surfacique_face_ns_[next()].echange_espace_virtuel();
8050
8051 for (int face_dir = 0; face_dir < 3; face_dir++)
8052 {
8053 for (int bary_compo = 0; bary_compo < 2; bary_compo++)
8054 {
8055 ns.redistrib_from_ft_elem().redistribute(barycentre_phase1_face_ft_[next()][face_dir][bary_compo], barycentre_phase1_face_ns_[next()][face_dir][bary_compo]);
8056 barycentre_phase1_face_ns_[next()][face_dir][bary_compo].echange_espace_virtuel(barycentre_phase1_face_ns_[next()][face_dir][bary_compo].ghost());
8057 }
8058 }
8059 statistics().end_count("Calcul Indicatrice Next");
8060}
8061
8062// Dans cette methode on calcule l'indicatrice_intermediaire_ en fonction de
8063// la variable interfaces_intermediaire_, qui doit correspondre a l'interface
8064// deplacee mais avant l'etape de remaillage.
8066 IJK_Field_double& indicatrice_intermediaire_ft,
8067 IJK_Field_double& indicatrice_intermediaire_ns,
8068 IJK_Field_vector3_double& indicatrice_surfacique_intermediaire_face_ft,
8069 IJK_Field_vector3_double& indicatrice_surfacique_intermediaire_face_ns,
8070 const bool parcourir
8071)
8072{
8073 // En monophasique, les champs sont a jours donc on zap :
8075 return;
8076 statistics().create_custom_counter("Calcul Indicatrice Next",2,"IJK");
8077 statistics().begin_count("Calcul Indicatrice Next",statistics().get_last_opened_counter_level()+1);
8078 // En diphasique sans bulle (pour cas tests), on met tout a 1.
8079 if (get_nb_bulles_reelles() == 0)
8080 {
8081 indicatrice_intermediaire_ft.data() = 1.;
8082 indicatrice_intermediaire_ns.data() = 1.;
8083 indicatrice_intermediaire_ft.echange_espace_virtuel(indicatrice_intermediaire_ft.ghost());
8084 indicatrice_intermediaire_ns.echange_espace_virtuel(indicatrice_intermediaire_ns.ghost());
8085
8086 if (parcourir)
8088 statistics().end_count("Calcul Indicatrice Next");
8089 return;
8090 }
8091
8092 if (parcourir)
8094
8095 // Calcul de l'indicatrice sur le domaine etendu :
8096 // faut-il calculer les valeurs de l'indicatrice from scratch ? (avec methode
8097 // des composantes connexes)
8099 calculer_indicatrice(indicatrice_intermediaire_ft);
8100 else
8101 calculer_indicatrice_optim(indicatrice_intermediaire_ft);
8102
8103 indicatrice_intermediaire_ft.echange_espace_virtuel(indicatrice_intermediaire_ft.ghost());
8104
8105 // Calcul de l'indicatrice sur le domaine NS :
8106 ref_ijk_ft_->eq_ns().redistrib_from_ft_elem().redistribute(
8107 indicatrice_intermediaire_ft, indicatrice_intermediaire_ns);
8108 indicatrice_intermediaire_ns.echange_espace_virtuel(indicatrice_intermediaire_ns.ghost());
8109
8110 // Calcul de l'indicatrice surfacique correspondante
8111 calculer_indicatrice_surfacique_face(indicatrice_surfacique_intermediaire_face_ft, indicatrice_intermediaire_ft, normal_of_interf_[next()]);
8112 indicatrice_surfacique_intermediaire_face_ft.echange_espace_virtuel();
8113
8114 ref_ijk_ft_->eq_ns().get_redistribute_from_splitting_ft_faces(
8115 indicatrice_surfacique_intermediaire_face_ft,
8116 indicatrice_surfacique_intermediaire_face_ns);
8117 indicatrice_surfacique_intermediaire_face_ns.echange_espace_virtuel();
8118
8119 statistics().end_count("Calcul Indicatrice Next");
8120}
8121
8122#if VERIF_INDIC
8124{
8125 calculer_indicatrice(indicatrice_ft_test_);
8126 indicatrice_ft_test_.echange_espace_virtuel(indicatrice_ft_test_.ghost());
8127 SChaine indic;
8128 if (nb_grps > 1)
8129 {
8130 calculer_indicatrices(groups_indicatrice_ft_test_);
8131 groups_indicatrice_ft_test_.echange_espace_virtuel();
8132 }
8133 SChaine group_indic;
8134
8135 const int ni = indicatrice_ft_[next()].ni();
8136 const int nj = indicatrice_ft_[next()].nj();
8137 const int nk = indicatrice_ft_[next()].nk();
8138
8139 int egalite = 1;
8140 for (int k = 0; k < nk; k++)
8141 for (int j = 0; j < nj; j++)
8142 for (int i = 0; i < ni; i++)
8143 {
8144 if (indicatrice_ft_[next()](i, j, k) != indicatrice_ft_test_(i, j, k))
8145 {
8146 egalite = 0;
8147 indic << "(" << i << "," << j << "," << k << ") : " << indicatrice_ft_[next()](i, j, k) << " VS "
8148 << indicatrice_ft_test_(i, j, k) << finl;
8149 }
8150 for (int igroup = 0; igroup < nb_grps; igroup++)
8151 {
8152 if (groups_indicatrice_ft_[next()][igroup](i, j, k) != groups_indicatrice_ft_test_[igroup](i, j, k))
8153 {
8154 egalite = 0;
8155 group_indic << "groupe = " << igroup << " (" << i << "," << j << "," << k
8156 << ") : " << groups_indicatrice_ft_[next()][igroup](i, j, k) << " VS "
8157 << groups_indicatrice_ft_next_test_[igroup](i, j, k) << finl;
8158 }
8159 }
8160 }
8161
8162 Process::Journal() << indic.get_str() << group_indic.get_str() << finl;
8163 if (!egalite)
8164 {
8165 Cerr << "Probleme_FTD_IJK_base:: calcul de l'indicatrice faux ! (iteration " << tstep_ << " sur " << nb_timesteps_ << " )"
8166 << finl;
8167 Process::exit();
8168 }
8169}
8170#endif
8171
8172double IJK_Interfaces::get_barycentre(bool next_time, int bary_compo, int phase, int i, int j, int k) const
8173{
8174 int current_time = next_time ? next() : old();
8175 int other_time = next_time ? old() : next();
8176
8177 double current_indicatrice = next_time ? In(i,j,k) : I(i,j,k);
8178 double other_time_indicatrice = next_time ? I(i,j,k) : In(i,j,k);
8179
8180 if ((I(i,j,k) == 0.) && (In(i,j,k) == 0.))
8181 {
8182 return .5;
8183 }
8184 else if ((I(i,j,k) == 1.) && (In(i,j,k) == 1.))
8185 {
8186 return .5;
8187 }
8188 else if (current_indicatrice == 0.)
8189 {
8190 assert(barycentre_phase1_ns_[current_time][bary_compo](i,j,k) == .5);
8191 if (phase == 0)
8192 {
8193 return .5;
8194 }
8195 else
8196 {
8197 double other_time_bary_compo = barycentre_phase1_ns_[other_time][bary_compo](i,j,k);
8198 if (other_time_bary_compo > .5)
8199 {
8200 return 1;
8201 }
8202 else
8203 {
8204 return 0;
8205 }
8206 }
8207 }
8208 else if (current_indicatrice == 1.)
8209 {
8210 assert(barycentre_phase1_ns_[current_time][bary_compo](i,j,k) == .5);
8211 if (phase == 1)
8212 {
8213 return .5;
8214 }
8215 else
8216 {
8217 double other_time_bary_compo = barycentre_phase1_ns_[other_time][bary_compo](i,j,k);
8218 other_time_bary_compo = opposing_barycentre(other_time_bary_compo, other_time_indicatrice);
8219 if (other_time_bary_compo > .5)
8220 {
8221 return 1;
8222 }
8223 else
8224 {
8225 return 0;
8226 }
8227 }
8228 }
8229 else
8230 {
8231 double bary = barycentre_phase1_ns_[current_time][bary_compo](i,j,k);
8232
8233 if (phase == 0)
8234 {
8235 bary = opposing_barycentre(bary, current_indicatrice);
8236 }
8237 assert(bary >= 0 && bary <= 1.);
8238 return bary;
8239 }
8240}
8241double IJK_Interfaces::get_barycentre_face(bool next_time, int face_dir, int bary_compo, int phase, int i, int j, int k) const
8242{
8243 int current_time = next_time ? next() : old();
8244 int other_time = next_time ? old() : next();
8245
8246 double old_indicatrice_surfacique = get_indicatrice_surfacique_face_old()[face_dir](i,j,k);
8247 double next_indicatrice_surfacique = get_indicatrice_surfacique_face_next()[face_dir](i,j,k);
8248 double current_indicatrice_surfacique = next_time ? next_indicatrice_surfacique : old_indicatrice_surfacique;
8249 double other_time_indicatrice_surfacique = next_time ? old_indicatrice_surfacique : next_indicatrice_surfacique;
8250
8251 if (face_dir == bary_compo)
8252 {
8253 return 0.;
8254 }
8255 else
8256 {
8257 // Pour la face x dir1=z -> (2->0) dir2=y -> (1->1)
8258 // Pour la face y dir1=x -> (0->0) dir2=z -> (2->1)
8259 // Pour la face z dir1=y -> (1->0) dir2=x -> (0->1)
8260 int compo2D = (face_dir == 0) ? ((bary_compo == 2) ? 0 : ((bary_compo == 1) ? 1 : -1)) :
8261 ((face_dir == 1) ? ((bary_compo == 0) ? 0 : ((bary_compo == 2) ? 1 : -1)) :
8262 ((face_dir == 2) ? ((bary_compo == 1) ? 0 : ((bary_compo == 0) ? 1 : -1)) :
8263 -1));
8264 assert(compo2D >= 0);
8265 if ((old_indicatrice_surfacique == 0.) && (next_indicatrice_surfacique == 0.))
8266 {
8267 return .5;
8268 }
8269 else if ((old_indicatrice_surfacique == 1.) && (next_indicatrice_surfacique == 1.))
8270 {
8271 return .5;
8272 }
8273 else if (current_indicatrice_surfacique == 0.)
8274 {
8275 //assert(barycentre_phase1_face_ns_[current_time][face_dir][compo2D](i,j,k) == .5);
8276 if (phase == 0)
8277 {
8278 return .5;
8279 }
8280 else
8281 {
8282 double other_time_bary_compo = barycentre_phase1_face_ns_[other_time][face_dir][compo2D](i,j,k);
8283 if (other_time_bary_compo > .5)
8284 {
8285 return 1;
8286 }
8287 else
8288 {
8289 return 0;
8290 }
8291 }
8292 }
8293 else if (current_indicatrice_surfacique == 1.)
8294 {
8295 //assert(barycentre_phase1_face_ns_[current_time][face_dir][compo2D](i,j,k) == .5);
8296 if (phase == 1)
8297 {
8298 return .5;
8299 }
8300 else
8301 {
8302 double other_time_bary_compo = barycentre_phase1_face_ns_[other_time][face_dir][compo2D](i,j,k);
8303 other_time_bary_compo = opposing_barycentre(other_time_bary_compo, other_time_indicatrice_surfacique);
8304 if (other_time_bary_compo > .5)
8305 {
8306 return 1;
8307 }
8308 else
8309 {
8310 return 0;
8311 }
8312 }
8313 }
8314 else
8315 {
8316 double bary = barycentre_phase1_face_ns_[current_time][face_dir][compo2D](i,j,k);
8317
8318 if (phase == 0)
8319 {
8320 bary = opposing_barycentre(bary, current_indicatrice_surfacique);
8321 }
8322 assert(bary >= 0 && bary <= 1.);
8323 return bary;
8324 }
8325 }
8326}
8327
8328// Copie de l'interface et des intersections associees au pas de temps precedent
8333
8335{
8337 return;
8338
8340
8341 champs_compris_.switch_ft_fields();
8342
8343 // TODO: verifier la liste des echanges espace virtuels
8344 // TODO: il faut choisir, soit je les fait sur les next soit sur les old, mais
8345 // pas les deux.
8346 indicatrice_ft_[old()].echange_espace_virtuel(indicatrice_ft_[old()].ghost());
8347 groups_indicatrice_ft_[old()].echange_espace_virtuel();
8348 nb_compo_traversante_[old()].echange_espace_virtuel(nb_compo_traversante_[old()].ghost());
8349 normale_par_compo_[old()].echange_espace_virtuel();
8350 bary_par_compo_[old()].echange_espace_virtuel();
8351 surface_par_compo_[old()].echange_espace_virtuel();
8352
8353 surface_interface_ft_[old()].echange_espace_virtuel(surface_interface_ft_[old()].ghost());
8354 surface_interface_ns_[old()].echange_espace_virtuel(surface_interface_ns_[old()].ghost());
8355
8356 for (int bary_compo = 0; bary_compo < 3; bary_compo++)
8357 {
8358 barycentre_phase1_ft_[old()][bary_compo].echange_espace_virtuel(barycentre_phase1_ft_[old()][bary_compo].ghost());
8359 barycentre_phase1_ns_[old()][bary_compo].echange_espace_virtuel(barycentre_phase1_ns_[old()][bary_compo].ghost());
8360 }
8361
8362 indicatrice_surfacique_face_ft_[old()].echange_espace_virtuel();
8363 indicatrice_surfacique_face_ns_[old()].echange_espace_virtuel();
8364
8365 for (int face_dir = 0; face_dir < 3; face_dir++)
8366 {
8367 for (int bary_compo = 0; bary_compo < 2; bary_compo++)
8368 {
8369 barycentre_phase1_face_ft_[old()][face_dir][bary_compo].echange_espace_virtuel(barycentre_phase1_face_ft_[old()][face_dir][bary_compo].ghost());
8370 barycentre_phase1_face_ns_[old()][face_dir][bary_compo].echange_espace_virtuel(barycentre_phase1_face_ns_[old()][face_dir][bary_compo].ghost());
8371 }
8372 }
8373
8374 normal_of_interf_[old()].echange_espace_virtuel();
8375 bary_of_interf_[old()].echange_espace_virtuel();
8376 normal_of_interf_ns_[old()].echange_espace_virtuel();
8377 bary_of_interf_ns_[old()].echange_espace_virtuel();
8378
8379 surface_vapeur_par_face_[old()].echange_espace_virtuel();
8380 surface_vapeur_par_face_ns_[old()].echange_espace_virtuel();
8381 for (int c = 0; c < 3; c++)
8382 {
8383 barycentre_vapeur_par_face_[old()][c].echange_espace_virtuel();
8384 barycentre_vapeur_par_face_ns_[old()][c].echange_espace_virtuel();
8385 }
8386
8387 indicatrice_ns_[old()].echange_espace_virtuel(indicatrice_ns_[old()].ghost());
8388 groups_indicatrice_ns_[old()].echange_espace_virtuel();
8389}
8390
8391
8397 const DoubleTab& gravite,
8398 const double delta_rho,
8399 const double sigma,
8400 const double time,
8401 const int itstep
8402)
8403{
8404 field_repulsion_.data() = -1.;
8405
8406 ArrOfDouble potentiels_sommets;
8407 ArrOfDouble repulsions_sommets;
8408 calculer_phi_repuls_sommet(potentiels_sommets, repulsions_sommets, gravite, delta_rho, sigma, time, itstep);
8409 val_par_compo_in_cell_computation_.calculer_moy_field_sommet_par_compo(
8410 potentiels_sommets, phi_par_compo);
8411
8412
8413 if (!maillage_ft_ijk_.Surfactant_facettes().get_disable_surfactant() or (maillage_ft_ijk_.Surfactant_facettes().get_disable_surfactant() and use_tryggvason_interfacial_source_ ))
8414 {
8415 // on passe ici si sigma = variable
8416 // ou si sigma = cte, mais terme source interf = formulation Tryggvason
8417 DoubleTab interfacial_source_term_sommet = maillage_ft_ijk_.update_sigma_and_interfacial_source_term_sommet(ref_domaine_, true, use_tryggvason_interfacial_source_, sigma);
8418 ArrOfDouble interfacial_source_term_sommet_dir, unite;
8419 interfacial_source_term_sommet_dir.resize(maillage_ft_ijk_.nb_sommets());
8420 unite.resize(maillage_ft_ijk_.nb_sommets());
8421 for (int som = 0; som < maillage_ft_ijk_.nb_sommets(); som++)
8422 unite(som) = 1. ;
8423 val_par_compo_in_cell_computation_.calculer_somme_field_sommet_par_compo(unite, surf_par_compo);
8424
8425 for (int dir = 0; dir < 3; dir++)
8426 {
8427 for (int som = 0; som < maillage_ft_ijk_.nb_sommets(); som++)
8428 interfacial_source_term_sommet_dir(som)=interfacial_source_term_sommet(som, dir);
8429 val_par_compo_in_cell_computation_.calculer_moy_field_sommet_par_compo(interfacial_source_term_sommet_dir, source_interf_par_compo[dir]);
8430 }
8431 }
8432
8433 val_par_compo_in_cell_computation_.calculer_moy_field_sommet_par_compo(
8434 repulsions_sommets, repuls_par_compo);
8435
8436 const Domaine_IJK& split = ref_domaine_;
8437 const int ni = split.get_nb_elem_local(DIRECTION_I);
8438 const int nj = split.get_nb_elem_local(DIRECTION_J);
8439 const int nk = split.get_nb_elem_local(DIRECTION_K);
8440
8441 for (int k = 0; k < nk; k++)
8442 for (int j = 0; j < nj; j++)
8443 for (int i = 0; i < ni; i++)
8444 {
8445 field_repulsion_(i, j, k) = repuls_par_compo[0](i, j, k);
8446 }
8447}
8448
8449
8451 ArrOfDouble& potentiels_sommets,
8452 ArrOfDouble& repulsions_sommets,
8453 const DoubleTab& gravite,
8454 const double delta_rho,
8455 const double sigma,
8456 const double time,
8457 const int itstep
8458)
8459{
8460
8461 // Initialisation forcee a -1 :
8462
8463 const Domaine_IJK& geom = ref_domaine_.valeur();
8464
8465 // calculer la courbure et le terme de gravite aux sommets du maillage
8466 // lagrangien On appelle ce terme "phi", potentiel aux sommets
8467 const Maillage_FT_IJK& mesh = maillage_ft_ijk_;
8468 const ArrOfDouble& courbure = mesh.get_update_courbure_sommets();
8469 potentiels_sommets = courbure;
8470 const double dxi = geom.get_constant_delta(DIRECTION_I);
8471 const double dxj = geom.get_constant_delta(DIRECTION_J);
8472 const double dxk = geom.get_constant_delta(DIRECTION_K);
8473 const double vol_cell = dxi * dxj * dxk;
8474 const DoubleTab& sommets = mesh.sommets();
8475 const int nb_som = potentiels_sommets.size_array();
8476 //ducluz : c'est ici qu'on multiplie le potentiel par sigma
8477 //Il faut quil passe en sigma variable ici dans le cas de surfactant
8478 if (!maillage_ft_ijk_.Surfactant_facettes().get_disable_surfactant())
8479 {
8480 //DoubleTab interfacial_source_term_sommet = maillage_ft_ijk_.update_sigma_and_interfacial_source_term_sommet(ref_domaine_, false, use_tryggvason_interfacial_source_);
8481 const ArrOfDouble& sigma_sommets = maillage_ft_ijk_.Surfactant_facettes().get_sigma_sommets();
8482 for (int i = 0; i < nb_som; i++)
8483 {
8484 potentiels_sommets[i] *= sigma_sommets[i];
8485 }
8486 }
8487 else
8488 {
8489 potentiels_sommets *= sigma;
8490 }
8491
8492
8493 // Terme source de gravite:
8494 // on ajoute le potentiel de gravite = +/- delta_rho * (vecteur_g scalaire
8495 // Ox), Ox est le vecteur qui va de l'origine au sommet de l'interface
8496 repulsions_sommets.resize_array(nb_som);
8497
8498 // Ajout du terme de gravite:
8499
8500 ArrOfIntFT compo_connexe_sommets;
8501 mesh.calculer_compo_connexe_sommets(compo_connexe_sommets);
8503 {
8504 // Nouvelle version :
8505 DoubleTab deplacement;
8506 // le tableau contient l'encodage pour le deplacement que l'on va decoder :
8507 calculer_deplacement_from_code_compo_connexe_negatif(
8508 mesh, deplacement, bounding_box_NS_domain_
8509 );
8510
8511 for (int i = 0; i < nb_som; i++)
8512 {
8513 double correction_potentiel_deplacement = 0.;
8514 if (compo_connexe_sommets[i] < 0)
8515 {
8516 // Bulle ghost : correction du deplacement:
8517 correction_potentiel_deplacement = -(
8518 gravite(0,0) * deplacement(i, 0) +
8519 gravite(0,1) * deplacement(i, 1) +
8520 gravite(0,2) * deplacement(i, 2)
8521 );
8522 }
8523 const Vecteur3 coord(sommets, i);
8524 double p = (
8525 gravite(0,0) * coord[0] +
8526 gravite(0,1) * coord[1] +
8527 gravite(0,2) * coord[2] +
8528 correction_potentiel_deplacement
8529 );
8530 potentiels_sommets[i] -= p * delta_rho;
8531 }
8532 }
8533
8534 // Terme source de repulsion des bulles:
8536 {
8537 double vrx = DMAXFLOAT;
8538 double vry = DMAXFLOAT;
8539 double vrz = DMAXFLOAT;
8540 DoubleTab vr_to_closer; // The velocity of the closest neighbour
8543 {
8544 double dmin = portee_force_repulsion_;
8545 const ArrOfDouble& z_grid_nodes = geom.get_node_coordinates(DIRECTION_K);
8546 const int nznodes = z_grid_nodes.size_array();
8547 const double zmin = z_grid_nodes[0];
8548 const double zmax = z_grid_nodes[nznodes - 1];
8549 double zsmin = (zmax - zmin) / 2.;
8550 for (int i = 0; i < nb_som; i++)
8551 {
8552 double d = distance_autres_interfaces_[i];
8553 if (d < dmin)
8554 {
8555 dmin = d;
8556 vrx = vr_to_closer(i, 0);
8557 vry = vr_to_closer(i, 1);
8558 vrz = vr_to_closer(i, 2);
8559 }
8560 // dmin = std::min(dmin, d);
8561 double phi = 0.;
8562 if (active_repulsion_paroi_ && !geom.get_periodic_flag(DIRECTION_K))
8563 {
8564 // Repulsion des parois haute et basse:
8565 const double z = sommets(i, 2);
8566 double dzs = std::min(z - zmin, zmax - z);
8567 zsmin = std::min(zsmin, dzs);
8569 {
8570 dzs = std::min(dzs, portee_wall_repulsion_);
8571 // Ici, la repulsion paroi est donnee par une loi specifique :
8572 phi = (
8574 (portee_wall_repulsion_ - dzs) /
8576 );
8577 }
8578 else
8579 {
8580 // Ici, la repulsion paroi est mise dans d, donc c'est la meme loi
8581 // que pour l'inter-bulles :
8582 d = std::min(d, dzs);
8583 }
8584 }
8585 // Le "+=" sert dans le cas ou on a mis 2 lois differentes :
8587 potentiels_sommets[i] -= phi;
8588 repulsions_sommets[i] = -phi * vol_cell;
8589 }
8590 double dmin_local = dmin;
8591 // Reduce 2 mp_min calls to 1 by using mp_min_for_each
8592 Process::mp_min_for_each(dmin, zsmin);
8593
8594 int flag = 0;
8595 int iproc = Process::nproc();
8596 if (fabs(dmin_local - dmin) < 1e-12)
8597 {
8598 flag = 1;
8599 iproc = Process::me();
8600 }
8601 const int sumflag = Process::check_int_overflow(Process::mp_sum(flag));
8602 if (sumflag != 1)
8603 {
8604 Cerr << "Warning. There were equalities ("
8605 << Process::mp_sum(flag)
8606 << ") in dmin computation. "
8607 << "2 equalities seems possible if it's between two markers "
8608 "separated by a proc frontieer. "
8609 << finl;
8610 // En cas d'egalite, il faut trancher pour que tout le monde soit
8611 // d'accord sur les envois/receptions :
8612 // on prend le petit proc:
8613 iproc = Process::mp_min(iproc);
8614 }
8615 else
8616 {
8617 // S'il n'y a pas d'egalite, il faut faire connaitre iproc a tous pour
8618 // l'envoi : C'est une sorte d'envoyer_broadcast(iproc, iproc), sauf
8619 // qu'evidemment, ca n'a pas de sens.
8620 iproc = Process::mp_min(iproc);
8621 // Voila. Au moins tout le monde connait le proc du min...
8622 }
8623 envoyer_broadcast(vrx, iproc);
8624 envoyer_broadcast(vry, iproc);
8625 envoyer_broadcast(vrz, iproc);
8626
8627 // Impression dans le fichier _dmin.out :
8628 const double dx = geom.get_constant_delta(DIRECTION_I);
8629 const double dy = geom.get_constant_delta(DIRECTION_J);
8630 const double dz = geom.get_constant_delta(DIRECTION_K);
8632 {
8633 double norm_ur = std::sqrt(vrx * vrx + vry * vry + vrz * vrz);
8634 const double dt = ref_ijk_ft_->schema_temps_ijk().get_timestep();
8635 double cfl = dt * std::min(std::min(std::fabs(vrx) / dx, std::fabs(vry) / dy), std::fabs(vrz) / dz);
8636 int reset = (!reprise_) && (itstep == 0);
8637 SFichier fic = Ouvrir_fichier(
8638 "_dmin.out", "tstep\ttime\t\tdmin\tzsmin\tur\tCFL_local", reset
8639 );
8640 fic << itstep << " " << time << " " << dmin << " " << zsmin;
8641 fic << " " << norm_ur << " " << cfl << finl;
8642 fic.close();
8643 }
8644 }
8645 }
8646 potentiels_sommets *= dxi * dxj * dxk;
8647
8648 // Au pire, on prend la plus grande largeur de maille eulerienne :
8649 double lg_euler = std::max(std::max(dxi, dxj), dxk);
8650 double lg_lagrange = mesh.minimum_longueur_arrete();
8651 const double sqrt_3 = 1.7320508075688772;
8652 bool ok = (lg_lagrange > lg_euler * sqrt_3);
8653 Cerr << "Test de la taille de maille eulerienne : lg_lagrange=" << lg_lagrange << " > (lg_euler=" << lg_euler
8654 << ")*1.7320... ? " << (ok ? "ok" : "ko") << " (ratio : " << lg_lagrange / (lg_euler * sqrt_3)
8655 << (ok ? " >" : " <") << "1 )" << finl;
8656}
const IJK_Interfaces & get_interfaces() const
Int3 get_ijk(int n) const
int get_n(int i, int j, int k) const
static void calcul_surface_interface_efficace(double timestep, const IJK_Field_vector3_double &velocity, const IJK_Field_double &old_indicatrice_ns, const IJK_Field_double &next_indicatrice_ns, const DoubleTabFT_cut_cell_vector3 &vitesse_deplacement_interface, const DoubleTabFT_cut_cell_vector3 &normale_deplacement_interface, DoubleTabFT_cut_cell_scalar &surface_efficace_interface)
static void calcul_surface_interface_efficace_initiale(int methode_explicite, const IJK_Field_double &old_indicatrice_ns, const IJK_Field_double &next_indicatrice_ns, const IJK_Field_double &surface_interface_ns_old, const IJK_Field_double &surface_interface_ns_next, const IJK_Field_vector3_double &normal_of_interf_ns_old, const IJK_Field_vector3_double &normal_of_interf_ns_next, DoubleTabFT_cut_cell_vector3 &normale_deplacement_interface, DoubleTabFT_cut_cell_scalar &surface_efficace_interface, DoubleTabFT_cut_cell_scalar &surface_efficace_interface_initial)
static void imprimer_informations_surface_efficace_interface(int verbosite_surface_efficace_interface, double timestep, const IJK_Field_vector3_double &velocity, const IJK_Field_double &old_indicatrice_ns, const IJK_Field_double &next_indicatrice_ns, const DoubleTabFT_cut_cell_scalar &surface_efficace_interface, const DoubleTabFT_cut_cell_scalar &surface_efficace_interface_initial, const DoubleTabFT_cut_cell_vector3 &normale_deplacement_interface, const DoubleTabFT_cut_cell_vector3 &vitesse_deplacement_interface)
static void calcul_delta_volume_theorique_bilan(int compo, const DoubleTab &bounding_box_bulles, double timestep, const IJK_Field_double &indicatrice_avant_deformation, const IJK_Field_double &indicatrice_apres_deformation, const IJK_Field_vector3_double &indicatrice_surfacique_efficace_deformation_face, const Cut_field_vector3_double &deformation_velocity, IJK_Field_double &delta_volume_theorique_bilan)
static void imprimer_informations_surface_efficace_face(int verbosite_surface_efficace_face, int iteration_solver_surface_efficace_face, double timestep, const Cut_field_vector3_double &velocity, const IJK_Field_double &old_indicatrice_ns, const IJK_Field_double &next_indicatrice_ns, const DoubleTabFT_cut_cell_vector3 &indicatrice_surfacique_efficace_face, const DoubleTabFT_cut_cell_vector3 &indicatrice_surfacique_efficace_face_initial)
static void calcul_vitesse_interface(const IJK_Field_vector3_double &velocity, const IJK_Field_double &old_indicatrice_ns, const IJK_Field_double &next_indicatrice_ns, const IJK_Field_vector3_double &barycentre_phase1_ns_old, const IJK_Field_vector3_double &barycentre_phase1_ns_next, DoubleTabFT_cut_cell_vector3 &coord_deplacement_interface, DoubleTabFT_cut_cell_vector3 &vitesse_deplacement_interface)
static void calcul_surface_face_efficace_initiale(int methode_explicite, const IJK_Field_vector3_double &old_indicatrice_surfacique_face_ns, const IJK_Field_vector3_double &next_indicatrice_surfacique_face_ns, DoubleTabFT_cut_cell_vector3 &indicatrice_surfacique_efficace_face, DoubleTabFT_cut_cell_vector3 &indicatrice_surfacique_efficace_face_initial)
static void calcul_surface_face_efficace_iteratif(int verbosite_surface_efficace_face, double timestep, const Cut_field_vector3_double &velocity, int &iteration_solver_surface_efficace_face, const IJK_Field_double &old_indicatrice_ns, const IJK_Field_double &next_indicatrice_ns, const IJK_Field_vector3_double &old_indicatrice_surfacique_face_ns, const IJK_Field_vector3_double &next_indicatrice_surfacique_face_ns, DoubleTabFT_cut_cell_vector3 &indicatrice_surfacique_efficace_face, const DoubleTabFT_cut_cell_vector3 &indicatrice_surfacique_efficace_face_initial, DoubleTabFT_cut_cell_vector6 &indicatrice_surfacique_efficace_face_correction, DoubleTabFT_cut_cell_scalar &indicatrice_surfacique_efficace_face_absolute_error)
void set_to_uniform_value(int valeur)
void collecter_espace_virtuel(ArrOfDouble &tab, MD_Vector_tools::Operations_echange op) const
void echange_espace_virtuel(ArrOfDouble &tab) const
virtual void creer_tableau_elements(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
creation d'un tableau parallele de valeurs aux elements.
Definition Domaine.cpp:851
This class encapsulates all the information related to the eulerian mesh for TrioIJK.
Definition Domaine_IJK.h:47
int get_offset_local(int direction) const
Returns the local offset in requested direction.
int get_neighbour_processor(int previous_or_next, int direction) const
Returns the index of the requested neighbour processor (-1 if no neighbour).
bool is_uniform(int direction) const
Method returns true if uniform in this direction.
int get_nb_elem_local(int direction) const
Returns the number of elements owned by this processor in the given direction.
bool get_periodic_flag(int direction) const
Method returns true if periodic in this direction.
double get_domain_length(int direction) const
Returns the length of the entire domain in requested direction.
double get_constant_delta(int direction) const
Returns the size of cells in a direction.
double get_origin(int direction) const
Returns the coordinate of the first node (global) of the mesh in the requested direction.
int get_nb_items_global(Localisation loc, int direction) const
Returns the number of local items (on this processor) for the given localisation in the requested dir...
Vecteur3 get_coords_of_dof(int i, int j, int k, Localisation loc) const
Determines the dof of an element along a localisation.
int convert_ijk_cell_to_packed(const FixedVector< int, 3 > ijk) const
Converts the ijk index of an element to a cell index.
const ArrOfDouble & get_node_coordinates(int direction) const
Returns an array with the coordinates of all nodes in the mesh in requested direction.
FixedVector< int, 3 > convert_packed_to_ijk_cell(int index) const
Convert the local index of an element to a vector with IJK indices.
Localisation
Localisation sub class.
Definition Domaine_IJK.h:53
void search_elem(const double &x, const double &y, const double &z, FixedVector< int, 3 > &ijk_global, FixedVector< int, 3 > &ijk_local, FixedVector< int, 3 > &ijk_me) const
Find the element which contains the item's coodirnates.
class Domaine_VF
Definition Domaine_VF.h:44
int elem_faces(int i, int j) const
renvoie le numero de le ieme face de la maille num_elem la facon dont ces faces sont numerotees est
Definition Domaine_VF.h:543
int face_voisins(int num_face, int i) const
renvoie l'element voisin de numface dans la direction i.
Definition Domaine_VF.h:418
classe Domaine_dis_base Cette classe est la base de la hierarchie des domaines discretisees.
const Domaine & domaine() const
Fichier en lecture Cette classe est a la classe C++ ifstream ce que la classe Entree est a la.
Definition EFichier.h:29
Ecriture dans un fichier partage Cette classe derive de Ecr_Fic_Par, en utilisant une sortie en binai...
int put(const unsigned *ob, std::streamsize n, std::streamsize pas) override
int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::out) override
Ouvre le fichier avec les parametres mode et prot donnes Ces parametres sont les parametres de la met...
Sortie & syncfile() override
Provoque l'ecriture sur disque des donnees accumulees sur les differents processeurs depuis le dernie...
void set_64b(bool is64) override
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
classe Equation_base Le role d'une equation est le calcul d'un ou plusieurs champs....
Domaine_dis_base & domaine_dis()
Renvoie le domaine discretise associe a l'equation.
void passer_variable_intensive(const Maillage_FT_IJK &mesh)
Definition FT_Field.cpp:261
ArrOfDouble check_conservation(const Maillage_FT_IJK &mesh)
void correction_conservation_globale(const Maillage_FT_IJK &mesh, const ArrOfDouble &surfactant_avant_remaillage, const ArrOfDouble &surfactant_apres_remaillage)
void passer_variable_extensive(const Maillage_FT_IJK &mesh)
Definition FT_Field.cpp:279
void set_disable_surfactant(bool disable_surfactant)
Definition FT_Field.h:360
ArrOfDouble get_FT_field_Array() const
Definition FT_Field.h:347
void avancer_en_temps(const Maillage_FT_IJK &mesh, const double time_step)
Definition FT_Field.cpp:161
bool get_disable_surfactant() const
Definition FT_Field.h:351
void allocate(const Domaine_IJK &d, Domaine_IJK::Localisation l, int ghost_size, int additional_k_layers=0, int nb_compo=1, const Nom &name=Nom(), bool external_storage=false, int monofluide=0, double rov=0., double rol=0., int use_inv_rho_in_pressure_solver=0)
void echange_espace_virtuel(int ghost)
Exchange data over "ghost" number of cells.
Domaine_IJK::Localisation get_localisation() const
const Domaine_IJK & get_domaine() const
const Domaine_IJK & get_domaine() const
: class IJK_Interfaces
void reset_flags_and_counters()
ArrOfInt ghost_compo_converter_
void calculer_kappa_ft(IJK_Field_double &kappa_ft)
void calculer_surface_interface(IJK_Field_double &surf_interface, IJK_Field_double &indic)
FixedVector< FixedVector< IJK_Field_double, max_authorized_nb_of_components_ >, 2 > phi_par_compo_
DoubleTab positions_reference_
ArrOfDoubleFT distance_autres_interfaces_
FixedVector< IJK_Field_vector3_double, 2 > indicatrice_surfacique_face_ft_
IJK_Field_vector3_double deformation_velocity_
static double opposing_barycentre(double initial_barycentre, double initial_area)
SurfaceVapeurIJKComputation surface_vapeur_par_face_computation_
void verif_indic()
int posttraiter_champs_instantanes(const Motcles &liste_post_instantanes, const char *lata_name, const int lata_step) const
double portee_force_repulsion_
const Milieu_base & milieu() const override
void calculer_surfactant(ArrOfDouble &surfactant, ArrOfDouble &surfactant_min, ArrOfDouble &surfactant_max) const
FixedVector< FixedVector< IJK_Field_double, max_authorized_nb_of_components_ >, 2 > indicatrice_par_compo_
void compute_surface_average_per_bubble(const ArrOfDouble &surfaces, const ArrOfDouble &in, ArrOfDouble &out) const
void ajouter_terme_source_interfaces(IJK_Field_vector3_double &vpoint, IJK_Field_vector3_double &vrepul, IJK_Field_vector3_double &vabsrepul) const
int is_terme_gravite_rhog() const
Probleme_FTD_IJK_base & probleme_ijk()
FixedVector< IJK_Field_double, 2 > indicatrice_ns_
void initialize(const Domaine_IJK &splitting_FT, const Domaine_IJK &splitting_NS, const Domaine_dis_base &domaine_dis, const int thermal_probes_ghost_cells=0, const bool compute_vint=true, const bool is_switch=false)
DoubleTab bubbles_velocities_
Nom fichier_sauvegarde_interface_
void set_param_reprise_pb(Param &)
int get_nb_bulles_ghost(const int print=0) const
ArrOfInt compo_to_group_
void deplacer_bulle_perio(const ArrOfInt &masque_deplacement_par_compo)
double factor_length_duplicata_
void calculer_var_volume_remaillage(double timestep, const DoubleTab &vitesses_translation_bulles, const DoubleTab &mean_bubble_rotation_vector, const DoubleTab &centre_gravite, ArrOfDouble &var_volume)
void calculer_indicatrices(IJK_Field_vector3_double &indic)
void supprimer_certaines_bulles_reelles()
void posttraiter_tous_champs(Motcles &liste) const
FixedVector< FixedVector< IJK_Field_double, max_authorized_nb_of_components_ >, 2 > surface_par_compo_
void transporter_maillage_deformation(const int correction_semi_locale_volume_bulle, const DoubleTab &vitesses_translation_bulles, const DoubleTab &mean_bubble_rotation_vector, const DoubleTab &centre_gravite, const double dt_tot, ArrOfDouble &dvol, const int rk_step, const int first_step_interface_smoothing=0)
double seuil_indicatrice_negligeable_
void calculer_indicatrice_optim(IJK_Field_double &indic)
int next() const
DoubleTab bubbles_bary_old_
const IJK_Field_double & I_ft() const
void compute_drapeaux_vapeur_v3(const Maillage_FT_IJK &mesh, const Domaine_IJK &split, const IntVect &vecteur_composantes, ArrOfInt &drapeau_vapeur) const
DoubleTabFT_cut_cell_vector3 vitesse_deplacement_interface_
void calculer_color(ArrOfInt &color) const
void calculer_vitesse_de_deformation(int compo, const DoubleTab &bounding_box_bulles, const Cut_field_vector3_double &cut_field_velocity, const DoubleTab &vitesses_translation_bulles, const DoubleTab &mean_bubble_rotation_vector, const DoubleTab &positions_bulles)
int lire_motcle_non_standard(const Motcle &un_mot, Entree &is) override
Lecture des parametres de type non simple d'un objet_U a partir d'un flot d'entree.
int timestep_sauvegarde_interface_
FixedVector< IJK_Field_double, 2 > surface_interface_ns_
ArrOfDouble var_volume_correction_globale_
void compute_indicatrice_non_perturbe(IJK_Field_double &indic_np, const IJK_Field_double &indic, const ArrOfDouble &volume_reel, const DoubleTab &position) const
void associer_pb_base(const Probleme_base &) override
S'associe au Probleme passe en parametre.
FixedVector< IJK_Field_vector3_double, 2 > bary_of_interf_ns_
int get_ghost_number_from_compo(const int compo) const
void calculer_aire_interfaciale_for_compo(IJK_Field_double &ai, const int compo) const
bool has_readen_barycentres_prev_
DoubleTabFT_cut_cell_scalar surface_efficace_interface_
void calculer_vmoy_translation_composantes_connexes(const Maillage_FT_IJK &maillage, const ArrOfDouble &surface_facette, const ArrOfDouble &surface_par_bulle, const ArrOfInt &compo_connexes_facettes, const int nbulles_reelles, const int nbulles_ghost, const DoubleTab &vitesse_sommets, DoubleTab &vitesses_translation_sommets) const
DoubleTab mean_force_
const IJK_Field_double & I() const
void transporter_maillage_remaillage(int correction_semi_locale_volume_bulle, const DoubleTab &vitesses_translation_bulles, const DoubleTab &mean_bubble_rotation_vector, const DoubleTab &centre_gravite, double dt_tot, ArrOfDouble &dvol, const int rk_step, const double temps)
IJK_Field_double indicatrice_apres_remaillage_ft_
void update_indicatrice_variables_monofluides()
FixedVector< IJK_Field_vector3_double, 2 > indicatrice_surfacique_face_ns_
int old() const
void compute_drapeaux_vapeur_v2(const IntVect &vecteur_composantes, ArrOfInt &drapeau_liquide) const
DoubleTabFT_cut_cell_vector3 indicatrice_surfacique_efficace_face_initial_
FixedVector< FixedVector< IJK_Field_double, 3 *max_authorized_nb_of_components_ >, 2 > bary_par_compo_
DoubleTab RK3_G_store_vi_
FixedVector< FixedVector< IJK_Field_double, 3 *max_authorized_nb_of_components_ >, 2 > normale_par_compo_
IJK_Field_vector3_double indicatrice_surfacique_avant_remaillage_face_ft_
IJK_Composantes_Connex ijk_compo_connex_
void convert_to_IntVect(const ArrOfInt &in, IntVect &out) const
DoubleTab bubbles_bary_new_
FixedVector< FixedVector< FixedVector< IJK_Field_double, 2 >, 3 >, 2 > barycentre_phase1_face_ns_
void dupliquer_bulle_perio(ArrOfInt &masque_duplicata_pour_compo)
ArrOfDouble var_volume_deformation_
void calculer_barycentre(IJK_Field_vector3_double &baric, IJK_Field_double &indic)
std::map< Motcle, IJK_Field_double > scalar_post_fields_
ArrOfDouble var_volume_remaillage_
Remaillage_FT_IJK remaillage_ft_ijk_
int get_nb_bulles_reelles() const
FixedVector< IJK_Field_int, 2 > nb_compo_traversante_
void compute_compo_connex_from_bounding_box()
void preparer_duplicata_bulles(const DoubleTab &bounding_box_of_bubbles, const DoubleTab &bounding_box_offsetp, const DoubleTab &bounding_box_offsetm, const DoubleTab &authorized_bounding_box, ArrOfInt &masque_duplicata_pour_compo_reel)
int ghost_compo_converter(const int i) const
int dt_impression_bilan_indicatrice_
bool read_bubbles_barycentres_vel(const Nom &interf_name, FixedVector< ArrOfDouble, 3 > &bubbles_rising_dir, FixedVector< ArrOfDouble, 3 > &bubbles_rising_vel, ArrOfDouble &bubbles_rising_vel_mag)
const IJK_Field_vector3_double & get_indicatrice_surfacique_face_old() const
bool has_champ(const Motcle &nom) const override
DoubleTab bubbles_velocities_bary_
FixedVector< IJK_Field_vector3_double, 2 > normal_of_interf_
Parcours_interface parcours_
void calculer_phi_repuls_sommet(ArrOfDouble &potentiels_sommets, ArrOfDouble &repulsions_sommets, const DoubleTab &gravite, const double delta_rho, const double sigma, const double time, const int itstep)
double portee_wall_repulsion_
FixedVector< IJK_Field_vector3_double, 2 > barycentre_phase1_ft_
DoubleTabFT_cut_cell_vector3 indicatrice_surfacique_efficace_face_
void postraiter_colors(Sortie &os, const double current_time) const
bool read_bubbles_barycentres(const Nom &interf_name, const Nom &suffix, FixedVector< ArrOfDouble, 3 > &bubbles_bary)
void get_noms_champs_postraitables(Noms &noms, Option opt=NONE) const override
FixedVector< FixedVector< FixedVector< IJK_Field_double, 2 >, 3 >, 2 > barycentre_phase1_face_ft_
void calculer_indicatrice_surfacique_barycentre_face(IJK_Field_vector3_double &indic_surfacique_face, FixedVector< FixedVector< IJK_Field_double, 2 >, 3 > &baric_face, IJK_Field_double &indic, IJK_Field_vector3_double &norme)
int get_recompute_indicator() const
void calculer_aire_interfaciale(IJK_Field_double &ai) const
FixedVector< int, 2 > n_faces_mouilles_
void calculer_indicatrice(IJK_Field_double &indic)
void update_old_intersections()
DoubleTab bounding_box_duplicate_criteria_
void detecter_et_supprimer_rejeton(bool duplicatas_etaient_presents)
FixedVector< FixedVector< IJK_Field_double, max_authorized_nb_of_components_ >, 2 > repuls_par_compo_
void transporter_maillage_rigide(const double dt_tot, const DoubleTab &vitesses_translation_bulles, const DoubleTab &mean_bubble_rotation_vector, const DoubleTab &centre_gravite, const int rk_step, const int first_step_interface_smoothing=0)
int verbosite_surface_efficace_face_
IJK_Field_double indicatrice_avant_remaillage_ft_
ComputeValParCompoInCell val_par_compo_in_cell_computation_
int compute_cell_phase_with_interface_normal(int num_elem, int direction, int face_plus)
bool compute_distance_autres_interfaces_
FixedVector< IJK_Field_vector3_double, 2 > bary_of_interf_
FixedVector< IJK_Field_double, 2 > surface_interface_ft_
void calculer_distance_autres_compo_connexe_ijk(const DoubleTab &sommets_a_tester, const ArrOfInt &compo_connexe_sommets, const DoubleTab &vinterp_tmp, const Maillage_FT_IJK &mesh, ArrOfDouble &distance, DoubleTab &v_closer, const double distmax)
Maillage_FT_IJK maillage_ft_ijk_
static void Fill_postprocessable_fields(std::vector< FieldInfo_t > &chps)
const IJK_Field_vector3_double & get_indicatrice_surfacique_face_next() const
FixedVector< FixedVector< IJK_Field_int, max_authorized_nb_of_components_ >, 2 > compos_traversantes_
const int & nb_groups() const
FixedVector< IJK_Field_vector3_double, 2 > barycentre_phase1_ns_
IJK_Field_double indicatrice_avant_remaillage_ns_
void store_bubbles_barycentres(const Nom &interf_name)
void calculer_phi_repuls_par_compo(FixedVector< IJK_Field_double, max_authorized_nb_of_components_ > &surf_par_compo, FixedVector< FixedVector< IJK_Field_double, max_authorized_nb_of_components_ >, 3 > &source_interf_par_compo, FixedVector< IJK_Field_double, max_authorized_nb_of_components_ > &phi_par_compo, FixedVector< IJK_Field_double, max_authorized_nb_of_components_ > &repuls_par_compo, const DoubleTab &gravite, const double delta_rho, const double sigma, const double time, const int itstep)
DoubleTabFT_cut_cell_scalar surface_efficace_interface_initial_
int verbosite_surface_efficace_interface_
IJK_Field_double field_repulsion_
const IJK_Field_double & In() const
void preparer_duplicata_bulles_masque_6bit(const DoubleTab &bounding_box, const DoubleTab &authorized_bounding_box, ArrOfInt &masque_duplicata_pour_compo)
static double mean_over_compo(const FixedVector< IJK_Field_double, max_authorized_nb_of_components_ > &field_for_compo, const IJK_Field_int &nb_compo_traversante, const int i, const int j, const int k)
void calcul_surface_efficace_face_initial(TYPE_SURFACE_EFFICACE_FACE type_surface_efficace_face)
void dumplata_ft_mesh(const char *filename, const char *meshname, int step) const
void compute_external_forces_(IJK_Field_vector3_double &rappel_ft, IJK_Field_vector3_double &rappel, const IJK_Field_vector3_double &vitesse, const IJK_Field_double &indic_ns, const IJK_Field_double &indic_ft, const double coef_immo, const int tstep, const double current_time, const double coef_ammortissement, const double coef_rayon_force_rappel, double compteur, double coef_mean_force, double coef_force_time_n)
void associer_switch(const Switch_FT_double &ijk_ft_switch)
void calculer_vecteurs_de_deplacement_rigide(DoubleTab &vitesses_translation_bulles, DoubleTab &mean_bubble_rotation_vector, DoubleTab &centre_gravite, const int first_step_interface_smoothing=0)
void compute_rising_velocities_from_compo()
FixedVector< IJK_Field_vector3_double, 2 > surface_vapeur_par_face_ns_
FixedVector< IJK_Field_vector< double, max_authorized_nb_of_groups_ >, 2 > groups_indicatrice_ft_
void calcul_surface_efficace_interface_initial(TYPE_SURFACE_EFFICACE_INTERFACE type_surface_efficace_interface)
FixedVector< FixedVector< FixedVector< IJK_Field_double, max_authorized_nb_of_components_ >, 3 >, 2 > source_interf_par_compo_
FixedVector< FixedVector< IJK_Field_double, max_authorized_nb_of_components_ >, 2 > surf_par_compo_
bool use_tryggvason_interfacial_source_
DoubleTabFT_cut_cell_scalar indicatrice_surfacique_efficace_face_absolute_error_
void calcul_surface_efficace_face(TYPE_SURFACE_EFFICACE_FACE type_surface_efficace_face, double timestep, const Cut_field_vector3_double &total_velocity)
bool read_barycentres_velocity_
void switch_indicatrice_next_old()
int timestep_reprise_interface_
double get_barycentre_face(bool next_time, int face_dir, int bary_compo, int phase, int i, int j, int k) const
DoubleTab bounding_box_delete_criteria_
FixedVector< FixedVector< IJK_Field_double, max_authorized_nb_of_components_ >, 2 > courbure_par_compo_
void calculer_indicatrices_optim(IJK_Field_vector3_double &indic)
void calculer_indicatrice_surfacique_face(IJK_Field_vector3_double &indic_surfacique_face, IJK_Field_double &indic, IJK_Field_vector3_double &norme)
ArrOfDouble bubbles_velocities_bary_magnitude_
Connectivite_frontieres connectivite_frontieres_
void calculer_vmoy_rotation_composantes_connexes(const Maillage_FT_IJK &maillage, const ArrOfDouble &surface_facette, const ArrOfDouble &surface_par_bulle, const ArrOfInt &compo_connexes_facettes, const int nbulles_reelles, const int nbulles_ghost, const DoubleTab &centre_gravite, const DoubleTab &vitesse_sommets, const DoubleTab &vitesse_translation_sommets, DoubleTab &mean_bubble_rotation_vector) const
void calculer_distance_autres_compo_connexe2(ArrOfDouble &distance, DoubleTab &v_closer)
bool has_computed_bubble_barycentres_
void compute_compo_connex_from_interface()
Intersection_Interface_ijk_cell intersection_ijk_cell_
bool has_champ_vectoriel(const Motcle &nom) const override
void parcourir_maillage()
void calculer_indicatrice_intermediaire(IJK_Field_double &indicatrice_intermediaire_ft_, IJK_Field_double &indicatrice_intermediaire_ns_, IJK_Field_vector3_double &indicatrice_surfacique_intermediaire_face_ft_, IJK_Field_vector3_double &indicatrice_surfacique_intermediaire_face_ns_, const bool parcourir=true)
void calculer_aspect_ratio(ArrOfDouble &aspect_ratio) const
bool correction_gradient_potentiel_
static int est_pure(double indicatrice)
double get_barycentre(bool next_time, int bary_compo, int phase, int i, int j, int k) const
void calcul_surface_efficace_interface(TYPE_SURFACE_EFFICACE_INTERFACE type_surface_efficace_interface, double timestep, const Cut_field_vector3_double &velocity)
void compute_external_forces_color_function(IJK_Field_vector3_double &rappel, const IJK_Field_double &indic_ns, const IJK_Field_double &indic_ft, DoubleTab &individual_forces, const ArrOfDouble &volume_reel, const DoubleTab &position)
DoubleTab force_time_n_
Intersection_Interface_ijk_face intersection_ijk_face_
FixedVector< IJK_Field_vector3_double, 2 > surface_vapeur_par_face_
void update_surface_normale() const
IJK_Field_double indicatrice_apres_remaillage_ns_
void calculer_bounding_box_bulles(DoubleTab &bounding_box, int option_shear=0) const
void remailler_interface(const double temps, Maillage_FT_IJK &maillage, ArrOfDouble &var_volume, Remaillage_FT_IJK &algo_remaillage_local)
void calculer_poussee_bulles(const DoubleTab &gravite, DoubleTab &poussee) const
const IJK_Field_double & get_IJK_field(const Motcle &nom) override
double delta_p_max_repulsion_
FixedVector< FixedVector< IJK_Field_vector3_double, 3 >, 2 > barycentre_vapeur_par_face_
void recursive_calcul_distance_chez_voisin(DoubleTab &vinterp_tmp, int dir, const Maillage_FT_IJK &mesh, DoubleTab &coord_sommets, ArrOfInt &compo_sommet, ArrOfDouble &distance, DoubleTab &v_closer, double distmax)
void supprimer_duplicata_bulles()
DoubleTab bubbles_rising_vectors_bary_
void calculer_volume_bulles(ArrOfDouble &volumes, DoubleTab &centre_gravite) const
FixedVector< IJK_Field_vector3_double, 2 > normal_of_interf_ns_
ArrOfInt through_yminus_
DoubleTab bounding_box_forbidden_criteria_
void compute_bubbles_volume_and_barycentres(ArrOfDouble &volumes, DoubleTab &barycentres, const int &store_values)
void compute_drapeaux_vapeur_v4(const IntVect &vecteur_composantes, ArrOfInt &drapeau_vapeur) const
IJK_Field_double delta_volume_theorique_bilan_ns_
IJK_Field_vector3_double indicatrice_surfacique_efficace_deformation_face_
IJK_Field_vector3_double indicatrice_surfacique_avant_remaillage_face_ns_
void compute_external_forces_parser(IJK_Field_vector3_double &rappel, const IJK_Field_double &indic_ns, const DoubleTab &individual_forces, const ArrOfDouble &volume_reel, const DoubleTab &position, const double coef_rayon_force_rappel)
FixedVector< IJK_Field_double, 2 > indicatrice_ft_
IJK_Field_vector3_double indicatrice_surfacique_apres_remaillage_face_ns_
void imprime_bilan_indicatrice()
void calculer_distance_autres_compo_connexe_octree(const DoubleTab &sommets_a_tester, const ArrOfInt &compo_connexe_sommets, const DoubleTab &vinterp_tmp, const Maillage_FT_IJK &mesh, ArrOfDouble &distance, DoubleTab &v_closer, const double distmax)
void read_bubbles_barycentres_old_new(const Nom &interf_name)
FixedVector< IJK_Field_vector< double, max_authorized_nb_of_groups_ >, 2 > groups_indicatrice_ns_
const IJK_Field_vector3_double & get_IJK_field_vector(const Motcle &nom) override
double delta_p_wall_max_repulsion_
Maillage_FT_IJK old_maillage_ft_ijk_
int update_indicatrice(IJK_Field_double &indic)
DoubleTabFT_cut_cell_vector3 coord_deplacement_interface_
void set_recompute_indicator(int i)
FixedVector< FixedVector< IJK_Field_vector3_double, 3 >, 2 > barycentre_vapeur_par_face_ns_
void sauvegarder_interfaces(const char *lata_name, const Nom &interf_name="??")
void calculer_indicatrice_next(const DoubleTab &gravite, const double delta_rho, const double sigma, const double time, const int itstep, const bool parcourir=true)
void calculer_normales_et_aires_interfaciales(IJK_Field_double &ai, IJK_Field_double &kappa_ai, IJK_Field_vector3_double &normale_cell, const int igroup) const
void calculer_surface_bulles(ArrOfDouble &surfaces) const
IJK_Field_vector3_double indicatrice_surfacique_apres_remaillage_face_ft_
DoubleTabFT_cut_cell_vector3 normale_deplacement_interface_
DoubleTab bounding_box_NS_domain_
DoubleTabFT_cut_cell_vector6 indicatrice_surfacique_efficace_face_correction_
: class Intersections_Elem_Facettes
const ArrOfInt & index_elem() const
Renvoie un tableau de taille domaine.
const ArrOfInt & index_facette() const
Renvoie un tableau de taille "nombre de facettes de l'interface" pour un element 0 <= facette < nb_fa...
const Intersections_Elem_Facettes_Data & data_intersection(int index) const
Renvoie les donnees de l'intersection stockee a l'indice "index" dans le tableau "data" ( 0 <= index ...
void get_liste_facettes_traversantes(int num_element, ArrOfInt &liste_facettes) const
: class Maillage_FT_Disc Cette classe decrit un maillage:
void preparer_tableau_avant_transport(ArrOfDouble &tableau, const Desc_Structure_FT &descripteur) const
Prepare un tableau de donnees aux sommets ou aux facettes pour conserver les valeurs apres transport.
const ArrOfInt & sommet_num_owner() const
pour postraitement, renvoie le numero des sommets sur le PE proprietaire des sommets
int nb_sommets() const
renvoie le nombre de sommets (reels et virtuels) (egal a sommets().
const DoubleTab & sommets() const
renvoie le tableau des sommets (reels et virtuels) dimension(0) = nombre de sommets,
void update_tableau_apres_transport(ArrOfDouble &tableau, int nb_elements, const Desc_Structure_FT &descripteur) const
Voir preparer_tableau_avant_transport.
int nb_facettes() const
renvoie le nombre de facettes (reelles et virtuelles) (egal a facettes().
int facette_virtuelle(int i) const
Renvoie 0 si la facette m'appartient, 1 sinon.
const Desc_Structure_FT & desc_sommets() const
renvoie le descripteur des sommets (espace_distant/virtuel)
virtual const DoubleTab & get_update_normale_facettes() const
Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le re...
void facette_PE_owner(ArrOfInt &facette_pe) const
pour postraitement, remplit le tableau en parametre avec le numero du PE proprietaire de chaque facet...
int sommet_virtuel(int i) const
const ArrOfInt & sommet_PE_owner() const
pour postraitement, renvoie le numero du PE proprietaire des sommets
const Intersections_Elem_Facettes & intersections_elem_facettes() const
virtual const ArrOfDouble & get_update_surface_facettes() const
Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le re...
virtual const ArrOfDouble & get_update_courbure_sommets() const
Calcule la grandeur demandee, stocke le resultat dans un tableau interne a la classe et renvoie le re...
const IntTab & facettes() const
renvoie le tableau des facettes (reelles et virtuelles) dimension(0) = nombre de facettes,
: class Maillage_FT_IJK
const ArrOfInt & compo_connexe_facettes() const
FT_Field & Surfactant_facettes_non_const()
const Domaine_IJK & get_domaine() const
DoubleTab update_sigma_and_interfacial_source_term_sommet(const Domaine_IJK &splitting, bool compute_interfacial_source, bool use_tryggvason_formulation, const double sigma_const=-1.)
const FT_Field & Surfactant_facettes() const
void transporter(const DoubleTab &deplacement) override
Deplace les sommets de l'interface d'un vecteur "deplacement" fourni, Change eventuellement les somme...
void nettoyer_maillage() override
Retire toutes les facettes virtuelles, toutes les facettes invalides (sommet0 == sommet1) et tous les...
void recopie(const Maillage_FT_Disc &source_mesh, Statut_Maillage niveau_copie) override
Recopie une partie du maillage source dans *this.
void update_gradient_laplacien_Surfactant()
void ajouter_maillage_IJK(const Maillage_FT_IJK &added_mesh)
void supprimer_facettes(const ArrOfInt &liste_facettes)
double minimum_longueur_arrete() const
void calculer_compo_connexe_sommets(ArrOfIntFT &compo_connexe_sommets) const
void initialize(const Domaine_IJK &, const Domaine_dis_base &, const Parcours_interface &, const bool use_tryggvason_interfacial_source=false)
void set_composante_connexe(const int i_facette, const int icompo)
classe Milieu_base Cette classe est la base de la hierarchie des milieux (physiques)
Definition Milieu_base.h:50
Une chaine de caractere (Nom) en majuscules.
Definition Motcle.h:26
Un tableau d'objets de la classe Motcle.
Definition Motcle.h:63
int contient_(const char *const ch) const
Definition Motcle.cpp:333
void get_redistribute_from_splitting_ft_faces(const IJK_Field_vector3_double &faces_ft, IJK_Field_vector3_double &faces_ns)
Redistribute_Field & redistrib_from_ft_elem()
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
Un tableau de chaine de caracteres (VECT(Nom)).
Definition Noms.h:26
friend class Entree
Definition Objet_U.h:76
friend class Sortie
Definition Objet_U.h:75
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
static const Nom & nom_du_cas()
Renvoie une reference constante vers le nom du cas.
Definition Objet_U.cpp:146
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
int_t search_elements_box(double xmin, double ymin, double zmin, double xmax, double ymax, double zmax, ArrOfInt_t &elements) const
cherche tous les elements ou points ayant potentiellement une intersection non vide avec la boite don...
void build_elements(const _TAB_TYPE_ &coords, const IntTab_t &elements, const double epsilon, const bool include_virtual)
Construit un octree a partir d'elements volumiques decrits par des ensembles de sommets.
static bool DISABLE_DIPHASIQUE
Definition Option_IJK.h:26
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
@ REQUIRED
Definition Param.h:115
const Cut_field_vector3_double & get_cut_field_velocity() const
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Probleme_U.h:109
classe Probleme_base C'est un Probleme_U qui n'est pas un couplage.
static void mp_max_for_each_item(TRUSTArray< _TYPE_ > &x, int n=-1)
Definition Process.cpp:196
static double mp_min(double)
Definition Process.cpp:386
static int check_int_overflow(trustIdType)
Definition Process.cpp:428
static void mp_sum_for_each(T &arg1, T &arg2)
C++14 compatible mp_sum_for_each: combine multiple mp_sum calls into one collective operation Usage: ...
Definition Process.cpp:207
static trustIdType mppartial_sum(trustIdType i)
Calul de la somme partielle de i sur les processeurs 0 a me()-1 (renvoie 0 sur le processeur 0).
Definition Process.cpp:396
static double mp_max(double)
Definition Process.cpp:376
static void mp_sum_for_each_item(TRUSTArray< _TYPE_ > &x, int n=-1)
Definition Process.cpp:193
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
static double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
static void mp_min_for_each(T &arg1, T &arg2)
C++14 compatible mp_min_for_each: combine multiple mp_min calls into one collective operation.
Definition Process.cpp:281
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
Definition Process.cpp:86
static void mp_min_for_each_item(TRUSTArray< _TYPE_ > &x, int n=-1)
Definition Process.cpp:199
void redistribute(const IJK_Field_double &input_field, IJK_Field_double &output_field)
void remaillage_local_interface(double temps, Maillage_FT_IJK &maillage)
void barycentrer_lisser_systematique_ijk(Maillage_FT_IJK &maillage, ArrOfDouble &var_volume)
int a_remailler(double temps, const Maillage_FT_Disc &maillage) const
Cette classe derivee de Sortie empile ce qu'on lui envoie dans une chaine de caracteres.
Definition SChaine.h:26
const char * get_str() const
returns a copy of the string stored by the SChaine
Definition SChaine.cpp:72
Cette classe est a la classe C++ ofstream ce que la classe Sortie est a la classe C++ ostream Elle re...
Definition SFichier.h:27
void echange_taille_et_messages() const
Cette methode lance l'echange de donnees entre tous les processeurs.
Sortie & send_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y entasser des donnees a envoyer.
void end_comm() const
Vide les buffers et libere les ressources: on a fini de lire les donnees recues dans les buffers.
Entree & recv_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y lire les donnees recues.
void begin_comm() const
Reserve les buffers de comm pour une nouvelle communication.
void set_send_recv_pe_list(const ArrOfInt &send_pe_list, const ArrOfInt &recv_pe_list, const int me_to_me=0)
Definit la liste des processeurs a qui on va envoyer et de qui on va recevoir des donnees.
virtual int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::out)
Classe de base des flux de sortie.
Definition Sortie.h:52
virtual void reset()
Definition TRUSTArray.h:240
void append_array(_TYPE_ valeur)
_SIZE_ size_array() const
_TYPE_ * addr()
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 resize(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTArray.h:156
void reset() override
Definition TRUSTTab.tpp:362
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
void append_line(_TYPE_)
Definition TRUSTTab.tpp:213
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")
static void transfert_conservatif_eulerien_vers_lagrangien_sommets(const Maillage_FT_Disc &maillage, const DoubleVect &valeurs_euler, ArrOfDouble &valeurs_lagrange)
static double produit_scalaire(const Vecteur3 &x, const Vecteur3 &y)
static void produit_vectoriel(const Vecteur3 &x, const Vecteur3 &y, Vecteur3 &resu)