TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
EDO_Pression_th_VEF_Gaz_Parfait.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 <EDO_Pression_th_VEF_Gaz_Parfait.h>
17#include <Frontiere_ouverte_rho_u_impose.h>
18#include <Fluide_Quasi_Compressible.h>
19#include <Neumann_sortie_libre.h>
20#include <Navier_Stokes_std.h>
21#include <Schema_Temps_base.h>
22#include <Loi_Etat_GP_QC.h>
23#include <Domaine_VEF.h>
24#include <Champ_P1NC.h>
25#include <Dirichlet.h>
26
27Implemente_instanciable(EDO_Pression_th_VEF_Gaz_Parfait, "EDO_Pression_th_VEF_Gaz_Parfait", EDO_Pression_th_VEF);
28
29Sortie& EDO_Pression_th_VEF_Gaz_Parfait::printOn(Sortie& os) const { return os << que_suis_je() << finl; }
30
32
33/*! @brief Solves the ODE.
34 *
35 * @param (double Pth_n) The pressure at the previous time step
36 * @return (double) The new pressure value
37 */
39{
40
41 int traitPth = le_fluide_->getTraitementPth();
42
43 if (traitPth == 2) // Pth constant
44 return Pth_n;
45
46 double present = le_fluide_->vitesse().equation().schema_temps().temps_courant();
47 double dt = le_fluide_->vitesse().equation().schema_temps().pas_de_temps();
48 double futur = present + dt;
49 const DoubleTab& tab_tempnp1 = le_fluide_->inco_chaleur().valeurs(futur); // T(n+1)
50 const DoubleTab& tab_tempn = le_fluide_->inco_chaleur().valeurs(present); // T(n)
51 int nb_faces = le_dom->nb_faces();
52 double Pth = 0;
53
54 const Domaine_VEF& domaine_vef = ref_cast(Domaine_VEF, le_dom.valeur());
55
56 if (traitPth == 0) // ODE
57 {
58 const DoubleTab& tab_rho = le_fluide_->masse_volumique().valeurs(); // n+1/2
59 const double rho_moy = Champ_P1NC::calculer_integrale_volumique(domaine_vef, tab_rho, FAUX_EN_PERIO);
60 DoubleTrav tab_tmp(tab_rho); // copy of rho
61 tab_tmp = tab_rho;
62 assert(tab_tmp.size() == nb_faces);
63 const double invdt = 1. / dt;
64 CDoubleArrView tempn = static_cast<const ArrOfDouble&>(tab_tempn).view_ro();
65 CDoubleArrView tempnp1 = static_cast<const ArrOfDouble&>(tab_tempnp1).view_ro();
66 DoubleArrView tmp = static_cast<ArrOfDouble&>(tab_tmp).view_wo();
67 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, nb_faces), KOKKOS_LAMBDA(const int i)
68 {
69 tmp[i] *= (tempnp1[i] - tempn[i]) / tempnp1[i] * invdt;
70 });
71 end_gpu_timer(__KERNEL_NAME__);
72 double S = Champ_P1NC::calculer_integrale_volumique(domaine_vef, tab_tmp, FAUX_EN_PERIO);
73
74 //////////////////
75 S /= rho_moy;
76 // double Pth = (Pth_n + S*dt/V);
77 //double Pth = Pth_n/(1- S*dt);
78 Pth = Pth_n / (1 - S * dt);
79 //test to reveal the difference on Pth
80 //Pth *= 1e10;
81 }
82
83 else if (traitPth == 1) // Mass conservation (WEC March 2008)
84 {
85
86 // We want Mass(n+1) - Mass(n) = dt * Boundary_fluxes
87 // where Mass = Pth / R * sum(Vi/Ti) in volume
88 // and Flux = Pth / R * sum(Sj.Uj/Tj) at Dirichlet faces
89
90 // So if we denote masse_n = sum(Vi/Ti(n))
91 // debit_u_imp = sum(Sj.Uj(imposed)/Tj(n+1)) for imposed velocities
92 // and debit_rho_u_imp = sum(Sj.Uj(imposed)/Tj(n+1)) for imposed rho_u
93 // where U(imposed) = (rho.U)(imposed) / rho(Pth(n),T(n+1))
94 // we need Pth(n+1)*masse_np1 - Pth(n)*masse_n = Pth(n+1) * debit_u_imp * dt
95 // + Pth(n) * debit_rho_u_imp * dt
96
97 // Warning: porosity should be taken into account in the integrals !!!
98
99 double debit_u_imp = 0, debit_rho_u_imp = 0;
100
101 // We want rho_np1 to be computed with T(n+1) and Pth_n for boundary conditions with imposed rho_u
102 le_fluide_->calculer_masse_volumique();
103
104 // Computation of masse_n and masse_np1
105 DoubleTrav tab_tmp;
106 tab_tmp.copy(tab_tempn, RESIZE_OPTIONS::NOCOPY_NOINIT); // copy the structure only
107
108 CDoubleArrView tempn = static_cast<const ArrOfDouble&>(tab_tempn).view_ro();
109 DoubleArrView tmp = static_cast<ArrOfDouble&>(tab_tmp).view_wo();
110 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, nb_faces), KOKKOS_LAMBDA(const int i)
111 {
112 tmp(i) = 1. / tempn(i);
113 });
114 end_gpu_timer(__KERNEL_NAME__);
115 const double masse_n = Champ_P1NC::calculer_integrale_volumique(domaine_vef, tab_tmp, FAUX_EN_PERIO);
116
117 CDoubleArrView tempnp1 = static_cast<const ArrOfDouble&>(tab_tempnp1).view_ro();
118 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_1D(0, nb_faces), KOKKOS_LAMBDA(const int i)
119 {
120 tmp(i) = 1. / tempnp1(i);
121 });
122 end_gpu_timer(__KERNEL_NAME__);
123 const double masse_np1 = Champ_P1NC::calculer_integrale_volumique(domaine_vef, tab_tmp, FAUX_EN_PERIO);
124
125 // Computation of debit_u_imp and debit_rho_u_imp
126 for (int n_bord = 0; n_bord < le_dom->nb_front_Cl(); n_bord++)
127 {
128 const Cond_lim_base& la_cl = le_dom_Cl->les_conditions_limites(n_bord).valeur();
129 if (sub_type(Dirichlet, la_cl))
130 {
131 const Dirichlet& diri = ref_cast(Dirichlet, la_cl);
132 const Front_VF& la_front_dis = ref_cast(Front_VF, la_cl.frontiere_dis());
133 int ndeb = la_front_dis.num_premiere_face();
134 int nfin = ndeb + la_front_dis.nb_faces();
135 int dim = Objet_U::dimension;
136 CDoubleTabView val_imp = diri.tab_val_imp(futur).view_ro();
137 CDoubleTabView face_normales = le_dom->face_normales().view_ro();
138 CIntTabView face_voisins = le_dom->face_voisins().view_ro();
139 double debit = 0;
140 Kokkos::parallel_reduce(start_gpu_timer(__KERNEL_NAME__), range_1D(ndeb, nfin), KOKKOS_LAMBDA(const int face, double& debit_local)
141 {
142 double debit_v = 0;
143 for (int d = 0; d < dim; d++)
144 debit_v += face_normales(face, d) * val_imp(face - ndeb, d) / tempnp1(face);
145 int n0 = face_voisins(face, 0);
146 if (n0 == -1)
147 debit_v = -debit_v;
148 debit_local += debit_v;
149 }, debit);
150 end_gpu_timer(__KERNEL_NAME__);
151 if (sub_type(Frontiere_ouverte_rho_u_impose, la_cl))
152 debit_rho_u_imp += debit;
153 else
154 debit_u_imp += debit;
155 }
156 else if (sub_type(Neumann_sortie_libre, la_cl))
157 {
158 Cerr << la_cl.que_suis_je() << " est incompatible avec le traitement conservation_masse." << finl;
159 exit();
160 }
161 }
162 // Sum over all procs
163 // Optimization: combine 2 mp_sum into 1 collective call
164 mp_sum_for_each(debit_u_imp, debit_rho_u_imp);
165
166 // Computation of Pth(n+1)
167 Pth = Pth_n * (masse_n - dt * debit_rho_u_imp) / (masse_np1 + dt * debit_u_imp);
168 }
169
170 return Pth;
171}
172
174{
175
176 const int traitPth = le_fluide_->getTraitementPth();
177 if (traitPth == 2)
178 return; // nothing to do
179 else if (traitPth == 0)
180 {
181 for (int n_bord = 0; n_bord < le_dom->nb_front_Cl(); n_bord++)
182 {
183 const Cond_lim& la_cl = le_dom_Cl->les_conditions_limites(n_bord);
184 if (sub_type(Neumann_sortie_libre, la_cl.valeur()))
185 return; // nothing to do
186 }
187
188 Cerr << "EDO_Pression_th_VEF_Gaz_Parfait::" << __func__ << " not yet coded ! Call the 911 !!" << finl;
190 }
191 else
192 {
193 const double present = le_fluide_->vitesse().equation().schema_temps().temps_courant();
194 const double dt = le_fluide_->vitesse().equation().schema_temps().pas_de_temps();
195 const double futur = present + dt;
196 const DoubleTab& tempnp1 = le_fluide_->inco_chaleur().valeurs(futur); // T(n+1)
197 const DoubleTab& tempn = le_fluide_->inco_chaleur().valeurs(present); // T(n)
198 const int nb_faces = le_dom->nb_faces();
199 const Domaine_VEF& domaine_vef = ref_cast(Domaine_VEF, le_dom.valeur());
200
201 // We want Mass(n+1) - Mass(n) = dt * Boundary_fluxes
202 // where Mass = Pth / R * sum(Vi/Ti) in volume
203 // and Flux = Pth / R * sum(Sj.Uj/Tj) at Dirichlet faces
204
205 // So if we denote masse_n = sum(Vi/Ti(n))
206 // debit_u_imp = sum(Sj.Uj(imposed)/Tj(n+1)) for imposed velocities
207 // and debit_rho_u_imp = sum(Sj.Uj(imposed)/Tj(n+1)) for imposed rho_u
208 // where U(imposed) = (rho.U)(imposed) / rho(Pth(n),T(n+1))
209 // we need Pth(n+1)*masse_np1 - Pth(n)*masse_n = Pth(n+1) * debit_u_imp * dt
210 // + Pth(n) * debit_rho_u_imp * dt
211
212 // Warning: porosity should be taken into account in the integrals !!!
213
214 double debit_u_imp = 0, debit_rho_u_imp = 0;
215
216 // We want rho_np1 to be computed with T(n+1) and Pth_n for boundary conditions with imposed rho_u
217 le_fluide_->calculer_masse_volumique();
218
219 // Computation of masse_n and masse_np1
220 DoubleVect tmp;
221 tmp.copy(tempn, RESIZE_OPTIONS::NOCOPY_NOINIT); // copy the structure only
222 for (int i = 0; i < nb_faces; i++)
223 tmp[i] = 1. / tempn[i];
224 const double masse_n = Champ_P1NC::calculer_integrale_volumique(domaine_vef, tmp, FAUX_EN_PERIO);
225 for (int i = 0; i < nb_faces; i++)
226 tmp[i] = 1. / tempnp1[i];
227 const double masse_np1 = Champ_P1NC::calculer_integrale_volumique(domaine_vef, tmp, FAUX_EN_PERIO);
228
229 // Computation of debit_u_imp and debit_rho_u_imp
230 for (int n_bord = 0; n_bord < le_dom->nb_front_Cl(); n_bord++)
231 {
232 const Cond_lim_base& la_cl = le_dom_Cl->les_conditions_limites(n_bord).valeur();
233 if (sub_type(Dirichlet, la_cl))
234 {
235 const Dirichlet& diri = ref_cast(Dirichlet, la_cl);
236 const Front_VF& la_front_dis = ref_cast(Front_VF, la_cl.frontiere_dis());
237 int ndeb = la_front_dis.num_premiere_face();
238 int nfin = ndeb + la_front_dis.nb_faces();
239 for (int face = ndeb; face < nfin; face++)
240 {
241 double debit_v = 0;
242 for (int d = 0; d < dimension; d++)
243 debit_v += le_dom->face_normales(face, d) * diri.val_imp_au_temps(futur, face - ndeb, d) / tempnp1(face);
244 int n0 = le_dom->face_voisins(face, 0);
245 if (n0 == -1)
246 debit_v = -debit_v;
247 if (sub_type(Frontiere_ouverte_rho_u_impose, la_cl))
248 debit_rho_u_imp += debit_v;
249 else
250 debit_u_imp += debit_v;
251 }
252 }
253 else if (sub_type(Neumann_sortie_libre, la_cl))
254 {
255 Cerr << la_cl.que_suis_je() << " est incompatible avec le traitement conservation_masse." << finl;
256 exit();
257 }
258 }
259 // Sum over all procs
260 // Optimization: combine 2 mp_sum into 1 collective call
261 mp_sum_for_each(debit_u_imp, debit_rho_u_imp);
262
263 // Computation of Pth(n+1)
264 for (int f = 0; f < nb_faces; f++)
265 Pth_n(f) = Pth_n(f) * (masse_n - dt * debit_rho_u_imp) / (masse_np1 + dt * debit_u_imp);
266 }
267}
static double calculer_integrale_volumique(const Domaine_VEF &, const DoubleVect &, Ok_Perio ok)
class Cond_lim_base Base class for the hierarchy of classes that represent the different boundary con...
virtual Frontiere_dis_base & frontiere_dis()
Returns the discretized boundary to which the boundary conditions apply.
class Cond_lim Generic class used to represent any class
Definition Cond_lim.h:31
Dirichlet This class is the base class of the hierarchy of Dirichlet-type boundary conditions.
Definition Dirichlet.h:31
virtual double val_imp_au_temps(double temps, int i) const
Returns the imposed value on the i-th component of the field at the boundary at the specified time.
Definition Dirichlet.cpp:54
virtual const DoubleTab & tab_val_imp(double temps=DMAXFLOAT) const
Definition Dirichlet.cpp:75
class Domaine_VEF
Definition Domaine_VEF.h:53
class EDO_Pression_th_VEF_Gaz_Parfait
double resoudre(double) override
Solves the ODE.
class EDO_Pression_th_VEF This class represents the ODE on the pressure associated with the computati...
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
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
Open boundary on which the mass flux rho.U is imposed instead of the velocity U.
Neumann_sortie_libre This class represents an open boundary without imposed velocity.
static int dimension
Definition Objet_U.h:94
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
static void mp_sum_for_each(T &arg1, T &arg2)
C++14 compatible mp_sum_for_each: combine multiple mp_sum calls into one collective operation Usage: ...
Definition Process.cpp:208
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
Base class for output streams.
Definition Sortie.h:52
void copy(const TRUSTTab &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:622
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, ConstView< _TYPE_, _SHAPE_ > > view_ro() const
Definition TRUSTTab.h:261
_SIZE_ size() const
Definition TRUSTVect.tpp:45
void copy(const TRUSTArray< _TYPE_, _SIZE_ > &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)