TrioCFD 1.9.9_beta
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 Calls Equation_base::readOn(Entree& is). On exit, verifies that the following have been read:
63 *
64 * - the diffusive term,
65 * - the convective term,
66 * - the pressure solver
67 *
68 * @param (Entree& is) input stream
69 * @return (Entree&) the modified input stream
70 * @throws diffusive term not specified in data file; specify a negligeable type if it should be neglected
71 * @throws convective term not specified in data file; specify a negligeable type if it should be neglected
72 * @throws pressure solver not defined in data file
73 */
75{
77 if (est_egal(seuil_projection,0.) && (sub_type(solv_iteratif,solveur_pression_.valeur())))
78 {
79 solv_iteratif& solv_iter = ref_cast(solv_iteratif,solveur_pression_.valeur());
80 seuil_projection = solv_iter.get_seuil();
81 }
82
83 terme_convectif.set_fichier("Convection_qdm");
84 terme_convectif.set_description("Momentum flow rate=Integral(rho*u*u*ndS) [N] if SI units used");
85 terme_diffusif.set_fichier("Contrainte_visqueuse");
86 terme_diffusif.set_description("Friction drag exerted by the fluid=Integral(-mu*(grad(u) +grad(u)^T)*ndS) [N] if SI units used");
87 divergence.set_fichier("Debit");
88 divergence.set_description((Nom)"Volumetric flow rate=Integral(u*ndS) [m"+(Nom)(dimension+bidim_axi)+".s-1] if SI units used");
89 gradient.set_fichier("Force_pression");
90 gradient.set_description("Pressure drag exerted by the fluid=Integral(P*ndS) [N] if SI units used");
91
92 return is;
93}
94
96{
98 param.ajouter_non_std("diffusion",(this));
99 param.ajouter_non_std("convection",(this));
100 param.ajouter_condition("is_read_diffusion","The diffusion operator must be read, select negligeable type if you want to neglect it.");
101 param.ajouter_condition("is_read_convection","The convection operator must be read, select negligeable type if you want to neglect it.");
102 param.ajouter_non_std("solveur_pression",(this),Param::REQUIRED); // XD attr solveur_pression solveur_sys_base solveur_pression OPT Linear pressure system resolution method.
103 param.ajouter_non_std("dt_projection",(this)); // XD attr dt_projection deuxmots dt_projection OPT nb value : This
104 // XD_CONT keyword checks every nb time-steps the equality of velocity divergence to zero. value is the criteria
105 // XD_CONT convergency for the solver used.
106 param.ajouter_non_std("Traitement_particulier",(this)); // XD attr traitement_particulier traitement_particulier traitement_particulier OPT Keyword to post-process particular values.
107 param.ajouter_non_std("Erreur_max_DivU",(this));
108 param.ajouter("uzawa",&seuil_uzawa);
109 //param.ajouter_non_std("vitesse_transportante",(this));
110 param.ajouter_non_std("seuil_divU",(this)); // XD attr seuil_divU floatfloat seuil_divU OPT value factor : this
111 // XD_CONT keyword is intended to minimise the number of iterations during the pressure system resolution. The
112 // XD_CONT convergence criteria during this step (\'seuil\' in solveur_pression) is dynamically adapted according to
113 // XD_CONT the mass conservation. At tn , the linear system Ax=B is considered as solved if the residual
114 // XD_CONT ||Ax-B||<seuil(tn). For tn+1, the threshold value seuil(tn+1) will be evualated as: NL2 If (
115 // XD_CONT |max(DivU)*dt|<value ) NL2 Seuil(tn+1)= Seuil(tn)*factor NL2 Else NL2 Seuil(tn+1)= Seuil(tn)*factor NL2
116 // XD_CONT Endif NL2 The first parameter (value) is the mass evolution the user is ready to accept per timestep, and
117 // XD_CONT the second one (factor) is the factor of evolution for \'seuil\' (for example 1.1, so 10% per timestep).
118 // XD_CONT Investigations has to be lead to know more about the effects of these two last parameters on the behaviour
119 // XD_CONT of the simulations.
120 param.ajouter_non_std("solveur_bar",(this)); // XD attr solveur_bar solveur_sys_base solveur_bar OPT This keyword is
121 // XD_CONT used to define when filtering operation is called (typically for EF convective scheme, standard diffusion
122 // XD_CONT operator and Source_Qdm_lambdaup ). A file (solveur.bar) is then created and used for inversion procedure.
123 // XD_CONT Syntax is the same then for pressure solver (GCP is required for multi-processor calculations and, in a
124 // XD_CONT general way, for big meshes).
125 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.
126 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
127 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.
128}
129
131{
132 if (mot=="diffusion")
133 {
134 Cerr << "Reading and typing of the diffusion operator : " << finl;
135 terme_diffusif.associer_diffusivite(diffusivite_pour_transport());
136 is >> terme_diffusif;
137 // the field for dt_stab is the same as that of the operator
138 terme_diffusif.associer_diffusivite_pour_pas_de_temps(diffusivite_pour_pas_de_temps());
139 return 1;
140 }
141 else if (mot=="convection")
142 {
143 Cerr << "Reading and typing of the convection operator : " << finl;
144 const Champ_base& vitesse_transportante = vitesse_pour_transport();
145 terme_convectif.associer_vitesse(vitesse_transportante);
146 is >> terme_convectif;
147 return 1;
148 }
149 else if (mot=="solveur_pression")
150 {
151 Cerr << "Reading and typing of pressure solver : " << finl;
152 is >> solveur_pression_;
153 Cerr<<"Pressure solver type : "<<solveur_pression_->que_suis_je()<< finl;
154 solveur_pression_.nommer("solveur_pression");
155 return 1;
156 }
157 else if (mot=="dt_projection")
158 {
159 Cerr << "Reading projection time step " << finl;
160 is >> dt_projection;
161 is >> seuil_projection;
162 return 1;
163 }
164 else if (mot=="Traitement_particulier")
165 {
166 Cerr << "Reading and typing of Traitement_particulier considered : " << finl;
167 Nom type="Traitement_particulier_NS_";
168 Motcle motbidon;
169 Motcle accouverte = "{" , accfermee = "}" ;
170 is >> motbidon;
171 if (motbidon == accouverte)
172 {
173 Motcle le_cas;
174 is >> le_cas;
175 if (le_cas == accfermee)
176 le_cas ="";
177 else
178 {
179 type+= le_cas;
180 type+= "_";
181 }
183 if (discr == "VEFPreP1B")
184 discr = "VEF";
185 type+=discr;
186 Cerr << type << finl;
187 le_traitement_particulier.typer(type);
188 le_traitement_particulier->associer_eqn(*this);
189 le_traitement_particulier->lire(is);
190 }
191 else
192 {
193 Cerr << "Error while reading Traitement_particulier for Navier_Stokes_standard equation";
194 Cerr << "A { was expected." << finl;
195 exit();
196 }
197 return 1;
198 }
199 else if (mot=="Erreur_max_DivU")
200 {
201 Cerr << "Reading DivU maximum" << finl;
202 is >> max_div_U;
203 is >> seuil_projection;
204 return 1;
205 }
206 else if (mot=="seuil_divU")
207 {
208 Cerr << "Reading the threshold value for the velocity divergence " << finl;
209 is >> seuil_divU;
210 is >> raison_seuil_divU;
211 return 1;
212 }
213 else if (mot=="solveur_bar")
214 {
215 Motcle motlu;
216 Motcle accouverte = "{" , accfermee = "}" ;
217 Nom type_solv("");
218 int acc=0;
219 int ok=0;
220 while (acc!=0 || !ok)
221 {
222 is >> motlu;
223 if (motlu==accouverte)
224 {
225 ok=1;
226 acc++;
227 };
228 if (motlu==accfermee) acc--;
229 type_solv+=" ";
230 type_solv+=motlu;
231 }
232 if (je_suis_maitre())
233 {
234 SFichier s("solveur.bar");
235 s<<type_solv<<finl;
236 s.close();
237 }
238 return 1;
239 }
240 else if (mot=="methode_calcul_pression_initiale")
241 {
242 Motcle methode;
243 is >> methode;
244 Motcles compris(4);
245 compris[0]="avec_les_cl";
246 compris[1]="avec_sources";
247 compris[2]="avec_sources_et_operateurs";
248 compris[3]="sans_rien";
251 {
252 Cerr<<methode<<" is not understood."<<finl;
253 Cerr<<" Allowed keywords are :"<<compris<<finl;
254 exit();
255 }
256 return 1;
257 }
258 else
260}
261
266
268{
269 return terme_diffusif.diffusivite();
270}
271
273{
274 return la_vitesse;
275}
276
277
278/*! @brief Associates with the problem: calls Equation_base::associer_pb_base(const Probleme_base&)
279 *
280 * and associates with the divergence and gradient operators.
281 *
282 * @param (Probleme_base& pb) the problem to associate with
283 */
285{
287 divergence.associer_eqn(*this);
288 gradient.associer_eqn(*this);
289}
290
291/*! @brief Completes the base equation, associates the pressure with the equation,
292 *
293 * completes the divergence, gradient and pressure solver.
294 * Adds 2 source terms: one representing the centrifugal force
295 * in the axisymmetric case, the other involved in the resolution
296 * in 2D axisymmetric.
297 * Associates an interface transport equation with the set
298 * of tracked points if the fluid is marked.
299 *
300 */
302{
303 if (axi == 1)
304 {
305 Source t;
306 Source& so=les_sources.add(t);
307 Cerr << "Centrifuge force term creation for Axi case."<< finl;
308 Nom type_so = "Force_Centrifuge_";
309 Nom disc = discretisation().que_suis_je();
310 Nom champ = inconnue().que_suis_je();
311 champ.suffix("Champ_");
312 type_so+=disc;
313 type_so+="_";
314 type_so+=champ;
315 type_so += "_Axi";
316 so.typer_direct(type_so);
317 so->associer_eqn(*this);
318 }
319
321
322 // Do not split the residual by components for the velocity:
324
325 la_pression->associer_eqn(*this);
326 la_pression->completer(le_dom_Cl_dis.valeur());
327 // [ABN] make sure the pressure knows the domaine_Cl_dis to be able to use specific postreatment like 'gravcl'
328 la_pression->associer_domaine_cl_dis(le_dom_Cl_dis);
329
330 divergence_U->associer_eqn(*this);
331 if (gradient_P) gradient_P->associer_eqn(*this);
332 la_pression_en_pa->associer_eqn(*this);
333 la_pression_en_pa->completer(le_dom_Cl_dis.valeur());
334 la_pression_en_pa->associer_domaine_cl_dis(le_dom_Cl_dis);
335 divergence.completer();
336 gradient.completer();
337 assembleur_pression_->associer_domaine_cl_dis_base(domaine_Cl_dis());
338 assembleur_pression_->completer(*this);
339
340 if (distance_paroi_globale)// Initialize the wall distance at the start of the computation if needed; it will no longer be updated since the mesh is fixed; done late because boundary conditions must be read first.
341 {
342 Domaine_dis_base& domaine = domaine_dis();
343 domaine.init_dist_paroi_globale(domaine_Cl_dis().les_conditions_limites());
344 Cerr << "Initializing distance_paroi_globale ... " << finl;
345 const DoubleTab& dist_calc = domaine.y_elem();
346 for (int e = 0 ; e < domaine.nb_elem() ; e++) distance_paroi_globale->valeurs()(e, 0) = dist_calc(e);
347 distance_paroi_globale->valeurs().echange_espace_virtuel();
348 }
349
350}
351
353{
355}
356
357/*! @brief Discretizes the equation.
358 *
359 */
361{
362 Cerr << "Hydraulic equation discretization (Navier_Stokes_std::discretiser)" << finl;
363 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
364
366 la_vitesse->add_synonymous(Nom("velocity"));
367 champs_compris_.ajoute_champ(la_vitesse);
368
370 la_pression->add_synonymous(Nom("P_star"));
371 champs_compris_.ajoute_champ(la_pression);
372
374 la_pression_en_pa->add_synonymous(Nom("Pressure"));
376
377
380 divergence.typer();
381 divergence.l_op_base().associer_eqn(*this);
382 gradient.typer();
383 gradient.l_op_base().associer_eqn(*this);
384
385
386 champs_compris_.ajoute_champ(divergence_U);
387
388
389 // Call the virtual method for pressure assembler discretization:
391
393}
394
396{
397 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
398 dis.vitesse(schema_temps(), domaine_dis(), la_vitesse);
399}
400
407
408/*! @brief Types the pressure assembler.
409 *
410 * The assembler name is built as:
411 * "Assembleur_P_xxx" where "xxx" is the name of the discretization.
412 * This method is virtual and overridden in front-tracking.
413 * It is called by Navier_Stokes_std::discretiser()
414 *
415 */
416
418{
419 Nom type = "Assembleur_P_";
420 type += discretisation().que_suis_je();
421 Cerr << "Navier_Stokes_std::discretiser_assembleur_pression : type="<< type << finl;
422 assembleur_pression_.typer(type);
423 assembleur_pression_->associer_domaine_dis_base(domaine_dis());
424}
425
427{
428 if (!probleme().domaine().mesh_update_required()) return;
429
430 if (!probleme().is_dilatable())
431 assembleur_pression_->assembler(matrice_pression_);
432 else
433 assembleur_pression_->assembler_QC(fluide().masse_volumique().valeurs(), matrice_pression_);
434
435 solveur_pression_->reinit();
436}
437
438/*! @brief Returns the number of operators in the equation: 2 for the standard Navier-Stokes equations.
439 *
440 * @return (int) the number of operators in the equation
441 */
443{
444 return 2;
445}
446
448{
449 return 4;
450}
451
452/*! @brief Returns the i-th operator of the equation: - terme_diffusif if i = 0
453 *
454 * - terme_convectif if i = 1
455 * exits if i > 1
456 * (const version)
457 *
458 * @param (int i) the index of the operator to return
459 * @return (Operateur&) the operator at index i
460 */
462{
463 switch(i)
464 {
465 case 0:
466 return terme_diffusif;
467 case 1:
468 return terme_convectif;
469 default :
470 Cerr << "Error for Navier_Stokes_std::operateur(int i)" << finl;
471 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" operators "<<finl;
472 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
473 exit();
474 }
475 // For compilers!
476 return terme_diffusif;
477}
478
479/*! @brief Returns the i-th operator of the equation: - terme_diffusif if i = 0
480 *
481 * - terme_convectif if i = 1
482 * exits if i > 1
483 *
484 * @param (int i) the index of the operator to return
485 * @return (Operateur&) the operator at index i
486 */
488{
489 switch(i)
490 {
491 case 0:
492 return terme_diffusif;
493 case 1:
494 return terme_convectif;
495 default :
496 Cerr << "Error for Navier_Stokes_std::operateur(int i)" << finl;
497 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" operators "<<finl;
498 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
499 exit();
500 }
501 // For compilers!
502 return terme_diffusif;
503}
504
506{
507 switch(i)
508 {
509 case 0:
510 return gradient;
511 case 1:
512 return divergence;
513 default :
514 Cerr << "Error for Navier_Stokes_std::operateur_fonctionnel(int i)" << finl;
515 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" functional operators "<<finl;
516 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
517 exit();
518 }
519 // For compilers!
521}
522
524{
525 switch(i)
526 {
527 case 0:
528 return gradient;
529 case 1:
530 return divergence;
531 default :
532 Cerr << "Error for Navier_Stokes_std::operateur_fonctionnel(int i)" << finl;
533 Cerr << "Navier_Stokes_std has " << nombre_d_operateurs() <<" functional operators "<<finl;
534 Cerr << "and you are trying to access the " << i <<" th one."<< finl;
535 exit();
536 }
537 // For compilers!
539}
540
541
542/*! @brief Returns the divergence operator associated with the equation.
543 *
544 * @return (Operateur_Div&) the divergence operator.
545 */
550
551/*! @brief Returns the divergence operator associated with the equation.
552 *
553 * (const version)
554 *
555 * @return (Operateur_Div&) the divergence operator
556 */
561
562/*! @brief Returns the gradient operator associated with the equation.
563 *
564 * @return (Operateur_Grad&) the gradient operator
565 */
570
575
580
581/*! @brief Returns the gradient operator associated with the equation.
582 *
583 * (const version)
584 *
585 * @return (Operateur_Grad&) the gradient operator
586 */
591
592
593/*! @brief Returns the velocity (unknown field of the equation) (const version)
594 *
595 * @return (Champ_Inc_base&) the unknown field representing the velocity
596 */
598{
599 return la_vitesse.valeur();
600}
601
602/*! @brief Returns the velocity (unknown field of the equation)
603 *
604 * @return (Champ_Inc_base&) the unknown field representing the velocity
605 */
607{
608 return la_vitesse.valeur();
609}
610
611/*! @brief Returns the pressure solver (const version)
612 *
613 * @return (SolveurSys&) the pressure solver
614 */
619
620/*! @brief Returns the incompressible fluid (physical medium of the equation) associated with the equation.
621 *
622 * (const version)
623 *
624 * @return (Fluide_base&) the incompressible fluid associated with the equation
625 */
627{
628 return le_fluide.valeur();
629}
630
631
632/*! @brief Returns the incompressible fluid (physical medium of the equation) associated with the equation.
633 *
634 * @return (Fluide_base&) the incompressible fluid associated with the equation
635 */
637{
638 return le_fluide.valeur();
639}
640
642{
643 Cerr << "Reading of initial conditions\n";
644 Nom nom;
645 Motcle motlu;
646 is >> nom;
647 motlu = nom;
648 if(motlu!=Motcle("{"))
649 {
650 Cerr << "We expected a { while reading " << que_suis_je() << finl;
651 Cerr << "and not : " << nom << finl;
652 exit();
653 }
654 Motcles compris(3);
655 compris[0]="}";
656 compris[1]="vitesse";
657 compris[2]="pression";
658 int ind = -1;
659 while (ind!=0)
660 {
661 is >> nom;
662 motlu = nom;
663 ind = compris.rang(motlu);
664 if (ind==1)
665 {
666 OWN_PTR(Champ_Don_base) ch_init;
667 is >> ch_init;
669 inconnue().affecter(ch_init.valeur());
670 }
671 else if (ind==2)
672 {
673 OWN_PTR(Champ_Don_base) ch_init;
674 is >> ch_init;
676 pression().affecter(ch_init.valeur());
677 }
678 else if (ind==-1)
679 {
680 Cerr << nom << " is not understood. Keywords are:" << finl;
681 Cerr << compris << finl;
682 exit();
683 }
684 }
685 return is;
686}
687
688/*! @brief Add a specific term for Navier Stokes (-gradP(n)) if necessary
689 *
690 */
691DoubleTab& Navier_Stokes_std::corriger_derivee_expl(DoubleTab& derivee)
692{
693 if (assembleur_pression_->get_resoudre_increment_pression())
694 {
695 // PL: To avoid computing this gradient, the following must hold:
696 // A) postraitement_gradient_P_==0 car sinon grad contient alors M-1BtP
697 // B) pressure boundary conditions are stationary (hard to detect: Orlansky, P(t), imposed pressure gradient...)
698 // Moreover, this causes discrepancies with the iterative CN scheme
699 const DoubleTab& tab_pression = la_pression->valeurs();
700 DoubleTab& gradP = gradient_P->valeurs();
701 gradient.calculer(tab_pression, gradP);
702 derivee -= gradP;
703 }
704 return derivee;
705}
706
707/*! @brief Resolution de la pression, inconnue implicitee de Navier Stokes
708 *
709 */
710DoubleTab& Navier_Stokes_std::corriger_derivee_impl(DoubleTab& derivee)
711{
712 // We want to solve:
713 // dU/dt + M-1 Bt Cp = M-1(F - BtP)
714 // B dU/dt = 0
715 // with F explicit terms: sum(operators)+sources
716 // In: derivee = M-1(F - BtP(n))
717 // Out: derivee = M-1(F - BtP(n+1)), P(n+1)=P(n)+Cp
718
719 DoubleTab& tab_pression=la_pression->valeurs();
720 DoubleTab& gradP=gradient_P->valeurs();
721 DoubleTrav secmemP(tab_pression);
722
723 const bool is_ALE = probleme().domaine().deformable();
724
726
727 const double dt = schema_temps().pas_de_temps();
729 {
730 // we want div u = 0 rather than d/dt(div u) = 0 to avoid accumulating errors
731 // this only works with explicit Euler-type schemes
732 DoubleTab derivee2(derivee);
733 derivee2*=dt;
734 derivee2+=la_vitesse->passe();
735 derivee2/=dt;
736 divergence.calculer(derivee2, secmemP); // Div(M-1(F - BtP))
737 }
738 else if (is_ALE)
739 {
740 // ALE explicit volumetric correction:
741 // In ALE formulation, the conservative form of the transient term is:
742 // (V^{n+1} U^{n+1} - V^n U^n ) / dt
743 // For an explicit Euler scheme, this leads to the additional term:
744 // (V^n / V^{n+1}) * (U^n / dt) which is added to the explicit RHS (M-1(F - BtP)).
745 // This ensures discrete mass conservation (Geometric Conservation Law) when the mesh is deformable.
746 // This correction is required only for explicit schemes because
747 // implicit schemes naturally incorporate the volume variation inside the mass matrix formulation.
748 DoubleTab derivee2(derivee);
749 // Conservative ALE form: deriveeALE= (Volume_n+1/Volume_n)*Un/delta t + derivee
750 probleme().domaine().ajouter_correctif_volumique(la_vitesse->valeurs(), derivee, dt, derivee2);
751 divergence.calculer(derivee2, secmemP);
752 }
753 else
754 divergence.calculer(derivee, secmemP); // Div(M-1(F - BtP))
755
756 secmemP *= -1; // because div = -B
757 // Correction of the right-hand side according to the boundary conditions:
758 assembleur_pression_->modifier_secmem(secmemP);
759
760 // Set print of the linear system solve according to dt_impr:
761 solveur_pression_->fixer_schema_temps_limpr(schema_temps().limpr());
762
763 if (assembleur_pression_->get_resoudre_increment_pression())
764 {
765 // Solve B M-1 Bt Cp = M-1(F - BtP)
766 DoubleTrav Cp(tab_pression);
767 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(), secmemP, Cp);
768
769 // P(n+1) = P(n) + Cp
770 tab_pression += Cp;
771 assembleur_pression_->modifier_solution(tab_pression);
772
773 // M-1 Bt P(n+1)
774 solveur_masse->appliquer(gradP);
775 derivee += gradP; // M-1 F
776 }
777 else
778 {
779 // Solve B M-1 Bt P(n+1) = B M-1 F
780 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(), secmemP, tab_pression);
781 assembleur_pression_->modifier_solution(tab_pression);
782 // It is not done anymore cause:
783 // Iterative solvers are less accurate
784 // Time converges in O(sqrt(dt)) and not O(dt)
785 // See: http://www.sciencedirect.com/science/article/pii/S0021999108004518
786 }
787
788 // (BM) gradient operator requires updated virtual space in source vector
789 // Calculate Bt P(n+1)
790 tab_pression.echange_espace_virtuel();
791 gradient.calculer(tab_pression, gradP);
792
793 // gradP = Bt P(n+1) is kept and
794 // M-1Bt P(n+1) is calculated:
795 DoubleTrav Mmoins1gradP(gradP);
796 Mmoins1gradP = gradP;
797 solveur_masse->appliquer(Mmoins1gradP);
798
799 // dU/dt = M-1(F-Bt P(n+1))
800 derivee -= Mmoins1gradP;
801
802 return derivee;
803}
804
805/*! @brief Computes the solution U of the equations: | M(U-V)/dt + BtP = 0
806 *
807 * |-BU=0
808 * The pressure problem is solved: -BM-1BtP = -BV/dt
809 * where -BV represents the divergence of V.
810 * The velocity problem is solved by applying the mass solver
811 * to the gradient of P: U=V - dt*M-1BtP
812 *
813 * @throws time step too small
814 */
816{
817 if (probleme().is_dilatable() && probleme().reprise_effectuee())
818 Cerr << "WARNING: Quasi compressible model --> no projection (except the first time step)." << finl;
819 else
820 {
821 Cerr << "Projection of initial and boundaries conditions " << finl;
822 DoubleTab& tab_vitesse = la_vitesse->valeurs();
823 tab_vitesse.echange_espace_virtuel();
824 la_pression->valeurs().echange_espace_virtuel();
825
826 double normal_seuil = 0.;
827
828 // M u + eBt l = M v
829 // B u = 0
830 // => e B(M-1)Bt l = Bv
831 //
833
834 DoubleTrav secmem(la_pression->valeurs());
835 divergence.calculer(tab_vitesse, secmem);
836 // The time step is now computed before the projection.
837 // Previously, dt=dt_min at the start of the computation.
838 double dt = std::max(le_schema_en_temps->pas_temps_min(),calculer_pas_de_temps());
839 dt = std::min(dt, le_schema_en_temps->pas_temps_max());
840
841 secmem*=(-1./dt);
842 secmem.echange_espace_virtuel();
843
844 double bilan=mp_norme_vect(secmem); // TODO DG surcharger cette fonction pour avoir \sum \int_T || \sum_{nfunc_p} secmem*fbase_p ||
845 Cout << "------------- Projection -----------------" << finl;
846 Cout << "--------------------------------------------" << finl;
847 Cout << "Mass balance before projection : " << bilan << finl;
848
849 if( sub_type(solv_iteratif,solveur_pression_.valeur()) )
850 {
851 solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
852 normal_seuil=solv_iter.get_seuil();
853 solv_iter.set_seuil(seuil_projection);
854 }
855
856 // Correction of the right-hand side according to the boundary conditions:
857 // There is no point initializing lagrange with the pressure;
858 // it actually penalizes the computation in p1B with CL p<>0.
859 // Use a DoubleTrav instead of a DoubleTab to initialize lagrange=0.
860 DoubleTrav lagrange(la_pression->valeurs());
861 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(),secmem,lagrange);
862 assembleur_pression_->modifier_solution(lagrange);
863 lagrange.echange_espace_virtuel();
864
865 // M-1 Bt l
866 DoubleTrav gradP(gradient_P->valeurs());
867 gradient->multvect(lagrange, gradP);
870 solveur_masse->appliquer(gradP);
872
873 if (tab_vitesse.dimension_tot(0) == gradP.dimension_tot(0))
874 tab_vitesse.ajoute(-dt,gradP);
875 else
876 {
877 DoubleTab_parts partv(tab_vitesse);
878 partv[0].ajoute(-dt,gradP);
879 }
880 tab_vitesse.echange_espace_virtuel();
881 solveur_masse->corriger_solution(tab_vitesse, tab_vitesse);
882
883 Debog::verifier("Navier_Stokes_std::projeter, vitesse", tab_vitesse);
884
885 // Verification...
886 divergence.calculer(tab_vitesse, secmem);
887 secmem.echange_espace_virtuel();
888
889 bilan=mp_norme_vect(secmem);
890 Cout << "Mass balance after projection : " << bilan << finl;
891 Cout << "------------- Projection OK---------------" << finl;
892 Cout << "--------------------------------------------" << finl;
893
894 if( sub_type(solv_iteratif,solveur_pression_.valeur()) )
895 {
896 solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
897 solv_iter.set_seuil(normal_seuil);
898 }
899 }
901}
902
904{
905 // No projection if the equation is not solved
906 // if (equation_non_resolue()) return 0;
907
908 double temps = le_schema_en_temps->temps_courant()+le_schema_en_temps->pas_de_temps();
909 // See Schema_Temps_base::limpr for information on modf
910 double nb_proj_int;
911 modf(temps/dt_projection, &nb_proj_int);
912 static double nb_proj = nb_proj_int;
914 return 1;
915 else if (inf_ou_egal((nb_proj+1.)*dt_projection,temps))
916 {
917 nb_proj=nb_proj+1.;
918 return 1;
919 }
920 return 0;
921}
922
923/*! @brief cf Equation_base::preparer_calcul() Assembly of the pressure solver and
924 *
925 * initialization of the pressure.
926 *
927 * Assembly of the pressure system.
928 *
929 * @return (int) always returns 1
930 */
932{
933 const double temps = schema_temps().temps_courant();
934 sources().mettre_a_jour(temps);
936 bool is_dilatable = probleme().is_dilatable();
937 if (!is_dilatable)
938 assembleur_pression_->assembler(matrice_pression_);
939 else
940 {
941 Cerr << "Assembling for quasi-compressible" << finl;
942 assembleur_pression_->assembler_QC(fluide().masse_volumique().valeurs(), matrice_pression_);
943 }
944
945 // GF: on restart, we preserve the pressure value.
946 // Previously it was only used to initialize the lagrange for the projection.
947 // It is important for Simpler/Piso to restart from the saved pressure.
948 //la_pression->valeurs()=0.;
949 Debog::verifier("Navier_Stokes_std::preparer_calcul, la_pression av projeter", la_pression->valeurs());
950 if (projection_a_faire())
951 projeter();
952
953 // In case a pressure boundary condition depends on u that was just modified
954 le_dom_Cl_dis->mettre_a_jour(temps);
955 Debog::verifier("Navier_Stokes_std::preparer_calcul, la_pression ap projeter", la_pression->valeurs());
956
957 // Initialization of the pressure field (solving Laplacian(P)=0 with pressure boundary conditions)
958 // Allows starting the resolution with a good pressure approximation (important for Piso or P!=0)
959 if (!probleme().reprise_effectuee() && methode_calcul_pression_initiale_ != 3)
960 {
961 Cout << "Estimation of the pressure field at startup:" << finl;
962 DoubleTrav secmem(la_pression->valeurs());
963 DoubleTrav vpoint(gradient_P->valeurs());
964 gradient.calculer(la_pression->valeurs(), gradient_P->valeurs());
965 vpoint -= gradient_P->valeurs();
966
968 for (int op = 0; op < nombre_d_operateurs(); op++)
969 operateur(op).ajouter(vpoint);
971 {
972 int mod = 0;
973 if (le_schema_en_temps->pas_de_temps() == 0)
974 {
975 double dt = std::max(le_schema_en_temps->pas_temps_min(), calculer_pas_de_temps());
976 dt = std::min(dt, le_schema_en_temps->pas_temps_max());
977 le_schema_en_temps->set_dt() = (dt);
978 mod = 1;
979 }
980 sources().ajouter(vpoint);
981 if (mod)
982 le_schema_en_temps->set_dt() = 0;
983 }
984
985 solveur_masse->appliquer(vpoint);
986 vpoint.echange_espace_virtuel();
987 divergence.calculer(vpoint, secmem);
988 secmem *= -1;
989 secmem.echange_espace_virtuel();
990
991 assembleur_pression_->modifier_secmem_pour_incr_p(la_pression->valeurs(), 1, secmem);
992 DoubleTrav inc_pre(la_pression->valeurs());
993 solveur_pression_.resoudre_systeme(matrice_pression_.valeur(), secmem, inc_pre);
994 Cerr << "Pressure increment computed successfully" << finl;
995
996 // We want the virtual space to be up-to-date, hence all_items
997 operator_add(la_pression->valeurs(), inc_pre, VECT_ALL_ITEMS);
998 }
999 // Update pressure
1000 la_pression->changer_temps(temps);
1002 // Compute pressure forces:
1003 gradient->calculer_flux_bords();
1004
1005 // Compute gradient_P (ToDo: make consistent with ::mettre_a_jour()):
1006 gradient.calculer(la_pression->valeurs(), gradient_P->valeurs());
1007 gradient_P->changer_temps(temps);
1008
1009 // Compute divergence_U
1010 divergence.calculer(la_vitesse->valeurs(), divergence_U->valeurs());
1011 divergence_U->changer_temps(temps);
1012
1013 if (le_traitement_particulier)
1014 le_traitement_particulier->preparer_calcul_particulier();
1015
1016 Debog::verifier("Navier_Stokes_std::preparer_calcul, vitesse", inconnue());
1017 Debog::verifier("Navier_Stokes_std::preparer_calcul, pression", la_pression);
1018
1019 return 1;
1020}
1021
1022/*! @brief Performs a time update of the equation.
1023 *
1024 * Calls Equation_base::mettre_a_jour(double)
1025 * and updates the pressure.
1026 * Integrates tracked points if the fluid is marked.
1027 * Updates the corresponding post-processable field.
1028 *
1029 * @param (double temps) the update time
1030 */
1032{
1033 // Update the parent class (advance the time wheel).
1035
1036 // Update pressure
1037 la_pression->mettre_a_jour(temps);
1039 // Compute pressure forces:
1040 gradient->calculer_flux_bords();
1041
1042 // Update the divergence of the velocity div(U)
1043// statistics().end_count(STD_COUNTERS::update_variables,0,0);
1044 divergence.calculer(la_vitesse->valeurs(),divergence_U->valeurs());
1045 //statistics().begin_count(STD_COUNTERS::update_variables,statistics().get_last_opened_counter_level()+1);
1046 divergence_U->mettre_a_jour(temps);
1047
1048 // For post-processing, we want M-1BtP and not BtP
1049 if (postraitement_gradient_P_)
1050 {
1051 gradient.calculer(la_pression->valeurs(), gradient_P->valeurs());
1053 solveur_masse->appliquer(gradient_P->valeurs());
1054 gradient_P->mettre_a_jour(temps);
1055 }
1056
1057 // PQ: 04/03: procedure for dynamic determination of the pressure convergence threshold
1058 if(sub_type(solv_iteratif,solveur_pression_.valeur()) && seuil_divU < 1.)
1059 {
1060 // Dynamic threshold computation for the iterative pressure solver
1061 solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
1062 double seuil_dyn=solv_iter.get_seuil();
1063
1064 if(LocalFlowRateRelativeError()<seuil_divU)
1065 seuil_dyn*=raison_seuil_divU;
1066 else
1067 seuil_dyn/=raison_seuil_divU;
1068 double seuil_dyn_max = 1.e-10;
1069 seuil_dyn=std::max(seuil_dyn,seuil_dyn_max);
1070 solv_iter.set_seuil(seuil_dyn);
1071 }
1072 // end of the dynamic pressure convergence threshold procedure
1073
1074 if (projection_a_faire())
1075 projeter();
1076
1077 if (le_traitement_particulier)
1078 le_traitement_particulier->post_traitement_particulier();
1079 Debog::verifier("Navier_Stokes_std::mettre_a_jour : pression", la_pression->valeurs());
1080 Debog::verifier("Navier_Stokes_std::mettre_a_jour : vitesse", la_vitesse->valeurs());
1081
1082 if (la_vorticite) la_vorticite->mettre_a_jour(temps);
1083 if (critere_Q) critere_Q->mettre_a_jour(temps);
1084 if (Reynolds_maille) Reynolds_maille->mettre_a_jour(temps);
1085 if (Taux_cisaillement) Taux_cisaillement->mettre_a_jour(temps);
1086 if (grad_u) grad_u->mettre_a_jour(temps);
1087}
1088
1089double Navier_Stokes_std::LocalFlowRateRelativeError() const
1090{
1091 // Estimation of a flow rate relative error
1092 DoubleTrav array(divergence_U->valeurs()); // array(i)=sum(u.ndS)
1093 divergence.volumique(array); // array(i)=sum(u.ndS)/vol(i)
1094 return mp_max_abs_vect(array) * schema_temps().pas_de_temps(); // =max|sum(u.ndS)/(vol(i)/dt)|
1095}
1096
1098{
1099 // Restore the pressure from the beginning of the time step.
1100 // Useful if the time step is retried because the pressure diverged (otherwise very poor accuracy)
1101 // and when using Piso (which assumes correct pressure at the start of the time step).
1102 pression().valeurs()=P_n;
1103 //pression().valeurs()=0;
1105}
1106
1107/* @brief Override. Reset pression too !
1108 */
1110{
1111 pression().resetTime(time);
1113}
1114
1116{
1117 P_n=pression().valeurs();
1118
1119 // Check that dt_max is correctly set for a zero
1120 // velocity field with active implicit diffusion <=> dt_conv=INF
1121 const Schema_Temps_base& sch_tps = le_schema_en_temps.valeur();
1122 bool ddt = Equation_base::initTimeStep(dt);
1123
1124 for (int i=1; i<=sch_tps.nb_valeurs_futures(); i++)
1125 if (i <= pression().nb_valeurs_temporelles())
1126 {
1127 double tps=sch_tps.temps_futur(i);
1128 // Update time in pressure fields
1131 pression().futur(i)=pression().valeurs();
1133 }
1134
1135 return ddt;
1136}
1137
1138/*! @brief Computes "la_pression_en_pa" from "la_pression".
1139 *
1140 * If the field milieu().masse_volumique() is uniform, it is assumed that
1141 * la_pression is P* = P/rho, and the value is multiplied by rho. Otherwise,
1142 * la_pression is already in Pa.
1143 * This method is overridden in front-tracking.
1144 *
1145 */
1147{
1148 DoubleTab& Pa=la_pression_en_pa->valeurs();
1149 DoubleTab& tab_pression=la_pression->valeurs();
1150 const Champ_base& rho=milieu().masse_volumique();
1151 if (Pa.get_md_vector() == tab_pression.get_md_vector())
1152 Pa = tab_pression; //Pa and tab_pression share the same support
1153 else
1154 {
1155 ConstDoubleTab_parts ppart(tab_pression);
1156 assert(Pa.get_md_vector() == ppart[0].get_md_vector());
1157 Pa = ppart[0]; //tab_pression has one extra piece
1158 }
1159 // Multiply by rho if uniform, otherwise already in Pa...
1160 if (sub_type(Champ_Uniforme,rho))
1161 Pa *= rho.valeurs()(0,0);
1162 la_pression_en_pa->mettre_a_jour(pression().temps());
1163}
1164
1165/*! @brief for PDI IO: retrieve name, type and dimensions of the fields to save/restore
1166 *
1167 */
1168std::vector<YAML_data> Navier_Stokes_std::data_a_sauvegarder() const
1169{
1170 std::vector<YAML_data> data = Equation_base::data_a_sauvegarder();
1171 std::vector<YAML_data> pression = la_pression->data_a_sauvegarder();
1172 data.insert(data.end(), pression.begin(), pression.end());
1173 return data;
1174}
1175
1176/*! @brief Calls Equation_base::sauvegarder(Sortie&) and saves the pressure to an output stream.
1177 *
1178 * @param (Sortie& os) output stream to save to
1179 * @return (int) always returns 1
1180 */
1182{
1183 int bytes=0;
1184 bytes += Equation_base::sauvegarder(os);
1185 bytes += la_pression->sauvegarder(os);
1186 // The sauver() method ensuring save for the particular treatment
1187 // is now called here instead of being called in specific problems.
1188 sauver();
1189
1190 return bytes;
1191}
1192
1193/*! @brief Performs a restart from an input stream.
1194 *
1195 * Calls Equation_base::reprendre()
1196 * and restores the pressure.
1197 *
1198 * @param (Entree& is) input stream
1199 * @return (int) always returns 1
1200 * @throws restart failed, pressure identifier not found
1201 */
1203{
1206 {
1207 double temps = schema_temps().temps_courant();
1208 Nom ident_pression(la_pression->le_nom());
1209 ident_pression += la_pression->que_suis_je();
1210 ident_pression += probleme().domaine().le_nom();
1211 ident_pression += Nom(temps,probleme().reprise_format_temps());
1212 if (probleme().discretisation().is_poly_family())
1213 {
1214 Nom field_tag_syno = create_polymacfamily_syno(ident_pression);
1215 avancer_fichier_with_syno(is,ident_pression,field_tag_syno);
1216 }
1217 // end of the backward compatibility
1218 else
1219 avancer_fichier(is,ident_pression);
1220 }
1221 la_pression->reprendre(is);
1222
1223 if (le_traitement_particulier)
1224 le_traitement_particulier->reprendre_stat();
1225
1226 return 1;
1227}
1228
1229/*! @brief Associates a physical medium with the equation by dynamically constructing (casting) an object of type Fluide_base
1230 *
1231 * from the Milieu_base object passed as parameter.
1232 *
1233 * @param (Milieu_base& un_milieu) the medium to associate with the equation
1234 */
1236{
1237 if (sub_type(Fluide_base, un_milieu))
1238 {
1239 const Fluide_base& un_fluide = ref_cast(Fluide_base,un_milieu);
1240 associer_fluide(un_fluide);
1241 }
1242 else
1243 {
1244 Cerr << "Error of fluid type for the method Navier_Stokes_std::associer_milieu_base" << finl;
1245 exit();
1246 }
1247}
1248
1249/*! @brief Returns the physical medium of the equation (Fluide_base upcast to Milieu_base)
1250 *
1251 * @return (Milieu_base&) the Fluide_base of the equation upcast to Milieu_base
1252 */
1254{
1255 if (!le_fluide)
1256 {
1257 Cerr << "You forgot to associate a fluid to the problem named " << probleme().le_nom() << finl;
1258 Process::exit();
1259 }
1260 return le_fluide.valeur();
1261}
1262
1263/*! @brief Returns the physical medium of the equation (Fluide_base upcast to Milieu_base)
1264 *
1265 * (const version)
1266 *
1267 * @return (Milieu_base&) the Fluide_base of the equation upcast to Milieu_base
1268 */
1270{
1271 if (!le_fluide)
1272 {
1273 Cerr << "You forgot to associate a fluid to the problem named " << probleme().le_nom() << finl;
1274 Process::exit();
1275 }
1276 return le_fluide.valeur();
1277}
1278
1280{
1282
1283 if (motlu == "vorticite")
1284 {
1285 if (!la_vorticite)
1286 {
1287 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1288 dis.creer_champ_vorticite(schema_temps(),la_vitesse,la_vorticite);
1289 champs_compris_.ajoute_champ(la_vorticite);
1290 }
1291 }
1292 else if (motlu == "critere_Q")
1293 {
1294 if (!critere_Q)
1295 {
1296 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
1297 dis.critere_Q(domaine_dis(),domaine_Cl_dis(),la_vitesse,critere_Q);
1298 champs_compris_.ajoute_champ(critere_Q);
1299 }
1300 }
1301 else if (motlu == "y_plus")
1302 {
1303 if (!y_plus)
1304 {
1305 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1306 dis.y_plus(domaine_dis(),domaine_Cl_dis(),la_vitesse,y_plus);
1307 champs_compris_.ajoute_champ(y_plus);
1308 }
1309 }
1310 else if (motlu == "distance_paroi_globale")
1311 {
1312 if (!distance_paroi_globale)
1313 {
1314 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1315 dis.distance_paroi_globale(schema_temps(), domaine_dis(), distance_paroi_globale);
1316 champs_compris_.ajoute_champ(distance_paroi_globale);
1317 }
1318 }
1319 else if (motlu == "reynolds_maille")
1320 {
1321 if (!Reynolds_maille)
1322 {
1323 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1325 champs_compris_.ajoute_champ(Reynolds_maille);
1326 }
1327 }
1328 else if (motlu == "courant_maille")
1329 {
1330 if (!Courant_maille)
1331 {
1332 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1334 champs_compris_.ajoute_champ(Courant_maille);
1335 }
1336 }
1337 else if (motlu == "taux_cisaillement")
1338 {
1339 if (!Taux_cisaillement)
1340 {
1341 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1343 champs_compris_.ajoute_champ(Taux_cisaillement);
1344 }
1345 }
1346 else if (motlu == "pression_hydrostatique")
1347 {
1349 {
1350 const Discret_Thyd& dis=ref_cast(Discret_Thyd,discretisation());
1351 dis.discretiser_champ("Champ_sommets",domaine_dis(),"pression_hydrostatique","Pa",1,0.,pression_hydrostatique_);
1353 }
1354 }
1355
1356 else if (motlu == "gradient_vitesse")
1357 {
1358 if (!grad_u)
1359 {
1360 const Discret_Thyd& dis=ref_cast(Discret_Thyd, discretisation());
1361 dis.grad_u(domaine_dis(),domaine_Cl_dis(),la_vitesse,grad_u);
1362 champs_compris_.ajoute_champ(grad_u);
1363 }
1364 }
1365
1366 if (le_traitement_particulier)
1367 le_traitement_particulier->creer_champ(motlu);
1368
1370 if (!grad_u) creer_champ("gradient_vitesse");
1371}
1372
1374{
1375 DoubleTab& val= pression_hydro.valeurs();
1376 const DoubleTab& coords = domaine_dis().domaine().les_sommets();
1377 if (!milieu().a_gravite())
1378 {
1379 Cerr<<"postprocessing of presion_hydrostatique needs gravity"<<finl;
1380 exit();
1381 }
1382 const Champ_base& rho = milieu().masse_volumique();
1383 if (!sub_type(Champ_Uniforme,rho))
1384 {
1385 Cerr<<"postprocessing of presion_hydrostatique availabe only for incompressible flow"<<finl;
1386 exit();
1387 }
1388 const DoubleTab& gravite = milieu().gravite().valeurs();
1389
1390 val=rho.valeurs()(0,0);
1391 const int nb_som=val.dimension(0);
1392
1393 for (int som=0; som<nb_som; som++)
1394 {
1395 double gz=0;
1396 for (int dir=0; dir<dimension; dir++)
1397 gz+=coords(som,dir)*gravite(0,dir);
1398 val[som]*=gz;
1399 }
1401}
1402
1403bool Navier_Stokes_std::has_champ(const Motcle& nom, OBS_PTR(Champ_base)& ref_champ) const
1404{
1405 if (nom == "gradient_pression")
1406 {
1407 ref_champ = Navier_Stokes_std::get_champ(nom);
1408 return true;
1409 }
1410
1411 if (nom == "vorticite" && la_vorticite)
1412 {
1413 ref_champ = Navier_Stokes_std::get_champ(nom);
1414 return true;
1415 }
1416
1417 if (nom == "critere_Q" && critere_Q)
1418 {
1419 ref_champ = Navier_Stokes_std::get_champ(nom);
1420 return true;
1421 }
1422
1423 if (nom == "y_plus" && y_plus)
1424 {
1425 ref_champ = Navier_Stokes_std::get_champ(nom);
1426 return true;
1427 }
1428
1429 if (nom == "reynolds_maille" && Reynolds_maille)
1430 {
1431 ref_champ = Navier_Stokes_std::get_champ(nom);
1432 return true;
1433 }
1434
1435 if (nom == "courant_maille" && Courant_maille)
1436 {
1437 ref_champ = Navier_Stokes_std::get_champ(nom);
1438 return true;
1439 }
1440
1441 if (nom == "taux_cisaillement" && Taux_cisaillement)
1442 {
1443 ref_champ = Navier_Stokes_std::get_champ(nom);
1444 return true;
1445 }
1446
1447 if (nom == "gradient_vitesse" && grad_u)
1448 {
1449 ref_champ = Navier_Stokes_std::get_champ(nom);
1450 return true;
1451 }
1452
1453 if (nom == "pression_hydrostatique" && pression_hydrostatique_)
1454 {
1455 ref_champ = Navier_Stokes_std::get_champ(nom);
1456 return true;
1457 }
1458
1459 if (Equation_base::has_champ(nom, ref_champ))
1460 return true;
1461
1462 if (le_traitement_particulier)
1463 if (le_traitement_particulier->has_champ(nom, ref_champ))
1464 return true;
1465
1466 return false; /* nothing found */
1467}
1468
1470{
1471 if (nom == "gradient_pression")
1472 return true;
1473
1474 if (nom == "vorticite" && la_vorticite)
1475 return true;
1476
1477 if (nom == "critere_Q" && critere_Q)
1478 return true;
1479
1480 if (nom == "y_plus" && y_plus)
1481 return true;
1482
1483 if (nom == "reynolds_maille" && Reynolds_maille)
1484 return true;
1485
1486 if (nom == "courant_maille" && Courant_maille)
1487 return true;
1488
1489 if (nom == "taux_cisaillement" && Taux_cisaillement)
1490 return true;
1491
1492 if (nom == "gradient_vitesse" && grad_u)
1493 return true;
1494
1495 if (nom == "pression_hydrostatique" && pression_hydrostatique_)
1496 return true;
1497
1498 if (Equation_base::has_champ(nom))
1499 return true;
1500
1501 if (le_traitement_particulier)
1502 if (le_traitement_particulier->has_champ(nom))
1503 return true;
1504
1505 return false; /* nothing found */
1506}
1507
1509{
1510 double temps_init = schema_temps().temps_init();
1511 if (nom == "gradient_pression")
1512 postraitement_gradient_P_ = 1;
1513
1514 if (nom == "vorticite")
1515 {
1516 if (!la_vorticite)
1517 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1518
1519 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, la_vorticite.valeur());
1520 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1521 ch.mettre_a_jour(la_vitesse->temps());
1522 return champs_compris_.get_champ(nom);
1523 }
1524
1525 if (nom == "critere_Q")
1526 {
1527 if (!critere_Q)
1528 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1529
1530 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, critere_Q.valeur());
1531 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1532 ch.mettre_a_jour(la_vitesse->temps());
1533 return champs_compris_.get_champ(nom);
1534 }
1535
1536 if (nom == "y_plus")
1537 {
1538 if (!y_plus)
1539 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1540
1541 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, y_plus.valeur());
1542 if (((ch.temps() != la_vitesse->temps()) || (ch.temps() == temps_init)) && (la_vitesse->mon_equation_non_nul()))
1543 ch.mettre_a_jour(la_vitesse->temps());
1544 return champs_compris_.get_champ(nom);
1545 }
1546
1547 if (nom == "reynolds_maille")
1548 {
1549 if (!Reynolds_maille)
1550 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1551
1552 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, Reynolds_maille.valeur());
1553 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1554 ch.mettre_a_jour(la_vitesse->temps());
1555 return champs_compris_.get_champ(nom);
1556 }
1557
1558 if (nom == "courant_maille")
1559 {
1560 if (!Courant_maille)
1561 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1562
1563 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, Courant_maille.valeur());
1564 if (((ch.temps() != la_vitesse->temps()) || (ch.temps() == temps_init)) && (la_vitesse->mon_equation_non_nul()))
1565 ch.mettre_a_jour(la_vitesse->temps());
1566 return champs_compris_.get_champ(nom);
1567 }
1568
1569 if (nom == "taux_cisaillement")
1570 {
1571 if (!Taux_cisaillement)
1572 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1573
1574 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, Taux_cisaillement.valeur());
1575 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1576 ch.mettre_a_jour(la_vitesse->temps());
1577 return champs_compris_.get_champ(nom);
1578 }
1579
1580 if (nom == "gradient_vitesse")
1581 {
1582 if (!grad_u)
1583 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1584
1585 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, grad_u.valeur());
1586 if ((ch.temps() == temps_init) && (la_vitesse->mon_equation_non_nul()))
1587 ch.mettre_a_jour(la_vitesse->temps());
1588 return champs_compris_.get_champ(nom);
1589 }
1590
1591 if (nom == "pression_hydrostatique")
1592 {
1594 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1595
1596 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, pression_hydrostatique_.valeur());
1597 if (((ch.temps() != la_vitesse->temps()) || (ch.temps() == temps_init)) && (la_vitesse->mon_equation_non_nul()))
1598 {
1600 ch.mettre_a_jour(la_vitesse->temps());
1601 }
1602 return champs_compris_.get_champ(nom);
1603 }
1604
1605 OBS_PTR(Champ_base) ref_champ;
1606
1607 if (Equation_base::has_champ(nom, ref_champ))
1608 return ref_champ;
1609
1610 if (le_traitement_particulier)
1611 if (le_traitement_particulier->has_champ(nom, ref_champ))
1612 return ref_champ;
1613
1614 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1615}
1616
1618{
1620
1621 if (le_traitement_particulier)
1622 le_traitement_particulier->get_noms_champs_postraitables(nom, opt);
1623
1624 Noms noms_compris = champs_compris_.liste_noms_compris();
1625 noms_compris.add("vorticite");
1626 noms_compris.add("critere_Q");
1627 noms_compris.add("y_plus");
1628 noms_compris.add("reynolds_maille");
1629 noms_compris.add("courant_maille");
1630 noms_compris.add("taux_cisaillement");
1631 noms_compris.add("pression_hydrostatique");
1632 noms_compris.add("gradient_vitesse");
1633
1634 if (opt == DESCRIPTION)
1635 Cerr << " Navier_Stokes_std : " << noms_compris << finl;
1636 else
1637 nom.add(noms_compris);
1638}
1639
1640/*! @brief Prints some information to an output stream: - maximum of div U
1641 *
1642 * - convective term
1643 * - diffusive term
1644 * - divergence
1645 * - gradient
1646 *
1647 * @param (Sortie& os) output stream
1648 * @return (int) always returns 1
1649 */
1651{
1652 // Display volumetric balance if not in quasi-compressible mode or Front Tracking
1653 if (!probleme().is_dilatable() && probleme().que_suis_je()!="Probleme_FT_Disc_gen")
1654 {
1655 double LocalFlowRateError=mp_max_abs_vect(divergence_U->valeurs());
1656 os << finl;
1657 os << "Cell balance flow rate control for the problem " << probleme().le_nom() << " : " << finl;
1658 os << "Absolute value : " << LocalFlowRateError << " m"<<dimension+bidim_axi<<"/s" << finl;
1659 os << "Relative value : " << LocalFlowRateRelativeError() << finl; // max|sum(u.ndS)i/(vol(i)/dt)|=max|div(U)i/dt|
1660 // Calculation as OpenFOAM: http://foam.sourceforge.net/docs/cpp/a04190_source.html
1661 // It is relative errors (normalized by the volume/dt)
1662 double dt = schema_temps().pas_de_temps();
1663 double local = LocalFlowRateError / ( probleme().domaine().volume_total() / dt );
1664 double global = mp_somme_vect(divergence_U->valeurs()) / ( probleme().domaine().volume_total() / dt );
1665 cumulative_ += global;
1666 os << "time step continuity errors : sum local = " << local << ", global = " << global << ", cumulative = " << cumulative_ << finl;
1667 // New in 1.6.1: stop if mass balance is bad and threshold < 1.e20
1668 if (local>0.01 && sub_type(solv_iteratif,solveur_pression_.valeur()))
1669 {
1670 if (ref_cast(solv_iteratif,solveur_pression_.valeur()).get_seuil()<1e10)
1671 {
1672 Cerr << "The mass balance is too bad (relative value>1%)." << finl;
1673 Cerr << "Please check and lower the convergence value of the pressure solver." << finl;
1674 exit();
1675 }
1676 }
1677#ifndef TRUST_USE_GPU
1678 // Since 1.6.6, warning to use PETSc Cholesky instead of an iterative method for pressure solver
1679 int nw=100;
1680 if (solveur_pression_->solveur_direct()==0 && le_schema_en_temps->nb_pas_dt()<nw && Process::nproc()<256 && la_pression->valeurs().size_array()<40000)
1681 {
1682 Cerr << finl << "********************** Advice (printed only on the first " << nw << " time steps) *********************" << finl;
1683 Cerr << "You should use PETSc Cholesky solver instead of an iterative method for the pressure solver." << finl;
1684 Cerr << "For the caracteristics of your problem, it will be faster and give a better mass flow balance." << finl;
1685 Cerr << "**********************************************************************************************" << finl << finl;
1686 }
1687#endif
1688 }
1689
1690 if ((seuil_divU < 1.) && (sub_type(solv_iteratif,solveur_pression_.valeur())))
1691 {
1692 const solv_iteratif& solv_iter=ref_cast(solv_iteratif,solveur_pression_.valeur());
1693 os << " convergence threshold of the iterative solver : " << solv_iter.get_seuil() << finl;
1694 }
1696 divergence.impr(os);
1697 gradient.impr(os);
1698 return 1;
1699}
1700
1701
1702/*! @brief Returns the name of the application domain: "Hydraulique".
1703 *
1704 * @return the name representing the application domain
1705 */
1707{
1708 static Motcle domaine = "Hydraulique";
1709 return domaine;
1710}
1711
1712static void construire_matrice_implicite(Operateur_base& op,
1713 const DoubleTab& valeurs_inconnue,
1714 const Solveur_Masse_base& solv_masse,
1715 const double dt)
1716{
1717 Matrice& mat = op.set_matrice();
1718 if(!mat)
1719 mat.typer("Matrice_Morse");
1720
1721 if(op.get_decal_temps()==1)
1722 {
1723 Matrice_Morse& matrice = ref_cast(Matrice_Morse, mat.valeur());
1724 op.dimensionner(matrice);
1725 op.contribuer_a_avec(valeurs_inconnue, matrice);
1726 solv_masse.ajouter_masse(dt, matrice);
1727 matrice *= dt;
1728
1729 // If the solver is Cholesky or GCP, a matrix of type
1730 // Matrice_Morse_Sym is expected. Convert the matrix type:
1731 const Nom& type_solveur = op.get_solveur()->que_suis_je();
1732 if(type_solveur == "Solv_Cholesky" || type_solveur == "Solv_GCP")
1733 {
1734 Matrice_Morse_Sym new_mat(matrice);
1735 new_mat.set_est_definie(1);
1736 // mat is destroyed and then rebuilt:
1737 mat = new_mat;
1738 // Reinitialize the solver (recompute preconditioners, factorization, etc...)
1739 //ref_cast_non_const(SolveurSys_base,op.get_solveur().valeur()).reinit();
1740 op.set_solveur()->reinit();
1741 }
1742 }
1743}
1744
1745/* In PolyMAC_HFV, the gradient contributes to the N-S equation matrix */
1747{
1749 if (gradient->has_interface_blocs())
1750 gradient->dimensionner_blocs({{ "vitesse", &matrice }});
1751}
1752
1754{
1755 return Equation_base::has_interface_blocs() && gradient->has_interface_blocs();
1756}
1757
1758/* le gradient passe en dernier */
1759void Navier_Stokes_std::dimensionner_blocs(matrices_t matrices, const tabs_t& semi_impl) const
1760{
1761 Equation_base::dimensionner_blocs(matrices, semi_impl);
1762 gradient->dimensionner_blocs(matrices, semi_impl);
1763}
1764
1765void Navier_Stokes_std::assembler_blocs(matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl) const
1766{
1767 Equation_base::assembler_blocs(matrices, secmem, semi_impl);
1768 gradient->ajouter_blocs(matrices, secmem, semi_impl);
1769}
1770
1771DoubleTab& Navier_Stokes_std::derivee_en_temps_inco(DoubleTab& derivee)
1772{
1774 // Computation of the time derivative:
1775 if(!implicite_)
1776 {
1777 // Explicit computation, use the standard time derivative:
1779 }
1780 else
1781 {
1782 // Implicit computation of one or more operators (rarely used)
1783 // Dataset syntax: operateur { implicite solveur cholesky|gcp ... }
1784 derivee = 0;
1785 for(int i=0; i<nombre_d_operateurs(); i++)
1786 operateur(i).ajouter(derivee);
1787
1788 les_sources.ajouter(derivee);
1789 derivee.echange_espace_virtuel();
1790
1791 const double dt=schema_temps().pas_de_temps();
1792 static double dt_old=dt;
1793
1794 for(int i=0; i<nombre_d_operateurs(); i++)
1795 {
1797 // If matrix not build or matrix time dependant:
1798 if(!op.get_matrice() || !sys_invariant_)
1799 construire_matrice_implicite(op, inconnue().valeurs(), solv_masse(), dt);
1800
1801 if(op.get_decal_temps()==1)
1802 {
1803 if(sys_invariant_ && dt!=dt_old)
1804 {
1805 // The matrix does not change but the time step changes.
1806 // The matrix is written A =
1807 // Simplified update of the matrix
1808 Matrice_Morse& matrice=ref_cast(Matrice_Morse, op.set_matrice().valeur());
1809 matrice/=dt_old;
1810 solv_masse().ajouter_masse(-dt_old, op.set_matrice().valeur());
1811 solv_masse().ajouter_masse(dt, op.set_matrice().valeur());
1812 matrice*=dt;
1813 ref_cast_non_const(SolveurSys_base,op.get_solveur().valeur()).reinit();
1814 }
1815 Matrice_Morse& matrice=ref_cast(Matrice_Morse, op.set_matrice().valeur());
1816 if(implicite_==1)
1817 {
1818 // A single implicit operator.
1819 DoubleTrav secmem(derivee);
1820 secmem=derivee;
1821 DoubleTrav incre_pre(la_pression->valeurs());
1822 gradient.calculer(la_pression->valeurs(),gradient_P->valeurs());
1823 secmem-=gradient_P->valeurs();
1824 uzawa(secmem, matrice,op.set_solveur(),derivee, incre_pre);
1825
1826 la_pression->valeurs()+=incre_pre;
1827 gradient.calculer(la_pression->valeurs(),gradient_P->valeurs());
1828 }
1829 else
1830 {
1831 // plusieurs operateurs implicites ...
1832 Cerr << "To be developped ... " << finl;
1833 exit();
1834 }
1835 }
1836 }
1837 dt_old=dt;
1838 return derivee;
1839 }
1840}
1841
1842void Navier_Stokes_std::uzawa(const DoubleTab& secmem, const Matrice_Base& A, SolveurSys& solveur, DoubleTab& U, DoubleTab& P)
1843{
1844 // A U + Bt P = secmem
1845 // B U = G
1846 // Start from the current pressure and
1847 // secmem = inertia + conv + sources + diff BCs
1848 // Start from P0 and U0 satisfying BCs and BU0=G
1849
1850 // AU + Bt Cp = secmem
1851 // BU = 0
1852
1853 // Write a CG on B(A-1)Bt Cp = B(A-1)(secmem)
1854
1855 DoubleTrav Cu(U);
1856 DoubleTrav grad(U);
1857 DoubleTrav grad0(U);
1858 DoubleTrav resu(P);
1859 DoubleTrav residu(P);
1860 DoubleTrav Cp(P);
1861 double dold,dnew,alfa;
1862 double seuil=seuil_uzawa;
1863
1864 //Cu = A(-1) secmem
1865 Cerr << "Begining Uzawa, secmem norm value : " << mp_norme_vect(secmem) << finl;
1866 P=0.;
1867 gradient->multvect(P, grad0);
1868 solveur.nommer("uzawa_solver");
1869 solveur.resoudre_systeme(A, secmem, U);
1870 solv_masse().corriger_solution(U,Cu); // for Dirichlet boundary conditions!
1871
1872 // residu=BCu
1873 divergence->multvect(U, resu);
1874
1875 residu.copy(resu);
1876 residu*=-1.;
1877
1878 // Cp = -residu;
1879 Cp = residu;
1880 Cp*=-1;
1882
1883 // Square of the norm
1884 dold = mp_norme_vect(residu);
1885 dold = dold * dold;
1886 dnew = dold;
1887
1888 double s=0;
1889 int niter=0;
1890 int nmax=Cp.size();
1891 Cerr << "Uzawa, initial residue : " << dnew << finl;
1892 // seuil=std::max(seuil, dnew*1.e-12);
1893 while ( ( dnew > seuil ) && (niter++ < nmax) )
1894 {
1895 gradient->multvect(Cp, grad);
1896 grad-=grad0;
1897 grad*=-1;
1898 solveur.resoudre_systeme(A, grad, Cu);
1899 solv_masse().corriger_solution(Cu,U); // for Dirichlet boundary conditions!
1900 divergence->multvect(Cu, resu);
1901 resu*=-1;
1902
1903 s = mp_prodscal(resu, Cp);
1904 alfa = dold/(s);
1905 P.ajoute(alfa,Cp);
1906 residu.ajoute(alfa,resu);
1907 U.ajoute(alfa,Cu);
1908 dnew = mp_norme_vect(residu);
1909 dnew = dnew * dnew;
1910 assert(dnew >= 0);
1911 Cp *= (dnew/dold);
1912 Cp -= residu;
1913 dold = dnew;
1914 // Cerr << "Uzawa, Residu apres "
1915 // << niter << " iterations = " << dnew << finl;
1916 }
1917
1918 if(dnew > seuil)
1919 {
1920 Cerr << "######## Uzawa, No convergence after : " << niter << " iterations\n";
1921 Cerr << "######## Uzawa, Residue : "<< dnew << "\n";
1922 exit();
1923 }
1924
1925 else if ((je_suis_maitre()))
1926 {
1927 Cerr << finl << "Uzawa, convergence reached after " << niter << " iterations" << finl;
1928 }
1929 {
1930 // On verifie :
1931
1932 DoubleTrav R(resu);
1933 divergence->multvect(U, R);
1934
1935 gradient->multvect(P, grad);
1936 grad-=grad0;
1937 DoubleTrav F(secmem);
1938 DoubleTrav UU(U);
1939 F=secmem;
1940 F-=grad;
1941
1942 solveur.resoudre_systeme(A, F, UU);
1943 UU-=U;
1944
1945 // Optimization: combine 2 mp_norme_vect into 1 collective call
1946 double R_carre = local_carre_norme_vect(R);
1947 double UU_carre = local_carre_norme_vect(UU);
1948 Process::mp_sum_for_each(R_carre, UU_carre);
1949 Cerr << "Ending Uzawa : mass residue : " << sqrt(R_carre) <<finl;
1950 Cerr << "Ending Uzawa : Qdm residue : " << sqrt(UU_carre)<<finl;
1951 }
1952}
1953
1955{
1956 if (le_traitement_particulier)
1957 le_traitement_particulier->sauver_stat();
1958}
1959
1961{
1962 Cerr<<" Navier_Stokes_std::rho_la_vitesse() must be overloaded "<<finl;
1963 assert(0);
1964 exit();
1965 throw;
1966}
1967
1968void Navier_Stokes_std::update_y_plus(const DoubleTab& tab)
1969{
1970 if (!y_plus) Process::exit(que_suis_je() + " : y_plus must be initialised so it can be updated") ;
1971 DoubleTab& tab_y_p = y_plus->valeurs();
1972 if (tab.nb_dim()==2)
1973 for (int i = 0 ; i < tab_y_p.dimension_tot(0) ; i++)
1974 for (int n = 0 ; n < tab_y_p.dimension_tot(1) ; n++) tab_y_p(i,n) = tab(i,n);
1975 if (tab.nb_dim()==3)
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,0,n);
1978}
1979
1981{
1982 if(probleme().domaine().getCouplingMethod()) //implicit IFS coupling
1983 // Equivalent of setting present = past for velocity done in for eg. Schema_Euler_Implicite::test_stationnaire.
1984 // Ensures sub-iterations start with the correct pressure for implicit coupling
1985 pression().valeurs()= P_n;
1986}
1987
1992
1994{
1995 // in case of implicit coupling with a structural code: update the fluxes (used for computing the fluid force) during implicit sub-iterations
1996
1997 if(probleme().domaine().getCouplingMethod()) //implicit IFS coupling case
1998 {
1999 Cout<<" Implicit coupling: Navier_Stokes_std_ALE::updateFluidForce "<<finl;
2000 //update diffusion operator
2001 DoubleTab field_value = velocity;
2002 field_value = 0.;
2003 operateur_diff().ajouter(velocity, field_value);
2004
2005
2006 //update gradient operator
2007 pression().mettre_a_jour(schema_temps().temps_courant());
2009 gradient->calculer_flux_bords();
2010 }
2011}
class Champ_Don_base base class of Given Fields (not calculated)
DoubleTab & valeurs() override
Overrides Champ_base::valeurs() Returns the array of values.
class Champ_Fonc_base Base class of fields that are functions of a calculated quantity
void mettre_a_jour(double temps) override
Time update of the field.
Class Champ_Inc_base.
DoubleTab & futur(int i=1) override
Returns field values at instant t+i.
void mettre_a_jour(double temps) override
Performs a time update of the unknown field.
void resetTime(double time) override
DoubleTab & valeurs() override
Returns the array of field values at the current time.
double changer_temps_futur(double, int i=1)
Sets the time of the i-th future field.
virtual DoubleTab & valeurs()=0
Champ_Uniforme Represents a field that is constant in space and time.
class Champ_base This class is the base of the fields hierarchy.
Definition Champ_base.h:43
Champ_base & affecter(const Champ_base &)
Assign a field to another.
double temps() const
Returns the time of the field.
static void verifier(const char *const msg, double)
Definition Debog.cpp:21
class Discret_Thyd This class is the base class representing a discretization
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:876
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
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
class Domaine_dis_base This class is the base of the hierarchy of discretized domains.
const Domaine & domaine() const
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
class Equation_base The role of an equation is the calculation of one or more fields....
virtual void set_param(Param &titi) const override
int reprendre(Entree &) override
We resume the unknown from an input stream.
virtual void dimensionner_matrice_sans_mem(Matrice_Morse &mat_morse)
virtual int verif_Cl() const
Verifies the compatibility of boundary conditions with the 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 &)
Associates with the Problem passed as parameter.
Sources & sources()
Returns the source terms associated with the equation.
const Discretisation_base & discretisation() const
Returns the discretization associated with the equation.
Solveur_Masse_base & solv_masse()
Returns the mass solver associated with the 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)
The value of the unknown at the time step has been calculated.
virtual int impr(Sortie &os) const
Prints the equation operators to an output stream, unconditionally.
virtual void abortTimeStep()
Reinitialize what must be.
virtual void completer()
Completes the construction (initialization) of objects associated with the equation.
Sources les_sources
void get_noms_champs_postraitables(Noms &nom, Option opt=NONE) const override
virtual int preparer_calcul()
Everything that does not depend on other possible problems.
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
We save the unknown, then the source terms to an output stream.
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Returns the discretized boundary condition domain associated with the equation.
Probleme_base & probleme()
Returns the problem associated with the equation.
virtual void verifie_ch_init_nb_comp(const Champ_Inc_base &ch_ref, const int nb_comp) const
Verification of the number of components read for the specification of a field.
int lire_motcle_non_standard(const Motcle &, Entree &) override
Reads non-simple-type parameters of an Objet_U from an input stream.
int limpr() const
Ask the time scheme if an output is needed.
void creer_champ(const Motcle &motlu) override
Schema_Temps_base & schema_temps()
Returns the time scheme associated with the equation.
virtual bool initTimeStep(double dt)
Allocation and initialization of the unknown and boundary conditions until present+dt.
virtual void discretiser()
Discretizes the 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()
Returns the discretized domain associated with the equation.
virtual double calculer_pas_de_temps() const
Calculation of the next time step.
virtual int nb_comp() const
Definition Field_base.h:56
Base class for an incompressible fluid and its properties:
Definition Fluide_base.h:36
const Champ_Don_base & viscosite_cinematique() const
Definition Fluide_base.h:56
Matrice_Base class - Base class of the matrix hierarchy.
Matrice_Morse_Sym class - Represents a sparse symmetric matrix M stored in Morse format.
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
Matrice class - Generic class in the matrix hierarchy.
Definition Matrice.h:34
Milieu_base This class is the base of the (physical) medium hierarchy.
Definition Milieu_base.h:50
virtual const Champ_base & masse_volumique() const
Returns the mass density of the medium (const version).
virtual const Champ_Don_base & gravite() const
Returns the gravity of the medium if it has been associated, raises an error otherwise (const version...
A character string (Nom) in uppercase.
Definition Motcle.h:26
An array of Motcle objects.
Definition Motcle.h:63
int rang(const char *const ch) const
Definition Motcle.cpp:336
Navier_Stokes_std This class carries the terms of the momentum equation.
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
Returns the physical medium of the equation (Fluide_base upcast to Milieu_base).
const Motcle & domaine_application() const override
Returns the name of the application domain: "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
Performs a restart from an input stream.
Operateur_Conv terme_convectif
const Champ_Inc_base & inconnue() const override
Returns the velocity (unknown field of the equation) (const version).
void creer_champ(const Motcle &motlu) override
virtual const Champ_base & vitesse_pour_transport() const
int lire_motcle_non_standard(const Motcle &, Entree &) override
Reads non-simple-type parameters of an Objet_U from an input stream.
Entree & lire_cond_init(Entree &) override
Reading of initial conditions in an input stream.
DoubleTab & corriger_derivee_impl(DoubleTab &) override
Resolution de la pression, inconnue implicitee de Navier Stokes.
const Fluide_base & fluide() const
Returns the incompressible fluid (physical medium of the equation) associated with the equation.
void mettre_a_jour(double temps) override
Performs a time update of the equation.
virtual void projeter()
Computes the solution U of the equations: | M(U-V)/dt + BtP = 0.
Operateur_Div & operateur_divergence()
Returns the divergence operator associated with the equation.
void completer() override
Completes the base equation, associates the pressure with the equation,.
int sauvegarder(Sortie &) const override
Calls Equation_base::sauvegarder(Sortie&) and saves the pressure to an output stream.
const Champ_base & get_champ(const Motcle &nom) const override
Champ_Inc_base & pression_pa()
bool initTimeStep(double dt) override
Allocation and initialization of the unknown and boundary conditions until present+dt.
void abortTimeStep() override
Reinitialize what must be.
int impr(Sortie &os) const override
Prints some information to an output stream: - maximum of 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
Associates with the problem: calls 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()
Returns the gradient operator associated with the 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()
Types the pressure assembler.
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
Verifies the compatibility of boundary conditions with the 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
Discretizes the 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() Assembly of the pressure solver and
Operateur_Diff & operateur_diff()
const Operateur & operateur_fonctionnel(int) const override
void reassembler_pression_si_necessaire()
const Operateur & operateur(int) const override
Returns the i-th operator of the equation: - terme_diffusif if i = 0.
int nombre_d_operateurs_tot() const override
void associer_milieu_base(const Milieu_base &) override
Associates a physical medium with the equation by dynamically constructing (casting) an object of typ...
void assembler_blocs(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={}) const override
SolveurSys & solveur_pression()
Returns the pressure solver (const version).
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()
Computes "la_pression_en_pa" from "la_pression".
int nombre_d_operateurs() const override
Returns the number of operators in the equation: 2 for the standard Navier-Stokes equations.
Champ_Inc_base & pression()
void associer_fluide(const Fluide_base &un_fluide)
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
Nom & suffix(const char *const)
Suffix extraction: Nom x("azerty");.
Definition Nom.cpp:266
const std::string & getString() const
Definition Nom.h:92
An array of character strings (VECT(Nom)).
Definition Noms.h:26
friend class Entree
Definition Objet_U.h:71
static int dimension
Definition Objet_U.h:94
friend class Sortie
Definition Objet_U.h:70
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
static int bidim_axi
Definition Objet_U.h:97
static int axi
Definition Objet_U.h:96
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
Operateur_Diff Generic class of the hierarchy of operators representing a diffusion.
DoubleTab & ajouter(const DoubleTab &, DoubleTab &) const override
Call to the underlying object.
Operateur_Div Generic class of the hierarchy of operators computing the divergence.
void volumique(DoubleTab &) const
Initializes the array passed as parameter with the contribution of the operator.
Classe Operateur_Grad Generic class of the hierarchy of operators computing the gradient.
class Operateur_base This class is the base of the hierarchy of objects representing an
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
class Operateur Generic class of the operator hierarchy.
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
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
Definition Probleme_U.h:109
class Probleme_base It is a Probleme_U that is not a coupling.
bool is_dilatable() const
const Domaine & domaine() const
Returns the domain associated with the problem.
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:208
static int nproc()
Returns the number of processors in the current group. See Comm_Group::nproc() and PE_Groups::current...
Definition Process.cpp:102
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
static int je_suis_maitre()
Returns 1 if on the master processor of the current group (i.e. me() == 0), 0 otherwise.
Definition Process.cpp:82
SFichier is to the C++ ofstream class what Sortie is to the C++ ostream class.
Definition SFichier.h:29
class Schema_Temps_base
double temps_courant() const
Returns the current time.
virtual double temps_futur(int i) const =0
double pas_de_temps() const
Returns the current time step (delta_t).
virtual int nb_valeurs_futures() const =0
double temps_init() const
Returns the initial time.
class SolveurSys A SolveurSys represents any class
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
Solveur_Masse_base Represents the mass matrix of an 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
Base class for output streams.
Definition Sortie.h:52
Source Generic class of the source term hierarchy. A Source object can.
Definition Source.h:33
void typer_direct(const Nom &)
Definition Source.cpp:41
void mettre_a_jour(double temps)
Time update of all sources in the list.
Definition Sources.cpp:109
DoubleTab & ajouter(DoubleTab &) const
Adds the contribution of all sources in the list to the array passed as parameter,...
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)