TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Source_Masse_Fluide_Dilatable_VEF.cpp
1/****************************************************************************
2* Copyright (c) 2025, 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 <Convection_Diffusion_Fluide_Dilatable_base.h>
17#include <Source_Masse_Fluide_Dilatable_VEF.h>
18#include <Fluide_Weakly_Compressible.h>
19#include <Champ_front_uniforme.h>
20#include <Domaine_VEF.h>
21#include <TRUSTTrav.h>
22#include <Domaine.h>
23#include <kokkos++.h>
24
25Implemente_instanciable(Source_Masse_Fluide_Dilatable_VEF,"Source_Masse_Fluide_Dilatable_VEF",Source_Masse_Fluide_Dilatable_base);
26
29/*
30 * Elie Saikali : Implementation notes
31 *
32 * - The classical system of binary mixture LMN equations (iso-thermal) is as follows
33 *
34 * Mass : d rho / dt + div (rho.u) = 0
35 * Momentum : ....
36 * Species : d(rho Y)/dt + div( rho*u*Y ) = div( rho*D*grad(Y) ), which using the mass equation
37 * is written in a non-conservative formulation as : rho d(Y)/dt + rho*u grad(Y) = div( rho*D*grad(Y) )
38 * and when divided by rho as : d(Y)/dt = div( rho*D*grad(Y) ) / rho - u grad(Y)
39 * EOS : ...
40 *
41 * - With the mass source term, the Mass equation becomes
42 *
43 * Mass : d rho / dt + div (rho.u) = S ( S in Kg / s / m3)
44 *
45 * This will induce an additional term in the Species equation that becomes
46 *
47 * Species : rho d(Y)/dt + rho*u grad(Y) = div( rho*D*grad(Y) ) - Y.S
48 * and when divided by rho as : d(Y)/dt = div( rho*D*grad(Y) ) / rho - u grad(Y) - Y.S / rho
49 *
50 * Other equations are not touched ...
51 *
52 *
53 * - Note that the mass equation is never explicitly solved. It is only used in the projection algorithm to correct the velocity using
54 *
55 * div (rho.u) = - d rho / dt + S
56 *
57 * Note that div (rho.u) is located as the pressure : on cell centers in VEF, cell centers + nodes in VEF
58 *
59 * - To code this source term, we have 2 situations (at present) : VDF and VEF. The source term is considered as a volumic one
60 * and is imposed on the first cell near the boundary where the mass is removed ...
61 *
62 * VEF : ////////////////////////
63 * --------------------------
64 * \ x /\ x /\ x /
65 * \ / \ / \ /
66 * \/ \/ \/
67 * --------------
68 *
69 * - FOR VEF : PAY ATTENTION
70 *
71 * Y on faces, P on cell centers + nodes. We need to apply the term source on the first cell touching the boundary !
72 *
73 * S = F * surf (F is in kg / m2 / s)
74 *
75 * For projection we code at the element center : F * surf / V , where
76 * surf and V are the surface of the cell touching the boundary and V is the volume of the tetra/triangle. As in VDF, this gives well the unit Kg / s / m3 ...
77 *
78 * After, we interpolate the elem values on the nodes of the tetra/triangle touching the boundary.
79 *
80 *
81 * For the species equation we code : - Y * F * surf / (rho * V ), where
82 * Y is the value interpolated on the elem, rho at boundary face, and V is teh volume_entrelaces for the bd face cell... This gives well the unit 1 / s, as d(Y)/dt !
83 *
84 */
86{
87 assert(sub_type(Fluide_Weakly_Compressible,fluide));
88
89 const Domaine_Cl_dis_base& zclb = domaine_cl_dis_.valeur();
90 const Domaine_VF& zvf = ref_cast(Domaine_VF, zclb.domaine_dis());
91 const int nb_faces = zvf.nb_faces();
92 DoubleTrav val_flux(nb_faces, 1);
93
94 CDoubleTabView val_flux0 = ch_front_source_->valeurs().view_ro();
95 DoubleTabView view_val_flux = val_flux.view_rw();
96 const int val_flux0_line_sz = ch_front_source_->valeurs().line_size();
97 CIntTabView face_voisins = zvf.face_voisins().view_ro();
98 CDoubleArrView face_surfaces = zvf.face_surfaces().view_ro();
99 CDoubleArrView rho = static_cast<const DoubleVect&>(fluide.masse_volumique().valeurs()).view_ro();
100
101 CDoubleArrView volumes_entrelaces = zvf.volumes_entrelaces().view_ro();
102 DoubleArrView view_resu = resu.view_rw();
103
104 // pour post
105 Champ_Don_base * post_src_ch = fluide.has_source_masse_espece_champ() ? &ref_cast_non_const(Fluide_Dilatable_base, fluide).source_masse_espece() : nullptr;
106
107 bool ok_post_src_ch = post_src_ch ? true:false;
108 DoubleArrView valeurs;
109 if (ok_post_src_ch) valeurs = static_cast<DoubleVect&>((*post_src_ch).valeurs()).view_wo();
110
111 /*
112 * XXX Elie Saikali mai 2025 : soucis avec ICoCo ...
113 * Attention : val_flux a dimension de nb_faces or val_flux0 a dimension de nb_faces du bord nom_bord_ ...
114 * faut bien remplir les bonnes faces ...
115 * On commence par remplir val_flux seulement pour les bonnes faces ...
116 * TODO FIXME utilise Source_Masse_Fluide_Dilatable_base::fill_val_flux_tab ...
117 */
118
119 for (int n_bord = 0; n_bord < domaine_cl_dis_->nb_cond_lim(); n_bord++)
120 {
121 const Cond_lim& la_cl = domaine_cl_dis_->les_conditions_limites(n_bord);
122 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
123
124 if (le_bord.le_nom() == nom_bord_)
125 {
126 // Handle uniform case ... such a pain:
127 const int is_uniforme = sub_type(Champ_front_uniforme, ch_front_source_.valeur());
128 const int ndeb = le_bord.num_premiere_face(), nfin = ndeb + le_bord.nb_faces();
129
130 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(ndeb, nfin), KOKKOS_LAMBDA (const int num_face)
131 {
132 for (int ncomp = 0; ncomp < val_flux0_line_sz; ncomp++)
133 view_val_flux(num_face, 0) += is_uniforme ? val_flux0(0, ncomp) : val_flux0(num_face - ndeb, ncomp);
134 });
135 end_gpu_timer(__KERNEL_NAME__);
136 }
137 }
138
139 // Maintennat on regarde resu ...
140 for (int n_bord = 0; n_bord < domaine_cl_dis_->nb_cond_lim(); n_bord++)
141 {
142 const Cond_lim& la_cl = domaine_cl_dis_->les_conditions_limites(n_bord);
143 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
144
145 if (le_bord.le_nom() == nom_bord_)
146 {
147 const int ndeb = le_bord.num_premiere_face(), nfin = ndeb + le_bord.nb_faces();
148 CIntTabView elem_faces = zvf.elem_faces().view_ro();
149 CDoubleArrView Y = static_cast<const ArrOfDouble&>(eqn.inconnue().valeurs()).view_ro();
150 int elem_faces_line_size = zvf.elem_faces().line_size();
151
152 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(ndeb, nfin), KOKKOS_LAMBDA (const int num_face)
153 {
154 const int elem1 = face_voisins(num_face, 0), elem2 = face_voisins(num_face, 1);
155 int elem = elem1 == -1 ? elem2 : elem1;
156 const double surface_elem = face_surfaces(num_face);
157 /*
158 * NOTA BENE : on cherche un facteur de correction car Y est aux faces
159 * Terme source surfacique, on utilise Y face => volume entrelaces
160 * Or P aux elems et sommets => on a pas le meme volume
161 * On interpole Y aux elem, le facteur = Yelem / Yface
162 *
163 * Conclusion : pour Y on utilise les valeurs aux elems pas faaces !
164 * Attention, on divise par rho(face) car c'est pas dans la formulation de terme source !
165 */
166 double YY = 0.;
167 for (int j = 0; j < elem_faces_line_size; j++)
168 YY += Y(elem_faces(elem, j));
169
170 YY /= elem_faces_line_size;
171 double srcmass = -(YY * view_val_flux(num_face, 0) * surface_elem) / rho(num_face);
172 if (is_expl)
173 srcmass /= volumes_entrelaces(num_face); // on divise par volume (pas de solveur masse dans l'equation ...)
174 view_resu(num_face) += srcmass;
175
176 // DOUBT_HARI: Could give a different result according to order of execution
177 if (ok_post_src_ch)
178 valeurs(elem) = srcmass;
179 });
180 end_gpu_timer(__KERNEL_NAME__);
181 }
182 }
183
184 // pour post
185 if (post_src_ch)
186 (*post_src_ch).mettre_a_jour(fluide.inco_chaleur().temps());
187}
188
190{
191 assert(sub_type(Fluide_Weakly_Compressible,fluide));
192 const Domaine_Cl_dis_base& zclb = domaine_cl_dis_.valeur();
193 const Domaine_VEF& zp1b = ref_cast(Domaine_VEF, zclb.domaine_dis());
194 // pour post
195 Champ_Don_base * post_src_ch = fluide.has_source_masse_projection_champ() ? &ref_cast_non_const(Fluide_Dilatable_base, fluide).source_masse_projection() : nullptr;
196
197 const int nb_faces = zp1b.nb_faces();
198 const int val_flux0_line_sz = ch_front_source_->valeurs().line_size();
199 DoubleTrav tab_val_flux(nb_faces, 1);
200
201 CDoubleTabView val_flux0 = ch_front_source_->valeurs().view_ro();
202 DoubleTabView val_flux = tab_val_flux.view_rw();
203
204 /*
205 * XXX Elie Saikali mai 2025 : soucis avec ICoCo ...
206 * Attention : val_flux a dimension de nb_faces or val_flux0 a dimension de nb_faces du bord nom_bord_ ...
207 * faut bien remplir les bonnes faces ...
208 * On commence par remplir val_flux seulement pour les bonnes faces ...
209 * TODO FIXME utilise Source_Masse_Fluide_Dilatable_base::fill_val_flux_tab ...
210 */
211
212 for (int n_bord = 0; n_bord < domaine_cl_dis_->nb_cond_lim(); n_bord++)
213 {
214 const Cond_lim& la_cl = domaine_cl_dis_->les_conditions_limites(n_bord);
215 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
216
217 if (le_bord.le_nom() == nom_bord_)
218 {
219 // Handle uniform case ... such a pain:
220 const int is_uniforme = sub_type(Champ_front_uniforme, ch_front_source_.valeur());
221 const int ndeb = le_bord.num_premiere_face(), nfin = ndeb + le_bord.nb_faces();
222
223 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(ndeb, nfin), KOKKOS_LAMBDA (const int num_face)
224 {
225 for (int ncomp = 0; ncomp < val_flux0_line_sz; ncomp++)
226 val_flux(num_face, 0) += is_uniforme ? val_flux0(0, ncomp) : val_flux0(num_face - ndeb, ncomp);
227 });
228 end_gpu_timer(__KERNEL_NAME__);
229 }
230 }
231 /*
232 * Attention : ici resu est comme la Pression => P0 et P1 ... Pa peut etre
233 * Le flux est aux faces
234 * Donc : passage aux elems et aux sommets
235 */
236 DoubleTrav tab_flux_faces = fluide.inco_chaleur().valeurs(); // pour initialiser avec la bonne taille
237 tab_flux_faces = 0.;
238
239 const int nb_elem_tot = zp1b.nb_elem_tot(), nb_som_tot = zp1b.domaine().nb_som_tot(), nb_faces_tot = zp1b.nb_faces_tot();
240 CDoubleArrView face_surfaces = zp1b.face_surfaces().view_ro();
241 CDoubleArrView volumes = zp1b.volumes().view_ro();
242 CDoubleArrView volumes_entrelaces = zp1b.volumes_entrelaces().view_ro();
243 CIntTabView face_voisins = zp1b.face_voisins().view_ro();
244 CIntTabView face_sommets = zp1b.face_sommets().view_ro();
245 DoubleArrView flux_faces = static_cast<DoubleVect&>(tab_flux_faces).view_rw();
246 // remplir flux_faces (seulement au bord !)
247 for (int n_bord = 0; n_bord < domaine_cl_dis_->nb_cond_lim(); n_bord++)
248 {
249 const Cond_lim& la_cl = domaine_cl_dis_->les_conditions_limites(n_bord);
250 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
251
252 if (le_bord.le_nom() == nom_bord_)
253 {
254 const int ndeb = le_bord.num_premiere_face(), nfin = ndeb + le_bord.nb_faces();
255
256 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(ndeb, nfin), KOKKOS_LAMBDA (const int num_face)
257 {
258 const int elem1 = face_voisins(num_face, 0), elem2 = face_voisins(num_face, 1);
259 int elem = elem1 == -1 ? elem2 : elem1;
260 const double surf = face_surfaces(num_face);
261 flux_faces(num_face) = val_flux(num_face, 0) * surf / volumes(elem); // TODO multiple elements!! units val_flux(num_face-ndeb,0) *surf [kg.s-1] => gives [kg.m-3.s-1]
262 });
263 end_gpu_timer(__KERNEL_NAME__);
264 }
265 }
266
267 DoubleTrav tab_flux_som(nb_som_tot), tab_volume_int_som(nb_som_tot);
268 tab_volume_int_som = 0.;
269
270 const int nfe = zp1b.domaine().nb_faces_elem(), nsf = zp1b.nb_som_face();
271 // calcul de la somme des volumes entrelacees autour d'un sommet
272 CIntArrView renum_som_perio = zp1b.domaine().get_renum_som_perio().view_ro();
273 DoubleArrView volume_int_som = static_cast<DoubleVect&>(tab_volume_int_som).view_rw();
274 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nb_faces_tot, KOKKOS_LAMBDA (const int face)
275 {
276 for (int som = 0; som < nsf; som++)
277 {
278 int som_glob = renum_som_perio(face_sommets(face, som));
279 Kokkos::atomic_add(&volume_int_som(som_glob), volumes_entrelaces(face));
280 }
281 });
282 end_gpu_timer(__KERNEL_NAME__);
283
284 // interpolation du flux aux sommets
285 tab_flux_som = 0.;
286 DoubleArrView flux_som = static_cast<DoubleVect&>(tab_flux_som).view_rw();
287 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nb_faces_tot, KOKKOS_LAMBDA (const int face)
288 {
289 for (int som = 0; som < nsf; som++)
290 {
291 int som_glob = renum_som_perio(face_sommets(face, som));
292 double pond = volumes_entrelaces(face) / volume_int_som(som_glob);
293 Kokkos::atomic_add(&flux_som(som_glob), flux_faces(face) * pond);
294 }
295 });
296 end_gpu_timer(__KERNEL_NAME__);
297 // on passe aux elems
298 bool ok_post_src_ch = post_src_ch ? true:false;
299 int decal = 0;
300 int p_has_elem = zp1b.get_alphaE();
301 int nb_case = nb_elem_tot * p_has_elem;
302 DoubleArrView valeurs;
303 if (ok_post_src_ch) valeurs = static_cast<DoubleVect&>((*post_src_ch).valeurs()).view_wo();
304 CIntTabView elem_faces = zp1b.elem_faces().view_ro();
305 DoubleArrView resu = tab_resu.view_rw();
306 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nb_case, KOKKOS_LAMBDA (const int elem)
307 {
308 double fll = 0.;
309 for (int face = 0; face < nfe; face++)
310 fll += flux_faces(elem_faces(elem, face)); // divise par nfe ??? sais pas
311
312 resu(elem) -= fll; // in [kg.m-3.s-1]
313
314 if (ok_post_src_ch) valeurs(elem) = fll;
315 });
316 end_gpu_timer(__KERNEL_NAME__);
317
318 decal += nb_case;
319 tab_resu.echange_espace_virtuel();
320 int p_has_som = zp1b.get_alphaS();
321 nb_case = nb_som_tot * p_has_som;
322
323 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nb_case, KOKKOS_LAMBDA (const int som)
324 {
325 resu(decal + som) -= flux_som(som); // in [kg.m-3.s-1]
326 });
327 end_gpu_timer(__KERNEL_NAME__);
328
329 tab_resu.echange_espace_virtuel();
330
331 // pour post
332 if (post_src_ch)
333 (*post_src_ch).mettre_a_jour(fluide.inco_chaleur().temps());
334}
classe Champ_Don_base classe de base des Champs donnes (non calcules)
void mettre_a_jour(double temps) override
Mise a jour en temps.
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
double temps() const
Renvoie le temps du champ.
classe Champ_front_uniforme Classe derivee de Champ_front_base qui represente les
classe Cond_lim Classe generique servant a representer n'importe quelle classe
Definition Cond_lim.h:31
classe Convection_Diffusion_Fluide_Dilatable_base pour un fluide dilatable
int_t get_renum_som_perio(int_t i) const
Definition Domaine.h:281
int nb_faces_elem(int=0) const
Renvoie le nombre de face de type i des elements geometriques constituants le domaine.
Definition Domaine.h:484
int_t nb_som_tot() const
Renvoie le nombre total de sommets du domaine i.e. le nombre de sommets reels et virtuels sur le proc...
Definition Domaine.h:123
classe Domaine_Cl_dis_base Les objets Domaine_Cl_dis_base representent les conditions aux limites
Domaine_dis_base & domaine_dis()
Renvoie une reference sur le domaine discretise associe aux conditions aux limites.
class Domaine_VEF
Definition Domaine_VEF.h:54
int get_alphaS() const
Definition Domaine_VEF.h:93
int get_alphaE() const
Definition Domaine_VEF.h:92
class Domaine_VF
Definition Domaine_VF.h:44
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
int nb_faces() const
renvoie le nombre global de faces.
Definition Domaine_VF.h:471
DoubleVect & volumes_entrelaces()
Definition Domaine_VF.h:99
int nb_faces_tot() const
renvoie le nombre total de faces.
Definition Domaine_VF.h:481
double volumes(int i) const
Definition Domaine_VF.h:113
int face_sommets(int i, int j) const
renvoie le numero du ieme sommet de la face num_face.
Definition Domaine_VF.h:583
int nb_som_face() const
renvoie le nombre de sommets par face.
Definition Domaine_VF.h:494
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
int nb_elem_tot() const
const Domaine & domaine() const
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
classe Fluide_Dilatable_base Cette classe represente un d'un fluide dilatable,
bool has_source_masse_espece_champ() const
bool has_source_masse_projection_champ() const
const Champ_Inc_base & inco_chaleur() const
classe Fluide_Weakly_Compressible Cette classe represente un d'un fluide faiblement compressible
class Front_VF
Definition Front_VF.h:36
int nb_faces() const
Definition Front_VF.h:53
int num_premiere_face() const
Definition Front_VF.h:63
const Nom & le_nom() const override
Renvoie le nom de la frontiere geometrique.
virtual const Champ_base & masse_volumique() const
Renvoie la masse volumique du milieu.
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
Classe de base des flux de sortie.
Definition Sortie.h:52
void ajouter_projection(const Fluide_Dilatable_base &fluide, DoubleVect &resu) const override
void ajouter_eq_espece(const Convection_Diffusion_Fluide_Dilatable_base &eqn, const Fluide_Dilatable_base &fluide, const bool is_expl, DoubleVect &resu) const override
: classe Source_Masse_Fluide_Dilatable_base Une source speciale pour l'equation de masse (utilisee se...
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, View< _TYPE_, _SHAPE_ > > view_rw()
Definition TRUSTTab.h:291
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")