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
113 // XD_CONT this 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)`.
117 // XD_CONT For `tn+1`, the threshold value `seuil(tn+1)` will be evaluated as:
118 // XD_CONT
119 // XD_CONT ```
120 // XD_CONT If ( |max(DivU)*dt| < value )
121 // XD_CONT Seuil(tn+1)= Seuil(tn)*factor
122 // XD_CONT Else
123 // XD_CONT Seuil(tn+1)= Seuil(tn)*factor
124 // XD_CONT Endif
125 // XD_CONT ```
126 // XD_CONT
127 // XD_CONT The first parameter (value) is the mass evolution the user is ready to accept per timestep, and
128 // XD_CONT the second one (factor) is the factor of evolution for `seuil` (for example 1.1, so 10% per timestep).
129 // XD_CONT Investigations has to be lead to know more about the effects of these two last parameters on the behaviour
130 // XD_CONT of the simulations.
131 param.ajouter_non_std("solveur_bar",(this)); // XD attr solveur_bar solveur_sys_base solveur_bar OPT This keyword is
132 // XD_CONT used to define when filtering operation is called (typically for EF convective scheme, standard diffusion
133 // XD_CONT operator and Source_Qdm_lambdaup ). A file (solveur.bar) is then created and used for inversion procedure.
134 // XD_CONT Syntax is the same then for pressure solver (GCP is required for multi-processor calculations and, in a
135 // XD_CONT general way, for big meshes).
136 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.
137 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
138 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.
139}
140
142{
143 if (mot=="diffusion")
144 {
145 Cerr << "Reading and typing of the diffusion operator : " << finl;
146 terme_diffusif.associer_diffusivite(diffusivite_pour_transport());
147 is >> terme_diffusif;
148 // le champ pour le dt_stab est le meme que celui de l'operateur
149 terme_diffusif.associer_diffusivite_pour_pas_de_temps(diffusivite_pour_pas_de_temps());
150 return 1;
151 }
152 else if (mot=="convection")
153 {
154 Cerr << "Reading and typing of the convection operator : " << finl;
155 const Champ_base& vitesse_transportante = vitesse_pour_transport();
156 terme_convectif.associer_vitesse(vitesse_transportante);
157 is >> terme_convectif;
158 return 1;
159 }
160 else if (mot=="solveur_pression")
161 {
162 Cerr << "Reading and typing of pressure solver : " << finl;
163 is >> solveur_pression_;
164 Cerr<<"Pressure solver type : "<<solveur_pression_->que_suis_je()<< finl;
165 solveur_pression_.nommer("solveur_pression");
166 return 1;
167 }
168 else if (mot=="dt_projection")
169 {
170 Cerr << "Reading projection time step " << finl;
171 is >> dt_projection;
172 is >> seuil_projection;
173 return 1;
174 }
175 else if (mot=="Traitement_particulier")
176 {
177 Cerr << "Reading and typing of Traitement_particulier considered : " << finl;
178 Nom type="Traitement_particulier_NS_";
179 Motcle motbidon;
180 Motcle accouverte = "{" , accfermee = "}" ;
181 is >> motbidon;
182 if (motbidon == accouverte)
183 {
184 Motcle le_cas;
185 is >> le_cas;
186 if (le_cas == accfermee)
187 le_cas ="";
188 else
189 {
190 type+= le_cas;
191 type+= "_";
192 }
194 if (discr == "VEFPreP1B")
195 discr = "VEF";
196 type+=discr;
197 Cerr << type << finl;
198 le_traitement_particulier.typer(type);
199 le_traitement_particulier->associer_eqn(*this);
200 le_traitement_particulier->lire(is);
201 }
202 else
203 {
204 Cerr << "Error while reading Traitement_particulier for Navier_Stokes_standard equation";
205 Cerr << "A { was expected." << finl;
206 exit();
207 }
208 return 1;
209 }
210 else if (mot=="Erreur_max_DivU")
211 {
212 Cerr << "Reading DivU maximum" << finl;
213 is >> max_div_U;
214 is >> seuil_projection;
215 return 1;
216 }
217 else if (mot=="seuil_divU")
218 {
219 Cerr << "Reading the threshold value for the velocity divergence " << finl;
220 is >> seuil_divU;
221 is >> raison_seuil_divU;
222 return 1;
223 }
224 else if (mot=="solveur_bar")
225 {
226 Motcle motlu;
227 Motcle accouverte = "{" , accfermee = "}" ;
228 Nom type_solv("");
229 int acc=0;
230 int ok=0;
231 while (acc!=0 || !ok)
232 {
233 is >> motlu;
234 if (motlu==accouverte)
235 {
236 ok=1;
237 acc++;
238 };
239 if (motlu==accfermee) acc--;
240 type_solv+=" ";
241 type_solv+=motlu;
242 }
243 if (je_suis_maitre())
244 {
245 SFichier s("solveur.bar");
246 s<<type_solv<<finl;
247 s.close();
248 }
249 return 1;
250 }
251 else if (mot=="methode_calcul_pression_initiale")
252 {
253 Motcle methode;
254 is >> methode;
255 Motcles compris(4);
256 compris[0]="avec_les_cl";
257 compris[1]="avec_sources";
258 compris[2]="avec_sources_et_operateurs";
259 compris[3]="sans_rien";
262 {
263 Cerr<<methode<<" is not understood."<<finl;
264 Cerr<<" Allowed keywords are :"<<compris<<finl;
265 exit();
266 }
267 return 1;
268 }
269 else
271}
272
277
279{
280 return terme_diffusif.diffusivite();
281}
282
284{
285 return la_vitesse;
286}
287
288
289/*! @brief S'associe au probleme: apelle Equation_base::associer_pb_base(const Probleme_base&)
290 *
291 * s'associe avec les operateurs de divergence et de gradient.
292 *
293 * @param (Probleme_base& pb) le probleme auquel s'associer
294 */
296{
298 divergence.associer_eqn(*this);
299 gradient.associer_eqn(*this);
300}
301
302/*! @brief Complete l'equation base, associe la pression a l'equation,
303 *
304 * complete la divergence, le gradient et le solveur pression.
305 * Ajout de 2 termes sources: l'un representant la force centrifuge
306 * dans le cas axi-symetrique,l'autre intervenant dans la resolution
307 * en 2D axisymetrique
308 * Association d une equation de transport d interface a l ensemble
309 * de points suivis si le fluide est marque
310 *
311 */
313{
314 if (axi == 1)
315 {
316 Source t;
317 Source& so=les_sources.add(t);
318 Cerr << "Centrifuge force term creation for Axi case."<< finl;
319 Nom type_so = "Force_Centrifuge_";
320 Nom disc = discretisation().que_suis_je();
321 Nom champ = inconnue().que_suis_je();
322 champ.suffix("Champ_");
323 type_so+=disc;
324 type_so+="_";
325 type_so+=champ;
326 type_so += "_Axi";
327 so.typer_direct(type_so);
328 so->associer_eqn(*this);
329 }
330
332
333 // On ne decline pas le residu par composantes pour la vitesse:
335
336 la_pression->associer_eqn(*this);
337 la_pression->completer(le_dom_Cl_dis.valeur());
338 // [ABN] make sure the pressure knows the domaine_Cl_dis to be able to use specific postreatment like 'gravcl'
339 la_pression->associer_domaine_cl_dis(le_dom_Cl_dis);
340
341 divergence_U->associer_eqn(*this);
342 if (gradient_P) gradient_P->associer_eqn(*this);
343 la_pression_en_pa->associer_eqn(*this);
344 la_pression_en_pa->completer(le_dom_Cl_dis.valeur());
345 la_pression_en_pa->associer_domaine_cl_dis(le_dom_Cl_dis);
346 divergence.completer();
347 gradient.completer();
348 assembleur_pression_->associer_domaine_cl_dis_base(domaine_Cl_dis());
349 assembleur_pression_->completer(*this);
350
351 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
352 {
353 Domaine_dis_base& domaine = domaine_dis();
354 domaine.init_dist_paroi_globale(domaine_Cl_dis().les_conditions_limites());
355 Cerr << "Initializing distance_paroi_globale ... " << finl;
356 const DoubleTab& dist_calc = domaine.y_elem();
357 for (int e = 0 ; e < domaine.nb_elem() ; e++) distance_paroi_globale->valeurs()(e, 0) = dist_calc(e);
358 distance_paroi_globale->valeurs().echange_espace_virtuel();
359 }
360
361}
362
364{
366}
367
368/*! @brief Dicretise l'equation.
369 *
370 */
372{
373 Cerr << "Hydraulic equation discretization (Navier_Stokes_std::discretiser)" << finl;
374 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
375
377 la_vitesse->add_synonymous(Nom("velocity"));
378 champs_compris_.ajoute_champ(la_vitesse);
379
381 la_pression->add_synonymous(Nom("P_star"));
382 champs_compris_.ajoute_champ(la_pression);
383
385 la_pression_en_pa->add_synonymous(Nom("Pressure"));
387
388
391 divergence.typer();
392 divergence.l_op_base().associer_eqn(*this);
393 gradient.typer();
394 gradient.l_op_base().associer_eqn(*this);
395
396
397 champs_compris_.ajoute_champ(divergence_U);
398
399
400 // Appel a la methode virtuelle de discretisation de l'assembleur pression:
402
404}
405
407{
408 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
409 dis.vitesse(schema_temps(), domaine_dis(), la_vitesse);
410}
411
418
419/*! @brief Typage de l'assembleur pression.
420 *
421 * Le nom de l'assembleur utilise est construit comme :
422 * Assembleur_P_xxx" ou "xxx" est le nom de la discretisation.
423 * Cette methode est virtuelle et surchargee dans le front-tracking.
424 * Elle est appelee par Navier_Stokes_std::discretiser()
425 *
426 */
427
429{
430 Nom type = "Assembleur_P_";
431 type += discretisation().que_suis_je();
432 Cerr << "Navier_Stokes_std::discretiser_assembleur_pression : type="<< type << finl;
433 assembleur_pression_.typer(type);
434 assembleur_pression_->associer_domaine_dis_base(domaine_dis());
435}
436
438{
439 if (!probleme().domaine().mesh_update_required()) return;
440
441 if (!probleme().is_dilatable())
442 assembleur_pression_->assembler(matrice_pression_);
443 else
444 assembleur_pression_->assembler_QC(fluide().masse_volumique().valeurs(), matrice_pression_);
445
446 solveur_pression_->reinit();
447}
448
449/*! @brief Renvoie le nombre d'operateurs de l'equation: Pour Navier Stokes Standard c'est 2.
450 *
451 * @return (int) le nombre d'operateur de l'equation
452 */
454{
455 return 2;
456}
457
459{
460 return 4;
461}
462
463/*! @brief Renvoie le i-eme operateur de l'equation: - le terme_diffusif si i = 0
464 *
465 * - le terme_convectif si i = 1
466 * exit si i>1
467 * (version const)
468 *
469 * @param (int i) l'index de l'operateur a renvoyer
470 * @return (Operateur&) l'operateur indexe par i
471 */
473{
474 switch(i)
475 {
476 case 0:
477 return terme_diffusif;
478 case 1:
479 return terme_convectif;
480 default :
481 Cerr << "Error for Navier_Stokes_std::operateur(int i)" << finl;
482 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" operators "<<finl;
483 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
484 exit();
485 }
486 // Pour les compilos!!
487 return terme_diffusif;
488}
489
490/*! @brief Renvoie le i-eme operateur de l'equation: - le terme_diffusif si i = 0
491 *
492 * - le terme_convectif si i = 1
493 * exit si i>1
494 *
495 * @param (int i) l'index de l'operateur a renvoyer
496 * @return (Operateur&) l'operateur indexe par i
497 */
499{
500 switch(i)
501 {
502 case 0:
503 return terme_diffusif;
504 case 1:
505 return terme_convectif;
506 default :
507 Cerr << "Error for Navier_Stokes_std::operateur(int i)" << finl;
508 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" operators "<<finl;
509 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
510 exit();
511 }
512 // Pour les compilos!!
513 return terme_diffusif;
514}
515
517{
518 switch(i)
519 {
520 case 0:
521 return gradient;
522 case 1:
523 return divergence;
524 default :
525 Cerr << "Error for Navier_Stokes_std::operateur_fonctionnel(int i)" << finl;
526 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" functional operators "<<finl;
527 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
528 exit();
529 }
530 // Pour les compilos!!
532}
533
535{
536 switch(i)
537 {
538 case 0:
539 return gradient;
540 case 1:
541 return divergence;
542 default :
543 Cerr << "Error for Navier_Stokes_std::operateur_fonctionnel(int i)" << finl;
544 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" functional operators "<<finl;
545 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
546 exit();
547 }
548 // Pour les compilos!!
550}
551
552
553/*! @brief Renvoie l'operateur de calcul de la divergence associe a l'equation.
554 *
555 * @return (Operateur_Div&) l'operateur de calcul de la divergence.
556 */
561
562/*! @brief Renvoie l'operateur de calcul de la divergence associe a l'equation.
563 *
564 * (version const)
565 *
566 * @return (Operateur_Div&) l'operateur de calcul de la divergence
567 */
572
573/*! @brief Renvoie l'operateur de calcul du gradient associe a l'equation.
574 *
575 * @return (Operateur_Grad&) l'operateur de calcul du gradient
576 */
581
586
591
592/*! @brief Renvoie l'operateur de calcul du gradient associe a l'equation.
593 *
594 * (version const)
595 *
596 * @return (Operateur_Grad&) l'operateur de calcul du gradient
597 */
602
603
604/*! @brief Renvoie la vitesse (champ inconnue de l'equation) (version const)
605 *
606 * @return (Champ_Inc_base&) le champ inconnue representant la vitesse
607 */
609{
610 return la_vitesse.valeur();
611}
612
613/*! @brief Renvoie la vitesse (champ inconnue de l'equation)
614 *
615 * @return (Champ_Inc_base&) le champ inconnue representant la vitesse
616 */
618{
619 return la_vitesse.valeur();
620}
621
622/*! @brief Renvoie le solveur en pression (version const)
623 *
624 * @return (SolveurSys&) le solveur en pression
625 */
630
631/*! @brief Renvoie le fluide incompressible (milieu physique de l'equation) associe a l'equation.
632 *
633 * (version const)
634 *
635 * @return (Fluide_base&) le fluide incompressible associe a l'equation
636 */
638{
639 return le_fluide.valeur();
640}
641
642
643/*! @brief Renvoie le fluide incompressible (milieu physique de l'equation) associe a l'equation.
644 *
645 * @return (Fluide_base&) le fluide incompressible associe a l'equation
646 */
648{
649 return le_fluide.valeur();
650}
651
653{
654 Cerr << "Reading of initial conditions\n";
655 Nom nom;
656 Motcle motlu;
657 is >> nom;
658 motlu = nom;
659 if(motlu!=Motcle("{"))
660 {
661 Cerr << "We expected a { while reading " << que_suis_je() << finl;
662 Cerr << "and not : " << nom << finl;
663 exit();
664 }
665 Motcles compris(3);
666 compris[0]="}";
667 compris[1]="vitesse";
668 compris[2]="pression";
669 int ind = -1;
670 while (ind!=0)
671 {
672 is >> nom;
673 motlu = nom;
674 ind = compris.rang(motlu);
675 if (ind==1)
676 {
677 OWN_PTR(Champ_Don_base) ch_init;
678 is >> ch_init;
680 inconnue().affecter(ch_init.valeur());
681 }
682 else if (ind==2)
683 {
684 OWN_PTR(Champ_Don_base) ch_init;
685 is >> ch_init;
687 pression().affecter(ch_init.valeur());
688 }
689 else if (ind==-1)
690 {
691 Cerr << nom << " is not understood. Keywords are:" << finl;
692 Cerr << compris << finl;
693 exit();
694 }
695 }
696 return is;
697}
698
699/*! @brief Add a specific term for Navier Stokes (-gradP(n)) if necessary
700 *
701 */
702DoubleTab& Navier_Stokes_std::corriger_derivee_expl(DoubleTab& derivee)
703{
704 if (assembleur_pression_->get_resoudre_increment_pression())
705 {
706 // PL: Pour ne pas calculer ce gradient, il faut
707 // A) postraitement_gradient_P_==0 car sinon grad contient alors M-1BtP
708 // B) les conditions en pression soient stationnaires (pas facile a detecter: Orlansky, P(t), gradient_pression impose...)
709 // En outre, cela fait des ecarts avec le schema CN iteratif
710 const DoubleTab& tab_pression = la_pression->valeurs();
711 DoubleTab& gradP = gradient_P->valeurs();
712 gradient.calculer(tab_pression, gradP);
713 derivee -= gradP;
714 }
715 return derivee;
716}
717
718/*! @brief Resolution de la pression, inconnue implicitee de Navier Stokes
719 *
720 */
721DoubleTab& Navier_Stokes_std::corriger_derivee_impl(DoubleTab& derivee)
722{
723 // We want to solve:
724 // dU/dt + M-1 Bt Cp = M-1(F - BtP)
725 // B dU/dt = 0
726 // with F explicit terms: sum(operators)+sources
727 // In: derivee = M-1(F - BtP(n))
728 // Out: derivee = M-1(F - BtP(n+1)), P(n+1)=P(n)+Cp
729
730 DoubleTab& tab_pression=la_pression->valeurs();
731 DoubleTab& gradP=gradient_P->valeurs();
732 DoubleTrav secmemP(tab_pression);
733
734 const bool is_ALE = probleme().domaine().deformable();
735
737
738 const double dt = schema_temps().pas_de_temps();
740 {
741 // on veut div u =0 et non d/dt (div u)=0 pour eviter de cumuler les erreurs
742 // cela ne marche qu'avec les schema type euler_explicite
743 DoubleTab derivee2(derivee);
744 derivee2*=dt;
745 derivee2+=la_vitesse->passe();
746 derivee2/=dt;
747 divergence.calculer(derivee2, secmemP); // Div(M-1(F - BtP))
748 }
749 else if (is_ALE)
750 {
751 // ALE explicit volumetric correction:
752 // In ALE formulation, the conservative form of the transient term is:
753 // (V^{n+1} U^{n+1} - V^n U^n ) / dt
754 // For an explicit Euler scheme, this leads to the additional term:
755 // (V^n / V^{n+1}) * (U^n / dt) which is added to the explicit RHS (M-1(F - BtP)).
756 // This ensures discrete mass conservation (Geometric Conservation Law) when the mesh is deformable.
757 // This correction is required only for explicit schemes because
758 // implicit schemes naturally incorporate the volume variation inside the mass matrix formulation.
759 DoubleTab derivee2(derivee);
760 // Conservative ALE form: deriveeALE= (Volume_n+1/Volume_n)*Un/delta t + derivee
761 probleme().domaine().ajouter_correctif_volumique(la_vitesse->valeurs(), derivee, dt, derivee2);
762 divergence.calculer(derivee2, secmemP);
763 }
764 else
765 divergence.calculer(derivee, secmemP); // Div(M-1(F - BtP))
766
767 secmemP *= -1; // car div =-B
768 // Correction du second membre d'apres les conditions aux limites :
769 assembleur_pression_->modifier_secmem(secmemP);
770
771 // Set print of the linear system solve according to dt_impr:
772 solveur_pression_->fixer_schema_temps_limpr(schema_temps().limpr());
773
774 if (assembleur_pression_->get_resoudre_increment_pression())
775 {
776 // Solve B M-1 Bt Cp = M-1(F - BtP)
777 DoubleTrav Cp(tab_pression);
778 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(), secmemP, Cp);
779
780 // P(n+1) = P(n) + Cp
781 tab_pression += Cp;
782 assembleur_pression_->modifier_solution(tab_pression);
783
784 // M-1 Bt P(n+1)
785 solveur_masse->appliquer(gradP);
786 derivee += gradP; // M-1 F
787 }
788 else
789 {
790 // Solve B M-1 Bt P(n+1) = B M-1 F
791 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(), secmemP, tab_pression);
792 assembleur_pression_->modifier_solution(tab_pression);
793 // It is not done anymore cause:
794 // Iterative solvers are less accurate
795 // Time converges in O(sqrt(dt)) and not O(dt)
796 // See: http://www.sciencedirect.com/science/article/pii/S0021999108004518
797 }
798
799 // (BM) gradient operator requires updated virtual space in source vector
800 // Calculate Bt P(n+1)
801 tab_pression.echange_espace_virtuel();
802 gradient.calculer(tab_pression, gradP);
803
804 // gradP = Bt P(n+1) is kept and
805 // M-1Bt P(n+1) is calculated:
806 DoubleTrav Mmoins1gradP(gradP);
807 Mmoins1gradP = gradP;
808 solveur_masse->appliquer(Mmoins1gradP);
809
810 // dU/dt = M-1(F-Bt P(n+1))
811 derivee -= Mmoins1gradP;
812
813 return derivee;
814}
815
816/*! @brief Calcule la solution U des equations: | M(U-V)/dt + BtP = 0
817 *
818 * |-BU=0
819 * On resoud le probleme en pression: -BM-1BtP = -BV/dt
820 * sachant que -BV represente le calcul de la divergence de V
821 * On resoud le probleme en vitesse en appliquant le solveur
822 * de masse au gradient de P: U=V - dt*M-1BtP
823 *
824 * @throws pas de temps trop petit
825 */
827{
828 if (probleme().is_dilatable() && probleme().reprise_effectuee())
829 Cerr << "WARNING: Quasi compressible model --> no projection (except the first time step)." << finl;
830 else
831 {
832 Cerr << "Projection of initial and boundaries conditions " << finl;
833 DoubleTab& tab_vitesse = la_vitesse->valeurs();
834 tab_vitesse.echange_espace_virtuel();
835 la_pression->valeurs().echange_espace_virtuel();
836
837 double normal_seuil = 0.;
838
839 // M u + eBt l = M v
840 // B u = 0
841 // => e B(M-1)Bt l = Bv
842 //
844
845 DoubleTrav secmem(la_pression->valeurs());
846 divergence.calculer(tab_vitesse, secmem);
847 // Desormais on calcule le pas de temps avant la projection
848 // Avant, on avait dt=dt_min au debut du calcul
849 double dt = std::max(le_schema_en_temps->pas_temps_min(),calculer_pas_de_temps());
850 dt = std::min(dt, le_schema_en_temps->pas_temps_max());
851
852 secmem*=(-1./dt);
853 secmem.echange_espace_virtuel();
854
855 double bilan=mp_norme_vect(secmem); // TODO DG surcharger cette fonction pour avoir \sum \int_T || \sum_{nfunc_p} secmem*fbase_p ||
856 Cout << "------------- Projection -----------------" << finl;
857 Cout << "--------------------------------------------" << finl;
858 Cout << "Bilan de masse avant projection : " << bilan << finl;
859
860 if( sub_type(solv_iteratif,solveur_pression_.valeur()) )
861 {
862 solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
863 normal_seuil=solv_iter.get_seuil();
864 solv_iter.set_seuil(seuil_projection);
865 }
866
867 // Correction du second membre d'apres les conditions aux limites :
868 // Cela ne sert a rien d'initialiser lagrange avec la pression
869 // voir ca penalise le calcul en p1B et CL p<>0
870 // On prend un DoubleTrav au lieu d'un DoubleTab pour avoir lagrange=0
871 DoubleTrav lagrange(la_pression->valeurs());
872 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(),secmem,lagrange);
873 assembleur_pression_->modifier_solution(lagrange);
874 lagrange.echange_espace_virtuel();
875
876 // M-1 Bt l
877 DoubleTrav gradP(gradient_P->valeurs());
878 gradient->multvect(lagrange, gradP);
881 solveur_masse->appliquer(gradP);
883
884 if (tab_vitesse.dimension_tot(0) == gradP.dimension_tot(0))
885 tab_vitesse.ajoute(-dt,gradP);
886 else
887 {
888 DoubleTab_parts partv(tab_vitesse);
889 partv[0].ajoute(-dt,gradP);
890 }
891 tab_vitesse.echange_espace_virtuel();
892 solveur_masse->corriger_solution(tab_vitesse, tab_vitesse);
893
894 Debog::verifier("Navier_Stokes_std::projeter, vitesse", tab_vitesse);
895
896 // Verif ...
897 divergence.calculer(tab_vitesse, secmem);
898 secmem.echange_espace_virtuel();
899
900 bilan=mp_norme_vect(secmem);
901 Cout << "Bilan de masse apres projection : " << bilan << finl;
902 Cout << "------------- Projection OK---------------" << finl;
903 Cout << "--------------------------------------------" << finl;
904
905 if( sub_type(solv_iteratif,solveur_pression_.valeur()) )
906 {
907 solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
908 solv_iter.set_seuil(normal_seuil);
909 }
910 }
912}
913
915{
916 // Pas de projection si l'equation n'est pas resolue
917 // if (equation_non_resolue()) return 0;
918
919 double temps = le_schema_en_temps->temps_courant()+le_schema_en_temps->pas_de_temps();
920 // Voir Schema_Temps_base::limpr pour information sur modf
921 double nb_proj_int;
922 modf(temps/dt_projection, &nb_proj_int);
923 static double nb_proj = nb_proj_int;
925 return 1;
926 else if (inf_ou_egal((nb_proj+1.)*dt_projection,temps))
927 {
928 nb_proj=nb_proj+1.;
929 return 1;
930 }
931 return 0;
932}
933
934/*! @brief cf Equation_base::preparer_calcul() Assemblage du solveur pression et
935 *
936 * initialisation de la pression.
937 *
938 * assemblage du systeme en pression
939 *
940 * @return (int) renvoie toujours 1
941 */
943{
944 const double temps = schema_temps().temps_courant();
945 sources().mettre_a_jour(temps);
947 bool is_dilatable = probleme().is_dilatable();
948 if (!is_dilatable)
949 assembleur_pression_->assembler(matrice_pression_);
950 else
951 {
952 Cerr << "Assembling for quasi-compressible" << finl;
953 assembleur_pression_->assembler_QC(fluide().masse_volumique().valeurs(), matrice_pression_);
954 }
955
956 // GF en cas de reprise on conserve la valeur de la pression
957 // avant elle ne servait qu' a initialiser le lagrange pour la projection
958 // C'est important pour le Simpler/Piso de bien repartir de la pression
959 // sauvegardee...
960 //la_pression->valeurs()=0.;
961 Debog::verifier("Navier_Stokes_std::preparer_calcul, la_pression av projeter", la_pression->valeurs());
962 if (projection_a_faire())
963 projeter();
964
965 // Au cas ou une cl de pression depend de u que l'on vient de modifier
966 le_dom_Cl_dis->mettre_a_jour(temps);
967 Debog::verifier("Navier_Stokes_std::preparer_calcul, la_pression ap projeter", la_pression->valeurs());
968
969 // Initialisation du champ de pression (resolution de Laplacien(P)=0 avec les conditions limites en pression)
970 // Permet de demarrer la resolution avec une bonne approximation de la pression (important pour le Piso ou P!=0)
971 if (!probleme().reprise_effectuee() && methode_calcul_pression_initiale_ != 3)
972 {
973 Cout << "Estimation du champ de pression au demarrage:" << finl;
974 DoubleTrav secmem(la_pression->valeurs());
975 DoubleTrav vpoint(gradient_P->valeurs());
976 gradient.calculer(la_pression->valeurs(), gradient_P->valeurs());
977 vpoint -= gradient_P->valeurs();
978
980 for (int op = 0; op < nombre_d_operateurs(); op++)
981 operateur(op).ajouter(vpoint);
983 {
984 int mod = 0;
985 if (le_schema_en_temps->pas_de_temps() == 0)
986 {
987 double dt = std::max(le_schema_en_temps->pas_temps_min(), calculer_pas_de_temps());
988 dt = std::min(dt, le_schema_en_temps->pas_temps_max());
989 le_schema_en_temps->set_dt() = (dt);
990 mod = 1;
991 }
992 sources().ajouter(vpoint);
993 if (mod)
994 le_schema_en_temps->set_dt() = 0;
995 }
996
997 solveur_masse->appliquer(vpoint);
998 vpoint.echange_espace_virtuel();
999 divergence.calculer(vpoint, secmem);
1000 secmem *= -1;
1001 secmem.echange_espace_virtuel();
1002
1003 assembleur_pression_->modifier_secmem_pour_incr_p(la_pression->valeurs(), 1, secmem);
1004 DoubleTrav inc_pre(la_pression->valeurs());
1005 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(), secmem, inc_pre);
1006 Cerr << "Pressure increment computed successfully" << finl;
1007
1008 // On veut que l'espace virtuel soit a jour, donc all_items
1009 operator_add(la_pression->valeurs(), inc_pre, VECT_ALL_ITEMS);
1010 }
1011 // Mise a jour pression
1012 la_pression->changer_temps(temps);
1014 // Calcul des forces de pression:
1015 gradient->calculer_flux_bords();
1016
1017 // Calcul gradient_P (ToDo rendre coherent avec ::mettre_a_jour()):
1018 gradient.calculer(la_pression->valeurs(), gradient_P->valeurs());
1019 gradient_P->changer_temps(temps);
1020
1021 // Calcul divergence_U
1022 divergence.calculer(la_vitesse->valeurs(), divergence_U->valeurs());
1023 divergence_U->changer_temps(temps);
1024
1025 if (le_traitement_particulier)
1026 le_traitement_particulier->preparer_calcul_particulier();
1027
1028 Debog::verifier("Navier_Stokes_std::preparer_calcul, vitesse", inconnue());
1029 Debog::verifier("Navier_Stokes_std::preparer_calcul, pression", la_pression);
1030
1031 return 1;
1032}
1033
1034/*! @brief Effectue une mise a jour en temps de l'equation.
1035 *
1036 * Appelle Equation_base::mettre_a_jour(double)
1037 * et met a jour la pression.
1038 * Integration des points suivis si le fluide est marque
1039 * Mise a jour du champ postraitable correspondant
1040 *
1041 * @param (double temps) le temps de mise a jour
1042 */
1044{
1045 // Mise a jour de la classe mere (on tourne la roue).
1047
1048 // Mise a jour de la pression
1049 la_pression->mettre_a_jour(temps);
1051 // Calcul des forces de pression:
1052 gradient->calculer_flux_bords();
1053
1054 // Update the divergence of the velocity div(U)
1055// statistics().end_count(STD_COUNTERS::update_variables,0,0);
1056 divergence.calculer(la_vitesse->valeurs(),divergence_U->valeurs());
1057 //statistics().begin_count(STD_COUNTERS::update_variables,statistics().get_last_opened_counter_level()+1);
1058 divergence_U->mettre_a_jour(temps);
1059
1060 // Pour le postraitement, on veut M-1BtP et non BtP
1061 if (postraitement_gradient_P_)
1062 {
1063 gradient.calculer(la_pression->valeurs(), gradient_P->valeurs());
1065 solveur_masse->appliquer(gradient_P->valeurs());
1066 gradient_P->mettre_a_jour(temps);
1067 }
1068
1069 // PQ : 04/03 : procedure de determination dynamique du seuil de convergence en pression
1070 if(sub_type(solv_iteratif,solveur_pression_.valeur()) && seuil_divU < 1.)
1071 {
1072 // Calcul dynamique d'un seuil sur le solveur iteratif de pression
1073 solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
1074 double seuil_dyn=solv_iter.get_seuil();
1075
1076 if(LocalFlowRateRelativeError()<seuil_divU)
1077 seuil_dyn*=raison_seuil_divU;
1078 else
1079 seuil_dyn/=raison_seuil_divU;
1080 double seuil_dyn_max = 1.e-10;
1081 seuil_dyn=std::max(seuil_dyn,seuil_dyn_max);
1082 solv_iter.set_seuil(seuil_dyn);
1083 }
1084 // fin procedure de determination du seuil dynamique de convergence en pression
1085
1086 if (projection_a_faire())
1087 projeter();
1088
1089 if (le_traitement_particulier)
1090 le_traitement_particulier->post_traitement_particulier();
1091 Debog::verifier("Navier_Stokes_std::mettre_a_jour : pression", la_pression->valeurs());
1092 Debog::verifier("Navier_Stokes_std::mettre_a_jour : vitesse", la_vitesse->valeurs());
1093
1094 if (la_vorticite) la_vorticite->mettre_a_jour(temps);
1095 if (critere_Q) critere_Q->mettre_a_jour(temps);
1096 if (Reynolds_maille) Reynolds_maille->mettre_a_jour(temps);
1097 if (Taux_cisaillement) Taux_cisaillement->mettre_a_jour(temps);
1098 if (grad_u) grad_u->mettre_a_jour(temps);
1099}
1100
1101double Navier_Stokes_std::LocalFlowRateRelativeError() const
1102{
1103 // Estimation of a flow rate relative error
1104 DoubleTrav array(divergence_U->valeurs()); // array(i)=sum(u.ndS)
1105 divergence.volumique(array); // array(i)=sum(u.ndS)/vol(i)
1106 return mp_max_abs_vect(array) * schema_temps().pas_de_temps(); // =max|sum(u.ndS)/(vol(i)/dt)|
1107}
1108
1110{
1111 // On reprend la pression du debut du pas de temps
1112 // Utile si on reprend le pas de temps parce que la pression a diverge (sinon tres mauvaise precision)
1113 // et si on est en Piso (suppose pression juste au debut du pas de temps).
1114 pression().valeurs()=P_n;
1115 //pression().valeurs()=0;
1117}
1118
1119/* @brief Override. Reset pression too !
1120 */
1122{
1123 pression().resetTime(time);
1125}
1126
1128{
1129 P_n=pression().valeurs();
1130
1131 // Verification que dt_max est correctement fixe pour un champ
1132 // de vitesse nul et diffusion_implicite active <=> dt_conv=INF
1133 const Schema_Temps_base& sch_tps = le_schema_en_temps.valeur();
1134 bool ddt = Equation_base::initTimeStep(dt);
1135
1136 for (int i=1; i<=sch_tps.nb_valeurs_futures(); i++)
1137 if (i <= pression().nb_valeurs_temporelles())
1138 {
1139 double tps=sch_tps.temps_futur(i);
1140 // Mise a jour du temps dans les champs de pression
1143 pression().futur(i)=pression().valeurs();
1145 }
1146
1147 return ddt;
1148}
1149
1150/*! @brief Calcul de "la_pression_en_pa" en fonction de "la_pression".
1151 *
1152 * Si le champ milieu().masse_volumique() est uniforme, on suppose que
1153 * la_pression est P* = P/rho, et on multiplie par rho. Sinon,
1154 * la_pression est deja en Pa.
1155 * Cette methode est surchargee en front-tracking.
1156 *
1157 */
1159{
1160 DoubleTab& Pa=la_pression_en_pa->valeurs();
1161 DoubleTab& tab_pression=la_pression->valeurs();
1162 const Champ_base& rho=milieu().masse_volumique();
1163 if (Pa.get_md_vector() == tab_pression.get_md_vector())
1164 Pa = tab_pression; //Pa et tab_pression ont le meme support
1165 else
1166 {
1167 ConstDoubleTab_parts ppart(tab_pression);
1168 assert(Pa.get_md_vector() == ppart[0].get_md_vector());
1169 Pa = ppart[0]; //tab_pression a un morceau en plus
1170 }
1171 // On multiplie par rho si uniforme sinon deja en Pa...
1172 if (sub_type(Champ_Uniforme,rho))
1173 Pa *= rho.valeurs()(0,0);
1174 la_pression_en_pa->mettre_a_jour(pression().temps());
1175}
1176
1177/*! @brief for PDI IO: retrieve name, type and dimensions of the fields to save/restore
1178 *
1179 */
1180std::vector<YAML_data> Navier_Stokes_std::data_a_sauvegarder() const
1181{
1182 std::vector<YAML_data> data = Equation_base::data_a_sauvegarder();
1183 std::vector<YAML_data> pression = la_pression->data_a_sauvegarder();
1184 data.insert(data.end(), pression.begin(), pression.end());
1185 return data;
1186}
1187
1188/*! @brief Appelle Equation_base::sauvegarder(Sortie&) et sauvegarde la pression sur un flot de sortie.
1189 *
1190 * @param (Sortie& os) un flot de sortie sur lequel sauvegarder
1191 * @return (int) renvoie toujours 1
1192 */
1194{
1195 int bytes=0;
1196 bytes += Equation_base::sauvegarder(os);
1197 bytes += la_pression->sauvegarder(os);
1198 //La methode sauver() assurant la sauvegarde pour le traitement particulier
1199 //est maintenant appelee ici au lieu d etre appelee dans des problemes particuliers
1200 sauver();
1201
1202 return bytes;
1203}
1204
1205/*! @brief Effectue une reprise a partir d'un flot d'entree.
1206 *
1207 * Appelle Equation_base::reprendre()
1208 * et reprend la pression.
1209 *
1210 * @param (Entree& is) un flot d'entree
1211 * @return (int) renvoie toujours 1
1212 * @throws la reprise a echoue, identificateur de la pression non trouve
1213 */
1215{
1218 {
1219 double temps = schema_temps().temps_courant();
1220 Nom ident_pression(la_pression->le_nom());
1221 ident_pression += la_pression->que_suis_je();
1222 ident_pression += probleme().domaine().le_nom();
1223 ident_pression += Nom(temps,probleme().reprise_format_temps());
1224 if (probleme().discretisation().is_poly_family())
1225 {
1226 Nom field_tag_syno = create_polymacfamily_syno(ident_pression);
1227 avancer_fichier_with_syno(is,ident_pression,field_tag_syno);
1228 }
1229 // end of the backward compatibility
1230 else
1231 avancer_fichier(is,ident_pression);
1232 }
1233 la_pression->reprendre(is);
1234
1235 if (le_traitement_particulier)
1236 le_traitement_particulier->reprendre_stat();
1237
1238 return 1;
1239}
1240
1241/*! @brief Associe un mileu physique a l'equation en construisant dynamiquement (cast) un objet de type Fluide_base
1242 *
1243 * a partir de l'objet Milieu_base passe en parametre.
1244 *
1245 * @param (Milieu_base& un_milieu) le milieu a associer a l'equation
1246 */
1248{
1249 if (sub_type(Fluide_base, un_milieu))
1250 {
1251 const Fluide_base& un_fluide = ref_cast(Fluide_base,un_milieu);
1252 associer_fluide(un_fluide);
1253 }
1254 else
1255 {
1256 Cerr << "Error of fluid type for the method Navier_Stokes_std::associer_milieu_base" << finl;
1257 exit();
1258 }
1259}
1260
1261/*! @brief Renvoie le milieu physique de l'equation (le Fluide_base upcaste en Milieu_base)
1262 *
1263 * @return (Milieu_base&) le Fluide_base de l'equation upcaste en Milieu_base
1264 */
1266{
1267 if (!le_fluide)
1268 {
1269 Cerr << "You forgot to associate a fluid to the problem named " << probleme().le_nom() << finl;
1270 Process::exit();
1271 }
1272 return le_fluide.valeur();
1273}
1274
1275/*! @brief Renvoie le milieu physique de l'equation (le Fluide_base upcaste en Milieu_base)
1276 *
1277 * (version const)
1278 *
1279 * @return (Milieu_base&) le Fluide_base de l'equation upcaste en Milieu_base
1280 */
1282{
1283 if (!le_fluide)
1284 {
1285 Cerr << "You forgot to associate a fluid to the problem named " << probleme().le_nom() << finl;
1286 Process::exit();
1287 }
1288 return le_fluide.valeur();
1289}
1290
1292{
1294
1295 if (motlu == "vorticite")
1296 {
1297 if (!la_vorticite)
1298 {
1299 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1300 dis.creer_champ_vorticite(schema_temps(),la_vitesse,la_vorticite);
1301 champs_compris_.ajoute_champ(la_vorticite);
1302 }
1303 }
1304 else if (motlu == "critere_Q")
1305 {
1306 if (!critere_Q)
1307 {
1308 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
1309 dis.critere_Q(domaine_dis(),domaine_Cl_dis(),la_vitesse,critere_Q);
1310 champs_compris_.ajoute_champ(critere_Q);
1311 }
1312 }
1313 else if (motlu == "y_plus")
1314 {
1315 if (!y_plus)
1316 {
1317 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1318 dis.y_plus(domaine_dis(),domaine_Cl_dis(),la_vitesse,y_plus);
1319 champs_compris_.ajoute_champ(y_plus);
1320 }
1321 }
1322 else if (motlu == "distance_paroi_globale")
1323 {
1324 if (!distance_paroi_globale)
1325 {
1326 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1327 dis.distance_paroi_globale(schema_temps(), domaine_dis(), distance_paroi_globale);
1328 champs_compris_.ajoute_champ(distance_paroi_globale);
1329 }
1330 }
1331 else if (motlu == "reynolds_maille")
1332 {
1333 if (!Reynolds_maille)
1334 {
1335 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1337 champs_compris_.ajoute_champ(Reynolds_maille);
1338 }
1339 }
1340 else if (motlu == "courant_maille")
1341 {
1342 if (!Courant_maille)
1343 {
1344 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1346 champs_compris_.ajoute_champ(Courant_maille);
1347 }
1348 }
1349 else if (motlu == "taux_cisaillement")
1350 {
1351 if (!Taux_cisaillement)
1352 {
1353 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1355 champs_compris_.ajoute_champ(Taux_cisaillement);
1356 }
1357 }
1358 else if (motlu == "pression_hydrostatique")
1359 {
1361 {
1362 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1363 dis.discretiser_champ("Champ_sommets",domaine_dis(),"pression_hydrostatique","Pa",1,0.,pression_hydrostatique_);
1365 }
1366 }
1367
1368 else if (motlu == "gradient_vitesse")
1369 {
1370 if (!grad_u)
1371 {
1372 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
1373 dis.grad_u(domaine_dis(),domaine_Cl_dis(),la_vitesse,grad_u);
1374 champs_compris_.ajoute_champ(grad_u);
1375 }
1376 }
1377
1378 if (le_traitement_particulier)
1379 le_traitement_particulier->creer_champ(motlu);
1380
1382 if (!grad_u) creer_champ("gradient_vitesse");
1383}
1384
1386{
1387 DoubleTab& val= pression_hydro.valeurs();
1388 const DoubleTab& coords = domaine_dis().domaine().les_sommets();
1389 if (!milieu().a_gravite())
1390 {
1391 Cerr<<"postprocessing of presion_hydrostatique needs gravity"<<finl;
1392 exit();
1393 }
1394 const Champ_base& rho = milieu().masse_volumique();
1395 if (!sub_type(Champ_Uniforme,rho))
1396 {
1397 Cerr<<"postprocessing of presion_hydrostatique availabe only for incompressible flow"<<finl;
1398 exit();
1399 }
1400 const DoubleTab& gravite = milieu().gravite().valeurs();
1401
1402 val=rho.valeurs()(0,0);
1403 const int nb_som=val.dimension(0);
1404
1405 for (int som=0; som<nb_som; som++)
1406 {
1407 double gz=0;
1408 for (int dir=0; dir<dimension; dir++)
1409 gz+=coords(som,dir)*gravite(0,dir);
1410 val[som]*=gz;
1411 }
1413}
1414
1415bool Navier_Stokes_std::has_champ(const Motcle& nom, OBS_PTR(Champ_base)& ref_champ) const
1416{
1417 if (nom == "gradient_pression")
1418 {
1419 ref_champ = Navier_Stokes_std::get_champ(nom);
1420 return true;
1421 }
1422
1423 if (nom == "vorticite" && la_vorticite)
1424 {
1425 ref_champ = Navier_Stokes_std::get_champ(nom);
1426 return true;
1427 }
1428
1429 if (nom == "critere_Q" && critere_Q)
1430 {
1431 ref_champ = Navier_Stokes_std::get_champ(nom);
1432 return true;
1433 }
1434
1435 if (nom == "y_plus" && y_plus)
1436 {
1437 ref_champ = Navier_Stokes_std::get_champ(nom);
1438 return true;
1439 }
1440
1441 if (nom == "reynolds_maille" && Reynolds_maille)
1442 {
1443 ref_champ = Navier_Stokes_std::get_champ(nom);
1444 return true;
1445 }
1446
1447 if (nom == "courant_maille" && Courant_maille)
1448 {
1449 ref_champ = Navier_Stokes_std::get_champ(nom);
1450 return true;
1451 }
1452
1453 if (nom == "taux_cisaillement" && Taux_cisaillement)
1454 {
1455 ref_champ = Navier_Stokes_std::get_champ(nom);
1456 return true;
1457 }
1458
1459 if (nom == "gradient_vitesse" && grad_u)
1460 {
1461 ref_champ = Navier_Stokes_std::get_champ(nom);
1462 return true;
1463 }
1464
1465 if (nom == "pression_hydrostatique" && pression_hydrostatique_)
1466 {
1467 ref_champ = Navier_Stokes_std::get_champ(nom);
1468 return true;
1469 }
1470
1471 if (Equation_base::has_champ(nom, ref_champ))
1472 return true;
1473
1474 if (le_traitement_particulier)
1475 if (le_traitement_particulier->has_champ(nom, ref_champ))
1476 return true;
1477
1478 return false; /* rien trouve */
1479}
1480
1482{
1483 if (nom == "gradient_pression")
1484 return true;
1485
1486 if (nom == "vorticite" && la_vorticite)
1487 return true;
1488
1489 if (nom == "critere_Q" && critere_Q)
1490 return true;
1491
1492 if (nom == "y_plus" && y_plus)
1493 return true;
1494
1495 if (nom == "reynolds_maille" && Reynolds_maille)
1496 return true;
1497
1498 if (nom == "courant_maille" && Courant_maille)
1499 return true;
1500
1501 if (nom == "taux_cisaillement" && Taux_cisaillement)
1502 return true;
1503
1504 if (nom == "gradient_vitesse" && grad_u)
1505 return true;
1506
1507 if (nom == "pression_hydrostatique" && pression_hydrostatique_)
1508 return true;
1509
1510 if (Equation_base::has_champ(nom))
1511 return true;
1512
1513 if (le_traitement_particulier)
1514 if (le_traitement_particulier->has_champ(nom))
1515 return true;
1516
1517 return false; /* rien trouve */
1518}
1519
1521{
1522 double temps_init = schema_temps().temps_init();
1523 if (nom == "gradient_pression")
1524 postraitement_gradient_P_ = 1;
1525
1526 if (nom == "vorticite")
1527 {
1528 if (!la_vorticite)
1529 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1530
1531 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, la_vorticite.valeur());
1532 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1533 ch.mettre_a_jour(la_vitesse->temps());
1534 return champs_compris_.get_champ(nom);
1535 }
1536
1537 if (nom == "critere_Q")
1538 {
1539 if (!critere_Q)
1540 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1541
1542 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, critere_Q.valeur());
1543 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1544 ch.mettre_a_jour(la_vitesse->temps());
1545 return champs_compris_.get_champ(nom);
1546 }
1547
1548 if (nom == "y_plus")
1549 {
1550 if (!y_plus)
1551 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1552
1553 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, y_plus.valeur());
1554 if (((ch.temps() != la_vitesse->temps()) || (ch.temps() == temps_init)) && (la_vitesse->mon_equation_non_nul()))
1555 ch.mettre_a_jour(la_vitesse->temps());
1556 return champs_compris_.get_champ(nom);
1557 }
1558
1559 if (nom == "reynolds_maille")
1560 {
1561 if (!Reynolds_maille)
1562 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1563
1564 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, Reynolds_maille.valeur());
1565 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1566 ch.mettre_a_jour(la_vitesse->temps());
1567 return champs_compris_.get_champ(nom);
1568 }
1569
1570 if (nom == "courant_maille")
1571 {
1572 if (!Courant_maille)
1573 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1574
1575 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, Courant_maille.valeur());
1576 if (((ch.temps() != la_vitesse->temps()) || (ch.temps() == temps_init)) && (la_vitesse->mon_equation_non_nul()))
1577 ch.mettre_a_jour(la_vitesse->temps());
1578 return champs_compris_.get_champ(nom);
1579 }
1580
1581 if (nom == "taux_cisaillement")
1582 {
1583 if (!Taux_cisaillement)
1584 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1585
1586 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, Taux_cisaillement.valeur());
1587 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1588 ch.mettre_a_jour(la_vitesse->temps());
1589 return champs_compris_.get_champ(nom);
1590 }
1591
1592 if (nom == "gradient_vitesse")
1593 {
1594 if (!grad_u)
1595 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1596
1597 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, grad_u.valeur());
1598 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1599 ch.mettre_a_jour(la_vitesse->temps());
1600 return champs_compris_.get_champ(nom);
1601 }
1602
1603 if (nom == "pression_hydrostatique")
1604 {
1606 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1607
1608 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, pression_hydrostatique_.valeur());
1609 if (((ch.temps() != la_vitesse->temps()) || (ch.temps() == temps_init)) && (la_vitesse->mon_equation_non_nul()))
1610 {
1612 ch.mettre_a_jour(la_vitesse->temps());
1613 }
1614 return champs_compris_.get_champ(nom);
1615 }
1616
1617 OBS_PTR(Champ_base) ref_champ;
1618
1619 if (Equation_base::has_champ(nom, ref_champ))
1620 return ref_champ;
1621
1622 if (le_traitement_particulier)
1623 if (le_traitement_particulier->has_champ(nom, ref_champ))
1624 return ref_champ;
1625
1626 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1627}
1628
1630{
1632
1633 if (le_traitement_particulier)
1634 le_traitement_particulier->get_noms_champs_postraitables(nom, opt);
1635
1636 Noms noms_compris = champs_compris_.liste_noms_compris();
1637 noms_compris.add("vorticite");
1638 noms_compris.add("critere_Q");
1639 noms_compris.add("y_plus");
1640 noms_compris.add("reynolds_maille");
1641 noms_compris.add("courant_maille");
1642 noms_compris.add("taux_cisaillement");
1643 noms_compris.add("pression_hydrostatique");
1644 noms_compris.add("gradient_vitesse");
1645
1646 if (opt == DESCRIPTION)
1647 Cerr << " Navier_Stokes_std : " << noms_compris << finl;
1648 else
1649 nom.add(noms_compris);
1650}
1651
1652/*! @brief Effectue quelques impressions sur un flot de sortie: - maximum de div U
1653 *
1654 * - terme convectif
1655 * - terme diffusif
1656 * - divergence
1657 * - gradient
1658 *
1659 * @param (Sortie& os) un flot de sortie
1660 * @return (int) renvoie toujours 1
1661 */
1663{
1664 // Affichage des bilans volumiques si on n'est pas en QC, ni en Front Tracking
1665 if (!probleme().is_dilatable() && probleme().que_suis_je()!="Probleme_FT_Disc_gen")
1666 {
1667 double LocalFlowRateError=mp_max_abs_vect(divergence_U->valeurs());
1668 os << finl;
1669 os << "Cell balance flow rate control for the problem " << probleme().le_nom() << " : " << finl;
1670 os << "Absolute value : " << LocalFlowRateError << " m"<<dimension+bidim_axi<<"/s" << finl;
1671 os << "Relative value : " << LocalFlowRateRelativeError() << finl; // max|sum(u.ndS)i/(vol(i)/dt)|=max|div(U)i/dt|
1672 // Calculation as OpenFOAM: http://foam.sourceforge.net/docs/cpp/a04190_source.html
1673 // It is relative errors (normalized by the volume/dt)
1674 double dt = schema_temps().pas_de_temps();
1675 double local = LocalFlowRateError / ( probleme().domaine().volume_total() / dt );
1676 double global = mp_somme_vect(divergence_U->valeurs()) / ( probleme().domaine().volume_total() / dt );
1677 cumulative_ += global;
1678 os << "time step continuity errors : sum local = " << local << ", global = " << global << ", cumulative = " << cumulative_ << finl;
1679 // Nouveau 1.6.1, arret si bilans de masse mauvais et seuil<1.e20
1680 if (local>0.01 && sub_type(solv_iteratif,solveur_pression_.valeur()))
1681 {
1682 if (ref_cast(solv_iteratif,solveur_pression_.valeur()).get_seuil()<1e10)
1683 {
1684 Cerr << "The mass balance is too bad (relative value>1%)." << finl;
1685 Cerr << "Please check and lower the convergence value of the pressure solver." << finl;
1686 exit();
1687 }
1688 }
1689#ifndef TRUST_USE_GPU
1690 // Since 1.6.6, warning to use PETSc Cholesky instead of an iterative method for pressure solver
1691 int nw=100;
1692 if (solveur_pression_->solveur_direct()==0 && le_schema_en_temps->nb_pas_dt()<nw && Process::nproc()<256 && la_pression->valeurs().size_array()<40000)
1693 {
1694 Cerr << finl << "********************** Advice (printed only on the first " << nw << " time steps) *********************" << finl;
1695 Cerr << "You should use PETSc Cholesky solver instead of an iterative method for the pressure solver." << finl;
1696 Cerr << "For the caracteristics of your problem, it will be faster and give a better mass flow balance." << finl;
1697 Cerr << "**********************************************************************************************" << finl << finl;
1698 }
1699#endif
1700 }
1701
1702 if ((seuil_divU < 1.) && (sub_type(solv_iteratif,solveur_pression_.valeur())))
1703 {
1704 const solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
1705 os << " seuil de convergence du solveur iteratif : " << solv_iter.get_seuil() << finl;
1706 }
1708 divergence.impr(os);
1709 gradient.impr(os);
1710 return 1;
1711}
1712
1713
1714/*! @brief Renvoie le nom du domaine d'application: "Hydraulique".
1715 *
1716 * @return (Motcle&) lenom representant le domaine d'application
1717 */
1719{
1720 static Motcle domaine = "Hydraulique";
1721 return domaine;
1722}
1723
1724static void construire_matrice_implicite(Operateur_base& op,
1725 const DoubleTab& valeurs_inconnue,
1726 const Solveur_Masse_base& solv_masse,
1727 const double dt)
1728{
1729 Matrice& mat = op.set_matrice();
1730 if(!mat)
1731 mat.typer("Matrice_Morse");
1732
1733 if(op.get_decal_temps()==1)
1734 {
1735 Matrice_Morse& matrice = ref_cast(Matrice_Morse, mat.valeur());
1736 op.dimensionner(matrice);
1737 op.contribuer_a_avec(valeurs_inconnue, matrice);
1738 solv_masse.ajouter_masse(dt, matrice);
1739 matrice *= dt;
1740
1741 // Si le solveur est cholesky ou gcp, on attend une matrice de type
1742 // Matrice_Morse_Sym. Transformation du type de la matrice:
1743 const Nom& type_solveur = op.get_solveur()->que_suis_je();
1744 if(type_solveur == "Solv_Cholesky" || type_solveur == "Solv_GCP")
1745 {
1746 Matrice_Morse_Sym new_mat(matrice);
1747 new_mat.set_est_definie(1);
1748 // mat est detruite puis reconstruite:
1749 mat = new_mat;
1750 // Reinitialisation du solveur (recalcul des preconditionnements, factorisation, etc...)
1751 //ref_cast_non_const(SolveurSys_base,op.get_solveur().valeur()).reinit();
1752 op.set_solveur()->reinit();
1753 }
1754 }
1755}
1756
1757/* dans PolyMAC_HFV, le gradient contribue a la matrice de l'equation de N-S */
1759{
1761 if (gradient->has_interface_blocs())
1762 gradient->dimensionner_blocs({{ "vitesse", &matrice }});
1763}
1764
1766{
1767 return Equation_base::has_interface_blocs() && gradient->has_interface_blocs();
1768}
1769
1770/* le gradient passe en dernier */
1771void Navier_Stokes_std::dimensionner_blocs(matrices_t matrices, const tabs_t& semi_impl) const
1772{
1773 Equation_base::dimensionner_blocs(matrices, semi_impl);
1774 gradient->dimensionner_blocs(matrices, semi_impl);
1775}
1776
1777void Navier_Stokes_std::assembler_blocs(matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl) const
1778{
1779 Equation_base::assembler_blocs(matrices, secmem, semi_impl);
1780 gradient->ajouter_blocs(matrices, secmem, semi_impl);
1781}
1782
1783DoubleTab& Navier_Stokes_std::derivee_en_temps_inco(DoubleTab& derivee)
1784{
1786 // Calcul de la derivee en temps:
1787 if(!implicite_)
1788 {
1789 // Calcul explicite, on utilise la derivee en temps standard:
1791 }
1792 else
1793 {
1794 // Calcul implicite d'un ou plusieurs operateurs (peu utilise)
1795 // Syntaxe jeu de donnees: operateur { implicite solveur cholesky|gcp ... }
1796 derivee = 0;
1797 for(int i=0; i<nombre_d_operateurs(); i++)
1798 operateur(i).ajouter(derivee);
1799
1800 les_sources.ajouter(derivee);
1801 derivee.echange_espace_virtuel();
1802
1803 const double dt=schema_temps().pas_de_temps();
1804 static double dt_old=dt;
1805
1806 for(int i=0; i<nombre_d_operateurs(); i++)
1807 {
1809 // If matrix not build or matrix time dependant:
1810 if(!op.get_matrice() || !sys_invariant_)
1811 construire_matrice_implicite(op, inconnue().valeurs(), solv_masse(), dt);
1812
1813 if(op.get_decal_temps()==1)
1814 {
1815 if(sys_invariant_ && dt!=dt_old)
1816 {
1817 // La matrice ne change pas mais on change le pas de temps.
1818 // La matrice s'ecrit A =
1819 // Mise a jour simplifiee de la matrice
1820 Matrice_Morse& matrice=ref_cast(Matrice_Morse, op.set_matrice().valeur());
1821 matrice/=dt_old;
1822 solv_masse().ajouter_masse(-dt_old, op.set_matrice().valeur());
1823 solv_masse().ajouter_masse(dt, op.set_matrice().valeur());
1824 matrice*=dt;
1825 ref_cast_non_const(SolveurSys_base,op.get_solveur().valeur()).reinit();
1826 }
1827 Matrice_Morse& matrice=ref_cast(Matrice_Morse, op.set_matrice().valeur());
1828 if(implicite_==1)
1829 {
1830 // Un seul operateur implicite.
1831 DoubleTrav secmem(derivee);
1832 secmem=derivee;
1833 DoubleTrav incre_pre(la_pression->valeurs());
1834 gradient.calculer(la_pression->valeurs(),gradient_P->valeurs());
1835 secmem-=gradient_P->valeurs();
1836 uzawa(secmem, matrice,op.set_solveur(),derivee, incre_pre);
1837
1838 la_pression->valeurs()+=incre_pre;
1839 gradient.calculer(la_pression->valeurs(),gradient_P->valeurs());
1840 }
1841 else
1842 {
1843 // plusieurs operateurs implicites ...
1844 Cerr << "To be developped ... " << finl;
1845 exit();
1846 }
1847 }
1848 }
1849 dt_old=dt;
1850 return derivee;
1851 }
1852}
1853
1854void Navier_Stokes_std::uzawa(const DoubleTab& secmem, const Matrice_Base& A, SolveurSys& solveur, DoubleTab& U, DoubleTab& P)
1855{
1856 // A U + Bt P = secmem
1857 // B U = G
1858 // On part de la pression courante et
1859 // secmem = inertie + conv + sources + cl diff
1860 // On part de P0 et U0 verifiant les C.L. et BU0=G
1861
1862 // AU + Bt Cp = secmem
1863 // BU = 0
1864
1865 // On ecrit un GC sur B(A-1)Bt Cp = B(A-1)(secmem)
1866
1867 DoubleTrav Cu(U);
1868 DoubleTrav grad(U);
1869 DoubleTrav grad0(U);
1870 DoubleTrav resu(P);
1871 DoubleTrav residu(P);
1872 DoubleTrav Cp(P);
1873 double dold,dnew,alfa;
1874 double seuil=seuil_uzawa;
1875
1876 //Cu = A(-1) secmem
1877 Cerr << "Begining Uzawa, secmem norm value : " << mp_norme_vect(secmem) << finl;
1878 P=0.;
1879 gradient->multvect(P, grad0);
1880 solveur.nommer("uzawa_solver");
1881 solveur.resoudre_systeme(A, secmem, U);
1882 solv_masse().corriger_solution(U,Cu); // pour les C.L. de Dirichlet!
1883
1884 // residu=BCu
1885 divergence->multvect(U, resu);
1886
1887 residu.copy(resu);
1888 residu*=-1.;
1889
1890 // Cp = -residu;
1891 Cp = residu;
1892 Cp*=-1;
1894
1895 // Carre de la norme
1896 dold = mp_norme_vect(residu);
1897 dold = dold * dold;
1898 dnew = dold;
1899
1900 double s=0;
1901 int niter=0;
1902 int nmax=Cp.size();
1903 Cerr << "Uzawa, initial residue : " << dnew << finl;
1904 // seuil=std::max(seuil, dnew*1.e-12);
1905 while ( ( dnew > seuil ) && (niter++ < nmax) )
1906 {
1907 gradient->multvect(Cp, grad);
1908 grad-=grad0;
1909 grad*=-1;
1910 solveur.resoudre_systeme(A, grad, Cu);
1911 solv_masse().corriger_solution(Cu,U); // pour les C.L. de Dirichlet!
1912 divergence->multvect(Cu, resu);
1913 resu*=-1;
1914
1915 s = mp_prodscal(resu, Cp);
1916 alfa = dold/(s);
1917 P.ajoute(alfa,Cp);
1918 residu.ajoute(alfa,resu);
1919 U.ajoute(alfa,Cu);
1920 dnew = mp_norme_vect(residu);
1921 dnew = dnew * dnew;
1922 assert(dnew >= 0);
1923 Cp *= (dnew/dold);
1924 Cp -= residu;
1925 dold = dnew;
1926 // Cerr << "Uzawa, Residu apres "
1927 // << niter << " iterations = " << dnew << finl;
1928 }
1929
1930 if(dnew > seuil)
1931 {
1932 Cerr << "######## Uzawa, No convergence after : " << niter << " iterations\n";
1933 Cerr << "######## Uzawa, Residue : "<< dnew << "\n";
1934 exit();
1935 }
1936
1937 else if ((je_suis_maitre()))
1938 {
1939 Cerr << finl << "Uzawa, convergence reached after " << niter << " iterations" << finl;
1940 }
1941 {
1942 // On verifie :
1943
1944 DoubleTrav R(resu);
1945 divergence->multvect(U, R);
1946
1947 gradient->multvect(P, grad);
1948 grad-=grad0;
1949 DoubleTrav F(secmem);
1950 DoubleTrav UU(U);
1951 F=secmem;
1952 F-=grad;
1953
1954 solveur.resoudre_systeme(A, F, UU);
1955 UU-=U;
1956
1957 // Optimization: combine 2 mp_norme_vect into 1 collective call
1958 double R_carre = local_carre_norme_vect(R);
1959 double UU_carre = local_carre_norme_vect(UU);
1960 Process::mp_sum_for_each(R_carre, UU_carre);
1961 Cerr << "Ending Uzawa : mass residue : " << sqrt(R_carre) <<finl;
1962 Cerr << "Ending Uzawa : Qdm residue : " << sqrt(UU_carre)<<finl;
1963 }
1964}
1965
1967{
1968 if (le_traitement_particulier)
1969 le_traitement_particulier->sauver_stat();
1970}
1971
1973{
1974 Cerr<<" Navier_Stokes_std::rho_la_vitesse() must be overloaded "<<finl;
1975 assert(0);
1976 exit();
1977 throw;
1978}
1979
1980void Navier_Stokes_std::update_y_plus(const DoubleTab& tab)
1981{
1982 if (!y_plus) Process::exit(que_suis_je() + " : y_plus must be initialised so it can be updated") ;
1983 DoubleTab& tab_y_p = y_plus->valeurs();
1984 if (tab.nb_dim()==2)
1985 for (int i = 0 ; i < tab_y_p.dimension_tot(0) ; i++)
1986 for (int n = 0 ; n < tab_y_p.dimension_tot(1) ; n++) tab_y_p(i,n) = tab(i,n);
1987 if (tab.nb_dim()==3)
1988 for (int i = 0 ; i < tab_y_p.dimension_tot(0) ; i++)
1989 for (int n = 0 ; n < tab_y_p.dimension_tot(1) ; n++) tab_y_p(i,n) = tab(i,0,n);
1990}
1991
1993{
1994 if(probleme().domaine().getCouplingMethod()) //implicit IFS coupling
1995 // Equivalent of setting present = past for velocity done in for eg. Schema_Euler_Implicite::test_stationnaire.
1996 // Ensures sub-iterations start with the correct pressure for implicit coupling
1997 pression().valeurs()= P_n;
1998}
1999
2004
2006{
2007 // in case of implicit coupling with a structural code: update the fluxes (used for computing the fluid force) during implicit sub-iterations
2008
2009 if(probleme().domaine().getCouplingMethod()) //implicit IFS coupling case
2010 {
2011 Cout<<" Implicit coupling: Navier_Stokes_std_ALE::updateFluidForce "<<finl;
2012 //update diffusion operator
2013 DoubleTab field_value = velocity;
2014 field_value = 0.;
2015 operateur_diff().ajouter(velocity, field_value);
2016
2017
2018 //update gradient operator
2019 pression().mettre_a_jour(schema_temps().temps_courant());
2021 gradient->calculer_flux_bords();
2022 }
2023}
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)