TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Op_Diff_PolyMAC_CDO_Elem.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 <Modele_turbulence_scal_base.h>
17#include <Echange_contact_PolyMAC_CDO.h>
18#include <Op_Diff_PolyMAC_CDO_Elem.h>
19#include <Domaine_Cl_PolyMAC_family.h>
20#include <Champ_Elem_PolyMAC_CDO.h>
21#include <Probleme_base.h>
22#include <Matrix_tools.h>
23#include <Array_tools.h>
24#include <TRUSTTab_parts.h>
25#include <EChaine.h>
26
27Implemente_instanciable_sans_constructeur( Op_Diff_PolyMAC_CDO_Elem , "Op_Diff_PolyMAC_CDO_Elem|Op_Diff_PolyMAC_CDO_var_Elem" , Op_Diff_PolyMAC_CDO_base );
28Implemente_instanciable( Op_Dift_PolyMAC_CDO_Elem , "Op_Dift_PolyMAC_CDO|Op_Dift_PolyMAC_CDO_var_P0_PolyMAC_CDO" , Op_Diff_PolyMAC_CDO_Elem );
29Implemente_instanciable( Op_Diff_Nonlinear_PolyMAC_CDO_Elem, "Op_Diff_nonlinear_PolyMAC_CDO_Elem|Op_Diff_nonlinear_PolyMAC_CDO_var_Elem" , Op_Diff_PolyMAC_CDO_Elem );
30Implemente_instanciable( Op_Dift_Nonlinear_PolyMAC_CDO_Elem, "Op_Dift_PolyMAC_CDO_nonlinear|Op_Dift_PolyMAC_CDO_var_P0_PolyMAC_CDO_nonlinear", Op_Diff_PolyMAC_CDO_Elem );
31
36
41
46
48{
50 if (polymac_flica5)
51 {
52 // For small systems, a direct factorization can be faster than iterative solvers.
53 bool flag = Process::nproc() == 1 && le_dom_poly_->nb_elem() < 10000;
54 EChaine chl(flag ? "Petsc Cholesky_lapack { quiet }" : "Petsc Cholesky { quiet }");
55 lire_solveur(chl);
56 solveur.nommer("Op_Diff_PolyMAC_CDO_Elem solver");
57 }
58 const Champ_Elem_PolyMAC_CDO& ch = ref_cast(Champ_Elem_PolyMAC_CDO, equation().inconnue());
59 const Domaine_PolyMAC_CDO& domaine = le_dom_poly_.valeur();
60 if (domaine.domaine().nb_joints() && domaine.domaine().joint(0).epaisseur() < 1)
61 Cerr << "Op_Diff_PolyMAC_CDO_Elem : largeur de joint insuffisante (minimum 1)!" << finl, Process::exit();
62 ch.fcl();
63 int nb_comp = (equation().que_suis_je() == "Transport_K_Epsilon") ? 2 : ch.valeurs().line_size();
64 flux_bords_.resize(domaine.premiere_face_int(), nb_comp);
65
66 stab_ = que_suis_je().find("nonlinear") >= 0;
67 if (stab_)
68 {
69 delta_e.resize(0, nb_comp), delta_f.resize(0, nb_comp), delta_f_int.resize(0, nb_comp, 2);
70 domaine.domaine().creer_tableau_elements(delta_e), domaine.creer_tableau_faces(delta_f), domaine.creer_tableau_faces(delta_f_int);
71 }
72 delta_int_a_jour_ = delta_a_jour_ = (stab_ ? 0 : 1);
73
74 if (!que_suis_je().debute_par("Op_Dift"))
75 return;
76 const RefObjU& modele_turbulence = equation().get_modele(TURBULENCE);
77 const Modele_turbulence_scal_base& mod_turb = ref_cast(Modele_turbulence_scal_base, modele_turbulence.valeur());
78 const Champ_Fonc_base& lambda_t = mod_turb.conductivite_turbulente();
80}
81
83{
84 if (delta_int_a_jour_)
85 return; //deja fait
86 const DoubleTab& inco = equation().inconnue().valeurs();
87 const Domaine_PolyMAC_CDO& domaine = le_dom_poly_.valeur();
88 const IntTab& e_f = domaine.elem_faces();
89 const DoubleVect& fs = domaine.face_surfaces(), &ve = domaine.volumes();
90 int i, j, k, l, e, f, fb, ne_tot = domaine.nb_elem_tot(), n, N = inco.line_size();
91 double fac, fac_n;
92
93 update_nu(); //prerequis : nu
94 delta_f_int = 0;
95 DoubleTrav nu_ef(e_f.dimension(1), N), de_num(N), de_den(N);
96 for (e = 0; e < domaine.nb_elem_tot(); e++)
97 {
98 de_num = 0, de_den = 0; //numerateur / denominateur de delta_e
99 remplir_nu_ef(e, nu_ef);
100 for (i = 0, j = domaine.m2d(e); j < domaine.m2d(e + 1); i++, j++)
101 {
102 //partie 'face-face'
103 for (f = e_f(e, i), k = domaine.w2i(j); k < domaine.w2i(j + 1); k++)
104 for (fb = e_f(e, l = domaine.w2j(k)), fac = fs(f) * fs(fb) / ve(e) * domaine.w2c(k), n = 0; n < N; n++)
105 {
106 fac_n = fac * nu_ef(l, n) * (inco(ne_tot + fb, n) - inco(e, n));
107 de_num(n) += fac_n, delta_f_int(f, n, 0) += fac_n;
108 delta_f_int(f, n, 1) += std::fabs(inco(ne_tot + fb, n) - inco(ne_tot + f, n));
109 }
110 //partie 'face-element'
111 for (n = 0; n < N; n++)
112 {
113 fac = std::fabs(inco(e, n) - inco(ne_tot + f, n));
114 de_den(n) += fac, delta_f_int(f, n, 1) += fac;
115 }
116 }
117 //on peut calculer delta_e des maintenant
118 for (n = 0; n < N; n++)
119 delta_e(e, n) = de_den(n) > 1e-8 ? std::fabs(de_num(n)) / de_den(n) : 0;
120 }
121 delta_e.echange_espace_virtuel(), delta_f_int.echange_espace_virtuel();
122 delta_int_a_jour_ = 1;
123}
124
126{
127 if (delta_a_jour_)
128 return; //deja fait
129 const Champ_Elem_PolyMAC_CDO& ch = ref_cast(Champ_Elem_PolyMAC_CDO, equation().inconnue());
130 const Conds_lim& cls = la_zcl_poly_->les_conditions_limites();
131 const Domaine_PolyMAC_CDO& domaine = le_dom_poly_.valeur();
132 int i, f, n, N = ch.valeurs().line_size();
133
134 //prerequis : delta_int interne + dans les CL Echange_contact
136 for (i = 0; i < cls.size(); i++)
137 if (sub_type(Echange_contact_PolyMAC_CDO, cls[i].valeur()))
138 ref_cast_non_const(Echange_contact_PolyMAC_CDO, cls[i].valeur()).update_coeffs();
139 //calcul final de delta_f
140 for (f = 0; f < domaine.nb_faces_tot(); f++)
141 for (n = 0; n < N; n++)
142 {
143 double n_d[2] = { delta_f_int(f, n, 0), delta_f_int(f, n, 1) };
144 //contribution de l'autre probleme par des CL de type Echange_contact
145 for (i = 0; ch.fcl()(f, 0) == 3 && i < 2; i++)
146 n_d[i] += ref_cast(Echange_contact_PolyMAC_CDO, cls[ch.fcl()(f, 1)].valeur()).delta_int(ch.fcl()(f, 2), n, i);
147 delta_f(f, n) = n_d[1] > 1e-8 ? std::fabs(n_d[0]) / n_d[1] : 0;
148 }
149 delta_f.echange_espace_virtuel();
150 delta_a_jour_ = 1;
151}
152
157
159{
160 /*
161 0 | 1
162 ---+---
163 2 | 3
164 */
165
166 if (p > 3 || p < -1)
167 Process::exit("Op_Diff_PolyMAC_CDO_Elem::dimensionner_bloc : invalid bloc number! p must be in [-1, 3]");
168
169 const Champ_Elem_PolyMAC_CDO& ch = ref_cast(Champ_Elem_PolyMAC_CDO, equation().inconnue());
170 const Domaine_PolyMAC_CDO& domaine = le_dom_poly_.valeur();
171 const IntTab& e_f = domaine.elem_faces();
172 int i, j, k, l, e, f, ne_tot = domaine.nb_elem_tot(), nf_tot = domaine.nb_faces_tot(), n, N = ch.valeurs().line_size();
173 domaine.init_m2();
174
175 Stencil stencil(0, 2);
176 VECT(Stencil) sp(4);
177 for (int q = 0; q < 4; q++) sp[q].resize(0, 2);
178
179 for (e = 0; e < domaine.nb_elem_tot(); e++)
180 {
181 //dependance en les Te : diagonale -> faces autour de chaque element
182 if (e < domaine.nb_elem())
183 for (n = 0; n < N; n++)
184 {
185 stencil.append_line(N * e + n, N * e + n);
186 sp[0].append_line(N * e + n, N * e + n);
187 }
188 for (i = 0; i < e_f.dimension(1) && (f = e_f(e, i)) >= 0; i++)
189 for (n = 0; f < domaine.nb_faces() && n < N; n++)
190 {
191 stencil.append_line(N * (ne_tot + f) + n, N * e + n);
192 sp[2].append_line(N * f + n, N * e + n);
193 }
194
195 //dependence en les Tf
196 for (j = 0, k = domaine.m2d(e); k < domaine.m2d(e + 1); j++, k++)
197 for (f = e_f(e, j), l = domaine.w2i(k); l < domaine.w2i(k + 1); l++)
198 {
199 //blocs superieurs : divergence
200 for (n = 0; e < domaine.nb_elem() && n < N; n++)
201 {
202 stencil.append_line(N * e + n, N * (ne_tot + e_f(e, domaine.w2j(l))) + n);
203 sp[1].append_line(N * e + n, N * e_f(e, domaine.w2j(l)) + n);
204 }
205
206 //blocs inferieurs : continuite
207 for (n = 0; f < domaine.nb_faces() && n < N; n++)
208 {
209 stencil.append_line(N * (ne_tot + f) + n, N * (ne_tot + e_f(e, domaine.w2j(l))) + n);
210 sp[3].append_line(N * f + n, N * e_f(e, domaine.w2j(l)) + n);
211 }
212 }
213 }
214 if (p == -1)
215 {
216 tableau_trier_retirer_doublons(stencil);
217 Matrix_tools::allocate_morse_matrix(N * (ne_tot + nf_tot), N * (ne_tot + nf_tot), stencil, mat);
218 }
219 else
220 {
221 tableau_trier_retirer_doublons(sp[p]);
222 const int nx = N * ((p <= 1) ? ne_tot : nf_tot);
223 const int ny = N * ((p == 0 || p == 2) ? ne_tot : nf_tot);
224 Matrix_tools::allocate_morse_matrix(nx, ny, sp[p], mat);
225 }
226}
227
228void Op_Diff_PolyMAC_CDO_Elem::dimensionner_termes_croises(Matrice_Morse& matrice, const Probleme_base& autre_pb, int nl, int nc) const
229{
230 const Champ_Elem_PolyMAC_CDO& ch = ref_cast(Champ_Elem_PolyMAC_CDO, equation().inconnue());
231 const Domaine_PolyMAC_CDO& domaine = le_dom_poly_.valeur();
232 const Conds_lim& cls = la_zcl_poly_->les_conditions_limites();
233 int i, j, k, l, f, n, N = ch.valeurs().line_size(), ne_tot = domaine.nb_elem_tot();
234
235 Stencil stencil(0, 2);
236
237 for (i = 0; i < cls.size(); i++)
238 if (sub_type(Echange_contact_PolyMAC_CDO, cls[i].valeur()))
239 {
240 const Echange_contact_PolyMAC_CDO& cl = ref_cast(Echange_contact_PolyMAC_CDO, cls[i].valeur());
241 if (cl.nom_autre_pb() != autre_pb.le_nom())
242 continue; //not our problem
243
244 /* stencil */
245 const Front_VF& fvf = ref_cast(Front_VF, cl.frontiere_dis());
246 for (j = 0; j < cl.item.dimension(0); j++)
247 for (k = 0, f = fvf.num_face(j); k < cl.item.dimension(1) && (l = cl.item(j, k)) >= 0; k++)
248 for (n = 0; n < N; n++)
249 stencil.append_line(N * (ne_tot + f) + n, N * l + n);
250 }
251
252 tableau_trier_retirer_doublons(stencil);
253 Matrix_tools::allocate_morse_matrix(nl, nc, stencil, matrice);
254}
255
256void Op_Diff_PolyMAC_CDO_Elem::ajouter_termes_croises(const DoubleTab& inco, const Probleme_base& autre_pb, const DoubleTab& autre_inco, DoubleTab& resu) const
257{
258 const Champ_Elem_PolyMAC_CDO& ch = ref_cast(Champ_Elem_PolyMAC_CDO, equation().inconnue());
259 const Domaine_PolyMAC_CDO& domaine = le_dom_poly_.valeur();
260 const Conds_lim& cls = la_zcl_poly_->les_conditions_limites();
261 int i, j, k, l, f, n, N = ch.valeurs().line_size(), ne_tot = domaine.nb_elem_tot();
262
263 //prerequis : nu, delta en interne + coeffs/delta dans les CL Echange_contact
265 for (i = 0; i < cls.size(); i++)
266 if (sub_type(Echange_contact_PolyMAC_CDO, cls[i].valeur()))
267 ref_cast_non_const(Echange_contact_PolyMAC_CDO, cls[i].valeur()).update_coeffs(), ref_cast(Echange_contact_PolyMAC_CDO, cls[i].valeur()).update_delta();
268
269 for (i = 0; i < cls.size(); i++)
270 if (sub_type(Echange_contact_PolyMAC_CDO, cls[i].valeur()))
271 {
272 const Echange_contact_PolyMAC_CDO& cl = ref_cast(Echange_contact_PolyMAC_CDO, cls[i].valeur());
273 if (cl.nom_autre_pb() != autre_pb.le_nom())
274 continue; //not our problem
275 const Front_VF& fvf = ref_cast(Front_VF, cl.frontiere_dis());
276 for (j = 0; j < fvf.nb_faces(); j++)
277 {
278 f = fvf.num_face(j);
279 for (n = 0; n < N; n++)
280 resu(ne_tot + f, n) -= cl.coeff(j, 0, n) * inco(ne_tot + f, n); //terme de la face elle-meme
281 for (k = 0; k < cl.item.dimension(1) && (l = cl.item(j, k)) >= 0; k++)
282 for (n = 0; n < N; n++)
283 {
284 //operateur
285 resu(ne_tot + f, n) -= cl.coeff(j, k + 1, n) * autre_inco(l, n);
286 //correction non lineaire
287 if (stab_)
288 resu(ne_tot + f, n) -= std::max(delta_f(f, n), cl.delta(j, k, n)) * (inco(ne_tot + f, n) - autre_inco(l, n));
289 }
290 }
291 }
292}
293
294void Op_Diff_PolyMAC_CDO_Elem::contribuer_termes_croises(const DoubleTab& inco, const Probleme_base& autre_pb, const DoubleTab& autre_inco, Matrice_Morse& matrice) const
295{
296 const Champ_Elem_PolyMAC_CDO& ch = ref_cast(Champ_Elem_PolyMAC_CDO, equation().inconnue());
297 const Domaine_PolyMAC_CDO& domaine = le_dom_poly_.valeur();
298 const Conds_lim& cls = la_zcl_poly_->les_conditions_limites();
299 int i, j, k, l, f, n, N = ch.valeurs().line_size(), ne_tot = domaine.nb_elem_tot();
300
301 //prerequis : nu, delta en interne + coeffs/delta dans les CL Echange_contact
303 for (i = 0; i < cls.size(); i++)
304 if (sub_type(Echange_contact_PolyMAC_CDO, cls[i].valeur()))
305 ref_cast_non_const(Echange_contact_PolyMAC_CDO, cls[i].valeur()).update_coeffs(), ref_cast(Echange_contact_PolyMAC_CDO, cls[i].valeur()).update_delta();
306
307 for (i = 0; i < cls.size(); i++)
308 if (sub_type(Echange_contact_PolyMAC_CDO, cls[i].valeur()))
309 {
310 const Echange_contact_PolyMAC_CDO& cl = ref_cast(Echange_contact_PolyMAC_CDO, cls[i].valeur());
311 if (cl.nom_autre_pb() != autre_pb.le_nom())
312 continue; //not our problem
313 const Front_VF& fvf = ref_cast(Front_VF, cl.frontiere_dis());
314 for (j = 0; j < fvf.nb_faces(); j++) //on peut remplir tous les coeffs, sauf celui de la face elle-meme (rempli par contribuer_a_avec)
315 for (k = 0, f = fvf.num_face(j); k < cl.item.dimension(1) && (l = cl.item(j, k)) >= 0; k++)
316 for (n = 0; n < N; n++)
317 matrice(N * (ne_tot + f) + n, N * l + n) += cl.coeff(j, k + 1, n) - (stab_ ? std::max(delta_f(f, n), cl.delta(j, k, n)) : 0); //operateur + correction non lineaire
318 }
319}
320
321DoubleTab& Op_Diff_PolyMAC_CDO_Elem::ajouter(const DoubleTab& inco, DoubleTab& resu) const
322{
323 const Champ_Elem_PolyMAC_CDO& ch = ref_cast(Champ_Elem_PolyMAC_CDO, equation().inconnue());
324 const Domaine_PolyMAC_CDO& domaine = le_dom_poly_.valeur();
325 const Conds_lim& cls = la_zcl_poly_->les_conditions_limites();
326 const IntTab& e_f = domaine.elem_faces();
327 const DoubleVect& fs = domaine.face_surfaces(), &ve = domaine.volumes();
328 int i, j, e, f, fb, ne_tot = domaine.nb_elem_tot(), n, N = inco.line_size();
329 bool elem_only = polymac_flica5 ? resu.dimension_tot(0) == ne_tot : false;
330 double fac;
331
332 //prerequis : nu, delta en interne + coeffs/delta dans les CL Echange_contact
334 for (i = 0; i < cls.size(); i++)
335 if (sub_type(Echange_contact_PolyMAC_CDO, cls[i].valeur()))
336 ref_cast_non_const(Echange_contact_PolyMAC_CDO, cls[i].valeur()).update_coeffs(), ref_cast(Echange_contact_PolyMAC_CDO, cls[i].valeur()).update_delta();
337 flux_bords_ = 0;
338
339 DoubleTrav nu_ef(e_f.dimension(1), N), mff(N), mfe(N), mee(N);
340 for (e = 0; e < ne_tot; e++)
341 {
342 /* operateur : divergence pour les lignes aux elements, continuite pour les lignes aux faces */
343 int n_f = domaine.m2d(e + 1) - domaine.m2d(e); //nombre de faces de l'element e
344 for (remplir_nu_ef(e, nu_ef), mee = 0, i = 0; i < n_f; i++, mee += mfe)
345 {
346 for (f = e_f(e, i), j = domaine.w2i(domaine.m2d(e) + i), mfe = 0; j < domaine.w2i(domaine.m2d(e) + i + 1); j++, mfe += mff)
347 {
348 for (fb = e_f(e, domaine.w2j(j)), n = 0, fac = fs(f) * fs(fb) / ve(e) * domaine.w2c(j); n < N; n++)
349 mff(n) = fac * nu_ef(domaine.w2j(j), n);
350 if (!elem_only)
351 for (n = 0; ch.fcl()(f, 0) < 6 && n < N; n++)
352 resu(ne_tot + f, n) -= mff(n) * inco(ne_tot + fb, n);
353 if (!elem_only)
354 for (n = 0; f < domaine.premiere_face_int() && n < N; n++)
355 flux_bords_(f, n) -= mff(n) * inco(ne_tot + fb, n);
356 for (n = 0; n < N; n++)
357 resu(e, n) += mff(n) * inco(ne_tot + fb, n);
358
359 //correction non lineaire : partie "faces/faces"
360 if (!elem_only)
361 for (n = 0; stab_ && ch.fcl()(f, 0) < 4 && n < N; n++)
362 resu(ne_tot + f, n) -= std::max(delta_f(f, n), delta_f(fb, n)) * (inco(ne_tot + f, n) - inco(ne_tot + fb, n));
363 }
364 if (!elem_only)
365 for (n = 0; ch.fcl()(f, 0) < 6 && n < N; n++)
366 resu(ne_tot + f, n) += mfe(n) * inco(e, n);
367 for (n = 0; f < domaine.premiere_face_int() && n < N; n++)
368 flux_bords_(f, n) += mfe(n) * inco(e, n);
369
370 //Echange_impose_base
371 if (!elem_only)
372 if (ch.fcl()(f, 0) > 0 && ch.fcl()(f, 0) < 2 && f < domaine.nb_faces())
373 for (n = 0; n < N; n++)
374 resu(ne_tot + f, n) -= fs(f) * ref_cast(Echange_impose_base, cls[ch.fcl()(f, 1)].valeur()).h_imp(ch.fcl()(f, 2), n)
375 * (inco(ch.fcl()(f, 0) == 1 ? ne_tot + f : e, n) - ref_cast(Echange_impose_base, cls[ch.fcl()(f, 1)].valeur()).T_ext(ch.fcl()(f, 2), n));
376
377 //correction non lineaire : parties "elements/faces" et "faces/elements"
378 for (n = 0; stab_ && ch.fcl()(f, 0) < 4 && n < N; n++) //non appliquee aux CLs de Dirichlet ou Neumann
379 {
380 double corr = std::max(delta_e(e, n), delta_f(f, n)) * (inco(e, n) - inco(ne_tot + f, n));
381 resu(e, n) -= corr, resu(ne_tot + f, n) += corr;
382 }
383 }
384 for (n = 0; n < N; n++)
385 resu(e, n) -= mee(n) * inco(e, n);
386 }
387
388 return resu;
389}
390
391void Op_Diff_PolyMAC_CDO_Elem::contribuer_bloc(const DoubleTab& inco, Matrice_Morse& matrice, const int ip) const
392{
393 if (ip > 3 || ip < -1)
394 Process::exit("Op_Diff_PolyMAC_CDO_Elem::contribuer_bloc : invalid bloc number! p must be in [-1, 3]");
395
396 const Champ_Elem_PolyMAC_CDO& ch = ref_cast(Champ_Elem_PolyMAC_CDO, equation().inconnue());
397 const Domaine_PolyMAC_CDO& domaine = le_dom_poly_.valeur();
398 const Conds_lim& cls = la_zcl_poly_->les_conditions_limites();
399 const IntTab& e_f = domaine.elem_faces();
400 const DoubleVect& fs = domaine.face_surfaces(), &ve = domaine.volumes();
401 int i, j, k, l, e, f, fb, ne_tot = domaine.nb_elem_tot(), n, N = inco.line_size();
402 double fac;
403
404 //prerequis : nu, delta en interne + coeffs/delta dans les CL Echange_contact
406 for (i = 0; i < cls.size(); i++)
407 if (sub_type(Echange_contact_PolyMAC_CDO, cls[i].valeur()))
408 ref_cast_non_const(Echange_contact_PolyMAC_CDO, cls[i].valeur()).update_coeffs(), ref_cast(Echange_contact_PolyMAC_CDO, cls[i].valeur()).update_delta();
409
410 /* operateur : divergence pour les lignes aux elements, continuite pour les lignes aux faces */
411 DoubleTrav nu_ef(e_f.dimension(1), N), mff(N), mfe(N), mee(N);
412 for (e = 0; e < ne_tot; e++)
413 {
414 int n_f = domaine.m2d(e + 1) - domaine.m2d(e); //nombre de faces de l'element e
415 for (remplir_nu_ef(e, nu_ef), mee = 0, i = 0; i < n_f; i++, mee += mfe)
416 {
417 for (f = e_f(e, i), j = domaine.w2i(domaine.m2d(e) + i), mfe = 0; j < domaine.w2i(domaine.m2d(e) + i + 1); j++, mfe += mff)
418 {
419 for (fb = e_f(e, domaine.w2j(j)), n = 0, fac = fs(f) * fs(fb) / ve(e) * domaine.w2c(j); n < N; n++)
420 mff(n) = fac * nu_ef(domaine.w2j(j), n);
421 for (n = 0; f < domaine.nb_faces() && ((ch.fcl()(f, 0) < 6 && ch.fcl()(fb, 0) < 6) || ip > -1) && n < N; n++)
422 {
423 if (ip == -1)
424 matrice(N * (ne_tot + f) + n, N * (ne_tot + fb) + n) += mff(n);
425 else if (ip == 3)
426 matrice(N * f + n, N * fb + n) += mff(n);
427 }
428 for (n = 0; e < domaine.nb_elem() && ch.fcl()(fb, 0) < 6 && n < N; n++)
429 {
430 if (ip == -1)
431 matrice(N * e + n, N * (ne_tot + fb) + n) -= mff(n);
432 else if (ip == 1)
433 matrice(N * e + n, N * fb + n) -= mff(n);
434 }
435
436 //correction non lineaire : partie "faces/faces"
437 for (n = 0; stab_ && ch.fcl()(f, 0) < 4 && f < domaine.nb_faces() && n < N; n++)
438 for (k = 0, fac = std::max(delta_f(f, n), delta_f(fb, n)); k < 2; k++)
439 {
440 if (ip == -1)
441 matrice(N * (ne_tot + f) + n, N * (ne_tot + (k ? fb : f)) + n) += (k ? -1 : 1) * fac;
442 else if (ip == 3)
443 matrice(N * f + n, N * (k ? fb : f) + n) += (k ? -1 : 1) * fac;
444 }
445 }
446 for (n = 0; f < domaine.nb_faces() && (ch.fcl()(f, 0) < 6 || ip > -1) && n < N; n++)
447 {
448 if (ip == -1)
449 matrice(N * (ne_tot + f) + n, N * e + n) -= mfe(n);
450 else if (ip == 2)
451 matrice(N * f + n, N * e + n) -= mfe(n);
452 }
453
454 //Echange_impose_base
455 if (ch.fcl()(f, 0) == 1 && f < domaine.nb_faces())
456 for (n = 0; n < N; n++)
457 {
458 if (ip == -1)
459 matrice(N * (ne_tot + f) + n, N * (ch.fcl()(f, 0) == 1 ? ne_tot + f : e) + n) += fs(f) * ref_cast(Echange_impose_base, cls[ch.fcl()(f, 1)].valeur()).h_imp(ch.fcl()(f, 2), n);
460 else
461 Process::exit("Echange_impose_base et diffusion explicite : pas bon!");
462 }
463 else if (ch.fcl()(f, 0) == 3 && f < domaine.nb_faces()) //paroi_contact gere en monolithique -> ajout du coeff a la face issu de l'autre cote
464 {
465 const Echange_contact_PolyMAC_CDO& cl = ref_cast(Echange_contact_PolyMAC_CDO, cls[ch.fcl()(f, 1)].valeur());
466 for (j = ch.fcl()(f, 2), n = 0; n < N; n++)
467 {
468 if (ip == -1)
469 matrice(N * (ne_tot + f) + n, N * (ne_tot + f) + n) += cl.coeff(j, 0, n); //coeff de la face elle-meme
470 else
471 Process::exit("Echange_impose_base et diffusion explicite : pas bon!");
472 }
473 for (k = 0; stab_ && k < cl.item.dimension(1) && cl.item(j, k) >= 0; k++)
474 for (n = 0; n < N; n++) //correction non lineaire
475 {
476 if (ip == -1)
477 matrice(N * (ne_tot + f) + n, N * (ne_tot + f) + n) += std::max(delta_f(f, n), cl.delta(j, k, n));
478 else
479 Process::exit("Echange_impose_base et diffusion explicite : pas bon!");
480 }
481 }
482
483 //correction non lineaire : parties "elements/faces" et "faces/elements"
484 for (n = 0; stab_ && ch.fcl()(f, 0) < 4 && n < N; n++) //non appliquee aux CLs de Dirichlet ou Neumann
485 {
486 double corr = std::max(delta_e(e, n), delta_f(f, n));
487 for (k = 0; k < 2; k++)
488 for (l = 0; (k ? (f < domaine.nb_faces()) : (e < domaine.nb_elem())) && l < 2; l++)
489 {
490 if (ip == -1)
491 matrice(N * (k ? ne_tot + f : e) + n, N * (l ? ne_tot + f : e) + n) += (k == l ? 1 : -1) * corr;
492 else
493 Process::exit("Echange_impose_base et diffusion explicite : pas bon!");
494 }
495 }
496 }
497 for (n = 0; e < domaine.nb_elem() && n < N; n++)
498 if (ip == -1 || (ip == 0))
499 matrice(N * e + n, N * e + n) += mee(n);
500 }
501
502}
503
504void Op_Diff_PolyMAC_CDO_Elem::contribuer_a_avec(const DoubleTab& inco, Matrice_Morse& matrice) const
505{
506 const Domaine_PolyMAC_CDO& domaine = le_dom_poly_.valeur();
507 const int ne_tot = domaine.nb_elem_tot(), nf_tot = domaine.nb_faces_tot();
508 int i = -1;
509 if (matrice.nb_lignes() == ne_tot && matrice.nb_colonnes() == ne_tot) i = 0;
510 if (matrice.nb_lignes() == ne_tot && matrice.nb_colonnes() == nf_tot) i = 1;
511 if (matrice.nb_lignes() == nf_tot && matrice.nb_colonnes() == ne_tot) i = 2;
512 if (matrice.nb_lignes() == nf_tot && matrice.nb_colonnes() == nf_tot) i = 3;
513 contribuer_bloc(inco, matrice, i);
514}
515
520
521static Matrice_Morse FE, FF;
523{
524 if (!polymac_flica5) return;
525// resolution de M_ff T_f = -M_fe T_e
526 DoubleTab sm(inco);
527 sm = 0.;
528 DoubleTab_parts inco_parts(inco);
529 DoubleTab_parts sm_parts(sm);
530
531 // 1. dimensionnement
532 //std::clock_t start = std::clock();
533 if (FF.nb_lignes() == 0)
534 {
535 //Matrice_Morse FE, FF;
536 dimensionner_bloc(FE, 2);
537 dimensionner_bloc(FF, 3);
538 }
539 else
540 {
541 FE.clean();
542 FF.clean();
543 }
544 //Cout << "[Op_Diff_PolyMAC_CDO_Elem] Time to initialize matrix: " << (std::clock() - start) / (double) CLOCKS_PER_SEC << finl;
545 // 2. remplissage
546 contribuer_a_avec(inco, FE);
547 contribuer_a_avec(inco, FF);
548
549 // 3. resolution
550 FE *= -1.;
551 FE.ajouter_multvect(inco_parts[0], sm_parts[1]);
552
553 if (FF.is_diagonal())
554 {
555 const int n = FF.nb_lignes();
556 for (int i = 0; i < n; i++)
557 for (auto k = FF.get_tab1()(i) - 1; k < FF.get_tab1()(i + 1) - 1; k++)
558 inco_parts[1][i] = sm_parts[1][i] / FF.get_coeff()(k);
559 inco_parts[1].echange_espace_virtuel();
560 }
561 else
562 {
563 set_solveur()->reinit();
564 inco_parts[1] = 0.;
565 try
566 {
567 set_solveur().resoudre_systeme(FF, sm_parts[1], inco_parts[1]);
568 }
569 catch(...)
570 {
571 // PL: Crash de Cholesky_lapack sur maillages avec pas de diffusion localement:
572 statistics().end_count(STD_COUNTERS::system_solver,0,0);
573 Nom solv("Petsc Cholesky { quiet }");
574 Cerr << "Echec du solveur dans Op_Diff_PolyMAC_CDO_Elem..." << finl;
575 Cerr << "On change pour un solveur plus robuste (mais plus lent): " << solv << finl;
576 EChaine chl(solv);
577 lire_solveur(chl);
578 solveur.nommer("Op_Diff_PolyMAC_CDO_Elem solver");
579 set_solveur().resoudre_systeme(FF, sm_parts[1], inco_parts[1]);
580 }
581 }
582}
classe Champ_Fonc_base Classe de base des champs qui sont fonction d'une grandeur calculee
const IntTab & fcl() const
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
virtual Frontiere_dis_base & frontiere_dis()
Renvoie la frontiere discretisee a laquelle les conditions aux limites s'appliquent.
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
int elem_faces(int i, int j) const
renvoie le numero de le ieme face de la maille num_elem la facon dont ces faces sont numerotees est
Definition Domaine_VF.h:543
int nb_elem_tot() const
Une entree dont la source est une chaine de caracteres.
Definition EChaine.h:31
classe Echange_impose_base: Cette condition limite sert uniquement pour l'equation d'energie.
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual const RefObjU & get_modele(Type_modele type) const
virtual const Champ_Inc_base & inconnue() const =0
class Front_VF
Definition Front_VF.h:36
int nb_faces() const
Definition Front_VF.h:53
int num_face(const int) const
Definition Front_VF.h:68
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
int nb_colonnes() const override
Return local number of columns (=size on the current proc).
int nb_lignes() const override
Return local number of lines (=size on the current proc).
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)
Classe Modele_turbulence_scal_base Cette classe represente un modele de turbulence pour une equation ...
const Champ_Fonc_base & conductivite_turbulente() const
const Equation_base & equation() const
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
virtual int find(const char *const n) const
Definition Nom.cpp:314
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
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
void dimensionner_bloc(Matrice_Morse &mat, const int p) const
void contribuer_bloc(const DoubleTab &inco, Matrice_Morse &matrice, const int i) const
DoubleTab & ajouter(const DoubleTab &, DoubleTab &) const override
void contribuer_termes_croises(const DoubleTab &inco, const Probleme_base &autre_pb, const DoubleTab &autre_inco, Matrice_Morse &matrice) const override
void dimensionner(Matrice_Morse &mat) const override
DOES NOTHING - to override in derived classes.
void ajouter_termes_croises(const DoubleTab &inco, const Probleme_base &autre_pb, const DoubleTab &autre_inco, DoubleTab &resu) const override
void completer() override
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son equation.
void contribuer_a_avec(const DoubleTab &, Matrice_Morse &) const override
DOES NOTHING - to override in derived classes.
void dimensionner_termes_croises(Matrice_Morse &, const Probleme_base &autre_pb, int nl, int nc) const override
void remplir_nu_ef(int e, DoubleTab &nu_ef) const
void completer() override
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son equation.
void associer_diffusivite_turbulente(const Champ_Fonc_base &)
SolveurSys solveur
SolveurSys & set_solveur()
DoubleTab flux_bords_
Entree & lire_solveur(Entree &)
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Probleme_U.h:109
classe Probleme_base C'est un Probleme_U qui n'est pas un couplage.
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
int resoudre_systeme(const Matrice_Base &matrice, const DoubleVect &secmem, DoubleVect &solution)
Classe de base des flux de sortie.
Definition Sortie.h:52
virtual void declare_support_masse_volumique(int ok)
Le constructeur d'une classe derivee qui se sert de la masse volumique doit appeler cette fonction av...
_SIZE_ dimension_tot(int) const override
Definition TRUSTTab.tpp:160
void append_line(_TYPE_)
Definition TRUSTTab.tpp:213
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
int line_size() const
Definition TRUSTVect.tpp:67
const Objet_U & valeur() const
Definition TRUST_Ref.h:134