TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Navier_Stokes_std.cpp
1/****************************************************************************
2* Copyright (c) 2026, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <Transport_Interfaces_base.h>
17#include <MD_Vector_composite.h>
18#include <Matrice_Morse_Sym.h>
19#include <Navier_Stokes_std.h>
20#include <Frontiere_dis_base.h>
21#include <Schema_Temps_base.h>
22#include <MD_Vector_tools.h>
23#include <Assembleur_base.h>
24#include <TRUSTTab_parts.h>
25#include <communications.h>
26#include <Champ_Uniforme.h>
27#include <MD_Vector_std.h>
28#include <solv_iteratif.h>
29#include <Probleme_base.h>
30#include <Discret_Thyd.h>
31#include <Fluide_base.h>
32#include <Domaine_VF.h>
33#include <TRUSTTrav.h>
34#include <SFichier.h>
35#include <Domaine.h>
36#include <Param.h>
37#include <Avanc.h>
38#include <Debog.h>
39
40#include <TRUST_2_PDI.h>
41
42Implemente_instanciable_sans_constructeur(Navier_Stokes_std,"Navier_Stokes_standard",Equation_base);
43// XD navier_stokes_standard eqn_base navier_stokes_standard INHERITS_BRACE Navier-Stokes equations.
44
56
58{
59 return Equation_base::printOn(is);
60}
61
62/*! @brief Appel Equation_base::readOn(Entree& is) En sortie verifie que l'on a bien lu:
63 *
64 * - le terme diffusif,
65 * - le terme convectif,
66 * - le solveur en pression
67 *
68 * @param (Entree& is) un flot d'entree
69 * @return (Entree&) le flot d'entree modifie
70 * @throws terme diffusif non specifie dans jeu de donnees, specifier
71 * un type negligeable pour l'operateur si il est a negliger
72 * @throws terme convectif non specifie dans jeu de donnees, specifier
73 * un type negligeable pour l'operateur si il est a negliger
74 * @throws solveur pression non defini dans jeu de donnees
75 */
77{
79 if (est_egal(seuil_projection,0.) && (sub_type(solv_iteratif,solveur_pression_.valeur())))
80 {
81 solv_iteratif& solv_iter = ref_cast(solv_iteratif,solveur_pression_.valeur());
82 seuil_projection = solv_iter.get_seuil();
83 }
84
85 terme_convectif.set_fichier("Convection_qdm");
86 terme_convectif.set_description("Momentum flow rate=Integral(rho*u*u*ndS) [N] if SI units used");
87 terme_diffusif.set_fichier("Contrainte_visqueuse");
88 terme_diffusif.set_description("Friction drag exerted by the fluid=Integral(-mu*(grad(u) +grad(u)^T)*ndS) [N] if SI units used");
89 divergence.set_fichier("Debit");
90 divergence.set_description((Nom)"Volumetric flow rate=Integral(u*ndS) [m"+(Nom)(dimension+bidim_axi)+".s-1] if SI units used");
91 gradient.set_fichier("Force_pression");
92 gradient.set_description("Pressure drag exerted by the fluid=Integral(P*ndS) [N] if SI units used");
93
94 return is;
95}
96
98{
100 param.ajouter_non_std("diffusion",(this));
101 param.ajouter_non_std("convection",(this));
102 param.ajouter_condition("is_read_diffusion","The diffusion operator must be read, select negligeable type if you want to neglect it.");
103 param.ajouter_condition("is_read_convection","The convection operator must be read, select negligeable type if you want to neglect it.");
104 param.ajouter_non_std("solveur_pression",(this),Param::REQUIRED); // XD attr solveur_pression solveur_sys_base solveur_pression OPT Linear pressure system resolution method.
105 param.ajouter_non_std("dt_projection",(this)); // XD attr dt_projection deuxmots dt_projection OPT nb value : This
106 // XD_CONT keyword checks every nb time-steps the equality of velocity divergence to zero. value is the criteria
107 // XD_CONT convergency for the solver used.
108 param.ajouter_non_std("Traitement_particulier",(this)); // XD attr traitement_particulier traitement_particulier traitement_particulier OPT Keyword to post-process particular values.
109 param.ajouter_non_std("Erreur_max_DivU",(this));
110 param.ajouter("uzawa",&seuil_uzawa);
111 //param.ajouter_non_std("vitesse_transportante",(this));
112 param.ajouter_non_std("seuil_divU",(this)); // XD attr seuil_divU floatfloat seuil_divU OPT value factor : this
113 // XD_CONT keyword is intended to minimise the number of iterations during the pressure system resolution. The
114 // XD_CONT convergence criteria during this step (\'seuil\' in solveur_pression) is dynamically adapted according to
115 // XD_CONT the mass conservation. At tn , the linear system Ax=B is considered as solved if the residual
116 // XD_CONT ||Ax-B||<seuil(tn). For tn+1, the threshold value seuil(tn+1) will be evualated as: NL2 If (
117 // XD_CONT |max(DivU)*dt|<value ) NL2 Seuil(tn+1)= Seuil(tn)*factor NL2 Else NL2 Seuil(tn+1)= Seuil(tn)*factor NL2
118 // XD_CONT Endif NL2 The first parameter (value) is the mass evolution the user is ready to accept per timestep, and
119 // XD_CONT the second one (factor) is the factor of evolution for \'seuil\' (for example 1.1, so 10% per timestep).
120 // XD_CONT Investigations has to be lead to know more about the effects of these two last parameters on the behaviour
121 // XD_CONT of the simulations.
122 param.ajouter_non_std("solveur_bar",(this)); // XD attr solveur_bar solveur_sys_base solveur_bar OPT This keyword is
123 // XD_CONT used to define when filtering operation is called (typically for EF convective scheme, standard diffusion
124 // XD_CONT operator and Source_Qdm_lambdaup ). A file (solveur.bar) is then created and used for inversion procedure.
125 // XD_CONT Syntax is the same then for pressure solver (GCP is required for multi-processor calculations and, in a
126 // XD_CONT general way, for big meshes).
127 param.ajouter("projection_initiale",&projection_initiale); // XD attr projection_initiale entier projection_initiale OPT Keyword to suppress, if boolean equals 0, the initial projection which checks DivU=0. By default, boolean equals 1.
128 param.ajouter_flag("postraiter_gradient_pression_sans_masse", &postraiter_gradient_pression_sans_masse_); // XD attr postraiter_gradient_pression_sans_masse rien postraiter_gradient_pression_sans_masse OPT Avoid mass matrix multiplication for the gradient postprocessing
129 param.ajouter_non_std("methode_calcul_pression_initiale",(this)); // XD attr methode_calcul_pression_initiale chaine(into=["avec_les_cl","avec_sources","avec_sources_et_operateurs","sans_rien"]) methode_calcul_pression_initiale OPT Keyword to select an option for the pressure calculation before the fist time step. Options are : avec_les_cl (default option lapP=0 is solved with Neuman boundary conditions on pressure if any), avec_sources (lapP=f is solved with Neuman boundaries conditions and f integrating the source terms of the Navier-Stokes equations) and avec_sources_et_operateurs (lapP=f is solved as with the previous option avec_sources but f integrating also some operators of the Navier-Stokes equations). The two last options are useful and sometime necessary when source terms are implicited when using an implicit time scheme to solve the Navier-Stokes equations.
130}
131
133{
134 if (mot=="diffusion")
135 {
136 Cerr << "Reading and typing of the diffusion operator : " << finl;
137 terme_diffusif.associer_diffusivite(diffusivite_pour_transport());
138 is >> terme_diffusif;
139 // le champ pour le dt_stab est le meme que celui de l'operateur
140 terme_diffusif.associer_diffusivite_pour_pas_de_temps(diffusivite_pour_pas_de_temps());
141 return 1;
142 }
143 else if (mot=="convection")
144 {
145 Cerr << "Reading and typing of the convection operator : " << finl;
146 const Champ_base& vitesse_transportante = vitesse_pour_transport();
147 terme_convectif.associer_vitesse(vitesse_transportante);
148 is >> terme_convectif;
149 return 1;
150 }
151 else if (mot=="solveur_pression")
152 {
153 Cerr << "Reading and typing of pressure solver : " << finl;
154 is >> solveur_pression_;
155 Cerr<<"Pressure solver type : "<<solveur_pression_->que_suis_je()<< finl;
156 solveur_pression_.nommer("solveur_pression");
157 return 1;
158 }
159 else if (mot=="dt_projection")
160 {
161 Cerr << "Reading projection time step " << finl;
162 is >> dt_projection;
163 is >> seuil_projection;
164 return 1;
165 }
166 else if (mot=="Traitement_particulier")
167 {
168 Cerr << "Reading and typing of Traitement_particulier considered : " << finl;
169 Nom type="Traitement_particulier_NS_";
170 Motcle motbidon;
171 Motcle accouverte = "{" , accfermee = "}" ;
172 is >> motbidon;
173 if (motbidon == accouverte)
174 {
175 Motcle le_cas;
176 is >> le_cas;
177 if (le_cas == accfermee)
178 le_cas ="";
179 else
180 {
181 type+= le_cas;
182 type+= "_";
183 }
185 if (discr == "VEFPreP1B")
186 discr = "VEF";
187 type+=discr;
188 Cerr << type << finl;
189 le_traitement_particulier.typer(type);
190 le_traitement_particulier->associer_eqn(*this);
191 le_traitement_particulier->lire(is);
192 }
193 else
194 {
195 Cerr << "Error while reading Traitement_particulier for Navier_Stokes_standard equation";
196 Cerr << "A { was expected." << finl;
197 exit();
198 }
199 return 1;
200 }
201 else if (mot=="Erreur_max_DivU")
202 {
203 Cerr << "Reading DivU maximum" << finl;
204 is >> max_div_U;
205 is >> seuil_projection;
206 return 1;
207 }
208 else if (mot=="seuil_divU")
209 {
210 Cerr << "Reading the threshold value for the velocity divergence " << finl;
211 is >> seuil_divU;
212 is >> raison_seuil_divU;
213 return 1;
214 }
215 else if (mot=="solveur_bar")
216 {
217 Motcle motlu;
218 Motcle accouverte = "{" , accfermee = "}" ;
219 Nom type_solv("");
220 int acc=0;
221 int ok=0;
222 while (acc!=0 || !ok)
223 {
224 is >> motlu;
225 if (motlu==accouverte)
226 {
227 ok=1;
228 acc++;
229 };
230 if (motlu==accfermee) acc--;
231 type_solv+=" ";
232 type_solv+=motlu;
233 }
234 if (je_suis_maitre())
235 {
236 SFichier s("solveur.bar");
237 s<<type_solv<<finl;
238 s.close();
239 }
240 return 1;
241 }
242 else if (mot=="methode_calcul_pression_initiale")
243 {
244 Motcle methode;
245 is >> methode;
246 Motcles compris(4);
247 compris[0]="avec_les_cl";
248 compris[1]="avec_sources";
249 compris[2]="avec_sources_et_operateurs";
250 compris[3]="sans_rien";
253 {
254 Cerr<<methode<<" is not understood."<<finl;
255 Cerr<<" Allowed keywords are :"<<compris<<finl;
256 exit();
257 }
258 return 1;
259 }
260 else
262}
263
268
270{
271 return terme_diffusif.diffusivite();
272}
273
275{
276 return la_vitesse;
277}
278
279
280/*! @brief S'associe au probleme: apelle Equation_base::associer_pb_base(const Probleme_base&)
281 *
282 * s'associe avec les operateurs de divergence et de gradient.
283 *
284 * @param (Probleme_base& pb) le probleme auquel s'associer
285 */
287{
289 divergence.associer_eqn(*this);
290 gradient.associer_eqn(*this);
291}
292
293/*! @brief Complete l'equation base, associe la pression a l'equation,
294 *
295 * complete la divergence, le gradient et le solveur pression.
296 * Ajout de 2 termes sources: l'un representant la force centrifuge
297 * dans le cas axi-symetrique,l'autre intervenant dans la resolution
298 * en 2D axisymetrique
299 * Association d une equation de transport d interface a l ensemble
300 * de points suivis si le fluide est marque
301 *
302 */
304{
305 if (axi == 1)
306 {
307 Source t;
308 Source& so=les_sources.add(t);
309 Cerr << "Centrifuge force term creation for Axi case."<< finl;
310 Nom type_so = "Force_Centrifuge_";
311 Nom disc = discretisation().que_suis_je();
312 Nom champ = inconnue().que_suis_je();
313 champ.suffix("Champ_");
314 type_so+=disc;
315 type_so+="_";
316 type_so+=champ;
317 type_so += "_Axi";
318 so.typer_direct(type_so);
319 so->associer_eqn(*this);
320 }
321
323
324 // On ne decline pas le residu par composantes pour la vitesse:
326
327 la_pression->associer_eqn(*this);
328 la_pression->completer(le_dom_Cl_dis.valeur());
329 // [ABN] make sure the pressure knows the domaine_Cl_dis to be able to use specific postreatment like 'gravcl'
330 la_pression->associer_domaine_cl_dis(le_dom_Cl_dis);
331
332 divergence_U->associer_eqn(*this);
333 if (gradient_P) gradient_P->associer_eqn(*this);
334 la_pression_en_pa->associer_eqn(*this);
335 la_pression_en_pa->completer(le_dom_Cl_dis.valeur());
336 la_pression_en_pa->associer_domaine_cl_dis(le_dom_Cl_dis);
337 divergence.completer();
338 gradient.completer();
339 assembleur_pression_->associer_domaine_cl_dis_base(domaine_Cl_dis());
340 assembleur_pression_->completer(*this);
341
342 if (distance_paroi_globale)// On initialize la distance au bord au debut du calcul si on en a besoin, ce ne sera plus mis a jour par la suite car le maillage est fixe ; on le fait tard car il faut avoir lu les CL
343 {
344 Domaine_dis_base& domaine = domaine_dis();
345 domaine.init_dist_paroi_globale(domaine_Cl_dis().les_conditions_limites());
346 Cerr << "Initializing distance_paroi_globale ... " << finl;
347 const DoubleTab& dist_calc = domaine.y_elem();
348 for (int e = 0 ; e < domaine.nb_elem() ; e++) distance_paroi_globale->valeurs()(e, 0) = dist_calc(e);
349 distance_paroi_globale->valeurs().echange_espace_virtuel();
350 }
351
352}
353
355{
357}
358
359/*! @brief Dicretise l'equation.
360 *
361 */
363{
364 Cerr << "Hydraulic equation discretization (Navier_Stokes_std::discretiser)" << finl;
365 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
366
368 la_vitesse->add_synonymous(Nom("velocity"));
369 champs_compris_.ajoute_champ(la_vitesse);
370
372 la_pression->add_synonymous(Nom("P_star"));
373 champs_compris_.ajoute_champ(la_pression);
374
376 la_pression_en_pa->add_synonymous(Nom("Pressure"));
378
379
382 divergence.typer();
383 divergence.l_op_base().associer_eqn(*this);
384 gradient.typer();
385 gradient.l_op_base().associer_eqn(*this);
386
387
388 champs_compris_.ajoute_champ(divergence_U);
389
390
391 // Appel a la methode virtuelle de discretisation de l'assembleur pression:
393
395}
396
398{
399 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
400 dis.vitesse(schema_temps(), domaine_dis(), la_vitesse);
401}
402
409
410/*! @brief Typage de l'assembleur pression.
411 *
412 * Le nom de l'assembleur utilise est construit comme :
413 * Assembleur_P_xxx" ou "xxx" est le nom de la discretisation.
414 * Cette methode est virtuelle et surchargee dans le front-tracking.
415 * Elle est appelee par Navier_Stokes_std::discretiser()
416 *
417 */
418
420{
421 Nom type = "Assembleur_P_";
422 type += discretisation().que_suis_je();
423 Cerr << "Navier_Stokes_std::discretiser_assembleur_pression : type="<< type << finl;
424 assembleur_pression_.typer(type);
425 assembleur_pression_->associer_domaine_dis_base(domaine_dis());
426}
427
429{
430 if (!probleme().domaine().mesh_update_required()) return;
431
432 if (!probleme().is_dilatable())
433 assembleur_pression_->assembler(matrice_pression_);
434 else
435 assembleur_pression_->assembler_QC(fluide().masse_volumique().valeurs(), matrice_pression_);
436
437 solveur_pression_->reinit();
438}
439
440/*! @brief Renvoie le nombre d'operateurs de l'equation: Pour Navier Stokes Standard c'est 2.
441 *
442 * @return (int) le nombre d'operateur de l'equation
443 */
445{
446 return 2;
447}
448
450{
451 return 4;
452}
453
454/*! @brief Renvoie le i-eme operateur de l'equation: - le terme_diffusif si i = 0
455 *
456 * - le terme_convectif si i = 1
457 * exit si i>1
458 * (version const)
459 *
460 * @param (int i) l'index de l'operateur a renvoyer
461 * @return (Operateur&) l'operateur indexe par i
462 */
464{
465 switch(i)
466 {
467 case 0:
468 return terme_diffusif;
469 case 1:
470 return terme_convectif;
471 default :
472 Cerr << "Error for Navier_Stokes_std::operateur(int i)" << finl;
473 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" operators "<<finl;
474 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
475 exit();
476 }
477 // Pour les compilos!!
478 return terme_diffusif;
479}
480
481/*! @brief Renvoie le i-eme operateur de l'equation: - le terme_diffusif si i = 0
482 *
483 * - le terme_convectif si i = 1
484 * exit si i>1
485 *
486 * @param (int i) l'index de l'operateur a renvoyer
487 * @return (Operateur&) l'operateur indexe par i
488 */
490{
491 switch(i)
492 {
493 case 0:
494 return terme_diffusif;
495 case 1:
496 return terme_convectif;
497 default :
498 Cerr << "Error for Navier_Stokes_std::operateur(int i)" << finl;
499 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" operators "<<finl;
500 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
501 exit();
502 }
503 // Pour les compilos!!
504 return terme_diffusif;
505}
506
508{
509 switch(i)
510 {
511 case 0:
512 return gradient;
513 case 1:
514 return divergence;
515 default :
516 Cerr << "Error for Navier_Stokes_std::operateur_fonctionnel(int i)" << finl;
517 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" functional operators "<<finl;
518 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
519 exit();
520 }
521 // Pour les compilos!!
523}
524
526{
527 switch(i)
528 {
529 case 0:
530 return gradient;
531 case 1:
532 return divergence;
533 default :
534 Cerr << "Error for Navier_Stokes_std::operateur_fonctionnel(int i)" << finl;
535 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" functional operators "<<finl;
536 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
537 exit();
538 }
539 // Pour les compilos!!
541}
542
543
544/*! @brief Renvoie l'operateur de calcul de la divergence associe a l'equation.
545 *
546 * @return (Operateur_Div&) l'operateur de calcul de la divergence.
547 */
552
553/*! @brief Renvoie l'operateur de calcul de la divergence associe a l'equation.
554 *
555 * (version const)
556 *
557 * @return (Operateur_Div&) l'operateur de calcul de la divergence
558 */
563
564/*! @brief Renvoie l'operateur de calcul du gradient associe a l'equation.
565 *
566 * @return (Operateur_Grad&) l'operateur de calcul du gradient
567 */
572
577
582
583/*! @brief Renvoie l'operateur de calcul du gradient associe a l'equation.
584 *
585 * (version const)
586 *
587 * @return (Operateur_Grad&) l'operateur de calcul du gradient
588 */
593
594
595/*! @brief Renvoie la vitesse (champ inconnue de l'equation) (version const)
596 *
597 * @return (Champ_Inc_base&) le champ inconnue representant la vitesse
598 */
600{
601 return la_vitesse.valeur();
602}
603
604/*! @brief Renvoie la vitesse (champ inconnue de l'equation)
605 *
606 * @return (Champ_Inc_base&) le champ inconnue representant la vitesse
607 */
609{
610 return la_vitesse.valeur();
611}
612
613/*! @brief Renvoie le solveur en pression (version const)
614 *
615 * @return (SolveurSys&) le solveur en pression
616 */
621
622/*! @brief Renvoie le fluide incompressible (milieu physique de l'equation) associe a l'equation.
623 *
624 * (version const)
625 *
626 * @return (Fluide_base&) le fluide incompressible associe a l'equation
627 */
629{
630 return le_fluide.valeur();
631}
632
633
634/*! @brief Renvoie le fluide incompressible (milieu physique de l'equation) associe a l'equation.
635 *
636 * @return (Fluide_base&) le fluide incompressible associe a l'equation
637 */
639{
640 return le_fluide.valeur();
641}
642
644{
645 Cerr << "Reading of initial conditions\n";
646 Nom nom;
647 Motcle motlu;
648 is >> nom;
649 motlu = nom;
650 if(motlu!=Motcle("{"))
651 {
652 Cerr << "We expected a { while reading " << que_suis_je() << finl;
653 Cerr << "and not : " << nom << finl;
654 exit();
655 }
656 Motcles compris(3);
657 compris[0]="}";
658 compris[1]="vitesse";
659 compris[2]="pression";
660 int ind = -1;
661 while (ind!=0)
662 {
663 is >> nom;
664 motlu = nom;
665 ind = compris.rang(motlu);
666 if (ind==1)
667 {
668 OWN_PTR(Champ_Don_base) ch_init;
669 is >> ch_init;
671 inconnue().affecter(ch_init.valeur());
672 }
673 else if (ind==2)
674 {
675 OWN_PTR(Champ_Don_base) ch_init;
676 is >> ch_init;
678 pression().affecter(ch_init.valeur());
679 }
680 else if (ind==-1)
681 {
682 Cerr << nom << " is not understood. Keywords are:" << finl;
683 Cerr << compris << finl;
684 exit();
685 }
686 }
687 return is;
688}
689
690/*! @brief Add a specific term for Navier Stokes (-gradP(n)) if necessary
691 *
692 */
693DoubleTab& Navier_Stokes_std::corriger_derivee_expl(DoubleTab& derivee)
694{
695 if (assembleur_pression_->get_resoudre_increment_pression())
696 {
697 // PL: Pour ne pas calculer ce gradient, il faut
698 // A) postraitement_gradient_P_==0 car sinon grad contient alors M-1BtP
699 // B) les conditions en pression soient stationnaires (pas facile a detecter: Orlansky, P(t), gradient_pression impose...)
700 // En outre, cela fait des ecarts avec le schema CN iteratif
701 const DoubleTab& tab_pression = la_pression->valeurs();
702 DoubleTab& gradP = gradient_P->valeurs();
703 gradient.calculer(tab_pression, gradP);
704 derivee -= gradP;
705 }
706 return derivee;
707}
708
709/*! @brief Resolution de la pression, inconnue implicitee de Navier Stokes
710 *
711 */
712DoubleTab& Navier_Stokes_std::corriger_derivee_impl(DoubleTab& derivee)
713{
714 // We want to solve:
715 // dU/dt + M-1 Bt Cp = M-1(F - BtP)
716 // B dU/dt = 0
717 // with F explicit terms: sum(operators)+sources
718 // In: derivee = M-1(F - BtP(n))
719 // Out: derivee = M-1(F - BtP(n+1)), P(n+1)=P(n)+Cp
720
721 DoubleTab& tab_pression=la_pression->valeurs();
722 DoubleTab& gradP=gradient_P->valeurs();
723 DoubleTrav secmemP(tab_pression);
724
725 const bool is_ALE = probleme().domaine().deformable();
726
728
729 const double dt = schema_temps().pas_de_temps();
731 {
732 // on veut div u =0 et non d/dt (div u)=0 pour eviter de cumuler les erreurs
733 // cela ne marche qu'avec les schema type euler_explicite
734 DoubleTab derivee2(derivee);
735 derivee2*=dt;
736 derivee2+=la_vitesse->passe();
737 derivee2/=dt;
738 divergence.calculer(derivee2, secmemP); // Div(M-1(F - BtP))
739 }
740 else if (is_ALE)
741 {
742 // ALE explicit volumetric correction:
743 // In ALE formulation, the conservative form of the transient term is:
744 // (V^{n+1} U^{n+1} - V^n U^n ) / dt
745 // For an explicit Euler scheme, this leads to the additional term:
746 // (V^n / V^{n+1}) * (U^n / dt) which is added to the explicit RHS (M-1(F - BtP)).
747 // This ensures discrete mass conservation (Geometric Conservation Law) when the mesh is deformable.
748 // This correction is required only for explicit schemes because
749 // implicit schemes naturally incorporate the volume variation inside the mass matrix formulation.
750 DoubleTab derivee2(derivee);
751 // Conservative ALE form: deriveeALE= (Volume_n+1/Volume_n)*Un/delta t + derivee
752 probleme().domaine().ajouter_correctif_volumique(la_vitesse->valeurs(), derivee, dt, derivee2);
753 divergence.calculer(derivee2, secmemP);
754 }
755 else
756 divergence.calculer(derivee, secmemP); // Div(M-1(F - BtP))
757
758 secmemP *= -1; // car div =-B
759 // Correction du second membre d'apres les conditions aux limites :
760 assembleur_pression_->modifier_secmem(secmemP);
761
762 // Set print of the linear system solve according to dt_impr:
763 solveur_pression_->fixer_schema_temps_limpr(schema_temps().limpr());
764
765 if (assembleur_pression_->get_resoudre_increment_pression())
766 {
767 // Solve B M-1 Bt Cp = M-1(F - BtP)
768 DoubleTrav Cp(tab_pression);
769 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(), secmemP, Cp);
770
771 // P(n+1) = P(n) + Cp
772 tab_pression += Cp;
773 assembleur_pression_->modifier_solution(tab_pression);
774
775 // M-1 Bt P(n+1)
776 solveur_masse->appliquer(gradP);
777 derivee += gradP; // M-1 F
778 }
779 else
780 {
781 // Solve B M-1 Bt P(n+1) = B M-1 F
782 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(), secmemP, tab_pression);
783 assembleur_pression_->modifier_solution(tab_pression);
784 // It is not done anymore cause:
785 // Iterative solvers are less accurate
786 // Time converges in O(sqrt(dt)) and not O(dt)
787 // See: http://www.sciencedirect.com/science/article/pii/S0021999108004518
788 }
789
790 // (BM) gradient operator requires updated virtual space in source vector
791 // Calculate Bt P(n+1)
792 tab_pression.echange_espace_virtuel();
793 gradient.calculer(tab_pression, gradP);
794
795 // gradP = Bt P(n+1) is kept and
796 // M-1Bt P(n+1) is calculated:
797 DoubleTrav Mmoins1gradP(gradP);
798 Mmoins1gradP = gradP;
799 solveur_masse->appliquer(Mmoins1gradP);
800
801 // dU/dt = M-1(F-Bt P(n+1))
802 derivee -= Mmoins1gradP;
803
804 return derivee;
805}
806
807/*! @brief Calcule la solution U des equations: | M(U-V)/dt + BtP = 0
808 *
809 * |-BU=0
810 * On resoud le probleme en pression: -BM-1BtP = -BV/dt
811 * sachant que -BV represente le calcul de la divergence de V
812 * On resoud le probleme en vitesse en appliquant le solveur
813 * de masse au gradient de P: U=V - dt*M-1BtP
814 *
815 * @throws pas de temps trop petit
816 */
818{
819 if (probleme().is_dilatable() && probleme().reprise_effectuee())
820 Cerr << "WARNING: Quasi compressible model --> no projection (except the first time step)." << finl;
821 else
822 {
823 Cerr << "Projection of initial and boundaries conditions " << finl;
824 DoubleTab& tab_vitesse = la_vitesse->valeurs();
825 tab_vitesse.echange_espace_virtuel();
826 la_pression->valeurs().echange_espace_virtuel();
827
828 double normal_seuil = 0.;
829
830 // M u + eBt l = M v
831 // B u = 0
832 // => e B(M-1)Bt l = Bv
833 //
835
836 DoubleTrav secmem(la_pression->valeurs());
837 divergence.calculer(tab_vitesse, secmem);
838 // Desormais on calcule le pas de temps avant la projection
839 // Avant, on avait dt=dt_min au debut du calcul
840 double dt = std::max(le_schema_en_temps->pas_temps_min(),calculer_pas_de_temps());
841 dt = std::min(dt, le_schema_en_temps->pas_temps_max());
842
843 secmem*=(-1./dt);
844 secmem.echange_espace_virtuel();
845
846 double bilan=mp_norme_vect(secmem); // TODO DG surcharger cette fonction pour avoir \sum \int_T || \sum_{nfunc_p} secmem*fbase_p ||
847 Cout << "------------- Projection -----------------" << finl;
848 Cout << "--------------------------------------------" << finl;
849 Cout << "Bilan de masse avant projection : " << bilan << finl;
850
851 if( sub_type(solv_iteratif,solveur_pression_.valeur()) )
852 {
853 solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
854 normal_seuil=solv_iter.get_seuil();
855 solv_iter.set_seuil(seuil_projection);
856 }
857
858 // Correction du second membre d'apres les conditions aux limites :
859 // Cela ne sert a rien d'initialiser lagrange avec la pression
860 // voir ca penalise le calcul en p1B et CL p<>0
861 // On prend un DoubleTrav au lieu d'un DoubleTab pour avoir lagrange=0
862 DoubleTrav lagrange(la_pression->valeurs());
863 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(),secmem,lagrange);
864 assembleur_pression_->modifier_solution(lagrange);
865 lagrange.echange_espace_virtuel();
866
867 // M-1 Bt l
868 DoubleTrav gradP(gradient_P->valeurs());
869 gradient->multvect(lagrange, gradP);
872 solveur_masse->appliquer(gradP);
874
875 if (tab_vitesse.dimension_tot(0) == gradP.dimension_tot(0))
876 tab_vitesse.ajoute(-dt,gradP);
877 else
878 {
879 DoubleTab_parts partv(tab_vitesse);
880 partv[0].ajoute(-dt,gradP);
881 }
882 tab_vitesse.echange_espace_virtuel();
883 solveur_masse->corriger_solution(tab_vitesse, tab_vitesse);
884
885 Debog::verifier("Navier_Stokes_std::projeter, vitesse", tab_vitesse);
886
887 // Verif ...
888 divergence.calculer(tab_vitesse, secmem);
889 secmem.echange_espace_virtuel();
890
891 bilan=mp_norme_vect(secmem);
892 Cout << "Bilan de masse apres projection : " << bilan << finl;
893 Cout << "------------- Projection OK---------------" << finl;
894 Cout << "--------------------------------------------" << finl;
895
896 if( sub_type(solv_iteratif,solveur_pression_.valeur()) )
897 {
898 solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
899 solv_iter.set_seuil(normal_seuil);
900 }
901 }
903}
904
906{
907 // Pas de projection si l'equation n'est pas resolue
908 // if (equation_non_resolue()) return 0;
909
910 double temps = le_schema_en_temps->temps_courant()+le_schema_en_temps->pas_de_temps();
911 // Voir Schema_Temps_base::limpr pour information sur modf
912 double nb_proj_int;
913 modf(temps/dt_projection, &nb_proj_int);
914 static double nb_proj = nb_proj_int;
916 return 1;
917 else if (inf_ou_egal((nb_proj+1.)*dt_projection,temps))
918 {
919 nb_proj=nb_proj+1.;
920 return 1;
921 }
922 return 0;
923}
924
925/*! @brief cf Equation_base::preparer_calcul() Assemblage du solveur pression et
926 *
927 * initialisation de la pression.
928 *
929 * assemblage du systeme en pression
930 *
931 * @return (int) renvoie toujours 1
932 */
934{
935 const double temps = schema_temps().temps_courant();
936 sources().mettre_a_jour(temps);
938 bool is_dilatable = probleme().is_dilatable();
939 if (!is_dilatable)
940 assembleur_pression_->assembler(matrice_pression_);
941 else
942 {
943 Cerr << "Assembling for quasi-compressible" << finl;
944 assembleur_pression_->assembler_QC(fluide().masse_volumique().valeurs(), matrice_pression_);
945 }
946
947 // GF en cas de reprise on conserve la valeur de la pression
948 // avant elle ne servait qu' a initialiser le lagrange pour la projection
949 // C'est important pour le Simpler/Piso de bien repartir de la pression
950 // sauvegardee...
951 //la_pression->valeurs()=0.;
952 Debog::verifier("Navier_Stokes_std::preparer_calcul, la_pression av projeter", la_pression->valeurs());
953 if (projection_a_faire())
954 projeter();
955
956 // Au cas ou une cl de pression depend de u que l'on vient de modifier
957 le_dom_Cl_dis->mettre_a_jour(temps);
958 Debog::verifier("Navier_Stokes_std::preparer_calcul, la_pression ap projeter", la_pression->valeurs());
959
960 // Initialisation du champ de pression (resolution de Laplacien(P)=0 avec les conditions limites en pression)
961 // Permet de demarrer la resolution avec une bonne approximation de la pression (important pour le Piso ou P!=0)
962 if (!probleme().reprise_effectuee() && methode_calcul_pression_initiale_ != 3)
963 {
964 Cout << "Estimation du champ de pression au demarrage:" << finl;
965 DoubleTrav secmem(la_pression->valeurs());
966 DoubleTrav vpoint(gradient_P->valeurs());
967 gradient.calculer(la_pression->valeurs(), gradient_P->valeurs());
968 vpoint -= gradient_P->valeurs();
969
971 for (int op = 0; op < nombre_d_operateurs(); op++)
972 operateur(op).ajouter(vpoint);
974 {
975 int mod = 0;
976 if (le_schema_en_temps->pas_de_temps() == 0)
977 {
978 double dt = std::max(le_schema_en_temps->pas_temps_min(), calculer_pas_de_temps());
979 dt = std::min(dt, le_schema_en_temps->pas_temps_max());
980 le_schema_en_temps->set_dt() = (dt);
981 mod = 1;
982 }
983 sources().ajouter(vpoint);
984 if (mod)
985 le_schema_en_temps->set_dt() = 0;
986 }
987
988 solveur_masse->appliquer(vpoint);
989 vpoint.echange_espace_virtuel();
990 divergence.calculer(vpoint, secmem);
991 secmem *= -1;
992 secmem.echange_espace_virtuel();
993
994 assembleur_pression_->modifier_secmem_pour_incr_p(la_pression->valeurs(), 1, secmem);
995 DoubleTrav inc_pre(la_pression->valeurs());
996 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(), secmem, inc_pre);
997 Cerr << "Pressure increment computed successfully" << finl;
998
999 // On veut que l'espace virtuel soit a jour, donc all_items
1000 operator_add(la_pression->valeurs(), inc_pre, VECT_ALL_ITEMS);
1001 }
1002 // Mise a jour pression
1003 la_pression->changer_temps(temps);
1005 // Calcul des forces de pression:
1006 gradient->calculer_flux_bords();
1007
1008 // Calcul gradient_P (ToDo rendre coherent avec ::mettre_a_jour()):
1009 gradient.calculer(la_pression->valeurs(), gradient_P->valeurs());
1010 gradient_P->changer_temps(temps);
1011
1012 // Calcul divergence_U
1013 divergence.calculer(la_vitesse->valeurs(), divergence_U->valeurs());
1014 divergence_U->changer_temps(temps);
1015
1016 if (le_traitement_particulier)
1017 le_traitement_particulier->preparer_calcul_particulier();
1018
1019 Debog::verifier("Navier_Stokes_std::preparer_calcul, vitesse", inconnue());
1020 Debog::verifier("Navier_Stokes_std::preparer_calcul, pression", la_pression);
1021
1022 return 1;
1023}
1024
1025/*! @brief Effectue une mise a jour en temps de l'equation.
1026 *
1027 * Appelle Equation_base::mettre_a_jour(double)
1028 * et met a jour la pression.
1029 * Integration des points suivis si le fluide est marque
1030 * Mise a jour du champ postraitable correspondant
1031 *
1032 * @param (double temps) le temps de mise a jour
1033 */
1035{
1036 // Mise a jour de la classe mere (on tourne la roue).
1038
1039 // Mise a jour de la pression
1040 la_pression->mettre_a_jour(temps);
1042 // Calcul des forces de pression:
1043 gradient->calculer_flux_bords();
1044
1045 // Update the divergence of the velocity div(U)
1046// statistics().end_count(STD_COUNTERS::update_variables,0,0);
1047 divergence.calculer(la_vitesse->valeurs(),divergence_U->valeurs());
1048 //statistics().begin_count(STD_COUNTERS::update_variables,statistics().get_last_opened_counter_level()+1);
1049 divergence_U->mettre_a_jour(temps);
1050
1051 // Pour le postraitement, on veut M-1BtP et non BtP
1052 if (postraitement_gradient_P_)
1053 {
1054 gradient.calculer(la_pression->valeurs(), gradient_P->valeurs());
1056 solveur_masse->appliquer(gradient_P->valeurs());
1057 gradient_P->mettre_a_jour(temps);
1058 }
1059
1060 // PQ : 04/03 : procedure de determination dynamique du seuil de convergence en pression
1061 if(sub_type(solv_iteratif,solveur_pression_.valeur()) && seuil_divU < 1.)
1062 {
1063 // Calcul dynamique d'un seuil sur le solveur iteratif de pression
1064 solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
1065 double seuil_dyn=solv_iter.get_seuil();
1066
1067 if(LocalFlowRateRelativeError()<seuil_divU)
1068 seuil_dyn*=raison_seuil_divU;
1069 else
1070 seuil_dyn/=raison_seuil_divU;
1071 double seuil_dyn_max = 1.e-10;
1072 seuil_dyn=std::max(seuil_dyn,seuil_dyn_max);
1073 solv_iter.set_seuil(seuil_dyn);
1074 }
1075 // fin procedure de determination du seuil dynamique de convergence en pression
1076
1077 if (projection_a_faire())
1078 projeter();
1079
1080 if (le_traitement_particulier)
1081 le_traitement_particulier->post_traitement_particulier();
1082 Debog::verifier("Navier_Stokes_std::mettre_a_jour : pression", la_pression->valeurs());
1083 Debog::verifier("Navier_Stokes_std::mettre_a_jour : vitesse", la_vitesse->valeurs());
1084
1085 if (la_vorticite) la_vorticite->mettre_a_jour(temps);
1086 if (critere_Q) critere_Q->mettre_a_jour(temps);
1087 if (Reynolds_maille) Reynolds_maille->mettre_a_jour(temps);
1088 if (Taux_cisaillement) Taux_cisaillement->mettre_a_jour(temps);
1089 if (grad_u) grad_u->mettre_a_jour(temps);
1090}
1091
1092double Navier_Stokes_std::LocalFlowRateRelativeError() const
1093{
1094 // Estimation of a flow rate relative error
1095 DoubleTrav array(divergence_U->valeurs()); // array(i)=sum(u.ndS)
1096 divergence.volumique(array); // array(i)=sum(u.ndS)/vol(i)
1097 return mp_max_abs_vect(array) * schema_temps().pas_de_temps(); // =max|sum(u.ndS)/(vol(i)/dt)|
1098}
1099
1101{
1102 // On reprend la pression du debut du pas de temps
1103 // Utile si on reprend le pas de temps parce que la pression a diverge (sinon tres mauvaise precision)
1104 // et si on est en Piso (suppose pression juste au debut du pas de temps).
1105 pression().valeurs()=P_n;
1106 //pression().valeurs()=0;
1108}
1109
1110/* @brief Override. Reset pression too !
1111 */
1113{
1114 pression().resetTime(time);
1116}
1117
1119{
1120 P_n=pression().valeurs();
1121
1122 // Verification que dt_max est correctement fixe pour un champ
1123 // de vitesse nul et diffusion_implicite active <=> dt_conv=INF
1124 const Schema_Temps_base& sch_tps = le_schema_en_temps.valeur();
1125 bool ddt = Equation_base::initTimeStep(dt);
1126
1127 for (int i=1; i<=sch_tps.nb_valeurs_futures(); i++)
1128 if (i <= pression().nb_valeurs_temporelles())
1129 {
1130 double tps=sch_tps.temps_futur(i);
1131 // Mise a jour du temps dans les champs de pression
1134 pression().futur(i)=pression().valeurs();
1136 }
1137
1138 return ddt;
1139}
1140
1141/*! @brief Calcul de "la_pression_en_pa" en fonction de "la_pression".
1142 *
1143 * Si le champ milieu().masse_volumique() est uniforme, on suppose que
1144 * la_pression est P* = P/rho, et on multiplie par rho. Sinon,
1145 * la_pression est deja en Pa.
1146 * Cette methode est surchargee en front-tracking.
1147 *
1148 */
1150{
1151 DoubleTab& Pa=la_pression_en_pa->valeurs();
1152 DoubleTab& tab_pression=la_pression->valeurs();
1153 const Champ_base& rho=milieu().masse_volumique();
1154 if (Pa.get_md_vector() == tab_pression.get_md_vector())
1155 Pa = tab_pression; //Pa et tab_pression ont le meme support
1156 else
1157 {
1158 ConstDoubleTab_parts ppart(tab_pression);
1159 assert(Pa.get_md_vector() == ppart[0].get_md_vector());
1160 Pa = ppart[0]; //tab_pression a un morceau en plus
1161 }
1162 // On multiplie par rho si uniforme sinon deja en Pa...
1163 if (sub_type(Champ_Uniforme,rho))
1164 Pa *= rho.valeurs()(0,0);
1165 la_pression_en_pa->mettre_a_jour(pression().temps());
1166}
1167
1168/*! @brief for PDI IO: retrieve name, type and dimensions of the fields to save/restore
1169 *
1170 */
1171std::vector<YAML_data> Navier_Stokes_std::data_a_sauvegarder() const
1172{
1173 std::vector<YAML_data> data = Equation_base::data_a_sauvegarder();
1174 std::vector<YAML_data> pression = la_pression->data_a_sauvegarder();
1175 data.insert(data.end(), pression.begin(), pression.end());
1176 return data;
1177}
1178
1179/*! @brief Appelle Equation_base::sauvegarder(Sortie&) et sauvegarde la pression sur un flot de sortie.
1180 *
1181 * @param (Sortie& os) un flot de sortie sur lequel sauvegarder
1182 * @return (int) renvoie toujours 1
1183 */
1185{
1186 int bytes=0;
1187 bytes += Equation_base::sauvegarder(os);
1188 bytes += la_pression->sauvegarder(os);
1189 //La methode sauver() assurant la sauvegarde pour le traitement particulier
1190 //est maintenant appelee ici au lieu d etre appelee dans des problemes particuliers
1191 sauver();
1192
1193 return bytes;
1194}
1195
1196/*! @brief Effectue une reprise a partir d'un flot d'entree.
1197 *
1198 * Appelle Equation_base::reprendre()
1199 * et reprend la pression.
1200 *
1201 * @param (Entree& is) un flot d'entree
1202 * @return (int) renvoie toujours 1
1203 * @throws la reprise a echoue, identificateur de la pression non trouve
1204 */
1206{
1209 {
1210 double temps = schema_temps().temps_courant();
1211 Nom ident_pression(la_pression->le_nom());
1212 ident_pression += la_pression->que_suis_je();
1213 ident_pression += probleme().domaine().le_nom();
1214 ident_pression += Nom(temps,probleme().reprise_format_temps());
1215 if (probleme().discretisation().is_poly_family())
1216 {
1217 Nom field_tag_syno = create_polymacfamily_syno(ident_pression);
1218 avancer_fichier_with_syno(is,ident_pression,field_tag_syno);
1219 }
1220 // end of the backward compatibility
1221 else
1222 avancer_fichier(is,ident_pression);
1223 }
1224 la_pression->reprendre(is);
1225
1226 if (le_traitement_particulier)
1227 le_traitement_particulier->reprendre_stat();
1228
1229 return 1;
1230}
1231
1232/*! @brief Associe un mileu physique a l'equation en construisant dynamiquement (cast) un objet de type Fluide_base
1233 *
1234 * a partir de l'objet Milieu_base passe en parametre.
1235 *
1236 * @param (Milieu_base& un_milieu) le milieu a associer a l'equation
1237 */
1239{
1240 if (sub_type(Fluide_base, un_milieu))
1241 {
1242 const Fluide_base& un_fluide = ref_cast(Fluide_base,un_milieu);
1243 associer_fluide(un_fluide);
1244 }
1245 else
1246 {
1247 Cerr << "Error of fluid type for the method Navier_Stokes_std::associer_milieu_base" << finl;
1248 exit();
1249 }
1250}
1251
1252/*! @brief Renvoie le milieu physique de l'equation (le Fluide_base upcaste en Milieu_base)
1253 *
1254 * @return (Milieu_base&) le Fluide_base de l'equation upcaste en Milieu_base
1255 */
1257{
1258 if (!le_fluide)
1259 {
1260 Cerr << "You forgot to associate a fluid to the problem named " << probleme().le_nom() << finl;
1261 Process::exit();
1262 }
1263 return le_fluide.valeur();
1264}
1265
1266/*! @brief Renvoie le milieu physique de l'equation (le Fluide_base upcaste en Milieu_base)
1267 *
1268 * (version const)
1269 *
1270 * @return (Milieu_base&) le Fluide_base de l'equation upcaste en Milieu_base
1271 */
1273{
1274 if (!le_fluide)
1275 {
1276 Cerr << "You forgot to associate a fluid to the problem named " << probleme().le_nom() << finl;
1277 Process::exit();
1278 }
1279 return le_fluide.valeur();
1280}
1281
1283{
1285
1286 if (motlu == "vorticite")
1287 {
1288 if (!la_vorticite)
1289 {
1290 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1291 dis.creer_champ_vorticite(schema_temps(),la_vitesse,la_vorticite);
1292 champs_compris_.ajoute_champ(la_vorticite);
1293 }
1294 }
1295 else if (motlu == "critere_Q")
1296 {
1297 if (!critere_Q)
1298 {
1299 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
1300 dis.critere_Q(domaine_dis(),domaine_Cl_dis(),la_vitesse,critere_Q);
1301 champs_compris_.ajoute_champ(critere_Q);
1302 }
1303 }
1304 else if (motlu == "y_plus")
1305 {
1306 if (!y_plus)
1307 {
1308 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1309 dis.y_plus(domaine_dis(),domaine_Cl_dis(),la_vitesse,y_plus);
1310 champs_compris_.ajoute_champ(y_plus);
1311 }
1312 }
1313 else if (motlu == "distance_paroi_globale")
1314 {
1315 if (!distance_paroi_globale)
1316 {
1317 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1318 dis.distance_paroi_globale(schema_temps(), domaine_dis(), distance_paroi_globale);
1319 champs_compris_.ajoute_champ(distance_paroi_globale);
1320 }
1321 }
1322 else if (motlu == "reynolds_maille")
1323 {
1324 if (!Reynolds_maille)
1325 {
1326 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1328 champs_compris_.ajoute_champ(Reynolds_maille);
1329 }
1330 }
1331 else if (motlu == "courant_maille")
1332 {
1333 if (!Courant_maille)
1334 {
1335 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1337 champs_compris_.ajoute_champ(Courant_maille);
1338 }
1339 }
1340 else if (motlu == "taux_cisaillement")
1341 {
1342 if (!Taux_cisaillement)
1343 {
1344 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1346 champs_compris_.ajoute_champ(Taux_cisaillement);
1347 }
1348 }
1349 else if (motlu == "pression_hydrostatique")
1350 {
1352 {
1353 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1354 dis.discretiser_champ("Champ_sommets",domaine_dis(),"pression_hydrostatique","Pa",1,0.,pression_hydrostatique_);
1356 }
1357 }
1358
1359 else if (motlu == "gradient_vitesse")
1360 {
1361 if (!grad_u)
1362 {
1363 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
1364 dis.grad_u(domaine_dis(),domaine_Cl_dis(),la_vitesse,grad_u);
1365 champs_compris_.ajoute_champ(grad_u);
1366 }
1367 }
1368
1369 if (le_traitement_particulier)
1370 le_traitement_particulier->creer_champ(motlu);
1371
1373 if (!grad_u) creer_champ("gradient_vitesse");
1374}
1375
1377{
1378 DoubleTab& val= pression_hydro.valeurs();
1379 const DoubleTab& coords = domaine_dis().domaine().les_sommets();
1380 if (!milieu().a_gravite())
1381 {
1382 Cerr<<"postprocessing of presion_hydrostatique needs gravity"<<finl;
1383 exit();
1384 }
1385 const Champ_base& rho = milieu().masse_volumique();
1386 if (!sub_type(Champ_Uniforme,rho))
1387 {
1388 Cerr<<"postprocessing of presion_hydrostatique availabe only for incompressible flow"<<finl;
1389 exit();
1390 }
1391 const DoubleTab& gravite = milieu().gravite().valeurs();
1392
1393 val=rho.valeurs()(0,0);
1394 const int nb_som=val.dimension(0);
1395
1396 for (int som=0; som<nb_som; som++)
1397 {
1398 double gz=0;
1399 for (int dir=0; dir<dimension; dir++)
1400 gz+=coords(som,dir)*gravite(0,dir);
1401 val[som]*=gz;
1402 }
1404}
1405
1406bool Navier_Stokes_std::has_champ(const Motcle& nom, OBS_PTR(Champ_base)& ref_champ) const
1407{
1408 if (nom == "gradient_pression")
1409 {
1410 ref_champ = Navier_Stokes_std::get_champ(nom);
1411 return true;
1412 }
1413
1414 if (nom == "vorticite" && la_vorticite)
1415 {
1416 ref_champ = Navier_Stokes_std::get_champ(nom);
1417 return true;
1418 }
1419
1420 if (nom == "critere_Q" && critere_Q)
1421 {
1422 ref_champ = Navier_Stokes_std::get_champ(nom);
1423 return true;
1424 }
1425
1426 if (nom == "y_plus" && y_plus)
1427 {
1428 ref_champ = Navier_Stokes_std::get_champ(nom);
1429 return true;
1430 }
1431
1432 if (nom == "reynolds_maille" && Reynolds_maille)
1433 {
1434 ref_champ = Navier_Stokes_std::get_champ(nom);
1435 return true;
1436 }
1437
1438 if (nom == "courant_maille" && Courant_maille)
1439 {
1440 ref_champ = Navier_Stokes_std::get_champ(nom);
1441 return true;
1442 }
1443
1444 if (nom == "taux_cisaillement" && Taux_cisaillement)
1445 {
1446 ref_champ = Navier_Stokes_std::get_champ(nom);
1447 return true;
1448 }
1449
1450 if (nom == "gradient_vitesse" && grad_u)
1451 {
1452 ref_champ = Navier_Stokes_std::get_champ(nom);
1453 return true;
1454 }
1455
1456 if (nom == "pression_hydrostatique" && pression_hydrostatique_)
1457 {
1458 ref_champ = Navier_Stokes_std::get_champ(nom);
1459 return true;
1460 }
1461
1462 if (Equation_base::has_champ(nom, ref_champ))
1463 return true;
1464
1465 if (le_traitement_particulier)
1466 if (le_traitement_particulier->has_champ(nom, ref_champ))
1467 return true;
1468
1469 return false; /* rien trouve */
1470}
1471
1473{
1474 if (nom == "gradient_pression")
1475 return true;
1476
1477 if (nom == "vorticite" && la_vorticite)
1478 return true;
1479
1480 if (nom == "critere_Q" && critere_Q)
1481 return true;
1482
1483 if (nom == "y_plus" && y_plus)
1484 return true;
1485
1486 if (nom == "reynolds_maille" && Reynolds_maille)
1487 return true;
1488
1489 if (nom == "courant_maille" && Courant_maille)
1490 return true;
1491
1492 if (nom == "taux_cisaillement" && Taux_cisaillement)
1493 return true;
1494
1495 if (nom == "gradient_vitesse" && grad_u)
1496 return true;
1497
1498 if (nom == "pression_hydrostatique" && pression_hydrostatique_)
1499 return true;
1500
1501 if (Equation_base::has_champ(nom))
1502 return true;
1503
1504 if (le_traitement_particulier)
1505 if (le_traitement_particulier->has_champ(nom))
1506 return true;
1507
1508 return false; /* rien trouve */
1509}
1510
1512{
1513 double temps_init = schema_temps().temps_init();
1514 if (nom == "gradient_pression")
1515 postraitement_gradient_P_ = 1;
1516
1517 if (nom == "vorticite")
1518 {
1519 if (!la_vorticite)
1520 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1521
1522 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, la_vorticite.valeur());
1523 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1524 ch.mettre_a_jour(la_vitesse->temps());
1525 return champs_compris_.get_champ(nom);
1526 }
1527
1528 if (nom == "critere_Q")
1529 {
1530 if (!critere_Q)
1531 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1532
1533 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, critere_Q.valeur());
1534 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1535 ch.mettre_a_jour(la_vitesse->temps());
1536 return champs_compris_.get_champ(nom);
1537 }
1538
1539 if (nom == "y_plus")
1540 {
1541 if (!y_plus)
1542 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1543
1544 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, y_plus.valeur());
1545 if (((ch.temps() != la_vitesse->temps()) || (ch.temps() == temps_init)) && (la_vitesse->mon_equation_non_nul()))
1546 ch.mettre_a_jour(la_vitesse->temps());
1547 return champs_compris_.get_champ(nom);
1548 }
1549
1550 if (nom == "reynolds_maille")
1551 {
1552 if (!Reynolds_maille)
1553 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1554
1555 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, Reynolds_maille.valeur());
1556 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1557 ch.mettre_a_jour(la_vitesse->temps());
1558 return champs_compris_.get_champ(nom);
1559 }
1560
1561 if (nom == "courant_maille")
1562 {
1563 if (!Courant_maille)
1564 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1565
1566 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, Courant_maille.valeur());
1567 if (((ch.temps() != la_vitesse->temps()) || (ch.temps() == temps_init)) && (la_vitesse->mon_equation_non_nul()))
1568 ch.mettre_a_jour(la_vitesse->temps());
1569 return champs_compris_.get_champ(nom);
1570 }
1571
1572 if (nom == "taux_cisaillement")
1573 {
1574 if (!Taux_cisaillement)
1575 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1576
1577 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, Taux_cisaillement.valeur());
1578 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1579 ch.mettre_a_jour(la_vitesse->temps());
1580 return champs_compris_.get_champ(nom);
1581 }
1582
1583 if (nom == "gradient_vitesse")
1584 {
1585 if (!grad_u)
1586 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1587
1588 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, grad_u.valeur());
1589 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1590 ch.mettre_a_jour(la_vitesse->temps());
1591 return champs_compris_.get_champ(nom);
1592 }
1593
1594 if (nom == "pression_hydrostatique")
1595 {
1597 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1598
1599 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, pression_hydrostatique_.valeur());
1600 if (((ch.temps() != la_vitesse->temps()) || (ch.temps() == temps_init)) && (la_vitesse->mon_equation_non_nul()))
1601 {
1603 ch.mettre_a_jour(la_vitesse->temps());
1604 }
1605 return champs_compris_.get_champ(nom);
1606 }
1607
1608 OBS_PTR(Champ_base) ref_champ;
1609
1610 if (Equation_base::has_champ(nom, ref_champ))
1611 return ref_champ;
1612
1613 if (le_traitement_particulier)
1614 if (le_traitement_particulier->has_champ(nom, ref_champ))
1615 return ref_champ;
1616
1617 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1618}
1619
1621{
1623
1624 if (le_traitement_particulier)
1625 le_traitement_particulier->get_noms_champs_postraitables(nom, opt);
1626
1627 Noms noms_compris = champs_compris_.liste_noms_compris();
1628 noms_compris.add("vorticite");
1629 noms_compris.add("critere_Q");
1630 noms_compris.add("y_plus");
1631 noms_compris.add("reynolds_maille");
1632 noms_compris.add("courant_maille");
1633 noms_compris.add("taux_cisaillement");
1634 noms_compris.add("pression_hydrostatique");
1635 noms_compris.add("gradient_vitesse");
1636
1637 if (opt == DESCRIPTION)
1638 Cerr << " Navier_Stokes_std : " << noms_compris << finl;
1639 else
1640 nom.add(noms_compris);
1641}
1642
1643/*! @brief Effectue quelques impressions sur un flot de sortie: - maximum de div U
1644 *
1645 * - terme convectif
1646 * - terme diffusif
1647 * - divergence
1648 * - gradient
1649 *
1650 * @param (Sortie& os) un flot de sortie
1651 * @return (int) renvoie toujours 1
1652 */
1654{
1655 // Affichage des bilans volumiques si on n'est pas en QC, ni en Front Tracking
1656 if (!probleme().is_dilatable() && probleme().que_suis_je()!="Probleme_FT_Disc_gen")
1657 {
1658 double LocalFlowRateError=mp_max_abs_vect(divergence_U->valeurs());
1659 os << finl;
1660 os << "Cell balance flow rate control for the problem " << probleme().le_nom() << " : " << finl;
1661 os << "Absolute value : " << LocalFlowRateError << " m"<<dimension+bidim_axi<<"/s" << finl;
1662 os << "Relative value : " << LocalFlowRateRelativeError() << finl; // max|sum(u.ndS)i/(vol(i)/dt)|=max|div(U)i/dt|
1663 // Calculation as OpenFOAM: http://foam.sourceforge.net/docs/cpp/a04190_source.html
1664 // It is relative errors (normalized by the volume/dt)
1665 double dt = schema_temps().pas_de_temps();
1666 double local = LocalFlowRateError / ( probleme().domaine().volume_total() / dt );
1667 double global = mp_somme_vect(divergence_U->valeurs()) / ( probleme().domaine().volume_total() / dt );
1668 cumulative_ += global;
1669 os << "time step continuity errors : sum local = " << local << ", global = " << global << ", cumulative = " << cumulative_ << finl;
1670 // Nouveau 1.6.1, arret si bilans de masse mauvais et seuil<1.e20
1671 if (local>0.01 && sub_type(solv_iteratif,solveur_pression_.valeur()))
1672 {
1673 if (ref_cast(solv_iteratif,solveur_pression_.valeur()).get_seuil()<1e10)
1674 {
1675 Cerr << "The mass balance is too bad (relative value>1%)." << finl;
1676 Cerr << "Please check and lower the convergence value of the pressure solver." << finl;
1677 exit();
1678 }
1679 }
1680#ifndef TRUST_USE_GPU
1681 // Since 1.6.6, warning to use PETSc Cholesky instead of an iterative method for pressure solver
1682 int nw=100;
1683 if (solveur_pression_->solveur_direct()==0 && le_schema_en_temps->nb_pas_dt()<nw && Process::nproc()<256 && la_pression->valeurs().size_array()<40000)
1684 {
1685 Cerr << finl << "********************** Advice (printed only on the first " << nw << " time steps) *********************" << finl;
1686 Cerr << "You should use PETSc Cholesky solver instead of an iterative method for the pressure solver." << finl;
1687 Cerr << "For the caracteristics of your problem, it will be faster and give a better mass flow balance." << finl;
1688 Cerr << "**********************************************************************************************" << finl << finl;
1689 }
1690#endif
1691 }
1692
1693 if ((seuil_divU < 1.) && (sub_type(solv_iteratif,solveur_pression_.valeur())))
1694 {
1695 const solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
1696 os << " seuil de convergence du solveur iteratif : " << solv_iter.get_seuil() << finl;
1697 }
1699 divergence.impr(os);
1700 gradient.impr(os);
1701 return 1;
1702}
1703
1704
1705/*! @brief Renvoie le nom du domaine d'application: "Hydraulique".
1706 *
1707 * @return (Motcle&) lenom representant le domaine d'application
1708 */
1710{
1711 static Motcle domaine = "Hydraulique";
1712 return domaine;
1713}
1714
1715static void construire_matrice_implicite(Operateur_base& op,
1716 const DoubleTab& valeurs_inconnue,
1717 const Solveur_Masse_base& solv_masse,
1718 const double dt)
1719{
1720 Matrice& mat = op.set_matrice();
1721 if(!mat)
1722 mat.typer("Matrice_Morse");
1723
1724 if(op.get_decal_temps()==1)
1725 {
1726 Matrice_Morse& matrice = ref_cast(Matrice_Morse, mat.valeur());
1727 op.dimensionner(matrice);
1728 op.contribuer_a_avec(valeurs_inconnue, matrice);
1729 solv_masse.ajouter_masse(dt, matrice);
1730 matrice *= dt;
1731
1732 // Si le solveur est cholesky ou gcp, on attend une matrice de type
1733 // Matrice_Morse_Sym. Transformation du type de la matrice:
1734 const Nom& type_solveur = op.get_solveur()->que_suis_je();
1735 if(type_solveur == "Solv_Cholesky" || type_solveur == "Solv_GCP")
1736 {
1737 Matrice_Morse_Sym new_mat(matrice);
1738 new_mat.set_est_definie(1);
1739 // mat est detruite puis reconstruite:
1740 mat = new_mat;
1741 // Reinitialisation du solveur (recalcul des preconditionnements, factorisation, etc...)
1742 //ref_cast_non_const(SolveurSys_base,op.get_solveur().valeur()).reinit();
1743 op.set_solveur()->reinit();
1744 }
1745 }
1746}
1747
1748/* dans PolyMAC_HFV, le gradient contribue a la matrice de l'equation de N-S */
1750{
1752 if (gradient->has_interface_blocs())
1753 gradient->dimensionner_blocs({{ "vitesse", &matrice }});
1754}
1755
1757{
1758 return Equation_base::has_interface_blocs() && gradient->has_interface_blocs();
1759}
1760
1761/* le gradient passe en dernier */
1762void Navier_Stokes_std::dimensionner_blocs(matrices_t matrices, const tabs_t& semi_impl) const
1763{
1764 Equation_base::dimensionner_blocs(matrices, semi_impl);
1765 gradient->dimensionner_blocs(matrices, semi_impl);
1766}
1767
1768void Navier_Stokes_std::assembler_blocs(matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl) const
1769{
1770 Equation_base::assembler_blocs(matrices, secmem, semi_impl);
1771 gradient->ajouter_blocs(matrices, secmem, semi_impl);
1772}
1773
1774DoubleTab& Navier_Stokes_std::derivee_en_temps_inco(DoubleTab& derivee)
1775{
1777 // Calcul de la derivee en temps:
1778 if(!implicite_)
1779 {
1780 // Calcul explicite, on utilise la derivee en temps standard:
1782 }
1783 else
1784 {
1785 // Calcul implicite d'un ou plusieurs operateurs (peu utilise)
1786 // Syntaxe jeu de donnees: operateur { implicite solveur cholesky|gcp ... }
1787 derivee = 0;
1788 for(int i=0; i<nombre_d_operateurs(); i++)
1789 operateur(i).ajouter(derivee);
1790
1791 les_sources.ajouter(derivee);
1792 derivee.echange_espace_virtuel();
1793
1794 const double dt=schema_temps().pas_de_temps();
1795 static double dt_old=dt;
1796
1797 for(int i=0; i<nombre_d_operateurs(); i++)
1798 {
1800 // If matrix not build or matrix time dependant:
1801 if(!op.get_matrice() || !sys_invariant_)
1802 construire_matrice_implicite(op, inconnue().valeurs(), solv_masse(), dt);
1803
1804 if(op.get_decal_temps()==1)
1805 {
1806 if(sys_invariant_ && dt!=dt_old)
1807 {
1808 // La matrice ne change pas mais on change le pas de temps.
1809 // La matrice s'ecrit A =
1810 // Mise a jour simplifiee de la matrice
1811 Matrice_Morse& matrice=ref_cast(Matrice_Morse, op.set_matrice().valeur());
1812 matrice/=dt_old;
1813 solv_masse().ajouter_masse(-dt_old, op.set_matrice().valeur());
1814 solv_masse().ajouter_masse(dt, op.set_matrice().valeur());
1815 matrice*=dt;
1816 ref_cast_non_const(SolveurSys_base,op.get_solveur().valeur()).reinit();
1817 }
1818 Matrice_Morse& matrice=ref_cast(Matrice_Morse, op.set_matrice().valeur());
1819 if(implicite_==1)
1820 {
1821 // Un seul operateur implicite.
1822 DoubleTrav secmem(derivee);
1823 secmem=derivee;
1824 DoubleTrav incre_pre(la_pression->valeurs());
1825 gradient.calculer(la_pression->valeurs(),gradient_P->valeurs());
1826 secmem-=gradient_P->valeurs();
1827 uzawa(secmem, matrice,op.set_solveur(),derivee, incre_pre);
1828
1829 la_pression->valeurs()+=incre_pre;
1830 gradient.calculer(la_pression->valeurs(),gradient_P->valeurs());
1831 }
1832 else
1833 {
1834 // plusieurs operateurs implicites ...
1835 Cerr << "To be developped ... " << finl;
1836 exit();
1837 }
1838 }
1839 }
1840 dt_old=dt;
1841 return derivee;
1842 }
1843}
1844
1845void Navier_Stokes_std::uzawa(const DoubleTab& secmem, const Matrice_Base& A, SolveurSys& solveur, DoubleTab& U, DoubleTab& P)
1846{
1847 // A U + Bt P = secmem
1848 // B U = G
1849 // On part de la pression courante et
1850 // secmem = inertie + conv + sources + cl diff
1851 // On part de P0 et U0 verifiant les C.L. et BU0=G
1852
1853 // AU + Bt Cp = secmem
1854 // BU = 0
1855
1856 // On ecrit un GC sur B(A-1)Bt Cp = B(A-1)(secmem)
1857
1858 DoubleTrav Cu(U);
1859 DoubleTrav grad(U);
1860 DoubleTrav grad0(U);
1861 DoubleTrav resu(P);
1862 DoubleTrav residu(P);
1863 DoubleTrav Cp(P);
1864 double dold,dnew,alfa;
1865 double seuil=seuil_uzawa;
1866
1867 //Cu = A(-1) secmem
1868 Cerr << "Begining Uzawa, secmem norm value : " << mp_norme_vect(secmem) << finl;
1869 P=0.;
1870 gradient->multvect(P, grad0);
1871 solveur.nommer("uzawa_solver");
1872 solveur.resoudre_systeme(A, secmem, U);
1873 solv_masse().corriger_solution(U,Cu); // pour les C.L. de Dirichlet!
1874
1875 // residu=BCu
1876 divergence->multvect(U, resu);
1877
1878 residu.copy(resu);
1879 residu*=-1.;
1880
1881 // Cp = -residu;
1882 Cp = residu;
1883 Cp*=-1;
1885
1886 // Carre de la norme
1887 dold = mp_norme_vect(residu);
1888 dold = dold * dold;
1889 dnew = dold;
1890
1891 double s=0;
1892 int niter=0;
1893 int nmax=Cp.size();
1894 Cerr << "Uzawa, initial residue : " << dnew << finl;
1895 // seuil=std::max(seuil, dnew*1.e-12);
1896 while ( ( dnew > seuil ) && (niter++ < nmax) )
1897 {
1898 gradient->multvect(Cp, grad);
1899 grad-=grad0;
1900 grad*=-1;
1901 solveur.resoudre_systeme(A, grad, Cu);
1902 solv_masse().corriger_solution(Cu,U); // pour les C.L. de Dirichlet!
1903 divergence->multvect(Cu, resu);
1904 resu*=-1;
1905
1906 s = mp_prodscal(resu, Cp);
1907 alfa = dold/(s);
1908 P.ajoute(alfa,Cp);
1909 residu.ajoute(alfa,resu);
1910 U.ajoute(alfa,Cu);
1911 dnew = mp_norme_vect(residu);
1912 dnew = dnew * dnew;
1913 assert(dnew >= 0);
1914 Cp *= (dnew/dold);
1915 Cp -= residu;
1916 dold = dnew;
1917 // Cerr << "Uzawa, Residu apres "
1918 // << niter << " iterations = " << dnew << finl;
1919 }
1920
1921 if(dnew > seuil)
1922 {
1923 Cerr << "######## Uzawa, No convergence after : " << niter << " iterations\n";
1924 Cerr << "######## Uzawa, Residue : "<< dnew << "\n";
1925 exit();
1926 }
1927
1928 else if ((je_suis_maitre()))
1929 {
1930 Cerr << finl << "Uzawa, convergence reached after " << niter << " iterations" << finl;
1931 }
1932 {
1933 // On verifie :
1934
1935 DoubleTrav R(resu);
1936 divergence->multvect(U, R);
1937
1938 gradient->multvect(P, grad);
1939 grad-=grad0;
1940 DoubleTrav F(secmem);
1941 DoubleTrav UU(U);
1942 F=secmem;
1943 F-=grad;
1944
1945 solveur.resoudre_systeme(A, F, UU);
1946 UU-=U;
1947
1948 // Optimization: combine 2 mp_norme_vect into 1 collective call
1949 double R_carre = local_carre_norme_vect(R);
1950 double UU_carre = local_carre_norme_vect(UU);
1951 Process::mp_sum_for_each(R_carre, UU_carre);
1952 Cerr << "Ending Uzawa : mass residue : " << sqrt(R_carre) <<finl;
1953 Cerr << "Ending Uzawa : Qdm residue : " << sqrt(UU_carre)<<finl;
1954 }
1955}
1956
1958{
1959 if (le_traitement_particulier)
1960 le_traitement_particulier->sauver_stat();
1961}
1962
1964{
1965 Cerr<<" Navier_Stokes_std::rho_la_vitesse() must be overloaded "<<finl;
1966 assert(0);
1967 exit();
1968 throw;
1969}
1970
1971void Navier_Stokes_std::update_y_plus(const DoubleTab& tab)
1972{
1973 if (!y_plus) Process::exit(que_suis_je() + " : y_plus must be initialised so it can be updated") ;
1974 DoubleTab& tab_y_p = y_plus->valeurs();
1975 if (tab.nb_dim()==2)
1976 for (int i = 0 ; i < tab_y_p.dimension_tot(0) ; i++)
1977 for (int n = 0 ; n < tab_y_p.dimension_tot(1) ; n++) tab_y_p(i,n) = tab(i,n);
1978 if (tab.nb_dim()==3)
1979 for (int i = 0 ; i < tab_y_p.dimension_tot(0) ; i++)
1980 for (int n = 0 ; n < tab_y_p.dimension_tot(1) ; n++) tab_y_p(i,n) = tab(i,0,n);
1981}
1982
1984{
1985 if(probleme().domaine().getCouplingMethod()) //implicit IFS coupling
1986 // Equivalent of setting present = past for velocity done in for eg. Schema_Euler_Implicite::test_stationnaire.
1987 // Ensures sub-iterations start with the correct pressure for implicit coupling
1988 pression().valeurs()= P_n;
1989}
1990
1995
1997{
1998 // in case of implicit coupling with a structural code: update the fluxes (used for computing the fluid force) during implicit sub-iterations
1999
2000 if(probleme().domaine().getCouplingMethod()) //implicit IFS coupling case
2001 {
2002 Cout<<" Implicit coupling: Navier_Stokes_std_ALE::updateFluidForce "<<finl;
2003 //update diffusion operator
2004 DoubleTab field_value = velocity;
2005 field_value = 0.;
2006 operateur_diff().ajouter(velocity, field_value);
2007
2008
2009 //update gradient operator
2010 pression().mettre_a_jour(schema_temps().temps_courant());
2012 gradient->calculer_flux_bords();
2013 }
2014}
classe Champ_Don_base classe de base des Champs donnes (non calcules)
DoubleTab & valeurs() override
Surcharge Champ_base::valeurs() Renvoie le tableau des valeurs.
classe Champ_Fonc_base Classe de base des champs qui sont fonction d'une grandeur calculee
void mettre_a_jour(double temps) override
Mise a jour en temps du champ.
Classe Champ_Inc_base.
DoubleTab & futur(int i=1) override
Renvoie les valeurs du champs a l'instant t+i.
void mettre_a_jour(double temps) override
Effectue une mise a jour en temps du champ inconnue.
void resetTime(double time) override
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
double changer_temps_futur(double, int i=1)
Fixe le temps du ieme champ futur.
virtual DoubleTab & valeurs()=0
classe Champ_Uniforme Represente un champ constant dans l'espace et dans le temps.
classe Champ_base Cette classe est la base de la hierarchie des champs.
Definition Champ_base.h:43
Champ_base & affecter(const Champ_base &)
Affecter un champ dans un autre.
double temps() const
Renvoie le temps du champ.
static void verifier(const char *const msg, double)
Definition Debog.cpp:21
classe Discret_Thyd Cette classe est la classe de base representant une discretisation
void gradient_P(const Schema_Temps_base &, Domaine_dis_base &, OWN_PTR(Champ_Inc_base)&, int nb_comp=1) const
void pression_en_pa(const Schema_Temps_base &, Domaine_dis_base &, OWN_PTR(Champ_Inc_base)&) const
void pression(const Schema_Temps_base &, Domaine_dis_base &, OWN_PTR(Champ_Inc_base)&) const
virtual void courant_maille(const Domaine_dis_base &, const Schema_Temps_base &, const Champ_Inc_base &, OWN_PTR(Champ_Fonc_base)&) const
virtual void y_plus(const Domaine_dis_base &, const Domaine_Cl_dis_base &, const Champ_Inc_base &, OWN_PTR(Champ_Fonc_base)&) const
virtual void taux_cisaillement(const Domaine_dis_base &, const Domaine_Cl_dis_base &, const Champ_Inc_base &, OWN_PTR(Champ_Fonc_base)&) const
virtual void creer_champ_vorticite(const Schema_Temps_base &, const Champ_Inc_base &, OWN_PTR(Champ_Fonc_base)&) const
virtual void grad_u(const Domaine_dis_base &, const Domaine_Cl_dis_base &, const Champ_Inc_base &, OWN_PTR(Champ_Fonc_base)&) const
void divergence_U(const Schema_Temps_base &, Domaine_dis_base &, OWN_PTR(Champ_Inc_base)&) const
virtual void distance_paroi_globale(const Schema_Temps_base &, Domaine_dis_base &, OWN_PTR(Champ_Fonc_base)&) const
void vitesse(const Schema_Temps_base &, Domaine_dis_base &, OWN_PTR(Champ_Inc_base)&, int nb_comp=1) const
virtual void reynolds_maille(const Domaine_dis_base &, const Fluide_base &, const Champ_Inc_base &, OWN_PTR(Champ_Fonc_base)&) const
virtual void critere_Q(const Domaine_dis_base &, const Domaine_Cl_dis_base &, const Champ_Inc_base &, OWN_PTR(Champ_Fonc_base)&) const
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
double volume_total() const
Definition Domaine.cpp:877
DoubleTab_t & les_sommets()
Definition Domaine.h:113
bool deformable() const
virtual void ajouter_correctif_volumique(const DoubleTab &, const DoubleTab &, double, DoubleTab &) const
virtual bool getCouplingMethod() const
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
classe Domaine_dis_base Cette classe est la base de la hierarchie des domaines discretisees.
const Domaine & domaine() const
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....
virtual void set_param(Param &titi) const override
int reprendre(Entree &) override
On reprend l'inconnue a partir d'un flot d'entree.
virtual void dimensionner_matrice_sans_mem(Matrice_Morse &mat_morse)
virtual int verif_Cl() const
Verifie la compatibilite des conditions limites avec l'equation.
virtual std::vector< YAML_data > data_a_sauvegarder() const
for PDI IO: retrieve name, type and dimensions of the data to save/restore. This has to be overrode f...
virtual void associer_pb_base(const Probleme_base &)
S'associe au Probleme passe en parametre.
Sources & sources()
Renvoie les termes sources asssocies a 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.
Nom create_polymacfamily_syno(const Nom &field_tag) const
Create a synonym of a field name in order to ensure backward compatibility with old names of the Poly...
virtual void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={}) const
virtual void mettre_a_jour(double temps)
La valeur de l'inconnue sur le pas de temps a ete calculee.
virtual int impr(Sortie &os) const
Imprime les operateurs de l'equation sur un flot de sortie, de facon inconditionnelle.
virtual void abortTimeStep()
Reinitialiser ce qui doit l'etre.
virtual void completer()
Complete la construction (initialisation) des objets associes a l'equation.
Sources les_sources
void get_noms_champs_postraitables(Noms &nom, Option opt=NONE) const override
virtual int preparer_calcul()
Tout ce qui ne depend pas des autres problemes eventuels.
bool has_champ(const Motcle &nom, OBS_PTR(Champ_base) &ref_champ) const override
void initialise_residu(int=0)
virtual DoubleTab & derivee_en_temps_inco(DoubleTab &)
Returns the time derivative of the unknown I of the equation: dI/dt = M-1*(sum(operators(I) + sources...
int sauvegarder(Sortie &) const override
On sauvegarde l'inconnue, puis les sources sur un flot de sortie.
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.
virtual void verifie_ch_init_nb_comp(const Champ_Inc_base &ch_ref, const int nb_comp) const
Verification du nombre de composantes lues pour la specification d un champ.
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 limpr() const
Demande au schema en temps si il faut effectuer une impression.
void creer_champ(const Motcle &motlu) override
Schema_Temps_base & schema_temps()
Renvoie le schema en temps associe a l'equation.
virtual bool initTimeStep(double dt)
Allocation et initialisation de l'inconnue et des CLs jusqu'a present+dt.
virtual void discretiser()
Discretise l'equation.
virtual int has_interface_blocs() const
virtual void resetTime(double time)
Reset current time of the equation. Used from ICoCo. See documentation of Problem_base::resetTime().
Champs_compris champs_compris_
virtual void assembler_blocs(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={}) const
Domaine_dis_base & domaine_dis()
Renvoie le domaine discretise associe a l'equation.
virtual double calculer_pas_de_temps() const
Calcul du prochain pas de temps.
virtual int nb_comp() const
Definition Field_base.h:56
classe Fluide_base Cette classe represente un d'un fluide incompressible ainsi que
Definition Fluide_base.h:38
const Champ_Don_base & viscosite_cinematique() const
Definition Fluide_base.h:58
Classe Matrice_Base Classe de base de la hierarchie des matrices.
Classe Matrice_Morse_Sym Represente une matrice M (creuse) symetrique stockee au format Morse.
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
Classe Matrice Classe generique de la hierarchie des matrices.
Definition Matrice.h:34
classe Milieu_base Cette classe est la base de la hierarchie des milieux (physiques)
Definition Milieu_base.h:50
virtual const Champ_base & masse_volumique() const
Renvoie la masse volumique du milieu.
virtual const Champ_Don_base & gravite() const
Renvoie la gravite du milieu si elle a ete associe provoque une erreur sinon.
Une chaine de caractere (Nom) en majuscules.
Definition Motcle.h:26
Un tableau d'objets de la classe Motcle.
Definition Motcle.h:63
int rang(const char *const ch) const
Definition Motcle.cpp:338
classe Navier_Stokes_std Cette classe porte les termes de l'equation de la dynamique
virtual const Champ_base & diffusivite_pour_pas_de_temps() const
Operateur_Diff terme_diffusif
void dimensionner_matrice_sans_mem(Matrice_Morse &matrice) override
virtual const Champ_Inc_base & rho_la_vitesse() const
virtual void updateFluidForce(DoubleTab &)
const Milieu_base & milieu() const override
Renvoie le milieu physique de l'equation (le Fluide_base upcaste en Milieu_base).
const Motcle & domaine_application() const override
Renvoie le nom du domaine d'application: "Hydraulique".
virtual void modify_initial_variable()
void resetTime(double time) override
Reset current time of the equation. Used from ICoCo. See documentation of Problem_base::resetTime().
Operateur_Grad gradient
int reprendre(Entree &) override
Effectue une reprise a partir d'un flot d'entree.
Operateur_Conv terme_convectif
const Champ_Inc_base & inconnue() const override
Renvoie la vitesse (champ inconnue de l'equation) (version const).
void creer_champ(const Motcle &motlu) override
virtual const Champ_base & vitesse_pour_transport() const
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.
Entree & lire_cond_init(Entree &) override
Lecture des conditions initiales dans un flot d'entree.
DoubleTab & corriger_derivee_impl(DoubleTab &) override
Resolution de la pression, inconnue implicitee de Navier Stokes.
const Fluide_base & fluide() const
Renvoie le fluide incompressible (milieu physique de l'equation) associe a l'equation.
void mettre_a_jour(double temps) override
Effectue une mise a jour en temps de l'equation.
virtual void projeter()
Calcule la solution U des equations: | M(U-V)/dt + BtP = 0.
Operateur_Div & operateur_divergence()
Renvoie l'operateur de calcul de la divergence associe a l'equation.
void completer() override
Complete l'equation base, associe la pression a l'equation,.
int sauvegarder(Sortie &) const override
Appelle Equation_base::sauvegarder(Sortie&) et sauvegarde la pression sur un flot de sortie.
const Champ_base & get_champ(const Motcle &nom) const override
Champ_Inc_base & pression_pa()
bool initTimeStep(double dt) override
Allocation et initialisation de l'inconnue et des CLs jusqu'a present+dt.
void abortTimeStep() override
Reinitialiser ce qui doit l'etre.
int impr(Sortie &os) const override
Effectue quelques impressions sur un flot de sortie: - maximum de div U.
virtual void calculer_pression_hydrostatique(Champ_base &pression_hydro) const
std::vector< YAML_data > data_a_sauvegarder() const override
for PDI IO: retrieve name, type and dimensions of the fields to save/restore
void associer_pb_base(const Probleme_base &) override
S'associe au probleme: apelle Equation_base::associer_pb_base(const Probleme_base&).
virtual void sauver() const
void get_noms_champs_postraitables(Noms &nom, Option opt=NONE) const override
Operateur_Grad & operateur_gradient()
Renvoie l'operateur de calcul du gradient associe a l'equation.
virtual void discretiser_grad_p()
bool postraiter_gradient_pression_sans_masse_
Operateur_Div divergence
void update_y_plus(const DoubleTab &tab)
virtual void discretiser_assembleur_pression()
Typage de l'assembleur pression.
virtual void modify_initial_gradP(DoubleTrav &)
DoubleTab & corriger_derivee_expl(DoubleTab &) override
Add a specific term for Navier Stokes (-gradP(n)) if necessary.
int has_interface_blocs() const override
void set_param(Param &titi) const override
void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={}) const override
int verif_Cl() const override
Verifie la compatibilite des conditions limites avec l'equation.
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...
virtual int projection_a_faire()
virtual void discretiser_vitesse()
void discretiser() override
Dicretise l'equation.
void uzawa(const DoubleTab &, const Matrice_Base &, SolveurSys &, DoubleTab &, DoubleTab &)
virtual bool getCouplingInfoForFiltering() const
virtual const Champ_Don_base & diffusivite_pour_transport() const
OWN_PTR(Assembleur_base) &assembleur_pression()
int preparer_calcul() override
cf Equation_base::preparer_calcul() Assemblage du solveur pression et
Operateur_Diff & operateur_diff()
const Operateur & operateur_fonctionnel(int) const override
void reassembler_pression_si_necessaire()
const Operateur & operateur(int) const override
Renvoie le i-eme operateur de l'equation: - le terme_diffusif si i = 0.
int nombre_d_operateurs_tot() const override
void associer_milieu_base(const Milieu_base &) override
Associe un mileu physique a l'equation en construisant dynamiquement (cast) un objet de type Fluide_b...
void assembler_blocs(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={}) const override
SolveurSys & solveur_pression()
Renvoie le solveur en pression (version const).
OBS_PTR(Fluide_base) le_fluide
bool has_champ(const Motcle &nom, OBS_PTR(Champ_base) &ref_champ) const override
virtual void calculer_la_pression_en_pa()
Calcul de "la_pression_en_pa" en fonction de "la_pression".
int nombre_d_operateurs() const override
Renvoie le nombre d'operateurs de l'equation: Pour Navier Stokes Standard c'est 2.
Champ_Inc_base & pression()
void associer_fluide(const Fluide_base &un_fluide)
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
const std::string & getString() const
Definition Nom.h:92
Un tableau de chaine de caracteres (VECT(Nom)).
Definition Noms.h:26
friend class Entree
Definition Objet_U.h:76
static int dimension
Definition Objet_U.h:99
friend class Sortie
Definition Objet_U.h:75
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
static int bidim_axi
Definition Objet_U.h:102
static int axi
Definition Objet_U.h:101
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
classe Operateur_Diff Classe generique de la hierarchie des operateurs representant un terme
DoubleTab & ajouter(const DoubleTab &, DoubleTab &) const override
Appel a l'objet sous-jacent.
classe Operateur_Div Classe generique de la hierarchie des operateurs calculant la divergence
void volumique(DoubleTab &) const
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.
classe Operateur_base Classe est la base de la hierarchie des objets representant un
const SolveurSys & get_solveur() const
virtual void contribuer_a_avec(const DoubleTab &, Matrice_Morse &) const
DOES NOTHING - to override in derived classes.
SolveurSys & set_solveur()
Matrice & set_matrice()
int get_decal_temps() const
virtual void dimensionner(Matrice_Morse &) const
DOES NOTHING - to override in derived classes.
const Matrice & get_matrice() const
classe Operateur Classe generique de la hierarchie des operateurs.
Definition Operateur.h:39
virtual Operateur_base & l_op_base()=0
virtual DoubleTab & ajouter(const DoubleTab &, DoubleTab &) const =0
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
@ 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
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Probleme_U.h:109
classe Probleme_base C'est un Probleme_U qui n'est pas un couplage.
bool is_dilatable() const
const Domaine & domaine() const
Renvoie le domaine associe au probleme.
static void mp_sum_for_each(T &arg1, T &arg2)
C++14 compatible mp_sum_for_each: combine multiple mp_sum calls into one collective operation Usage: ...
Definition Process.cpp:207
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
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 est a la classe C++ ofstream ce que la classe Sortie est a la classe C++ ostream Elle re...
Definition SFichier.h:27
class Schema_Temps_base
double temps_courant() const
Renvoie le temps courant.
virtual double temps_futur(int i) const =0
double pas_de_temps() const
Renvoie le pas de temps (delta_t) courant.
virtual int nb_valeurs_futures() const =0
double temps_init() const
Renvoie le temps initial.
class SolveurSys Un SolveurSys represente n'importe qu'elle classe
Definition SolveurSys.h:32
int resoudre_systeme(const Matrice_Base &matrice, const DoubleVect &secmem, DoubleVect &solution)
void nommer(const Nom &nom) override
Definition SolveurSys.h:37
classe Solveur_Masse_base Represente la matrice de masse d'une equation.
virtual Matrice_Base & ajouter_masse(double dt, Matrice_Base &matrice, int penalisation=1) const
virtual DoubleTab & corriger_solution(DoubleTab &x, const DoubleTab &y, int incr=0) const
Classe de base des flux de sortie.
Definition Sortie.h:52
classe Source Classe generique de la hierarchie des sources, un objet Source peut
Definition Source.h:33
void typer_direct(const Nom &)
Definition Source.cpp:41
void mettre_a_jour(double temps)
Mise a jour en temps, de toute les sources de la liste.
Definition Sources.cpp:109
DoubleTab & ajouter(DoubleTab &) const
Ajoute la contribution de toutes les sources de la liste au tableau passe en parametre,...
Definition Sources.cpp:85
int nb_dim() const
Definition TRUSTTab.h:199
_SIZE_ dimension_tot(int) const override
Definition TRUSTTab.tpp:160
void copy(const TRUSTTab &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:622
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
void ajoute(_SCALAR_TYPE_ alpha, const TRUSTVect &y, Mp_vect_options opt=VECT_ALL_ITEMS)
Definition TRUSTVect.tpp:52
virtual const MD_Vector & get_md_vector() const
Definition TRUSTVect.h:123
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")
static int is_PDI_restart()
double get_seuil() const
void set_seuil(double s)