TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
SETS.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 <Discretisation_base.h>
17#include <Operateur_Diff_base.h>
18#include <Schema_Temps_base.h>
19#include <Aire_interfaciale.h>
20#include <Masse_Multiphase.h>
21#include <Neumann_val_ext.h>
22#include <MD_Vector_tools.h>
23#include <Assembleur_base.h>
24#include <TRUSTTab_parts.h>
25#include <QDM_Multiphase.h>
26#include <Pb_Multiphase.h>
27#include <Pb_Conduction.h>
28#include <MD_Vector_std.h>
29#include <Matrix_tools.h>
30#include <Matrice_Bloc.h>
31#include <Array_tools.h>
32#include <Domaine_VF.h>
33#include <TRUSTTrav.h>
34#include <Dirichlet.h>
35#include <SFichier.h>
36#include <EChaine.h>
37#include <Lapack.h>
38#include <Debog.h>
39#include <SETS.h>
40
41#include <TablePrinter.h>
43
44#ifndef NDEBUG
45template class std::map<std::string, matrices_t>;
46template class std::map<std::string, Matrice_Morse>;
47#endif
48
49Implemente_instanciable_sans_constructeur(SETS, "SETS", Simpler);
50// XD sets simpler sets INHERITS_BRACE Stability-Enhancing Two-Step solver which is useful for a multiphase problem. Ref
51// XD_CONT : J. H. MAHAFFY, A stability-enhancing two-step method for fluid flow calculations, Journal of Computational
52// XD_CONT Physics, 46, 3, 329 (1982).
53// XD attr criteres_convergence bloc_criteres_convergence criteres_convergence OPT Set the convergence thresholds for
54// XD_CONT each unknown (i.e: alpha, temperature, velocity and pressure). The default values are respectively 0.01, 0.1,
55// XD_CONT 0.01 and 100
56// XD attr iter_min entier iter_min OPT Number of minimum iterations (default value 1)
57// XD attr iter_max entier iter_max OPT Number of maximum iterations (default value 10)
58// XD attr seuil_convergence_implicite floattant seuil_convergence_implicite OPT Convergence criteria.
59// XD attr nb_corrections_max entier nb_corrections_max OPT Maximum number of corrections performed by the PISO
60// XD_CONT algorithm to achieve the projection of the velocity field. The algorithm may perform less corrections then
61// XD_CONT nb_corrections_max if the accuracy of the projection is sufficient. (By default nb_corrections_max is set to
62// XD_CONT 21).
63// XD attr facsec_diffusion_for_sets floattant facsec_diffusion_for_sets OPT facsec to impose on the diffusion time step
64// XD_CONT in sets while the total time step stays smaller than the convection time step.
65// XD bloc_criteres_convergence bloc_lecture nul NO_BRACE Not set
66
67Implemente_instanciable_sans_constructeur(ICE, "ICE", SETS);
68// XD ice sets ice INHERITS_BRACE Implicit Continuous-fluid Eulerian solver which is useful for a multiphase problem.
69// XD_CONT Robust pressure reduction resolution.
70// XD attr pression_degeneree entier pression_degeneree OPT Set to 1 if the pressure field is degenerate (ex. :
71// XD_CONT incompressible fluid with no imposed-pressure BCs). Default: autodetected
72// XD attr reduction_pression|pressure_reduction entier reduction_pression OPT Set to 1 if the user wants a resolution
73// XD_CONT with a pressure reduction. Otherwise, the flag is to be set to 0 so that the complete matrix is considered.
74// XD_CONT The default value of this flag is 1.
75// XD criteres_convergence interprete nul NO_BRACE convergence criteria
76// XD attr aco chaine(into=["{"]) aco REQ Opening curly bracket.
77// XD attr inco chaine inco OPT Unknown (i.e: alpha, temperature, velocity and pressure)
78// XD attr val floattant val OPT Convergence threshold
79// XD attr acof chaine(into=["}"]) acof REQ Closing curly bracket.
80
82{
83 sets_ = 1;
84}
85
86ICE::ICE()
87{
88 sets_ = 0;
89}
90
91Sortie& SETS::printOn(Sortie& os) const
92{
93 return Simpler::printOn(os);
94}
95
97{
98 /* valeurs par defaut des criteres de convergence */
99 crit_conv_ = {{ "alpha", 1e-2 }, { "temperature", 1e-1 },
100 { "enthalpie", 1e2 }, { "vitesse", 1e-2 },
101 { "pression", 100 }, { "k", 1e-2 },
102 { "tau", 1e-2 }, { "omega", 1e-2 },
103 { "k_WIT", 1e-2 }, { "interfacial_area", 1e2 }
104 };
105 return Simpler::readOn(is);
106}
107
109{
110 if (mot == Motcle("criteres_convergence"))
111 {
112 Nom nom;
113 is >> nom;
114 if (nom != "{")
115 Process::exit(Nom("SETS::lire() : { expected instead of ") + nom);
116
117 for (is >> nom; nom != "}"; is >> nom)
118 {
119 double val;
120 is >> val;
121 crit_conv_[nom.getString()] = val;
122 }
123 }
124 else if (mot == "iter_min")
125 is >> iter_min_;
126 else if (mot == "iter_max")
127 is >> iter_max_;
128 else if (mot == "pression_degeneree")
129 is >> p_degen_;
130 else if (mot == "pressure_reduction" || mot == "reduction_pression")
132 else
133 return Simpler::lire(mot, is); //la classe mere connait-elle ce mot cle?
134 return is;
135}
136
137Sortie& ICE::printOn(Sortie& os) const
138{
139 return SETS::printOn(os);
140}
141
143{
144 return SETS::readOn(is);
145}
146
147static inline double corriger_incr_alpha(const DoubleTab& alpha, DoubleTab& incr, double& err_a_sum)
148{
149 const int N = alpha.line_size();
150 double a_sum, corr_max = 0;
151 DoubleTrav n_a(N);
152
153 err_a_sum = 0;
154
155 for (int i = 0; i < alpha.dimension_tot(0); i++)
156 {
157 a_sum = 0;
158 for (int n = 0; n < N; n++)
159 {
160 n_a(n) = alpha(i, n) + incr(i, n);
161 a_sum += n_a(n);
162 }
163 err_a_sum = std::max(err_a_sum, std::abs(a_sum - 1));
164
165 a_sum = 0;
166 for (int n = 0; n < N; n++)
167 {
168 n_a(n) = std::max(n_a(n), 0.);
169 a_sum += n_a(n);
170 }
171 if (static_cast<bool>(a_sum))
172 for (int n = 0; n < N; n++)
173 n_a(n) /= a_sum;
174 else
175 for (int n = 0; n < N; n++)
176 n_a(n) = 1. / N;
177
178 for (int n = 0; n < N; n++)
179 {
180 corr_max = std::max(corr_max,
181 std::fabs(alpha(i, n) + incr(i, n) - n_a(n)));
182 incr(i, n) = n_a(n) - alpha(i, n);
183 }
184 }
185 err_a_sum = Process::mp_max(err_a_sum);
186 return Process::mp_max(corr_max);
187}
188
189double SETS::unknown_positivation(const DoubleTab& uk, DoubleTab& incr)
190{
191 double corr_max = 0;
192 const int N = uk.line_size();
193 for (int i = 0; i < uk.dimension_tot(0); i++)
194 for (int n = 0; n < N; n++)
195 if (uk(i, n) + incr(i, n) < 0)
196 {
197 if (-uk(i, n) - incr(i, n) > corr_max)
198 corr_max = std::abs(uk(i, n) + incr(i, n));
199 incr(i, n) = -uk(i, n);
200 }
201 return Process::mp_max(corr_max);
202}
203
204#ifdef PETSCKSP_H
205void SETS::init_cv_ctx(const DoubleTab& secmem, const DoubleVect& norme)
206{
207 cv_ctx = (SETS::cv_test_t *) calloc(1, sizeof(SETS::cv_test_t));
208 cv_ctx->obj = this;
209 cv_ctx->eps_alpha = crit_conv_["alpha"];
210 norm = norme;
211 residu = secmem;
212 cv_ctx->t = nullptr;
213 cv_ctx->v = nullptr;
214 /* numerotation pour recuperer le residu : on fait comme dans Solv_Petsc */
215 ArrOfBit items_to_keep;
216 const int size = secmem.size_array();
217 auto idx = mppartial_sum(secmem.get_md_vector()->get_sequential_items_flags(items_to_keep, secmem.line_size()));
218 ix.resize(size);
219 for (int i = 0; i < size; i++)
220 if (items_to_keep[i])
221 ix[i] = idx, idx++;
222 else
223 ix[i] = -1;
224 KSPConvergedDefaultCreate(&cv_ctx->defctx);
225}
226
227#if PETSC_VERSION_GE(3,24,0)
228PetscErrorCode SETS::destroy_cvctx(void **mctx)
229{
230 SETS::cv_test_t *ctx = (SETS::cv_test_t *)*mctx;
231 if (ctx->v)
232 VecDestroy(&ctx->v);
233 if (ctx->t)
234 VecDestroy(&ctx->t);
235 PetscErrorCode err = KSPConvergedDefaultDestroy(&ctx->defctx);
236 free(ctx);
237 return err;
238}
239#else
240PetscErrorCode SETS::destroy_cvctx(void *mctx)
241{
242 SETS::cv_test_t *ctx = (SETS::cv_test_t *)mctx;
243 if (ctx->v)
244 VecDestroy(&ctx->v);
245 if (ctx->t)
246 VecDestroy(&ctx->t);
247 PetscErrorCode err = KSPConvergedDefaultDestroy(ctx->defctx);
248 free(ctx);
249 return err;
250}
251#endif
252
253/* test de convergence */
254PetscErrorCode SETS::convergence_test(KSP ksp, PetscInt it, PetscReal rnorm, KSPConvergedReason *reason,void *mctx)
255{
256 SETS::cv_test_t *ctx = (SETS::cv_test_t *)mctx;
257 if (ctx->t == nullptr) /* ctx->t, ctx-v non initialises -> on les cree */
258 {
259 Mat m;
260 KSPGetOperators(ksp,&m,nullptr);
261 MatCreateVecs(m, &ctx->v, &ctx->t);
262 VecSetOption(ctx->v, VEC_IGNORE_NEGATIVE_INDICES,PETSC_TRUE);
263 }
264 // PETSc 3.20 -> 3.22 change bug ? KSPBuildResidual corrupted after KSPConvergedDefault call
265 // So we switch order, annoying cause KSPBuildResidual is expensive...
266 Vec resi;
267 KSPBuildResidual(ksp, ctx->t, ctx->v, &resi);//residu
268 //Cerr << "Residual before:" << finl;
269 //VecView(resi,PETSC_VIEWER_STDOUT_WORLD);
270 PetscErrorCode ret = KSPConvergedDefault(ksp, it, rnorm, reason, &ctx->defctx); //on appelle le test par defaut
271 if (ret || *reason <= 0) return ret; //pas encore converge -> rien a faire
272 /* sinon -> on verfie que sum alpha = 1 est aussi OK */
273 //KSPBuildResidual(ksp, ctx->t, ctx->v, &resi);//residu
274 //Cerr << "Residual after:" << finl;
275 //VecView(resi,PETSC_VIEWER_STDOUT_WORLD);
276 VecGetValues(resi, ctx->obj->ix.size_array(), ctx->obj->ix.addr(), ctx->obj->residu.addr());
277 bool ok = true;
278 for (int i = 0; ok && i < ctx->obj->norm.size(); i++)
279 if (ctx->obj->ix[i] >= 0)
280 ok &= std::abs(ctx->obj->residu[i]) < ctx->obj->norm[i] * ctx->eps_alpha;
281 if (!Process::mp_and(ok)) *reason = KSP_CONVERGED_ITERATING;
282 return ret;
283}
284#endif
285
287 const DoubleTab& inut,
288 DoubleTab& current,
289 double dt,
290 int numero_iteration,
291 int& ok)
292{
293 /* on ne traite que Pb_Multiphase ou Pb_conduction */
294 if (!sub_type(Pb_Multiphase, eqn.probleme()) && !sub_type(Pb_Conduction, eqn.probleme()))
295 Process::exit(que_suis_je() + " cannot be applied to the problem "
296 + eqn.probleme().le_nom() + " of type " + eqn.probleme().que_suis_je() + "!");
297
298 /* equations non resolues directement : Masse_Multiphase et Aire Interfaciale (toujours), Energie_Multiphase (en ICE), Convection_Diffusion_std i.e. quantites turbulentes (en ICE) */
299 if (sub_type(Masse_Multiphase, eqn) || sub_type(Aire_interfaciale, eqn) || (!sets_ && sub_type(Energie_Multiphase, eqn))|| (!sets_ && sub_type(Convection_Diffusion_std, eqn)))
300 {
301 if (eqn.positive_unkown())
302 {
303 DoubleTrav incr;
304 incr = current;
305 incr -= eqn.inconnue().valeurs();
307 incr += eqn.inconnue().valeurs();
308 current = incr;
309 }
310 return true;
311 }
312
313 /* QDM_Multiphase: resolue par iterer_NS */
314 int cv {0};
315 if (sub_type(QDM_Multiphase, eqn))
316 {
317 Matrice_Morse matrix_unused;
318 DoubleTrav secmem_unused;
319 iterer_NS(eqn, current, ref_cast(QDM_Multiphase, eqn).pression().valeurs(),
320 dt, matrix_unused, 0, secmem_unused, numero_iteration, cv, ok);
321 return cv;
322 }
323
324 /* cas restant : equation thermique ou turblente d'un Pb_Multi ou d'un Pb_conduction -> on regle semi_impl si necessaire, puis on resout */
325 const std::string& nom_inco = eqn.inconnue().le_nom().getString();
326 const std::string nom_pb_inco = eqn.probleme().le_nom().getString() + "/" + nom_inco;
327
328 tabs_t semi_impl; /* en ICE, les temperatures de tous les problemes sont explicites */
329 const Operateur_Diff_base& op_diff = ref_cast(Operateur_Diff_base, eqn.operateur(0).l_op_base());
330
331 if (!sets_)
332 for (auto &&op_ext : op_diff.op_ext)
333 semi_impl[nom_inco + (op_ext != &op_diff ? "/" + op_ext->equation().probleme().le_nom().getString() : "")] = op_ext->equation().inconnue().passe();
334
335 if (!mat_pred_.count(nom_pb_inco)) /* matrice : dimensionnement au premier passage */
336 eqn.dimensionner_blocs( { { nom_inco, &mat_pred_[nom_pb_inco] } }, semi_impl);
337
338 /* assemblage et resolution */
339 DoubleTrav secmem(current);
341 eqn.assembler_blocs_avec_inertie( { { nom_inco, &mat_pred_[nom_pb_inco] } }, secmem, semi_impl);
342 mat_pred_[nom_pb_inco].ajouter_multvect(current, secmem); //passage increment -> variable
343 solv->reinit();
344 solv.resoudre_systeme(mat_pred_[nom_pb_inco], secmem, current);
345
346 if (eqn.positive_unkown())
347 {
348 DoubleTrav incr;
349 incr = current;
350 incr -= eqn.inconnue().valeurs();
352 incr += eqn.inconnue().valeurs();
353 current = incr;
354 }
355
356 /* mise a jour */
358 eqn.inconnue().futur() = current;
359 return true;
360}
361
362//Entree Un ; Pn
363//Sortie Un+1 = U***_k ; Pn+1 = P**_k
364//n designe une etape temporelle
365
366void SETS::iterer_NS(Equation_base& eqn, DoubleTab& current,
367 DoubleTab& pression, double dt,
368 Matrice_Morse& matrice_unused, double seuil_resol,
369 DoubleTrav& secmem_unused, int nb_ite, int& cv, int& ok)
370{
371 Pb_Multiphase& pb = *(Pb_Multiphase*) &ref_cast(Pb_Multiphase, eqn.probleme());
372 const bool res_en_T = pb.resolution_en_T();
373
374 const int n_eq = pb.nombre_d_equations();
375 int& it = iteration_;
376 QDM_Multiphase& eq_qdm = ref_cast(QDM_Multiphase, eqn);
377 double err_a_sum = 0;
378
379 std::vector<Equation_base*> eq_list; //ordres des equations
380 for (int i = 0; i < n_eq; i++)
381 eq_list.push_back(&pb.equation(i));
382 std::map<std::string, Equation_base*> eqs; //eqs[inconnue] = equation
383 std::vector<std::string> noms; //ordre des inconnues : le meme que les equations, puis la pression
384 for (int i = 0; i < n_eq; i++)
385 {
386 noms.push_back(eq_list[i]->inconnue().le_nom().getString());
387 eqs[noms[i]] = eq_list[i];
388 }
389 noms.push_back("pression"); //pas d'equation associee a la pression!
390
391 std::map<std::string, Champ_Inc_base*> inco; //tous les Champ_Inc
392 for (auto &i_eq : eqs)
393 inco[i_eq.first] = &i_eq.second->inconnue();
394 inco["pression"] = &eq_qdm.pression();
395 //initialisation du Newton avec les valeurs presentes (stockees dans passe() en implicite), dimensionnement de incr / sec
396 double t = eqn.schema_temps().temps_courant();
397 pb.mettre_a_jour(t); //inconnues -> milieu -> champs conserves
398
399 /* valeurs semi-implicites : inconnues (alpha, v, T, ..) et champs conserves (alpha_rho, alpha_rho_e, ..) */
400 tabs_t semi_impl;
401 for (auto &&i_eq : eqs)
402 if (i_eq.second != &eq_qdm)
403 {
404 semi_impl[i_eq.first] = i_eq.second->inconnue().passe();
405 if (i_eq.second->has_champ_conserve())
406 semi_impl[i_eq.second->champ_conserve().le_nom().getString()] = i_eq.second->champ_conserve().passe();
407 if (i_eq.second->has_champ_convecte())
408 semi_impl[i_eq.second->champ_convecte().le_nom().getString()] = i_eq.second->champ_convecte().passe();
409 }
410 //en SETS, on remplace la valeur passee de v par celle donnee par une etape de prediction
411 if (sets_ && !first_call_)
412 {
413 DoubleTrav secmem(current);
414 /* assemblage "implicite, vitesses seulement" */
415 if (!mat_pred_.count("vitesse"))
416 eq_qdm.dimensionner_blocs( { { "vitesse", &mat_pred_["vitesse"] } }); //premier passage : dimensionnement
417 eq_qdm.assembler_blocs_avec_inertie( { { "vitesse", &mat_pred_["vitesse"] } }, secmem);
418
419 /* resolution et stockage de la vitesse pedite dans current */
421 solv_qdm->reinit();
422 mat_pred_["vitesse"].ajouter_multvect(current, secmem); //passage increment -> variable pour faire plaisir aux solveurs iteratifs
423 solv_qdm.resoudre_systeme(mat_pred_["vitesse"], secmem, current);
424 semi_impl["vitesse"] = current;
425
427 for (auto &&i_eq : eqs)
428 if (i_eq.second != &eq_qdm)
429 {
430 Cerr << "Prediction of " << i_eq.first << finl;
431 const DoubleTab inut_loc(0);
432 iterer_eqn(*i_eq.second, inut_loc, i_eq.second->inconnue().valeurs(), dt, 0, ok);
433 /*
434 semi_impl[i_eq.first] = (*i_eq.second).inconnue().valeurs();
435 if (i_eq.second->has_champ_conserve()) semi_impl[i_eq.second->champ_conserve().le_nom().getString()] = i_eq.second->champ_conserve().passe();
436 if (i_eq.second->has_champ_convecte()) semi_impl[i_eq.second->champ_convecte().le_nom().getString()] = i_eq.second->champ_convecte().passe();
437 */
438 }
439 }
440 else
441 semi_impl["vitesse"] = eq_qdm.inconnue().passe();
442 eqn.solv_masse().corriger_solution(current, current, 0); //pour PolyMAC_MPFA : vf -> ve
443
444 //premier passage : dimensionnement de mat_semi_impl et de mdv_semi_impl, remplissage de p_degen_
445 if (!mat_semi_impl_.nb_lignes())
446 {
447 mat_semi_impl_.dimensionner(n_eq + 1, n_eq + 1); //derniere ligne -> continuite
448 for (int i = 0; i <= n_eq; i++)
449 for (int j = 0; j <= n_eq; j++)
450 mat_semi_impl_.get_bloc(i, j).typer("Matrice_Morse"), mats_[noms[i]][noms[j]] = &ref_cast(Matrice_Morse, mat_semi_impl_.get_bloc(i, j).valeur());
451 for (auto &&i_eq : eqs)
452 i_eq.second->dimensionner_blocs(mats_[i_eq.first], semi_impl); //option semi-implicite
453 eq_qdm.assembleur_pression()->dimensionner_continuite(mats_["pression"]);
454 /* si utilisation directe de mat_semi_impl : dimensionnement des blocs vides */
456 for (int i = 0; i <= n_eq; i++)
457 for (int j = 0; j <= n_eq; j++)
458 if (!mats_[noms[i]][noms[j]]->nb_lignes() && !mats_[noms[i]][noms[j]]->nb_colonnes())
459 mats_[noms[i]][noms[j]]->dimensionner(inco[noms[i]]->valeurs().size_totale(), inco[noms[j]]->valeurs().size_totale(), 0);
460
462 for (int i = 0; i <= n_eq; i++)
463 mdc.add_part(inco[noms[i]]->valeurs().get_md_vector(), inco[noms[i]]->valeurs().line_size());
464 mdv_semi_impl_.copy(mdc);
465
466 /* reglage de p_degen si non lu : si incompressible sans CLs de pression imposee, alors la pression est degeneree */
467 if (p_degen_ < 0)
468 {
469 p_degen_ = sub_type(Fluide_base, eq_qdm.milieu());
470 for (int i = 0; i < eq_qdm.domaine_Cl_dis().nb_cond_lim(); i++)
471 p_degen_ &= !sub_type(Neumann_val_ext, eq_qdm.domaine_Cl_dis().les_conditions_limites(i).valeur());
472 }
473 }
474
475 /* increments et residus pour l'algorithme de Newton */
476 DoubleTrav v_inco, v_incr, v_sec; //format "vecteur complet"
479
480 DoubleTab_parts p_incr(v_incr);
481 DoubleTab_parts p_sec(v_sec);
482 ptabs_t incr, sec; //format "std::map"
483 for (int i = 0; i <= n_eq; i++)
484 {
485 incr[noms[i]] = &p_incr[i];
486 sec[noms[i]] = &p_sec[i];
487 }
488 if (!pressure_reduction_) /* v_inco : rempli en copiant les inconnues si on ne fait pas de reduction en pression */
489 {
491 DoubleTab_parts p_inco(v_inco);
492 for (int i = 0; i <= n_eq; i++)
493 p_inco[i] = inco[noms[i]]->valeurs();
494 }
495 /* Newton : assemblage de mat_semi_impl -> assemblage de la matrice en pression -> resolution -> substitution */
496 TablePrinter tp(&get_Cerr().get_ostream());
497 if (!Process::me())
498 {
499 tp.AddColumn("it", 5);
500 Nom fichier(nom_du_cas() + ".newton_evol");
501 if (!header_written_)
502 {
503 Cerr << "SETS => File " << fichier << " is created ..." << finl;
504 SFichier newton_evol(fichier);
505 newton_evol << "# File showing the simulation time, time step, Newton iterations, status and convergence of the increments." << finl;
506 newton_evol << "# Time \t Time_step \t Newton \t Status \t ";
507 }
508
509 for (auto &&n_i : inco)
510 {
511 tp.AddColumn(n_i.first, std::max(12, (int) n_i.first.length()));
512 if (!header_written_)
513 {
514 SFichier newton_evol(fichier, ios::app);
515 newton_evol << n_i.first << "\t ";
516 }
517 }
518 header_written_ = true;
519 tp.PrintHeader();
520 }
521
522 cv = 0;
523 for (it = 0; it < iter_min_ || (!cv && it < iter_max_); it++)
524 {
525 /* remplissage par assembler_blocs */
526 //equation d'energie en premier pour pouvoir utiliser q_pi dans d'autres equations
527 res_en_T ?
528 eqs["temperature"]->assembler_blocs_avec_inertie(mats_["temperature"], *sec["temperature"], semi_impl) :
529 eqs["enthalpie"]->assembler_blocs_avec_inertie(mats_["enthalpie"], *sec["enthalpie"], semi_impl);
530 //les autres
531 for (auto &n_e : eqs)
532 if (n_e.first != "temperature" && n_e.first != "enthalpie")
533 n_e.second->assembler_blocs_avec_inertie(mats_[n_e.first], *sec[n_e.first], semi_impl);
534
535 //equation de continuite sum_k alpha_k = 1
536 eq_qdm.assembleur_pression()->assembler_continuite(mats_["pression"], *sec["pression"]);
537
538 SolveurSys& solv_p = eq_qdm.solveur_pression(); /* on utilise le "solveur_pression" de la QDM */
539 if (pressure_reduction_) /* reduction en pression */
540 {
541 /* expression des autres inconnues (x) en fonction de p : vitesse, puis temperature / pression */
542 tabs_t b_p;
543 std::vector<std::set<std::pair<std::string, int>>> ordre;
544 if (eq_qdm.domaine_dis().le_nom() == "PolyMAC_MPFA")
545 ordre.push_back( { { "vitesse", 1 } }); //si PolyMAC_MPFA: on commence par ve
546 ordre.push_back( { { "vitesse", 0 } }), ordre.push_back( { }); //puis vf, puis toutes les autres inconnues simultanement
547 for (auto &&nom : noms)
548 if (nom != "vitesse" && nom != "pression")
549 ordre.back().insert( { { nom, 0 } });
550 ok = mp_min(eliminer(ordre, "pression", mats_, sec, A_p_, b_p));
551 if (!ok)
552 {
553 Cerr << "Echec de l'elimination!";
554 break; //si l'elimination echoue, on sort
555 }
556
557 /* assemblage du systeme en pression */
558 assembler("pression", A_p_, b_p, mats_, sec, matrice_pression_, *sec["pression"], p_degen_);
559#ifdef PETSCKSP_H
560 if (!cv_ctx && sub_type(Solv_Petsc, solv_p.valeur()))
561 {
562 init_cv_ctx(*sec["pression"], eq_qdm.assembleur_pression()->norme_continuite());
563 ref_cast(Solv_Petsc, solv_p.valeur()).set_convergence_test(convergence_test, cv_ctx, destroy_cvctx);
564 }
565#endif
566
567 /* resolution : seulement si l'erreur en alpha (dans secmem_pression) depasse un seuil */
568 if (mp_max_abs_vect(*sec["pression"]) > 1e-16)
569 {
570 matrice_pression_.ajouter_multvect(inco["pression"]->valeurs(), *sec["pression"]); //passage increment -> variable pour faire plaisir aux solveurs iteratifs
571 solv_p->reinit(), solv_p->set_return_on_error(1); /* pour eviter un exit() en cas d'echec */
572 ok = (solv_p.resoudre_systeme(matrice_pression_, *sec["pression"], *incr["pression"]) >= 0);
573 if (!ok)
574 {
575 Cerr << "Echec du solveur!";
576 break; //le solveur a echoue -> on sort
577 }
578 incr["pression"]->echange_espace_virtuel();
579 *incr["pression"] -= inco["pression"]->valeurs();
580 }
581 else
582 *incr["pression"] = 0;
583
584 //increments des autres variables
585 for (auto &&n_v : b_p)
586 {
587 *incr[n_v.first] = n_v.second; //partie constante
588 A_p_[n_v.first].ajouter_multvect(*incr["pression"], *incr[n_v.first]); //dependance en les increments de pression
589 incr[n_v.first]->echange_espace_virtuel();
590 }
591 }
592 else /* pas de reduction en pression : on passe directement par mat_semi_impl */
593 {
594 mat_semi_impl_.ajouter_multvect(v_inco, v_sec); //passage increment -> variable pour faire plaisir aux solveurs iteratifs
595 solv_p->reinit(), solv_p->set_return_on_error(1); /* pour eviter un exit() en cas d'echec */
596 ok = (solv_p.resoudre_systeme(mat_semi_impl_, v_sec, v_incr) >= 0);
597 if (!ok)
598 {
599 Cerr << "Echec du solveur!";
600 break; //le solveur a echoue -> on sort
601 }
602 v_incr -= v_inco; //retour en increments
603 }
604
605 eqn.solv_masse().corriger_solution(*incr["vitesse"], *incr["vitesse"], 1); //pour PolyMAC_MPFA : sert a corriger ve
606
607 if (!Process::me())
608 tp << it + 1;
609 incr_var_convergence_.clear(); // clear if new time-step or Newton incr !
610 for (auto &&n_v : incr)
611 {
612 const double vm = mp_min_vect(*n_v.second);
613 const double vM = mp_max_vect(*n_v.second);
614 const double x = std::fabs(vM) > std::fabs(vm) ? vM : vm;
615 if (!Process::me())
616 {
617 tp << x;
618 incr_var_convergence_.push_back(x);
619 }
620 }
621
622 /* convergence? */
623 cv = corriger_incr_alpha(inco["alpha"]->valeurs(), *incr["alpha"], err_a_sum) < crit_conv_["alpha"];
624 for (auto &&n_v : incr)
625 if (crit_conv_.count(n_v.first))
626 cv &= mp_max_abs_vect(*n_v.second) < crit_conv_.at(n_v.first);
627
628 /* mises a jour : inconnues -> milieu -> champs/conserves -> sources */
629 for (auto &&n_i : inco)
630 n_i.second->valeurs() += *incr[n_i.first];
631 if (p_degen_)
632 inco["pression"]->valeurs() -= mp_min_vect(inco["pression"]->valeurs()); // On prend la pression minimale comme pression de reference afin d'avoir la meme pression de reference en sequentiel et parallele
633 if (!(ok = err_a_sum < crit_conv_["alpha"]))
634 {
635 Cerr << "Erreur en alpha!";
636 break; //si on a depasse les bornes du milieu sur (p, T) ou si on manque de precision, on doit sortir
637 }
638 if (!(ok = eq_qdm.milieu().check_unknown_range()))
639 {
640 Cerr << "Sortie des bornes!";
641 break; //si on a depasse les bornes du milieu sur (p, T) ou si on manque de precision, on doit sortir
642 }
643 pb.mettre_a_jour(t); //inconnues -> milieu -> champs conserves
644 }
645
646 if (!Process::me())
647 {
648 tp.PrintFooter();
649 Nom fichier(nom_du_cas() + ".newton_evol");
650 SFichier newton_evol(fichier, ios::app);
651 newton_evol.setf(ios::scientific);
652 newton_evol << finl << t << "\t " << eqn.schema_temps().pas_de_temps() << "\t " << it << "\t ";
653
654 /* status ! */
655 if (!cv)
656 newton_evol << "*KO*\t ";
657 else
658 newton_evol << "OK\t ";
659
660 for (auto &itr : incr_var_convergence_)
661 newton_evol << itr << "\t ";
662 }
663
664 //ha ha ha
665 if (ok && cv)
666 {
667 for (int i = 0; i < pb.nombre_d_equations(); i++)
668 if (pb.equation(i).positive_unkown())
669 {
670 std::string nom_inco = pb.equation(i).inconnue().le_nom().getString();
671 unknown_positivation(inco[nom_inco]->valeurs(), *incr[nom_inco]);
672 }
673
674 pb.mettre_a_jour(t); //inconnues -> milieu -> champs conserves
675 for (auto &&n_i : inco)
676 n_i.second->futur() = n_i.second->valeurs();
677 eq_qdm.pression().futur() = eq_qdm.pression().valeurs();
678 ConstDoubleTab_parts ppart(inco["pression"]->valeurs());
679 //en multiphase, la pression est deja en Pa
680 /* si pression_pa() est plus petit que pression() (ex. : variables auxiliaires PolyMAC_HFV), alors on ne copie que la 1ere partie */
681 eq_qdm.pression_pa().valeurs() = eq_qdm.pression_pa().valeurs().dimension_tot(0) < inco["pression"]->valeurs().dimension_tot(0) ? ppart[0] : inco["pression"]->valeurs(); //en multiphase, la pression est deja en Pa
682 first_call_ = 0;
683 }
684 else
685 {
686 for (auto &&n_i : inco)
687 n_i.second->futur() = n_i.second->valeurs() = n_i.second->passe();
688 if (err_a_sum > crit_conv_["alpha"])
689 Cerr << que_suis_je() + ": pressure solver inaccuracy detected (requested precision " << crit_conv_["alpha"] << " , achieved precision " << err_a_sum << " )" << finl;
690 ok = 0;
691 }
692 return;
693}
694
695int SETS::eliminer(const std::vector<std::set<std::pair<std::string, int>>> ordre,
696 const std::string inco_p,
697 const std::map<std::string, matrices_t>& mats,
698 const ptabs_t& sec,
699 std::map<std::string, Matrice_Morse>& A_p,
700 tabs_t& b_p)
701{
702
703 /* decoupage des inconnues de sec en parties par DoubleTab_parts */
704 std::map<std::pair<std::string, int>, int> offs; //offs[{inco, bloc}] : offset du bloc k de l'inconnue inco
705 std::map<std::pair<std::string, int>, std::array<int, 2>> dims; //dims[{inco, bloc}] : dimension 0/ line_size() du bloc k de inco
706 for (auto &&n_v : sec)
707 {
708 ConstDoubleTab_parts part(*n_v.second);
709 for (int i = 0; i < part.size(); i++)
710 {
711 offs[ { n_v.first, i }] = offs.count( { n_v.first, i - 1 }) ? offs[ { n_v.first, i - 1 }] + dims[ { n_v.first, i - 1 }][0] * dims[ { n_v.first, i - 1 }][1] : 0;
712 dims[ { n_v.first, i }] = { part[i].dimension_tot(0), part[i].line_size() };
713 }
714 }
715
716 /* boucle sur les blocs */
717 std::set<std::pair<std::string, int>> e_ib; //liste des { variable, bloc } deja elimines
718 std::set<std::string> e_i; //liste des variables deja eliminees
719 int infoo {0}; // in fortran call
720 int prems = !A_p.size(); //si A_p est vide, premier passage -> on doit dimensionner
721 int oMg {0}, M {0};
722 const Matrice_Morse *A;
723 char trans = 'T';
724
725 for (auto &&bloc : ordre)
726 {
727 std::set<std::string> i_bloc, dep; //variables du bloc, variables deja eliminees dont le bloc depend
728 for (auto &&i_b : bloc)
729 i_bloc.insert(i_b.first);
730 for (auto &&i_b : bloc)
731 for (auto &&v_m : mats.at(i_b.first))
732 if (v_m.second->nb_colonnes() && v_m.first != inco_p && e_i.count(v_m.first) && !i_bloc.count(v_m.first))
733 dep.insert(v_m.first);
734
735 /* lignes du bloc a traiter */
736 std::pair<std::string, int> i_b0 = *bloc.begin(); //premiere inconnue du bloc
737 IntTrav calc(dims[i_b0][0]); //calc[i] = 1 si on doit traiter l'item i
738 A = mats.at(i_b0.first).at(i_b0.first);
739 oMg = offs[i_b0];
740 M = dims[i_b0][1];
741 for (int i = 0; i < calc.size_array(); i++)
742 if (A->get_tab1()(oMg + M * i + 1) > A->get_tab1()(oMg + M * i))
743 calc(i) = 1; //on traite toutes les lignes dont la matrice est remplie
744
745 if (prems) //premier passage -> dimensionnement des A_p
746 {
747 /* verification de la compatibilite des inconnues du bloc -> avec les MD_Vector renseignes dans sec */
748 for (auto &&i_b : bloc)
749 if (dims[i_b0][0] != dims[i_b][0])
750 {
751 Cerr << "SETS::eliminer() : discretisation des inconnues" << i_b0.first << "/" << i_b0.second << " et " << i_b.first << "/" << i_b.second << " incompatibles!" << finl;
753 }
754
755 std::vector<std::set<int>> stencil(calc.size_array()); //stencil[i] -> stencil de l'item i (a demultiplier par le line_size() de chaque variable)
756 for (auto &&i_b : bloc)
757 for (auto &&v_m : mats.at(i_b.first))
758 if (v_m.second->nb_coeff())
759 {
760 oMg = offs[i_b];
761 M = dims[i_b][1];
762 if (v_m.first == inco_p) //dependance directe en inco_p
763 {
764 for (int i = 0; i < calc.size_array(); i++)
765 if (calc[i])
766 for (auto j = v_m.second->get_tab1()(oMg + M * i) - 1; j < v_m.second->get_tab1()(oMg + M * (i + 1)) - 1; j++) //dependances de toutes les lignes
767 stencil[i].insert(v_m.second->get_tab2()(j) - 1);
768 }
769 else if (e_i.count(v_m.first) || i_bloc.count(v_m.first)) //dependance en une variable partiellement / totalement eliminee
770 {
771 A = A_p.count(v_m.first) ? &A_p.at(v_m.first) : nullptr;
772 for (int i = 0; i < calc.size_array(); i++)
773 if (calc[i])
774 for (auto j = v_m.second->get_tab1()(oMg + M * i) - 1; j < v_m.second->get_tab1()(oMg + M * (i + 1)) - 1; j++)
775 {
776 const int jb = v_m.second->get_tab2()(j) - 1;
777 int k = 0;
778 while (offs.count( { v_m.first, k + 1 }) && jb >= offs.at( { v_m.first, k + 1 }))
779 k++; //l : bloc de l'inconnue dont on depend
780 const int oNg = offs[ { v_m.first, k }];
781 const int N = dims[ { v_m.first, k }][1];
782 const int n = jb - oNg - N * i;
783 if (bloc.count( { v_m.first, k }) && n >= 0 && n < N)
784 continue; //(variable, bloc) en cours d'elimination et coeff bloc-diagonal -> ok
785 else if (e_ib.count( { v_m.first, k })) //(variable, bloc) elimine -> dependance en inco_p dans A_p
786 for (auto l = A->get_tab1()(jb) - 1; l < A->get_tab1()(jb + 1) - 1; l++)
787 stencil[i].insert(A->get_tab2()(l) - 1);
788 else
789 {
790 Cerr << "SETS::eliminer() : dependance ( " << i_b.first << "/" << i_b.second << " , " << v_m.first << "/" << k << " ) interdite!" << finl;
792 }
793 }
794 }
795 else
796 {
797 Cerr << "SETS::eliminer() : dependance ( " << i_b.first << "/" << i_b.second << " , " << v_m.first << " ) interdite!" << finl;
799 }
800 }
801
802 for (auto &&i_bl : bloc) //stencil par inconnue -> en demultipliant
803 {
804 Stencil sten(0, 2);
805
806 oMg = offs[i_bl];
807 M = dims[i_bl][1];
808 for (int i = 0; i < calc.size_array(); i++)
809 if (calc[i])
810 for (int m = 0; m < M; m++)
811 for (auto &&col : stencil[i])
812 sten.append_line(oMg + M * i + m, col);
813 Matrice_Morse mat2;
814 Matrix_tools::allocate_morse_matrix(sec.at(i_bl.first)->size_totale(), sec.at(inco_p)->size_totale(), sten, mat2);
815 A_p[i_bl.first].nb_colonnes() ? A_p[i_bl.first] += mat2 : A_p[i_bl.first] = mat2; //A_p peut deja etre partiellement creee
816 }
817 }
818
819 std::vector<std::string> vbloc(i_bloc.begin(), i_bloc.end());
820 std::vector<std::string> vdep(dep.begin(), dep.end()); //sous forme de liste
821 const int nv = (int) vbloc.size(), nd = (int) vdep.size(); //nombre de variables du bloc, de dependances, taille totale
822 std::vector<int> size, off_l, off_g; //par (variable, bloc) : taille dans le systeme local, offset dans le systeme local, offset dans les systemes globaux
823 int nb {0};
824 for (auto &&i_b : bloc)
825 {
826 off_l.push_back(nb);
827 size.push_back(dims[i_b][1]);
828 off_g.push_back(offs[i_b]);
829 nb += size.back();
830 }
831
832 std::vector<const Matrice_Morse*> pmat(nv), dAp(nd); //par variable : dependance directe en inco_p, des variables du bloc / deja resolues
833 std::vector<std::vector<const Matrice_Morse*>> mat(nv), dmat(nv); //matrices des variables du bloc, des dependances
834 std::vector<const DoubleTab*> vsec(nv), dbp(nd); //seconds membres des variables, vecteurs b_p des variables / des dependances
835
836 std::vector<Matrice_Morse*> Ap(nv); //resultats : d{inco} = A_p[inco].d{inco_p} + b_p[inco] pour les variables du bloc
837 std::vector<DoubleTab*> bp(nv);
838
839 for (int i = 0; i < nv; i++)
840 {
841 Ap[i] = &A_p[vbloc[i]];
842 vsec[i] = sec.at(vbloc[i]);
843 if (!b_p.count(vbloc[i]))
844 b_p[vbloc[i]] = *vsec[i]; //creation des b_p
845 bp[i] = &b_p[vbloc[i]];
846 const matrices_t& line = mats.at(vbloc[i]);
847 pmat[i] = line.count(inco_p) && line.at(inco_p)->nb_colonnes() ? line.at(inco_p) : nullptr;
848 mat[i].resize(nv);
849 for (int j = 0; j < nv; j++)
850 mat[i][j] = line.count(vbloc[j]) && line.at(vbloc[j])->nb_colonnes() ? line.at(vbloc[j]) : nullptr;
851 dmat[i].resize(nd);
852 for (int j = 0; j < nd; j++)
853 dmat[i][j] = line.count(vdep[j]) && line.at(vdep[j])->nb_colonnes() ? line.at(vdep[j]) : nullptr;
854 }
855
856 //b_p / A_p des dependances
857 for (int i = 0; i < nd; i++)
858 {
859 dbp[i] = &b_p.at(vdep[i]);
860 dAp[i] = &A_p.at(vdep[i]);
861 }
862
863 DoubleTrav D(nb, nb); // bloc diagonal
864 DoubleTrav S; // seconds membres
865
866 IntTrav piv(nb);
867 for (int i = 0; i < calc.size_array(); i++)
868 if (calc[i])
869 {
870 const auto deb = Ap[0]->get_tab1()(off_g[0] + size[0] * i) - 1;
871 const auto fin = Ap[0]->get_tab1()(off_g[0] + size[0] * i + 1) - 1;
872 const int ic = (int)(fin - deb);
873 const int nc = ic + 1;
874 S.resize(nc, nb), S = 0; //second membre : 5(i, .) -> dependance en la i-eme colonne du stencil des Ap du bloc, S(ic, .) -> partie constante
875 //partie "second membre des equations"
876 for (int j = 0; j < nv; j++)
877 {
878 M = size[j];
879 oMg = off_g[j];
880 const int oMl = off_l[j];
881 for (int m = 0; m < M; m++)
882 S(ic, oMl + m) = vsec[j]->addr()[oMg + M * i + m];
883 }
884
885 /* remplissage par les matrices du bloc : diagonale, second membre (si partie d'une variable deja eliminee) */
886 D = 0;
887 for (int j = 0; j < nv; j++)
888 {
889 M = size[j];
890 oMg = off_g[j];
891 const int oMl = off_l[j];
892 for (int k = 0; k < nv; k++)
893 if (mat[j][k])
894 {
895 const int N = size[k];
896 const int oNg = off_g[k];
897 const int oNl = off_l[k];
898 for (int m = 0; m < M; m++)
899 for (auto l = mat[j][k]->get_tab1()(oMg + M * i + m) - 1; l < mat[j][k]->get_tab1()(oMg + M * i + m + 1) - 1; l++)
900 {
901 const int jb = mat[j][k]->get_tab2()(l) - 1;
902 const int n = jb - oNg - N * i;
903 if (n >= 0 && n < N) //on est dans le bloc diagonal
904 D(oMl + m, oNl + n) = mat[j][k]->get_coeff()(l);
905 else //dependance en un bloc deja elimine
906 {
907 const double coeff = mat[j][k]->get_coeff()(l);
908 S(ic, oMl + m) -= coeff * bp[k]->addr()[jb];
909 auto pos = deb - 1;
910 for (auto lb = Ap[k]->get_tab1()(jb) - 1; lb < Ap[k]->get_tab1()(jb + 1) - 1; lb++)
911 {
912 const int col = Ap[k]->get_tab2()(lb);
913 pos++;
914 while(Ap[0]->get_tab2()(pos) != col && pos < fin)
915 pos++;
916 assert(Ap[0]->get_tab2()(pos) == col);
917 S((int)(pos - deb), oMl + m) -= coeff * Ap[k]->get_coeff()(lb);
918 }
919 }
920 }
921 }
922 }
923 //partie "dependance directe en inco_p" -> dans S([0, ic[, .)
924 for (int j = 0; j < nv; j++)
925 if (pmat[j])
926 {
927 M = size[j];
928 oMg = off_g[j];
929 const int oMl = off_l[j];
930 for (int m = 0; m < M; m++)
931 {
932 auto pos = deb - 1;
933 for (auto k = pmat[j]->get_tab1()(oMg + M * i + m) - 1; k < pmat[j]->get_tab1()(oMg + M * i + m + 1) - 1; k++)
934 {
935 int col = pmat[j]->get_tab2()(k);
936 pos++;
937 while (Ap[0]->get_tab2()(pos) != col && pos < fin)
938 pos++;
939 assert(Ap[0]->get_tab2()(pos) == col);
940 S((int)(pos - deb), oMl + m) -= pmat[j]->get_coeff()(k);
941 }
942 }
943 }
944 //partie "dependance en une variable hors bloc eliminee" -> b_p contribue a S(0, .), A_p contribue a S(1..nc, .)
945 for (int j = 0; j < nv; j++)
946 for (int k = 0; k < nd; k++)
947 if (dmat[j][k])
948 {
949 M = size[j];
950 oMg = off_g[j];
951 const int oMl = off_l[j];
952 for (int m = 0; m < M; m++)
953 for (auto l = dmat[j][k]->get_tab1()(oMg + M * i + m) - 1; l < dmat[j][k]->get_tab1()(oMg + M * i + m + 1) - 1; l++)
954 {
955 const double coeff = dmat[j][k]->get_coeff()(l);
956 const int jb = dmat[j][k]->get_tab2()(l) - 1;
957 S(ic, oMl + m) -= coeff * dbp[k]->addr()[jb]; //partie "constante"
958 auto pos = deb - 1;
959 for (auto lb = dAp[k]->get_tab1()(jb) - 1; lb < dAp[k]->get_tab1()(jb + 1) - 1; lb++) //partie "dependance en inco_p"
960 {
961 const int col = dAp[k]->get_tab2()(lb);
962 pos++;
963 while (Ap[0]->get_tab2()(pos) != col && pos < fin)
964 pos++;
965 assert(Ap[0]->get_tab2()(pos) == col);
966 S((int)(pos - deb), oMl + m) -= coeff * dAp[k]->get_coeff()(lb);
967 }
968 }
969 }
970 /* factorisation et resolution */
971 // DoubleTrav D_back = D;
972 F77NAME(dgetrf)(&nb, &nb, &D(0, 0), &nb, &piv(0), &infoo);
973 if (infoo > 0)
974 return 0; //singularite rencontree -> on sort avant de diviser par 0
975 F77NAME(dgetrs)(&trans, &nb, &nc, &D(0, 0), &nb, &piv(0), &S(0, 0), &nb, &infoo);
976
977 /* stockage : S(0, .) dans b_p, S(1..nc, .) dans A_p */
978 for (int j = 0; j < nv; j++)
979 {
980 M = size[j];
981 oMg = off_g[j];
982 const int oMl = off_l[j];
983 for (int m = 0; m < M; m++)
984 {
985 bp[j]->addr()[oMg + M * i + m] = S(ic, oMl + m);
986 {
987 auto l = Ap[j]->get_tab1()(oMg + M * i + m) - 1;
988 for (int k = 0; k < ic; k++, l++)
989 Ap[j]->get_set_coeff()(l) = S(k, oMl + m);
990 }
991 }
992 }
993 }
994
995 for (auto &&i_b : bloc)
996 e_ib.insert(i_b), e_i.insert(i_b.first);
997 }
998 return 1;
999}
1000
1001void SETS::assembler(const std::string inco_p,
1002 const std::map<std::string, Matrice_Morse>& A_p,
1003 const tabs_t& b_p,
1004 const std::map<std::string, matrices_t>& mats,
1005 const ptabs_t& sec,
1006 Matrice_Morse& P,
1007 DoubleTab& secmem,
1008 int p_degen)
1009{
1010 secmem = *sec.at(inco_p);
1011 const int np = secmem.dimension_tot(0);
1012 const int M = secmem.line_size();
1013
1014 /* calc(i) = 1 si on doit remplir les lignes [N * i, (N + 1) * i[ de la matrice */
1015 ArrOfBit calc(np);
1016 if (secmem.get_md_vector())
1018 else
1019 calc = 1;
1020
1021 if (!P.nb_colonnes()) //dimensionnement au premier passage
1022 {
1023 Stencil stencil(0, 2);
1024
1025 for (auto &&n_m : mats.at(inco_p))
1026 if (n_m.second && n_m.second->nb_colonnes())
1027 {
1028 const Matrice_Morse& Mp = *n_m.second, *Ap = n_m.first != inco_p ? &A_p.at(n_m.first) : nullptr;
1029 for (int i = 0; i < np; i++)
1030 if (calc[i])
1031 {
1032 int ib = M * i;
1033 for (int m = 0; m < M; m++, ib++)
1034 for (auto j = Mp.get_tab1()(ib) - 1; j < Mp.get_tab1()(ib + 1) - 1; j++)
1035 {
1036 const int k = Mp.get_tab2()(j) - 1;
1037 for (auto l = (Ap ? Ap->get_tab1()(k) - 1 : 0); l < (Ap ? Ap->get_tab1()(k + 1) - 1 : 1); l++)
1038 stencil.append_line(ib, Ap ? Ap->get_tab2()(l) - 1 : k);
1039 }
1040 }
1041 }
1042 tableau_trier_retirer_doublons(stencil);
1043 Matrix_tools::allocate_morse_matrix(secmem.size_totale(), secmem.size_totale(), stencil, P);
1044 }
1045
1046 /* remplissage de P / secmem */
1047 P.get_set_coeff() = 0;
1048 for (auto &&n_m : mats.at(inco_p))
1049 if (n_m.first == inco_p && n_m.second && n_m.second->nb_colonnes())
1050 P += *n_m.second; /* dependance directe en inco_p -> on ajoute */
1051 else if (n_m.second && n_m.second->nb_colonnes()) /* dependance en une autre inconnue -> produit Mp.Ap + modif second membre */
1052 {
1053 const Matrice_Morse& Mp = *n_m.second, &Ap = A_p.at(n_m.first);
1054 const DoubleTab& bp = b_p.at(n_m.first);
1055 for (int i = 0; i < np; i++)
1056 if (calc[i])
1057 {
1058 int ib = M * i;
1059 for (int m = 0; m < M; m++, ib++)
1060 {
1061 const auto deb = P.get_tab1()(ib) - 1;
1062 const auto fin = P.get_tab1()(ib + 1) - 1;
1063 for (auto j = Mp.get_tab1()(ib) - 1; j < Mp.get_tab1()(ib + 1) - 1; j++)
1064 {
1065 const int k = Mp.get_tab2()(j) - 1;
1066 secmem(i, m) -= Mp.get_coeff()(j) * bp.addr()[k];
1067 auto pos = deb - 1;
1068 for (auto l = Ap.get_tab1()(k) - 1; l < Ap.get_tab1()(k + 1) - 1; l++)
1069 {
1070 const int col = Ap.get_tab2()(l);
1071 pos++;
1072 while (P.get_tab2()(pos) != col && pos < fin)
1073 pos++;
1074 assert(P.get_tab2()(pos) == col);
1075 P.get_set_coeff()(pos) += Mp.get_coeff()(j) * Ap.get_coeff()(l);
1076 }
1077 }
1078 }
1079 }
1080 }
1081 const double diag = P.get_coeff()(0);
1082 if (p_degen && !Process::me())
1083 for (auto i = 0; i < P.get_tab1()(1) - 1; i++)
1084 P.get_set_coeff()(i) += diag; //de-degeneration de la matrice
1085}
classe Aire_interfaciale Equation de transport de l'aire interfaciale
DoubleTab & futur(int i=1) override
Renvoie les valeurs du champs a l'instant t+i.
DoubleTab & passe(int i=1) override
Renvoie les valeurs du champs a l'instant t-i.
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
classe Convection_Diffusion_std Cette classe est la base des equations modelisant le transport
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
classe Energie_Multiphase Cas particulier de Convection_Diffusion_std pour un fluide quasi conpressib...
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
classe Equation_base Le role d'une equation est le calcul d'un ou plusieurs champs....
virtual void assembler_blocs_avec_inertie(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={})
Solveur_Masse_base & solv_masse()
Renvoie le solveur de masse associe a l'equation.
virtual const Champ_Inc_base & inconnue() const =0
virtual void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={}) const
virtual bool positive_unkown()
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Renvoie le domaine des conditions aux limite discretisee associee a l'equation.
Probleme_base & probleme()
Renvoie le probleme associe a l'equation.
Schema_Temps_base & schema_temps()
Renvoie le schema en temps associe a l'equation.
virtual const Operateur & operateur(int) const =0
Domaine_dis_base & domaine_dis()
Renvoie le domaine discretise associe a l'equation.
const Nom & le_nom() const override
Renvoie le nom du champ.
classe Fluide_base Cette classe represente un d'un fluide incompressible ainsi que
Definition Fluide_base.h:38
classe ICE (semi-implicte ICE, a la CATHARE 3D)
Definition SETS.h:141
int get_sequential_items_flags(ArrOfBit &flags, int line_size=1) const
Metadata for a distributed composite vector.
void add_part(const MD_Vector &part, int shape=0, Nom name="")
Append the "part" descriptor to the composite vector.
static void creer_tableau_distribue(const MD_Vector &, Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
transforme v en un tableau parallele ayant la structure md.
classe Masse_Multiphase Cas particulier de Convection_Diffusion_std pour un fluide quasi conpressible
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
const auto & get_tab2() const
const auto & get_tab1() const
auto & get_set_coeff()
int nb_colonnes() const override
Return local number of columns (=size on the current proc).
const auto & get_coeff() const
static void allocate_morse_matrix(const int nb_lines, const int nb_columns, const Stencil &stencil, Matrice_Morse &matrix, const bool &attach_stencil_to_matrix=false)
virtual int check_unknown_range() const
const Equation_base & equation() const
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
Une chaine de caractere (Nom) en majuscules.
Definition Motcle.h:26
const Milieu_base & milieu() const override
Renvoie le milieu physique de l'equation (le Fluide_base upcaste en Milieu_base).
const Champ_Inc_base & inconnue() const override
Renvoie la vitesse (champ inconnue de l'equation) (version const).
Champ_Inc_base & pression_pa()
SolveurSys & solveur_pression()
Renvoie le solveur en pression (version const).
Champ_Inc_base & pression()
Classe Neumann_val_ext Cette classe est la classe de base de la hierarchie des conditions.
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
const std::string & getString() const
Definition Nom.h:92
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
virtual const Nom & le_nom() const
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Objet_U.cpp:319
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
classe Operateur_Diff_base Cette classe est la base de la hierarchie des operateurs representant
std::vector< const Operateur_Diff_base * > op_ext
virtual Operateur_base & l_op_base()=0
Classe Pb_Conduction Cette classe represente un probleme de conduction avec rho et Cp non uniformes :
classe Pb_Multiphase Cette classe represente un probleme de thermohydraulique multiphase de type "3*N...
virtual bool resolution_en_T() const
int nombre_d_equations() const override
Renvoie le nombre d'equation, Renvoie 2 car il y a 2 equations a un probleme de.
const Equation_base & equation(int) const override
Renvoie l'equation d'hydraulique de type Navier_Stokes_std si i=0 Renvoie l'equation de la thermique ...
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
virtual void mettre_a_jour(double temps)
Effectue une mise a jour en temps du probleme.
static double mp_min(double)
Definition Process.cpp:386
static trustIdType mppartial_sum(trustIdType i)
Calul de la somme partielle de i sur les processeurs 0 a me()-1 (renvoie 0 sur le processeur 0).
Definition Process.cpp:396
static double mp_max(double)
Definition Process.cpp:376
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static bool mp_and(bool)
Calcule le 'et' logique de b sur tous les processeurs du groupe courant.
Definition Process.cpp:409
classe QDM_Multiphase Cette classe porte les termes de l'equation de la dynamique
void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={}) const override
void assembler_blocs_avec_inertie(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={}) override
classe SETS (semi-implicite + etapes de stabilisation, a la TRACE)
Definition SETS.h:35
int sets_
Definition SETS.h:80
Entree & lire(const Motcle &, Entree &) override
Definition SETS.cpp:108
Matrice_Bloc mat_semi_impl_
Definition SETS.h:121
SETS()
Definition SETS.cpp:81
int pressure_reduction_
Definition SETS.h:114
double facsec_diffusion_for_sets() const
Definition SETS.h:105
int p_degen_
Definition SETS.h:79
std::map< std::string, Matrice_Morse > A_p_
Definition SETS.h:126
MD_Vector mdv_semi_impl_
Definition SETS.h:122
int iter_min_
Definition SETS.h:112
static int eliminer(const std::vector< std::set< std::pair< std::string, int > > > ordre, const std::string inco_p, const std::map< std::string, matrices_t > &mats, const ptabs_t &sec, std::map< std::string, Matrice_Morse > &A_p, tabs_t &b_p)
Definition SETS.cpp:695
void iterer_NS(Equation_base &, DoubleTab &current, DoubleTab &pression, double, Matrice_Morse &, double, DoubleTrav &, int nb_iter, int &converge, int &ok) override
Definition SETS.cpp:366
double unknown_positivation(const DoubleTab &uk, DoubleTab &incr)
Definition SETS.cpp:189
std::map< std::string, double > crit_conv_
Definition SETS.h:117
static void assembler(const std::string inco_p, const std::map< std::string, Matrice_Morse > &A_p, const tabs_t &b_p, const std::map< std::string, matrices_t > &mats, const ptabs_t &sec, Matrice_Morse &matrice, DoubleTab &secmem, int p_degen)
Definition SETS.cpp:1001
int iteration_
Definition SETS.h:78
bool header_written_
Definition SETS.h:132
std::map< std::string, matrices_t > mats_
Definition SETS.h:120
int first_call_
Definition SETS.h:113
std::vector< double > incr_var_convergence_
Definition SETS.h:133
std::map< std::string, Matrice_Morse > mat_pred_
Definition SETS.h:123
Matrice_Morse matrice_pression_
Definition SETS.h:129
bool iterer_eqn(Equation_base &equation, const DoubleTab &inconnue, DoubleTab &result, double dt, int numero_iteration, int &ok) override
Definition SETS.cpp:286
int iter_max_
Definition SETS.h:112
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
double temps_courant() const
Renvoie le temps courant.
double pas_de_temps() const
Renvoie le pas de temps (delta_t) courant.
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)
virtual Entree & lire(const Motcle &, Entree &)
Parametre_implicite & get_and_set_parametre_implicite(Equation_base &eqn)
virtual DoubleTab & corriger_solution(DoubleTab &x, const DoubleTab &y, int incr=0) const
void setf(IOS_FORMAT code) override
Classe de base des flux de sortie.
Definition Sortie.h:52
_SIZE_ size_array() const
_TYPE_ * addr()
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 append_line(_TYPE_)
Definition TRUSTTab.tpp:213
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
int line_size() const
Definition TRUSTVect.tpp:67
virtual const MD_Vector & get_md_vector() const
Definition TRUSTVect.h:123
void AddColumn(const std::string &header_name, int column_width)
Add a column to our table.