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