TrioCFD 1.9.9_beta
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 // for post-processing
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 : issue with ICoCo ...
113 * Note: val_flux has dimension nb_faces whereas val_flux0 has dimension nb_faces of border nom_bord_ ...
114 * the correct faces must be filled ...
115 * Start by filling val_flux only for the relevant 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 // Now look at 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 : a correction factor is needed because Y is on faces
159 * Surface source term, we use Y face => interlaced volume
160 * But P is on elements and nodes => not the same volume
161 * Interpolate Y to elements, the factor = Yelem / Yface
162 *
163 * Conclusion: for Y we use element values, not face values!
164 * Note: we divide by rho(face) because it is not included in the source term formulation!
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); // divide by volume (no mass solver in the 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 // for post-processing
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 // for post-processing
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 : issue with ICoCo ...
206 * Warning: val_flux has dimension nb_faces while val_flux0 has dimension nb_faces of boundary nom_bord_ ...
207 * must fill the correct faces ...
208 * Start by filling val_flux only for the correct 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 * Note: here resu is like the Pressure => P0 and P1 ... possibly Pa
233 * The flux is on faces
234 * Therefore: interpolation to elements and nodes
235 */
236 DoubleTrav tab_flux_faces = fluide.inco_chaleur().valeurs(); // to initialize with the correct size
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 // fill flux_faces (boundary only!)
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 // compute the sum of interlaced volumes around a vertex
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 of the flux to the vertices
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 // interpolate to elements
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)); // divide by nfe ??? not sure
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 // for post-processing
332 if (post_src_ch)
333 (*post_src_ch).mettre_a_jour(fluide.inco_chaleur().temps());
334}
class Champ_Don_base base class of Given Fields (not calculated)
void mettre_a_jour(double temps) override
Time update.
DoubleTab & valeurs() override
Returns the array of field values at the current time.
double temps() const
Returns the time of the field.
class Champ_front_uniforme Derived class of Champ_front_base representing
class Cond_lim Generic class used to represent any class
Definition Cond_lim.h:31
Base class for convection-diffusion equations for a dilatable fluid.
int_t get_renum_som_perio(int_t i) const
Definition Domaine.h:281
int nb_faces_elem(int=0) const
Returns the number of faces of type i of the geometric elements that make up the domain.
Definition Domaine.h:484
int_t nb_som_tot() const
Returns the total number of vertices of the domain i.e. the number of real and virtual vertices on th...
Definition Domaine.h:123
class Domaine_Cl_dis_base Domaine_Cl_dis_base objects represent discretized boundary conditions
Domaine_dis_base & domaine_dis()
Returns a reference to the discretized domain associated with the boundary conditions.
class Domaine_VEF
Definition Domaine_VEF.h:53
int get_alphaS() const
Definition Domaine_VEF.h:92
int get_alphaE() const
Definition Domaine_VEF.h:91
class Domaine_VF
Definition Domaine_VF.h:44
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
int nb_faces() const
Returns the total number of faces.
Definition Domaine_VF.h:471
DoubleVect & volumes_entrelaces()
Definition Domaine_VF.h:99
int nb_faces_tot() const
Returns the total number of faces.
Definition Domaine_VF.h:481
double volumes(int i) const
Definition Domaine_VF.h:113
int face_sommets(int i, int j) const
Returns the index of the i-th vertex of face num_face.
Definition Domaine_VF.h:582
int nb_som_face() const
Returns the number of vertices per face.
Definition Domaine_VF.h:493
int elem_faces(int i, int j) const
Returns the index of the i-th face of element num_elem; the face numbering convention is.
Definition Domaine_VF.h:542
int face_voisins(int num_face, int i) const
Returns the neighbouring element of num_face in 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
Base class for a dilatable fluid, inheriting from Fluide_base.
bool has_source_masse_espece_champ() const
bool has_source_masse_projection_champ() const
const Champ_Inc_base & inco_chaleur() const
Fluide_Weakly_Compressible class This class represents a weakly compressible fluid,...
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
Returns the name of the geometric boundary.
virtual const Champ_base & masse_volumique() const
Returns the mass density of the medium (const version).
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
Base class for output streams.
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
Special mass source term for the mass equation (used only during the projection/correction step).
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")