TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Op_Grad_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_Grad_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
30Implemente_instanciable(Op_Grad_DG, "Op_Grad_DG", Operateur_Grad_base);
31
32Sortie& Op_Grad_DG::printOn(Sortie& s) const { return s << que_suis_je(); }
33
34Entree& Op_Grad_DG::readOn(Entree& s) { return s; }
35
36/**
37 * @brief Associates the operator with a DG domain and its boundary conditions.
38 * @param domaine_dis The discretized domain, expected to be a Domaine_DG.
39 * @param domaine_Cl_dis The boundary condition container, expected to be a Domaine_Cl_DG.
40 */
41void Op_Grad_DG::associer(const Domaine_dis_base& domaine_dis, const Domaine_Cl_dis_base& domaine_Cl_dis, const Champ_Inc_base&)
42{
43 le_dom_DG = ref_cast(Domaine_DG, domaine_dis);
44 le_dcl_DG = ref_cast(Domaine_Cl_DG, domaine_Cl_dis);
45}
46
47/**
48 * @brief Sizes the velocity-pressure matrix block for the gradient operator.
49 *
50 * @details Builds the sparsity pattern of the rectangular matrix mapping pressure DOFs
51 * to velocity DOFs. Each velocity DOF of element T is coupled to all pressure DOFs of
52 * T and its face-neighbours, as given by the pre-computed stencil. The resulting matrix
53 * has size_v rows (velocity global DOFs) and size_p columns (pressure global DOFs).
54 *
55 * Returns immediately if "pression" is absent from matrices or is treated semi-implicitly.
56 *
57 * @param matrices Map of matrix name → Matrice_Morse pointer to be sized.
58 * @param semi_impl Map of semi-implicit field names; if "pression" is present, returns immediately.
59 */
60void Op_Grad_DG::dimensionner_blocs(matrices_t matrices, const tabs_t& semi_impl) const
61{
62 if (!matrices.count("pression")) return; //rien a faire
63 if (semi_impl.count("pression"))
64 return; // semi-implicite -> rien a dimensionner
65
66 Matrice_Morse *mat = matrices["pression"], mat2;
67
68 const Domaine_DG& domaine = le_dom_DG.valeur();
69
70 int order_v = Option_DG::Get_order_for("vitesse");
71 int order_p = Option_DG::Get_order_for("pression");
72
73 const BasisFunction& bfunc_v = domaine.get_basisFunction(order_v);
74 const int nb_bfunc_v = bfunc_v.nb_bfunc();
75
76 const BasisFunction& bfunc_p = domaine.get_basisFunction(order_p);
77 const int nb_bfunc_p = bfunc_p.nb_bfunc();
78
79 int dim = Objet_U::dimension;
80 const IntTab& indices_glob_elem_v = bfunc_v.indices_glob_elem(dim);
81 const IntTab& indices_glob_elem_p = bfunc_p.indices_glob_elem();
82
83 int nb_elem_tot = domaine.nb_elem_tot();
84
85 int size_row = indices_glob_elem_v(nb_elem_tot);
86 int size_col = indices_glob_elem_p(nb_elem_tot);
87
88 mat2.dimensionner(size_row, size_col, 0);
89
90 auto& tab1 = mat2.get_set_tab1();
91 auto& tab2 = mat2.get_set_tab2();
92 auto& coeff = mat2.get_set_coeff();
93 coeff = 0;
94
95 const Stencil& stencil_sorted = domaine.get_stencil_sorted();
96 const int nb_stencil_max = stencil_sorted.dimension(1);
97
98 int nb_indices_line;
99 int row, col, indice;
100
101 tab1(0) = 1;
102 for (int nelem = 0; nelem < nb_elem_tot; nelem++)
103 {
104 nb_indices_line = 0;
105 for (int k = 0; k < nb_stencil_max; k++)
106 {
107 if (stencil_sorted(nelem, k) < 0)
108 break;
109 nb_indices_line += nb_bfunc_p;
110 }
111 for (int k = 0; k < nb_bfunc_v * dim; k++)
112 tab1(indices_glob_elem_v(nelem) + k + 1) = nb_indices_line + tab1(indices_glob_elem_v(nelem) + k);
113 }
114
115 mat2.dimensionner(size_row, size_col, tab1(size_row) - 1);
116
117 for (int nelem = 0; nelem < nb_elem_tot; nelem++)
118 {
119 row = tab1[indices_glob_elem_v(nelem)] - 1;
120 nb_indices_line = tab1[indices_glob_elem_v(nelem) + 1] - tab1[indices_glob_elem_v(nelem)];
121 indice = 0;
122
123 for (int i = 0; i < nb_bfunc_v*dim; i++)
124 {
125 for (int k = 0; k < nb_stencil_max; k++)
126 {
127 if (stencil_sorted(nelem, k) < 0)
128 break;
129 col = indices_glob_elem_p(stencil_sorted(nelem, k)) + 1;
130 for (int j = 0 ; j < nb_bfunc_p; j++)
131 tab2[row + indice + j + k*nb_bfunc_p] = col + j;
132 }
133 indice += nb_indices_line;
134 }
135 }
136 mat2.is_sorted_stencil();
137 assert(mat2.is_sorted_stencil());
138 mat->nb_colonnes() ? *mat += mat2 : *mat = mat2;
139}
140
141/**
142 * @brief Assembles the DG gradient operator into the matrix and right-hand side.
143 *
144 * @details The assembly has two stages:
145 *
146 * **1. Volume term** — for each element:
147 * integral of grad(phi_p_j) . phi_v_i over the element,
148 * accumulated as (*mat)(v_dof, p_dof) += coeff and secmem(elem, v_dof) -= coeff * p(elem, p_dof).
149 *
150 * **2. Internal face term** — for each internal face shared by elem0 and elem1:
151 * The average-jump coupling integral of {{phi_p}} * [phi_v . n] is expanded into
152 * four pointwise products at face quadrature points:
153 * - coeff00: -0.5 * phi_p0 * n_d * phi_v0 (elem0 pressure, elem0 velocity)
154 * - coeff01: +0.5 * phi_p1 * n_d * phi_v0 (elem1 pressure, elem0 velocity)
155 * - coeff10: -0.5 * phi_p0 * n_d * phi_v1 (elem0 pressure, elem1 velocity)
156 * - coeff11: +0.5 * phi_p1 * n_d * phi_v1 (elem1 pressure, elem1 velocity)
157 *
158 * The sign convention follows the outward normal of elem0: the jump [v.n] on the
159 * face is (v0 - v1).n/|f|, hence the minus sign on elem0-side contributions.
160 *
161 * @param matrices Map of matrix name → Matrice_Morse pointer to accumulate into.
162 * @param secmem Right-hand side (momentum residual) to accumulate into.
163 * @param semi_impl Map of semi-implicit field values; if "pression" is present,
164 * its values are used instead of the current pressure field.
165 */
166void Op_Grad_DG::ajouter_blocs(matrices_t matrices, DoubleTab& secmem, const tabs_t& semi_impl) const
167{
168
169 const DoubleTab& inco_p = semi_impl.count("pression") ? semi_impl.at("pression") : ref_cast(Navier_Stokes_std, equation()).pression().valeurs(); // NB : is this working ?
170 Matrice_Morse *mat = matrices.count("pression") ? matrices.at("pression") : nullptr; // pression for the stabilisation term if np==nv
171
172 const Domaine_DG& domaine = le_dom_DG.valeur();
173
174 int order_v = Option_DG::Get_order_for("vitesse");
175 int order_p = Option_DG::Get_order_for("pression");
176
177 const BasisFunction& bfunc_v = domaine.get_basisFunction(order_v);
178 const int nb_bfunc_v = bfunc_v.nb_bfunc();
179
180 const BasisFunction& bfunc_p = domaine.get_basisFunction(order_p);
181 const int nb_bfunc_p = bfunc_p.nb_bfunc();
182
183 const int dim = Objet_U::dimension;
184 const IntTab& indices_glob_elem_v = bfunc_v.indices_glob_elem(dim);
185 const IntTab& indices_glob_elem_p = bfunc_p.indices_glob_elem();
186
187 const int quad_order = bfunc_p.get_default_quadrature_order(); //TODO DG should we choose the max or the p order quadrature ?
188 const Quadrature_base& quad = domaine.get_quadrature(quad_order); // Same quadrature for all champs
189
190
191 int nb_pts_integ_max = quad.nb_pts_integ_max();
192 double coeff;
193 DoubleTab grad_fbase_elem(nb_bfunc_p, nb_pts_integ_max, Objet_U::dimension);
194 DoubleTab f_base_v(nb_bfunc_v, nb_pts_integ_max);
195 DoubleTab scalar_product_dim(nb_pts_integ_max);
196
197 // Loop over elements to compute \int q_h div(u_h) dV
198 for (int elem = 0; elem < domaine.nb_elem(); elem++)
199 {
200 int ind_elem_v = indices_glob_elem_v(elem);
201 int ind_elem_p = indices_glob_elem_p(elem);
202 bfunc_p.eval_grad_bfunc(quad, elem, grad_fbase_elem);
203 bfunc_v.eval_bfunc(quad, elem, f_base_v);
204 for (int d = 0; d < dim; d++)
205 for (int velocity_index = 0; velocity_index < nb_bfunc_v; velocity_index++)
206 for (int pressure_index = 0; pressure_index < nb_bfunc_p; pressure_index++)
207 {
208 for (int k = 0; k < quad.nb_pts_integ(elem); k++)
209 scalar_product_dim(k) = grad_fbase_elem(pressure_index, k, d) * f_base_v(velocity_index, k);
210 coeff = quad.compute_integral_on_elem(elem, scalar_product_dim);
211 if (mat)
212 (*mat)(ind_elem_v + velocity_index + d * nb_bfunc_v, ind_elem_p + pressure_index) += coeff;
213 secmem(elem, velocity_index + d * nb_bfunc_v) -= coeff * inco_p(elem, pressure_index);
214 }
215 }
216
217 const DoubleTab& face_normales = domaine.face_normales();
218 const DoubleVect& face_surfaces = domaine.face_surfaces();
219 int nb_pts_int_fac = quad.nb_pts_integ_facets();
220 const IntTab& face_voisins = domaine.face_voisins();
221
222 double coeff00, coeff10, coeff01, coeff11;
223
224 DoubleTab eval_jump_on_facet00(nb_pts_int_fac);
225 DoubleTab eval_jump_on_facet01(nb_pts_int_fac);
226 DoubleTab eval_jump_on_facet10(nb_pts_int_fac);
227 DoubleTab eval_jump_on_facet11(nb_pts_int_fac);
228
229 DoubleTab f_base_v0(nb_bfunc_v, nb_pts_int_fac);
230 DoubleTab f_base_v1(nb_bfunc_v, nb_pts_int_fac);
231 DoubleTab f_base_p0(nb_bfunc_p, nb_pts_int_fac);
232 DoubleTab f_base_p1(nb_bfunc_p, nb_pts_int_fac);
233
234 int premiere_face_int = domaine.premiere_face_int();
235
236 // Loop over facets to compute \int_f [u_h.n]_F {{q_h}} dS
237 for (int face = premiere_face_int; face < domaine.nb_faces(); face++)
238 {
239 int elem0 = face_voisins(face,0);
240 int elem1 = face_voisins(face,1);
241 double sur_f = face_surfaces(face);
242 int ind_elem0_v = indices_glob_elem_v(elem0);
243 int ind_elem1_v = indices_glob_elem_v(elem1);
244 int ind_elem0_p = indices_glob_elem_p(elem0);
245 int ind_elem1_p = indices_glob_elem_p(elem1);
246 bfunc_v.eval_bfunc_on_facets(quad, elem0, face, f_base_v0);
247 bfunc_v.eval_bfunc_on_facets(quad, elem1, face, f_base_v1);
248 bfunc_p.eval_bfunc_on_facets(quad, elem0, face, f_base_p0);
249 bfunc_p.eval_bfunc_on_facets(quad, elem1, face, f_base_p1);
250 for (int d = 0; d < Objet_U::dimension; d++)
251 {
252 for (int velocity_index = 0; velocity_index < nb_bfunc_v; velocity_index++)
253 {
254 for (int pressure_index = 0; pressure_index < nb_bfunc_p; pressure_index++)
255 {
256 for (int k = 0; k < quad.nb_pts_integ_facets(); k++)
257 {
258 eval_jump_on_facet00(k) = -f_base_p0(pressure_index, k) * face_normales(face, d) * 0.5 * f_base_v0(velocity_index, k) / sur_f;
259 eval_jump_on_facet01(k) = +f_base_p1(pressure_index, k) * face_normales(face, d) * 0.5 * f_base_v0(velocity_index, k) / sur_f;
260 eval_jump_on_facet10(k) = -f_base_p0(pressure_index, k) * face_normales(face, d) * 0.5 * f_base_v1(velocity_index, k) / sur_f;
261 eval_jump_on_facet11(k) = +f_base_p1(pressure_index, k) * face_normales(face, d) * 0.5 * f_base_v1(velocity_index, k) / sur_f;
262 }
263 coeff00 = quad.compute_integral_on_facet(face, eval_jump_on_facet00);
264 coeff01 = quad.compute_integral_on_facet(face, eval_jump_on_facet01);
265 coeff10 = quad.compute_integral_on_facet(face, eval_jump_on_facet10);
266 coeff11 = quad.compute_integral_on_facet(face, eval_jump_on_facet11);
267
268 if (mat)
269 {
270 (*mat)(ind_elem0_v + velocity_index + d * nb_bfunc_v, ind_elem0_p + pressure_index) += coeff00;
271 (*mat)(ind_elem0_v + velocity_index + d * nb_bfunc_v, ind_elem1_p + pressure_index) += coeff01;
272 (*mat)(ind_elem1_v + velocity_index + d * nb_bfunc_v, ind_elem0_p + pressure_index) += coeff10;
273 (*mat)(ind_elem1_v + velocity_index + d * nb_bfunc_v, ind_elem1_p + pressure_index) += coeff11;
274 }
275 secmem(elem0, velocity_index + d * nb_bfunc_v) -= coeff00 * inco_p(elem0, pressure_index);
276 secmem(elem0, velocity_index + d * nb_bfunc_v) -= coeff01 * inco_p(elem1, pressure_index);
277 secmem(elem1, velocity_index + d * nb_bfunc_v) -= coeff10 * inco_p(elem0, pressure_index);
278 secmem(elem1, velocity_index + d * nb_bfunc_v) -= coeff11 * inco_p(elem1, pressure_index);
279 }
280 }
281 }
282 }
283}
284
285DoubleTab& Op_Grad_DG::calculer(const DoubleTab& pressure, DoubleTab& grad) const
286{
287 grad = 0.;
288 return ajouter(pressure, grad);
289}
290
291
293{
294 return 0;
295}
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.
classe Domaine_Cl_dis_base Les objets Domaine_Cl_dis_base representent les conditions aux limites
classe Domaine_dis_base Cette classe est la base de la hierarchie des domaines discretisees.
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
DG gradient operator acting on a DG pressure field to produce a velocity-space residual.
Definition Op_Grad_DG.h:46
void ajouter_blocs(matrices_t matrices, DoubleTab &secmem, const tabs_t &semi_impl={ }) const override
Assembles the DG gradient operator into the matrix and right-hand side.
int impr(Sortie &os) const override
DOES NOTHING - to override in derived classes.
void dimensionner_blocs(matrices_t matrices, const tabs_t &semi_impl={}) const override
Sizes the velocity-pressure matrix block for the gradient operator.
DoubleTab & calculer(const DoubleTab &, DoubleTab &) const override
void associer(const Domaine_dis_base &, const Domaine_Cl_dis_base &, const Champ_Inc_base &) override
Associates the operator with a DG domain and its boundary conditions.
Classe Operateur_Grad_base Cette classe est la base de la hierarchie des operateurs representant.
DoubleTab & ajouter(const DoubleTab &inco, DoubleTab &secmem) const override
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