TrioCFD 1.9.9_beta
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 // "Standard" method for computing the time step
71 // This estimate is very conservative: if the maximum diffusivity
72 // is not co-located with the minimum delta_h_squared,
73 // the time step will be underestimated.
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: field at elements and faces
135 // Variable density field.
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 // VDF-type cell (deux_dim faces on the element)
145 // ToDo: implement for the case 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); // multiply by 0.5 because each face is counted twice
152 }
153 // See 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; // already computed
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 // uniform diffusivity
246 int n = nu_.dimension_tot(0), nb_comp = nu_.line_size();
247 // Arrays viewed as one-dimensional:
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 // uniform diffusivity
285 int n = nu_.dimension_tot(0), nb_comp = nu_.line_size();
286 // Arrays viewed as one-dimensional:
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
Overrides Champ_base::valeurs() Returns the array of values.
Class Champ_Inc_base.
virtual DoubleTab & valeurs()=0
Champ_Uniforme Represents a field that is constant in space and time.
class Champ_base This class is the base of the fields hierarchy.
Definition Champ_base.h:43
class Champ_front_base Base class for the hierarchy of boundary fields.
virtual DoubleTab & valeurs() override
Returns the array of field values.
class Cond_lim_base Base class for the hierarchy of classes that represent the different boundary con...
int_t nb_elem() const
Definition Domaine.h:131
class Domaine_Cl_dis_base Domaine_Cl_dis_base objects represent discretized boundary conditions
int nb_cond_lim() const
Returns the number of boundary conditions.
const Cond_lim & les_conditions_limites(int) const
Returns the i-th boundary condition.
class Domaine_dis_base This class is the base of the hierarchy of discretized domains.
Classe Echange_externe_impose: This class represents the special case of the class.
virtual double h_imp(int num) const
Returns the value of the imposed heat exchange coefficient on the i-th component.
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
Milieu_base This class is the base of the (physical) medium hierarchy.
Definition Milieu_base.h:50
virtual const Champ_Don_base & conductivite() const
Returns the conductivity of the medium (const version).
const Equation_base & equation() const
Returns the reference to the equation pointed to by MorEqn::mon_equation.
Definition MorEqn.h:62
static int dimension
Definition Objet_U.h:94
friend class Sortie
Definition Objet_U.h:70
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
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
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
Operateur_Diff_base This class is the base of the hierarchy of operators representing.
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...
virtual void completer()
Associates the operator with the domaine_dis, the domaine_Cl_dis, and the unknown of its equation.
virtual DoubleTab & ajouter(const DoubleTab &, DoubleTab &) const
static double mp_min(double)
Definition Process.cpp:391
static double mp_max(double)
Definition Process.cpp:379
Base class for output streams.
Definition Sortie.h:52
virtual const Champ_base & get_champ_masse_volumique() const
Returns the density field.
virtual int has_champ_masse_volumique() const
Returns 1 if the density field has been associated, 0 otherwise.
_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