TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Op_Diff_PolyMAC_HFV_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 <Echange_contact_PolyMAC_HFV.h>
17#include <Op_Diff_PolyMAC_HFV_Elem.h>
18#include <Champ_Elem_PolyMAC_HFV.h>
19#include <Echange_externe_impose.h>
20#include <Domaine_PolyMAC_HFV.h>
21#include <Domaine_Cl_PolyMAC_family.h>
22#include <Flux_parietal_base.h>
23#include <Pb_Multiphase.h>
24#include <Matrix_tools.h>
25#include <Array_tools.h>
26#include <deque>
27#include <Perf_counters.h>
28
29Implemente_instanciable_sans_constructeur(Op_Diff_PolyMAC_HFV_Elem, "Op_Diff_PolyMAC_HFV_Elem|Op_Diff_PolyMAC_HFV_var_Elem", Op_Diff_PolyMAC_HFV_base);
30
35
37
39
41{
43 Equation_base& eq = equation();
44 Champ_Elem_PolyMAC_HFV& ch = ref_cast(Champ_Elem_PolyMAC_HFV, le_champ_inco ? le_champ_inco.valeur() : eq.inconnue());
46 const Domaine_PolyMAC_HFV& domaine = ref_cast(Domaine_PolyMAC_HFV, le_dom_poly_.valeur());
47 if (domaine.domaine().nb_joints() && domaine.domaine().joint(0).epaisseur() < 1)
48 {
49 Cerr << "Op_Diff_PolyMAC_HFV_Elem : largeur de joint insuffisante (minimum 1)!" << finl;
51 }
52 flux_bords_.resize(domaine.premiere_face_int(), ch.valeurs().line_size());
53}
54
56{
57 if (op_ext.size())
58 return; //deja fait
59 /* recherche d'operateurs connectes par des Echange_Contact_PolyMAC_HFV (eventuellement indirectement) */
60 std::set<const Op_Diff_PolyMAC_HFV_Elem*> ops_tbd = { this }, ops; //operateurs a scanner pour remplir op_ext, operateurs trouves
61 while (ops_tbd.size())
62 {
63 const Op_Diff_PolyMAC_HFV_Elem *op = *ops_tbd.begin();
64 ops_tbd.erase(ops_tbd.begin()), ops.insert(op);
66 for (const auto &itr : cls)
67 if (sub_type(Echange_contact_PolyMAC_HFV, itr.valeur()))
68 {
69 const Echange_contact_PolyMAC_HFV& cl = ref_cast(Echange_contact_PolyMAC_HFV, itr.valeur());
70 cl.init_op();
71 if (!ops.count(&cl.o_diff.valeur()))
72 ops_tbd.insert(&cl.o_diff.valeur()); //on a un nouvel operateur a scanner
73 }
74 }
75 op_ext = { this };
76 for (auto &&op : ops)
77 if (op != this)
78 op_ext.push_back(op); /* remplissage de op_ext avec l'operateur local en 1er */
79
80 /* remplissage des o_idx des Echange_Contact_PolyMAC_HFV connectes */
82 for (int i = 0; i < cls.size(); i++)
83 if (sub_type(Echange_contact_PolyMAC_HFV, cls[i].valeur()))
84 {
85 const Echange_contact_PolyMAC_HFV& cl = ref_cast(Echange_contact_PolyMAC_HFV, cls[i].valeur());
86 cl.o_idx = (int) (std::find(op_ext.begin(), op_ext.end(), &cl.o_diff.valeur()) - op_ext.begin());
87 }
88}
89
91{
92 const Domaine_PolyMAC_HFV& domaine = ref_cast(Domaine_PolyMAC_HFV, le_dom_poly_.valeur());
93 const IntTab& e_f = domaine.elem_faces();
94 const DoubleTab& nf = domaine.face_normales(), *alp = sub_type(Pb_Multiphase, equation().probleme()) ? &ref_cast(Pb_Multiphase, equation().probleme()).equation_masse().inconnue().passe() : nullptr, &diffu =
96 const DoubleVect& pe = equation().milieu().porosite_elem(), &vf = domaine.volumes_entrelaces(), &ve = domaine.volumes();
97 update_nu();
98
99 int i, e, f, n, N = equation().inconnue().valeurs().dimension(1), cD = diffu.dimension(0) == 1, cL = lambda.dimension(0) == 1;
100 double dt = 1e10;
101 DoubleTrav flux(N);
102 for (e = 0; e < domaine.nb_elem(); e++)
103 {
104 for (flux = 0, i = 0; i < e_f.dimension(1) && (f = e_f(e, i)) >= 0; i++)
105 for (n = 0; n < N; n++)
106 flux(n) += domaine.nu_dot(&nu_, e, n, &nf(f, 0), &nf(f, 0)) / vf(f);
107 for (n = 0; n < N; n++)
108 if ((!alp || (*alp)(e, n) > 1e-3) && flux(n)) /* sous 0.5e-6, on suppose que l'evanescence fait le job */
109 dt = std::min(dt, pe(e) * ve(e) * (alp ? (*alp)(e, n) : 1) * (lambda(!cL * e, n) / diffu(!cD * e, n)) / flux(n));
110 if (dt < 0)
111 abort();
112 }
113 return Process::mp_min(dt);
114}
115
116void Op_Diff_PolyMAC_HFV_Elem::dimensionner_blocs_ext(int aux_only, matrices_t matrices, const tabs_t& semi_impl) const
117{
118 init_op_ext();
119 const std::string& nom_inco = (le_champ_inco ? le_champ_inco.valeur() : equation().inconnue()).le_nom().getString();
120 int i, j, k, l, e, o_e, f, o_f, fb, m, n, M, n_ext = (int) op_ext.size(), n_sten = 0, semi = (int) semi_impl.count(nom_inco);
121 long p;
122 std::vector<Matrice_Morse*> mat(n_ext); //matrices
123 std::vector<int> N, ne_tot; //composantes, nombre d'elements total par pb
124 std::vector<std::reference_wrapper<const Domaine_PolyMAC_HFV>> domaine; //domaines
125 std::vector<std::reference_wrapper<const Conds_lim>> cls; //conditions aux limites
126 std::vector<std::reference_wrapper<const IntTab>> fcl, e_f, f_e; //tableaux "fcl", "elem_faces", "faces_voisins"
127 std::vector<std::reference_wrapper<const DoubleTab>> diffu, inco; //inconnues, normales aux faces, positions elems / faces / sommets
128 std::deque<ConstDoubleTab_parts> v_part; //blocs de chaque inconnue
129 std::vector<Stencil> stencil(n_ext); //stencils par matrice
130 for (i = 0, M = 0; i < n_ext; M = std::max(M, N[i]), i++)
131 {
132 std::string nom_mat = i ? nom_inco + "/" + op_ext[i]->equation().probleme().le_nom().getString() : nom_inco;
133 mat[i] = matrices.count(nom_mat) ? matrices.at(nom_mat) : nullptr;
134 domaine.push_back(std::ref(ref_cast(Domaine_PolyMAC_HFV, op_ext[i]->equation().domaine_dis())));
135 f_e.push_back(std::ref(domaine[i].get().face_voisins())), e_f.push_back(std::ref(domaine[i].get().elem_faces()));
136 cls.push_back(std::ref(op_ext[i]->equation().domaine_Cl_dis().les_conditions_limites()));
137 diffu.push_back(ref_cast(Op_Diff_PolyMAC_HFV_Elem, *op_ext[i]).nu());
138 const Champ_Elem_PolyMAC_HFV& ch = ref_cast(Champ_Elem_PolyMAC_HFV, op_ext[i]->has_champ_inco() ? op_ext[i]->mon_inconnue() : op_ext[i]->equation().inconnue());
139
140 N.push_back(ch.valeurs().line_size()), fcl.push_back(std::ref(ch.fcl())), ne_tot.push_back(domaine[i].get().nb_elem_tot());
141 inco.push_back(ch.valeurs()), v_part.emplace_back(ch.valeurs());
142 stencil[i].resize(0, 2);
143
144 }
145
146 IntTrav tpfa(0, N[0]); //pour suivre quels flux sont a deux points
147 domaine[0].get().creer_tableau_faces(tpfa), tpfa = 1;
148
149 if (!aux_only)
150 Cerr << "Op_Diff_PolyMAC_HFV_Elem::dimensionner() : ";
151 DoubleTrav w2;
152 /* probleme local */
153 for (e = 0; e < ne_tot[0]; e++)
154 {
155 domaine[0].get().W2(&diffu[0].get(), e, w2); //interpolation : [n_ef.nu grad T]_f = w2_{ff'} (T_f' - T_e)
156 //element <-> toutes ses faces (non Dirichlet)
157 if (!aux_only && !semi)
158 for (i = 0; i < w2.dimension(0); i++)
159 if (!semi && fcl[0](f = e_f[0](e, i), 0) < 6)
160 {
161 if (e < domaine[0].get().nb_elem())
162 for (n = 0; n < N[0]; n++)
163 stencil[0].append_line(N[0] * e + n, N[0] * (ne_tot[0] + f) + n);
164 if (f < domaine[0].get().nb_faces())
165 for (n = 0; n < N[0]; n++)
166 stencil[0].append_line(N[0] * (ne_tot[0] + f) + n, N[0] * e + n);
167 }
168 //face <-> face (si les deux sont non Dirichlet)
169 for (i = 0; i < w2.dimension(0); i++)
170 if ((f = e_f[0](e, i)) >= domaine[0].get().nb_faces())
171 continue; //face virtuelle -> rien
172 else if (semi || fcl[0](f = e_f[0](e, i), 0) > 5)
173 for (n = 0; n < N[0]; n++) //Dirichlet ou semi-implicite -> diagonale
174 stencil[0].append_line(N[0] * (!aux_only * ne_tot[0] + f) + n, N[0] * (!aux_only * ne_tot[0] + f) + n);
175 else
176 for (j = 0; j < w2.dimension(1); j++)
177 for (fb = e_f[0](e, j), n = 0; n < N[0]; n++) //cas reel
178 if (fcl[0](fb, 0) < 6 && w2(i, j, n))
179 stencil[0].append_line(N[0] * (!aux_only * ne_tot[0] + f) + n, N[0] * (!aux_only * ne_tot[0] + fb) + n), tpfa(f, n) &= (i == j);
180 }
181 /* problemes distants : pour les Echange_contact */
183 if (!semi)
184 for (i = 0; i < cls[0].get().size(); i++)
185 if ((pcl = sub_type(Echange_contact_PolyMAC_HFV, cls[0].get()[i].valeur()) ? &ref_cast(Echange_contact_PolyMAC_HFV, cls[0].get()[i].valeur()) : nullptr))
186 for (pcl->init_f_dist(), j = 0, p = std::find(op_ext.begin(), op_ext.end(), &pcl->o_diff.valeur()) - op_ext.begin(); j < pcl->fvf->nb_faces(); j++)
187 {
188 f = pcl->fvf->num_face(j), o_f = pcl->f_dist(j), o_e = f_e[p](o_f, 0); //faces cote local/distant, elem cote distant
189 domaine[p].get().W2(&diffu[p].get(), o_e, w2); //matrice w2 de l'autre cote
190 k = (int) (std::find(&e_f[p](o_e, 0), &e_f[p](o_e, 0) + w2.dimension(0), o_f) - &e_f[p](o_e, 0)); //indice de o_f dans o_e
191 if (!aux_only)
192 for (n = 0; n < N[0]; n++)
193 for (m = (N[0] == N[p]) * n; m < (N[0] == N[p] ? n + 1 : N[p]); m++)
194 stencil[p].append_line(N[0] * (ne_tot[0] + f) + n, N[p] * o_e + m); //face <-> elem : compo par compo si N[0] == N[p], tout sinon
195 for (l = 0; l < w2.dimension(0); l++)
196 if (fcl[p](fb = e_f[p](o_e, l), 0) < 6)
197 for (n = 0; n < N[0]; n++)
198 for (m = (N[0] == N[p]) * n; m < (N[0] == N[p] ? n + 1 : N[p]); m++)
199 if (w2(k, l, m))
200 stencil[p].append_line(N[0] * (!aux_only * ne_tot[0] + f) + n, N[p] * (!aux_only * ne_tot[p] + fb) + m);
201 }
202
203 for (i = 0; i < n_ext; i++)
204 if (mat[i])
205 {
206 tableau_trier_retirer_doublons(stencil[i]);
207 Matrice_Morse mat2;
208 Matrix_tools::allocate_morse_matrix(aux_only ? v_part[0][1].size_totale() : inco[0].get().size_totale(), aux_only ? v_part[i][1].size_totale() : inco[i].get().size_totale(), stencil[i], mat2);
209 mat[i]->nb_colonnes() ? *mat[i] += mat2 : *mat[i] = mat2;
210 }
211
212 for (auto &&st : stencil)
213 n_sten += st.dimension(0); //n_sten : nombre total de points du stencil de l'operateur
214 if (!aux_only)
215 {
216 const double elem_face_t = static_cast<double>(domaine[0].get().mdv_elems_faces->nb_items_seq_tot()),
217 face_t = static_cast<double>(domaine[0].get().md_vector_faces()->nb_items_seq_tot());
218 Cerr << "width " << mp_sum_as_double(n_sten) / (N[0] * elem_face_t) << " "
219 << mp_somme_vect_as_double(tpfa) * 100. / (N[0] * face_t) << "% TPFA " << finl;
220 }
221}
222
223void Op_Diff_PolyMAC_HFV_Elem::ajouter_blocs_ext(int aux_only, matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl) const
224{
225 init_op_ext();
226 const std::string& nom_inco = (le_champ_inco ? le_champ_inco.valeur() : equation().inconnue()).le_nom().getString();
227 int i, j, k1, k2, e, f, fb, n, M, n_ext = (int) op_ext.size(), semi = (int) semi_impl.count(nom_inco), d, D = dimension;
228 std::vector<Matrice_Morse*> mat(n_ext); //matrices
229 std::vector<int> N, ne_tot; //composantes
230 std::vector<std::reference_wrapper<const Domaine_PolyMAC_HFV>> domaine; //domaines
231 std::vector<std::reference_wrapper<const Conds_lim>> cls; //conditions aux limites
232 std::vector<std::reference_wrapper<const IntTab>> fcl, e_f, f_e, f_s; //tableaux "fcl", "elem_faces", "faces_voisins"
233 std::vector<std::reference_wrapper<const DoubleVect>> fs, pf, pe, ve; //surfaces
234 std::vector<std::reference_wrapper<const DoubleTab>> inco, xp, xv, diffu, v_aux; //inconnues, normales aux faces, positions elems / faces / sommets
235 std::deque<ConstDoubleTab_parts> v_part; //blocs de chaque inconnue
236 std::vector<const Flux_parietal_base*> corr; //correlations de flux parietal (si elles existent)
237 for (i = 0, M = 0; i < n_ext; M = std::max(M, N[i]), i++)
238 {
239 std::string nom_mat = i ? nom_inco + "/" + op_ext[i]->equation().probleme().le_nom().getString() : nom_inco;
240 mat[i] = matrices.count(nom_mat) ? matrices.at(nom_mat) : nullptr;
241 domaine.push_back(std::ref(ref_cast(Domaine_PolyMAC_HFV, op_ext[i]->equation().domaine_dis())));
242 f_e.push_back(std::ref(domaine[i].get().face_voisins())), e_f.push_back(std::ref(domaine[i].get().elem_faces())), f_s.push_back(std::ref(domaine[i].get().face_sommets()));
243 fs.push_back(std::ref(domaine[i].get().face_surfaces()));
244 xp.push_back(std::ref(domaine[i].get().xp())), xv.push_back(std::ref(domaine[i].get().xv()));
245 pe.push_back(std::ref(equation().milieu().porosite_elem())), pf.push_back(std::ref(equation().milieu().porosite_face())), ve.push_back(std::ref(domaine[i].get().volumes()));
246 cls.push_back(std::ref(op_ext[i]->equation().domaine_Cl_dis().les_conditions_limites()));
247 diffu.push_back(ref_cast(Op_Diff_PolyMAC_HFV_Elem, *op_ext[i]).nu());
248 const Champ_Elem_PolyMAC_HFV& ch = ref_cast(Champ_Elem_PolyMAC_HFV, op_ext[i]->has_champ_inco() ? op_ext[i]->mon_inconnue() : op_ext[i]->equation().inconnue());
249 inco.push_back(std::ref(semi_impl.count(nom_mat) ? semi_impl.at(nom_mat) : ch.valeurs())), v_part.emplace_back(inco.back());
250 corr.push_back(
251 sub_type(Energie_Multiphase, op_ext[i]->equation()) && op_ext[i]->equation().probleme().has_correlation("flux_parietal") ?
252 &ref_cast(Flux_parietal_base, op_ext[i]->equation().probleme().get_correlation("flux_parietal")) : nullptr);
253 N.push_back(inco[i].get().line_size()), ne_tot.push_back(domaine[i].get().nb_elem_tot()), fcl.push_back(std::ref(ch.fcl()));
254 }
255
256 /* que faire avec les variables auxiliaires ? */
257 double t = equation().schema_temps().temps_courant(), dt = equation().schema_temps().pas_de_temps(), fac, prefac;
258 if (aux_only)
259 use_aux_ = 0; /* 1) on est en train d'assembler le systeme de resolution des variables auxiliaires lui-meme */
260 else if (mat[0] && !semi)
261 t_last_aux_ = t + dt, use_aux_ = 0; /* 2) on est en implicite complet : pas besoin de mat_aux / var_aux, on aura les variables a t + dt */
262 else if (t_last_aux_ < t)
263 update_aux(t); /* 3) premier pas a ce temps en semi-implicite : on calcule les variables auxiliaires a t et on les stocke dans var_aux */
264 for (i = 0; i < n_ext; i++)
265 v_aux.push_back(use_aux_ ? ref_cast(Op_Diff_PolyMAC_HFV_Elem, *op_ext[i]).var_aux : v_part[i][1]); /* les variables auxiliaires peuvent etre soit dans inco/semi_impl (cas 1), soit dans var_aux (cas 2) */
266
267 DoubleTrav w2, flux(N[0]), acc(N[0]);
268 for (e = 0; e < ne_tot[0]; e++)
269 {
270 domaine[0].get().W2(&diffu[0].get(), e, w2); //interpolation : [n_ef.nu grad T]_f = w2_{ff'} (T_f' - T_e)
271
272 for (i = 0; i < w2.dimension(0); i++) //seconds membres
273 {
274 for (f = e_f[0](e, i), flux = 0, j = 0; j < w2.dimension(1); j++)
275 for (fb = e_f[0](e, j), n = 0; n < N[0]; n++)
276 flux(n) += w2(i, j, n) * (v_aux[0](fb, n) - inco[0](e, n));
277 if (!semi && fcl[0](f, 0) < 6)
278 for (n = 0; n < N[0]; n++)
279 secmem(!aux_only * ne_tot[0] + f, n) -= flux(n);
280 if (!aux_only)
281 for (n = 0; n < N[0]; n++)
282 secmem(e, n) += flux(n);
283 if (!aux_only && f < domaine[0].get().premiere_face_int())
284 for (n = 0; n < N[0]; n++)
285 flux_bords_(f, n) = flux(n); //flux aux bords
286 }
287
288 if (semi || !mat[0])
289 continue;
290 //matrice: elem-elem
291 for (acc = 0, i = 0; i < w2.dimension(0); i++)
292 for (j = 0; j < w2.dimension(1); j++)
293 for (n = 0; n < N[0]; n++)
294 acc(n) += w2(i, j, n);
295 if (!aux_only && e < domaine[0].get().nb_elem())
296 for (n = 0; n < N[0]; n++)
297 (*mat[0])(N[0] * e + n, N[0] * e + n) += acc(n);
298 //matrice: elem-face
299 if (!aux_only)
300 for (i = 0; i < w2.dimension(0); i++)
301 if (fcl[0](f = e_f[0](e, i), 0) < 6)
302 {
303 for (acc = 0, j = 0; j < w2.dimension(1); j++)
304 for (n = 0; n < N[0]; n++)
305 acc(n) += w2(i, j, n);
306 if (f < domaine[0].get().nb_faces())
307 for (n = 0; n < N[0]; n++)
308 (*mat[0])(N[0] * (ne_tot[0] + f) + n, N[0] * e + n) -= acc(n);
309 if (e < domaine[0].get().nb_elem())
310 for (n = 0; n < N[0]; n++)
311 (*mat[0])(N[0] * e + n, N[0] * (ne_tot[0] + f) + n) -= acc(n);
312 }
313 //matrice : face-face
314 for (i = 0; i < w2.dimension(0); i++)
315 if (fcl[0](f = e_f[0](e, i), 0) < 6 && f < domaine[0].get().nb_faces())
316 for (j = 0; j < w2.dimension(1); j++)
317 if (fcl[0](fb = e_f[0](e, j), 0) < 6)
318 for (n = 0; n < N[0]; n++)
319 if (w2(i, j, n))
320 (*mat[0])(N[0] * (!aux_only * ne_tot[0] + f) + n, N[0] * (!aux_only * ne_tot[0] + fb) + n) += w2(i, j, n);
321 }
322
323 //contributions restantes aux equations aux faces
324 for (f = 0; f < domaine[0].get().nb_faces(); f++)
325 if (!aux_only && semi && mat[0])
326 for (n = 0; n < N[0]; n++) //semi-implicite : T_f^+ = var_aux
327 secmem(ne_tot[0] + f, n) += v_aux[0](f, n) - (le_champ_inco ? le_champ_inco->valeurs() : equation().inconnue().valeurs())(ne_tot[0] + f, n), (*mat[0])(N[0] * (ne_tot[0] + f) + n,
328 N[0] * (ne_tot[0] + f) + n)++;
329 else if (fcl[0](f, 0) == 0 || fcl[0](f, 0) == 5)
330 continue; //face interne ou Neumann_val_ext -> rien
331 else if (corr[0]) //Pb_Multiphase avec flux parietal -> on ne traite (pour le moment) que Dirichlet et Echange_contact
332 {
333 if (fcl[0](f, 0) == 2)
334 abort(); //Echange_global_impose -> on ne sait pas faire (que vaut T_paroi dans l'element?)
335 const Echange_contact_PolyMAC_HFV *ech = fcl[0](f, 0) == 3 ? &ref_cast(Echange_contact_PolyMAC_HFV, cls[0].get()[fcl[0](f, 1)].valeur()) : nullptr;
336 int o_p = ech ? ech->o_idx : -1, o_f = ech ? ech->f_dist(fcl[0](f, 2)) : -1;
337 const Pb_Multiphase& pbm = ref_cast(Pb_Multiphase, equation().probleme());
338 const DoubleTab& alpha = pbm.equation_masse().inconnue().passe(), &dh = pbm.milieu().diametre_hydraulique_elem(),
339 &press = ref_cast(QDM_Multiphase, pbm.equation_qdm()).pression().passe(), &vit = pbm.equation_qdm().inconnue().passe(),
340 &lambda = pbm.milieu().conductivite().passe(), &mu = ref_cast(Fluide_base, pbm.milieu()).viscosite_dynamique().passe(), &rho = pbm.milieu().masse_volumique().passe(), &Cp =
344 DoubleTrav qpk(N[0]), dTf_qpk(N[0], N[0]), dTp_qpk(N[0]), qpi(N[0], N[0]), dTf_qpi(N[0], N[0], N[0]), dTp_qpi(N[0], N[0]), v(N[0], D), nv(N[0]);
345 in.N = N[0], in.f = f, in.D_h = dh(e), in.D_ch = dh(e), in.alpha = &alpha(e, 0), in.T = &v_aux[0](f, 0), in.p = press(e), in.v = nv.addr(), in.lambda = &lambda(e, 0), in.mu = &mu(e, 0), in.rho =
346 &rho(e, 0), in.Cp = &Cp(e, 0);
347 out.qpk = &qpk, out.dTf_qpk = &dTf_qpk, out.dTp_qpk = &dTp_qpk, out.qpi = &qpi, out.dTf_qpi = &dTf_qpi, out.dTp_qpi = &dTp_qpi;
348 for (e = f_e[0](f, 0), i = 0; i < e_f[0].get().dimension(1) && (fb = e_f[0](e, i)) >= 0; i++)
349 for (prefac = fs[0](fb) * pf[0](fb) * (e == f_e[0](fb, 0) ? 1 : -1) / (pe[0](e) * ve[0](e)), n = 0; n < N[0]; n++)
350 for (fac = prefac * vit(fb, n), d = 0; d < D; d++)
351 v(n, d) += fac * (xv[0](fb, d) - xp[0](e, d));
352 for (n = 0; n < N[0]; n++)
353 nv(n) = sqrt(domaine[0].get().dot(&v(n, 0), &v(n, 0)));
354 //Tparoi : estimation initiale + Newton si on ne la connait pas
355 double h_imp = fcl[0](f, 0) == 1 ? ref_cast(Echange_impose_base, cls[0].get()[fcl[0](f, 1)].valeur()).h_imp(fcl[0](f, 2), 0) : 0, T_ext =
356 fcl[0](f, 0) == 1 ? ref_cast(Echange_impose_base, cls[0].get()[fcl[0](f, 1)].valeur()).T_ext(fcl[0](f, 2), 0) : 0, dTp, FT, dFTp;
357 in.Tp = ech ? v_aux[o_p](o_f, 0) : fcl[0](f, 0) == 5 ? 0 : fcl[0](f, 0) == 6 ? ref_cast(Dirichlet, cls[0].get()[fcl[0](f, 1)].valeur()).val_imp(fcl[0](f, 2), 0) :
358 fcl[0](f, 0) == 1 ? T_ext : v_aux[0](f, 0);
359 //appel : on n'est implicite qu'en les temperatures
360 dTp = 0;
361 for (int it = 0; it < 10 && (!it || std::abs(dTp) > 1e-5); in.Tp += dTp, it++)
362 {
363 corr[0]->qp(in, out);
364 for (FT = 0, dFTp = 0; n < N[0]; n++)
365 FT += qpk(n), dFTp += dTp_qpk(n);
366 dTp = fcl[0](f, 0) == 5 ? (ref_cast(Neumann, cls[0].get()[fcl[0](f, 1)].valeur()).flux_impose(fcl[0](f, 2), 0) - FT) / dFTp :
367 fcl[0](f, 0) == 1 ? (h_imp * (T_ext - in.Tp) - FT) / (dFTp + h_imp) : 0;
368 }
369 for (n = 0; n < N[0]; n++)
370 secmem(!aux_only * ne_tot[0] + f, n) += fs[0](f) * qpk(n); //second membre
371 if (mat[0])
372 for (k1 = 0; k1 < N[0]; k1++)
373 for (k2 = 0; k2 < N[0]; k2++) //derivees en Tfluide
374 (*mat[0])(N[0] * (!aux_only * ne_tot[0] + f) + k1, N[0] * (!aux_only * ne_tot[0] + f) + k2) -= fs[0](f) * dTf_qpk(k1, k2);
375 if (ech && mat[o_p])
376 for (n = 0; n < N[0]; n++) /* derivees en Tparoi (si Echange_contact) */
377 (*mat[o_p])(N[0] * (!aux_only * ne_tot[0] + f) + n, !aux_only * ne_tot[o_p] + o_f) -= fs[0](f) * dTp_qpk(n);
378 }
379 else if (fcl[0](f, 0) > 5)
380 for (n = 0; n < N[0]; n++) //Dirichlet : T_f^+ = T_b
381 {
382 secmem(!aux_only * ne_tot[0] + f, n) += (fcl[0](f, 0) == 6 ? ref_cast(Dirichlet, cls[0].get()[fcl[0](f, 1)].valeur()).val_imp(fcl[0](f, 2), n) : 0) - v_aux[0](f, n);
383 if (mat[0])
384 (*mat[0])(N[0] * (!aux_only * ne_tot[0] + f) + n, N[0] * (!aux_only * ne_tot[0] + f) + n)++;
385 }
386 else if (fcl[0](f, 0) == 3) //Echange_contact
387 {
388 const Echange_contact_PolyMAC_HFV& ech = ref_cast(Echange_contact_PolyMAC_HFV, cls[0].get()[fcl[0](f, 1)].valeur());
389 int o_p = ech.o_idx, o_f = ech.f_dist(fcl[0](f, 2)), o_e = f_e[o_p](o_f, 0); //autre pb/face/elem
390 if (corr[o_p] || N[o_p] != N[0]) /* correlation de l'autre cote */
391 {
392 const Pb_Multiphase& pbm = ref_cast(Pb_Multiphase, op_ext[o_p]->equation().probleme());
393 const DoubleTab& alpha = pbm.equation_masse().inconnue().passe(), &dh = pbm.milieu().diametre_hydraulique_elem(),
394 &press = ref_cast(QDM_Multiphase, pbm.equation_qdm()).pression().passe(), &vit = pbm.equation_qdm().inconnue().passe(),
395 &lambda = pbm.milieu().conductivite().passe(), &mu = ref_cast(Fluide_base, pbm.milieu()).viscosite_dynamique().passe(), &rho = pbm.milieu().masse_volumique().passe(), &Cp =
397 DoubleTrav qpk(N[o_p]), dTf_qpk(N[o_p], N[o_p]), dTp_qpk(N[o_p]), qpi(N[o_p], N[o_p]), dTf_qpi(N[o_p], N[o_p], N[o_p]), dTp_qpi(N[o_p], N[o_p]), v(N[o_p], D), nv(N[o_p]);
398 for (i = 0; i < e_f[o_p].get().dimension(1) && (fb = e_f[o_p](o_e, i)) >= 0; i++)
399 for (prefac = fs[o_p](fb) * pf[o_p](fb) * (o_e == f_e[o_p](fb, 0) ? 1 : -1) / (pe[o_p](o_e) * ve[o_p](o_e)), n = 0; n < N[o_p]; n++)
400 for (fac = prefac * vit(fb, n), d = 0; d < D; d++)
401 v(n, d) += fac * (xv[o_p](fb, d) - xp[o_p](o_e, d));
402 for (n = 0; n < N[o_p]; n++)
403 nv(n) = sqrt(domaine[0].get().dot(&v(n, 0), &v(n, 0)));
404 //appel : on n'est implicite qu'en les temperatures
407
408 in.N = N[o_p], in.f = o_f, in.D_h = dh(o_e), in.D_ch = dh(o_e), in.alpha = &alpha(o_e, 0), in.T = &v_aux[o_p](o_f, 0), in.p = press(e), in.v = nv.addr(), in.Tp = v_aux[0](f, 0), in.lambda =
409 &lambda(o_e, 0), in.mu = &mu(o_e, 0), in.rho = &rho(o_e, 0), in.Cp = &Cp(o_e, 0);
410 out.qpk = &qpk, out.dTf_qpk = &dTf_qpk, out.dTp_qpk = &dTp_qpk, out.qpi = &qpi, out.dTf_qpi = &dTf_qpi, out.dTp_qpi = &dTp_qpi, out.nonlinear = &j;
411 corr[o_p]->qp(in, out);
412 for (n = 0; n < N[o_p]; n++)
413 secmem(!aux_only * ne_tot[0] + f, 0) -= fs[0](f) * qpk(n); //second membre
414 if (mat[o_p])
415 for (k1 = 0; k1 < N[o_p]; k1++)
416 for (k2 = 0; k2 < N[o_p]; k2++) //derivees en Tfluide
417 (*mat[o_p])(!aux_only * ne_tot[0] + f, N[o_p] * (!aux_only * ne_tot[o_p] + o_f) + k2) += fs[0](f) * dTf_qpk(k1, k2);
418 if (mat[0])
419 for (n = 0; n < N[o_p]; n++) /* derivees en Tparoi */
420 (*mat[0])(!aux_only * ne_tot[0] + f, !aux_only * ne_tot[0] + f) += fs[0](f) * dTp_qpk(n);
421 }
422 else if (ech.invh_paroi)
423 for (n = 0; n < N[0]; n++)/* resistance de la paroi -> ajout du h(T'-T) */
424 {
425 secmem(!aux_only * ne_tot[0] + f, n) -= fs[0](f) / ech.invh_paroi * (v_aux[0](f, n) - v_aux[o_p](o_f, n)); //second membre
426 if (mat[0])
427 (*mat[0])(N[0] * (!aux_only * ne_tot[0] + f) + n, N[0] * (!aux_only * ne_tot[0] + f) + n) += fs[0](f) / ech.invh_paroi; //derivees
428 if (mat[o_p])
429 (*mat[o_p])(N[0] * (!aux_only * ne_tot[0] + f) + n, N[o_p] * (!aux_only * ne_tot[o_p] + o_f) + n) -= fs[0](f) / ech.invh_paroi;
430 }
431 else
432 for (domaine[o_p].get().W2(&diffu[o_p].get(), o_e, w2), i = 0; i < w2.dimension(0); i++) /* pas de resistance -> ajout du flux de l'autre cote */
433 if (e_f[o_p](o_e, i) == o_f)
434 for (j = 0; j < w2.dimension(1); j++)
435 for (n = 0; n < N[0]; n++)
436 if (w2(i, j, n))
437 {
438 secmem(!aux_only * ne_tot[0] + f, n) -= w2(i, j, n) * (v_aux[o_p * (j != i)](j != i ? e_f[o_p](o_e, j) : f, n) - inco[o_p](o_e, n)); //second membre
439 if (mat[o_p * (j != i)] && (j == i || fcl[o_p](o_f, 0) < 6)) //autre face: on substitue T_fb par T_f
440 (*mat[o_p * (j != i)])(N[0] * (!aux_only * ne_tot[0] + f) + n, N[0] * (!aux_only * ne_tot[o_p * (j != i)] + (j != i ? e_f[o_p](o_e, j) : f)) + n) += w2(i, j, n);
441 if (!aux_only && mat[o_p])
442 (*mat[o_p])(N[0] * (ne_tot[0] + f) + n, N[0] * o_e + n) -= w2(i, j, n); //autre element
443 }
444 }
445 else if (fcl[0](f, 0) == 4)
446 for (n = 0; n < N[0]; n++) //Neumann
447 secmem(!aux_only * ne_tot[0] + f, n) += fs[0](f) * ref_cast(Neumann, cls[0].get()[fcl[0](f, 1)].valeur()).flux_impose(fcl[0](f, 2), n);
448 else if (fcl[0](f, 0) && fcl[0](f, 0) < 3)
449 for (e = f_e[0](f, 0), n = 0; n < N[0]; n++) //Echange_global_impose
450 {
451 const Echange_impose_base& ech = ref_cast(Echange_impose_base, cls[0].get()[fcl[0](f, 1)].valeur());
452 double h = ech.h_imp(fcl[0](f, 2), n), T = ech.T_ext(fcl[0](f, 2), n);
453 secmem(!aux_only * ne_tot[0] + f, n) -= fs[0](f) * h * ((fcl[0](f, 0) == 1 ? v_aux[0](f, n) : inco[0](e, n)) - T);
454 if (mat[0] && fcl[0](f, 0) == 1)
455 (*mat[0])(N[0] * (!aux_only * ne_tot[0] + f) + n, N[0] * (!aux_only * ne_tot[0] + f) + n) += h * fs[0](f);
456 if (mat[0] && fcl[0](f, 0) == 2 && !aux_only)
457 (*mat[0])(N[0] * (ne_tot[0] + f) + n, N[0] * e + n) += h * fs[0](f);
458 }
459}
: class Champ_Elem_PolyMAC_HFV
const IntTab & fcl() const
DoubleTab & passe(int i=1) override
Renvoie les valeurs du champs a l'instant t-i.
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
virtual DoubleTab & valeurs()=0
virtual DoubleTab & passe(int i=1)
Definition Champ_Proto.h:50
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
classe Dirichlet Cette classe est la classe de base de la hierarchie des conditions aux limites de ty...
Definition Dirichlet.h:31
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
classe : Echange_contact_PolyMAC_HFV Outre le champ_front representant la temperature de paroi,
classe Echange_impose_base: Cette condition limite sert uniquement pour l'equation d'energie.
classe Energie_Multiphase Cas particulier de Convection_Diffusion_std pour un fluide quasi conpressib...
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
classe Equation_base Le role d'une equation est le calcul d'un ou plusieurs champs....
virtual const Milieu_base & milieu() const =0
virtual const Champ_Inc_base & inconnue() const =0
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Renvoie le domaine des conditions aux limite discretisee associee a l'equation.
Schema_Temps_base & schema_temps()
Renvoie le schema en temps associe a l'equation.
classe Fluide_base Cette classe represente un d'un fluide incompressible ainsi que
Definition Fluide_base.h:38
classe Flux_parietal_base correlations de flux parietal de la forme
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
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)
DoubleVect & porosite_elem()
Definition Milieu_base.h:58
virtual const Champ_Don_base & capacite_calorifique() const
Renvoie la capacite calorifique du milieu.
virtual const Champ_Don_base & conductivite() const
Renvoie la conductivite du milieu.
virtual const Champ_base & masse_volumique() const
Renvoie la masse volumique du milieu.
DoubleTab & diametre_hydraulique_elem()
Definition Milieu_base.h:70
const Equation_base & equation() const
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
Classe Neumann Cette classe est la classe de base de la hierarchie des conditions aux limites de type...
Definition Neumann.h:31
static int dimension
Definition Objet_U.h:99
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
const Champ_base & diffusivite() const override
void dimensionner_blocs_ext(int aux_only, matrices_t matrices, const tabs_t &semi_impl={ }) const override
void completer() override
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son equation.
double calculer_dt_stab() const override
Calcul dt_stab.
void ajouter_blocs_ext(int aux_only, matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={ }) const override
class Op_Diff_PolyMAC_HFV_base
void completer() override
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son equation.
std::vector< const Operateur_Diff_base * > op_ext
virtual const Champ_base & diffusivite_pour_pas_de_temps() const
Renvoie le champ_don correspondant a la vraie diffusivite du milieu qui sert pour le calcul du pas de...
DoubleTab flux_bords_
bool has_champ_inco() const
const Champ_Inc_base & mon_inconnue() const
classe Pb_Multiphase Cette classe represente un probleme de thermohydraulique multiphase de type "3*N...
virtual Equation_base & equation_qdm()
virtual Equation_base & equation_masse()
virtual const Milieu_base & milieu() const
Renvoie le milieu physique associe au probleme.
static double mp_min(double)
Definition Process.cpp:386
static void abort()
Routine de sortie de Trio-U sur une erreur abort().
Definition Process.cpp:570
static double mp_sum_as_double(int v)
Definition Process.h:99
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
classe QDM_Multiphase Cette classe porte les termes de l'equation de la dynamique
double temps_courant() const
Renvoie le temps courant.
double pas_de_temps() const
Renvoie le pas de temps (delta_t) courant.
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...
_TYPE_ * addr()
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