TrioCFD 1.9.9_beta
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; //already done
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(); //prerequisite: 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; //numerator / denominator of 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 //'face-face' part
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 //'face-element' part
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 //we can compute delta_e now
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; //already done
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 //prerequisite: delta_int internally + in Echange_contact boundary conditions
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 //final computation of 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 from the other problem via Echange_contact boundary conditions
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 //dependence on Te: diagonal -> faces around each 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 on 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 //upper blocks: 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 //lower blocks: continuity
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 //prerequisites: nu, delta internally + coeffs/delta in Echange_contact boundary conditions
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); //face's own term
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 //operator
285 resu(ne_tot + f, n) -= cl.coeff(j, k + 1, n) * autre_inco(l, n);
286 //nonlinear correction
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 //prerequisites: nu, delta internally + coeffs/delta in Echange_contact boundary conditions
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++) //we can fill all coefficients except the face's own (filled by 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); //operator + nonlinear correction
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 //prerequisites: nu, delta internally + coeffs/delta in Echange_contact boundary conditions
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 /* operator: divergence for element rows, continuity for face rows */
343 int n_f = domaine.m2d(e + 1) - domaine.m2d(e); //number of faces of 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 //nonlinear correction: "faces/faces" part
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 //nonlinear correction: "elements/faces" and "faces/elements" parts
378 for (n = 0; stab_ && ch.fcl()(f, 0) < 4 && n < N; n++) //not applied to Dirichlet or Neumann boundary conditions
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 //prerequisites: nu, delta internally + coeffs/delta in Echange_contact boundary conditions
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 /* operator: divergence for element rows, continuity for face rows */
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); //number of faces of 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 //nonlinear correction: "faces/faces" part
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 handled monolithically -> add coefficient to face from the other side
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); //coefficient of the face itself
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++) //nonlinear correction
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 //nonlinear correction: "elements/faces" and "faces/elements" parts
484 for (n = 0; stab_ && ch.fcl()(f, 0) < 4 && n < N; n++) //not applied to Dirichlet or Neumann boundary conditions
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// solve 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. sizing
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. filling
546 contribuer_a_avec(inco, FE);
547 contribuer_a_avec(inco, FF);
548
549 // 3. solving
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: Cholesky_lapack crash on meshes with no local diffusion:
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}
class Champ_Fonc_base Base class of fields that are functions of a calculated quantity
const IntTab & fcl() const
DoubleTab & valeurs() override
Returns the array of field values at the current time.
virtual Frontiere_dis_base & frontiere_dis()
Returns the discretized boundary to which the boundary conditions apply.
class Conds_lim This class represents a vector of boundary conditions.
Definition Conds_lim.h:32
int elem_faces(int i, int j) const
Returns the index of the i-th face of element num_elem; the face numbering convention is.
Definition Domaine_VF.h:542
int nb_elem_tot() const
An input stream whose source is a character string.
Definition EChaine.h:31
Echange_impose_base: This boundary condition is used only for the energy equation.
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
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
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)
Base class for scalar turbulence models coupled to a Navier-Stokes convection-diffusion equation.
const Champ_Fonc_base & conductivite_turbulente() const
const Equation_base & equation() const
Returns the reference to the equation pointed to by MorEqn::mon_equation.
Definition MorEqn.h:62
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
virtual int find(const char *const n) const
Definition Nom.cpp:309
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
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
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
Associates the operator with the domaine_dis, the domaine_Cl_dis, and the unknown of its 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
Associates the operator with the domaine_dis, the domaine_Cl_dis, and the unknown of its 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
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
Definition Probleme_U.h:109
class Probleme_base It is a Probleme_U that is not a coupling.
static int nproc()
Returns the number of processors in the current group. See Comm_Group::nproc() and PE_Groups::current...
Definition Process.cpp:102
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
int resoudre_systeme(const Matrice_Base &matrice, const DoubleVect &secmem, DoubleVect &solution)
Base class for output streams.
Definition Sortie.h:52
virtual void declare_support_masse_volumique(int ok)
The constructor of a derived class that uses the density field must call this function with the value...
_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