TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Op_Diff_DG_base.cpp
1/****************************************************************************
2* Copyright (c) 2026, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <Modele_turbulence_scal_base.h>
17#include <Echange_externe_impose.h>
18#include <Op_Diff_DG_base.h>
19#include <Check_espace_virtuel.h>
20#include <Domaine_Cl_DG.h>
21#include <Champ_Elem_DG.h>
22#include <Champ_Fonc_P0_base.h>
23#include <Schema_Temps_base.h>
24#include <Domaine_DG.h>
25#include <Champ_Uniforme.h>
26#include <communications.h>
27#include <Probleme_base.h>
28#include <EcrFicPartage.h>
29#include <Milieu_base.h>
30#include <TRUSTTrav.h>
31#include <SFichier.h>
32
33Implemente_base(Op_Diff_DG_base, "Op_Diff_DG_base", Operateur_Diff_base);
34
35Sortie& Op_Diff_DG_base::printOn(Sortie& s) const { return s << que_suis_je(); }
36
37Entree& Op_Diff_DG_base::readOn(Entree& s) { return s; }
38
39/**
40 * @brief Computes the maximum stable explicit time step for the diffusion operator.
41 *
42 * @details Two branches are handled depending on whether a variable density field is present:
43 *
44 * - **Constant density** (standard branch): The criterion is
45 * dt = h_min^2 / (2 * dim * alpha_max),
46 * where h_min is the minimum mesh size and alpha_max is the maximum diffusivity over all elements.
47 * This estimate is conservative: if the maximum diffusivity and the minimum mesh size are not
48 * co-located, the time step will be underestimated.
49 * Additionally, if a Robin boundary condition (Echange_externe_impose) is present, the Biot number
50 * Bi = h_imp_max * sqrt(h_min^2) / lambda_max
51 * is computed. If Bi > 1, alpha_max is scaled by the same factor, further tightening the criterion.
52 *
53 * - **Variable density** (rho field present): A per-element time step is computed as
54 * dt = 0.5 * rho / (nu * h), for VDF-like elements (exactly 2*dim faces),
55 * dt = rho * h^2 / (2 * dim * nu), for general elements,
56 * and the global minimum is taken across all elements and MPI processes.
57 *
58 * @return The minimum stable time step across all elements and MPI processes.
59 */
61{
62 update_nu();
63 const Domaine& mon_dom = le_dom_dg_->domaine();
64 double dt_stab = DMAXFLOAT;
65
66 const int nb_elem = mon_dom.nb_elem();
67
69 {
70 // Methode "standard" de calcul du pas de temps
71 // Ce calcul est tres conservatif: si le max de la diffusivite
72 // n'est pas atteint a l'endroit ou le min de delta_h_carre est atteint,
73 // le pas de temps est sous-estime.
74 const Champ_base& champ_diffusivite = diffusivite_pour_pas_de_temps();
75 const DoubleVect& valeurs_diffusivite = champ_diffusivite.valeurs();
76 double alpha_max = local_max_vect(valeurs_diffusivite);
77
78 // Detect if a heat flux is imposed on a boundary through Paroi_echange_externe_impose keyword
79 double h_imp_max = -1, h_imp_temp = -2;
80
81 const Domaine_Cl_DG& le_dom_cl_dg = la_zcl_dg_.valeur();
82 for (int i = 0; i < le_dom_cl_dg.nb_cond_lim(); i++)
83 {
84 // loop on boundaries
85 const Cond_lim_base& la_cl = le_dom_cl_dg.les_conditions_limites(i).valeur();
86
87 if (sub_type(Echange_externe_impose, la_cl))
88 {
89 const Echange_externe_impose& la_cl_int = ref_cast(Echange_externe_impose, la_cl);
90 const Champ_front_base& le_ch_front = ref_cast(Champ_front_base, la_cl_int.h_imp());
91 const DoubleVect& tab = le_ch_front.valeurs();
92 if (tab.size() != 0)
93 {
94 h_imp_temp = local_max_vect(tab); // get h_imp from datafile
95 h_imp_temp = std::fabs(h_imp_temp); // we should take the absolute value since it can be negative!
96 h_imp_max = (h_imp_temp > h_imp_max) ? h_imp_temp : h_imp_max; // Should we take the max if more than one bc has h_imp ?
97 }
98 }
99 } // End loop on boundaries
100 h_imp_max = Process::mp_max(h_imp_max);
101
102 if (alpha_max != 0.0 && nb_elem != 0)
103 {
104 double min_delta_h_carre = le_dom_dg_->carre_pas_du_maillage();
105 if (h_imp_max > 0.0) //a heat flux is imposed on a boundary condition
106 {
107 // get the thermal conductivity
108 const Equation_base& mon_eqn = le_dom_cl_dg.equation();
109 const Milieu_base& mon_milieu = mon_eqn.milieu();
110 const DoubleVect& tab_lambda = mon_milieu.conductivite().valeurs();
111 double max_conductivity = local_max_vect(tab_lambda);
112
113 // compute Biot number given by Bi = L*h/lambda.
114 double Bi = h_imp_max * sqrt(min_delta_h_carre) / max_conductivity;
115 // if Bi>1, replace conductivity by h_imp*h in diffusivity. We are very conservative since h_imp_max is not necessarily located where max_conductivity is.
116 if (Bi > 1.0)
117 alpha_max *= h_imp_max * sqrt(min_delta_h_carre) / max_conductivity;
118 }
119 dt_stab = min_delta_h_carre / (2. * dimension * alpha_max);
120 }
121
122 }
123 else
124 {
125 const int deux_dim = 2 * Objet_U::dimension;
126 const Champ_base& champ_diffu = diffusivite();
127 const DoubleTab& valeurs_diffu = champ_diffu.valeurs();
128 const Champ_base& champ_rho = get_champ_masse_volumique();
129 const DoubleTab& valeurs_rho = champ_rho.valeurs();
130
131 assert(sub_type(Champ_Elem_DG, champ_rho));
132 assert(sub_type(Champ_Fonc_P0_base, champ_diffu));
133 // assert(valeurs_rho.size_array()== mon_dom.les_elems().dimension_tot(0));
134 // Champ_Elem_DG : champ aux elems et aux faces
135 // Champ de masse volumique variable.
136 const IntTab& e_f = le_dom_dg_->elem_faces();
137 for (int elem = 0; elem < nb_elem; elem++)
138 {
139 const double diffu = valeurs_diffu(elem);
140 const double rho = valeurs_rho(elem);
141 double dt;
142 if (e_f.dimension(1) == deux_dim || e_f(elem, deux_dim) == -1)
143 {
144 // Maille type VDF (deux_dim faces sur l'element)
145 // ToDo: coder dans le cas has_champ_masse_volumique()==false
146 double h = 0;
147 for (int f = 0; f < deux_dim; f++)
148 {
149 int face = e_f(elem, f);
150 const double d = le_dom_dg_->volumes(elem) / le_dom_dg_->face_surfaces(face);
151 h += 0.5 / (d * d); // On multiplie par 0.5 car face comptee 2 fois
152 }
153 // Voir Op_Diff_VDF_Elem_base::calculer_dt_stab():
154 dt = 0.5 * rho / ((diffu + DMINFLOAT) * h);
155 }
156 else
157 {
158 dt = le_dom_dg_->carre_pas_maille(elem) * rho / (deux_dim * (diffu + DMINFLOAT));
159 }
160 if (dt < dt_stab)
161 dt_stab = dt;
162 }
163 }
164
165 dt_stab = Process::mp_min(dt_stab);
166 return dt_stab;
167}
168
170{
171 return 1;
172}
173
174/**
175 * @brief Associates the operator with a DG domain and its boundary conditions.
176 */
178{
179 le_dom_dg_ = ref_cast(Domaine_DG, domaine_dis);
180 la_zcl_dg_ = ref_cast(Domaine_Cl_DG, zcl);
181}
182
183/**
184 * @brief Computes the diffusion operator applied to inco and stores the result in resu.
185 * @details Initializes resu to zero then delegates to ajouter(), which adds the diffusive
186 * contribution. This follows the standard TRUST operator pattern where calculer()
187 * resets the result before calling ajouter().
188 * @param inco The input field (e.g., temperature, velocity component).
189 * @param resu The output field, zeroed then filled with the diffusion contribution.
190 * @return A reference to resu.
191 */
192DoubleTab& Op_Diff_DG_base::calculer(const DoubleTab& inco, DoubleTab& resu) const
193{
194 resu = 0.;
195 return ajouter(inco, resu);
196}
197
198/**
199 * @brief Finalizes the operator setup after all associations have been made.
200 * @details Calls the parent completer(), then allocates and initializes the effective
201 * diffusivity table nu_. The number of components is set to 2 for the
202 * Transport_K_Epsilon equation (one per turbulent quantity), or to the
203 * line size of the diffusivity field for all other equations.
204 * The nu_a_jour_ flag is reset to 0 to force a recomputation on the first use.
205 */
207{
209 nu_.resize(0, equation().que_suis_je() == "Transport_K_Epsilon" ? 2 : diffusivite().valeurs().line_size());
210 le_dom_dg_->domaine().creer_tableau_elements(nu_);
211 nu_a_jour_ = 0;
212}
213
214/**
215 * @brief Updates the cached effective diffusivity field nu_ by combining molecular and turbulent contributions.
216 *
217 * @details This method is a no-op if nu_a_jour_ is already set. Otherwise, it fills nu_ as follows:
218 *
219 * 1. **Molecular diffusivity** (all equations except Transport_K_Epsilon):
220 * - If the diffusivity has no metadata vector (i.e., it is spatially uniform), nu_ is filled
221 * by broadcasting the uniform value to all elements, treating both arrays as flat 1D vectors.
222 * - Otherwise (spatially variable diffusivity), nu_ is directly injected from the diffusivity array,
223 * after asserting that both share the same parallel metadata vector.
224 *
225 * 2. Not usable for now: **Turbulent diffusivity** (if has_diffusivite_turbulente() is true):
226 * @warning This branch is currently unreachable: it starts with a throw statement,
227 * indicating that turbulent diffusivity is not yet supported for DG operators.
228 * - For Transport_K_Epsilon, nu_(i,j) = nu_molecular(i) + nu_turb(i,j) for j in {0,1}.
229 * - For other equations, nu_turb is added to nu_ element-wise, handling the uniform case
230 * (no metadata vector) and the variable case separately.
231 *
232 * After the update, nu_a_jour_ is set to 1 to prevent redundant recomputations.
233 */
235{
236 if (nu_a_jour_) return; // on a deja fait le travail
237
238 int i, j;
239
240 const DoubleTab& diffu = diffusivite().valeurs();
241 if (equation().que_suis_je() != "Transport_K_Epsilon")
242 {
243 if (!diffu.get_md_vector())
244 {
245 // diffusivite uniforme
246 int n = nu_.dimension_tot(0), nb_comp = nu_.line_size();
247 // Tableaux vus comme uni-dimenionnels:
248 const DoubleVect& arr_diffu = diffu;
249 DoubleVect& arr_nu = nu_;
250 for (i = 0; i < n; i++)
251 for (j = 0; j < nb_comp; j++)
252 arr_nu[i * nb_comp + j] = arr_diffu[j];
253 }
254 else
255 {
256 assert(nu_.get_md_vector() == diffu.get_md_vector());
257 assert_espace_virtuel_vect(diffu);
258 nu_.inject_array(diffu);
259 }
260 }
261
262 /* ajout de la diffusivite turbulente si elle existe */
264 {
265 throw;
266
267 const DoubleTab& diffu_turb = diffusivite_turbulente().valeurs();
268 if (equation().que_suis_je() == "Transport_K_Epsilon")
269 {
270 bool nu_uniforme = sub_type(Champ_Uniforme, diffusivite());
271 double val_nu = diffu(0, 0);
272 for (i = 0; i < diffu_turb.dimension(0); i++)
273 for (j = 0; j < 2; j++)
274 {
275 if (!nu_uniforme)
276 val_nu = diffu(i, 0);
277 nu_(i, j) = val_nu + diffu_turb(i, j);
278 }
279 }
280 else
281 {
282 if (!diffu_turb.get_md_vector())
283 {
284 // diffusvite uniforme
285 int n = nu_.dimension_tot(0), nb_comp = nu_.line_size();
286 // Tableaux vus comme uni-dimenionnels:
287 const DoubleVect& arr_diffu_turb = diffu_turb;
288 DoubleVect& arr_nu = nu_;
289 for (i = 0; i < n; i++)
290 for (j = 0; j < nb_comp; j++)
291 arr_nu[i * nb_comp + j] += arr_diffu_turb[j];
292 }
293 else
294 {
295 assert(nu_.get_md_vector() == diffu_turb.get_md_vector());
296 assert_espace_virtuel_vect(diffu_turb);
297 nu_ += diffu_turb;
298 }
299 }
300 }
301
302 nu_a_jour_ = 1;
303}
DoubleTab & valeurs() override
Surcharge Champ_base::valeurs() Renvoie le tableau des valeurs.
Classe Champ_Inc_base.
virtual DoubleTab & valeurs()=0
classe Champ_Uniforme Represente un champ constant dans l'espace et dans le temps.
classe Champ_base Cette classe est la base de la hierarchie des champs.
Definition Champ_base.h:43
classe Champ_front_base Classe de base pour la hierarchie des champs aux frontieres.
virtual DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ.
classe Cond_lim_base Classe de base pour la hierarchie des classes qui representent les differentes c...
int_t nb_elem() const
Definition Domaine.h:131
classe Domaine_Cl_dis_base Les objets Domaine_Cl_dis_base representent les conditions aux limites
int nb_cond_lim() const
Renvoie le nombre de conditions aux limites.
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
classe Domaine_dis_base Cette classe est la base de la hierarchie des domaines discretisees.
Classe Echange_externe_impose: Cette classe represente le cas particulier de la classe.
virtual double h_imp(int num) const
Renvoie la valeur du coefficient d'echange de chaleur impose sur la i-eme composante.
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
classe Milieu_base Cette classe est la base de la hierarchie des milieux (physiques)
Definition Milieu_base.h:50
virtual const Champ_Don_base & conductivite() const
Renvoie la conductivite du milieu.
const Equation_base & equation() const
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
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....
DoubleTab & calculer(const DoubleTab &, DoubleTab &) const override
Computes the diffusion operator applied to inco and stores the result in resu.
double calculer_dt_stab() const override
Computes the maximum stable explicit time step for the diffusion operator.
int impr(Sortie &os) const override
DOES NOTHING - to override in derived classes.
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.
void completer() override
Finalizes the operator setup after all associations have been made.
const Champ_base & diffusivite() const override
void update_nu() const
Updates the cached effective diffusivity field nu_ by combining molecular and turbulent contributions...
const Champ_Fonc_base & diffusivite_turbulente() const
classe Operateur_Diff_base Cette classe est la base de la hierarchie des operateurs representant
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...
virtual void completer()
Associe l'operateur au domaine_dis, le domaine_Cl_dis, et a l'inconnue de son equation.
virtual DoubleTab & ajouter(const DoubleTab &, DoubleTab &) const
static double mp_min(double)
Definition Process.cpp:386
static double mp_max(double)
Definition Process.cpp:376
Classe de base des flux de sortie.
Definition Sortie.h:52
virtual const Champ_base & get_champ_masse_volumique() const
Renvoie le champ de masse volumique.
virtual int has_champ_masse_volumique() const
Renvoie 1 si la masse volumique a ete associee, 0 sinon.
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
virtual const MD_Vector & get_md_vector() const
Definition TRUSTVect.h:123