TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Op_Div_DG.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 <Op_Div_DG.h>
17#include <Check_espace_virtuel.h>
18#include <Domaine_Cl_DG.h>
19#include <Navier_Stokes_std.h>
20#include <Schema_Temps_base.h>
21#include <Probleme_base.h>
22#include <EcrFicPartage.h>
23#include <Matrice_Morse.h>
24#include <Matrix_tools.h>
25#include <Array_tools.h>
26#include <SFichier.h>
27#include <Debog.h>
28#include <BasisFunction.h>
29#include <Champ_front_txyz.h>
30#include <Champ_front_softanalytique.h>
31#include <Neumann_paroi.h>
32#include <Dirichlet.h>
33
34Implemente_instanciable(Op_Div_DG, "Op_Div_DG", Operateur_Div_base);
35
36Sortie& Op_Div_DG::printOn(Sortie& s) const { return s << que_suis_je(); }
37
38Entree& Op_Div_DG::readOn(Entree& s) { return s; }
39
40void Op_Div_DG::associer(const Domaine_dis_base& domaine_dis, const Domaine_Cl_dis_base& domaine_Cl_dis, const Champ_Inc_base&)
41{
42 le_dom_DG = ref_cast(Domaine_DG, domaine_dis);
43 le_dcl_DG = ref_cast(Domaine_Cl_DG, domaine_Cl_dis);
44}
45
47{
49 op_diff_ = ref_cast(Op_Diff_DG_base, equation().operateur(0).l_op_base());
50}
51
52/**
53 * @brief Sizes the velocity-pressure and pressure-pressure matrix blocks.
54 *
55 * @details Builds two sparsity patterns depending on what is needed:
56 *
57 * - **Velocity-pressure block** (matv, always built when the "vitesse" matrix is present):
58 * Each pressure DOF of element T is coupled to all velocity DOFs of T and its
59 * face-neighbours, as given by the pre-computed stencil. The block has
60 * size_p rows and size_v columns.
61 *
62 * - **Pressure-pressure block** (matp, only built when order_v == order_p):
63 * Required for the equal-order pressure stabilization term. Each pressure DOF of
64 * element T is coupled to all pressure DOFs of T and its face-neighbours.
65 * When order_v != order_p, a minimal dummy pattern (one non-zero) is allocated
66 * to satisfy the matrix infrastructure without adding real entries.
67 *
68 * @param matrices Map of matrix name → Matrice_Morse pointer to be sized.
69 * @param semi_impl Map of semi-implicit field names; if "vitesse" is present, returns immediately.
70 */
71void Op_Div_DG::dimensionner_blocs(matrices_t matrices, const tabs_t& semi_impl) const
72{
73
74 if (!matrices.count("vitesse"))
75 return; // rien a faire
76 if (semi_impl.count("vitesse"))
77 return; // semi-implicite -> rien a dimensionner
78
79 Matrice_Morse *matv = matrices.count("vitesse") ? matrices["vitesse"] : nullptr,
80 *matp = matrices.count("pression") ? matrices["pression"] : nullptr,
81 matv2, matp2;
82
83 const Domaine_DG& domaine = le_dom_DG.valeur();
84
85 int order_v = Option_DG::Get_order_for("vitesse");
86 int order_p = Option_DG::Get_order_for("pression");
87
88 const BasisFunction& bfunc_v = domaine.get_basisFunction(order_v);
89 const int nb_bfunc_v = bfunc_v.nb_bfunc();
90
91 const BasisFunction& bfunc_p = domaine.get_basisFunction(order_p);
92 const int nb_bfunc_p = bfunc_p.nb_bfunc();
93
94 int dim = Objet_U::dimension;
95 const IntTab& indices_glob_elem_v = bfunc_v.indices_glob_elem(dim);
96 const IntTab& indices_glob_elem_p = bfunc_p.indices_glob_elem();
97
98 int nb_elem_tot = domaine.nb_elem_tot();
99
100 int size_row = indices_glob_elem_p(nb_elem_tot);
101 int size_col = indices_glob_elem_v(nb_elem_tot);
102
103 const Stencil& stencil_sorted = domaine.get_stencil_sorted();
104 const int nb_stencil_max = stencil_sorted.dimension(1);
105
106 int nb_indices_line;
107 int row, col, indice;
108
109 if (matv)
110 {
111 matv2.dimensionner(size_row, size_col, 0);
112
113 auto& tabv1 = matv2.get_set_tab1();
114 auto& tabv2 = matv2.get_set_tab2();
115 auto& coeff = matv2.get_set_coeff();
116 coeff = 0;
117 tabv1(0) = 1;
118 for (int nelem = 0; nelem < nb_elem_tot; nelem++)
119 {
120 nb_indices_line = 0;
121 for (int k = 0; k < nb_stencil_max; k++)
122 {
123 if (stencil_sorted(nelem, k) < 0)
124 break;
125 nb_indices_line += nb_bfunc_v * dim;
126 }
127 for (int k = 0; k < nb_bfunc_p; k++)
128 tabv1(indices_glob_elem_p(nelem) + k + 1) = nb_indices_line + tabv1(indices_glob_elem_p(nelem) + k);
129 }
130
131 matv2.dimensionner(size_row, size_col, tabv1(size_row) - 1);
132
133 for (int nelem = 0; nelem < nb_elem_tot; nelem++)
134 {
135 row = tabv1[indices_glob_elem_p(nelem)] - 1;
136 nb_indices_line = tabv1[indices_glob_elem_p(nelem) + 1] - tabv1[indices_glob_elem_p(nelem)];
137 indice = 0;
138
139 for (int i = 0; i < nb_bfunc_p; i++)
140 {
141 for (int k = 0; k < nb_stencil_max; k++)
142 {
143 if (stencil_sorted(nelem, k) < 0)
144 break;
145 col = indices_glob_elem_v(stencil_sorted(nelem, k)) + 1;
146 for (int j = 0; j < nb_bfunc_v * dim; j++)
147 tabv2[row + indice + j + k * nb_bfunc_v * dim] = col + j;
148 }
149 indice += nb_indices_line;
150 }
151 }
152 matv2.is_sorted_stencil();
153 assert(matv2.is_sorted_stencil());
154 matv->nb_colonnes() ? *matv += matv2 : *matv = matv2;
155 }
156 if (matp && order_v == order_p) // Stabilization term for equal order interpolation of velocity and pressure
157 {
158 const int size_p = indices_glob_elem_p(nb_elem_tot);
159
160 matp2.dimensionner(size_p, size_p, 0);
161
162 auto& tabp1 = matp2.get_set_tab1();
163 auto& tabp2 = matp2.get_set_tab2();
164 auto& coeffp = matp2.get_set_coeff();
165 coeffp = 0.;
166
167 tabp1(0) = 1;
168
169 // Nombre de colonnes non nulles par ligne :
170 // pour chaque ddl pression d'un élément, on couple avec tous les ddl pression
171 // de l'élément courant + de son stencil.
172 for (int nelem = 0; nelem < nb_elem_tot; nelem++)
173 {
174 nb_indices_line = 0;
175 for (int k = 0; k < nb_stencil_max; k++)
176 {
177 if (stencil_sorted(nelem, k) < 0)
178 break;
179 nb_indices_line += nb_bfunc_p;
180 }
181
182 for (int i = 0; i < nb_bfunc_p; i++)
183 tabp1(indices_glob_elem_p(nelem) + i + 1) = nb_indices_line + tabp1(indices_glob_elem_p(nelem) + i);
184 }
185
186 matp2.dimensionner(size_p, size_p, tabp1(size_p) - 1);
187
188 for (int nelem = 0; nelem < nb_elem_tot; nelem++)
189 {
190 nb_indices_line = tabp1(indices_glob_elem_p(nelem) + 1) - tabp1(indices_glob_elem_p(nelem));
191
192 for (int i = 0; i < nb_bfunc_p; i++)
193 {
194 row = tabp1(indices_glob_elem_p(nelem) + i) - 1;
195
196 for (int k = 0; k < nb_stencil_max; k++)
197 {
198 if (stencil_sorted(nelem, k) < 0)
199 break;
200
201 col = indices_glob_elem_p(stencil_sorted(nelem, k)) + 1;
202 for (int j = 0; j < nb_bfunc_p; j++)
203 tabp2[row + j + k * nb_bfunc_p] = col + j;
204 }
205 }
206 }
207 }
208 else // no stabilization term, but we still need to dimension the matrix
209 {
210 matp2.dimensionner(size_row, 1);
211 auto& tabp1 = matp2.get_set_tab1();
212 tabp1 = 2;
213 tabp1(0) = 1;
214 auto& tabp2 = matp2.get_set_tab2();
215 tabp2(0) = 1;
216 auto& coeffp = matp2.get_set_coeff();
217 coeffp = 0;
218 }
219 matp2.is_sorted_stencil();
220 assert(matp2.is_sorted_stencil());
221
222 matp->nb_colonnes() ? *matp += matp2 : *matp = matp2;
223}
224
225/**
226 * @brief Assembles the DG divergence operator and, if needed, the pressure stabilization term.
227 *
228 * @details The assembly proceeds in two independent parts:
229 *
230 * **1. Divergence part** (always assembled)
231 *
232 * Uses the velocity basis gradient and the pressure basis:
233 * - *Volume term*: for each element,
234 * integral of q_h * div(u_h) = integral of grad(q_h) . u_h (integration by parts)
235 * i.e., integral of grad(phi_p_j) . phi_v_i over the element.
236 * - *Internal face jump term*: for each internal face shared by elem0 and elem1,
237 * integral of [u_h . n]_f * {{q_h}} = 0.5 * integral of (phi_v_i0 - phi_v_i1) . n * (phi_p_j0 + phi_p_j1)
238 * The four (elem0/elem1) x (elem0/elem1) combinations are assembled with the appropriate sign.
239 * - *Boundary face term*: for Dirichlet boundaries, the boundary velocity contributes
240 * to the face normal flux. The commented-out block handles time-varying Dirichlet
241 * data on the RHS (not yet active).
242 *
243 * **2. Pressure stabilization part** (only when order_v == order_p and matp is allocated)
244 *
245 * Adds a Dohrmann-Bochev-type face stabilization to recover inf-sup stability for
246 * equal-order velocity-pressure pairs:
247 * nu_f * integral of [p_h]_f * [q_h]_f
248 * where nu_f is the harmonic mean of the diffusivities of the two adjacent elements,
249 * and the jump [.]_f is assembled as the four cross-element combinations.
250 *
251 * @param vit Velocity field values.
252 * @param matrices Map of matrix name → Matrice_Morse pointer to accumulate into.
253 * @param secmem Right-hand side (continuity residual) to accumulate into.
254 * @param semi_impl Map of semi-implicit field values.
255 */
256void Op_Div_DG::ajouter_blocs_ext(const DoubleTab& vit, matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl) const
257{
258 int order_v = Option_DG::Get_order_for("vitesse");
259 int order_p = Option_DG::Get_order_for("pression");
260
261 Matrice_Morse *matv = matrices.count("vitesse") ? matrices["vitesse"] : nullptr;
262
263 bool stabilisation = ((order_v == order_p) && matrices.count("pression")); // Calculate the stabilization term if the same order is used for velocity and pressure, and if the matrix for pressure is allocated
264 Matrice_Morse *matp = matrices.count("pression") ? (stabilisation ? matrices["pression"] : nullptr) : nullptr;
265 const DoubleTab& inco_p = semi_impl.count("pression") ? semi_impl.at("pression") : ref_cast(Navier_Stokes_std, equation()).pression().valeurs();
266
267 const Domaine_DG& domaine = le_dom_DG.valeur();
268 const IntTab& face_voisins = domaine.face_voisins();
269
270 const BasisFunction& bfunc_v = domaine.get_basisFunction(order_v);
271 const int nb_bfunc_v = bfunc_v.nb_bfunc();
272
273 const BasisFunction& bfunc_p = domaine.get_basisFunction(order_p);
274 const int nb_bfunc_p = bfunc_p.nb_bfunc();
275
276 const int dim = Objet_U::dimension;
277 const IntTab& indices_glob_elem_v = bfunc_v.indices_glob_elem(dim);
278 const IntTab& indices_glob_elem_p = bfunc_p.indices_glob_elem();
279
280 {
281 // div part
282 const int quad_order = bfunc_v.get_default_quadrature_order();
283 const Quadrature_base& quad = domaine.get_quadrature(quad_order); // Same quadrature for all champs
284
285 int nb_pts_integ_max = quad.nb_pts_integ_max();
286 double coeff;
287 DoubleTab grad_fbase_elem(nb_bfunc_v, nb_pts_integ_max, Objet_U::dimension);
288 DoubleTab f_base_p(nb_bfunc_p, nb_pts_integ_max);
289 DoubleTab scalar_product_dim(nb_pts_integ_max);
290
291 // Loop over elements to compute \int q_h div(u_h) dV
292 for (int elem = 0; elem < domaine.nb_elem(); elem++)
293 {
294 int ind_elem_v = indices_glob_elem_v(elem);
295 int ind_elem_p = indices_glob_elem_p(elem);
296 bfunc_v.eval_grad_bfunc(quad, elem, grad_fbase_elem);
297 bfunc_p.eval_bfunc(quad, elem, f_base_p);
298 for (int pressure_index = 0; pressure_index < nb_bfunc_p; pressure_index++)
299 for (int d = 0; d < dim; d++)
300 for (int velocity_index = 0; velocity_index < nb_bfunc_v; velocity_index++)
301 {
302 for (int k = 0; k < quad.nb_pts_integ(elem); k++)
303 scalar_product_dim(k) = grad_fbase_elem(velocity_index, k, d) * f_base_p(pressure_index, k);
304 coeff = quad.compute_integral_on_elem(elem, scalar_product_dim);
305 if (matv)
306 (*matv)(ind_elem_p + pressure_index, ind_elem_v + velocity_index + d * nb_bfunc_v) += coeff;
307 secmem(elem, pressure_index) -= coeff * vit(elem, velocity_index + d * nb_bfunc_v);
308 }
309 }
310
311 const DoubleTab& face_normales = domaine.face_normales();
312 const DoubleVect& face_surfaces = domaine.face_surfaces();
313 int nb_pts_int_fac = quad.nb_pts_integ_facets();
314
315 double coeff00, coeff10, coeff01, coeff11;
316
317 DoubleTab eval_jump_on_facet00(nb_pts_int_fac);
318 DoubleTab eval_jump_on_facet01(nb_pts_int_fac);
319 DoubleTab eval_jump_on_facet10(nb_pts_int_fac);
320 DoubleTab eval_jump_on_facet11(nb_pts_int_fac);
321
322 DoubleTab f_base_v0(nb_bfunc_v, nb_pts_int_fac);
323 DoubleTab f_base_v1(nb_bfunc_v, nb_pts_int_fac);
324 DoubleTab f_base_p0(nb_bfunc_p, nb_pts_int_fac);
325 DoubleTab f_base_p1(nb_bfunc_p, nb_pts_int_fac);
326
327 int premiere_face_int = domaine.premiere_face_int();
328
329 // Loop over facets to compute \int_f [u_h.n]_F q_h dS
330 for (int face = premiere_face_int; face < domaine.nb_faces(); face++)
331 {
332 int elem0 = face_voisins(face, 0);
333 int elem1 = face_voisins(face, 1);
334 double sur_f = face_surfaces(face);
335 int ind_elem0_v = indices_glob_elem_v(elem0);
336 int ind_elem1_v = indices_glob_elem_v(elem1);
337 int ind_elem0_p = indices_glob_elem_p(elem0);
338 int ind_elem1_p = indices_glob_elem_p(elem1);
339 bfunc_v.eval_bfunc_on_facets(quad, elem0, face, f_base_v0);
340 bfunc_v.eval_bfunc_on_facets(quad, elem1, face, f_base_v1);
341 bfunc_p.eval_bfunc_on_facets(quad, elem0, face, f_base_p0);
342 bfunc_p.eval_bfunc_on_facets(quad, elem1, face, f_base_p1);
343 for (int pressure_index = 0; pressure_index < nb_bfunc_p; pressure_index++)
344 {
345 for (int velocity_index = 0; velocity_index < nb_bfunc_v; velocity_index++)
346 {
347 for (int d = 0; d < Objet_U::dimension; d++)
348 {
349 for (int k = 0; k < quad.nb_pts_integ_facets(); k++)
350 {
351 eval_jump_on_facet00(k) = -f_base_v0(velocity_index, k) * face_normales(face, d) * 0.5 * f_base_p0(pressure_index, k) / sur_f;
352 eval_jump_on_facet01(k) = +f_base_v1(velocity_index, k) * face_normales(face, d) * 0.5 * f_base_p0(pressure_index, k) / sur_f;
353 eval_jump_on_facet10(k) = -f_base_v0(velocity_index, k) * face_normales(face, d) * 0.5 * f_base_p1(pressure_index, k) / sur_f;
354 eval_jump_on_facet11(k) = +f_base_v1(velocity_index, k) * face_normales(face, d) * 0.5 * f_base_p1(pressure_index, k) / sur_f;
355 }
356 coeff00 = quad.compute_integral_on_facet(face, eval_jump_on_facet00);
357 coeff01 = quad.compute_integral_on_facet(face, eval_jump_on_facet01);
358 coeff10 = quad.compute_integral_on_facet(face, eval_jump_on_facet10);
359 coeff11 = quad.compute_integral_on_facet(face, eval_jump_on_facet11);
360
361 if (matv)
362 {
363 (*matv)(ind_elem0_p + pressure_index, ind_elem0_v + velocity_index + d * nb_bfunc_v) += coeff00;
364 (*matv)(ind_elem0_p + pressure_index, ind_elem1_v + velocity_index + d * nb_bfunc_v) += coeff01;
365 (*matv)(ind_elem1_p + pressure_index, ind_elem0_v + velocity_index + d * nb_bfunc_v) += coeff10;
366 (*matv)(ind_elem1_p + pressure_index, ind_elem1_v + velocity_index + d * nb_bfunc_v) += coeff11;
367 }
368 secmem(elem0, pressure_index) -= coeff00 * vit(elem0, velocity_index + d * nb_bfunc_v);
369 secmem(elem0, pressure_index) -= coeff01 * vit(elem1, velocity_index + d * nb_bfunc_v);
370 secmem(elem1, pressure_index) -= coeff10 * vit(elem0, velocity_index + d * nb_bfunc_v);
371 secmem(elem1, pressure_index) -= coeff11 * vit(elem1, velocity_index + d * nb_bfunc_v);
372 }
373 }
374 }
375 }
376
377 // Treatment of the boundary conditions
378 for (int face = 0; face < premiere_face_int; face++)
379 {
380 int elem = face_voisins(face, 0); // The cell that have one facet on the boundary
381 double sur_f = face_surfaces(face);
382
383 int ind_elem_v = indices_glob_elem_v(elem);
384 int ind_elem_p = indices_glob_elem_p(elem);
385 bfunc_v.eval_bfunc_on_facets(quad, elem, face, f_base_v0);
386 bfunc_p.eval_bfunc_on_facets(quad, elem, face, f_base_p0);
387 for (int pressure_index = 0; pressure_index < nb_bfunc_p; pressure_index++)
388 {
389 for (int velocity_index = 0; velocity_index < nb_bfunc_v; velocity_index++)
390 {
391 for (int d = 0; d < Objet_U::dimension; d++)
392 {
393 //eval_jump_on_facet00 = 0.;
394 for (int k = 0; k < quad.nb_pts_integ_facets(); k++)
395 eval_jump_on_facet00(k) = -f_base_v0(velocity_index, k) * face_normales(face, d) * f_base_p0(pressure_index, k) / sur_f;
396 coeff00 = quad.compute_integral_on_facet(face, eval_jump_on_facet00);
397 if (matv)
398 (*matv)(ind_elem_p + pressure_index, ind_elem_v + velocity_index + d * nb_bfunc_v) += coeff00;
399 secmem(elem, pressure_index) -= coeff00 * vit(elem, velocity_index + d * nb_bfunc_v);
400 }
401 }
402 }
403 }
404
405 /* DoubleTab u_bord_k(nb_pts_int_fac, dim); // Dirichlet projection
406 const DoubleTab& integ_points_facets = quad.get_integ_points_facets();
407 for (int num_cl = 0; num_cl < le_dom_DG->nb_front_Cl(); num_cl++)
408 {
409 const Cond_lim& la_cl = le_dcl_DG->les_conditions_limites(num_cl);
410 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
411 int num1f = 0;
412 int num2f = le_bord.nb_faces();
413 double xk = 0., yk = 0., zk = 0.;
414 double temps = equation().schema_temps().temps_courant();
415
416 if (sub_type(Champ_front_softanalytique, la_cl.valeur().champ_front()))
417 {
418 Cerr << " Il faut utiliser Champ_front_fonc_txyz et non " << la_cl.valeur().champ_front().que_suis_je() << finl;
419 exit();
420 }
421
422 bool avec_valeur_aux_points = false;
423 if (sub_type(Champ_front_var_instationnaire, la_cl.valeur().champ_front()))
424 {
425 const Champ_front_var_instationnaire& ch_txyz = ref_cast(Champ_front_var_instationnaire, la_cl.valeur().champ_front());
426 avec_valeur_aux_points = ch_txyz.valeur_au_temps_et_au_point_disponible();
427 }
428
429 if (sub_type(Dirichlet, la_cl.valeur()))
430 {
431 if (avec_valeur_aux_points)
432 {
433 if (sub_type(Champ_front_var_instationnaire, la_cl.valeur().champ_front()))
434 {
435 const Champ_front_var_instationnaire& champ_front =
436 ref_cast(Champ_front_var_instationnaire, la_cl.valeur().champ_front());
437
438 for (int ind_faceb = num1f; ind_faceb < num2f; ind_faceb++)
439 {
440 u_bord_k = 0.;
441 int face = le_bord.num_face(ind_faceb);
442 int elem = face_voisins(face, 0); // The cell that have one facet on the boundary
443 double sur_f = face_surfaces(face);
444
445 bfunc_v.eval_bfunc_on_facets(quad, elem, face, f_base_v0);
446 bfunc_p.eval_bfunc_on_facets(quad, elem, face, f_base_p0);
447
448 for (int k = 0; k < nb_pts_int_fac; k++)
449 {
450 // Coordonnees des points d'integration
451 xk = integ_points_facets(face, k, 0);
452 yk = integ_points_facets(face, k, 1);
453 if (dimension == 3)
454 zk = integ_points_facets(face, k, 2);
455
456 for (int d = 0; d < Objet_U::dimension; d++)
457 u_bord_k(k, d) = champ_front.valeur_au_temps_et_au_point(temps, 0, xk, yk, zk, d);
458 }
459
460 for (int pressure_index = 0; pressure_index < nb_bfunc_p; pressure_index++)
461 {
462 for (int d = 0; d < Objet_U::dimension; d++)
463 {
464 //eval_jump_on_facet01 = 0.;
465 for (int k = 0; k < quad.nb_pts_integ_facets(); k++)
466 eval_jump_on_facet01(k) = +u_bord_k(k, d) * face_normales(face, d) * f_base_p0(pressure_index, k) / sur_f;
467 coeff01 = quad.compute_integral_on_facet(face, eval_jump_on_facet01);
468 secmem(elem, pressure_index) -= coeff01;
469 }
470 }
471 }
472 }
473 }
474 else
475 {
476
477 const Dirichlet& dirichlet = ref_cast(Dirichlet, la_cl.valeur());
478
479 for (int ind_faceb = num1f; ind_faceb < num2f; ind_faceb++)
480 {
481 int face = le_bord.num_face(ind_faceb);
482 int elem = face_voisins(face, 0); // The cell that have one facet on the boundary
483 double sur_f = face_surfaces(face);
484
485 bfunc_v.eval_bfunc_on_facets(quad, elem, face, f_base_v0);
486 bfunc_p.eval_bfunc_on_facets(quad, elem, face, f_base_p0);
487
488 for (int pressure_index = 0; pressure_index < nb_bfunc_p; pressure_index++)
489 {
490 for (int d = 0; d < Objet_U::dimension; d++)
491 {
492 //eval_jump_on_facet01 = 0.;
493 double u_bord = dirichlet.val_imp_au_temps(temps, ind_faceb, d);
494 for (int k = 0; k < quad.nb_pts_integ_facets(); k++)
495 eval_jump_on_facet01(k) = +u_bord * face_normales(face, d) * f_base_p0(pressure_index, k) / sur_f;
496 coeff01 = quad.compute_integral_on_facet(face, eval_jump_on_facet01);
497 secmem(elem, pressure_index) -= coeff01;
498 }
499 }
500 }
501 }
502 }
503 } */
504 }
505
506
507 if (!matp) return; // No matrix allocated for the stabilization term, we skip the calculation
508 {
509 //stabilization part
510 op_diff_->update_nu();
511
512 int premiere_face_int = domaine.premiere_face_int();
513
514 const DoubleVect& face_surfaces = domaine.face_surfaces();
515 const int quad_order = bfunc_p.get_default_quadrature_order();
516 const Quadrature_base& quad = domaine.get_quadrature(quad_order); // pressure quad
517
518 int nb_pts_int_fac = quad.nb_pts_integ_facets();
519 DoubleTab f_base_p0(nb_bfunc_p, nb_pts_int_fac);
520 DoubleTab f_base_p1(nb_bfunc_p, nb_pts_int_fac);
521 DoubleTab eval_jump_on_facet00(nb_pts_int_fac);
522 DoubleTab eval_jump_on_facet01(nb_pts_int_fac);
523 DoubleTab eval_jump_on_facet10(nb_pts_int_fac);
524 DoubleTab eval_jump_on_facet11(nb_pts_int_fac);
525 double coeff00, coeff01, coeff11;
526
527 // Loop over facets to compute \int_f [u_h.n]_F q_h dS
528 for (int face = premiere_face_int; face < domaine.nb_faces(); face++)
529 {
530 int elem0 = face_voisins(face, 0);
531 int elem1 = face_voisins(face, 1);
532 double sur_f = face_surfaces(face);
533 int ind_elem0_p = indices_glob_elem_p(elem0);
534 int ind_elem1_p = indices_glob_elem_p(elem1);
535 bfunc_p.eval_bfunc_on_facets(quad, elem0, face, f_base_p0);
536 bfunc_p.eval_bfunc_on_facets(quad, elem1, face, f_base_p1);
537
538 double nu0 = op_diff_->nu(elem0, 0);
539 double nu1 = op_diff_->nu(elem1, 0);
540 double nu_f = 2. * nu0 * nu1 / (nu0 + nu1); // harmonic mean
541
542 for (int pressure_index_l = 0; pressure_index_l < nb_bfunc_p; pressure_index_l++) // Loop for basis function
543 {
544 for (int pressure_index_r = 0; pressure_index_r < nb_bfunc_p; pressure_index_r++) // Loop for test function
545 {
546 // elem 0 with elem 0
547 for (int k = 0; k < quad.nb_pts_integ_facets(); k++)
548 eval_jump_on_facet00(k) = nu_f * f_base_p0(pressure_index_l, k) * f_base_p0(pressure_index_r, k) * sur_f;
549 coeff00 = quad.compute_integral_on_facet(face, eval_jump_on_facet00);
550 (*matp)(ind_elem0_p + pressure_index_l, ind_elem0_p + pressure_index_r) += coeff00;
551 secmem(elem0, pressure_index_l) -= coeff00 * inco_p(elem0, pressure_index_r);
552
553 // elem 0 with elem 1
554 for (int k = 0; k < quad.nb_pts_integ_facets(); k++)
555 eval_jump_on_facet01(k) = -nu_f * f_base_p0(pressure_index_l, k) * f_base_p1(pressure_index_r, k) * sur_f;
556 coeff01 = quad.compute_integral_on_facet(face, eval_jump_on_facet01);
557 (*matp)(ind_elem0_p + pressure_index_l, ind_elem1_p + pressure_index_r) += coeff01;
558 secmem(elem0, pressure_index_l) -= coeff01 * inco_p(elem1, pressure_index_r);
559 // elem 1 with elem 0
560 (*matp)(ind_elem1_p + pressure_index_r, ind_elem0_p + pressure_index_l) += coeff01;
561 secmem(elem1, pressure_index_r) -= coeff01 * inco_p(elem0, pressure_index_l);
562
563 // elem 1 with elem 1
564 for (int k = 0; k < quad.nb_pts_integ_facets(); k++)
565 eval_jump_on_facet11(k) = nu_f * f_base_p1(pressure_index_l, k) * f_base_p1(pressure_index_r, k) * sur_f;
566 coeff11 = quad.compute_integral_on_facet(face, eval_jump_on_facet11);
567 (*matp)(ind_elem1_p + pressure_index_l, ind_elem1_p + pressure_index_r) += coeff11;
568 secmem(elem1, pressure_index_l) -= coeff11 * inco_p(elem1, pressure_index_r);
569 }
570 }
571 }
572 }
573}
574
575DoubleTab& Op_Div_DG::calculer(const DoubleTab& vit, DoubleTab& div) const
576{
577 div = 0.;
578 return ajouter(vit, div);
579}
580
582{
583 return 1;
584}
585
586/**
587 * @brief Converts the divergence field from an integrated to a volumetric (per-unit-volume) form.
588 * @details Divides each element's divergence value by the element volume.
589 * @param div The divergence field to scale in-place.
590 * @todo The current scaling is inconsistent for multi-component fields; only div(elem, 0)
591 * is divided, which needs to be revisited for a proper volumetric normalization.
592 */
593void Op_Div_DG::volumique(DoubleTab& div) const
594{
595 const Domaine_DG& domaine_DG = le_dom_DG.valeur();
596 const DoubleVect& vol = domaine_DG.volumes();
597 const int nb_elem = domaine_DG.domaine().nb_elem_tot();
598
599 for (int num_elem = 0; num_elem < nb_elem; num_elem++)
600 div(num_elem, 0) /= vol(num_elem); // TODO DFG ici c'est n'importe quoi, trouve comment avoir une valeur coherente !!!
601}
Manages the local polynomial basis functions for Discontinuous Galerkin elements.
void eval_grad_bfunc(const Quadrature_base &quad, const int &nelem, DoubleTab &fbasis) const
Evaluates the gradients of all basis functions at the element quadrature points.
void eval_bfunc_on_facets(const Quadrature_base &quad, const int &nelem, const int &num_face, DoubleTab &grad_fbasis) const
Evaluates all basis functions of element nelem at the quadrature points of face num_face.
const IntTab & indices_glob_elem(const int dim=1) const
void eval_bfunc(const Quadrature_base &quad, const int &nelem, DoubleTab &fbasis) const
Evaluates all basis functions at the element quadrature points.
const int & nb_bfunc() const
const int & get_default_quadrature_order() const
Classe Champ_Inc_base.
int_t nb_elem_tot() const
Definition Domaine.h:132
classe Domaine_Cl_dis_base Les objets Domaine_Cl_dis_base representent les conditions aux limites
double volumes(int i) const
Definition Domaine_VF.h:113
int face_voisins(int num_face, int i) const
renvoie l'element voisin de numface dans la direction i.
Definition Domaine_VF.h:418
classe Domaine_dis_base Cette classe est la base de la hierarchie des domaines discretisees.
const Domaine & domaine() const
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
int nb_colonnes() const override
Return local number of columns (=size on the current proc).
const Equation_base & equation() const
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
classe Navier_Stokes_std Cette classe porte les termes de l'equation de la dynamique
static int dimension
Definition Objet_U.h:99
friend class Sortie
Definition Objet_U.h:75
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
This class provides the common infrastructure shared by all DG diffusion operators in TRUST....
class Op_Div_DG
Definition Op_Div_DG.h:35
void completer() override
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son equation.
Definition Op_Div_DG.cpp:46
void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={}) const override
Sizes the velocity-pressure and pressure-pressure matrix blocks.
Definition Op_Div_DG.cpp:71
int impr(Sortie &os) const override
DOES NOTHING - to override in derived classes.
void volumique(DoubleTab &) const override
Converts the divergence field from an integrated to a volumetric (per-unit-volume) form.
DoubleTab & calculer(const DoubleTab &, DoubleTab &) const override
void ajouter_blocs_ext(const DoubleTab &vit, matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={ }) const override
Assembles the DG divergence operator and, if needed, the pressure stabilization term.
void associer(const Domaine_dis_base &, const Domaine_Cl_dis_base &, const Champ_Inc_base &) override
Definition Op_Div_DG.cpp:40
Classe Operateur_Div_base Cette classe est la base de la hierarchie des operateurs representant.
DoubleTab & ajouter(const DoubleTab &vit, DoubleTab &div) const override
virtual void completer()
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son equation.
static int Get_order_for(const Nom &n)
Definition Option_DG.cpp:70
int nb_pts_integ(int e) const
double compute_integral_on_facet(int num_facet, Parser_U &parser) const
int nb_pts_integ_max() const
double compute_integral_on_elem(int num_elem, Parser_U &parser) const
int nb_pts_integ_facets() const
Classe de base des flux de sortie.
Definition Sortie.h:52
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133