TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Convection_Diffusion_Temperature_FT_Disc.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#include <Convection_Diffusion_Temperature_FT_Disc.h>
16#include <Transport_Interfaces_FT_Disc.h>
17#include <Domaine_VF.h>
18#include <Discretisation_base.h>
19#include <Probleme_FT_Disc_gen.h>
20#include <Fluide_Diphasique.h>
21#include <Fluide_Incompressible.h>
22#include <Domaine.h>
23#include <Sous_Domaine.h>
24#include <Param.h>
25#include <Champ_Uniforme.h>
26#include <Echange_impose_base.h>
27#include <Echange_contact_VDF_FT_Disc.h>
28#include <Domaine_Cl_VDF.h>
29#include <Neumann_paroi.h>
30#include <Neumann_paroi_adiabatique.h>
31#include <SChaine.h>
32#include <Entree.h>
33#include <EChaine.h>
34#include <Interprete_bloc.h>
35#include <Domaine_VDF.h>
36#include <Perf_counters.h>
37#include <TRUST_Ref.h>
38#include <Parametre_implicite.h>
39#include <Dirichlet_paroi_fixe.h>
40#include <Dirichlet_paroi_defilante.h>
41
42static const double TSAT_CONSTANTE = 0.;
43
44// XD convection_diffusion_temperature_ft_disc convection_diffusion_temperature convection_diffusion_temperature_ft_disc INHERITS_BRACE not_set
45Implemente_instanciable_sans_constructeur(Convection_Diffusion_Temperature_FT_Disc,"Convection_Diffusion_Temperature_FT_Disc",Convection_Diffusion_Temperature);
46
48{
49 phase_ = -1;
50 correction_courbure_ordre_=0; // Par defaut, pas de prise en compte de la courbure pour corriger le champ etendu delta_vitesse
51 correction_gradt_ordre_=1; // Par defaut, temperature gradient is computed in ordre 1
52 stencil_width_ = 8; //GB : Valeur par defaut de stencil_width_
53 temp_moy_ini_ = 0.; //GB : Valeur par defaut de la temperature moyenne initiale
54 nom_sous_domaine_ = "unknown_sous_domaine"; //GB : Valeur par defaut de la sous-domaine de moyenne
55 prescribed_mpoint_ = -1.e30;
56 mixed_elems_.resize_array(0);
57 lost_fluxes_.resize_array(0);
58 derivee_energy_.resize_array(0);
59 mixed_elems_diffu_.resize_array(0);
60 lost_fluxes_diffu_.resize_array(0);
61 mixed_elems_conv_.resize_array(0);
62 lost_fluxes_conv_.resize_array(0);
63}
64
66{
68}
69/*! @brief cf Convection_Diffusion_std::readOn(Entree&).
70 *
71 */
73{
74 // Ne pas faire assert(fluide non nul)
76 solveur_masse->set_name_of_coefficient_temporel("rho_cp_comme_T");
77 Nom num=inconnue().le_nom(); // On prevoir le cas d'equation de scalaires passifs
78 num.suffix("temperature_thermique");
79 Nom nom="Convection_chaleur";
80 nom+=num;
81 terme_convectif.set_fichier(nom);
82 terme_convectif.set_description((Nom)"Convective heat transfer rate=Integral(-rho*cp*T*u*ndS) [W] if SI units used");
83 nom="Diffusion_chaleur";
84 nom+=num;
85 terme_diffusif.set_fichier(nom);
86 terme_diffusif.set_description((Nom)"Conduction heat transfer rate=Integral(lambda*grad(T)*ndS) [W] if SI units used");
87
88 // If keyword correction_mpoint_diff_conv_energy_ has not been read, the table should be properly set:
89 if (correction_mpoint_diff_conv_energy_.size_array() != 3)
90 {
91 Cerr << "We account for no energy correction!!" << finl;
96 }
97 return is;
98}
99
101{
103 param.ajouter("phase",&phase_); // XD_ADD_P entier(into=[0,1])
104 // XD_CONT Phase in which the temperature equation will be solved. The temperature, which may be postprocessed with
105 // XD_CONT the keyword temperature_EquationName, in the orther phase may be negative: the code only computes the
106 // XD_CONT temperature field in the specified phase. The other phase is supposed to physically stay at saturation
107 // XD_CONT temperature. The code uses a ghost fluid numerical method to work on a smooth temperature field at the
108 // XD_CONT interface. In the opposite phase (1-X) the temperature will therefore be extrapolated in the vicinity of
109 // XD_CONT the interface and have the opposite sign, saturation temperature is zero by convention).
110 param.ajouter_condition("(value_of_phase_eq_0)_or_(value_of_phase_eq_1)","phase must be set to 0 or 1");
111 param.ajouter("stencil_width",&stencil_width_); // XD_ADD_P entier
112 // XD_CONT distance in mesh elements over which the temperature field should be extrapolated in the opposite phase.
113 param.ajouter("correction_courbure_ordre", &correction_courbure_ordre_); // XD_ADD_P entier Order of the curvature correction for the temperature gradient.
114 param.ajouter("correction_gradt_ordre", &correction_gradt_ordre_); // XD_ADD_P entier
115 // XD_CONT not_set
116 param.ajouter_non_std("equation_interface",(this),Param::REQUIRED); // XD_ADD_P chaine
117 // XD_CONT The name of the interface equation should be given.
118 param.ajouter_non_std("maintien_temperature",(this)); // XD_ADD_P objet_lecture_maintien_temperature
119 // XD_CONT maintien_temperature SOUS_ZONE_NAME VALUE : experimental, this acts as a dynamic source term that heats or
120 // XD_CONT cools the fluid to maintain the average temperature to VALUE within the specified region. At this time,
121 // XD_CONT this is done by multiplying the temperature within the SOUS_ZONE by an appropriate uniform value at each
122 // XD_CONT timestep. This feature might be implemented in a separate source term in the future.
123 param.ajouter_non_std("equation_navier_stokes",(this),Param::REQUIRED); // XD_ADD_P chaine
124 // XD_CONT The name of the Navier Stokes equation of the problem should be given.
125 param.ajouter_non_std("prescribed_mpoint", (this)); // XD_ADD_P floattant
126 // XD_CONT User defined value of the phase-change rate (override the value computed based on the temperature field)
127 param.ajouter("correction_mpoint_diff_conv_energy", &correction_mpoint_diff_conv_energy_); // XD_ADD_P list
128 // XD_CONT not_set
129 param.ajouter_flag("divergence_free_velocity_extension", &divergence_free_velocity_extension_); // XD_ADD_P rien
130 // XD_CONT not_set
131 param.ajouter_flag("explicit_u_NS", &explicit_u_NS_); // X_D_ADD_P rien Flag to force a really explicit scheme
132 param.ajouter_non_std("solveur_pression_fictive",(this),Param::OPTIONAL); // XD_ADD_P solveur_sys_base
133 // XD_CONT not_set
134 param.ajouter("bc_opening_pressure",&name_bc_opening_pressure_,Param::OPTIONAL); // XD_ADD_P listchaine
135 // XD_CONT not_set
136 param.ajouter_flag("reinjection_tcl", &reinjection_); // XD_ADD_P rien Enable triple-contact-line (TCL) reinjection.
137 param.ajouter("tempC", &tempC_); // XD_ADD_P floattant Contact temperature for the TCL reinjection model.
138 param.ajouter("Rc_inject", &Rc_inject_); // XD_ADD_P floattant Injection radius for the TCL reinjection model.
139 param.ajouter("thetaC", &thetaC_); // XD_ADD_P floattant Contact angle for the TCL reinjection model.
140 param.ajouter("Rc_GridN", &Rc_GridN_); // XD_ADD_P entier Number of grid cells used by the TCL reinjection model.
141}
142
144{
145 if (mot=="equation_interface")
146 {
147 const Probleme_FT_Disc_gen& pb = ref_cast(Probleme_FT_Disc_gen,probleme());
148 Motcle nom_eq;
149 is >> nom_eq;
151 Cerr << " Interface equation for the temperature convection diffusion equation :"
152 << nom_eq << finl;
153 ref_eq_interface_ = pb.equation_interfaces(nom_eq);
154 return 1;
155 }
156 else if (mot=="solveur_pression_fictive")
157 {
159 Cerr << "Reading and typing of fictitious pressure solver (for velocity extension) : " << finl;
160 is >> solveur_pression_;
161 Cerr<<"Fake Pressure solver type : "<<solveur_pression_->que_suis_je()<< finl;
162 solveur_pression_.nommer("solveur_pression_fictive");
163 return 1;
164 }
165 else if (mot=="diffusion")
166 {
167 if (je_suis_maitre())
168 Cerr << " "<< que_suis_je() <<"::lire diffusivite" << finl;
169 // Need phase to know which diffusivity to use:
170 if (phase_ < 0)
171 {
172 barrier();
173 Cerr << " Error: phase must be specified before diffusion" << finl;
175 }
177 return 1;
178 }
179 else if (mot=="convection")
180 {
181 if (je_suis_maitre())
182 Cerr << " "<< que_suis_je() <<"::lire convection" << finl;
183 if (!ref_eq_ns_)
184 {
185 barrier();
186 Cerr << " Error: equation_navier_stokes must be specified before convection" << finl;
188 }
190 return 1;
191 }
192 else if (mot=="maintien_temperature")
193 {
194 if (je_suis_maitre())
195 Cerr << " Equation_Concentration_FT::lire maintien_temperature" << finl;
197 is >> nom_sous_domaine_;
198 is >> temp_moy_ini_;
199 return 1;
200 }
201 else if (mot=="prescribed_mpoint")
202 {
203 if (je_suis_maitre())
204 Cerr << que_suis_je() <<"::lire prescribed_mpoint" << finl;
205 is_prescribed_mpoint_ = true; // set flag to true.
206 is >> prescribed_mpoint_;
207 return 1;
208 }
209 else if (mot=="equation_navier_stokes")
210 {
211 const Probleme_FT_Disc_gen& pb = ref_cast(Probleme_FT_Disc_gen,probleme());
212 Motcle nom_eq;
213 is >> nom_eq;
215 Cerr << " Navier_stokes equation for the temperature convection diffusion equation :"
216 << nom_eq << finl;
217 const Navier_Stokes_std& ns = pb.equation_hydraulique(nom_eq);
218 ref_eq_ns_ = ns;
219 return 1;
220 }
221 else
223}
224
226{
227 // return ref_eq_ns_->vitesse();
228 // GB 2019.03.07 (code lost between 2022.02.16 and 2023.06.20!!)
229 // We will go through all the effort of creating a continous velocity from the unknown of NS!
230 // We might as well use it! ;-)
231 return vitesse_convection_;
232}
233
237
242
246
247static void extrapolate(const Domaine_VF& domaine_vf,
248 const DoubleTab& interfacial_area,
249 const int stencil_width,
250 const DoubleTab& distance,
251 DoubleTab& field)
252{
253 const double invalid_test = -1.e30;
254 const IntTab& elem_faces = domaine_vf.elem_faces();
255 const IntTab& faces_elem = domaine_vf.face_voisins();
256 const int nb_faces_elem = elem_faces.dimension(1);
257 const int nb_elem = elem_faces.dimension(0);
258 DoubleTab field_old;
259 // n_iterations = stencil_width is the minimum to get a propagation of information from the interface to the border
260 // of the extrapolation. But doing more will lead to smoother values... And it probably costs close to nothing
261 const double n_iterations = 5*stencil_width;
262 for (int iteration = 0; iteration < n_iterations; iteration++)
263 {
264 // Copy the old field value as we do not want to use the current iteration values.
265 field_old = field;
266 // La valeur sur un element est la moyenne des valeurs sur les elements voisins
267 for (int i_elem = 0; i_elem < nb_elem; i_elem++)
268 {
269 // Do not touch field in interfacial cells.
270 // Iterate on other values.
271 const double d = distance[i_elem];
272 if (( d > invalid_test) && (interfacial_area[i_elem]<DMINFLOAT))
273 {
274 double somme = 0.;
275 double coeff = 0.;
276 for (int i_face = 0; i_face < nb_faces_elem; i_face++)
277 {
278 const int face = elem_faces(i_elem, i_face);
279 const int voisin = faces_elem(face, 0) + faces_elem(face, 1) - i_elem;
280 if (voisin >= 0)
281 {
282 // Not a boundary...
283 double mp = field_old[voisin];
284 const double dvois = distance[voisin];
285 if (dvois > invalid_test)
286 {
287 // Give more weight in the smoothing to values closer to the interface:
288 if (fabs(dvois)<DMINFLOAT)
289 {
290 Cerr << "distance is very much at zero whereas interfacial_area is zero too... Pathological case to be looked into closely. " << finl;
291 Cerr << "Is it from a Break-up or coalescence? " << finl;
292 Cerr << "see Convection_Diffusion_Temperature_FT_Disc and static void extrapolate" << finl;
293 Cerr << "Contact TRUST support." << finl;
295 }
296 const double inv_d2 = 1./(dvois*dvois);
297 somme += mp*inv_d2;
298 coeff+=inv_d2;
299 }
300 }
301 }
302 if (coeff > 0.)
303 field[i_elem] = somme / coeff;
304 }
305 }
307 }
308}
309
310static void extrapoler_dans_phase(DoubleTab& gradient,
311 const DoubleTab& indicatrice,
312 const Domaine_VF& domaine_vf,
313 const double invalid_test,
314 const double indic_phase, const int nb_iter)
315{
316 DoubleTab gradient_old;
317 for (int iteration = 0; iteration < nb_iter; iteration++)
318 {
319 // Copie de la valeur du gradient: on ne veut pas utiliser les valeurs
320 // calculees lors de l'iteration courante
321 gradient_old = gradient;
322 // La valeur sur un element est la moyenne des valeurs sur les elements voisins
323 for (int i_elem = 0; i_elem < domaine_vf.elem_faces().dimension(0); i_elem++)
324 {
325 if (indicatrice[i_elem] != indic_phase)
326 {
327 // Ne pas toucher au gradient de la phase "phase".
328 // Iterer sur les autres valeurs.
329 double somme = 0.;
330 int coeff = 0;
331 for (int i_face = 0; i_face < domaine_vf.elem_faces().dimension(1); i_face++)
332 {
333 const int face = domaine_vf.elem_faces(i_elem, i_face);
334 const int voisin = domaine_vf.face_voisins(face, 0) + domaine_vf.face_voisins(face, 1) - i_elem;
335 if (voisin >= 0)
336 {
337 // Not a boundary...
338 const double grad = gradient_old[voisin];
339 if (grad > invalid_test)
340 {
341 somme += grad;
342 coeff++;
343 }
344 }
345 }
346 if (coeff > 0)
347 gradient[i_elem] = somme / coeff;
348 }
349 }
350 gradient.echange_espace_virtuel();
351 }
352}
353// A partir des valeurs du "champ" dans la phase "phase", calcule
354// les valeurs du "champ" dans un voisinage d'epaisseur "stencil_width"
355// en extrapolant lineairement et en supposant que la valeur a l'interface
356// vaut "interfacial_value".
357static void extrapoler_champ_elem(const Domaine_VF& domaine_vf,
358 const DoubleTab& indicatrice,
359 const DoubleTab& distance_interface,
360 const DoubleTab& normale_interface,
361 const DoubleTab& champ_div_n,
362 const int correction_gradt_ordre_,
363 const int phase,
364 const int stencil_width,
365 const double interfacial_value,
366 DoubleTab& champ,
367 DoubleTab& gradient,
368 const double temps)
369{
370 const IntTab& elem_faces = domaine_vf.elem_faces();
371 //const IntTab& faces_elem = domaine_vf.face_voisins();
372 const int nb_faces_elem = elem_faces.dimension(1);
373 const int nb_elem = elem_faces.dimension(0);
374
375 const DoubleTab& centre_gravite_elem = domaine_vf.xp();
376 const DoubleTab& centre_gravite_face = domaine_vf.xv();
377 const double invalid_test = -1.e30;
378 const double invalid_value = -2.e30;
379 // Calcul de la composante normale du gradient du champ:
380 // gradient normal = (champ - valeur_interface) / distance.
381 assert(gradient.dimension(0) == distance_interface.dimension(0));
382 gradient = invalid_value;
383 const double indic_phase = (phase == 0) ? 0. : 1.;
384 int i_elem;
385 int err_count = 0;
386 for (i_elem = 0; i_elem < nb_elem; i_elem++)
387 {
388 double d = distance_interface[i_elem];
389 if (indicatrice[i_elem] == indic_phase && d > invalid_test)
390 {
391
392 // Test pour remedier a une eventuelle erreur de calcul de la
393 // fonction distance dans les mailles voisines des mailles traversees
394 // par l'interface. On sait que la distance est superieure a delta_x/2
395 // A faire: calculer distance_min = delta_x/2
396 // if (std::fabs(d) < distance_min) {
397 // d = (d>0) ? distance_min : -distance_min;
398 // err_count++;
399 // }
400
401 // Test pour savoir si la distance a l'interface est bien inferieure
402 // au rayon du cercle inscrit a l'element
403 // Si c'est le cas, on remplace la distance par plus ou moins ce rayon
404 // suivant la phase dans laquelle se situe l'element
405 double dist_elem_face_min = 1e30;
406 for (int face_loc=0; face_loc<nb_faces_elem; face_loc++)
407 {
408 double dist_elem_face = 0;
409 const int face_glob = elem_faces(i_elem,face_loc);
410 for (int i_dim=0; i_dim<Objet_U::dimension; i_dim++)
411 {
412 double centre_elem_i = centre_gravite_elem(i_elem,i_dim);
413 double centre_face_i = centre_gravite_face(face_glob,i_dim);
414 dist_elem_face += (centre_elem_i-centre_face_i)*(centre_elem_i-centre_face_i);
415 }
416 dist_elem_face = sqrt(dist_elem_face);
417 dist_elem_face_min = (dist_elem_face < dist_elem_face_min) ? dist_elem_face : dist_elem_face_min;
418 }
419
420 // Codage initial valable uniquement pour une discretisation VDF
421 // double dx = domaine_vf.volumes(i_elem)/domaine_vf.face_surfaces(elem_faces(i_elem,0));
422 // double dy = domaine_vf.volumes(i_elem)/domaine_vf.face_surfaces(elem_faces(i_elem,1));
423 // double dz = domaine_vf.volumes(i_elem)/domaine_vf.face_surfaces(elem_faces(i_elem,2));
424 // double dist_elem_face_min = ( ((dx<dy) ? dx : dy)<dz ? ((dx<dy) ? dx : dy) : dz )/2;
425
426 // Si la distance entre le centre de l'element et l'interface est plus petite
427 // que la plus petite distance entre le centre de l'element et le centre de ses faces
428 // on ecrase la valeur de la distance a l'interface qui est manifestement fausse.
429 // On choisit par defaut la plus petite distance entre le centre de l'element et le
430 // centre de ses faces. Le signe de la distance est determine en fonction de la phase
431 // de l'element (la distance etant fausse, son signe a toutes les chances de l'etre
432 // aussi).
433 if (std::fabs(d) < dist_elem_face_min)
434 {
435 Cerr << "Time = " << temps << "; extrapoler_champ_elem: distance lower than dx/2" << finl;
436 Cerr << " Element position:" << finl;
437 for (int i_dim=0; i_dim<Objet_U::dimension; i_dim++)
438 {
439 Cerr << " x(" << i_dim << ") = " << centre_gravite_elem(i_elem,i_dim) << finl;
440 }
441
442 d = (phase == 0) ? -dist_elem_face_min : dist_elem_face_min;
443
444 err_count++;
445 }
446 const double v = champ[i_elem];
447 // Ceci est le gradient evalue a une distance d/2 de l'interface
448 // (difference finie centree)
449 const double grad = (v - interfacial_value) / d;
450 // Correction du gradient pour trouver la valeur a l'interface :
451 // on suppose que le transfert est stationnaire, et flux normal
452 // a l'interface.
453 const double div_n = champ_div_n[i_elem];
454
455 switch (correction_gradt_ordre_)
456 {
457 case 0:
458 // Pas de prise en compte de la correction en courbure
459 gradient[i_elem] = grad;
460 break;
461 case 1:
462 // note that div_n and k are in opposite sign
463 gradient[i_elem] = grad * (1. - (-div_n) * d / 2.);
464 break;
465 case 2:
466 // Prise en compte de la correction en courbure a l'ordre 2
467 gradient[i_elem] = grad * (1. - (-div_n) * d / 2. + (-div_n) * (-div_n) * d * d / 6.);
468 break;
469 default:
470 Cerr << "Error for the method Convection_Diffusion_Temperature_FT_Disc::extrapoler_champ_elem correction_gradt_ordre_" << finl;
472 }
473 }
474 }
475 if (err_count)
476 Cerr << "extrapoler_champ_elem: errcount=" << err_count << finl;
477 gradient.echange_espace_virtuel();
478 // On etale ce gradient par continuite sur une epaisseur de "stencil_value"
479 // Les iterations de cet algorithme convergent vers une sorte de laplacien=0
480 // avec condition aux limites de Dirichlet sur les elements de la phase "phase".
481 extrapoler_dans_phase(gradient, indicatrice, domaine_vf, invalid_test, indic_phase, stencil_width/* nb_iter*/ );
482
483 // 2023. Pour la vitesse de convection extrapolee, on reextrapole dans l'autre phase :
484 const double autre_phase = 1.-indic_phase;
485 extrapoler_dans_phase(gradient, indicatrice, domaine_vf, invalid_test, autre_phase, stencil_width/* nb_iter*/ );
486
487 // On calcule la valeur extrapolee:
488 for (i_elem = 0; i_elem < nb_elem; i_elem++)
489 {
490 const double d = distance_interface[i_elem];
491 const double grad = gradient[i_elem];
492 if (indicatrice[i_elem] != indic_phase
493 && d > invalid_test
494 && grad > invalid_test)
495 {
496 // Extrapolation parabolique tenant compte de la courbure de l'interface :
497 const double div_n = champ_div_n[i_elem];
498 champ[i_elem] = d * grad * (1. - 0.5 * div_n * d) + interfacial_value;
499 // TODO: Assess Higher order Taylor series by the inclusion of a new parameter in the datafile. (Formulae below to be checked)
500 // champ[i_elem] = 0.5 * d * grad * (1. - 0.5 * div_n * d) + interfacial_value; // multiplied by 0.5 (may be it was missing...we have to check)
501 // champ[i_elem] = d * grad * (1. - 0.5 * div_n * d + div_n * div_n * d * d / 6.) + interfacial_value;
502 }
503 }
504 champ.echange_espace_virtuel();
505}
506
507/*! @brief met a jour le champ grad_t en fonction du champ inconnue.
508 *
509 * Attention, l'inconnue est modifiee (on etend le champ de temperature dans la phase
510 * opposee.
511 *
512 */
514{
515 Transport_Interfaces_FT_Disc& eq_interface_ = ref_eq_interface_.valeur();
516 const DoubleTab& indicatrice = eq_interface_.get_indicatrice().valeurs();
517 const DoubleTab& distance_interface = eq_interface_.get_distance_interface().valeurs();
518 const DoubleTab& normale_interface = eq_interface_.get_normale_interface().valeurs();
519 //GB : Augmenter la constante de l'epaisseur
520 //GB : const int stencil_width = 8;
521 const int stencil_width = stencil_width_;
522 const double interfacial_value = TSAT_CONSTANTE;
523
524 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis());
525
526 const double temps = schema_temps().temps_courant();
527
528 // Extrapolation lineaire de la temperature des mailles diphasiques a partir
529 // de la temperature des mailles de la "phase".
530 DoubleTab& temperature = inconnue().valeurs();
531
532 Navier_Stokes_FT_Disc& eq_navier_stokes = ref_cast(Navier_Stokes_FT_Disc, ref_eq_ns_.valeur());
533 const DoubleTab& div_n = eq_navier_stokes.calculer_div_normale_interface().valeurs();
534
535 extrapoler_champ_elem(domaine_vf, indicatrice, distance_interface, normale_interface, div_n,
537 phase_, stencil_width, interfacial_value,
538 temperature,
539 grad_t_->valeurs(),
540 temps);
541}
542
547
549{
550 const double invalid_test = -1.e25;
552
554 {
555 mpoint.valeurs() = prescribed_mpoint_;
556 return;
557 }
558 mpoint.valeurs() = grad_t_->valeurs();
559
560 DoubleTab& val = mpoint.valeurs();
561 const int n = val.size();
562 for (int i = 0; i < n; i++)
563 if (val[i] < invalid_test)
564 val[i] = 0;
565
566 const double k = fluide_dipha_->fluide_phase(phase_).conductivite().valeurs()(0,0);
567 const double L = fluide_dipha_->chaleur_latente();
568 // L est la chaleur latente de changement de phase pour passer de
569 // la phase 0 a la phase 1.
570 double f = k / L;
571 // Si on est dans la phase 0 et que L > 0, on doit avoir mpoint positif pour
572 // gradient(T) scalaire n negatif.
573 if (phase_ == 0)
574 f = -f;
575
576 mpoint.valeurs() *= f;
577
578 // Pour deverminage : on impose une variation de mpoint lineaire en z
579 //const Domaine_VF & domaine_vf = ref_cast(Domaine_VF, domaine_dis());
580 //for (int i = 0; i < n ; i++)
581 // mpoint.valeurs()[i] = 500./8957.*(1.+0.1*(domaine_vf.xp()(i,3)-0.0005)/0.001);
582
583
584 // Here, it is too early to correct the table mpoint.valeurs() because it has not been used yet to build the extended velocities.
585 // If we were correcting it here with the TCL contribution, we would generate tangential artificial delta_u velocities that are not desired.
586 // Consequently, the TCL effect will be explicitely applied to secmem2 and mpoint will be explicitely corrected too (but later,
587 // just before post-processing in fact).
588
590}
591
592// The list mixed_elems_ contains elems several times (once per operator conv/diff, once per face to a pure phase_ neighbour)
593// (that is four times in most of 2D cells when convection+diffusion are applied)
594// We reduce the list to unique occurences of elements.
595static void collect_into_unique_occurence(ArrOfInt& mixed_elems, ArrOfDouble& lost_fluxes)
596{
597 const int nb_elem_with_duplicates = mixed_elems.size_array();
598 int nb_elem = 0;
599 // Cerr << "Algo may be optimized? It is in NxN = " << nb_elem_with_duplicates << " x "
600 // << nb_elem_with_duplicates << " = " << nb_elem_with_duplicates*nb_elem_with_duplicates <<finl;
601 for (int i=0; i<nb_elem_with_duplicates; i++)
602 {
603 const int elemi = mixed_elems[i];
604 // Have we seen this element already?
605 int j=0;
606 for(j=0; j<i; j++)
607 {
608 const int elemj = mixed_elems[j];
609 if (elemi == elemj)
610 {
611 // yes, then we hit the "continue" in the next if and the loop continues with the next element
612 break;
613 }
614 }
615 if (j!=i)
616 continue;
617
618 // Here, we are with a new element that will remain in the list (may be moved to the position nb_elem)
619 lost_fluxes[nb_elem] = lost_fluxes[i]; // We store the first lost_flux for this elem
620 for (j=i+1; j<nb_elem_with_duplicates; j++)
621 {
622 const int elemj = mixed_elems[j];
623 if (elemi == elemj)
624 {
625 lost_fluxes[nb_elem] += lost_fluxes[j]; // and pile-up others...
626 }
627 }
628 mixed_elems[nb_elem] = elemi;
629 nb_elem++;
630 }
631 lost_fluxes.resize_array(nb_elem);
632 mixed_elems.resize_array(nb_elem);
633}
634
636{
637 Cerr << "Work in progress and widly incorrect. " << finl;
638 Cerr << "Wait and see for further improvements. Exit" << finl;
640 if (inconnue().nb_valeurs_temporelles() == 1)
641 {
642 Cerr << "You need at least 2 positions to the wheel... Contact TRUST support. " << finl;
644 }
645 Transport_Interfaces_FT_Disc& eq_interface_ = ref_eq_interface_.valeur();
646 //const Champ_base& ch_indic = ref_cast(Champ_Inc,eq_interface_.get_indicatrice());
647 //const DoubleTab& indicatrice = ch_indic.valeurs();
648 const DoubleTab& indicatrice = eq_interface_.inconnue().valeurs();
649 const DoubleTab& indicatrice_passe = eq_interface_.inconnue().passe();
650 const double& dt = schema_temps().pas_de_temps();
651 //const DoubleTab& indicatrice_passe = ch_indic.passe();
652 DoubleTab& temperature = inconnue().valeurs();
653 const DoubleTab& temperature_passe = inconnue().passe();
654 const double rhocp = fluide_dipha_->fluide_phase(phase_).masse_volumique().valeurs()(0,0)
655 * fluide_dipha_->fluide_phase(phase_).capacite_calorifique().valeurs()(0,0);
656
657 const int nb_elem = mixed_elems_.size_array();
658 //assert(mixed_elems_diffu_.size_array()==nb_elem);
659 //assert(mixed_elems_conv_.size_array()==nb_elem); // all lists should now have the same size. Or maybe not due to BC?
660 // But still, mixed_elems_ should be the longest and the other should be included
661 derivee_energy_.resize_array(nb_elem);
662 for(int i=0; i<nb_elem; i++)
663 {
664 const int elemi = mixed_elems_[i];
665 derivee_energy_[i] = (temperature[elemi] * indicatrice[elemi] - temperature_passe[elemi] * indicatrice_passe[elemi])* rhocp;
666 }
667
668 Navier_Stokes_FT_Disc& ns = ref_cast(Navier_Stokes_FT_Disc, ref_eq_ns_.valeur());
669 const double Lvap = fluide_dipha_->chaleur_latente();
670 const DoubleVect& volume = ref_cast(Domaine_VF, domaine_dis()).volumes();
671 DoubleTab& mp = mpoint_->valeurs();
672 const DoubleTab& ai = ns.get_interfacial_area();
673 const double temps = schema_temps().temps_courant();
674 {
675 double total_flux_lost = 0.;
676 double total_derivee_energy = 0.;
677 double mpai_tot = 0.;
678 double mp_sum_before = 0.;
679 double int_ai_before = 0.;
680 for (int nd=0 ; nd<nb_elem ; nd++)
681 {
682 const int elembe = mixed_elems_[nd];
683 int_ai_before += ai[elembe];
684 // Cerr << " elembe= " << elembe << finl;
685 // total_flux_lost -= lost_fluxes_(nd)*rhocp; // multiplied by rhocp (vp) // "-" because depends on convention (GB)
686 total_flux_lost -= lost_fluxes_(nd); // in the present TRUST version it should not be multiplied by rhocp
687 total_derivee_energy += derivee_energy_(nd)*volume[nd];
688 mpai_tot += mp[elembe]*ai[elembe]*Lvap;// multiplied by Lvap (vp)
689 mp_sum_before += mp[elembe]*ai[elembe];
690 }
691 if (int_ai_before>DMINFLOAT)
692 {
693 const double mean_mp_before = mp_sum_before/int_ai_before;
694 Cerr << " mp_sum_before= " << mp_sum_before << " mean_mp_before= " << mean_mp_before << " time= " << temps << finl;
695 }
696 total_flux_lost = mp_sum(total_flux_lost);
697 mpai_tot = mp_sum(mpai_tot);
698 total_derivee_energy = mp_sum(total_derivee_energy)/dt;
699 Cerr << "[Basic-Mixed-cells-Energy-Balance] Time= " << temps << " nb_elems= " << nb_elem
700 << " phi(positive if towards mixed cells)= " << total_flux_lost
701 << " mp*ai*Lvap= " << mpai_tot
702 << " dE/dt= " << total_derivee_energy
703 << " imbalance= " << total_derivee_energy-total_flux_lost+mpai_tot << finl;
704 }
705
706 // Energy balance correction. Loop on mixed elems only :
707 const int option=-1; // To disable that
708 {
709 const int account_for_diff = correction_mpoint_diff_conv_energy_[0];
710 const int account_for_conv = correction_mpoint_diff_conv_energy_[1];
711 const int account_for_mixed_cell_energy = correction_mpoint_diff_conv_energy_[2];
712 double int_dmp_ai = 0.; // The integral over the interface of delta_mp
713 double int_ai = 0.; // The interface area
714 double int_mp_ai = 0.;
715 for(int i=0; i<nb_elem; i++)
716 {
717 const int elem = mixed_elems_[i];
718 // The convention is that phi_lost is viewed from the liquid side point-of-view.
719 // (negative for evap as it's leaving the pure liquid)
720 // So when we consider mixed cells, the incoming flux is "-phi_lost"
721 const double phi_in_mixed_cell = lost_fluxes_[i];
722 double phi_conv_lost_by_mixed_cell = 0.;
723 double phi_diffu_added_to_mixed_cell = 0.;
724 if (mixed_elems_diffu_[i] != elem)
725 {
726 Cerr << "Search for a solution? What case is it? diffu, BC? " << finl;
728 }
729 else
730 {
731 phi_diffu_added_to_mixed_cell = lost_fluxes_diffu_[i];
732 // Cerr << " lost-flux-diff= " << phi_diffu_added_to_mixed_cell << " at-time= " << temps << " in-elem= " << elem << finl;
733 }
734 if (i>=mixed_elems_conv_.size_array() || mixed_elems_conv_[i] != elem)
735 {
736 phi_conv_lost_by_mixed_cell =0.;
737 int j=0;
738 for (j=0; j<mixed_elems_conv_.size_array(); j++)
739 {
740 if (mixed_elems_conv_[j] == elem)
741 {
742 phi_conv_lost_by_mixed_cell = lost_fluxes_conv_[j];
743 break;
744 }
745 }
746 if (j==mixed_elems_conv_.size_array())
747 {
748 Cerr << "conv. The end of the list is reached, "
749 << "mixed_elems_["<< i<<"]= " << elem << " was not found in mixed_elem_conv_"<< finl;
750 Cerr << "mixed_elems_conv_= " << mixed_elems_conv_ << finl;
751 Cerr << "mixed_elems_= " << mixed_elems_ << finl;
752 Cerr << "WE ASSUME IT IS BECAUSE IT IS A BC? any solution? WE IGNORE IT"<< finl;
753 // Process::exit();
754 }
755
756 }
757 else
758 {
759 phi_conv_lost_by_mixed_cell = lost_fluxes_conv_[i];
760 // Cerr << " lost-flux-conv= " << phi_conv_lost_by_mixed_cell << " at-time= " << temps << " in-elem= " << elem << finl;
761 }
762
763 double VdrhocpT_dt = 0.;
764 if (account_for_mixed_cell_energy)
765 {
766 VdrhocpT_dt=(rhocp*volume[elem])*(temperature[elem] * indicatrice[elem] - temperature_passe[elem] * indicatrice_passe[elem])/dt;
767 // Cerr << "temp_current= " << temperature[elem] << " temp_previous= " << temperature_passe[elem] << finl;
768 }
769
770 if (option ==1)
771 {
772 // OPtion 1 : Correction of T
773 const double value_before = temperature[elem];
774 temperature[elem] = 1/indicatrice[elem] * (temperature_passe[elem] * indicatrice_passe[elem] + dt/(rhocp*volume[elem])*(mp[elem]*ai[elem]*Lvap - phi_in_mixed_cell*rhocp));
775 // multiplied phi_lost by rhocp (vp)
776 Cerr << "[Delta-T-due-to-Energy-correction] elem "<< elem <<" Tnew-Tuncorrected " << temperature[elem]-value_before << finl;
777 //
778 const double tmp = (temperature[elem] * indicatrice[elem] - temperature_passe[elem] * indicatrice_passe[elem])* rhocp;
779 if (derivee_energy_[i] != tmp)
780 {
781 Cerr << "New derivee_energy after correction (before/after) : ( "<< derivee_energy_[i] <<" / " << tmp << " )." << finl;
782 derivee_energy_[i] = tmp;
783 }
784 }
785 else if (option ==2)
786 {
787 // Option 2 : Correction of mp: local corrections in all mixed cells
788 if (ai[elem]>DMINFLOAT)
789 {
790 const double old_mp = mp[elem];
791
792 double delta_mp = 0. ;
793 if (account_for_diff)
794 {
795 delta_mp += (1/(ai[elem]*Lvap))*((mp[elem]*ai[elem]*Lvap + phi_diffu_added_to_mixed_cell)); // for Stefan it is negative sign before phi_difu_...
796 // (we need to make it uniform so that it works for all with the same sign convention....may depend on the normal)
797 Cerr << " delta-mp-diff= " << delta_mp << finl;
798 }
799 if (account_for_conv)
800 {
801 // To be checked :
802 // - the minus sign?
803 // - what surface should we use? ai or Sface?
804 // - The interpolation of T to the face?
805 // double Tface = temperature[elem];
806 // double rhov = fluide_dipha_->fluide_phase(1-phase_).masse_volumique()(0,0);
807
808 delta_mp += (1/(ai[elem]*Lvap))*(-phi_conv_lost_by_mixed_cell);
809 // delta_mp += (1/(ai[elem]*Lvap))*(-(mp[elem]*ai[elem]*rhocp/rhov*Tface - phi_conv_lost_by_mixed_cell));
810 Cerr << " delta-mp-conv= " << delta_mp << finl;
811 }
812 if (account_for_mixed_cell_energy)
813 delta_mp += (1/(ai[elem]*Lvap))*(VdrhocpT_dt);
814 // divided by Lvap (now consistent in units-vp) and multiplied phi_lost by rhocp
815 mp[elem] +=delta_mp;
816 Cerr << " delta_mp= " << delta_mp << " old_mp= " << old_mp << " new_mp= " << mp[elem] << finl;
817 if (fabs(old_mp)>DMINFLOAT)
818 Cerr << "relative correction of mp at time "<< temps << " elem= " << elem << " delta= " <<delta_mp/old_mp*100. << "%." <<finl;
819 }
820 }
821 else if (option==3)
822 {
823 // Option 3 : Global Correction of mp:
824 if ((ai[elem]>DMINFLOAT) and (temps>DMINFLOAT))
825 {
826 int_ai += ai[elem];
827 int_mp_ai += mp[elem]*ai[elem];
828 // Cerr << " area-elem= " << ai[elem] << " temps= " << temps << finl;
829 // Before we had : const double tmp = (1/(Lvap))*(VdrhocpT_dt-(mp[elem]*ai[elem]*Lvap - phi_in_mixed_cell*rhocp));
830
831 double delta_mp = 0. ;
832 if (account_for_diff)
833 {
834 // delta_mp += (1/(ai[elem]*Lvap))*(-(mp[elem]*ai[elem]*Lvap - phi_diffu_added_to_mixed_cell));
835 delta_mp += (-1/Lvap)*((mp[elem]*ai[elem]*Lvap - phi_diffu_added_to_mixed_cell));// for Stefan it is negative sign before phi_difu_...
836 // (we need to make it uniform so that it works for all with the same sign convention....may depend on the normal)
837 // delta_mp += mp[elem]*ai[elem] + (1/Lvap)*(phi_diffu_added_to_mixed_cell);
838 // Cerr << " mpaiL= " << mp[elem]*ai[elem]*Lvap << " phi_diff= " << phi_diffu_added_to_mixed_cell << finl;
839 // Cerr << " delta-mp-diff= " << delta_mp << finl;
840 }
841
842 if (account_for_conv)
843 {
844 // To be checked :
845 // - the minus sign?
846 // - what surface should we use? ai or Sface?
847 // - The interpolation of T to the face?
848 // double Tface = temperature[elem];
849 // double rhov = fluide_dipha_->fluide_phase(1-phase_).masse_volumique()(0,0);
850
851 // delta_mp += (1/(ai[elem]*Lvap))*(-(mp[elem]*ai[elem]*rhocp/rhov*Tface - phi_conv_lost_by_mixed_cell));
852 // delta_mp += (1/(ai[elem]*Lvap))*((mp[elem]*ai[elem]*rhocp/rhov*Tface - phi_conv_lost_by_mixed_cell));
853 // delta_mp += (1/Lvap)*(mp[elem]*ai[elem]*rhocp/rhov*Tface);
854 // Cerr << " conv-new= " << (1/Lvap)*(mp[elem]*ai[elem]*rhocp/rhov*Tface) << finl;
855 delta_mp += (-1/Lvap)*(phi_conv_lost_by_mixed_cell);
856 // Cerr << " conv-new= " << phi_conv_lost_by_mixed_cell << " in elem= " << elem << finl;
857 // Cerr << " delta-mp-conv= " << delta_mp << finl;
858 }
859 if (account_for_mixed_cell_energy)
860 {
861 delta_mp += (1/Lvap)*(VdrhocpT_dt);
862// Cerr << " delta-mp-energy= " << (1/Lvap)*(VdrhocpT_dt) << finl;
863 }
864 int_dmp_ai += delta_mp;
865// Cerr << " delta-mp-tot= " << int_dmp_ai << " time= " << temps << finl;
866 }
867 }
868 // End of options
869 }
870 if ((option==3) and (int_ai>DMINFLOAT))
871 // if ((option==3))
872 {
873 const double mean_dmp = int_dmp_ai/int_ai;
874 const double mean_mp = int_mp_ai/int_ai;
875 double rel= 0.;
876 if (fabs(mean_mp)>DMINFLOAT)
877 rel=mean_dmp/mean_mp*100.;
878 Cerr << "correction of mp at time "<< temps << " mean_mp= " << mean_mp << " relative= " << rel << "%." <<finl;
879 /* Bad correction:
880 *
881 for(int i=0; i<nb_elem; i++)
882 {
883 const int elem = mixed_elems_[i];
884 mp[elem] +=mean_dmp;
885 Cerr << " newmp= " << mp[elem] << finl;
886 }*/
887 // New correction truely based on AI:
888 // (to be in perfect agreement with the condition (on untouched variables) used later for the extrapolation:
889 /* for(int i=0; i<nb_elem; i++)
890 {
891 const int elem = mixed_elems_[i];
892 if ((ai[elem]>DMINFLOAT) and (temps>DMINFLOAT))
893 mp[elem] +=mean_dmp;
894 } */
895
896 // GB 18/10/2020. Application of the correction EVERYWHERE:
897 mp +=mean_dmp;
898 }
899
900 double total_flux_lost = 0.;
901 double total_derivee_energy = 0.;
902 double mpai_tot = 0.;
903// double mp_tot = 0.;
904 for (int nd=0 ; nd<nb_elem ; nd++)
905 {
906 total_flux_lost -= lost_fluxes_(nd)*rhocp; // multiplied by rhocp (vp) // "-" because depends on convention (GB)
907 total_derivee_energy += derivee_energy_(nd)*volume[nd];
908 const int elem = mixed_elems_[nd];
909 mpai_tot += mp[elem]*ai[elem]*Lvap; // multiplied by Lvap (vp)
910 // mp_tot += mp[elem];
911 }
912 if ((option==3) and (int_ai>DMINFLOAT))
913 {
914 const double mean_mp_corr = mpai_tot/(int_ai*Lvap);
915 Cerr << " mean_mp_corr= " << mean_mp_corr << " time= " << temps << finl;
916 }
917 total_flux_lost = mp_sum(total_flux_lost);
918 mpai_tot = mp_sum(mpai_tot);
919 total_derivee_energy = mp_sum(total_derivee_energy)/dt;
920 Cerr << "[Corrected-balance] Time= " << temps << " nb_elems= " << nb_elem
921 << " phi(positive if towards mixed cells)= " << total_flux_lost
922 << " mp*ai*Lvap= " << mpai_tot
923 << " dE/dt= " << total_derivee_energy
924 << " imbalance= " << total_derivee_energy-total_flux_lost+mpai_tot << finl;
925 }
926
927 // If mpoint has been modified in interfacial cells (mixed cells). We want to extend it back into both phases
928 // using the same procedure
929 if ((option==0) or (option==3) or (option==2))
930 {
931 double mmax = 0.;
932 const int n = ai.size_array();
933 for(int i=0; i<n; i++)
934 {
935 if ((ai[i]>DMINFLOAT) && (fabs(mp[i])>mmax))
936 {
937 mmax =fabs(mp[i]);
938 }
939 }
940 mmax = Process::mp_max(mmax);
941 // Cerr << "[Maximum-mp] Time= " << temps << " max(abs(mp))= " << mmax << finl;
942 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis());
943 const DoubleTab& distance_interface = eq_interface_.get_distance_interface().valeurs();
944 extrapolate(domaine_vf, ai, stencil_width_, distance_interface, mp);
945 }
946}
947
948// With this approach, calculer_delta_u_interface is not called,
949// so the velocity should be extended.
950// Fills the field : vitesse_convection_
952{
953 Navier_Stokes_FT_Disc& ns = ref_cast(Navier_Stokes_FT_Disc, ref_eq_ns_.valeur());
954 // vitesse_convection_->valeurs() = (bool)(explicit_u_NS_) ? ns.inconnue()->valeurs() : ns.inconnue()->futur();
955
956 const DoubleTab& val_vitesse_ns = explicit_u_NS_ ? ns.inconnue().valeurs() : ns.inconnue().futur();
957
959 vitesse_convection_->valeurs() += val_vitesse_ns;
960
961 // Projection of the convective field :
962 //SolveurSys solveur_pression(ns.get_solveur_pression());
963 OWN_PTR(Solveur_Masse_base) solveur_masse_fictitious(ns.solv_masse()); // Copy the operator to change the coeff
964 solveur_masse_fictitious->set_name_of_coefficient_temporel("no_coeff");
965
966 //On utilise un operateur de divergence temporaire et pas celui porte par l equation
967 //pour ne pas modifier les flux_bords_ rempli au cours de ...::mettre_a_jour
968 Operateur_Div div_tmp;
969 div_tmp.associer_eqn(ns);// It's slightly tricky but associating it to (*this) is not OK, because we want to apply it to a velocity.
970 // As delta_u is not the unknown of this equation (no more than vitesse_convection_), we resort to ns to
971 // make it work. Basically, it also means that delta_u gets the BC from u_ns?
972 // Problem with div_tmp.typer() that get the type of equation to make a type.
973 // Hence, it will see a conv/diff equation for a scalar... and will type div_tmp badly (not for a vector velocity field!)
974 // Instead we associer_eqn to ns
975 div_tmp.typer();
976 Cerr << "[Conv_diff_FT_Disc] div_tmp recieved the type " << div_tmp.type() << finl;
977 Cerr << "[Conv_diff_FT_Disc] div_tmp que suis je " << div_tmp.que_suis_je() << finl;
978 if (0)
979 {
980 Equation_base& eqn=ref_eq_ns_.valeur();
981 Nom inut;
982 Nom nom_type=eqn.discretisation().get_name_of_type_for(ns.que_suis_je(),inut,ns);
983 // const Probleme_FT_Disc_gen& pb = ref_cast(Probleme_FT_Disc_gen,probleme());
984 // ref_cast
985 // OWN_PTR(Operateur_Div_base)::typer(nom_type);
986 Cerr << "[Conv_diff_FT_Disc] Velocity correction. Construction of the divergence operator type : " << nom_type << finl;
987 // Cerr << valeur().que_suis_je() << finl ;
988 }
989
990 div_tmp.l_op_base().associer_eqn(ns);//*this);
991 //div_tmp.typer();
992 div_tmp->completer();
993 // En VDF, la methode 'completer()' est surchargee et fait
994 // 1. Operateur_base::completer();
995 // 2. iter.completer_();
996 // donc si on fait juste :
997 // div_tmp.l_op_base().associer(domaine_dis(), zcl_fictitious_, vitesse_convection_);
998 // On rate l'etape 2 qui a ete faite avec le completer plus haut...
999
1000 // WARNING : Si on prend les cl de l'ope de pression pour cette divergence, il y a une vitesse sur les sorties de NS
1001 // qui se trouve face a des conditions limites de symetrie dans zcl_fictitious...
1002 // Du coup, ca fait un gros div! Ce n'est pas ce qu'on veut.
1003 // PAR CONTRE, pour le calcul du gradient ci-dessous, c'est bien les cl de zcl_fictitious qu'on veut,
1004 // sinon, sortie libre va mettre un grad(P).n non nul au bord!!
1005 // DONC EN CONCLUSION, ON VEUT UN MIX!
1006 //
1007
1008 // RHS for this pressure solveur : div(delta_u)
1009 // We need to create a table sized as temperature to store the rhs :
1010 DoubleTab& secmem = divergence_delta_U->valeurs();
1011 //secmem.copy(inconnue().valeurs(), RESIZE_OPTIONS::NOCOPY_NOINIT);
1012 div_tmp->calculer(vitesse_convection_->valeurs(),secmem);
1013
1014 // On ne conserve que la divergence des elements proches de l'interface, et supprime quand la distance est invalide
1015 if (0) // Cela pourrait etre utile si on construisait le saut de vitesse delta u_0 mais
1016 // cela semble presenter que peu d'interet...
1017 {
1018 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis());
1019 const IntTab& face_voisins = domaine_vf.face_voisins();
1020 const IntTab& elem_faces = domaine_vf.elem_faces();
1021 const int nb_elem = secmem.size_array();
1022 const int nb_faces_elem = elem_faces.dimension(1);
1023 const Transport_Interfaces_FT_Disc& eq_transport = ref_eq_interface_.valeur();
1024 // Distance a l'interface discretisee aux elements:
1025 const DoubleTab& distance = eq_transport.get_distance_interface().valeurs();
1026 // const int nb_elem = secmem2.dimension(0);
1027 for (int elem = 0; elem < nb_elem; elem++)
1028 {
1029 const double dist = distance(elem);
1030 int i_face = -1;
1031 if (dist < -1e20)
1032 {
1033 // Distance invalide: on est loin de l'interface
1034 // invalide ou voisin invalide, on supprime la div :
1035 secmem(elem) = 0.;
1036 }
1037 else
1038 {
1039 // Y a-t-il un voisin pour lequel la distance est invalide
1040 for (i_face = 0; i_face < nb_faces_elem; i_face++)
1041 {
1042 const int face = elem_faces(elem, i_face);
1043 const int voisin = face_voisins(face, 0) + face_voisins(face, 1) - elem;
1044 if (voisin >= 0)
1045 {
1046 const double d = distance(voisin);
1047 if (d < -1e20)
1048 {
1049 // invalide ou voisin invalide, on supprime la div :
1050 secmem(elem) = 0.;
1051 break; // Un voisin invalide
1052 }
1053 }
1054 }
1055 }
1056 }
1057 }
1058 // Correction du second membre d'apres les conditions aux limites :
1059 assembleur_pression_->modifier_secmem(secmem);
1060 // Ajout pour la sauvegarde au premier pas de temps si reprise
1061 la_pression->changer_temps(schema_temps().temps_courant());
1062
1063 // Resolution du systeme en pression : calcul de la_pression
1064 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(),
1065 secmem,
1066 la_pression->valeurs()
1067 );
1068 assembleur_pression_->modifier_solution(la_pression->valeurs());
1069 // Calcul d(u)/dt = vpoint + 1/rho*grad(P)
1070
1071 DoubleTab& gradP = gradient_pression_->valeurs();
1072 // Can I re-use a gradient from NS?
1073 Operateur_Grad gradient_tmp;
1074 gradient_tmp.associer_eqn(ns);//*this);
1075 gradient_tmp.typer();
1076 gradient_tmp.l_op_base().associer_eqn(ns);//*this);
1077 gradient_tmp->completer();
1078 // It is important to associate the gradient to the good BC via zcl,
1079 // Otherwise a normal gradient appears at the outlet.
1080 gradient_tmp.l_op_base().associer(domaine_dis(), zcl_fictitious_, vitesse_convection_); // Quel champ inco pour le gradP? A quoi sert-elle?
1081 gradient_tmp.calculer(la_pression->valeurs(), gradP);
1082 // I don't wanna divide by rho_face :
1083 solveur_masse_fictitious->appliquer(gradP); // divide by cell_volume
1084
1085 // Correction of vitesse : "+=" seems the good sign, though I don't understand why...
1086 {
1087 int i, j;
1088 DoubleTab& vc = vitesse_convection_->valeurs();
1089 const int n = vc.dimension(0);
1090 if (vc.nb_dim() == 1)
1091 {
1092 // VDF
1093 for (i = 0; i < n; i++)
1094 vc(i) += gradP(i);
1095 }
1096 else
1097 {
1098 //VEF
1099 const int m = vc.dimension(1);
1100 for (i = 0; i < n; i++)
1101 for (j = 0; j < m; j++)
1102 vc(i,j) += gradP(i,j);
1103 }
1105 }
1106
1107}
1109{
1110 // We start the timestep by computing :
1111 // STEP 1. Extend velocity and temperature (via calculer_grad_t which does a linear extrapolation
1112 // from the values within "phase_")
1113 statistics().create_custom_counter("calculer_mpoint",3,"FrontTracking");
1114 statistics().begin_count("calculer_mpoint",statistics().get_last_opened_counter_level()+1);
1116 statistics().end_count("calculer_mpoint");
1117
1118 Navier_Stokes_FT_Disc& ns = ref_cast(Navier_Stokes_FT_Disc, ref_eq_ns_.valeur());
1119 // Emptying lists for new timestep.
1120 mixed_elems_.resize_array(0);
1121 lost_fluxes_.resize_array(0);
1122
1123 // STEP 2. Compute the continuous extension of velocity from phase_ into the other.
1124 // This velocity will be usefull for the convection operator.
1125 // Now, the step calculer_delta_u_interface calls get_mpoint instead of
1126 // calculer_mpoint (which used to in turns call: calculer_grad_t)
1127 // Therefore, it is important to have called explicitely the temperature
1128 // extension before at the begining of the function.
1129 statistics().create_custom_counter("extend_ui",3,"FrontTracking");
1130 statistics().begin_count("extend_ui", statistics().get_last_opened_counter_level()+1);
1131 const Champ_Inc_base& vitesse_ns = ns.inconnue();
1133 {
1134 // Here, we are in faire_un_pas_de_temps_eqn_base() between avancer and reculer()
1135 // We are not in mettre_a_jour(). valeurs() has u^n; futur() is u^(n+1)
1136 const DoubleTab& val_vitesse_ns = explicit_u_NS_ ? vitesse_ns.valeurs(): vitesse_ns.futur();
1137
1138 // vitesse_convection_ is Champ_Inc but never turns the wheel! So the field is always in .valeurs()
1140 vitesse_convection_->valeurs() += val_vitesse_ns;
1141 //Cerr << inconnue()->temps() << " =! " << vitesse_ns.temps() << " " << vitesse_convection_.temps() << finl;
1142 //Process::exit();
1143 }
1144 else
1145 {
1146 // Compute vitesse_convection_ which is equal to ns.inconnue() in phase_ and is extended (divergence-free) in the other phase:
1148 }
1149 statistics().end_count("extend_ui");
1150
1151 // Application of 2 operators: convection & diffusion
1152 // STEP 3: Convection operator
1153 // STEP 4: Diffusion operator
1154 // Convection and diffusion are dealt with in the standard way;
1155 // diffusion can be implicited.
1156 // rhoCp is used for convection.
1157 // vitesse_convection_ is used for convection.
1158 DoubleTab& temperature = inconnue().valeurs();
1159 derivee = 0.;
1160
1161 // STEP 3: Diffusion operator
1162 bool calcul_explicite = false;
1163 if (parametre_equation_ && sub_type(Parametre_implicite, parametre_equation_.valeur()))
1164 {
1165 Parametre_implicite& param2 = ref_cast(Parametre_implicite, parametre_equation_.valeur());
1166 calcul_explicite = param2.calcul_explicite();
1167 }
1168
1169 if (schema_temps().diffusion_implicite() && !calcul_explicite)
1170 {
1171 // do it later?
1172 }
1173 else
1174 {
1175 terme_diffusif.ajouter(temperature, derivee);
1176 }
1177 const int nb_diffu=mixed_elems_.size_array();
1178 // const double temps = schema_temps().temps_courant();
1179 lost_fluxes_diffu_.resize_array(nb_diffu);
1180 mixed_elems_diffu_.resize_array(nb_diffu);
1181 {
1182 double total_flux_lost = 0.;
1183 for (int nd=0 ; nd<nb_diffu ; nd++)
1184 {
1185 total_flux_lost += lost_fluxes_(nd);
1188 }
1189 total_flux_lost = mp_sum(total_flux_lost);
1190 // Cerr << "[Lost-fluxes-diffusif] Time= " << temps << " nb_faces= " << nb_diffu
1191 // << " Lost= " << total_flux_lost << finl;
1192 }
1193
1194 // STEP 4: Convection operator
1195 {
1196 const DoubleTab& rhoCp = get_champ("rho_cp_comme_T").valeurs();
1197 DoubleTab derivee_tmp(derivee);
1198 derivee_tmp = 0.;
1199 terme_convectif.ajouter(temperature, derivee_tmp);
1200 derivee_tmp *= rhoCp;
1201 derivee += derivee_tmp;
1202
1203 const int nb_conv=mixed_elems_.size_array()-nb_diffu;
1204 lost_fluxes_conv_.resize_array(nb_conv);
1205 mixed_elems_conv_.resize_array(nb_conv);
1206 double total_flux_conv_lost = 0.;
1207 for (int nd=0 ; nd<nb_conv ; nd++)
1208 {
1209 const int elem = mixed_elems_(nb_diffu+nd);
1210 const double flux = lost_fluxes_(nb_diffu+nd)*rhoCp[elem];
1211 total_flux_conv_lost += flux;
1212 lost_fluxes_conv_(nd) = flux;
1213 mixed_elems_conv_(nd) = elem;
1214 }
1215
1216 total_flux_conv_lost = mp_sum(total_flux_conv_lost);
1217 // Cerr << "[Lost-fluxes-convection] Time= " << temps << " nb_faces= " << nb_conv
1218 // << " Lost= " << total_flux_conv_lost << finl;
1219
1220 }
1221
1222 solveur_masse->appliquer(derivee);
1223 if (schema_temps().diffusion_implicite() && !calcul_explicite)
1224 {
1226 return derivee;
1227 }
1228 else
1229 {
1230 // TODO : J'aimerais bien deplacer la diffusion explicite la aussi.
1231 // Il faut juste revoir les boucles pour deplacer le lost_fluxes associes ici aussi
1232 // terme_diffusif.ajouter(temperature, derivee);
1233 }
1234
1235 // To remove duplicates in the list of mixed_elems (some elements are there several times, twice (conv+diff) for each face-to-pure-liquid)
1236 collect_into_unique_occurence(mixed_elems_, lost_fluxes_);
1237 collect_into_unique_occurence(mixed_elems_diffu_, lost_fluxes_diffu_);
1238 collect_into_unique_occurence(mixed_elems_conv_, lost_fluxes_conv_);
1239
1240 {
1241 const int nb=mixed_elems_.size_array();
1242 double total_flux_lost = 0.;
1243 for (int nd=0 ; nd<nb ; nd++)
1244 total_flux_lost += lost_fluxes_(nd);
1245
1246 total_flux_lost = mp_sum(total_flux_lost);
1247 // Cerr << "[Lost-fluxes-conv+diff] Time= " << temps << " nb_faces= " << nb
1248 // << " Lost= " << total_flux_lost << finl;
1249 }
1250
1251 // STEP 5: (OPTIONNAL?) Attempt to correct mpoint to reach an energy conservation.
1252 // Apply a correction to mpoint in order to locally satisfy the energy balance in mixed cells (consistency between incoming fluxes that are lost
1253 // and the phase change mp*ai, all with regards to the liquid energy evolution in the cell: d(rho*cp*chi*T)/dt.
1254 {
1255 mpoint_uncorrected_->valeurs() = mpoint_->valeurs();
1256 DoubleTab& mp = mpoint_->valeurs();
1257 const DoubleTab& ai = ns.get_interfacial_area();
1258 const double temps = schema_temps().temps_courant();
1259 const int nb_elemi = mixed_elems_.size_array();
1260 double mp_sum_before_corr = 0.;
1261 double int_ai_before = 0.;
1262 for (int nd=0 ; nd<nb_elemi ; nd++)
1263 {
1264 const int elembi = mixed_elems_[nd];
1265 int_ai_before += ai[elembi];
1266 // total_flux_lost -= lost_fluxes_(nd)*rhocp; // multiplied by rhocp (vp) // "-" because depends on convention (GB)
1267 // total_derivee_energy += derivee_energy_(nd)*volume[nd];
1268 // mpai_tot += mp[elemb]*ai[elemb]*Lvap;// multiplied by Lvap (vp)
1269 // Cerr << " ai= " << ai[elembi] << " int_ai= " << int_ai_before << finl;
1270 mp_sum_before_corr += mp[elembi]*ai[elembi];
1271 }
1272 if (int_ai_before>DMINFLOAT)
1273 {
1274 const double mean_mp_before_corr = mp_sum_before_corr/int_ai_before;
1275 Cerr << " mp_sum_before_corr= " << mp_sum_before_corr << " mean_mp_before_corr= " << mean_mp_before_corr << " time= " << temps << finl;
1276 }
1278 {
1279 // WARNING!! We don't correct mpoint if correction_mpoint_diff_conv_energy_ are all set to 0
1280 // this method is not related to TCL model but rather to attempting energy conserving Ghost Fluid Method.
1282 }
1283 }
1284
1285 const Probleme_FT_Disc_gen& pb = ref_cast(Probleme_FT_Disc_gen,probleme());
1286 const Triple_Line_Model_FT_Disc& tcl = pb.tcl();
1287 // const double max_val_before = max_array(temperature);
1288 // const double min_val_before = min_array(temperature);
1289 if (tcl.is_activated())
1290 {
1291 // No need to recompute TCL here, it should be up-to-date.
1292#ifdef DEBUG
1293 {
1294 const Transport_Interfaces_FT_Disc& eq_transport = ref_eq_interface_.valeur();
1295 const Maillage_FT_Disc& maillage = eq_transport.maillage_interface();
1296 assert(tcl.tag_tcl() == maillage.get_mesh_tag());
1297 toto ce code n est pas lu
1298 }
1299#endif
1300 // Ne compile pas, pourquoi?
1301 // assert(tcl.tag_tcl() == ref_eq_interface_->maillage_interface().get_mesh_tag());
1302
1303 // We are late enough within the timestep for the correction not to affect the velocities reconstructions (delta_u)
1304 // because we expect it has been done before. Nonetheless, we need to do it before the post-pro to see our corrected fields
1305 // in the lata
1306 //
1307 // Correct the field mpoint in wall-adjacent cells to account for TCL model:
1308 // ---> It cannot be done before because it would disturbs the solution via delta u!
1309 tcl.corriger_mpoint(mpoint_->valeurs());
1310
1311 // Correct the phase-change in wall adjacent cells:
1312 // The mean cell-temperature is simply derived from the TCL solution.
1313 // tcl.set_wall_adjacent_temperature_according_to_TCL_model(temperature);
1314 temperature.echange_espace_virtuel();
1315 }
1316 // Cerr << "[temperature] max before/after TCL model: " << max_val_before << " / " << max_array(temperature) << finl;
1317 // Cerr << "[temperature] min before/after TCL model: " << min_val_before << " / " << min_array(temperature) << finl;
1318
1319 return derivee;
1320}
1321
1323{
1325 vitesse_convection_->mettre_a_jour(temps);
1326 DoubleTab& temperature = inconnue().valeurs();
1327 // GB : Debut du maintien artificiel de la temperature.
1329 {
1330 const Nom nom_sous_domaine = nom_sous_domaine_;
1331 const double temp_moy_ini = temp_moy_ini_;
1332 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis());
1333 const Domaine& dom = domaine_vf.domaine();
1334 const Sous_Domaine& ss_domaine = dom.ss_domaine(nom_sous_domaine);
1335
1336 Transport_Interfaces_FT_Disc& eq_interface_ = ref_eq_interface_.valeur();
1337 const DoubleTab& indicatrice = eq_interface_.get_indicatrice().valeurs();
1338 const DoubleVect& volume = ref_cast(Domaine_VF, domaine_dis()).volumes();
1339 const int nb_elem = domaine_vf.domaine().nb_elem();
1340
1341 // Calcul de la moyenne sous domaine, et du facteur : fac = temp_moy_ini/temp_moy_ss_domaine
1342 double temp_moy_ss_domaine = 0.;
1343 double vol_liq = 0.;
1344 for(int i=0; i<ss_domaine.nb_elem_tot() /*methode d'acces au nombre d'elements*/; i++)
1345 {
1346 int index = ss_domaine[i];
1347 // assert(index < domaine_vf.domaine().nb_elem());
1348 if (index < nb_elem)
1349 {
1350 temp_moy_ss_domaine += temperature[index] * indicatrice[index] * volume[index];
1351 vol_liq += indicatrice[index] * volume[index];
1352 }
1353 }
1354 vol_liq = mp_sum(vol_liq);
1355 temp_moy_ss_domaine = mp_sum(temp_moy_ss_domaine);
1356 if (vol_liq == 0. || temp_moy_ss_domaine == 0.)
1357 {
1358 // ne fien faire
1359 }
1360 else
1361 {
1362 temp_moy_ss_domaine /= vol_liq ;
1363 double fac = temp_moy_ini / temp_moy_ss_domaine;
1364
1365 // Correction du champ de temperature :
1366 temperature *= fac; // Methode de multiplication d'un tableau
1367 }
1368 }
1369 // GB : Fin.
1370 temperature.echange_espace_virtuel();
1371
1372 // check if the wall is ready for reinjection of bubble
1373 const bool is_liq = (get_phase()==1);
1374 if (is_liq && is_reinject_activated())
1376}
1377
1379{
1380
1381 const Navier_Stokes_std& ns = ref_eq_ns_.valeur();
1382 const Domaine_Cl_dis_base& zcldis = ns.domaine_Cl_dis();
1383
1384 Transport_Interfaces_FT_Disc& eq_interface_ = ref_eq_interface_.valeur();
1385 const DoubleTab& indica = eq_interface_.get_indicatrice().valeurs();
1386
1387 // get wall BC frontiere nb
1388 int num_bord = -1;
1389 int nbwall_found = 0;
1390 for (int i=0; i<zcldis.nb_cond_lim(); i++)
1391 {
1392 const Cond_lim& la_cl = zcldis.les_conditions_limites(i);
1393 const Nom& bc_name = la_cl-> frontiere_dis().le_nom();
1394 // For each BC, we check its type to see if it's a wall:
1395 // BC for hydraulic equation
1396 bool is_wall = sub_type(Dirichlet_paroi_fixe,la_cl.valeur())
1397 || sub_type(Dirichlet_paroi_defilante,la_cl.valeur());
1398 if (is_wall)
1399 {
1400 Cerr << "[Convection_Diffusion_Temperature_FT_Disc]: Reinjection bubble: Wall-type BC found at " << bc_name <<finl;
1401 num_bord = i;
1402 nbwall_found = nbwall_found +1;
1403 }
1404 }
1405 if (nbwall_found != 1)
1406 Process::exit(Nom(nbwall_found) + " wall-type BC found!!!!! Check JDD, pls" );
1407 if (num_bord<0)
1408 Process::exit( "[Convection_Diffusion_Temperature_FT_Disc]: !!! NO WALL-TYPE BOUNDARY WAS FOUND IN THE DOMAINE, PLESEASE CHECK JDD" );
1409
1410 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis());
1411 const IntTab& face_voisins = domaine_vf.face_voisins();
1412
1413 const DoubleTab& centre_gravite_face = domaine_vf.xv();
1414 const DoubleVect& surface= domaine_vf.face_surfaces();
1415
1416 const Frontiere& fr=zcldis.les_conditions_limites(num_bord) -> frontiere_dis().frontiere();
1417 const int nb_first_face = fr.num_premiere_face();
1418 const int nb_face = fr.nb_faces();
1419
1420 ready_inject_ = false;
1421 int BC_has_vap = 0;
1422
1423 // get vap cells
1424 for (int ii = 0; ii < nb_face; ii++)
1425 {
1426 const int num_face = ii + nb_first_face;
1427 const int elemi = face_voisins (num_face, 0)
1428 + face_voisins (num_face, 1) + 1;
1429
1430 if (!est_egal (indica(elemi,0), 1.))
1431 {
1432 BC_has_vap = 1;
1433 break;
1434 }
1435 }
1436 BC_has_vap = Process::mp_max (BC_has_vap);
1437
1438 if (BC_has_vap == 0)
1439 {
1440 double sum_T = 0;
1441 double sum_surface = 0;
1442 for (int ii = 0; ii < nb_face; ii++)
1443 {
1444 const int num_face = ii + nb_first_face;
1445
1446 if (centre_gravite_face(num_face, 0) <= get_Rc_inject ())
1447 {
1448 sum_surface += surface (num_face);
1449 sum_T += surface (num_face) * get_Twall_at_face (num_face);
1450 }
1451 }
1452 sum_T = Process::mp_sum (sum_T);
1453 sum_surface = Process::mp_sum (sum_surface);
1454
1455 sum_T = (sum_surface > DMINFLOAT) ? sum_T / sum_surface : 0;
1456 ready_inject_ = (sum_T >= get_tempC()) ? true : false;
1457 }
1458}
1459
1461{
1462 phase_ = 1;
1463
1464 const Discretisation_base& dis = discretisation();
1465 const double temps = schema_temps().temps_courant();
1466 const Domaine_dis_base& un_domaine_dis = domaine_dis();
1467 LIST(OBS_PTR(Champ_base)) & champs_compris = liste_champs_compris_;
1468 const int nb_valeurs_temps = schema_temps().nb_valeurs_temporelles();
1469
1470 Nom nom;
1471
1472 nom = Nom("temperature_") + le_nom();
1473 dis.discretiser_champ("temperature", un_domaine_dis, nom, "K", 1 /* composantes */, nb_valeurs_temps, temps, la_temperature);
1474 champs_compris.add(la_temperature.valeur());
1475 champs_compris_.ajoute_champ(la_temperature);
1476
1477 nom = Nom("temperature_grad_") + le_nom();
1478 dis.discretiser_champ("temperature", un_domaine_dis, nom, "K/m", 1 /* composantes */, temps, grad_t_);
1479 champs_compris.add(grad_t_.valeur());
1480 champs_compris_.ajoute_champ(grad_t_);
1481
1482 nom = Nom("mpoint_") + le_nom();
1483 dis.discretiser_champ("temperature", un_domaine_dis, nom, "kg/(m2s)", 1 /* composante */, temps, mpoint_);
1484 champs_compris.add(mpoint_.valeur());
1485 champs_compris_.ajoute_champ(mpoint_);
1486
1487 nom = Nom("mpoint_uncorrected_") + le_nom();
1488 dis.discretiser_champ("temperature", un_domaine_dis, nom, "kg/(m2s)", 1 /* composante */, temps, mpoint_uncorrected_);
1489 champs_compris.add(mpoint_uncorrected_.valeur());
1490 champs_compris_.ajoute_champ(mpoint_uncorrected_);
1491
1492 nom = Nom("vitesse_conv_") + le_nom();
1493 dis.discretiser_champ("vitesse", un_domaine_dis, nom, "m/s", -1 /* nb composantes par defaut */, 1 /* valeur temporelle */, temps, vitesse_convection_);
1494 champs_compris.add(vitesse_convection_.valeur());
1495 champs_compris_.ajoute_champ(vitesse_convection_);
1496
1497 // TODO: I'd like the flag to work... But it is not updated yet. Please Help me, at Adrien Bruneton
1498 if (1 || divergence_free_velocity_extension_) // Problem for ABN : On n'a pas encore lu le param.ajouter qui passe mon flag a 1.
1499 {
1500 Cerr << "Fake Pressure gradient discretization" << finl;
1501 nom = Nom("gradient_pression_") + le_nom();
1502 dis.discretiser_champ("vitesse", un_domaine_dis,
1503 nom, "",
1504 -1 /* nb composantes par defaut */, 1 /* valeur temporelle */, temps,
1505 gradient_pression_);
1506 champs_compris.add(gradient_pression_.valeur());
1507 champs_compris_.ajoute_champ(gradient_pression_);
1508
1509 Cerr << "Fake Pressure discretization" << finl;
1510 nom = Nom("fake_pressure_") + le_nom();
1511 dis.discretiser_champ("pression",un_domaine_dis,nom,"Pa.m3/kg",1,1,temps,la_pression);
1512 champs_compris.add(la_pression.valeur());
1513 champs_compris_.ajoute_champ(la_pression);
1514
1515 Cerr << "Velocity (delta_u) divergence discretization" << finl;
1516 nom = Nom("divergence_delta_U_") + le_nom();
1517 dis.discretiser_champ("divergence_vitesse" /*directive */,un_domaine_dis, nom, "m3/s", 1,1,temps,divergence_delta_U);
1518 champs_compris.add(divergence_delta_U.valeur());
1519 champs_compris_.ajoute_champ(divergence_delta_U);
1520
1522 }
1524}
1525
1527{
1528 Nom type = "Assembleur_P_";
1529 type += discretisation().que_suis_je();
1530 //type += "_homogene";
1531 Cerr << "Navier_Stokes_std::discretiser_assembleur_pression : type="<< type << finl;
1532 assembleur_pression_.typer(type);
1533 assembleur_pression_->associer_domaine_dis_base(domaine_dis());
1534}
1535
1537{
1539 const Transport_Interfaces_FT_Disc& ft = ref_eq_interface_.valeur();
1540 const int ndist = ft.get_n_iterations_distance();
1541 if (stencil_width_ <= ndist)
1542 {
1543 Cerr << "The value of the stencil to compute mpoint should at least be strictly larger than "
1544 << "the width on which the distance is computed (given by n_iterations_distance in " << ft.que_suis_je() << ")" << finl;
1545 Cerr << "Current options : stencil= " << stencil_width_ << " and n_iterations_distance= " << ndist << " are invalid! Exiting." << finl;
1546 Process::exit();
1547 }
1549 {
1550 if (!solveur_pression_)
1551 {
1552 Cerr << "You are trying to make the extension of velocity divergence free. " << finl;
1553 Cerr << "A poisson solver is then required and should be defined in your equation by the addition of the optional keyword solveur_pression_fictive " << finl;
1554 Cerr << "as in e.g.: solveur_pression_fictive GCP { precond ssor { omega 1.5 } seuil 1e-15 impr } " << finl;
1555 Process::exit();
1556 }
1557 const Navier_Stokes_std& ns = ref_eq_ns_.valeur();
1558
1559 //
1560 // Build dummy Domaine_cl_dis object to pass to the assembleur_pression_ object:
1561 //
1562 // Step 0: Build string corresponding to the list of CLs we want to pass:
1563 SChaine instructions;
1564 instructions << "{" << finl;
1565 const Domaine& ladomaine=ns.domaine_dis().domaine();
1566 int nfront = ladomaine.nb_front_Cl();
1567 // The idea is to open the pressure on boundaries in contact with the other phase ie "(1-phase_)"
1568 // The goal is to let some fictitious pressure out (to accomodate for an (\int div(u_conv) dv !=0)
1569 for (int ifront=0; ifront<nfront; ifront++)
1570 {
1571 const Nom& nom_front = ladomaine.frontiere(ifront).le_nom();
1572 if (name_bc_opening_pressure_.contient_(nom_front))
1573 instructions << " " <<nom_front << " sortie_libre_rho_variable champ_front_uniforme 1 0" << finl;
1574 else
1575 instructions << " " <<nom_front << " symetrie" << finl;
1576 }
1577 instructions << "}" << finl;
1578 Cerr << "Interpretation de la chaine suivante:" << finl << instructions.get_str();
1579 EChaine is(instructions.get_str());
1580
1581 // Step 1: discretise (see Equation_base::discretiser())
1582 Cerr << "Discretisation of fictitious CL ..." << finl;
1583 zcl_fictitious_.typer("Domaine_Cl_VDF");
1584 Domaine_Cl_VDF& zcl_fictitious_vdf = ref_cast(Domaine_Cl_VDF, zcl_fictitious_.valeur());
1585 Domaine_VDF& domaine_vdf = ref_cast(Domaine_VDF, domaine_dis());
1586 zcl_fictitious_vdf.associer(domaine_vdf);
1587 zcl_fictitious_->associer_eqn(ns);
1588 // zcl_fictitious_->associer_inconnue(inconnue()); // Useless
1589
1590 // Step 2: read input (see Equation_base::lire_cl())
1591 Cerr << "Interpreting input string ..." << finl;
1592 is >> zcl_fictitious_vdf ;
1593
1594 // Step 3: completer (see Equation_base::completer())
1595 Cerr << "Completing fictitious CL ..." << finl;
1596 zcl_fictitious_->completer();
1597
1598 // Associate to the newly created zcl :
1599 // required because It's not a good plan to use ns.domaine_Cl_dis() because of outlet_BC
1600 assembleur_pression_->associer_domaine_cl_dis_base(zcl_fictitious_.valeur());
1601 assembleur_pression_->completer(ns); // Should it be associated to (*this) or ns?
1602 // I think it does not matter because Assembleur_base::completer is called and does nothing
1603 // On assemble la matrice de pression une seule et unique fois (puisqu'elle ne depend pas de rho...).
1604 assembleur_pression_->assembler(matrice_pression_);
1605 // Informe le solveur que la matrice a change :
1606 solveur_pression_->reinit();
1607 }
1608
1609 if ((Rc_GridN_ != 0)and(Rc_inject_>DMINFLOAT))
1610 {
1611 Cerr << "Check your datafile. Rc_GridN and Rc_inject should not but used simultaneously." << finl;
1612 Cerr << "Rc_tcl_GridN = " << Rc_GridN_ << finl;
1613 Cerr << "Rc_inject = " << Rc_inject_ <<finl;
1614 Process::exit();
1615 }
1616
1617 if ((Rc_inject_ == 0.) and is_reinject_activated() )
1618 {
1619 const Navier_Stokes_std& ns = ref_eq_ns_.valeur();
1620 const Domaine_Cl_dis_base& zcldis = ns.domaine_Cl_dis();
1621 int num_bord = -1;
1622 for (int i=0; i<zcldis.nb_cond_lim(); i++)
1623 {
1624 const Cond_lim& la_cl = zcldis.les_conditions_limites(i);
1625 // For each BC, we check its type to see if it's a wall:
1626 // BC for hydraulic equation
1627 bool is_wall = sub_type(Dirichlet_paroi_fixe,la_cl.valeur())
1628 || sub_type(Dirichlet_paroi_defilante,la_cl.valeur());
1629 if (is_wall)
1630 {
1631 num_bord = i;
1632 break;
1633 }
1634 }
1635 if (num_bord<0)
1636 Process::exit( "[Convection_Diffusion_Temperature_FT_Disc]: !!! NO WALL-TYPE BOUNDARY WAS FOUND IN THE DOMAINE, PLESEASE CHECK JDD" );
1637
1638 const Frontiere& fr=zcldis.les_conditions_limites(num_bord)-> frontiere_dis().frontiere();
1639 const int nb_face = fr.nb_faces();
1640 const Domaine_VDF& zvdf = ref_cast(Domaine_VDF, ns.domaine_dis());
1641 // supposing deltax = deltay in the first thermal layer
1642 if (nb_face>0)
1643 {
1644 const int num_face= fr.num_premiere_face();;
1645 int elem_voisin = zvdf.face_voisins(num_face, 0) + zvdf.face_voisins(num_face, 1) +1;
1646 const double cell_height = 2.*std::fabs(zvdf.dist_face_elem0(num_face,elem_voisin));
1647 Rc_inject_ = cell_height * Rc_GridN_;
1648 }
1650 Cerr << "[Convection_Diffusion_Temperature_FT_Disc] Rc_inject_ is set to " << Rc_inject_ << " according to provided Rc_GridN_ " << Rc_GridN_ << finl;
1651 }
1652 Rc_inject_ = std::fmax(Rc_inject_,DMINFLOAT);
1653}
1654
1655// Pour que milieu().mettre_a_jour(temps) ne plante pas...
1656// Et d'autres comme diffusivite_pour_transport...
1658{
1659 if (!fluide_dipha_)
1660 {
1661 Cerr << "You forgot to associate the diphasic fluid to the problem named " << probleme().le_nom() << finl;
1662 Process::exit();
1663 }
1664 // Cast non const cause acces const a fluide_phase!!
1665 return ref_cast_non_const(Milieu_base,fluide_dipha_->fluide_phase(phase_));
1666}
1668{
1669 if (!fluide_dipha_)
1670 {
1671 Cerr << "You forgot to associate the diphasic fluid to the problem named " << probleme().le_nom() << finl;
1672 Process::exit();
1673 }
1674 return fluide_dipha_->fluide_phase(phase_);
1675}
1676
1678{
1679 if (! sub_type(Fluide_Diphasique, un_milieu))
1680 {
1681 Cerr << "Erreur dans Convection_Diffusion_Temperature_FT_Disc::associer_milieu_base\n"
1682 << " On attendait un fluide diphasique" << finl;
1683 Cerr << "Error for Convection_Diffusion_Temperature_FT_Disc::associer_milieu_base\n"
1684 << "A Fluide_Diphasique medium was expected." << finl;
1685 Process::exit();
1686 }
1687 fluide_dipha_ = ref_cast(Fluide_Diphasique, un_milieu);
1688}
1689
1690/*! @brief Methode appelee par Transport_Interfaces_xxx::test_suppression_interfaces_sous_domaine() lorqu'une interfaces disparait.
1691 *
1692 * Il faut remettre la temperature de saturation dans
1693 * l'inclusion supprimee.
1694 *
1695 */
1697 const ArrOfInt& flags_compo_a_supprimer,
1698 int nouvelle_phase)
1699{
1700 // Si la nouvelle phase n'est pas la phase resolue, ne rien faire
1701 if (nouvelle_phase != phase_)
1702 return;
1703
1704 const int n = domaine_dis().domaine().nb_elem();
1705 assert(num_compo.size() == n);
1706 const int nb_valeurs_temporelles = inconnue().nb_valeurs_temporelles();
1707 // Il faut traiter toutes les cases temporelles:
1708 // selon l'ordre des equations dans le probleme, la roue a deja ete tournee ou pas...
1709 // Note B.M. est ce que c'est compatible avec la spec de ICOCO ? (modif
1710 // du temps n autorisee ???)
1711 for (int t = 0; t < nb_valeurs_temporelles; t++)
1712 {
1713 DoubleTab& temp = inconnue().futur(t);
1714 for (int i = 0; i < n; i++)
1715 {
1716 const int c = num_compo[i];
1717 if (c >= 0 && flags_compo_a_supprimer[c])
1718 temp[i] = TSAT_CONSTANTE;
1719 }
1721 }
1722}
1723
1725{
1726 set_is_solid_particle(ref_eq_interface_.valeur().get_is_solid_particle());
1728 ref_eq_interface_.valeur().associate_temp_equation_post_processing(*this);
1730// Si mpoint_ etait un champ inc? mpoint_.mettre_a_jour(schema_temps().temps_courant());
1732}
1733
1734// A few methods for TCL only:
1736{
1737 double interfacial_flux = 0.;
1738 const Domaine_Cl_dis_base& zcldis = domaine_Cl_dis();
1739 if (!sub_type(Domaine_Cl_VDF, zcldis))
1740 {
1741 Cerr << "Woops! Not VDF";
1742 Process::exit();
1743 }
1744 const Domaine_Cl_VDF& zclvdf = ref_cast(Domaine_Cl_VDF, zcldis);
1745 const Cond_lim& la_cl = zclvdf.la_cl_de_la_face(num_face);
1746 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1747 const Nom& bc_name = la_cl->frontiere_dis().le_nom();
1748 const int ndeb = le_bord.num_premiere_face();
1749// Cerr << " BC: " << la_cl.valeur() << " name: " << bc_name << finl;
1750// Cerr << "Dealing with face " << num_face << " belonging to BC " << la_cl.valeur();
1751 if ( sub_type(Neumann_paroi_adiabatique,la_cl.valeur()) )
1752 {
1753 Cerr << "paroi_adiabatique" << finl;
1754 return interfacial_flux;
1755 }
1756 else if ( sub_type(Neumann_paroi,la_cl.valeur()) )
1757 {
1758 Cerr << "paroi_flux_impose" << finl;
1759 const Neumann_paroi& la_cl_typee = ref_cast(Neumann_paroi, la_cl.valeur());
1760 double phi_imp = la_cl_typee.champ_front().valeurs()(num_face-ndeb); // Should it be valeurs instead of ?
1761 return phi_imp;
1762 }
1763 else if (sub_type(Echange_impose_base, la_cl.valeur()))
1764 {
1765 Cerr << "paroi_temperature_imposee (among other possibilities)" << finl;
1766 /* Le terme de flux calcule a partir du couple(h_imp,T_ext) s'ecrit :
1767 // h_t(T_ext - T_entier)*Surf
1768 // avec h_t : coefficient d'echange global.
1769 * */
1770 const Echange_impose_base& la_cl_typee = ref_cast(Echange_impose_base, la_cl.valeur());
1771 // Cerr << " Face " << num_face << " is actually #" << num_face-ndeb << " on this boundary." << finl;
1772 const double h = la_cl_typee.h_imp(num_face-ndeb);
1773 const double T_imp = la_cl_typee.T_ext(num_face-ndeb);
1774 // Cerr << " Reading coefficients h= " << h << " and T_imp= " << T_imp << " for heat flux evaluation." << finl;
1775 // The flux is between the wall and Tsat :
1776 interfacial_flux = h*(T_imp - TSAT_CONSTANTE); // What about the area? surf should be the interfacial area or come from the face area?
1777 // it is taken into account after this function.
1778 return interfacial_flux;
1779 }
1780 /* else if ( sub_type(paroi_contact,la_cl.valeur()) )
1781 {
1782 Cerr << que_suis_je() << "::get_flux_to_face() thermal BC " << la_cl.valeur()
1783 << " at face " << num_face << " not supported yet." << finl;
1784 Cerr << "The BC type " << la_cl << " for boundary "<< la_cl->champ_front().le_nom()
1785 << " is not supported yet."<< finl;
1786 Process::exit();
1787 } */
1788 else
1789 {
1790 Cerr << que_suis_je() << "::get_flux_to_face(). " ;
1791 Cerr << "The BC type " << la_cl.valeur() << " for boundary "<< bc_name
1792 << " is not supported yet."<< finl;
1793 Process::exit();
1794 }
1795 return interfacial_flux;
1796}
1797
1799{
1800 double flux=0., Twall=0.;
1801 get_flux_and_Twall(num_face,
1802 flux, Twall);
1803 return Twall;
1804}
1805
1807{
1808 //ArrOfInt num_faces;
1809 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis());
1810 const IntTab& elem_faces = domaine_vf.elem_faces();
1811 const IntTab& faces_elem = domaine_vf.face_voisins();
1812 const int nb_faces_voisins = elem_faces.dimension(1);
1813 // Struggle to get the boundary face
1814 int num_face=-1;
1815 int i;
1816 for (i=0; i<nb_faces_voisins; i++)
1817 {
1818 num_face = elem_faces(elem,i);
1819 // If it's a boundary face, one of the neighbours doesnot exist so it has "-1".
1820 // We detect a boundary that way:
1821 const int elemb = faces_elem(num_face, 0) + faces_elem(num_face, 1) +1;
1822 if (elem == elemb)
1823 {
1824 //num_faces[idx] = num_face;
1825 break;
1826 }
1827 }
1828 if (i==nb_faces_voisins)
1829 {
1830 Cerr << "Error. No boundary face found in this element "<< elem << finl;
1831 Process::exit();
1832 }
1833 double flux=0., Twall=0.;
1834 get_flux_and_Twall(num_face,
1835 flux, Twall);
1836 return Twall;
1837}
1838
1840 double& flux, double& Twall) const
1841{
1842 flux = 0.;
1843 const Domaine_Cl_dis_base& zcldis = domaine_Cl_dis();
1844 if (!sub_type(Domaine_Cl_VDF, zcldis))
1845 {
1846 Cerr << "Woops! Not VDF";
1847 Process::exit();
1848 }
1849 const Domaine_Cl_VDF& zclvdf = ref_cast(Domaine_Cl_VDF, zcldis);
1850 const Cond_lim& la_cl = zclvdf.la_cl_de_la_face(num_face);
1851 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1852 const Nom& bc_name = la_cl->frontiere_dis().le_nom();
1853 const int ndeb = le_bord.num_premiere_face();
1854// Cerr << " BC: " << la_cl.valeur() << " name: " << bc_name << finl;
1855// Cerr << "Dealing with face " << num_face << " belonging to BC " << la_cl.valeur();
1856 if ( sub_type(Neumann_paroi_adiabatique,la_cl.valeur()) )
1857 {
1858 Cerr << "paroi_adiabatique" << finl;
1859 flux = 0.;
1860 //
1861 Cerr << "How can we set Twall when temperature(elem) is not valid? Or is it?" << finl;
1862 Process::exit();
1863 }
1864 else if ( sub_type(Neumann_paroi,la_cl.valeur()) )
1865 {
1866 Cerr << "paroi_flux_impose" << finl;
1867 const Neumann_paroi& la_cl_typee = ref_cast(Neumann_paroi, la_cl.valeur());
1868 flux = la_cl_typee.champ_front().valeurs()(num_face-ndeb); // Should it be valeurs instead of ?
1869 //
1870 Cerr << "How can we set Twall when temperature(elem) is not valid? Or is it?" << finl;
1871 Process::exit();
1872 }
1873 else if (sub_type(Echange_impose_base, la_cl.valeur()))
1874 {
1875
1876 if (sub_type(Echange_contact_VDF_FT_Disc, la_cl.valeur()))
1877 {
1878 // Cerr << "Echange_contact_VDF_FT_Disc" << finl;
1879 /* Le terme de flux calcule a partir du (phi_ext) s'ecrit :
1880 // phi_ext_*Surf
1881 // avec phi_ext : heat flux density at the surface.
1882 * */
1883 const Echange_contact_VDF_FT_Disc& la_cl_typee = ref_cast(Echange_contact_VDF_FT_Disc, la_cl.valeur());
1884 // Cerr << " Face " << num_face << " is actually #" << num_face-ndeb << " on this boundary." << finl;
1885 const double h = la_cl_typee.h_imp(num_face-ndeb);
1886 const double T_imp = la_cl_typee.Ti_wall(num_face-ndeb);
1887 // Cerr << " Reading coefficients h= " << h << " and T_imp= " << T_imp << " for heat flux evaluation." << finl;
1888 // We keep the term + h*(T_imp - TSAT_CONSTANTE) as h = 0.;
1889 //
1890 flux = la_cl_typee.flux_exterieur_impose(num_face-ndeb) + h*(T_imp - TSAT_CONSTANTE);
1891 Twall = T_imp;
1892 }
1893 else
1894 {
1895 Cerr << "paroi_temperature_imposee (among other possibilities)" << finl;
1896 /* Le terme de flux calcule a partir du couple(h_imp,T_ext) s'ecrit :
1897 // h_t(T_ext - T_entier)*Surf
1898 // avec h_t : coefficient d'echange global.
1899 * */
1900 const Echange_impose_base& la_cl_typee = ref_cast(Echange_impose_base, la_cl.valeur());
1901 // Cerr << " Face " << num_face << " is actually #" << num_face-ndeb << " on this boundary." << finl;
1902 const double h = la_cl_typee.h_imp(num_face-ndeb);
1903 const double T_imp = la_cl_typee.T_ext(num_face-ndeb);
1904
1905 // Cerr << " Reading coefficients h= " << h << " and T_imp= " << T_imp << " for heat flux evaluation." << finl;
1906 // The flux is between the wall and Tsat :
1907 flux = h*(T_imp - TSAT_CONSTANTE); // What about the area? surf should be the interfacial area or come from the face area?
1908 // it is taken into account after this function.
1909 Twall = T_imp;
1910
1911 }
1912 }
1913 /* else if ( sub_type(paroi_contact,la_cl.valeur()) )
1914 {
1915 Cerr << que_suis_je() << "::get_flux_to_face() thermal BC " << la_cl.valeur()
1916 << " at face " << num_face << " not supported yet." << finl;
1917 Cerr << "The BC type " << la_cl << " for boundary "<< la_cl->champ_front().le_nom()
1918 << " is not supported yet."<< finl;
1919 Process::exit();
1920 } */
1921 else
1922 {
1923 Cerr << que_suis_je() << "::get_flux_and_Twall(). " ;
1924 Cerr << "The BC type " << la_cl.valeur() << " for boundary "<< bc_name
1925 << " is not supported yet."<< finl;
1926 Process::exit();
1927 }
1928}
1929
1930
1932{
1933 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF, domaine_dis());
1934 const IntTab& faces_elem = domaine_vf.face_voisins();
1935 // On of the neighbours doesnot exist so it has "-1". We get the other elem by:
1936 const int elem = faces_elem(num_face, 0) + faces_elem(num_face, 1) +1;
1937 const DoubleTab& temperature = inconnue().valeurs();
1938
1939 double P[3] = {0.,0.,0.}, xyz_face[3] = {0.,0.,0.};
1940 xyz_face[0] = domaine_vf.xv(num_face,0);
1941 xyz_face[1] = domaine_vf.xv(num_face,1);
1942 P[0] = domaine_vf.xp(elem, 0);
1943 P[1] = domaine_vf.xp(elem, 1);
1944 if (Objet_U::dimension == 3)
1945 {
1946 xyz_face[2] = domaine_vf.xv(num_face,2);
1947 P[2] = domaine_vf.xp(elem, 2);
1948 }
1949
1950 double d=0;
1951 for (int i=0; i<3; i++)
1952 d += (xyz_face[i] - P[i])*(xyz_face[i] - P[i]);
1953 d= sqrt(d);
1954 const double flux = get_flux_to_face(num_face);
1955 const double k = fluide_dipha_->fluide_phase(phase_).conductivite().valeurs()(0,0);
1956// Cerr << "flux/d/k" << flux << " " << d << " " << k << finl;
1957 // flux is incoming. So "-flux" is needed.
1958 const double Twall = temperature(elem) - d/k*flux;
1959// Cerr << "We have Twall = "<< Twall << " at face= " << num_face << " elem= " << elem << finl;
1960 return Twall;
1961}
1962
1964{
1965 return TSAT_CONSTANTE;
1966}
Classe Champ_Inc_base.
DoubleTab & futur(int i=1) override
Renvoie les valeurs du champs a l'instant t+i.
DoubleTab & passe(int i=1) override
Renvoie les valeurs du champs a l'instant t-i.
virtual int nb_valeurs_temporelles() const
Renvoie le nombre de valeurs temporelles actuellement conservees.
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
virtual DoubleTab & valeurs()=0
classe Champ_base Cette classe est la base de la hierarchie des champs.
Definition Champ_base.h:43
virtual DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ.
Champ_front_base & champ_front()
classe Cond_lim Classe generique servant a representer n'importe quelle classe
Definition Cond_lim.h:31
int lire_motcle_non_standard(const Motcle &, Entree &) override
Lecture des parametres de type non simple d'un objet_U a partir d'un flot d'entree.
void associer_milieu_base(const Milieu_base &milieu) override
Associe un milieu physique a l'equation, le milieu est en fait caste en Fluide_base.
int preparer_calcul() override
Tout ce qui ne depend pas des autres problemes eventuels.
void completer() override
Complete la construction (initialisation) des objets associes a l'equation.
void get_flux_and_Twall(const int num_face, double &flux, double &Twall) const
void calculer_grad_t()
met a jour le champ grad_t en fonction du champ inconnue.
DoubleTab & derivee_en_temps_inco(DoubleTab &) override
Returns the time derivative of the unknown I of the equation: dI/dt = M-1*(sum(operators(I) + sources...
LIST(OBS_PTR(Champ_base)) liste_champs_compris_
void mettre_a_jour(double temps) override
La valeur de l'inconnue sur le pas de temps a ete calculee.
OBS_PTR(Fluide_Diphasique) fluide_dipha_
virtual void suppression_interfaces(const IntVect &num_compo, const ArrOfInt &flags_compo_a_supprimer, int nouvelle_phase)
Methode appelee par Transport_Interfaces_xxx::test_suppression_interfaces_sous_domaine() lorqu'une in...
classe Convection_Diffusion_Temperature Cas particulier de Convection_Diffusion_std
const Champ_Inc_base & inconnue() const override
const Champ_base & get_champ(const Motcle &nom) const override
DoubleTab & derivee_en_temps_inco(DoubleTab &) override
Returns the time derivative of the unknown I of the equation: dI/dt = M-1*(sum(operators(I) + sources...
int lire_motcle_non_standard(const Motcle &, Entree &) override
Lecture des parametres de type non simple d'un objet_U a partir d'un flot d'entree.
int lire_motcle_non_standard(const Motcle &, Entree &) override
Lecture des parametres de type non simple d'un objet_U a partir d'un flot d'entree.
classe Dirichlet_paroi_defilante Impose la vitesse de paroi dnas une equation de type Navier_Stokes.
classe Dirichlet_paroi_fixe Represente une paroi immobile dans une equation de type Navier_Stokes.
classe Discretisation_base Cette classe represente un schema de discretisation en espace,...
virtual Nom get_name_of_type_for(const Nom &class_operateur, const Nom &type_operteur, const Equation_base &eqn, const OBS_PTR(Champ_base)&champ_supp=OBS_PTR(Champ_base)()) const
remplit le Nom type en focntion de la classe de operateur, du type de l'operateur et de l'equation
void discretiser_champ(const Motcle &directive, const Domaine_dis_base &z, const Nom &nom, const Nom &unite, int nb_comp, int nb_pas_dt, double temps, OWN_PTR(Champ_Inc_base)&champ, const Nom &sous_type=NOM_VIDE) const
const Sous_Domaine_t & ss_domaine(int i) const
Definition Domaine.h:290
int nb_front_Cl() const
Definition Domaine.h:236
const Frontiere_t & frontiere(int i) const
Definition Domaine.h:539
int_t nb_elem() const
Definition Domaine.h:131
class Domaine_Cl_VDF
void completer(const Domaine_dis_base &) override
const Cond_lim & la_cl_de_la_face(int numfa) const override
A partir d'un indice de face de bord dans le Domaine_VF, renvoie la condition aux limites a laquelle ...
void associer(const Domaine_dis_base &) override
classe Domaine_Cl_dis_base Les objets Domaine_Cl_dis_base representent les conditions aux limites
int nb_cond_lim() const
Renvoie le nombre de conditions aux limites.
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
class Domaine_VDF
Definition Domaine_VDF.h:64
double dist_face_elem0(int, int) const override
Fonction de calcul utilisable uniquement en coordonnees cartesiennes de la distance entre le centre d...
class Domaine_VF
Definition Domaine_VF.h:44
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
double xv(int num_face, int k) const
Definition Domaine_VF.h:76
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
double xp(int num_elem, int k) const
Definition Domaine_VF.h:77
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
Une entree dont la source est une chaine de caracteres.
Definition EChaine.h:31
: class Echange_contact_VDF_FT_Disc
virtual double Ti_wall(int num) const
virtual double flux_exterieur_impose(int i) const
classe Echange_impose_base: Cette condition limite sert uniquement pour l'equation d'energie.
virtual double h_imp(int num) const
Renvoie la valeur du coefficient d'echange de chaleur impose sur la i-eme composante.
virtual double T_ext(int num) const
Renvoie la valeur de la temperature imposee sur la i-eme composante du champ de frontiere.
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....
const Nom & le_nom() const override
Renvoie le nom de l'equation.
const Discretisation_base & discretisation() const
Renvoie la discretisation associee a l'equation.
Solveur_Masse_base & solv_masse()
Renvoie le solveur de masse associe a l'equation.
virtual void mettre_a_jour(double temps)
La valeur de l'inconnue sur le pas de temps a ete calculee.
virtual void completer()
Complete la construction (initialisation) des objets associes a l'equation.
virtual int preparer_calcul()
Tout ce qui ne depend pas des autres problemes eventuels.
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Renvoie le domaine des conditions aux limite discretisee associee a l'equation.
Probleme_base & probleme()
Renvoie le probleme associe a l'equation.
Schema_Temps_base & schema_temps()
Renvoie le schema en temps associe a l'equation.
virtual void discretiser()
Discretise l'equation.
Champs_compris champs_compris_
Domaine_dis_base & domaine_dis()
Renvoie le domaine discretise associe a l'equation.
const Nom & le_nom() const override
Renvoie le nom du champ.
class Front_VF
Definition Front_VF.h:36
int num_premiere_face() const
Definition Front_VF.h:63
int_t num_premiere_face() const
Definition Frontiere.h:67
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Frontiere.h:49
int_t nb_faces() const
Renvoie le nombre de faces de la frontiere.
Definition Frontiere.h:59
: class Maillage_FT_Disc Cette classe decrit un maillage:
int get_mesh_tag() const
return mesh_state_tag_
classe Milieu_base Cette classe est la base de la hierarchie des milieux (physiques)
Definition Milieu_base.h:50
void associer_eqn(const Equation_base &)
Associe une equation a l'objet.
Definition MorEqn.cpp:27
Une chaine de caractere (Nom) en majuscules.
Definition Motcle.h:26
void calculer_delta_u_interface(Champ_base &u0, int phase_pilote, int ordre, const bool future_or_past=false)
Calcul du saut de vitesse a l'interface du au changement de phase.
const DoubleTab & get_interfacial_area() const
virtual const Champ_base & calculer_div_normale_interface()
classe Navier_Stokes_std Cette classe porte les termes de l'equation de la dynamique
const Champ_Inc_base & inconnue() const override
Renvoie la vitesse (champ inconnue de l'equation) (version const).
Classe Neumann_paroi_adiabatique Cette condition limite correspond a une paroi adiabatique dans une.
Classe Neumann_paroi Cette condition limite correspond a un flux impose pour l'equation de.
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
Nom & suffix(const char *const)
Extraction de suffixe : Nom x("azerty");.
Definition Nom.cpp:271
static int dimension
Definition Objet_U.h:99
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
classe Operateur_Div Classe generique de la hierarchie des operateurs calculant la divergence
Operateur_base & l_op_base() override
Renvoie l'objet sous-jacent upcaste en Operateur_base.
void typer() override
Type l'operateur: se type "Op_div_"+discretisation()+.
DoubleTab & calculer(const DoubleTab &, DoubleTab &) const override
Initialise le tableau passe en parametre avec la contribution de l'operateur.
Classe Operateur_Grad Classe generique de la hierarchie des operateurs calculant le gradient.
DoubleTab & calculer(const DoubleTab &, DoubleTab &) const override
Initialise le tableau passe en parametre avec la contribution de l'operateur.
Operateur_base & l_op_base() override
Renvoie l'objet sous-jacent upcaste en Operateur_base.
void typer() override
Type l'operateur: se type "Op_Grad_"+discretisation()+.
virtual void associer(const Domaine_dis_base &, const Domaine_Cl_dis_base &, const Champ_Inc_base &inco)=0
void associer_eqn(const Equation_base &)
Associe une equation a l'operateur.
const Nom & type() const
Renvoie le (nom du) type de l'operateur a creer.
virtual void completer()
Met a jour les references des objets associes a l'operateur.
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter_flag(const char *keyword, const bool *value)
Register a boolean flag whose mere presence switches it to true.
Definition Param.cpp:474
void ajouter_condition(const char *condition, const char *message, const char *name=0)
Declare a post-read logical condition that must hold on the parameter values.
Definition Param.cpp:496
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
@ OPTIONAL
Definition Param.h:115
@ REQUIRED
Definition Param.h:115
void ajouter_non_std(const char *keyword, const Objet_U *value, Param::Nature nat=Param::OPTIONAL)
Register a keyword handled by Objet_U::lire_motcle_non_standard.
Definition Param.cpp:489
classe Parametre_implicite Un objet Parametre_implicite est un objet regroupant les differentes
virtual const Transport_Interfaces_FT_Disc & equation_interfaces(const Motcle &nom) const
virtual const Navier_Stokes_FT_Disc & equation_hydraulique(const Motcle &nom) const
const Triple_Line_Model_FT_Disc & tcl() 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
static double mp_max(double)
Definition Process.cpp:376
static double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
static void barrier()
Synchronise tous les processeurs du groupe courant (attend que tous les processeurs soient arrives a ...
Definition Process.cpp:136
static 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
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
double temps_courant() const
Renvoie le temps courant.
double pas_de_temps() const
Renvoie le pas de temps (delta_t) courant.
virtual int nb_valeurs_temporelles() const =0
classe Solveur_Masse_base Represente la matrice de masse d'une equation.
Classe de base des flux de sortie.
Definition Sortie.h:52
int_t nb_elem_tot() const
_SIZE_ size_array() const
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
int nb_dim() const
Definition TRUSTTab.h:199
_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")
const Champ_Inc_base & inconnue() const override
const Champ_base & get_indicatrice() override
getter champ variables_internes_->indicatrice_cache a partir de la position des interfaces.
virtual const Champ_base & get_normale_interface() const
const Maillage_FT_Disc & maillage_interface() const
virtual const Champ_base & get_distance_interface() const
virtual const int & get_n_iterations_distance() const
void corriger_mpoint(DoubleTab &mpoint) const