TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Equation_base.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 <Parametre_diffusion_implicite.h>
17#include <Solveur_Implicite_base.h>
18#include <Schema_Euler_explicite.h>
19#include <Schema_Euler_Implicite.h>
20#include <Source_dep_inco_base.h>
21#include <Operateur_Conv_base.h>
22#include <Op_Conv_negligeable.h>
23#include <Operateur_Diff_base.h>
24#include <Discretisation_base.h>
25#include <Matrice_Morse_Diag.h>
26#include <Frontiere_dis_base.h>
27#include <Matrice_Morse_Sym.h>
28#include <Operateur_base.h>
29#include <TRUSTTab_parts.h>
30#include <EcrFicPartage.h>
31#include <Postraitement.h>
32#include <Equation_base.h>
33#include <Milieu_base.h>
34#include <TRUST_2_PDI.h>
35#include <Domaine_VF.h>
36#include <SolveurSys.h>
37#include <Domaine_VF.h>
38#include <Operateur.h>
39#include <EChaine.h>
40#include <Avanc.h>
41#include <Debog.h>
42#include <Param.h>
43#include <Perf_counters.h>
44
45// XD condinit objet_lecture nul NO_BRACE Initial condition.
46// XD attr nom chaine nom REQ Name of initial condition field.
47// XD attr ch field_base ch REQ Type field and the initial values.
48
49// XD condinits listobj condinits INHERITS_BRACE condinit NO_COMMA Initial conditions.
50
51Implemente_base_sans_constructeur(Equation_base,"Equation_base",Objet_U);
52// XD eqn_base mor_eqn eqn_base BRACE Basic class for equations.
53/* Attributes further down in the cpp: */
54
55Equation_base::Equation_base()
56{
58 implicite_=-1;
59 has_time_factor_= false;
60 Nom expr_equation_non_resolue="0";
61 equation_non_resolue_.setNbVar(1);
62 equation_non_resolue_.setString(expr_equation_non_resolue); // Valeur par defaut, equation resolue
63 equation_non_resolue_.addVar("t");
64 equation_non_resolue_.parseString();
66}
67
69{
70 std::string str= equation_non_resolue_.getString();
71 std::string str2("INPUT_INT_VALUE");
72 if (str.compare(str2)==0)
73 {
74 Nom name = eq_non_resolue_input_.getName();
75 int eq_non_resolue_int = mon_probleme->getOutputIntValue(name);
76 return eq_non_resolue_int;
77 }
78 else
79 {
80 double t = le_schema_en_temps->temps_courant();
81 equation_non_resolue_.setVar("t",t);
82 return (int)equation_non_resolue_.eval();
83 }
84}
85
86/*! @brief Renvoie le domaine discretise associe a l'equation.
87 *
88 * @return (Domaine_dis_base&) le domaine discretise asscoie a l'equation
89 * @throws l'objet domaine discretise (Domaine_dis) est invalide,
90 * probleme associe non discretise.
91 */
93{
94 if (!le_dom_dis)
95 {
96 Cerr << "There is no object of type Domaine_dis yet associated to the equation " << que_suis_je() << finl;
97 Cerr << "This means that the problem has not been discretized or" << finl;
98 Cerr << "that instruction Discretiser is misplaced" << finl;
99 exit();
100 }
101 return le_dom_dis.valeur();
102}
103
104/*! @brief Renvoie le domaine discretise associe a l'equation.
105 *
106 * (version const)
107 *
108 * @return (Domaine_dis_base&) le domaine discretise asssocie a l'equation
109 * @throws l'objet domaine discretise (Domaine_dis) est invalide,
110 * probleme associe non discretise.
111 */
113{
114 if (!le_dom_dis)
115 {
116 Cerr << "There is no object of type Domaine_dis associated to the equation " << que_suis_je() << finl;
117 Cerr << "This means that the problem has not been discretized" << finl;
118 exit();
119 }
120 assert(le_dom_dis);
121 return le_dom_dis.valeur();
122}
123
124/*! @brief Complete la construction (initialisation) des objets associes a l'equation.
125 *
126 * Complete les sources, associe l'equation a l'inconnue complete les
127 * operateurs, complete les conditions aux limites discretisees.
128 * Voir les methodes Source_base::completer(),
129 * Operateur_base::completer()
130 * Domaine_Cl_dis_base::completer()
131 * Domaine_Cl_dis_base::completer(const Domaine_dis_base& )
132 *
133 */
135{
136 inconnue().associer_eqn(*this);
137 if (le_dom_Cl_dis)
138 le_dom_Cl_dis->completer();
139
140 inconnue().associer_domaine_cl_dis(le_dom_Cl_dis);
141
142 if (mon_probleme->is_coupled())
143 {
144 bool err = false;
145 int nb_cl = le_dom_Cl_dis->nb_cond_lim();
146 for (int i=0; i<nb_cl; i++)
147 {
148 const Cond_lim_base& la_cl = le_dom_Cl_dis->les_conditions_limites(i);
149 const Frontiere& la_frontiere = la_cl.frontiere_dis().frontiere();
150
151 bool raccord_found = false;
152
153 // VDF and PolyMAC_HFV
154 if (la_cl.que_suis_je().debute_par("Paroi_Echange_contact") || la_cl.que_suis_je().debute_par("Echange_contact_Rayo"))
155 raccord_found = true;
156
157 // VEF
158 if (la_cl.que_suis_je().debute_par("Scalaire_impose_paroi") || la_cl.que_suis_je().debute_par("paroi_temperature_imposee_rayo") || la_cl.que_suis_je().debute_par("temperature_imposee_paroi"))
159 raccord_found = true;
160
161 if ( raccord_found && !sub_type(Raccord_base,la_frontiere))
162 {
163 Cerr << "====================================================================" << finl;
164 Cerr << "Boundary " << la_frontiere.le_nom() << " should be a raccord" << finl;
165 Cerr << "Add in your data file between the definition and the partition of the domain " << mon_probleme->domaine().le_nom() << " : " << finl;
166 Cerr << "Modif_bord_to_raccord " << mon_probleme->domaine().le_nom() << " " << la_frontiere.le_nom() << finl;
167 err = true;
168 }
169 }
170 if(err)
171 exit();
172 }
173
174 //Ajout d un element vide qui sera renvoye si pas de modele trouve
175 RefObjU mod;
176 if (liste_modeles_.size()==0)
177 liste_modeles_.add(mod);
178
179 // pour les eqns n'appelant pas preparer_calcul
181 int nb_op=nombre_d_operateurs();
182 Nom msg="Equation_base::completer(), nb_op = " ;
183 Debog::verifier(msg, nb_op);
184 for(int i=0; i<nb_op; i++)
185 operateur(i).completer();
186
187 if (solveur_masse) // [ABN]: In case of Front-Tracking, mass solver mass might be uninitialized ...
189
190 les_sources.completer();
192
193 // Determine implicite_ and sys_invariant_ variables:
194 implicite_=0;
195 for(int i=0; i<nombre_d_operateurs(); i++)
196 {
197 if(operateur(i).l_op_base().get_decal_temps()==1)
198 {
199 ++implicite_;
201 }
202 }
203}
204
205
206/*! @brief Surcharge Objet_U::printOn Imprime l'equation et ses composants sur un flot de sortie.
207 *
208 * Imprime le nom de l'equation, le solveur masse, les termes sources
209 * les conditions aux limites discretisees, les inconnues et les operateurs.
210 *
211 * @param (Sortie& os) un flot de sortie
212 * @return (Sortie&) le flot de sortie modifie
213 */
215{
216 os << nom_ << finl;
217 os << solveur_masse;
218 os << les_sources;
219 os << le_dom_Cl_dis;
220 os << inconnue() ;
221 for(int i=0; i<nombre_d_operateurs(); i++)
222 {
223 os << operateur(i).l_op_base();
224 }
225 return os;
226}
227
228/*! @brief Lecture d'une equation sur un flot d'entree.
229 *
230 * Le format est le suivant:
231 * {
232 * [Source { [sou_1], [sour_2], ...} ]
233 * Conditions_limites { [cl_1] [cl_2] ... }
234 * Conditions_initiales { [cl_init] }
235 * }
236 *
237 * @param (Entree& is) un flot d'entree pour lire l'equation
238 * @return (Entree&) le flot d'entree modifie
239 * @throws mauvais format de lecture, accolade ouvrante attendue
240 * @throws pas de conditions initiales, il faut initialiser l'inconnue
241 * @throws pas de conditions aux limites, il faut donner des conditions aux limites
242 */
244{
245 Cerr<<"Reading of data for a "<<que_suis_je()<<" equation"<<finl;
246 Param param(que_suis_je());
247 set_param(param);
248 Nom expr_equation_non_resolue="0";
249 param.ajouter("disable_equation_residual",&disable_equation_residual_); // XD attr disable_equation_residual entier disable_equation_residual OPT The equation residual will not be used for the problem residual used when checking time convergence or computing dynamic time-step
250 equation_non_resolue_.setString(expr_equation_non_resolue);
251 param.lire_avec_accolades_depuis(is);
252 matrice_init = 0;
253 return is;
254}
255
256// XD attr convection bloc_convection convection OPT Keyword to alter the convection scheme.
257// XD attr diffusion bloc_diffusion diffusion OPT Keyword to specify the diffusion operator.
259{
260 param.ajouter_non_std("conditions_limites|boundary_conditions",(this),Param::REQUIRED); // XD attr conditions_limites|boundary_conditions condlims conditions_limites OPT Boundary conditions.
261 param.ajouter_non_std("conditions_initiales|initial_conditions",(this),Param::REQUIRED); // XD attr conditions_initiales|initial_conditions condinits conditions_initiales OPT Initial conditions.
262 param.ajouter_non_std("sources",(this)); // XD attr sources sources sources OPT To introduce a source term into an
263 // XD_CONT equation (in case of several source terms into the same equation, the blocks corresponding to the various
264 // XD_CONT terms need to be separated by a comma)
265 param.ajouter_non_std("ecrire_fichier_xyz_valeur",(this)); // XD attr ecrire_fichier_xyz_valeur ecrire_fichier_xyz_valeur ecrire_fichier_xyz_valeur OPT This keyword is used to write the values of a field only for some boundaries in a text file
266 param.ajouter("parametre_equation",&parametre_equation_); // XD attr parametre_equation parametre_equation_base parametre_equation OPT Keyword used to specify additional parameters for the equation
267 param.ajouter_non_std("equation_non_resolue",(this)); // XD attr equation_non_resolue chaine equation_non_resolue OPT
268 // XD_CONT The equation will not be solved while condition(t) is verified if equation_non_resolue keyword is used.
269 // XD_CONT Exemple: The Navier-Stokes equations are not solved between time t0 and t1. NL2 Navier_Sokes_Standard NL2 {
270 // XD_CONT equation_non_resolue (t>t0)*(t<t1) }
271 param.ajouter_non_std("rename_equation|renommer_equation",(this)); // XD attr renommer_equation chaine rename_equation OPT Rename the equation with a specific name.
272}
273
275{
276 if (mot=="sources")
277 {
278 lire_sources(is);
279 return 1;
280 }
281 else if (mot=="conditions_limites|boundary_conditions")
282 {
283 lire_cl(is);
284 verif_Cl();
285 return 1;
286 }
287 else if (mot=="conditions_initiales|initial_conditions")
288 {
289 lire_cond_init(is);
290 return 1;
291 }
292 else if (mot=="ecrire_fichier_xyz_valeur")
293 {
294 xyz_field_values_file_.associer_eqn(*this);
295 is >> xyz_field_values_file_;
296 return 1;
297 }
298 else if (mot=="rename_equation|renommer_equation")
299 {
300 Cerr << "Equation " << nom_ << " renamed to : ";
301 is >> nom_;
302 Cerr << nom_ << finl;
303 return 1;
304 }
305 else if (mot=="equation_non_resolue")
306 {
307 // differentiate an entry with an expression from an entry with the keyword eq_non_resoue_input_
308 // On complete:
309 Motcle expr_equation_non_resolue;
310 is >> expr_equation_non_resolue;
311 equation_non_resolue_.setString(expr_equation_non_resolue);
312 if (expr_equation_non_resolue=="INPUT_INT_VALUE")
313 is >> eq_non_resolue_input_;
314 else
315 equation_non_resolue_.parseString();
316 return 1;
317 }
318 return -1;
319}
320
321
322/*! @brief Lecture des termes sources dans un flot d'entree.
323 *
324 * @param (Entree& is) flot d'entree pour lire les termes sources
325 * @return (Entree&) le flot d'entree modifie
326 */
328{
329 static bool already_read=false;
330 if (already_read)
331 {
332 Cerr << "Error: the 'sources' keyword should only appear once per equation." << finl;
333 Cerr << "To declare several source terms, list them inside a single block separated by commas:" << finl;
334 Cerr << " sources { TermA { ... } , TermB { ... } }" << finl;
335 // Process::exit(); // comment that out since it appears pb_multiphase is doing shadowy stuff...
336 }
337
338 already_read=true;
339 Cerr << "Reading of source terms" << finl ;
340 is >> les_sources;
341 return is;
342}
343
344/*! @brief Renvoie les termes sources asssocies a l'equation
345 *
346 * @return (Sources&) la liste des termes sources associees a l'equation
347 */
352
353/*! @brief Renvoie les termes sources asssocies a l'equation (version const)
354 *
355 * @return (Sources&) la liste des termes sources associees a l'equation
356 */
358{
359 return les_sources;
360}
361
362/*! @brief Lecture des conditions initiales dans un flot d'entree.
363 *
364 * Le format de lecture est le suivant:
365 * {
366 * Nom [DOIT ETRE LE NOM DE L'INCONNUE]
367 * [LIRE UN CHAMP DONNE]
368 * }
369 *
370 * @param (Entree& is) le flot d'entree
371 * @return (Entree&) le flot d'entree modifie
372 * @throws erreur de format, accolade ouvrante attendue
373 * @throws mauvais nom pour l'inconnue
374 * @throws erreur de format, accolade fermante attendue
375 */
377{
378 Cerr << "Reading of initial conditions\n";
379 Nom nom;
380 Motcle motlu;
381 is >> nom;
382 motlu = nom;
383 if(motlu!=Motcle("{"))
384 {
385 Cerr << "We expected a { while reading " << que_suis_je() << finl;
386 Cerr << "and not : " << nom << finl;
387 exit();
388 }
389 is >> nom;
390 motlu = nom;
391 if (motlu != Motcle(inconnue().le_nom()))
392 {
393 Cerr << nom << " is not the name of the unknown "
394 << inconnue().le_nom() << finl;
395 exit();
396 }
397 OWN_PTR(Champ_Don_base) ch_init;
398 is >> ch_init;
399 const int nb_comp = ch_init->nb_comp();
401
402 //Cerr<<"inconnue().que_suis_je() = "<<inconnue().que_suis_je()<<finl;
403
404 inconnue().affecter(ch_init.valeur());
405 is >> nom;
406 motlu = nom;
407 if(motlu!=Motcle("}"))
408 {
409 Cerr << "We expected a } while reading " << que_suis_je() << finl;
410 Cerr << "and not : " << nom << finl;
411 exit();
412 }
413 return is;
414}
415
416/*! @brief Lecture des conditions limites sur un flot d'entree.
417 *
418 * voir Domaine_Cl_dis_base::readOn
419 *
420 * @param (Entree& is) le flot d'entree
421 * @return (Entree&) le flot d'entree modifie
422 * @throws le domaine des conditions aux limites discretisee est vide
423 */
425{
426 Cerr << "Reading of boundaries conditions\n";
427 if(!le_dom_Cl_dis)
428 {
429 Cerr << "Error while reading boundaries conditions : " <<
430 que_suis_je() << finl;
431 Cerr << "The Domaine_Cl_dis_base is empty ..." << finl;
432 exit();
433 }
434 is >> le_dom_Cl_dis.valeur();
435 return is;
436}
437
438/*! @brief On sauvegarde l'inconnue, puis les sources sur un flot de sortie.
439 *
440 * @param (Sortie& os)
441 * @return (int) le code de retour de Champ_Inc::sauvegarder()
442 */
444{
445 int ret = inconnue().sauvegarder(os);
446 for (int i = 0; i < les_sources.size(); i++)
447 ret += les_sources(i)->sauvegarder(os);
448 return ret;
449}
450
451
452/*! @brief for PDI IO: retrieve name, type and dimensions of the data to save/restore.
453 * This has to be overrode for all the equations that either:
454 * - have extra fields (ie in addition to the unknown) or extra scalars to save/restore.
455 * - want to save the unknown but with a different name
456 * These data will then be written in a YAML file, to initialize PDI.
457 * They have to be shared with PDI afterwards, when they need to be read/written (via TRUST_2_PDI)
458 *
459 */
460std::vector<YAML_data> Equation_base::data_a_sauvegarder() const
461{
462 std::vector<YAML_data> data = inconnue().data_a_sauvegarder();
463 return data;
464}
465
466/*! @brief On reprend l'inconnue a partir d'un flot d'entree.
467 *
468 * [ON CHERCHE L'INCONNUE PAR SON NOM]
469 * [ON LIT L'INCONNUE]
470 * Voir Champ_Inc::reprendre(Entree&)
471 *
472 * @param (Entree& fich) le flot d'entree (fichier) a lire
473 * @return (int) renvoie toujours 1
474 * @throws erreur de reprise, fin de fichier atteinte sans trouver l'inconnue
475 */
477{
479 {
480 double temps = schema_temps().temps_courant();
481 Nom field_tag(inconnue().le_nom());
482 field_tag += inconnue().que_suis_je();
483 field_tag += probleme().domaine().le_nom();
484 field_tag += Nom(temps,probleme().reprise_format_temps());
485 // This part ensure the backwards compatibility of TRUST regarding the renaming of the PolyMAC family of discretisation. It will be deprecated in the TRUST 2.0
486
487 if (probleme().discretisation().is_poly_family())
488 {
489 Nom field_tag_syno = create_polymacfamily_syno(field_tag);
490 avancer_fichier_with_syno(fich,field_tag,field_tag_syno);
491 }
492 // end of the backward compatibility
493 else
494 avancer_fichier(fich,field_tag);
495 }
496 int ret = inconnue().reprendre(fich);
497 for (int i = 0; i < les_sources.size(); i++)
498 ret = ret && les_sources(i)->reprendre(fich);
499 return ret;
500}
501
502/*! @brief Create a synonym of a field name in order to ensure backward compatibility with old names of the PolyMAC discretisation family
503 *
504 * @param field_tag
505 * @return synonym of the field tag
506 */
508{
509 Nom field_tag_syno=field_tag;
510 auto create_syno= [field_tag](std::string pattern, std::string replace)
511 {
512 std::string s = field_tag.getString();
513 std::size_t pos = s.find(pattern);
514 while (pos != std::string::npos)
515 {
516 s.replace(pos, pattern.length(), replace);
517 pos = s.find(pattern, pos + replace.length());
518 }
519 return Nom(s);
520 };
521
522 if (probleme().discretisation().is_PolyMAC_CDO())
523 field_tag_syno=create_syno("PolyMAC_CDO","PolyMAC");
524 else if (probleme().discretisation().is_PolyMAC_MPFA())
525 field_tag_syno=create_syno("PolyMAC_MPFA","PolyMAC_P0");
526 else if (probleme().discretisation().is_PolyMAC_HFV())
527 field_tag_syno=create_syno("PolyMAC_HFV","PolyMAC_P0P1NC");
528 return field_tag_syno;
529}
530/*! @brief Demande au schema en temps si il faut effectuer une impression.
531 *
532 * Renvoie 1 si il faut effectuer une impression.
533 * Appel simple a Schema_Temps_base::limpr()
534 *
535 * @return (int) 1 si il faut effectuer une impression, 0 sinon.
536 */
538{
539 return le_schema_en_temps->limpr();
540}
541
542/*! @brief Imprime les operateurs de l'equation sur un flot de sortie, de facon inconditionnelle.
543 *
544 * appelle Operateur_base::impr(os)
545 *
546 * @param (Sortie& os) le flot de sortie
547 * @return (int) renvoie toujours 1
548 */
550{
551 for(int i=0; i<nombre_d_operateurs(); i++)
552 operateur(i).impr(os);
553 //if (je_suis_maitre() && les_sources.size()>0) os << finl << "Impression des termes sources pour l'equation " << que_suis_je() << " : " << finl;
554 les_sources.impr(os);
555 return 1;
556}
557
558/*! @brief Imprime les operateurs de l'equation si le schema en temps indique que c'est necessaire.
559 *
560 * [SI limpr() ALORS impr(os)]
561 *
562 * @param (Sortie& os) le flot de sortie
563 */
565{
566 xyz_field_values_file_.write_fields();
567 if (limpr() )
568 impr(os);
569}
570
571/*! @brief Returns the time derivative of the unknown I of the equation: dI/dt = M-1*(sum(operators(I) + sources))
572 *
573 * In : derivee contains I (but immediatly set to 0)
574 * Out: derivee contains dI/dt
575 *
576 */
577DoubleTab& Equation_base::derivee_en_temps_inco(DoubleTab& derivee)
578{
579 derivee = 0.;
580
581 DoubleTrav secmem(derivee);
582 // secmem = sum(operators) + sources + equation specific terms
583
584
585 derivee_en_temps_inco_sources(secmem);
586 const double time_factor = get_time_factor();
587
588 bool calcul_explicite = false;
589 if (parametre_equation_ && sub_type(Parametre_implicite, parametre_equation_.valeur()))
590 {
591 Parametre_implicite& param2 = ref_cast(Parametre_implicite, parametre_equation_.valeur());
592 calcul_explicite = param2.calcul_explicite();
593 }
594
595 if (schema_temps().diffusion_implicite() && !calcul_explicite)
596 {
597 // Add convection operator only if equation has one
598 derivee=inconnue().valeurs();
599 if (nombre_d_operateurs()>1)
600 {
601 derivee_en_temps_conv(secmem, derivee);
603 {
604 secmem *= time_factor;
605 }
606 }
607 }
608 else
609 {
610 verify_scheme();
611
612 // Add all explicit operators
613 for(int i=0; i<nombre_d_operateurs(); i++)
614 if(operateur(i).l_op_base().get_decal_temps()!=1)
615 {
617 {
618 DoubleTrav secmem_tmp(secmem);
619 operateur(i).ajouter(secmem_tmp);
620 if (i == 1) secmem_tmp *= time_factor;
621 secmem += secmem_tmp;
622 }
623 else
624 {
625 operateur(i).ajouter(secmem);
626 }
627 }
628 }
629 les_sources.ajouter(secmem);
631 {
632 // Store dI/dt(n) = M-1 secmem :
633 derivee_en_temps().valeurs()=secmem;
634 solveur_masse->appliquer(derivee_en_temps().valeurs());
635 schema_temps().modifier_second_membre((*this),secmem); // Change secmem for some schemes (eg: Adams_Bashforth)
636 }
637
638 corriger_derivee_expl(secmem); // Add specific term for an equation (eg: -gradP for Navier Stokes)
639
640 if (implicite_==0)
641 {
642 solveur_masse->appliquer(secmem); // M-1 * secmem
643 if (schema_temps().diffusion_implicite() && !calcul_explicite)
644 {
645 // Solve: (1/dt + M-1*A)*dI = M-1 * secmem
646 // where A is the diffusion
648 }
649 else
650 {
651 derivee = secmem;
652 derivee.echange_espace_virtuel();
653 }
654 corriger_derivee_impl(derivee); // Solve specific implicit term for an equation (eg: pressure for Navier Stokes)
655
656 }
657 else if (implicite_>0)
658 {
659 // TRUST support notices that this part has never been covered...
660 //implicite
661 // M dU/dt + AU* = f -BUn;
662 // U* = Un+dt dU/dt
663 // (M/dt + A) U* = f -BUn + M/dt Un
664 //
665 double dt=schema_temps().pas_de_temps();
666 for(int i=0; i<nombre_d_operateurs(); i++)
667 {
668 //boucle sur les operateurs
670 if(!op.get_matrice())
671 op.set_matrice().typer("Matrice_Morse");
672 if(op.get_decal_temps()==1)
673 {
674 //if (op.set_matrice()->nb_lignes()<2)
675 {
676 Matrice_Morse& matrice=ref_cast(Matrice_Morse,op.set_matrice().valeur());
677 op.dimensionner(matrice);
679 }
680 if(!sys_invariant_)
681 {
682 Matrice_Morse& matrice=ref_cast(Matrice_Morse, op.set_matrice().valeur());
683 op.contribuer_a_avec(inconnue().valeurs(), matrice);
684 solv_masse().ajouter_masse(dt, op.set_matrice().valeur());
685
686 if(
687 (op.get_solveur()->que_suis_je()=="Solv_Cholesky")
688 ||
689 (op.get_solveur()->que_suis_je()=="Solv_GCP")
690 )
691 {
692 Matrice_Morse_Sym new_mat(matrice);
693 new_mat.set_est_definie(1);
694 op.set_matrice()=new_mat;
695 ref_cast_non_const(SolveurSys,op.get_solveur())->reinit();
696 }
697 }
698 }
699 }
700 if(implicite_==1)
701 {
702 // Un seul operateur implicite.
703 // On suppose que c'est le premier (la diffusion !!)
705 Matrice_Base& matrice=op.set_matrice().valeur();
706 // DoubleTrav secmem(derivee);
707 secmem=derivee;
708 solv_masse().ajouter_masse(dt, secmem, inconnue().valeurs());
709 op.contribuer_au_second_membre(secmem );
710 op.set_solveur().resoudre_systeme(matrice,
711 secmem,
712 derivee
713 );
714 solv_masse().corriger_solution(derivee,inconnue().valeurs());
715
716 derivee-=inconnue().valeurs();
717 derivee/=dt;
718
719 //Sert uniquement a calculer les flux sur les bords quand la diffusion est implicitee !
720 DoubleTab resu;
721 resu=derivee;
722 operateur(0).calculer(inconnue().valeurs(), resu);
723 }
724 else
725 {
726 // plusieurs operateurs implicites ...
727 Cerr << "Must be coded ... " << finl;
728 exit();
729 }
730 }
731 else
732 {
733 Cerr << "Error in Equation_base::derivee_en_temps_inco" << finl;
734 Cerr << "implicite_ = " << implicite_ << " has not been initialized!" << finl;
735 Cerr << "May be " << que_suis_je() << "::completer() method doesn't call Equation_base::completer()" << finl;
736 Cerr << "Contact TRUST support." << finl;
738 }
739
740 return derivee;
741}
742
743/*! @brief Renvoie le probleme associe a l'equation.
744 *
745 * @return (Probleme_base&) le probleme associe a l'equation
746 */
748{
749 return mon_probleme.valeur();
750}
751
752/*! @brief Renvoie le probleme associe a l'equation.
753 *
754 * (version const)
755 *
756 * @return (Probleme_base&) le probleme associe a l'equation
757 */
759{
760 return mon_probleme.valeur();
761}
762
763/*! @brief Methode appelee lorsqu'on cree l'instance de l'objet dans le jeu de donnees (Interprete::ajouter)
764 *
765 */
766void Equation_base::nommer(const Nom& un_nom)
767{
768 nom_ = un_nom;
769}
770
771/*! @brief S'associe au Probleme passe en parametre.
772 *
773 * Associe egalement les sources, les operateurs et le solveur
774 * de masse a l'equation.
775 *
776 * @param (Probleme_base& pb) le probleme auquel l'equation doit s'associer
777 */
779{
780 mon_probleme=pb;
781 // Modif B. Mathieu : pour le front_tracking, le nom de l'equation
782 // est donne dans le jeu de donnees lors de l'instanciation de l'objet
783 // (la methode "nommer" est appelee a ce moment).
784 // Si l'equation n'est pas instanciee, le nom est vide, on donne
785 // le nom par defaut qui est defini ci-dessous :
786 Nom nom_vide;
787 if (nom_ == nom_vide)
788 {
789 nom_ = pb.le_nom();
790 nom_ += que_suis_je();
791 }
792 // fin modif B.M.
793 les_sources.associer_eqn(*this);
794 int nb_op = nombre_d_operateurs();
795 for(int i=0; i<nb_op; i++)
796 operateur(i).associer_eqn(*this);
797
798}
799
800/*! @brief Discretise l'equation.
801 *
802 * Type le domaine_Cl_dis, la formatte, l'associe a l'equation.
803 * Type le solveur masse, lui associe le domaine discretise et
804 * le domaine des conditions aux limites discretisees.
805 *
806 */
808{
809 Cerr << "Discretizing of the boundary conditions... ";
810 le_dom_Cl_dis.typer(discretisation().domaine_cl_dis_type());
811 le_dom_Cl_dis->associer(domaine_dis());
812 Cerr << " OK " << finl;
813
814 le_dom_Cl_dis->associer_eqn(*this);
815 le_dom_Cl_dis->associer_inconnue(inconnue());
816
817 /*
818 * XXX : Elie Saikali : pour typer correctement le solveur_masse ...
819 */
820 Nom typ = discretisation().get_name_of_type_for("Solveur_Masse", "??" /* rien */, *this);
821 solveur_masse.typer(typ);
822 solveur_masse->associer_eqn(*this);
823 solveur_masse->associer_domaine_dis_base(domaine_dis());
824 solveur_masse->associer_domaine_cl_dis_base(le_dom_Cl_dis.valeur());
825
827 {
828 Motcle directive("temperature");
829 if (inconnue().is_vectorial())
830 directive="vitesse";
831
832 Nom nom("derivee_en_temps_");
833 nom += inconnue().le_nom();
834
835 Nom unite(inconnue().unites()[0]);
836 unite += "/s";
837
838 discretisation().discretiser_champ(directive,domaine_dis(),nom,unite,
839 inconnue().nb_comp(),
840 schema_temps().nb_valeurs_temporelles(),
841 schema_temps().temps_courant(),derivee_en_temps_);
842
843 champs_compris_.ajoute_champ(derivee_en_temps_);
844 }
845}
850
851/*! @brief S'associe au schema_en_temps.
852 *
853 * @param (Schema_Temps_base& un_schema_en_temps) le schema en temps a associer a l'equation
854 */
856{
857 le_schema_en_temps=un_schema_en_temps;
858}
859
860/*! @brief Renvoie le schema en temps associe a l'equation.
861 *
862 * @return (Schema_Temps_base&) le schema en temps associe a l'equation
863 * @throws pas de schema en temps associe a l'equation
864 */
866{
867 if(!le_schema_en_temps)
868 {
869 Cerr << "Error : " << que_suis_je()
870 << "has not been associated to a time scheme " << finl;
871 exit();
872 }
873 return le_schema_en_temps.valeur();
874}
875
876/*! @brief Renvoie le schema en temps associe a l'equation.
877 *
878 * @return (Schema_Temps_base&) le schema en temps associe a l'equation
879 * @throws pas de schema en temps associe a l'equation
880 */
882{
883 if(!le_schema_en_temps)
884 {
885 Cerr << "Error : " << que_suis_je()
886 << "has not been associated to a time scheme " << finl;
887 exit();
888 }
889 return le_schema_en_temps.valeur();
890}
891
892/*! @brief Associe le domaine discretise a l'equation.
893 *
894 * @param (Domaine_dis_base& z) le domaine discretise a associer
895 */
897{
898 le_dom_dis=z;
899}
900
901/*! @brief La valeur de l'inconnue sur le pas de temps a ete calculee.
902 *
903 * Cette methode avance le present jusqu'au temps passe en parametre.
904 * Elle met aussi a jour les proprietes du milieu.
905 *
906 * @param (double temps) le pas de temps de mise a jour
907 */
909{
910 // On tourne la roue de l'inconnue
911 // Update the unknown:
912 inconnue().mettre_a_jour(temps);
914
915 les_sources.mettre_a_jour(temps);
916
917 // On tourne la roue des CLs
918 // Update the boundary condition:
919 if (temps > schema_temps().temps_courant()) domaine_Cl_dis().avancer(temps);
920}
921
922//mise a jour de champ_conserve / champ_convecte : appele par Probleme_base::mettre_a_jour() apres avoir mis a jour le milieu
924{
925 if (reset && champ_conserve_) champ_conserve_->reset_champ_calcule(); //force le calcul de toutes les cases
926 if (reset && champ_convecte_) champ_convecte_->reset_champ_calcule();
927 if (champ_conserve_) champ_conserve_->mettre_a_jour(temps);
928 if (champ_convecte_) champ_convecte_->mettre_a_jour(temps);
929}
930
931/*! @brief Reinitialiser ce qui doit l'etre.
932 *
933 * Cette methode est appelee lorsqu'un pas de temps est abandonne,
934 * par exemple parce que le calcul a diverge.
935 * Il faut donc nettoyer ce qui pourrait polluer la nouvelle resolution.
936 *
937 * @throws WrongContext
938 */
940{
941 for (int i=0; i<nombre_d_operateurs(); i++)
944 if (champ_conserve_) champ_conserve_->abortTimeStep();
945 if (champ_convecte_) champ_convecte_->abortTimeStep();
946}
947
948/*! @brief Reset current time of the equation. Used from ICoCo.
949 * See documentation of Problem_base::resetTime()
950 */
952{
953 if(solveur_masse) solveur_masse->resetTime(time);
954 les_sources.resetTime(time);
955 le_dom_Cl_dis->resetTime(time);
956 for (int i=0; i<nombre_d_operateurs(); i++)
957 operateur(i).l_op_base().resetTime(time);
958 inconnue().resetTime(time);
959 if (champ_conserve_) champ_conserve_->resetTime(time);
960 if (champ_convecte_) champ_convecte_->resetTime(time);
961}
962
963
964/*! @brief methode virtuelle permettant de corriger l'onconnue lors d'iterations implicites par exemple K-eps doivent rester positifs
965 *
966 * les fractions massqiues entre 0 et 1
967 *
968 */
972
973/*! @brief Tout ce qui ne depend pas des autres problemes eventuels.
974 *
975 * @return (int) renvoie toujours 1
976 */
978{
979 solveur_masse->preparer_calcul();
980 int nb_op=nombre_d_operateurs();
981 for(int i=0; i<nb_op; i++)
982 {
984 dt_op_bak.add(0.);
985 }
987 double temps=schema_temps().temps_courant();
989 inconnue().changer_temps(temps);
991 le_dom_Cl_dis->initialiser(temps);
992
993 Nom msg=que_suis_je();
994 msg+=" dans Equation_base::preparer_calcul 1";
996
997 les_sources.initialiser(temps);
1000
1001 /* initialisation de parametre_equation() par le schema en temps si celui-ci le permet */
1002 if (sub_type(Schema_Implicite_base, schema_temps()))
1003 ref_cast(Schema_Implicite_base, schema_temps()).solveur()->get_and_set_parametre_equation(*this);
1004
1005 msg=que_suis_je();
1006 msg+=" dans Equation_base::preparer_calcul ";
1007 Debog::verifier(msg ,inconnue());
1008
1009 return 1;
1010}
1011
1012
1013/*! @brief Allocation et initialisation de l'inconnue et des CLs jusqu'a present+dt.
1014 *
1015 * + autres initialisations pour les calculs sur le prochain
1016 * pas de temps : operateurs, solveur_masse->
1017 *
1018 * @return (0 en cas d'erreur, 1 sinon)
1019 */
1021{
1023 double temps_present=sch.temps_courant();
1024
1025 // Le pas de temps doit etre celui du schema !!
1026 assert(sch.pas_de_temps()==dt);
1027
1028 // Pour chaque temps futur
1029 for (int i=1; i<=sch.nb_valeurs_futures(); i++)
1030 {
1031 double tps=sch.temps_futur(i);
1032 // Mise a jour du temps dans l'inconnue
1034 if (champ_conserve_) champ_conserve_->changer_temps_futur(tps,i);
1035 if (champ_convecte_) champ_convecte_->changer_temps_futur(tps,i);
1037
1038 inconnue().futur(i)=inconnue().valeurs();
1039 if (champ_conserve_) champ_conserve_->futur(i) = champ_conserve().valeurs();
1040 if (champ_convecte_) champ_convecte_->futur(i) = champ_convecte().valeurs();
1042
1043 // Mise a jour du temps dans les CL
1045 }
1046
1047 // Mise a jour du temps par defaut des CLs
1049
1050 // Mise a jour des operateurs
1051 for(int i=0; i<nombre_d_operateurs(); i++)
1052 operateur(i).mettre_a_jour(temps_present);
1053
1054 // Mise a jour du solveur masse au temps present
1055 if (solveur_masse)
1056 solveur_masse->mettre_a_jour(temps_present);
1057
1058 return true;
1059}
1060
1062{
1064 double temps_present=sch.temps_courant();
1065 double temps_futur=temps_present+sch.pas_de_temps();
1066
1067 // Pour chaque temps futur
1068 for (int i=1; i<=sch.nb_valeurs_futures(); i++)
1069 {
1070 double tps=sch.temps_futur(i);
1071 // Calcul des CLs a ce temps.
1073 }
1074 // Calcul du taux d'accroissement des CLs entre les temps present et futur.
1075 domaine_Cl_dis().calculer_derivee_en_temps(temps_present,temps_futur);
1076
1077 //MaJ des operateurs
1078 for (int i = 0; i < nombre_d_operateurs(); i++)
1079 if (operateur(i).op_non_nul())
1080 operateur(i).l_op_base().mettre_a_jour(temps_present);
1081
1082 // Mise a jour des sources au temps present
1083 les_sources.mettre_a_jour(temps_present);
1084
1085 return true;
1086}
1087
1088/*! @brief Renvoie la discretisation associee a l'equation.
1089 *
1090 * @return (Discretisation_base&) a discretisation associee a l'equation
1091 * @throws pas de probleme associe
1092 */
1094{
1095 if(!mon_probleme)
1096 {
1097 Cerr << "Error : " << que_suis_je() << " has not been associated to a problem ! " << finl;
1098 exit();
1099 }
1100 return mon_probleme->discretisation();
1101}
1102
1104{
1105 const Equation_base& me_const = (*this); // pour recuperer une equation const !!!!!
1106 const Nom& nom_inco = me_const.inconnue().le_nom();
1107 Nom inco(nom_inco);
1108 inco += "_residu";
1109 if (motlu == Motcle(inco))
1110 if (!field_residu_)
1111 {
1112 discretisation().residu(domaine_dis(), inconnue(), field_residu_);
1113 champs_compris_.ajoute_champ(field_residu_);
1114 }
1115
1116 for (int i = 0; i < nombre_d_operateurs(); i++)
1117 if (operateur(i).op_non_nul())
1118 operateur(i).l_op_base().creer_champ(motlu);
1119
1120 for (auto &itr : les_sources)
1121 if (itr)
1122 itr->creer_champ(motlu);
1123}
1124
1125bool Equation_base::has_champ(const Motcle& nom, OBS_PTR(Champ_base) &ref_champ) const
1126{
1127 Nom inco_residu(inconnue().le_nom());
1128 inco_residu += "_residu";
1129
1130 if (nom == Motcle(inco_residu))
1131 {
1132 ref_champ = Equation_base::get_champ(nom);
1133 return true;
1134 }
1135
1136 for (const auto &itr : list_champ_combi)
1137 if (itr->le_nom() == nom)
1138 {
1139 ref_champ = Equation_base::get_champ(nom);
1140 return true;
1141 }
1142
1143 if (champs_compris_.has_champ(nom, ref_champ))
1144 return true;
1145
1146 if (milieu().has_champ(nom, ref_champ))
1147 return true;
1148
1149 for (int i = 0; i < nombre_d_operateurs(); i++)
1150 if (operateur(i).op_non_nul())
1151 if (operateur(i).l_op_base().has_champ(nom, ref_champ))
1152 return true;
1153
1154 for (const auto &itr : les_sources)
1155 if (itr)
1156 if (itr->has_champ(nom, ref_champ))
1157 return true;
1158
1159 return false; /* rien trouve */
1160}
1161
1162bool Equation_base::has_champ(const Motcle& nom) const
1163{
1164 Nom inco_residu(inconnue().le_nom());
1165 inco_residu += "_residu";
1166
1167 if (nom == Motcle(inco_residu))
1168 return true;
1169
1170 for (const auto &itr : list_champ_combi)
1171 if (itr->le_nom() == nom)
1172 return true;
1173
1174 if (champs_compris_.has_champ(nom))
1175 return true;
1176
1177 if (milieu().has_champ(nom))
1178 return true;
1179
1180 for (int i = 0; i < nombre_d_operateurs(); i++)
1181 if (operateur(i).op_non_nul())
1182 if (operateur(i).l_op_base().has_champ(nom))
1183 return true;
1184
1185 for (const auto &itr : les_sources)
1186 if (itr)
1187 if (itr->has_champ(nom))
1188 return true;
1189
1190 return false; /* rien trouve */
1191}
1192
1194{
1195 Nom inco_residu(inconnue().le_nom());
1196 inco_residu += "_residu";
1197 if (nom == Motcle(inco_residu))
1198 {
1199 Champ_Fonc_base& ch = ref_cast_non_const(Champ_Fonc_base, field_residu_.valeur());
1200 double temps_init = schema_temps().temps_init();
1201 if (((ch.temps() != inconnue().temps()) || (ch.temps() == temps_init)) && (inconnue().mon_equation_non_nul()))
1202 ch.mettre_a_jour(inconnue().temps());
1203 }
1204
1205 for (const auto &itr : list_champ_combi)
1206 if (itr->le_nom() == nom && itr->temps() != inconnue().temps())
1207 ref_cast_non_const(Champ_Fonc_base,itr.valeur()).mettre_a_jour(inconnue().temps());
1208
1209 OBS_PTR(Champ_base) ref_champ;
1210
1211 if (champs_compris_.has_champ(nom, ref_champ))
1212 return ref_champ;
1213
1214 if (milieu().has_champ(nom, ref_champ))
1215 return ref_champ;
1216
1217 for (int i = 0; i < nombre_d_operateurs(); i++)
1218 if (operateur(i).op_non_nul())
1219 if (operateur(i).l_op_base().has_champ(nom, ref_champ))
1220 return ref_champ;
1221
1222 for (const auto &itr : les_sources)
1223 if (itr)
1224 if (itr->has_champ(nom, ref_champ))
1225 return ref_champ;
1226
1227 throw std::runtime_error(std::string("Field ") + nom.getString() + std::string(" not found !"));
1228}
1229
1231{
1232 if (opt == DESCRIPTION)
1233 Cerr << que_suis_je() << " : " << champs_compris_.liste_noms_compris() << finl;
1234 else
1235 noms.add(champs_compris_.liste_noms_compris());
1236
1238 for (int i = 0; i < nombre_d_operateurs(); i++)
1239 if (operateur(i).op_non_nul())
1241
1242 for (const auto &itr : les_sources)
1243 if (itr)
1244 itr->get_noms_champs_postraitables(noms, opt);
1245}
1246
1247/*! @brief Calcul du prochain pas de temps.
1248 *
1249 * Renvoie l'inverse de la somme des inverses des
1250 * pas de temps calcules par les operateurs.
1251 * Ces pas de temps sont ceux pour le schema d'Euler explicite.
1252 * Le pas de temps n'est pas majore par dt_max, ceci est fait dans corriger_dt_calcule
1253 *
1254 * @return (double) inverse de la somme des inverses des pas de temps calcules par les operateurs
1255 */
1257{
1258 double dt = 0;
1259 int nb_op = nombre_d_operateurs();
1260 const Schema_Temps_base& sch = le_schema_en_temps.valeur();
1261 bool cfl_based = sub_type(Schema_Euler_Implicite, sch) && ref_cast(Schema_Euler_Implicite, sch).facsec_cfl();
1262 for(int i=0; i<nb_op; i++)
1263 {
1264 const Operateur_base& op=operateur(i).l_op_base();
1265 bool diff_impl = sub_type(Operateur_Diff_base,op) && (sch.diffusion_implicite() || cfl_based);
1266 double dt_op = op.get_decal_temps()==1 ? DMAXFLOAT : operateur(i).calculer_pas_de_temps();
1267 Debog::verifier("Equation_base::calculer_pas_de_temps dt ",dt);
1268 if (dt_op>0 && !diff_impl)
1269 {
1270 // Une demie-moyenne harmonique est justifiee par le fait que diffusion et convection sont deux phenonomenes qui se cumulent
1271 // L'information a chaque pas de temps ne peut traverser plus d'une maille de calcul donc dt*U + dt*vitesse_diffusion(~alpha/dx) < dx
1272 // donc dt < dx/(U+alpha/dx) = 1/(1/(dx/U)+1/(dx^2/alpha)) : c'est bien une demie moyenne harmonique...
1273 dt = dt + 1./dt_op;
1274 }
1275 if (sch.limpr())
1276 {
1277 if (i == 0) Cout << " " << finl << "Printing of the next provisional time steps for the equation: " << que_suis_je() << finl;
1278 if (sub_type(Operateur_Conv_base,op))
1279 Cout << " convective";
1280 else if (sub_type(Operateur_Diff_base,op))
1281 Cout << " diffusive";
1282 else
1283 Cout << " operator ";
1284 Cout<<" time step : "<< dt_op_bak[i] << finl;
1285 }
1286 dt_op_bak[i]=dt_op;
1287 }
1288 if (dt==0.)
1289 dt = DMAXFLOAT;
1290 else
1291 dt = 1./dt;
1292
1293 // Cas implicite
1294 if (sub_type(Schema_Euler_Implicite,sch) && nb_op>1)
1295 {
1296 if (cfl_based)
1297 // Cas vitesse initiale nulle par exemple (dt=DMAFLOAT), on utilise le pas de temps de diffusion pour demarrer le calcul:
1298 if (dt>1e10) dt = dt_op_bak[0];
1299 }
1300 // Cas diffusion implicite et plusieurs operateurs:
1301 if (sub_type(Schema_Euler_explicite,sch) && nb_op>1)
1302 {
1303 if (sch.diffusion_implicite())
1304 {
1305 // Cas vitesse initiale nulle par exemple (dt=DMAFLOAT), on utilise le pas de temps de diffusion pour demarrer le calcul:
1306 if (dt>1e10) dt = dt_op_bak[0];
1307 }
1308 else
1309 {
1310 // Warning sur les premiers pas de temps si l'implicitation de la diffusion
1311 // dans un schema explicite vaut le coup (dt_diff<<min(dt_max,dt_conv))
1312 // On fait le test apres les 10 premiers pas de temps en cas de demarrage avec vitesse nulle
1313 int nw = 100;
1314 if (sch.nb_pas_dt() > 10 && sch.nb_pas_dt() < nw && sch.limpr())
1315 if (dt_op_bak[0] < 0.01 * std::min(sch.pas_temps_max(), dt_op_bak[1]))
1316 {
1317 Cerr << finl << "**** Advice (printed only on the first " << nw << " time steps) ****" << finl;
1318 Cerr << "You could use diffusion_implicite option into the Euler scheme to increase" << finl;
1319 Cerr << "the stability time step of the " << this->que_suis_je() << " equation by impliciting the diffusive operator." << finl;
1320 }
1321 }
1322 }
1323 Debog::verifier("Equation_base::calculer_pas_de_temps dt ",dt);
1324 return dt;
1325}
1326
1327// Calculation of local time: Vect of size number of faces of the domain
1328// Calculate whether the "steady" option is used in the "Euler implicit"
1329// The local time step is a convection temp step
1331{
1332 int nb_op=nombre_d_operateurs();
1333 for(int i=0; i<nb_op; i++)
1334 {
1335 const Operateur_base& op=operateur(i).l_op_base();
1336 if (sub_type(Operateur_Conv_base,op))
1337 {
1338 if(sub_type(Op_Conv_negligeable, op))
1339 {
1340 Cerr<<"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"<<finl;
1341 Cerr<<"STEADY option is not compatible with the 'CONVECTION { NEGLIGEABLE }' model!"<<finl;
1342 Cerr << "Please, contact TRUST support." << finl;
1343 Cerr<<"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"<<finl;
1344 exit();
1345 }
1346 else
1348
1349 }
1350 }
1351
1352}
1353
1354/*! @brief Verifie la compatibilite des conditions limites avec l'equation.
1355 *
1356 * voir Conds_lim::compatible_avec_eqn().
1357 *
1358 * @return (int)
1359 */
1361{
1362 const Conds_lim& les_cl=le_dom_Cl_dis->les_conditions_limites();
1363 les_cl.compatible_avec_eqn(*this);
1364 return les_cl.compatible_avec_discr(discretisation());
1365}
1366
1367/*! @brief Renvoie "indetermine" Navier_Stokes_standard par exemple surcharge cette methode
1368 *
1369 * pour renvoyer "Hydraulique"
1370 *
1371 * @return (Motcle&) le nom du domaine d'aplication
1372 */
1374{
1375 static Motcle defaut="indetermine";
1376 return defaut;
1377}
1378
1379/*! @brief Verification du nombre de composantes lues pour la specification d un champ.
1380 *
1381 * Actuellement utilise pour la lecture d un condition initiale ou limite.
1382 *
1383 * @param (ch_ref : un champ inconnu de l equation consideree)
1384 */
1385void Equation_base::verifie_ch_init_nb_comp(const Champ_Inc_base& ch_ref, const int nb_comp) const
1386{
1387 const Nature_du_champ nature = ch_ref.nature_du_champ();
1388 const int nb_composantes = ch_ref.nb_comp();
1389 const Nom& nom = ch_ref.le_nom();
1390
1391 if (nature==scalaire)
1392 {
1393 if (nb_comp!=1)
1394 {
1395 Cerr<<"The nature of the field "<<nom<<" unknown to the equation name "<<le_nom()<<" is scalar."<<finl;
1396 Cerr<<"The number of components readed for this field "<<nb_comp<<" is not compatible with its nature."<<finl;
1397 Cerr<<"We must read only one component for this field."<<finl;
1398 exit();
1399 }
1400 }
1401 else if (nature==quadrature_scalaire)
1402 {
1403 //DG size depends on the geometry
1404 }
1405 else if (nature==vectoriel)
1406 {
1407 if (nb_comp!=Objet_U::dimension)
1408 {
1409 Cerr<<"The nature of the field "<<nom<<" unknown to the equation name "<<le_nom()<<" is vector."<<finl;
1410 Cerr<<"The number of components readed for this field "<<nb_comp<<" is not compatible with its nature."<<finl;
1411 Cerr<<"It should read "<<Objet_U::dimension<<" components for this field."<<finl;
1412 exit();
1413 }
1414 }
1415 else if (nature==quadrature_vectoriel)
1416 {
1417 //DG size depends on the geometry
1418 }
1419 else if (nature==multi_scalaire)
1420 {
1421 if (nb_comp!=nb_composantes)
1422 {
1423 Cerr<<"The nature of the field "<<nom<<" unknown to the equation name "<<le_nom()<<" is multiscalar."<<finl;
1424 Cerr<<"The number of components readed for this field "<<nb_comp<<" does not match the number expected."<<finl;
1425 Cerr<<"It should read "<<nb_composantes<<" components for this field."<<finl;
1426 exit();
1427 }
1428 }
1429 else if (nature==basis_function_order_1_scalar)
1430 {
1431 /* if (nb_comp!=3)
1432 {
1433 Cerr<<"The nature of the field "<<nom<<" unknown to the equation name "<<le_nom()<<" is a basis_function_order_1_scalar."<<finl;
1434 Cerr<<"The number of components readed for this field "<<nb_comp<<" does not match the number expected."<<finl;
1435 Cerr<<"It should read "<<3<<" components for this field."<<finl;
1436 exit();
1437 } */
1438 }
1439 else if (nature==basis_function_order_2_scalar)
1440 {
1441 /* if (nb_comp!=6)
1442 {
1443 Cerr<<"The nature of the field "<<nom<<" unknown to the equation name "<<le_nom()<<" is a basis_function_order_2_scalar."<<finl;
1444 Cerr<<"The number of components readed for this field "<<nb_comp<<" does not match the number expected."<<finl;
1445 Cerr<<"It should read "<<6<<" components for this field."<<finl;
1446 exit();
1447 } */
1448 }
1449 else if (nature==basis_function_order_1_vectorial)
1450 {
1451 /* if (nb_comp!=3*Objet_U::dimension)
1452 {
1453 Cerr<<"The nature of the field "<<nom<<" unknown to the equation name "<<le_nom()<<" is a basis_function_order_1_vectorial."<<finl;
1454 Cerr<<"The number of components readed for this field "<<nb_comp<<" does not match the number expected."<<finl;
1455 Cerr<<"It should read "<<3*Objet_U::dimension<<" components for this field."<<finl;
1456 exit();
1457 } */
1458 }
1459 else if (nature==basis_function_order_2_vectorial)
1460 {
1461 /* if (nb_comp!=6*Objet_U::dimension)
1462 {
1463 Cerr<<"The nature of the field "<<nom<<" unknown to the equation name "<<le_nom()<<" is a basis_function_order_2_vectorial."<<finl;
1464 Cerr<<"The number of components readed for this field "<<nb_comp<<" does not match the number expected."<<finl;
1465 Cerr<<"It should read "<<6*Objet_U::dimension<<" components for this field."<<finl;
1466 exit();
1467 } */
1468 }
1469 else
1470 {
1471 Cerr<<"The nature of the field is not recognized"<<finl;
1472 exit();
1473 }
1474}
1475
1476/*! @brief Add convection term In: solution is the unknown I
1477 *
1478 * Out: secmem is increased by convection(I)
1479 *
1480 */
1481DoubleTab& Equation_base::derivee_en_temps_conv(DoubleTab& secmem, const DoubleTab& solution)
1482{
1483 double dt = le_schema_en_temps->pas_de_temps();
1484 double dt_convection;
1485 if (le_schema_en_temps->no_conv_subiteration_diffusion_implicite())
1486 {
1487 // faux mais permet de ne pas sous iterer sur la convection
1488 dt_convection=1e38;
1489 }
1490 else
1491 dt_convection= operateur(1).calculer_pas_de_temps();
1492 if(inf_strict(dt_convection,dt))
1493 {
1494 // Several steps (nstep) are done if the convective time step
1495 // is smaller than the time step (dt) :
1496 double epsilon = 1.e-10;
1497 int nstep = (int)((dt / dt_convection)*(1+epsilon)) + 1 ;
1498 if (( nstep % 2 ) != 0 ) nstep += 1 ;
1499 double dt_loc = dt/double(nstep) ;
1500 Cout << "Convection Semi Implicite: Number of Sub-Cycles : " << nstep << " with dt_loc = " << dt_loc << " dt =" << dt << finl ;
1501
1502 secmem = 0;
1503 DoubleTrav solution_loc(solution);
1504 solution_loc = solution;
1505 DoubleTrav derivee;
1506 derivee.copy(secmem, RESIZE_OPTIONS::NOCOPY_NOINIT);
1507 for (int i=0; i<nstep; i++)
1508 {
1509 derivee = 0. ;
1510 operateur(1).ajouter(solution_loc, derivee); // derivee=conv(solution_loc)
1511 derivee.echange_espace_virtuel();
1512 secmem += derivee ;
1513
1514 // Si ce n'est pas la derniere iteration:
1515 if (i+1 < nstep)
1516 {
1517 solveur_masse->appliquer(derivee);
1518 solution_loc.ajoute(dt_loc, derivee, VECT_REAL_ITEMS);
1519 solution_loc.echange_espace_virtuel();
1520 }
1521 }
1522 secmem /= double(nstep) ;
1523 return secmem;
1524 }
1525 else
1526 {
1527 operateur(1).ajouter(solution, secmem); // secmem+=conv(solution)
1528 return secmem;
1529 }
1530}
1531
1532/*! @brief Solve: (1/dt + M-1*L)*dI = M-1 * secmem with a Conjugate Gradient matrix-free algorithm by default
1533 *
1534 * L is the diffusion
1535 * M is the mass
1536 * In : solution=I(n)
1537 * Out: solution=dI/dt
1538 *
1539 */
1540void Equation_base::Gradient_conjugue_diff_impl(DoubleTrav& secmem, DoubleTab& solution, int size_terme_mul, const DoubleTab& terme_mul)
1541{
1542 if (le_schema_en_temps->impr_diffusion_implicite())
1543 Cout << "Implicited diffusion algorithm applied on " << que_suis_je() << " equation:" << finl;
1544 int marq_tot = 0;
1545 int size_s = sources().size();
1546 ArrOfInt marq(size_s);
1547 for (int i = 0; i < size_s; i++)
1548 {
1549 if (sub_type(Source_dep_inco_base, sources()(i).valeur()))
1550 {
1551 marq[i] = 1;
1552 marq_tot = 1;
1553 }
1554 }
1555 bool has_diffusion_implicit_solver = parametre_equation() &&
1556 sub_type(Parametre_diffusion_implicite, parametre_equation().valeur()) &&
1557 ref_cast(Parametre_diffusion_implicite, parametre_equation().valeur()).solveur();
1558 if (has_diffusion_implicit_solver)
1559 {
1560 // PL: Solve (M/dt + L)*dI = Secmem(sans diffusion) with a matrix build to use more solvers
1561 if (marq_tot)
1562 {
1563 Cerr << "solveur_dffusion_implicite can't be used yet with source terms depending from the unknowns. " << finl;
1564 Process::exit();
1565 }
1566 if (size_terme_mul)
1567 {
1568 Cerr << "solveur_dffusion_implicite can't be used yet with penalization. " << finl;
1569 Process::exit();
1570 }
1571 statistics().begin_count(STD_COUNTERS::matrix_assembly,statistics().get_last_opened_counter_level()+1);
1572 // On multiplie secmem par M (qui etait divise par M avant l'appel...)
1573 {
1574 // Scope to release Trav quickly
1575 DoubleTrav copie(secmem);
1576 copie = secmem;
1577 secmem = 0;
1578 solveur_masse->ajouter_masse(1, secmem, copie);
1579 }
1580 // Build matrix A:
1581 Matrice_Morse& matrice = ref_cast(Parametre_diffusion_implicite, parametre_equation().valeur()).matrice();
1582 if (matrice.ordre()==0) dimensionner_matrice(matrice);
1583 matrice.clean(); // A=0
1584 // Add diffusion matrix L into matrix
1585 {
1586 DoubleTrav present(solution); // I(n)
1587 present = solution;
1588 operateur(0).l_op_base().contribuer_a_avec(present, matrice); // A=L
1589 statistics().end_count(STD_COUNTERS::matrix_assembly);
1590 operateur(0).ajouter(present, secmem);
1591 statistics().begin_count(STD_COUNTERS::matrix_assembly,statistics().get_last_opened_counter_level()+1);
1592 matrice.ajouter_multvect(present, secmem);
1593 // Add M/dt into matrix
1594 schema_temps().ajouter_inertie(matrice,secmem,(*this)); // A=M/dt+L
1595 modifier_pour_Cl(matrice,secmem);
1596 statistics().end_count(STD_COUNTERS::matrix_assembly);
1597 // Solve to get I(n+1):
1598 SolveurSys& solveur = ref_cast(Parametre_diffusion_implicite, parametre_equation().valeur()).solveur();
1599 solveur->reinit(); // New matrix but same sparsity
1600 int niter = solveur.resoudre_systeme(matrice, secmem, solution);
1601 Cout << "Diffusion operator implicited for the equation " << que_suis_je()
1602 << " : Conjugate gradient converged in " << niter << " iterations." << finl;
1603 // CHD 230501 : Call to diffusive operator to update flux_bords (boundary fluxes):
1604 operateur(0).ajouter(inconnue(), secmem);
1605
1606 solution-=present; // dI=I(n+1)-I(n)
1607 solution/=schema_temps().pas_de_temps(); // dI/dt
1608 }
1609 }
1610 else
1611 {
1612 statistics().begin_count(STD_COUNTERS::implicit_diffusion,statistics().get_last_opened_counter_level()+1);
1613 int n = secmem.size_totale();
1614 if (solution.size_totale() != n)
1615 {
1616 Cerr << "the size of the solution and the second member does not match";
1617 exit();
1618 }
1619
1620 // Le nombre maximal d'iteration peut etre desormais borne par niter_max_diff_impl
1621 int nmax = le_schema_en_temps->niter_max_diffusion_implicite();
1622
1623 double aCKN = 1; // Crank - Nicholson -> 0.5
1624
1625 // Calcul de la matrice Diagonale
1626
1627 int precond_diag = 0;
1628 // On preconditionne par la diagonale si on penalise
1629 // car sinon residu initial trop grand
1630 if (size_terme_mul) precond_diag = 1;
1631
1632 double seuil_diffusion_implicite = le_schema_en_temps->seuil_diffusion_implicite();
1633 // Recuperation eventuelle d'options de Parametre_diffusion_implicite
1634 if (parametre_equation() && (sub_type(Parametre_diffusion_implicite, parametre_equation().valeur())))
1635 {
1637 parametre_equation().valeur());
1638 if (param.crank())
1639 aCKN = 0.5;
1640 precond_diag = param.precoditionnement_diag();
1641 if (param.seuil_diffusion_implicite() > 0)
1642 seuil_diffusion_implicite = param.seuil_diffusion_implicite();
1643 if (param.nb_it_max() > 0)
1644 nmax = param.nb_it_max();
1645 }
1646 statistics().end_count(STD_COUNTERS::implicit_diffusion,0,0);
1647 /////////////////////
1648 // Preconditionnement
1649 /////////////////////
1650 double dt = le_schema_en_temps->pas_de_temps();
1651 if (precond_diag)
1652 {
1653 statistics().begin_count(STD_COUNTERS::matrix_assembly,statistics().get_last_opened_counter_level()+1);
1654 const int nb_case = inconnue().valeurs().dimension_tot(0);
1655 const int nb_comp = inconnue().valeurs().line_size();
1656 if (nb_comp * nb_case != n)
1657 {
1658 Cerr << "the size of the unknown and the second member does not match" << finl;
1659 Cerr << "dimension_tot nbdim1 nb_comp = " << nb_case << " " << nb_comp << finl;
1660 Cerr << "size_totale = " << n << finl;
1661 exit();
1662 }
1663 if (diag_.ordre()==1) diag_.dimensionne_diag(n);
1664 diag_.clean(); // Set to 0
1666 for (int i = 0; i < size_s; i++)
1667 if (marq[i])
1668 sources()(i)->contribuer_a_avec(inconnue().valeurs(), diag_);
1669 // La diagonale est proportionnelle au volume de controle....
1670 // Il faut appliquer le solveur_masse
1671 DoubleTrav tab_tempo(inconnue().valeurs());
1672 {
1673 Matrice_Morse_View matrice; // ToDo Kokkos CMatrice_Morse_View diag = diag_.view_ro();
1674 matrice.set(diag_);
1675 DoubleTabView tempo = tab_tempo.view_wo();
1676 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
1677 Kokkos::RangePolicy<>(0, nb_case), KOKKOS_LAMBDA(
1678 const int ca)
1679 {
1680 for (int ncp = 0; ncp < nb_comp; ncp++)
1681 tempo(ca, ncp) = matrice.diag(ca * nb_comp + ncp);
1682 });
1683 end_gpu_timer(__KERNEL_NAME__);
1684 }
1685 solveur_masse->appliquer(tab_tempo);
1686 tab_tempo.echange_espace_virtuel();
1687 {
1688 // On inverse... // Crank - Nicholson
1689 // La matrice correspond a - la jacobienne (pour avoir un plus justement, GF)
1690 CDoubleTabView tempo = tab_tempo.view_ro();
1691 CDoubleTabView terme_mul_v = terme_mul.view_ro();
1692 Matrice_Morse_View matrice; // ToDo Kokkos Matrice_Morse_View diag = diag_.view_rw();
1693 matrice.set(diag_);
1694 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
1695 Kokkos::RangePolicy<>(0, nb_case), KOKKOS_LAMBDA(
1696 const int ca)
1697 {
1698 double tmp = (size_terme_mul ? terme_mul_v(ca, 0) : 1) / dt;
1699 for (int ncpa = 0; ncpa < nb_comp; ncpa++)
1700 matrice.diag(ca * nb_comp + ncpa) = 1. / (tmp + tempo(ca, ncpa) * aCKN);
1701 });
1702 end_gpu_timer(__KERNEL_NAME__);
1703 }
1704 statistics().end_count(STD_COUNTERS::matrix_assembly);
1705 }
1706 // Lambda function to apply diffusive operator and source terms to avoid code repetition
1707 auto matvec = [&](const DoubleTab& input_field, DoubleTab& output_field)
1708 {
1709 // Stop the counter because operator diffusion is also counted
1710 statistics().end_count(STD_COUNTERS::implicit_diffusion,0,0);
1711 operateur(0).ajouter(input_field, output_field);
1712 if (marq_tot)
1713 {
1714 for (int i = 0; i < size_s; i++)
1715 if (marq[i])
1716 ref_cast(Source_dep_inco_base, sources()(i).valeur()).ajouter_(input_field, output_field);
1717 }
1718 statistics().begin_count(STD_COUNTERS::implicit_diffusion,statistics().get_last_opened_counter_level()+1);
1719 output_field*=-1;
1720 };
1721 statistics().begin_count(STD_COUNTERS::implicit_diffusion,statistics().get_last_opened_counter_level()+1);
1722 // On utilise p pour calculer phiB :
1723 DoubleTrav p(solution);
1724 DoubleTrav moins_phiB(solution); // la partie Bord de l'operateur avec p=0
1725 matvec(p, moins_phiB);
1726
1727 DoubleTrav resu(solution);
1728 matvec(solution, resu);
1729 solveur_masse->appliquer(resu);
1731 {
1732 // Create scope to release DoubleTrav quickly
1733 DoubleTrav sol;
1734 if (size_terme_mul)
1735 {
1736 sol = solution;
1737 ToDo_Kokkos("critical for IBC");
1738 //operator_multiply(sol, term_mul);
1739 // tab_multiply_any_shape(sol, terme_mul);
1740 for (int i = 0; i < size_terme_mul; i++)
1741 sol(i) *= terme_mul(i);
1742 }
1743 else
1744 sol.ref(solution);
1745
1746 // on retire les sources dependantes de l inco ; on les rajoutera apres
1747 if (marq_tot)
1748 {
1749 DoubleTrav sum_sources(secmem);
1750 statistics().end_count(STD_COUNTERS::implicit_diffusion,0,0);
1751 for (int i = 0; i < size_s; i++)
1752 if (marq[i])
1753 sources()(i).ajouter(sum_sources);
1754 statistics().begin_count(STD_COUNTERS::implicit_diffusion,statistics().get_last_opened_counter_level()+1);
1755 solv_masse().appliquer(sum_sources);
1756 secmem.ajoute(-1., sum_sources); // ,VECT_REAL_ITEMS);
1757 }
1758 secmem.ajoute(1. / dt, sol, VECT_REAL_ITEMS);
1759 resu.ajoute(1. / dt, sol, VECT_REAL_ITEMS);
1760 }
1761
1762 DoubleTrav residu; // residu = Ax
1763 residu = resu;
1764 residu -= secmem; // residu = Ax-B
1765 DoubleTrav z;
1766 if (precond_diag)
1767 {
1768 z = residu;
1769 diag_.multvect(residu, z); // z = D-1(Ax-B)
1770 }
1771 else
1772 z.ref(residu); // z = Ax-B
1773 p -= z;
1774
1775 double initial_residual = mp_carre_norme_vect(z); // =||Ax(0)-B|| ou ||D-1.(Ax(0)-B)||
1776 /* Calcul different de initial_residual:
1777 DoubleTab tmp(secmem);
1778 if (precond_diag)
1779 diag_.multvect(secmem, tmp);
1780 else
1781 tmp.ref(secmem);
1782 double initial_residual = mp_carre_norme_vect(tmp) ; // =||B|| ou ||D-1.B|| */
1783
1784 if (le_schema_en_temps->impr_diffusion_implicite()) Cout << "Residu(0)=" << initial_residual << finl;
1785 double seuil = seuil_diffusion_implicite * seuil_diffusion_implicite;
1786 // On calcule un seuil relatif (PL: 18/07/12, j'ai l'impression qu'il y'a une erreur, c'est seuil*=initial_residual;
1787 // En outre, il serait bon de faire residual = sqrt(mp_carre_norme_vect(tmp)) a plusieurs endroits...
1788 if (initial_residual > seuil)
1789 seuil = seuil_diffusion_implicite * initial_residual;
1790
1791 double residual = seuil;
1792 double prodrz_old = mp_prodscal(residu, z);
1793 DoubleTrav pp;
1794 if (size_terme_mul) pp=p;
1795 DoubleTrav merk;
1796 merk = solution;
1797 int niter = 0;
1798 if (initial_residual != 0)
1799 while (niter++ <= nmax)
1800 {
1801 resu = moins_phiB; // On retire la contribution des bords.
1803 matvec(p, resu);
1804 solveur_masse->appliquer(resu);
1805
1806 if (aCKN!=1) resu *= aCKN; // Crank - Nicholson
1807 if (size_terme_mul)
1808 {
1809 for (int i = 0; i < size_terme_mul; i++)
1810 pp(i) = p(i) * terme_mul(i);
1811 resu.ajoute(1. / dt, pp, VECT_REAL_ITEMS);
1812 }
1813 else
1814 resu.ajoute(1. / dt, p, VECT_REAL_ITEMS);
1815 double alfa = prodrz_old / mp_prodscal(resu, p);
1816 // Inutile de faire un echange espace virtuel:
1817 solution.ajoute(alfa, p, VECT_REAL_ITEMS);
1818 residu.ajoute(alfa, resu, VECT_REAL_ITEMS);
1819
1820 if (precond_diag)
1821 diag_.multvect(residu, z); // preconditionnement par diag^(-1)
1822 // sinon z=residu
1823
1824 // Optimization: combine 2 MPI reductions into 1
1825 residual = local_carre_norme_vect(z);
1826 double prodrz_new = local_prodscal(residu, z);
1827 Process::mp_sum_for_each(residual, prodrz_new);
1828 if (le_schema_en_temps->impr_diffusion_implicite())
1829 Cout << "Iteration n=" << niter << " Residu(n)/Residu(0)=" << residual / initial_residual << finl;
1830
1831 if (residual<seuil)
1832 break;
1833 else
1834 {
1835 p *= (prodrz_new / prodrz_old);
1836 p -= z;
1837 prodrz_old = prodrz_new;
1838 // On previent si convergence anormalement longue sur de tres gros cas
1839 if (niter == 100)
1840 {
1841 Cout
1842 << "Already 100 iterations of the conjugate gradient solver used for diffusion implicited algorithm."
1843 << finl;
1844 Cout
1845 << "The calculation is diverging, may be because of incorrect initial and/or boundary conditions for the equation "
1846 << que_suis_je() << finl;
1847 Cout
1848 << "You may also try to stop the calculation and rerun it with a lower facsec, say 0.9 or may be less: 0.5."
1849 << finl;
1850 }
1851 }
1852 }
1853 if ((le_schema_en_temps->no_error_if_not_converged_diffusion_implicite() == 0) && (niter > nmax))
1854 {
1855 Cerr << "No convergence of the implicited diffusion algorithm for the equation " << que_suis_je() << " in "
1856 << nmax << " iterations." << finl;
1857 Cerr << "Residue : " << residual << " Threshold : " << seuil << finl;
1858 Cerr << "======================================================================================" << finl;
1859 Cerr << "The problem is post processed to help you to see where the non convergence is located." << finl;
1861 probleme().postraiter(1);
1862 probleme().mettre_a_jour(schema_temps().temps_courant());
1863 probleme().finir();
1864 Cerr << "The problem " << probleme().le_nom() << " has been saved too." << finl;
1865 exit();
1866 }
1867 else
1868 Cout << "Diffusion operator implicited for the equation " << que_suis_je()
1869 << " : Conjugate gradient converged in " << niter << " iterations." << finl;
1870 solution -= merk;
1871 solution.echange_espace_virtuel();
1872
1873 // CHD 230501 : last call to update flux_bords (boundary fluxes):
1874 resu = 0.;
1875 matvec(inconnue().valeurs(), resu);
1876
1877 // Since 1.6.8 returns dI/dt:
1878 solution/=dt;
1879
1880 // End the counter
1881 statistics().end_count(STD_COUNTERS::implicit_diffusion);
1882 }
1883}
1884
1886{
1887 return d;
1888}
1890{
1891 return d;
1892}
1893
1894const RefObjU& Equation_base::get_modele(Type_modele type) const
1895{
1896 return liste_modeles_(0);
1897
1898}
1899// MODIF ELI LAUCOIN (22/11/2007) : je rajoute un avancer et un reculer
1900// par defaut, cela ne fait qu'avancer ou reculer l'inconnue (et champ_conserve_ si initialise)
1902{
1903 inconnue().avancer(i);
1904 if (champ_conserve_) champ_conserve_->avancer(i);
1905 if (champ_convecte_) champ_convecte_->avancer(i);
1906}
1907
1909{
1910 inconnue().reculer(i);
1911 if (champ_conserve_) champ_conserve_->reculer(i);
1912 if (champ_convecte_) champ_convecte_->reculer(i);
1913}
1914// FIN MODIF ELI LAUCOIN (22/11/2007)
1915
1916
1917#define BLOQUE Cerr<<__PRETTY_FUNCTION__<< " "<<__FILE__<<":"<<(int)__LINE__<<" not coded, retrieves coding simpler" <<finl;exit()
1918
1919// methodes pour l'implicite
1920
1921/* peut utiliser une memoization (discretisations PolyMAC_HFV)*/
1923{
1924 if (matrice_init)
1925 {
1926 matrice.get_set_tab1().ref_array(matrice_stockee.get_set_tab1());
1927 matrice.get_set_tab2().ref_array(matrice_stockee.get_set_tab2());
1928 matrice.get_set_coeff().ref_array(matrice_stockee.get_set_coeff());
1929 matrice.set_nb_columns(matrice_stockee.nb_colonnes());
1930 matrice.sorted_ = matrice_stockee.sorted_;
1931 matrice.constant_stencil() = matrice_stockee.constant_stencil();
1932 matrice.get_set_coeff() = 0.0;
1933 return;
1934 }
1935
1936 dimensionner_matrice_sans_mem(matrice); //le vrai appel
1937
1938 matrice.get_set_coeff() = 0.0; // just to be sure ...
1939
1940 if (probleme().discretisation().is_poly_family() || probleme().discretisation().is_vef())
1941 {
1942 // PL: ToDo why sorting leads to issue in VEF ???
1943 if (probleme().discretisation().is_poly_family())
1944 {
1945 matrice.sort_stencil();
1946 matrice_stockee.sorted_ = 1;
1947 }
1948 matrice.constant_stencil()=true; // stencil will not change anymore
1949 matrice_stockee.get_set_tab1().ref_array(matrice.get_set_tab1());
1950 matrice_stockee.get_set_tab2().ref_array(matrice.get_set_tab2());
1951 matrice_stockee.get_set_coeff().ref_array(matrice.get_set_coeff());
1952 matrice_stockee.set_nb_columns(matrice.nb_colonnes());
1953 matrice_stockee.constant_stencil()=matrice.constant_stencil();
1954 matrice_init = 1;
1955 }
1956}
1957
1959{
1960 // [ABN]: dimensioning of the implicit matrix: it can receive input from:
1961 // - the operators
1962 // - the mass solver
1963 // - the sources
1964 // We proceed in this order, with the idea that operators should take most of the slots in the Morse
1965 // structure. Having the mass solver first would lead (in VDF, EF and VEF) to diagonal slots
1966 // being reserved before sub-diagonal terms. In the Morse structure coefficients would then
1967 // not be ordered by increasing columns number. This is not desirable, notably for EF which seem to
1968 // be sensitive to this ordering (although they should not ....). Some Baltiks too (FLICA5 - thermic part)
1969 // rely on this.
1970 if (matrice_init) // memoization
1971 {
1972 matrice.get_set_tab1().ref_array(matrice_stockee.get_set_tab1());
1973 matrice.get_set_tab2().ref_array(matrice_stockee.get_set_tab2());
1974 matrice.get_set_coeff().ref_array(matrice_stockee.get_set_coeff());
1975 matrice.set_nb_columns(matrice_stockee.nb_colonnes());
1976 matrice.constant_stencil() = matrice_stockee.constant_stencil();
1977 return;
1978 }
1979
1980 bool isInit = false;
1981 // Operators first (they're likely to take most of the slots in the Morse structure)
1982 for(int opp=0; opp < nombre_d_operateurs(); opp++)
1983 {
1984 if (!isInit)
1985 operateur(opp).l_op_base().dimensionner(matrice);
1986 else
1987 {
1988 Matrice_Morse mat2;
1989 operateur(opp).l_op_base().dimensionner(mat2);
1990 if (mat2.nb_colonnes())
1991 matrice += mat2; // this only works if the matrix has been given its overall size first
1992 }
1993 isInit = isInit || (matrice.nb_colonnes() != 0);
1994
1995 }
1996
1997 // ... then the mass solver ...
1998 if (!isInit)
1999 solv_masse().dimensionner(matrice);
2000 else
2001 {
2002 Matrice_Morse mat2;
2003 solv_masse().dimensionner(mat2);
2004 matrice += mat2; // this only works if the matrix has been given its overall size first
2005 }
2006
2007 // and finally sources (mass solver has surely done something already so no need for "isInit" test)
2008 les_sources.dimensionner(matrice);
2009}
2010
2011void Equation_base::dimensionner_termes_croises(Matrice_Morse& matrice, const Probleme_base& autre_pb, int nl, int nc)
2012{
2013 matrice.dimensionner(nl, nc, 0);
2014 for(int i = 0; i < nombre_d_operateurs(); i++)
2015 {
2016 Matrice_Morse mat2;
2017 operateur(i).l_op_base().dimensionner_termes_croises(mat2, autre_pb, nl, nc);
2018 if (mat2.nb_colonnes()) matrice += mat2;
2019 }
2020}
2021
2022void Equation_base::ajouter_termes_croises(const DoubleTab& inco, const Probleme_base& autre_pb, const DoubleTab& autre_inco, DoubleTab& resu) const
2023{
2024 for (int i = 0; i < nombre_d_operateurs(); i++)
2025 operateur(i).l_op_base().ajouter_termes_croises(inco, autre_pb, autre_inco, resu);
2026}
2027
2028void Equation_base::contribuer_termes_croises(const DoubleTab& inco, const Probleme_base& autre_pb, const DoubleTab& autre_inco, Matrice_Morse& matrice) const
2029{
2030 for (int i = 0; i < nombre_d_operateurs(); i++)
2031 operateur(i).l_op_base().contribuer_termes_croises(inco, autre_pb, autre_inco, matrice);
2032}
2033
2034// ajoute les contributions des operateurs et des sources
2035void Equation_base::assembler(Matrice_Morse& matrice, const DoubleTab& inco, DoubleTab& resu)
2036{
2037 // Test de verification de la methode contribuer_a_avec
2038 for (int op=0; op<nombre_d_operateurs(); op++)
2039 operateur(op).l_op_base().tester_contribuer_a_avec(inco, matrice);
2040
2041 // Contribution des operateurs et des sources:
2042 // [Vol/dt+A]Inco(n+1)=somme(residu)+Vol/dt*Inco(n)
2043 // Typiquement: si Op=flux(Inco) alors la matrice implicite A contient une contribution -dflux/dInco
2044 // Exemple: Op flux convectif en VDF:
2045 // Op=T*u*S et A=-d(T*u*S)/dT=-u*S
2048 {
2049 // On calcule somme(residu) par contribuer_au_second_membre (typiquement CL non implicitees)
2050 // Cette approche necessite de coder 3 methodes (contribuer_a_avec, contribuer_au_second_membre et ajouter pour l'explicite)
2051 sources().contribuer_a_avec(inco,matrice);
2052 statistics().end_count(STD_COUNTERS::matrix_assembly,0,0);
2053 sources().ajouter(resu);
2054 statistics().begin_count(STD_COUNTERS::matrix_assembly,statistics().get_last_opened_counter_level()+1);
2055 matrice.ajouter_multvect(inco, resu); // Add source residual first
2056 for (int op = 0; op < nombre_d_operateurs(); op++)
2057 {
2058 operateur(op).l_op_base().contribuer_a_avec(inco, matrice);
2060 }
2061 }
2062 else if (type_codage==Discretisation_base::VIA_AJOUTER)
2063 {
2064 // On calcule somme(residu) par somme(operateur)+sources+A*Inco(n)
2065 // Cette approche necessite de coder seulement deux methodes (contribuer_a_avec et ajouter)
2066 // Donc un peu plus couteux en temps de calcul mais moins de code a ecrire/maintenir
2067
2068 /*
2069 * XXX XXX XXX Elie Saikali, Gauthier Fauchet, aout 2025 :
2070 *
2071 * We need to calculate : [ I^(n+1) - I^n ] / dt = f( I^(n+1) )
2072 *
2073 * But we dont know now what is f( I^(n+1) )
2074 *
2075 * 2 possibilities
2076 *
2077 * 1- [ I^(k+1) - I^k ] / dt = f( I^(k) )
2078 * then use fixed point algo to have I^k = I^(k+1) = I^(n+1)
2079 *
2080 *
2081 * 2- Use Newton algorithm (we use this here)
2082 *
2083 * f( I^(n+1) ) = f ( I^n ) + df/dI ( I^(n+1) - I^n )
2084 *
2085 * df/dI is the matrix -A obtained by the method contribuer_a_avec
2086 *
2087 * so : f( I^(n+1) ) = f ( I^n ) - A ( I^(n+1) - I^n ) = f ( I^n ) - A * I^(n+1) + A * I^n
2088 *
2089 * Thus, 1/dt I^(n+1) + A * I^(n+1) = 1/dt I^n + f ( I^n ) + A * I^n
2090 *
2091 * I^(n+1) [ Identity / dt + A ] = 1/dt I^n + f ( I^n ) + A * I^n
2092 *
2093 * and f ( I^n ) is obtained by the method ajouter
2094 */
2095 for (int op=0; op<nombre_d_operateurs(); op++)
2096 {
2097 operateur(op).l_op_base().contribuer_a_avec(inco, matrice);
2098 statistics().end_count(STD_COUNTERS::matrix_assembly,0,0);
2099 operateur(op).ajouter(resu);
2100 statistics().begin_count(STD_COUNTERS::matrix_assembly,statistics().get_last_opened_counter_level()+1);
2101 }
2102 sources().contribuer_a_avec(inco,matrice);
2103 statistics().end_count(STD_COUNTERS::matrix_assembly,0,0);
2104 sources().ajouter(resu);
2105 statistics().begin_count(STD_COUNTERS::matrix_assembly,statistics().get_last_opened_counter_level()+1);
2106 matrice.ajouter_multvect(inco, resu); // Ajout de A*Inco(n)
2107 // PL (11/04/2018): On aimerait bien calculer la contribution des sources en premier
2108 // comme dans le cas VIA_CONTRIBUER_AU_SECOND_MEMBRE mais le cas Canal_perio_3D (keps
2109 // periodique plante: il y'a une erreur de periodicite dans les termes sources du modele KEps...
2110 }
2111 else
2112 {
2113 Cerr << "Unknown value in Equation_base::assembler for " << (int)type_codage << finl;
2114 Process::exit();
2115 }
2116}
2117
2118// modifie la matrice et le second mmebre en fonction des CL
2119void Equation_base::modifier_pour_Cl(Matrice_Morse& mat_morse, DoubleTab& secmem) const
2120{
2121 for (int op=0; op<nombre_d_operateurs(); op++)
2122 {
2123 operateur(op).l_op_base().modifier_pour_Cl(mat_morse,secmem);
2124 }
2125}
2126// assemble, ajoute linertie,et modifie_pour_cl.
2127void Equation_base::assembler_avec_inertie( Matrice_Morse& mat_morse,const DoubleTab& present, DoubleTab& secmem)
2128{
2129 statistics().begin_count(STD_COUNTERS::matrix_assembly,statistics().get_last_opened_counter_level()+1);
2130 assembler(mat_morse,present,secmem);
2131 schema_temps().ajouter_inertie(mat_morse,secmem,(*this));
2132 modifier_pour_Cl(mat_morse,secmem);
2133 statistics().end_count(STD_COUNTERS::matrix_assembly);
2134}
2135
2136/* verifie que tous les termes sont compatibles */
2138{
2139 int ok = 1;
2140 /* operateurs, masse, sources */
2141 for (int op = 0; op < nombre_d_operateurs(); op++) ok &= operateur(op).l_op_base().has_interface_blocs();
2143 for (int i = 0; i < les_sources.size(); i++) ok &= les_sources(i)->has_interface_blocs();
2144 return ok;
2145}
2146
2147/* comme dimmensionner_matrice(), mais sans memoization */
2148void Equation_base::dimensionner_blocs(matrices_t matrices, const tabs_t& semi_impl) const
2149{
2150 /* operateurs, masse, sources */
2151 int nb = nombre_d_operateurs();
2152 for (int op = 0; op < nb; op++) operateur(op).l_op_base().dimensionner_blocs(matrices, semi_impl);
2153 solv_masse().dimensionner_blocs(matrices);
2154 for (int i = 0; i < les_sources.size(); i++) les_sources(i)->dimensionner_blocs(matrices, semi_impl);
2155}
2156
2157void Equation_base::assembler_blocs(matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl) const
2158{
2159 /* mise a zero */
2160 secmem = 0;
2161 for (auto && i_m : matrices) i_m.second->get_set_coeff() = 0;
2162 /* operateurs, sources, masse */
2163 for (int i = 0; i < nombre_d_operateurs(); i++)
2164 operateur(i).l_op_base().ajouter_blocs(matrices, secmem, semi_impl);
2165
2166 statistics().end_count(STD_COUNTERS::ajouter_blocs,0,0);
2167
2168 statistics().begin_count(STD_COUNTERS::source_terms,statistics().get_last_opened_counter_level()+1);
2169 for (int i = 0; i < les_sources.size(); i++)
2170 les_sources(i)->ajouter_blocs(matrices, secmem, semi_impl);
2171
2172 statistics().end_count(STD_COUNTERS::source_terms);
2173
2174
2175 statistics().begin_count(STD_COUNTERS::ajouter_blocs,statistics().get_last_opened_counter_level()+1);
2176 if (!(discretisation().is_poly_family() || probleme().que_suis_je().debute_par("Pb_Multiphase") || que_suis_je().debute_par("Equation_flux")))
2177 {
2178 const std::string& nom_inco = inconnue().le_nom().getString();
2179 Matrice_Morse *mat = matrices.count(nom_inco) ? matrices.at(nom_inco) : nullptr;
2180 if(mat) mat->ajouter_multvect(inconnue().valeurs(), secmem);
2181 }
2182}
2183
2184void Equation_base::assembler_blocs_avec_inertie(matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl)
2185{
2186 statistics().begin_count(STD_COUNTERS::ajouter_blocs,statistics().get_last_opened_counter_level()+1);
2187 assembler_blocs(matrices, secmem, semi_impl);
2189 schema_temps().ajouter_blocs(matrices, secmem, *this);
2190
2191 if (!discretisation().is_poly_family())
2192 {
2193 const std::string& nom_inco = inconnue().le_nom().getString();
2194 Matrice_Morse *mat = matrices.count(nom_inco) ? matrices.at(nom_inco) : nullptr;
2195 modifier_pour_Cl(*mat,secmem);
2196 }
2197 statistics().end_count(STD_COUNTERS::ajouter_blocs);
2198}
2199
2200/* creation de champ_conserve_, cl_champ_conserve_ */
2202{
2203 if (champ_conserve_) return; //deja fait
2204 int Nt = inconnue().nb_valeurs_temporelles(),
2205 Nl = inconnue().valeurs().size_reelle_ok() ? inconnue().valeurs().dimension(0) : -1,
2206 Nc = inconnue().valeurs().line_size();
2207 //champ_conserve_ : meme type / support que l'inconnue
2208 discretisation().creer_champ(champ_conserve_, domaine_dis(), inconnue().que_suis_je(), "N/A", "N/A", Nc, Nl, Nt, schema_temps().temps_courant());
2209 champ_conserve_->associer_eqn(*this);
2210 auto nom_fonc = get_fonc_champ_conserve();
2211 champ_conserve_->nommer(nom_fonc.first);
2212 champ_conserve_->init_champ_calcule(*this, nom_fonc.second);
2213}
2214
2215/* methode de calcul par defaut de champ_conserve : produit coefficient_temporel * inconnue */
2216void Equation_base::calculer_champ_conserve(const Objet_U& obj, DoubleTab& val, DoubleTab& bval, tabs_t& deriv)
2217{
2218 const Equation_base& eqn = ref_cast(Equation_base, obj);
2219 const Champ_base *coeff = eqn.solv_masse().has_coefficient_temporel() ? &eqn.get_champ(eqn.solv_masse().get_name_of_coefficient_temporel()) : nullptr; //coeff temporel
2220 const Champ_Inc_base& inco = eqn.inconnue();
2221 ConstDoubleTab_parts part(inco.valeurs());
2222 //valeur du champ lui-meme
2223 val = part[0];
2224 if (coeff) tab_multiply_any_shape(val, coeff->valeurs(), VECT_ALL_ITEMS);
2225
2226 bval = inco.valeur_aux_bords();
2227 if (coeff) tab_multiply_any_shape(bval, coeff->valeur_aux_bords(), VECT_ALL_ITEMS);
2228
2229 DoubleTab& der = deriv[inco.le_nom().getString()];
2230 if (coeff) der = coeff->valeurs();
2231 else der.resize(val.dimension_tot(0), val.line_size()), der = 1;
2232}
2233
2234// Impression du residu dans fic (generalement dt_ev)
2235// Cette methode peut etre surchargee par des equations
2236// imprimant des residus particuliers (K-Eps, Concentrations,...)
2238{
2239 int size = residu_.size_array();
2240 for (int i=0; i<size; i++)
2241 {
2242 Nom tab = schema_temps().norm_residu() == "max" ? "\t " : "\t\t ";
2243 fic << residu_(i) << tab;
2244 int nb_unknowns = inconnue().valeurs().dimension_tot(0);
2245 double residual_limit = ( nb_unknowns == 0 ? DMAXFLOAT : DMAXFLOAT/nb_unknowns);
2246 if (residu_(i)>residual_limit)
2247 {
2248 fic << finl;
2249 Cerr << "Equation " << le_nom() << " is diverging:" << finl;
2250 Cerr << "A residual ||dI/dt|| for this equation is bigger than " << residual_limit << " !" << finl;
2251 Cerr << "Have a look at the " << nom_du_cas() << ".dt_ev file." << finl;
2252 Process::exit();
2253 }
2254 }
2255 // Affichage min/max
2256 if (schema_temps().impr_extremums() && limpr())
2257 {
2258 double vmax = mp_max_vect(inconnue().valeurs());
2259 double vmin = mp_min_vect(inconnue().valeurs());
2260 Cout << finl << inconnue().le_nom() << " field [min/max]: ";
2261 if (je_suis_maitre()) printf("[ %.2e / %.2e ]",vmin,vmax);
2262 Cout << finl;
2263 }
2264}
2265
2266// Retourne l'expression du residu (de meme peut etre surcharge)
2268{
2269 int size = residu_.size_array();
2270 Nom tmp(""),ajout("");
2271 if (probleme().is_coupled())
2272 {
2273 ajout="_";
2274 ajout+=probleme().le_nom();
2275 }
2276 for (int i=0; i<size; i++)
2277 {
2278 Nom norm = schema_temps().norm_residu();
2279 tmp+="Ri=";
2280 tmp+=norm;
2281 if(norm != "max") tmp+="-norm";
2282 tmp+=ajout;
2283 tmp+="|d";
2284 // Comment nommer de facon claire ET concise
2285 // le champ de l'expression:
2286 if (size==1)
2287 {
2288 // Champ scalaire
2289 tmp+=(Motcle)inconnue().le_nom()[0];
2290 }
2291 else
2292 {
2293 // Champ multiscalaire
2294 if (inconnue().nom_compo(0)[0]!=inconnue().nom_compo(size-1)[0])
2295 {
2296 // Exemple, champ K_Eps
2297 tmp+=(Motcle)inconnue().nom_compo(i)[0];
2298 }
2299 else
2300 {
2301 // Exemple, champ concentration
2302 tmp+=(Motcle)inconnue().le_nom()[0];
2303 tmp+=(Nom)i;
2304 }
2305 }
2306 tmp+="/dt|\t ";
2307 }
2308 return tmp;
2309}
2310
2311// Dimension les tableaux des residus
2313{
2314 if (size==0)
2315 size = inconnue().valeurs().line_size();
2316 residu_.resize(size);
2317 residu_initial_.resize(size);
2318 residu_=0;
2319 residu_initial_=0;
2320}
2321
2322// Remplit le champ field_residu_ si existant
2323void Equation_base::set_residuals(const DoubleTab& residual)
2324{
2325 if(field_residu_)
2326 {
2327 DoubleTab& tab = field_residu_->valeurs();
2328 if (tab.dimension_tot(0) == residual.dimension_tot(0))
2329 tab = residual;
2330 else
2331 {
2332 ConstDoubleTab_parts parts(residual);
2333 if (parts[0].dimension_tot(0) == tab.dimension_tot(0))
2334 tab = parts[0];
2335 }
2336 }
2337}
2338
2340{
2341 Cerr<<"The method operateur_fonctionnel is not coded for equation "<<que_suis_je()<<finl;
2342 exit();
2343 throw;
2344}
2345
2347{
2348 Cerr<<"The method operateur_fonctionnel is not coded for equation "<<que_suis_je()<<finl;
2349 exit();
2350 throw;
2351}
2352
classe Champ_Don_base classe de base des Champs donnes (non calcules)
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.
virtual void associer_domaine_cl_dis(const Domaine_Cl_dis_base &)
virtual int nb_valeurs_temporelles() const
Renvoie le nombre de valeurs temporelles actuellement conservees.
void mettre_a_jour(double temps) override
Effectue une mise a jour en temps du champ inconnue.
void resetTime(double time) override
double changer_temps(const double temps) override
Fixe le temps du champ.
virtual std::vector< YAML_data > data_a_sauvegarder() const
for PDI IO: retrieve name, type and dimensions of the field to save/restore.
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
virtual void associer_eqn(const Equation_base &)
Associe le champ a l'equation dont il represente une inconnue.
virtual void verifie_valeurs_cl()
int sauvegarder(Sortie &) const override
Sauvegarde le champ inconnue sur un flot de sortie.
Champ_Inc_base & avancer(int i=1)
Avance le pointeur courant de i pas de temps, dans la liste des valeurs temporelles conservees.
Champ_Inc_base & reculer(int i=1)
Recule le pointeur courant de i pas de temps, dans la liste des valeurs temporelles conservees.
int reprendre(Entree &) override
Lecture d'un champ inconnue a partir d'un flot d'entree en vue d'une reprise.
DoubleTab valeur_aux_bords() const override
renvoie la valeur du champ aux faces de bord
double changer_temps_futur(double, int i=1)
Fixe le temps du ieme champ futur.
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.
virtual void abortTimeStep()
classe Cond_lim_base Classe de base pour la hierarchie des classes qui representent les differentes c...
virtual Frontiere_dis_base & frontiere_dis()
Renvoie la frontiere discretisee a laquelle les conditions aux limites s'appliquent.
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
int compatible_avec_eqn(const Equation_base &) const
Renvoie si TOUTES les conditions aux limites du vecteurs sont compatibles avec l'equation passee en p...
Definition Conds_lim.h:84
int compatible_avec_discr(const Discretisation_base &) const
Renvoie si TOUTES les conditions aux limites du vecteurs sont compatibles avec la discretisation pass...
Definition Conds_lim.h:96
static void verifier(const char *const msg, double)
Definition Debog.cpp:21
classe Discretisation_base Cette classe represente un schema de discretisation en espace,...
static void creer_champ(OWN_PTR(Champ_Inc_base)&ch, const Domaine_dis_base &z, const Nom &type, const Nom &nom, const Nom &unite, int nb_comp, int nb_ddl, int nb_pas_dt, double temps, const Nom &directive=NOM_VIDE, const Nom &nom_discretisation=NOM_VIDE)
Methode statique qui cree un OWN_PTR(Champ_Inc_base) du type specifie.
virtual Nom get_name_of_type_for(const Nom &class_operateur, const Nom &type_operteur, const Equation_base &eqn, const OBS_PTR(Champ_base)&champ_supp=OBS_PTR(Champ_base)()) const
remplit le Nom type en focntion de la classe de operateur, du type de l'operateur et de l'equation
virtual type_calcul_du_residu codage_du_calcul_du_residu() const
virtual void residu(const Domaine_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
void calculer_derivee_en_temps(double t1, double t2)
Calcule le taux d'accroissement des CLs instationnaires entre t1 et t2.
virtual void imposer_cond_lim(Champ_Inc_base &, double)=0
void set_temps_defaut(double temps)
Change le i-eme temps futur de toutes les CLs.
virtual void mettre_a_jour(double temps)
Effectue une mise a jour en temps de toutes les conditions aux limites.
int avancer(double temps)
Tourne la roue des CLs jusqu'au temps donne.
void changer_temps_futur(double temps, int i)
Change le i-eme temps futur de toutes les CLs.
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.
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 int equation_non_resolue() const
Matrice_Morse matrice_stockee
virtual void dimensionner_termes_croises(Matrice_Morse &matrice, const Probleme_base &autre_pb, int nl, int nc)
virtual void ajouter_termes_croises(const DoubleTab &inco, const Probleme_base &autre_pb, const DoubleTab &autre_inco, DoubleTab &resu) const
virtual void set_param(Param &titi) const override
const Nom & le_nom() const override
Renvoie le nom de l'equation.
virtual void associer_milieu_equation()
virtual Entree & lire_cond_init(Entree &)
Lecture des conditions initiales dans un flot d'entree.
int reprendre(Entree &) override
On reprend l'inconnue a partir d'un flot d'entree.
virtual const Milieu_base & milieu() const =0
DoubleTab & derivee_en_temps_conv(DoubleTab &, const DoubleTab &)
Add convection term In: solution is the unknown I.
virtual const RefObjU & get_modele(Type_modele type) const
virtual void avancer(int i=1)
virtual void associer_domaine_dis(const Domaine_dis_base &)
Associe le domaine discretise a l'equation.
void set_residuals(const DoubleTab &residual)
void nommer(const Nom &nom) override
Methode appelee lorsqu'on cree l'instance de l'objet dans le jeu de donnees (Interprete::ajouter).
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 imprimer(Sortie &os) const
Imprime les operateurs de l'equation si le schema en temps indique que c'est necessaire.
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.
void set_calculate_time_derivative(int i)
OWN_PTR(Parametre_equation_base) &parametre_equation()
virtual void assembler_blocs_avec_inertie(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={})
const Discretisation_base & discretisation() const
Renvoie la discretisation associee a l'equation.
void init_champ_conserve() const
Champ_Inc_base & champ_conserve() const
Solveur_Masse_base & solv_masse()
Renvoie le solveur de masse associe a l'equation.
virtual void valider_iteration()
methode virtuelle permettant de corriger l'onconnue lors d'iterations implicites par exemple K-eps do...
virtual void mettre_a_jour_champs_conserves(double temps, int reset=0)
virtual const Champ_Inc_base & inconnue() const =0
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...
OBS_PTR(Schema_Temps_base) le_schema_en_temps
const Champ_base & get_champ(const Motcle &nom) const override
virtual Entree & lire_cl(Entree &)
Lecture des conditions limites sur un flot d'entree.
virtual DoubleTab & corriger_derivee_expl(DoubleTab &)
Matrice_Morse_Diag diag_
virtual void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={}) const
virtual void contribuer_termes_croises(const DoubleTab &inco, const Probleme_base &autre_pb, const DoubleTab &autre_inco, Matrice_Morse &matrice) 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 assembler_avec_inertie(Matrice_Morse &mat_morse, const DoubleTab &present, DoubleTab &secmem)
int calculate_time_derivative() const
virtual void completer()
Complete la construction (initialisation) des objets associes a l'equation.
virtual int nombre_d_operateurs() const =0
Champs_Fonc list_champ_combi
virtual double get_time_factor() const
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.
virtual void imprime_residu(SFichier &)
virtual int nombre_d_operateurs_tot() const
virtual bool updateGivenFields()
bool has_champ(const Motcle &nom, OBS_PTR(Champ_base) &ref_champ) const override
DoubleList dt_op_bak
virtual std::pair< std::string, fonc_calc_t > get_fonc_champ_conserve() const
void initialise_residu(int=0)
virtual void assembler(Matrice_Morse &mat_morse, const DoubleTab &present, DoubleTab &secmem)
virtual void modifier_pour_Cl(Matrice_Morse &mat_morse, DoubleTab &secmem) const
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.
virtual const Champ_Inc_base & derivee_en_temps() const
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.
virtual void associer_sch_tps_base(const Schema_Temps_base &)
S'associe au schema_en_temps.
virtual void reculer(int i=1)
virtual DoubleTab & corriger_derivee_impl(DoubleTab &)
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.
void Gradient_conjugue_diff_impl(DoubleTrav &secmem, DoubleTab &solution)
virtual bool initTimeStep(double dt)
Allocation et initialisation de l'inconnue et des CLs jusqu'a present+dt.
virtual void dimensionner_matrice(Matrice_Morse &mat_morse)
virtual const Operateur & operateur_fonctionnel(int) const
virtual void discretiser()
Discretise l'equation.
void calculer_pas_de_temps_locaux(DoubleTab &) const
virtual Entree & lire_sources(Entree &)
Lecture des termes sources dans un flot d'entree.
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
virtual const Operateur & operateur(int) const =0
static void calculer_champ_conserve(const Objet_U &obj, DoubleTab &val, DoubleTab &bval, tabs_t &deriv)
virtual Champ_Inc_base & champ_convecte() const
Domaine_dis_base & domaine_dis()
Renvoie le domaine discretise associe a l'equation.
virtual const Motcle & domaine_application() const
Renvoie "indetermine" Navier_Stokes_standard par exemple surcharge cette methode.
virtual double calculer_pas_de_temps() const
Calcul du prochain pas de temps.
virtual Nom expression_residu()
const Nom & le_nom() const override
Renvoie le nom du champ.
virtual int nb_comp() const
Definition Field_base.h:56
const Nom & nom_compo(int) const
Renvoie le nom de la ieme composante du champ.
virtual Nature_du_champ nature_du_champ() const
Definition Field_base.h:77
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Frontiere.h:49
const Frontiere & frontiere() const
Renvoie la frontiere geometrique associee.
Classe Matrice_Base Classe de base de la hierarchie des matrices.
virtual DoubleVect & ajouter_multvect(const DoubleVect &x, DoubleVect &r) const
Operation de multiplication-accumulation (saxpy) matrice vecteur.
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.
void clean() override
Remplit la matrice avec des zeros.
auto & get_set_tab2()
int ordre() const override
Renvoie l'ordre de la matrice: - le nombre de lignes si la matrice est carree.
bool & constant_stencil() const
void dimensionner(int n, _SIZE_ nnz)
Size the matrix with n lines and n columns and nnz zero-values coefficients.
void set_nb_columns(const int)
auto & get_set_coeff()
int nb_colonnes() const override
Return local number of columns (=size on the current proc).
auto & get_set_tab1()
void set_est_definie(int)
virtual void associer_equation(const Equation_base *eqn) const
void get_noms_champs_postraitables(Noms &nom, Option opt=NONE) const override
void associer_eqn(const Equation_base &)
Associe une equation a l'objet.
Definition MorEqn.cpp:28
Une chaine de caractere (Nom) en majuscules.
Definition Motcle.h:26
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
virtual int debute_par(const char *const n) const
Definition Nom.cpp:319
const std::string & getString() const
Definition Nom.h:92
const Nom & le_nom() const override
Renvoie *this;.
Definition Nom.cpp:563
Un tableau de chaine de caracteres (VECT(Nom)).
Definition Noms.h:26
classe Objet_U Cette classe est la classe de base des Objets de TRUST
Definition Objet_U.h:73
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 const Nom & nom_du_cas()
Renvoie une reference constante vers le nom du cas.
Definition Objet_U.cpp:146
Objet_U()
Constructeur par defaut : attribue un numero d'identifiant unique a l'objet (object_id_),...
Definition Objet_U.cpp:55
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
Classe Op_Conv_negligeable Cette classe represente un opperateur de convection negligeable.
classe Operateur_Conv_base Cette classe est la base de la hierarchie des operateurs representant
classe Operateur_Diff_base Cette classe est la base de la hierarchie des operateurs representant
classe Operateur_base Classe est la base de la hierarchie des objets representant un
virtual void ajouter_termes_croises(const DoubleTab &inco, const Probleme_base &autre_pb, const DoubleTab &autre_inco, DoubleTab &resu) const
virtual void modifier_pour_Cl(Matrice_Morse &, DoubleTab &) const
DOES NOTHING - to override in derived classes.
const SolveurSys & get_solveur() const
void creer_champ(const Motcle &motlu) override
virtual void contribuer_a_avec(const DoubleTab &, Matrice_Morse &) const
DOES NOTHING - to override in derived classes.
SolveurSys & set_solveur()
virtual int has_interface_blocs() const
void tester_contribuer_a_avec(const DoubleTab &, const Matrice_Morse &)
virtual void mettre_a_jour(double temps)
DOES NOTHING - to override in derived classes.
Matrice & set_matrice()
int get_decal_temps() const
virtual void preparer_calcul()
virtual void dimensionner_termes_croises(Matrice_Morse &, const Probleme_base &autre_pb, int nl, int nc) const
virtual void dimensionner(Matrice_Morse &) const
DOES NOTHING - to override in derived classes.
const Matrice & get_matrice() const
void get_noms_champs_postraitables(Noms &nom, Option opt=NONE) const override
virtual void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={ }) const
virtual void contribuer_au_second_membre(DoubleTab &) const
DOES NOTHING - to override in derived classes.
virtual void resetTime(double time)
virtual void abortTimeStep()
virtual int systeme_invariant() const
virtual void ajouter_blocs(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={ }) const
virtual void contribuer_termes_croises(const DoubleTab &inco, const Probleme_base &autre_pb, const DoubleTab &autre_inco, Matrice_Morse &matrice) const
classe Operateur Classe generique de la hierarchie des operateurs.
Definition Operateur.h:39
virtual Operateur_base & l_op_base()=0
double calculer_pas_de_temps() const
Calcule le prochain pas de temps.
int impr(Sortie &os) const
Imprime l'operateur sur un flot de sortie de facon inconditionnelle.
virtual DoubleTab & calculer(const DoubleTab &, DoubleTab &) const =0
virtual void mettre_a_jour(double temps)
Effecttue une mise a jour en temps de l'operateur.
virtual DoubleTab & ajouter(const DoubleTab &, DoubleTab &) const =0
virtual void completer()
Met a jour les references des objets associes a l'operateur.
void calculer_pas_de_temps_locaux(DoubleTab &) const
Calculate the next local time steps.
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
@ REQUIRED
Definition Param.h:115
void ajouter_non_std(const char *keyword, const Objet_U *value, Param::Nature nat=Param::OPTIONAL)
Register a keyword handled by Objet_U::lire_motcle_non_standard.
Definition Param.cpp:489
classe Parametre_diffusion_implicite Un objet Parametre_diffusion_implicite est un objet regroupant l...
classe Parametre_implicite Un objet Parametre_implicite est un objet regroupant les differentes
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.
int postraiter(int force=1) override
Si force=1, effectue le postraitement sans tenir compte des frequences de postraitement.
const Domaine & domaine() const
Renvoie le domaine associe au probleme.
const Discretisation_base & discretisation() const
Renvoie la discretisation associee au probleme.
virtual void mettre_a_jour(double temps)
Effectue une mise a jour en temps du probleme.
virtual void finir()
Finit le postraitement et sauve le probleme dans un fichier.
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 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
: classe Schema_Euler_explicite Cette classe represente un schema en temps d'Euler explicite: U(n+1) ...
class Schema_Implicite_base Classe de base pour tous les schemas en temps implicite
class Schema_Temps_base
int diffusion_implicite() const
Renvoie 1 si le schema en temps a ete lu diffusion_implicite.
int limpr() const
Renvoie 1 s'il y a lieu d'effectuer une impression (cf dt_impr) Renvoie 0 sinon.
double temps_courant() const
Renvoie le temps courant.
const Nom & norm_residu() const
virtual void ajouter_inertie(Matrice_Base &mat_morse, DoubleTab &secmem, const Equation_base &eqn) const
virtual double temps_futur(int i) const =0
double pas_temps_max() const
Renvoie le pas de temps maximum.
virtual void ajouter_blocs(matrices_t matrices, DoubleTab &secmem, const Equation_base &eqn, const tabs_t &semi_impl={}) const
double pas_de_temps() const
Renvoie le pas de temps (delta_t) courant.
virtual int nb_valeurs_futures() const =0
virtual void modifier_second_membre(const Equation_base &eqn, DoubleTab &secmem)
int nb_pas_dt() const
Renvoie le nombre de pas de temps effectues.
double temps_init() const
Renvoie le temps initial.
virtual double temps_defaut() const =0
virtual void completer()=0
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 set_penalisation_flag(int pen)
virtual void dimensionner(Matrice_Morse &matrix) const
const Nom & get_name_of_coefficient_temporel() const
int has_coefficient_temporel() const
virtual void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={}) const
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
virtual DoubleTab & appliquer(DoubleTab &) const
renvoie appliquer_impl(x/coeffient_temporelle) si on a un coefficient temporel sinon renvoie applique...
virtual int has_interface_blocs() const
Classe de base des flux de sortie.
Definition Sortie.h:52
class Source_dep_inco_base Les sources heritant de cette clase doivent coder ajouter_ de facon a perm...
class Sources Sources represente une liste de Source.
Definition Sources.h:31
void contribuer_a_avec(const DoubleTab &, Matrice_Morse &) const
contribution a la matrice implicite des termes sources par defaut pas de contribution
Definition Sources.cpp:201
DoubleTab & ajouter(DoubleTab &) const
Ajoute la contribution de toutes les sources de la liste au tableau passe en parametre,...
Definition Sources.cpp:85
_SIZE_ size_array() const
virtual void ref(const TRUSTTab &)
Definition TRUSTTab.tpp:308
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, View< _TYPE_, _SHAPE_ > > view_wo()
Definition TRUSTTab.h:276
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_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
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, ConstView< _TYPE_, _SHAPE_ > > view_ro() const
Definition TRUSTTab.h:261
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
int line_size() const
Definition TRUSTVect.tpp:67
_SIZE_ size_reelle_ok() const
Definition TRUSTVect.tpp:38
void ajoute(_SCALAR_TYPE_ alpha, const TRUSTVect &y, Mp_vect_options opt=VECT_ALL_ITEMS)
Definition TRUSTVect.tpp:52
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")
static int is_PDI_restart()