TrioCFD 1.9.9_beta
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 /* default values of the convergence criteria */
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); // does the parent class know this keyword?
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 /* numbering to retrieve the residual: same approach as in 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); //call the default convergence test
271 if (ret || *reason <= 0) return ret; //not yet converged -> nothing to do
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 /* only Pb_Multiphase or Pb_conduction are handled */
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 not solved directly: Masse_Multiphase and Aire_interfaciale (always), Energie_Multiphase (in ICE), Convection_Diffusion_std i.e. turbulent quantities (in 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: solved by 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 /* remaining case: thermal or turbulent equation of a Pb_Multi or Pb_conduction -> set semi_impl if needed, then solve */
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; /* in ICE, temperatures of all problems are explicit */
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)) /* matrix: size allocated on first pass */
336 eqn.dimensionner_blocs( { { nom_inco, &mat_pred_[nom_pb_inco] } }, semi_impl);
337
338 /* assembly and 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); //convert 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 /* update */
358 eqn.inconnue().futur() = current;
359 return true;
360}
361
362//Input: Un ; Pn
363//Output: Un+1 = U***_k ; Pn+1 = P**_k
364//n denotes a time step
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; // equation order
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[unknown] = equation
383 std::vector<std::string> noms; // unknown order: same as equations, then pressure
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"); // no equation associated with pressure!
390
391 std::map<std::string, Champ_Inc_base*> inco; // all Champ_Inc
392 for (auto &i_eq : eqs)
393 inco[i_eq.first] = &i_eq.second->inconnue();
394 inco["pression"] = &eq_qdm.pression();
395 // Newton initialization with current values (stored in passe() in implicit mode), sizing incr / sec
396 double t = eqn.schema_temps().temps_courant();
397 pb.mettre_a_jour(t); //unknowns -> medium -> conserved fields
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 // in SETS, replace the past velocity value with the one from a prediction step
411 if (sets_ && !first_call_)
412 {
413 DoubleTrav secmem(current);
414 /* implicit assembly, velocities only */
415 if (!mat_pred_.count("vitesse"))
416 eq_qdm.dimensionner_blocs( { { "vitesse", &mat_pred_["vitesse"] } }); // first pass: sizing
417 eq_qdm.assembler_blocs_avec_inertie( { { "vitesse", &mat_pred_["vitesse"] } }, secmem);
418
419 /* solve and store the predicted velocity in current */
421 solv_qdm->reinit();
422 mat_pred_["vitesse"].ajouter_multvect(current, secmem); //convert increment -> variable to satisfy iterative solvers
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); //for PolyMAC_MPFA: vf -> ve
443
444 // first pass: sizing mat_semi_impl and mdv_semi_impl, filling p_degen_
445 if (!mat_semi_impl_.nb_lignes())
446 {
447 mat_semi_impl_.dimensionner(n_eq + 1, n_eq + 1); //last row -> continuity
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); //semi-implicit option
453 eq_qdm.assembleur_pression()->dimensionner_continuite(mats_["pression"]);
454 /* if mat_semi_impl is used directly: size the empty blocks */
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 /* set p_degen if not read: for incompressible flow without imposed pressure BCs, pressure is degenerate */
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 and residuals for the Newton algorithm */
476 DoubleTrav v_inco, v_incr, v_sec; //format "complete vector"
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: filled by copying unknowns when no pressure reduction is performed */
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: assembly of mat_semi_impl -> assembly of the pressure matrix -> solve -> back-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 /* fill via assembler_blocs */
526 // energy equation first, so that q_pi can be used in other 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 // the others
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 // continuity equation 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(); /* use the "solveur_pression" of the QDM equation */
539 if (pressure_reduction_) /* pressure reduction */
540 {
541 /* express the other unknowns (x) as functions of p: velocity, then temperature / pressure */
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 } }); //if PolyMAC_MPFA: start with ve
546 ordre.push_back( { { "vitesse", 0 } }), ordre.push_back( { }); //then vf, then all other unknowns simultaneously
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 << "Elimination failed!";
554 break; //if the elimination fails, we exit
555 }
556
557 /* assembly of the pressure system */
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 /* solve: only if the error on alpha (in secmem_pression) exceeds a threshold */
568 if (mp_max_abs_vect(*sec["pression"]) > 1e-16)
569 {
570 matrice_pression_.ajouter_multvect(inco["pression"]->valeurs(), *sec["pression"]); //convert increment -> variable to satisfy iterative solvers
571 solv_p->reinit(), solv_p->set_return_on_error(1); /* to avoid an exit() on failure */
572 ok = (solv_p.resoudre_systeme(matrice_pression_, *sec["pression"], *incr["pression"]) >= 0);
573 if (!ok)
574 {
575 Cerr << "Solver failed!";
576 break; //solver failed -> exit
577 }
578 incr["pression"]->echange_espace_virtuel();
579 *incr["pression"] -= inco["pression"]->valeurs();
580 }
581 else
582 *incr["pression"] = 0;
583
584 // increments of the other variables
585 for (auto &&n_v : b_p)
586 {
587 *incr[n_v.first] = n_v.second; //constant part
588 A_p_[n_v.first].ajouter_multvect(*incr["pression"], *incr[n_v.first]); //dependence on pressure increments
589 incr[n_v.first]->echange_espace_virtuel();
590 }
591 }
592 else /* no pressure reduction: go directly through mat_semi_impl */
593 {
594 mat_semi_impl_.ajouter_multvect(v_inco, v_sec); //convert increment -> variable to satisfy iterative solvers
595 solv_p->reinit(), solv_p->set_return_on_error(1); /* to avoid an exit() on failure */
596 ok = (solv_p.resoudre_systeme(mat_semi_impl_, v_sec, v_incr) >= 0);
597 if (!ok)
598 {
599 Cerr << "Solver failed!";
600 break; //solver failed -> exit
601 }
602 v_incr -= v_inco; //back to increments
603 }
604
605 eqn.solv_masse().corriger_solution(*incr["vitesse"], *incr["vitesse"], 1); //for PolyMAC_MPFA: used to correct 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 check */
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 /* updates: unknowns -> medium -> conserved fields -> 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()); // Use the minimum pressure as reference so that the same reference is used in sequential and parallel
633 if (!(ok = err_a_sum < crit_conv_["alpha"]))
634 {
635 Cerr << "Error in alpha!";
636 break; //if we have exceeded the medium bounds on (p, T) or lack precision, we must exit
637 }
638 if (!(ok = eq_qdm.milieu().check_unknown_range()))
639 {
640 Cerr << "Out of bounds!";
641 break; //if we have exceeded the medium bounds on (p, T) or lack precision, we must exit
642 }
643 pb.mettre_a_jour(t); //unknowns -> medium -> conserved fields
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); //unknowns -> medium -> conserved fields
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 // in multiphase, pressure is already in Pa
680 /* if pression_pa() is smaller than pression() (e.g. auxiliary variables in PolyMAC_HFV), copy only the first part */
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(); // in multiphase, pressure is already in 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 /* split the unknowns from sec into parts via DoubleTab_parts */
704 std::map<std::pair<std::string, int>, int> offs; //offs[{inco, bloc}]: offset of block k of unknown inco
705 std::map<std::pair<std::string, int>, std::array<int, 2>> dims; //dims[{inco, bloc}]: dimension 0 / line_size() of block k of 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 /* loop over blocks */
717 std::set<std::pair<std::string, int>> e_ib; //list of { variable, block } already eliminated
718 std::set<std::string> e_i; //list of variables already eliminated
719 int infoo {0}; // in fortran call
720 int prems = !A_p.size(); //if A_p is empty, first pass -> sizing is needed
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; //block variables, already-eliminated variables on which the block depends
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 /* rows of the block to process */
736 std::pair<std::string, int> i_b0 = *bloc.begin(); //first unknown of the block
737 IntTrav calc(dims[i_b0][0]); //calc[i] = 1 if item i must be processed
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; //process all rows whose matrix is filled
744
745 if (prems) //first pass -> sizing of 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() : discretization of unknowns" << i_b0.first << "/" << i_b0.second << " and " << i_b.first << "/" << i_b.second << " incompatible!" << finl;
753 }
754
755 std::vector<std::set<int>> stencil(calc.size_array()); //stencil[i] -> stencil of item i (to be multiplied by line_size() of each 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) //direct dependence on 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++) //dependences of all rows
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)) //dependence on a partially / fully eliminated variable
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: block of the unknown on which we 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, block) currently being eliminated and block-diagonal coefficient -> ok
785 else if (e_ib.count( { v_m.first, k })) //(variable, block) eliminated -> dependence on inco_p in 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 per unknown -> expanding by line_size()
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 may already be partially created
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()); //as a list
821 const int nv = (int) vbloc.size(), nd = (int) vdep.size(); //number of block variables, dependencies, total size
822 std::vector<int> size, off_l, off_g; //per (variable, block): size in local system, offset in local system, offset in global systems
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); //per variable: direct dependence on inco_p, for block variables / already resolved
833 std::vector<std::vector<const Matrice_Morse*>> mat(nv), dmat(nv); //matrices of block variables, of dependencies
834 std::vector<const DoubleTab*> vsec(nv), dbp(nd); //right-hand sides of variables, b_p vectors of variables / dependencies
835
836 std::vector<Matrice_Morse*> Ap(nv); //results: d{inco} = A_p[inco].d{inco_p} + b_p[inco] for the block variables
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]; //create the 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 of the dependencies
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; //right-hand side: S(i, .) -> dependence on the i-th stencil column of the block Ap, S(ic, .) -> constant part
875 //right-hand side of the 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) //we are in the diagonal block
904 D(oMl + m, oNl + n) = mat[j][k]->get_coeff()(l);
905 else //dependence on an already eliminated block
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 //direct dependence on inco_p -> in 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 //dependence on an out-of-block eliminated variable -> b_p contributes to S(0, .), A_p contributes to 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]; //"constant" part
958 auto pos = deb - 1;
959 for (auto lb = dAp[k]->get_tab1()(jb) - 1; lb < dAp[k]->get_tab1()(jb + 1) - 1; lb++) //"inco_p dependence" part
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; //singularity encountered -> exit before dividing by 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 if we must fill rows [N * i, (N + 1) * i[ of the matrix */
1015 ArrOfBit calc(np);
1016 if (secmem.get_md_vector())
1018 else
1019 calc = 1;
1020
1021 if (!P.nb_colonnes()) //sizing on first pass
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-degenerate the matrix
1085}
Transport equation for the interfacial area.
DoubleTab & futur(int i=1) override
Returns field values at instant t+i.
DoubleTab & passe(int i=1) override
Returns field values at instant t-i.
DoubleTab & valeurs() override
Returns the array of field values at the current time.
Convection_Diffusion_std This class is the base for equations modelling the transport.
const Cond_lim & les_conditions_limites(int) const
Returns the i-th boundary condition.
Specialisation of Convection_Diffusion_std for multiphase flows where the transported scalar is tempe...
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
class Equation_base The role of an equation is the calculation of one or more fields....
virtual void assembler_blocs_avec_inertie(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={})
Solveur_Masse_base & solv_masse()
Returns the mass solver associated with the 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()
Returns the discretized boundary condition domain associated with the equation.
Probleme_base & probleme()
Returns the problem associated with the equation.
Schema_Temps_base & schema_temps()
Returns the time scheme associated with the equation.
virtual const Operateur & operateur(int) const =0
Domaine_dis_base & domaine_dis()
Returns the discretized domain associated with the equation.
const Nom & le_nom() const override
Returns the name of the field.
Base class for an incompressible fluid and its properties:
Definition Fluide_base.h:36
ICE scheme (semi-implicit ICE, CATHARE 3D style).
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)
Transforms v into a parallel array having the structure md.
Specialisation of Convection_Diffusion_std for multiphase flows where the transported scalar is the v...
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
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
Returns the reference to the equation pointed to by MorEqn::mon_equation.
Definition MorEqn.h:62
A character string (Nom) in uppercase.
Definition Motcle.h:26
const Milieu_base & milieu() const override
Returns the physical medium of the equation (Fluide_base upcast to Milieu_base).
const Champ_Inc_base & inconnue() const override
Returns the velocity (unknown field of the equation) (const version).
Champ_Inc_base & pression_pa()
SolveurSys & solveur_pression()
Returns the pressure solver (const version).
Champ_Inc_base & pression()
Classe Neumann_val_ext This class is the base class of the hierarchy of.
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
const std::string & getString() const
Definition Nom.h:92
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
static const Nom & nom_du_cas()
Returns a constant reference to the case name. This method is static.
Definition Objet_U.cpp:145
virtual const Nom & le_nom() const
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
Definition Objet_U.cpp:317
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
Operateur_Diff_base This class is the base of the hierarchy of operators representing.
std::vector< const Operateur_Diff_base * > op_ext
virtual Operateur_base & l_op_base()=0
Class Pb_Conduction: represents a heat conduction problem with non-uniform rho and Cp:
Multiphase thermohydraulics problem of type "3*N equations":
virtual bool resolution_en_T() const
int nombre_d_equations() const override
Returns the number of equations.
const Equation_base & equation(int) const override
Returns the equation at index i (const version).
const Nom & le_nom() const override
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
Definition Probleme_U.h:109
virtual void mettre_a_jour(double temps)
Performs a time update of the problem.
static double mp_min(double)
Definition Process.cpp:391
static trustIdType mppartial_sum(trustIdType i)
Computes the partial sum of x over processors 0 to me()-1 (returns 0 on processor 0).
Definition Process.cpp:403
static double mp_max(double)
Definition Process.cpp:379
static int me()
Returns the rank of the local processor in the current communication group. See Comm_Group::rank() an...
Definition Process.cpp:122
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
static bool mp_and(bool)
Computes the logical AND of b across all processors in the current group.
Definition Process.cpp:418
Carries the terms of the momentum equation for multiphase flow without turbulence modelling.
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
SETS scheme (semi-implicit + stabilisation steps, TRACE-style).
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
SFichier is to the C++ ofstream class what Sortie is to the C++ ostream class.
Definition SFichier.h:29
double temps_courant() const
Returns the current time.
double pas_de_temps() const
Returns the current time step (delta_t).
class SolveurSys A SolveurSys represents any class
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
Base class for output streams.
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.