TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Transport_K_Eps_base.cpp
1/****************************************************************************
2* Copyright (c) 2019, 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 <Transport_K_Eps_base.h>
17#include <Schema_Temps_base.h>
18#include <Domaine_VF.h>
19#include <Domaine_VEF.h>
20#include <Champ_Inc_P0_base.h>
21#include <communications.h>
22#include <Probleme_base.h>
23#include <Discret_Thyd.h>
24#include <Param.h>
25#include <Debog.h>
26
27Implemente_base(Transport_K_Eps_base, "Transport_K_Eps_base", Transport_2eq_base);
28// XD Transport_K_Eps_base Transport_2eq_base Transport_K_Eps_base BRACE Base equation for RANS k-eps model. Should not
29// XD_CONT be used directly
30
31/*! @brief
32 *
33 * @param (Sortie& is) un flot de sortie
34 * @return (Sortie&) le flot de sortie modifie
35 */
37{ return is << que_suis_je() << "\n"; }
38
39/*! @brief Simple appel a Equation_base::readOn(Entree&)
40 *
41 * @param (Entree& is) un flot d'entree
42 * @return (Entree&) le flot d'entree modifie
43 */
45{
47 return is;
48}
50{
51 param.ajouter_flag("exit_on_negative_k_eps", &exit_on_negative_k_eps_); // X_D_ADD_P flag Flag to exit (with postprocessing of fields) if a negative value is found for k or epsilon
52 param.ajouter_flag("exit_on_big_eps", &exit_on_big_eps_); // X_D_ADD_P flag Flag to exit (with postprocessing of fields) if an excessively big values of epsilon is found
54}
55
56
58{
59 if (sub_type(Discret_Thyd,discretisation()))
60 {
61 Cerr << "K,Eps transport equation ("<< que_suis_je() <<") discretization" << finl;
62 Cerr << "K_Eps field discretization" << finl;
63 Noms noms(2);
64 Noms unit(2);
65 noms[0]="K";
66 noms[1]="eps";
67 unit[0]="m2/s2";
68 unit[1]="m2/s3";
69
70 discretisation().discretiser_champ("temperature",domaine_dis(),multi_scalaire,noms,unit,2,schema_temps().nb_valeurs_temporelles(),schema_temps().temps_courant(),le_champ_K_Eps);
71 le_champ_K_Eps->nommer("K_Eps");
72 champs_compris_.ajoute_champ(le_champ_K_Eps);
74 {
76 }
77
79 }
80 else
81 {
82 Cerr<<" Transport_K_Eps_base::discretiser "<<finl;
83 Cerr<<"Discretization "<<discretisation().que_suis_je()<<" not recognized."<<finl;
85 }
86}
87
88/*! @brief Controle le champ inconnue K-epsilon en forcant a zero les valeurs du champ
89 *
90 * inferieurs a 1.e-10.
91 *
92 * @return (int) renvoie toujours 1 (c'est tres utile)
93 */
95{
96 DoubleTab& tab_K_Eps = le_champ_K_Eps->valeurs();
97
98 // size == nb_elem in VDF or nb_faces in VEF
99 int size = tab_K_Eps.dimension(0);
100
101 // can this situation really happen ?
102 if (size < 0)
103 {
104 if (sub_type(Champ_Inc_P0_base, le_champ_K_Eps.valeur()))
105 {
106 size = le_champ_K_Eps->equation().domaine_dis().domaine().nb_elem();
107 }
108 else
109 {
110 Cerr << "Unsupported K_Eps field in Transport_K_Eps_base::controler_K_Eps()" << finl;
111 Process::exit(1);
112 }
113 }
114
115 // these will store the amounts of problematic values of k or eps found
116 int count_negative_k = 0;
117 int count_negative_eps = 0;
118 int count_big_eps = 0;
119
120
121 // On interdit K-Eps negatif pour le K-Eps seulement
122 // Les autres modeles (2 couches, Launder, ne sont pas assez valides)
123 Debog::verifier("Transport_K_Eps_base::controler_K_Eps K_Eps before", tab_K_Eps);
124 const Domaine_VF& domaine_vf = ref_cast(Domaine_VF,domaine_dis());
125 bool vef_algo = sub_type(Domaine_VEF, domaine_vf) and not(disable_VEF_mean_value_corrections_);
126 double EPS_MIN = modele_turbulence().get_EPS_MIN();
127 double EPS_MAX = modele_turbulence().get_EPS_MAX();
128 double K_MIN = modele_turbulence().get_K_MIN();
129 int nb_faces_elem = domaine_vf.elem_faces().line_size();
130 // PL on ne fixe au seuil minimum que si negatifs
131 // car la loi de paroi peut fixer a des valeurs tres petites
132 // et le rapport K*K/eps est coherent
133 // Changement: 13/12/07: en cas de valeurs negatives pour k OU eps
134 // on fixe k ET eps a une valeur moyenne des 2 elements voisins
135
136 // PL: 09/12/25 GPU parallel algorithm has slower convergence on FLOREAL_KEPS study
137 // so we revert back to the CPU algorithm (sequential and numerotation dependent...)
138 // Need to think hard about a robust algorithm to control K-Eps values...
139 if (getenv("TRUST_CONTROL_KEPS_GPU")==nullptr)
140 {
141 const IntTab& face_voisins = domaine_vf.face_voisins();
142 const IntTab& elem_faces = domaine_vf.elem_faces();
143 ToDo_Kokkos("critical");
144 for (int n = 0; n < size; n++)
145 {
146 double& k = tab_K_Eps(n, 0);
147 double& eps = tab_K_Eps(n, 1);
148
149 // correct big values of epsilon
150 if (eps > EPS_MAX)
151 {
152 count_big_eps++;
153 eps = EPS_MAX;
154 }
155
156 // correct negative values of k or epsilon
157 if ((k < 0 || eps < 0) )
158 {
159 count_negative_k += ( k<0 ? 1 : 0);
160 count_negative_eps += (eps<0 ? 1 : 0);
161
162 // On impose une valeur plus physique (moyenne des elements voisins)
163 k = 0;
164 eps = 0;
165 int nk = 0;
166 int neps = 0;
167
168 if (vef_algo)
169 {
170 // Here we are in VEF discretization
171 for (int i = 0; i < 2; i++)
172 {
173 int elem = face_voisins(n, i);
174 if (elem != -1)
175 for (int j = 0; j < nb_faces_elem; j++)
176 if (j != n)
177 {
178 double k_face = tab_K_Eps(elem_faces(elem, j), 0);
179 if (k_face > K_MIN)
180 {
181 k += k_face;
182 nk++;
183 }
184 double e_face = tab_K_Eps(elem_faces(elem, j), 1);
185 if (e_face > EPS_MIN)
186 {
187 eps += e_face;
188 neps++;
189 }
190 }
191 }
192 }
193
194 if (nk != 0) {k /= nk;}
195 else {k = K_MIN;}
196 if (neps != 0) { eps /= neps; }
197 else { eps = EPS_MIN; }
198
199 } // fin (k < 0 || eps < 0)
200 }
201 }
202 else
203 {
204 CIntTabView face_voisins = domaine_vf.face_voisins().view_ro();
205 CIntTabView elem_faces = domaine_vf.elem_faces().view_ro();
206 DoubleTabView K_Eps = tab_K_Eps.view_rw();
207
208 // Two-phase parallel algorithm:
209 // Phase 1: Detection and counting with parallel reductions
210 // Phase 2: Correction with safe neighbor averaging
211
212 // Phase 1: Parallel detection and counting + simple corrections
213 struct CountValues
214 {
215 int count_k;
216 int count_eps;
217 int count_big;
218
219 KOKKOS_INLINE_FUNCTION
220 CountValues() : count_k(0), count_eps(0), count_big(0) {}
221
222 KOKKOS_INLINE_FUNCTION
223 CountValues(const CountValues& rhs) : count_k(rhs.count_k), count_eps(rhs.count_eps),
224 count_big(rhs.count_big) {}
225
226 KOKKOS_INLINE_FUNCTION CountValues& operator=(const CountValues&) = default;
227
228 KOKKOS_INLINE_FUNCTION
229 void operator+=(const CountValues& rhs)
230 {
231 count_k += rhs.count_k;
232 count_eps += rhs.count_eps;
233 count_big += rhs.count_big;
234 }
235 };
236
237 CountValues result;
238 Kokkos::parallel_reduce(start_gpu_timer(__KERNEL_NAME__), size,
239 KOKKOS_LAMBDA(const int n, CountValues &local_count)
240 {
241 double& k = K_Eps(n, 0);
242 double& eps = K_Eps(n, 1);
243
244 // Count and correct big values of epsilon (simple correction, no dependencies)
245 if (eps > EPS_MAX)
246 {
247 local_count.count_big++;
248 eps = EPS_MAX;
249 }
250
251 // Count negative values (correction will be done in phase 2)
252 if (k < 0) local_count.count_k++;
253 if (eps < 0) local_count.count_eps++;
254
255 }, result);
256 end_gpu_timer(__KERNEL_NAME__);
257
258 count_negative_k = result.count_k;
259 count_negative_eps = result.count_eps;
260 count_big_eps = result.count_big;
261
262 // Phase 2: Parallel correction of negative values with neighbor averaging
263 // Create a snapshot of original values to ensure consistent neighbor averaging
264 DoubleTrav K_Eps_original(tab_K_Eps);
265 CDoubleTabView K_Eps_orig = K_Eps_original.view_ro();
266 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), size, KOKKOS_LAMBDA(const int n)
267 {
268 double& k = K_Eps(n, 0);
269 double& eps = K_Eps(n, 1);
270
271 // correct negative values of k or epsilon
272 // IMPORTANT: In original algorithm, when EITHER k OR eps is negative, BOTH are corrected
273 if ((k < 0 || eps < 0))
274 {
275 // On impose une valeur plus physique (moyenne des elements voisins)
276 double k_new = 0;
277 double eps_new = 0;
278 int nk = 0;
279 int neps = 0;
280
281 if (vef_algo)
282 {
283 // Here we are in VEF discretization
284 for (int i = 0; i < 2; i++)
285 {
286 int elem = face_voisins(n, i);
287 if (elem != -1)
288 {
289 for (int j = 0; j < nb_faces_elem; j++)
290 {
291 if (j != n)
292 {
293 // Use original values for consistent neighbor averaging
294 double k_face = K_Eps_orig(elem_faces(elem, j), 0);
295 if (k_face > K_MIN)
296 {
297 k_new += k_face;
298 nk++;
299 }
300 double e_face = K_Eps_orig(elem_faces(elem, j), 1);
301 if (e_face > EPS_MIN)
302 {
303 eps_new += e_face;
304 neps++;
305 }
306 }
307 }
308 }
309 }
310 }
311
312 // Apply corrections to BOTH k and eps when either is negative (like original algorithm)
313 k = (nk != 0) ? (k_new / nk) : K_MIN;
314 eps = (neps != 0) ? (eps_new / neps) : EPS_MIN;
315 }
316 });
317 end_gpu_timer(__KERNEL_NAME__);
318 }
319 tab_K_Eps.echange_espace_virtuel();
320 Debog::verifier("Transport_K_Eps_base::controler_K_Eps K_Eps after", tab_K_Eps);
321
322 if (schema_temps().limpr() && !modele_turbulence().get_lquiet())
323 {
324 if (count_negative_k > 0 || count_negative_eps > 0)
325 {
326 const double time = le_champ_K_Eps->temps();
327
328 Journal() << "WARNING: Some values values forced for k and eps:" << finl;
329 if (count_negative_k > 0)
330 Journal() << "Negative values of k found on :" << count_negative_k << "/" << size << " nodes at time " << time << finl;
331 if (count_negative_eps > 0)
332 Journal() << "Negative values of eps found on :" << count_negative_eps << "/" << size << " nodes at time " << time << finl;
333
334 // Warning if more than 0.01% of nodes are values fixed
335 double ratio_k = 100. * count_negative_k / size;
336 double ratio_eps = 100. * count_negative_eps / size;
337 if ((ratio_k > 0.01 || ratio_eps > 0.01))
338 {
339 Cerr << "WARNING: Found high ratio of invalid values for k and/or epsilon (more that 0.01%) on process" << Process::me() << finl;
340 Cerr << "Check journal log file for more information. These messages can be disabled with the flag 'quiet' in modele_turbulence." << finl;
341
342 Journal() << "WARNING: Found high ratio of invalid values for k and/or epsilon (more that 0.01%)." << finl;
343 Journal() << "It is possible your initial and/or boundary conditions on k and/or eps are wrong." << finl;
344 Journal() << "Check the initial and boundary values for k and eps by using:" << finl;
345 Journal() << "k~" << (dimension == 2 ? "" : "3/2*") << "(t*U)^2 (t turbulence rate, U mean velocity) ";
346 Journal() << "and eps~Cmu^0.75 k^1.5/l with l turbulent length scale and Cmu a k-eps model parameter whose value is typically given as 0.09." << finl;
347 Journal() << "Remark : by giving the velocity field (u) and the hydraulic diameter (d), by using boundary_field_uniform_keps_from_ud and field_uniform_keps_from_ud, " << finl;
348 Journal() << "respectively for boudnaries and initial conditions, TrioCFD will determine automatically values for k and eps." << finl;
349 if (probleme().is_dilatable() == 1)
350 {
351 Journal() << "Please, don't forget (sorry for this TrioCFD syntax weakness) that when using Quasi-Compressible module" << finl;
352 Journal() << "the unknowns for which you define initial and boundary conditions are rho*k and rho*eps." << finl;
353 }
354 }
355
356 if (exit_on_negative_k_eps_)
357 {
358 // actually, this is writing the corrected field, so not very useful
359 probleme().postraiter(1);
361 };
362 }
363
364 if (count_big_eps> 0)
365 {
366 const double time = le_champ_K_Eps->temps();
367 Journal() << "WARNING: Some values values forced for k and eps:" << finl;
368 Journal() << "Excessive values of eps found on " << count_big_eps << "/" << size << " nodes at time " << time << finl;
369
370 if (exit_on_big_eps_)
371 {
372 // actually, this is writing the corrected field, so not very useful
373 probleme().postraiter(1);
375 };
376 }
377 }
378
379 return 1;
380}
381
382/*! @brief Method to correct the field K_Eps after an iteration
383 *
384 * Calls Transport_K_Eps_base::controler_K_Eps() which does the work.
385 *
386 * WARNING: The method controler_K_Eps is also called from Modele_turbulence_hyd_K_Eps_XXX::controler()
387 *
388 */
: class Champ_Inc_P0_base
static void verifier(const char *const msg, double)
Definition Debog.cpp:21
classe Discret_Thyd Cette classe est la classe de base representant une discretisation
void discretiser_champ(const Motcle &directive, const Domaine_dis_base &z, const Nom &nom, const Nom &unite, int nb_comp, int nb_pas_dt, double temps, OWN_PTR(Champ_Inc_base)&champ, const Nom &sous_type=NOM_VIDE) const
class Domaine_VEF
Definition Domaine_VEF.h:54
class Domaine_VF
Definition Domaine_VF.h:44
int elem_faces(int i, int j) const
renvoie le numero de le ieme face de la maille num_elem la facon dont ces faces sont numerotees est
Definition Domaine_VF.h:543
int face_voisins(int num_face, int i) const
renvoie l'element voisin de numface dans la direction i.
Definition Domaine_VF.h:418
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
void set_calculate_time_derivative(int i)
const Discretisation_base & discretisation() const
Renvoie la discretisation associee a l'equation.
int calculate_time_derivative() const
Probleme_base & probleme()
Renvoie le probleme associe a l'equation.
int limpr() const
Demande au schema en temps si il faut effectuer une impression.
Schema_Temps_base & schema_temps()
Renvoie le schema en temps associe a l'equation.
virtual void discretiser()
Discretise l'equation.
Champs_compris champs_compris_
Domaine_dis_base & domaine_dis()
Renvoie le domaine discretise associe a l'equation.
Un tableau de chaine de caracteres (VECT(Nom)).
Definition Noms.h:26
const Objet_U & operator=(const Objet_U &)
Operateur= : ne fait rien (on conserve le numero et l'identifiant).
Definition Objet_U.cpp:87
static int dimension
Definition Objet_U.h:99
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
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter_flag(const char *keyword, const bool *value)
Register a boolean flag whose mere presence switches it to true.
Definition Param.cpp:474
int postraiter(int force=1) override
Si force=1, effectue le postraitement sans tenir compte des frequences de postraitement.
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
Classe de base des flux de sortie.
Definition Sortie.h:52
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, ConstView< _TYPE_, _SHAPE_ > > view_ro() const
Definition TRUSTTab.h:261
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, View< _TYPE_, _SHAPE_ > > view_rw()
Definition TRUSTTab.h:291
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")
Classe Transport_2eq_base Classe de base pour les equations.
void set_param(Param &) const override
const Modele_turbulence_hyd_2_eq_base & modele_turbulence() const
Renvoie le modele de turbulence associe a l'equation.
Classe Transport_K_Eps_base Classe de base pour les equations.
void discretiser() override
Discretise l'equation.
virtual void set_param(Param &) const override
int controler_K_Eps()
Controle le champ inconnue K-epsilon en forcant a zero les valeurs du champ.
void valider_iteration() override
Method to correct the field K_Eps after an iteration.