TrioCFD 1.9.9_beta
TrioCFD documentation
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; //already done
59 /* search for operators connected through Echange_Contact_PolyMAC_HFV (possibly indirectly) */
60 std::set<const Op_Diff_PolyMAC_HFV_Elem*> ops_tbd = { this }, ops; //operators to scan to fill op_ext, operators found
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()); //a new operator to scan
73 }
74 }
75 op_ext = { this };
76 for (auto &&op : ops)
77 if (op != this)
78 op_ext.push_back(op); /* fill op_ext with the local operator first */
79
80 /* fill o_idx of the connected Echange_Contact_PolyMAC_HFV */
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)) /* below 0.5e-6, assume evanescence handles it */
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; //components, total number of elements per problem
124 std::vector<std::reference_wrapper<const Domaine_PolyMAC_HFV>> domaine; //domains
125 std::vector<std::reference_wrapper<const Conds_lim>> cls; //boundary conditions
126 std::vector<std::reference_wrapper<const IntTab>> fcl, e_f, f_e; //arrays "fcl", "elem_faces", "faces_voisins"
127 std::vector<std::reference_wrapper<const DoubleTab>> diffu, inco; //unknowns, face normals, element/face/vertex positions
128 std::deque<ConstDoubleTab_parts> v_part; //blocks of each unknown
129 std::vector<Stencil> stencil(n_ext); //stencils per matrix
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]); //to track which fluxes are two-point
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 <-> all its 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 (if both are 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; //virtual face -> nothing to do
172 else if (semi || fcl[0](f = e_f[0](e, i), 0) > 5)
173 for (n = 0; n < N[0]; n++) //Dirichlet or semi-implicit -> diagonal
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++) //real case
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 /* remote problems: for 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); //local/remote face sides, remote element side
189 domaine[p].get().W2(&diffu[p].get(), o_e, w2); //w2 matrix on the other side
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)); //index of o_f in 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: component by component if N[0] == N[p], all otherwise
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: total number of stencil points of the operator
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; //components
230 std::vector<std::reference_wrapper<const Domaine_PolyMAC_HFV>> domaine; //domains
231 std::vector<std::reference_wrapper<const Conds_lim>> cls; //boundary conditions
232 std::vector<std::reference_wrapper<const IntTab>> fcl, e_f, f_e, f_s; //arrays "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; //unknowns, face normals, element/face/vertex positions
235 std::deque<ConstDoubleTab_parts> v_part; //blocks of each unknown
236 std::vector<const Flux_parietal_base*> corr; //wall flux correlations (if they exist)
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 /* what to do with auxiliary variables? */
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) assembling the resolution system for auxiliary variables itself */
260 else if (mat[0] && !semi)
261 t_last_aux_ = t + dt, use_aux_ = 0; /* 2) fully implicit: no need for mat_aux / var_aux, variables will be at t + dt */
262 else if (t_last_aux_ < t)
263 update_aux(t); /* 3) first step at this time in semi-implicit: compute auxiliary variables at t and store in 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]); /* auxiliary variables are either in inco/semi_impl (case 1) or in var_aux (case 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++) //right-hand side contributions
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); //boundary fluxes
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 //remaining contributions to face equations
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-implicit: 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; //internal face or Neumann_val_ext -> nothing to do
331 else if (corr[0]) //Pb_Multiphase with wall flux -> only Dirichlet and Echange_contact handled (for now)
332 {
333 if (fcl[0](f, 0) == 2)
334 abort(); //Echange_global_impose -> not implemented (what is T_paroi in the 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: initial estimate + Newton if not known
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 //call: implicit only in 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); //right-hand side
371 if (mat[0])
372 for (k1 = 0; k1 < N[0]; k1++)
373 for (k2 = 0; k2 < N[0]; k2++) //derivatives with respect to 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++) /* derivatives with respect to Tparoi (if 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); //other problem/face/element
390 if (corr[o_p] || N[o_p] != N[0]) /* wall flux correlation on the other side */
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 //call: implicit only in 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); //right-hand side
414 if (mat[o_p])
415 for (k1 = 0; k1 < N[o_p]; k1++)
416 for (k2 = 0; k2 < N[o_p]; k2++) //derivatives with respect to 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++) /* derivatives with respect to 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++)/* wall resistance: adding the h(T'-T) term */
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)); //right-hand side
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; //derivatives
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++) /* no resistance: adding the flux from the other side */
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)); //right-hand side
439 if (mat[o_p * (j != i)] && (j == i || fcl[o_p](o_f, 0) < 6)) //other face: substitute T_fb by 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); //other 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
Returns field values at instant t-i.
DoubleTab & valeurs() override
Returns the array of field values at the current time.
virtual DoubleTab & valeurs()=0
virtual DoubleTab & passe(int i=1)
Definition Champ_Proto.h:50
class Conds_lim This class represents a vector of boundary conditions.
Definition Conds_lim.h:32
Dirichlet This class is the base class of the hierarchy of Dirichlet-type boundary conditions.
Definition Dirichlet.h:31
const Cond_lim & les_conditions_limites(int) const
Returns the i-th boundary condition.
class : Echange_contact_PolyMAC_HFV
Echange_impose_base: This boundary condition is used only for the energy equation.
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 const Milieu_base & milieu() const =0
virtual const Champ_Inc_base & inconnue() const =0
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Returns the discretized boundary condition domain associated with the equation.
Schema_Temps_base & schema_temps()
Returns the time scheme associated with the equation.
Base class for an incompressible fluid and its properties:
Definition Fluide_base.h:36
Base class for wall heat flux correlations of the form:
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
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
Returns the heat capacity of the medium (const version).
virtual const Champ_Don_base & conductivite() const
Returns the conductivity of the medium (const version).
virtual const Champ_base & masse_volumique() const
Returns the mass density of the medium (const version).
DoubleTab & diametre_hydraulique_elem()
Definition Milieu_base.h:70
const Equation_base & equation() const
Returns the reference to the equation pointed to by MorEqn::mon_equation.
Definition MorEqn.h:62
Classe Neumann This class is the base class of the hierarchy of Neumann-type boundary conditions.
Definition Neumann.h:31
static int dimension
Definition Objet_U.h:94
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
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
Associates the operator with the domaine_dis, the domaine_Cl_dis, and the unknown of its equation.
double calculer_dt_stab() const override
Computes 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
Associates the operator with the domaine_dis, the domaine_Cl_dis, and the unknown of its equation.
std::vector< const Operateur_Diff_base * > op_ext
virtual const Champ_base & diffusivite_pour_pas_de_temps() const
Returns the field corresponding to the true diffusivity of the medium used for the time step computat...
DoubleTab flux_bords_
bool has_champ_inco() const
const Champ_Inc_base & mon_inconnue() const
Multiphase thermohydraulics problem of type "3*N equations":
virtual Equation_base & equation_qdm()
virtual Equation_base & equation_masse()
virtual const Milieu_base & milieu() const
Returns the physical medium associated with the problem (const version).
static double mp_min(double)
Definition Process.cpp:391
static void abort()
Abort routine for TRUST on a fatal error.
Definition Process.cpp:573
static double mp_sum_as_double(int v)
Definition Process.h:97
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
Carries the terms of the momentum equation for multiphase flow without turbulence modelling.
double temps_courant() const
Returns the current time.
double pas_de_temps() const
Returns the current time step (delta_t).
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...
_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