TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Op_Dift_VEF_Face_Gen.tpp
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#ifndef Op_Dift_VEF_Face_Gen_TPP_included
17#define Op_Dift_VEF_Face_Gen_TPP_included
18
19#include <Modele_turbulence_scal_base.h>
20#include <Echange_externe_impose.h>
21#include <Scalaire_impose_paroi.h>
22#include <Neumann_sortie_libre.h>
23#include <Op_Diff_VEF_base.h>
24#include <Neumann_homogene.h>
25#include <Neumann_paroi.h>
26#include <Periodique.h>
27#include <Champ_P1NC.h>
28#include <Symetrie.h>
29#include <Device.h>
30#include <kokkos++.h>
31#include <TRUSTArray_kokkos.tpp>
33template <typename DERIVED_T> template <Type_Champ _TYPE_>
34void Op_Dift_VEF_Face_Gen<DERIVED_T>::fill_grad_Re(const DoubleTab& tab_inconnue, const DoubleTab& tab_resu, const DoubleTab& tab_nu, const DoubleTab& tab_nu_turb) const
35{
36 constexpr bool is_VECT = (_TYPE_ == Type_Champ::VECTORIEL);
37 if (is_VECT)
38 {
39 const auto *z_class = static_cast<const DERIVED_T*>(this); // CRTP --> I love you :*
41 const Domaine_Cl_VEF& domaine_Cl_VEF = z_class->domaine_cl_vef();
42 const Domaine_VEF& domaine_VEF = z_class->domaine_vef();
44 // Construction du tableau grad_ si necessaire
45 if (!grad_.get_md_vector().non_nul())
46 {
49 }
50 grad_ = 0.;
51
52 Champ_P1NC::calcul_gradient(tab_inconnue, grad_, domaine_Cl_VEF);
53
54 if (z_class->get_modele_turbulence().utiliser_loi_paroi())
55 Champ_P1NC::calcul_duidxj_paroi(grad_, tab_nu, tab_nu_turb, z_class->get_tau_tan(), domaine_Cl_VEF);
57 grad_.echange_espace_virtuel();
58
59 if (!Re_.get_md_vector().non_nul())
60 {
62 domaine_VEF.domaine().creer_tableau_elements(Re_);
63 }
64 Re_ = 0.;
65
66 bool flag = z_class->get_modele_turbulence().calcul_tenseur_Re(tab_nu_turb, grad_, Re_);
67 const int nbr_comp = tab_resu.line_size();
68 assert(nbr_comp > 1);
69 CDoubleTabView nu_turb = tab_nu_turb.view_ro();
70 DoubleTabView3 Re = Re_.view_rw<3>();
71 if (flag)
72 {
73 Cerr << "On utilise une diffusion turbulente non lineaire dans NS" << finl;
74 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_2D({0,0}, {domaine_VEF.nb_elem(),nbr_comp}), KOKKOS_LAMBDA(const int elem, const int i)
75 {
76// for (int i = 0; i < nbr_comp; i++)
77 for (int j = 0; j < nbr_comp; j++)
78 Re(elem, i, j) *= nu_turb(elem, 0);
79 });
80 }
81 else
82 {
83 CDoubleTabView3 grad = grad_.view_ro<3>();
84 // PL: range_3D plus lent que range_2D...
85 //Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_3D({0,0,0}, {nb_elem,nbr_comp,nbr_comp}), KOKKOS_LAMBDA(const int elem, const int i, const int j)
86 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), range_2D({0,0}, {domaine_VEF.nb_elem(),nbr_comp}), KOKKOS_LAMBDA(const int elem, const int i)
87 {
88// for (int i = 0; i < nbr_comp; i++)
89 for (int j = 0; j < nbr_comp; j++)
90 Re(elem, i, j) = nu_turb(elem,0) * (grad(elem, i, j) + grad(elem, j, i));
91 });
92 }
93 end_gpu_timer(__KERNEL_NAME__);
94 Re_.echange_espace_virtuel();
95 }
96}
97
98/*
99 * ***************************
100 * METHODES POUR L'EXPLICITE
101 * ***************************
102 */
103
104template <typename DERIVED_T> template<Type_Champ _TYPE_, bool _IS_RANS_>
105std::enable_if_t<_TYPE_ == Type_Champ::VECTORIEL, void>
106Op_Dift_VEF_Face_Gen<DERIVED_T>::ajouter_bord_gen(const DoubleTab& tab_inconnue, DoubleTab& tab_resu, DoubleTab& tab_flux_bords, const DoubleTab& tab_nu, const DoubleTab& tab_nu_turb) const
107{
108 // Kokkos tip: rename TRUST tab (ig: parametars) and use current name for view: limite code changes.
109 // Future: parameter will be views not TRUST arrays and it will be easier to refact by find/replace "const DoubleTab& tab_XXX" by "CDoubleTabView XXX"
110 const auto *z_class = static_cast<const DERIVED_T*>(this); // CRTP --> I love you :*
111
112 const Domaine_Cl_VEF& domaine_Cl_VEF = z_class->domaine_cl_vef();
113 const Domaine_VEF& domaine_VEF = z_class->domaine_vef();
114 const int nbr_comp = tab_resu.line_size();
115
116 // boucle sur les CL
117 const Conds_lim& les_cl = domaine_Cl_VEF.les_conditions_limites();
118 const int nb_cl = les_cl.size();
119 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();;
120 CDoubleTabView face_normale = domaine_VEF.face_normales().view_ro();;
121 CDoubleTabView nu = tab_nu.view_ro();
122 CDoubleTabView3 Re = Re_.view_ro<3>();
123 CDoubleTabView3 grad = grad_.view_ro<3>();
124 DoubleTabView flux_bords = tab_flux_bords.view_rw();
125 DoubleTabView resu = tab_resu.view_rw();
126 for (int n_bord = 0; n_bord < nb_cl; n_bord++)
127 {
128 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
129 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
130 const int ndeb = le_bord.num_premiere_face(), nfin = ndeb + le_bord.nb_faces();
131
132 if (sub_type(Periodique, la_cl.valeur()))
133 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
134 Kokkos::RangePolicy<>(ndeb, nfin), KOKKOS_LAMBDA(
135 const int num_face)
136 {
137 for (int kk = 0; kk < 2; kk++)
138 {
139 const int elem = face_voisins(num_face, kk), ori = 1 - 2 * kk;
140 for (int i = 0; i < nbr_comp; i++)
141 for (int j = 0; j < nbr_comp; j++)
142 resu(num_face, i) -=
143 ori * face_normale(num_face, j) * (nu(elem, 0) * grad(elem, i, j) + Re(elem, i, j));
144 }
145 });
146 else // CL pas periodique
147 {
148 bool Symetrie = sub_type(Symetrie, la_cl.valeur());
149 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
150 Kokkos::RangePolicy<>(ndeb, nfin), KOKKOS_LAMBDA(
151 const int num_face)
152 {
153 const int elem = face_voisins(num_face, 0);
154 for (int i = 0; i < nbr_comp; i++)
155 for (int j = 0; j < nbr_comp; j++)
156 {
157 double flux = face_normale(num_face, j) * (nu(elem, 0) * grad(elem, i, j) + Re(elem, i, j));
158 resu(num_face, i) -= flux;
159 flux_bords(num_face, i) -= flux;
160 }
161
162 // Correction tab_flux_bords si symetrie
163 if (Symetrie)
164 flux_bords(num_face, 0) = 0.;
165 });
166 }
167 end_gpu_timer(__KERNEL_NAME__);
168 }
169}
170
171
173{
174 // execution window
175 int nint;
177
178 // inputs
179 CIntTabView face_voisins;
180 CDoubleTabView face_normale;
181 CDoubleArrView nu;
182 CDoubleTabView3 Re;
183 CDoubleTabView3 grad;
184
185 // output
186 DoubleTabView resu;
187};
188
189inline void apply_ajouter_interne_gen_kernel_notemplate(const AjouterInterneData& data, const int nbr_comp)
190{
191 // Unpack on host side BEFORE passing to kernel
192 const int nint = data.nint;
193 const int nb_faces = data.nb_faces;
194 auto face_voisins = data.face_voisins;
195 auto face_normale = data.face_normale;
196 auto nu = data.nu;
197 auto Re = data.Re;
198 auto grad = data.grad;
199 auto resu = data.resu;
200
201 // PL: collapsing loops even with an atomic is x2-3 faster than no collapsing (seen on DomainFlowLES_BENCH)
202 bool collapse_loops = true;
203 if (collapse_loops)
204 {
205 Kokkos::MDRangePolicy<Kokkos::Rank<2>> policy({nint, 0}, {nb_faces, 2});
206 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), policy, KOKKOS_LAMBDA(const int num_face, const int kk)
207 {
208 const int elem = face_voisins(num_face, kk), ori = 1 - 2 * kk;
209 double nu_elem = nu(elem);
210 for (int i = 0; i < nbr_comp; i++)
211 for (int j = 0; j < nbr_comp; j++)
212 Kokkos::atomic_add(&resu(num_face, i), - ori * face_normale(num_face, j) * (nu_elem * grad(elem, i, j) + Re(elem, i, j)));
213 });
214 }
215 else
216 {
217 Kokkos::RangePolicy<> policy(nint, nb_faces);
218 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), policy, KOKKOS_LAMBDA(
219 const int num_face)
220 {
221 for (int kk = 0; kk < 2; kk++)
222 {
223 const int elem = face_voisins(num_face, kk), ori = 1 - 2 * kk;
224 double nu_elem = nu(elem);
225 for (int i = 0; i < nbr_comp; i++)
226 for (int j = 0; j < nbr_comp; j++)
227 resu(num_face, i) -=
228 ori * face_normale(num_face, j) * (nu_elem * grad(elem, i, j) + Re(elem, i, j));
229 }
230 });
231 }
232 end_gpu_timer(__KERNEL_NAME__);
233}
234
235template<int nbr_comp>
236void apply_ajouter_interne_gen_kernel(const AjouterInterneData& data)
237{
238 // Unpack on host side BEFORE passing to kernel
239 const int nint = data.nint;
240 const int nb_faces = data.nb_faces;
241 auto face_voisins = data.face_voisins;
242 auto face_normale = data.face_normale;
243 auto nu = data.nu;
244 auto Re = data.Re;
245 auto grad = data.grad;
246 auto resu = data.resu;
247
248 // Deduce policy
249 Kokkos::RangePolicy<> policy(nint, nb_faces);
250
251 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), policy,
252 KOKKOS_LAMBDA(const int num_face)
253 {
254 double resu_loc[2][nbr_comp];
255 double face_normale_loc[nbr_comp];
256 int face_voisins_loc[2];
257
258 // Load per-face data from global memory once
259 for (int j = 0; j < nbr_comp; ++j)
260 face_normale_loc[j] = face_normale(num_face, j);
261
262 for (int side = 0; side < 2; ++side)
263 {
264 face_voisins_loc[side] = face_voisins(num_face, side);
265 for (int i = 0; i < nbr_comp; ++i) resu_loc[side][i] = 0.0;
266 }
267
268 // Compute local contributions
269 for (int side = 0; side < 2; ++side)
270 {
271 const int elem = face_voisins_loc[side];
272 const int ori = 1 - 2 * side;
273 const double nu_elem = nu(elem);
274
275 for (int i = 0; i < nbr_comp; ++i)
276 {
277 double sum = 0.0;
278 for (int j = 0; j < nbr_comp; ++j)
279 {
280 sum -= ori * face_normale_loc[j]
281 * (nu_elem * grad(elem, i, j) + Re(elem, i, j));
282 }
283 resu_loc[side][i] += sum;
284 }
285 }
286
287 // Reduce two sides and write back
288 for (int i = 0; i < nbr_comp; ++i)
289 {
290 double sum = 0.0;
291 for (int side = 0; side < 2; ++side) sum += resu_loc[side][i];
292 resu(num_face, i) += sum;
293 }
294 });
295
296 end_gpu_timer(__KERNEL_NAME__);
297}
298
299// Explicit instantiations
300template void apply_ajouter_interne_gen_kernel<1>(const AjouterInterneData&);
301template void apply_ajouter_interne_gen_kernel<2>(const AjouterInterneData&);
302template void apply_ajouter_interne_gen_kernel<3>(const AjouterInterneData&);
303template void apply_ajouter_interne_gen_kernel<4>(const AjouterInterneData&);
304
305template <typename DERIVED_T> template<Type_Champ _TYPE_, bool _IS_RANS_>
306std::enable_if_t<_TYPE_ == Type_Champ::VECTORIEL, void>
308 DoubleTab& tab_resu,
309 DoubleTab& flux_bords,
310 const DoubleTab& tab_nu,
311 const DoubleTab& tab_nu_turb) const
312{
313 const Domaine_VEF& domaine_VEF = static_cast<const DERIVED_T*>(this)->domaine_vef();
314 const int nb_faces = domaine_VEF.nb_faces();
315 const int nint = domaine_VEF.premiere_face_int();
316 const int nbr_comp = tab_resu.line_size();
317
318 // Build views once
319 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
320 CDoubleTabView face_normale = domaine_VEF.face_normales().view_ro();
321 CDoubleArrView nu = static_cast<const ArrOfDouble&>(tab_nu).view_ro();
322 CDoubleTabView3 grad = grad_.view_ro<3>();
323 CDoubleTabView3 Re = Re_.view_ro<3>();
324 DoubleTabView resu = tab_resu.view_rw();
325 AjouterInterneData data {nint, nb_faces, face_voisins, face_normale, nu, Re, grad, resu};
326
327 //You might not want to use the templated version for HUGE values of nbr_comp
328 const bool use_templated_version=true;
329
330 // Dispatch on compile-time component count;
331 if (use_templated_version)
332 {
333 switch (nbr_comp)
334 {
335 case 1:
336 apply_ajouter_interne_gen_kernel<1>(data);
337 break;
338 case 2:
339 apply_ajouter_interne_gen_kernel<2>(data);
340 break;
341 case 3:
342 apply_ajouter_interne_gen_kernel<3>(data);
343 break;
344 case 4:
345 apply_ajouter_interne_gen_kernel<4>(data);
346 break;
347 default:
348 Cerr << "nbr_comp too large (>4), no templated verison of Op_Dift_VEF_Face_Gen<DERIVED_T>::ajouter_interne_gen implemented" << finl;
349 Cerr<< "Defaulting to the non templated version.";
350 apply_ajouter_interne_gen_kernel_notemplate(data, nbr_comp);
351 }
352 }
353 else
354 {
355 apply_ajouter_interne_gen_kernel_notemplate(data, nbr_comp);
356 }
357}
358
359
360template <typename DERIVED_T> template<Type_Champ _TYPE_, bool _IS_RANS_>
361std::enable_if_t<_TYPE_ == Type_Champ::SCALAIRE, void>
362Op_Dift_VEF_Face_Gen<DERIVED_T>::ajouter_bord_gen(const DoubleTab& inconnue, DoubleTab& resu, DoubleTab& tab_flux_bords, const DoubleTab& nu, const DoubleTab& nu_turb) const
363{
364 // On traite les faces bord
365 const auto *z_class = static_cast<const DERIVED_T*>(this); // CRTP --> I love you :*
366
367 const Domaine_Cl_VEF& domaine_Cl_VEF = z_class->domaine_cl_vef();
368 const Domaine_VEF& domaine_VEF = z_class->domaine_vef();
369 const int nb_front = domaine_VEF.nb_front_Cl();
370
371 for (int n_bord = 0; n_bord < nb_front; n_bord++)
372 {
373 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
374 if (sub_type(Periodique, la_cl.valeur()))
375 ajouter_bord_perio_gen__<_TYPE_, Type_Schema::EXPLICITE, false, _IS_RANS_>(n_bord, inconnue, &resu, nullptr, nu, nu_turb, nu_turb /* poubelle */);
376 else // CL pas periodique
377 {
378 if (sub_type(Scalaire_impose_paroi, la_cl.valeur()) || sub_type(Neumann_paroi, la_cl.valeur()) || sub_type(Neumann_homogene, la_cl.valeur())) // CL Temperature imposee
379 ajouter_bord_scalaire_impose_gen__<_TYPE_, Type_Schema::EXPLICITE, false>(n_bord, inconnue, &resu, nullptr, nu, nu_turb, nu_turb /* poubelle */, &tab_flux_bords);
380
381 // A pas oublier !
382 ajouter_bord_gen__<_TYPE_, Type_Schema::EXPLICITE, false, _IS_RANS_>(n_bord, inconnue, &resu, nullptr, nu, nu_turb, nu_turb /* poubelle */, &tab_flux_bords);
383 }
384 }
385 modifie_pour_cl_gen<false>(inconnue, resu, tab_flux_bords);
386}
387
388template <typename DERIVED_T> template <bool _IS_STAB_>
389void Op_Dift_VEF_Face_Gen<DERIVED_T>::modifie_pour_cl_gen(const DoubleTab& tab_inconnue, DoubleTab& tab_resu, DoubleTab& tab_flux_bords) const
390{
391 // On traite les faces bord
392 const auto *z_class = static_cast<const DERIVED_T*>(this); // CRTP --> I love you :*
393 constexpr bool is_STAB = _IS_STAB_;
394
395 const Domaine_Cl_VEF& domaine_Cl_VEF = z_class->domaine_cl_vef();
396 const Domaine_VEF& domaine_VEF = z_class->domaine_vef();
397 const int nb_front = domaine_VEF.nb_front_Cl(), nb_comp = tab_resu.line_size();
398
399 for (int n_bord = 0; n_bord < nb_front; n_bord++)
400 {
401 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
402 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
403 const int ndeb = le_bord.num_premiere_face(), nfin = ndeb + le_bord.nb_faces();
404
405 if (is_STAB && sub_type(Periodique, la_cl.valeur()))
406 {
407 const Periodique& la_cl_perio = ref_cast(Periodique, la_cl.valeur());
408 CIntArrView face_associee = la_cl_perio.face_associee().view_ro();
409 CIntArrView num_face = le_bord.num_face().view_ro();
410 DoubleTabView resu = tab_resu.view_rw();
411 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(0, le_bord.nb_faces()/2), KOKKOS_LAMBDA(const int ind_face)
412 {
413 const int face = num_face(ind_face);
414 const int voisine = num_face(face_associee(ind_face));
415 for (int nc = 0; nc < nb_comp; nc++)
416 {
417 resu(face, nc) += resu(voisine, nc);
418 resu(voisine, nc) = resu(face, nc);
419 }
420 });
421 end_gpu_timer(__KERNEL_NAME__);
422 }
423
424 if (sub_type(Neumann_paroi, la_cl.valeur()))
425 {
426 const Neumann_paroi& la_cl_paroi = ref_cast(Neumann_paroi, la_cl.valeur());
427 CDoubleTabView flux_impose = la_cl_paroi.flux_impose().view_ro();
428 CDoubleArrView face_surfaces = domaine_VEF.face_surfaces().view_ro();
429 DoubleTabView flux_bords = tab_flux_bords.view_wo();
430 DoubleTabView resu = tab_resu.view_rw();
431 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(ndeb, nfin), KOKKOS_LAMBDA(const int face)
432 {
433 for (int nc = 0; nc < nb_comp; nc++)
434 {
435 const double flux = flux_impose(face - ndeb, nc) * face_surfaces(face);
436 if (is_STAB) resu(face, nc) -= flux; // XXX -= car regarde dans Op_Dift_Stab_VEF_Face::ajouter
437 else resu(face, nc) += flux;
438 flux_bords(face, nc) = flux;
439 }
440 });
441 end_gpu_timer(__KERNEL_NAME__);
442 }
443
444 if (sub_type(Echange_externe_impose, la_cl.valeur()))
445 {
446 const Echange_externe_impose& la_cl_paroi = ref_cast(Echange_externe_impose, la_cl.valeur());
447 CDoubleTabView h_imp = la_cl_paroi.tab_h_imp().view_ro();
448 CDoubleTabView T_ext = la_cl_paroi.tab_T_ext().view_ro();
449 CDoubleArrView face_surfaces = domaine_VEF.face_surfaces().view_ro();
450 CDoubleTabView inconnue = tab_inconnue.view_ro();
451 DoubleTabView flux_bords = tab_flux_bords.view_wo();
452 DoubleTabView resu = tab_resu.view_rw();
453 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(ndeb, nfin), KOKKOS_LAMBDA(const int face)
454 {
455 for (int nc = 0; nc < nb_comp; nc++)
456 {
457 const double flux = h_imp(face - ndeb, nc) * (T_ext(face - ndeb, nc) - inconnue(face, nc)) * face_surfaces(face);
458 if (is_STAB) resu(face, nc) -= flux;
459 else resu(face, nc) += flux;
460 flux_bords(face, nc) = flux;
461 }
462 });
463 end_gpu_timer(__KERNEL_NAME__);
464 }
465
466 if (sub_type(Neumann_homogene, la_cl.valeur()) || sub_type(Symetrie, la_cl.valeur()) || sub_type(Neumann_sortie_libre, la_cl.valeur()))
467 {
468 DoubleTabView flux_bords = tab_flux_bords.view_wo();
469 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(ndeb, nfin), KOKKOS_LAMBDA(const int face)
470 {
471 for (int nc = 0; nc < nb_comp; nc++)
472 flux_bords(face, nc) = 0.;
473 });
474 end_gpu_timer(__KERNEL_NAME__);
475 }
476 }
477}
478
479/*
480 * ***************************
481 * METHODES POUR L'IMPLICITE
482 * ***************************
483 */
484template <typename DERIVED_T> template <Type_Champ _TYPE_, bool _IS_STAB_, bool _IS_RANS_>
485void Op_Dift_VEF_Face_Gen<DERIVED_T>::ajouter_contribution_bord_gen(const DoubleTab& transporte, Matrice_Morse& tab_matrice, const DoubleTab& nu,
486 const DoubleTab& nu_turb, const DoubleVect& porosite_eventuelle) const
487{
488 // On traite les faces bord
489 const auto *z_class = static_cast<const DERIVED_T*>(this); // CRTP --> I love you :*
490
491 const Domaine_Cl_VEF& domaine_Cl_VEF = z_class->domaine_cl_vef();
492 const Domaine_VEF& domaine_VEF = z_class->domaine_vef();
493 const int nb_bords = domaine_VEF.nb_front_Cl(), nb_comp = transporte.line_size();
494
495 for (int n_bord = 0; n_bord < nb_bords; n_bord++)
496 {
497 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
498 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
499
500 if (sub_type(Periodique, la_cl.valeur()))
501 ajouter_bord_perio_gen__<_TYPE_, Type_Schema::IMPLICITE, _IS_STAB_, _IS_RANS_>(n_bord, transporte, nullptr, &tab_matrice, nu, nu_turb, porosite_eventuelle);
502 else // pas perio
503 {
504 if (sub_type(Scalaire_impose_paroi, la_cl.valeur())) // CL Temperature imposee
505 ajouter_bord_scalaire_impose_gen__<_TYPE_, Type_Schema::IMPLICITE, _IS_STAB_>(n_bord, transporte, nullptr, &tab_matrice, nu, nu_turb, porosite_eventuelle);
506 else if (sub_type(Echange_externe_impose, la_cl.valeur()) && nb_comp < 2) // XXX : plus tard pour multi inco aussi ...
507 {
508 const Echange_externe_impose& la_cl_paroi = ref_cast(Echange_externe_impose, la_cl.valeur());
509 const int ndeb = le_bord.num_premiere_face(), nfin = ndeb + le_bord.nb_faces();
510 Matrice_Morse_View matrice;
511 matrice.set(tab_matrice);
512 CDoubleTabView h_imp = la_cl_paroi.tab_h_imp().view_ro();
513 CDoubleArrView face_surfaces = domaine_VEF.face_surfaces().view_ro();
514 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(ndeb, nfin), KOKKOS_LAMBDA(const int face)
515 {
516 matrice.add(face, face, h_imp(face - ndeb, 0) * face_surfaces(face));
517 });
518 end_gpu_timer(__KERNEL_NAME__);
519 }
520
521 // A pas oublier !
522 ajouter_bord_gen__<_TYPE_, Type_Schema::IMPLICITE, _IS_STAB_, _IS_RANS_>(n_bord, transporte, nullptr, &tab_matrice, nu, nu_turb, porosite_eventuelle);
523 }
524 }
525}
526
527// METHODES GENERIQUES
528template <typename DERIVED_T> template <Type_Champ _TYPE_, Type_Schema _SCHEMA_, bool _IS_STAB_, bool _IS_RANS_>
529void Op_Dift_VEF_Face_Gen<DERIVED_T>::ajouter_bord_perio_gen__(const int n_bord, const DoubleTab& tab_inconnue, DoubleTab* tab_resu /* Si explicite */, Matrice_Morse* matrice_morse /* Si implicite */,
530 const DoubleTab& tab_nu, const DoubleTab& tab_nu_turb, const DoubleVect& tab_porosite_eventuelle, DoubleTab* tab_flux_bord) const
531{
532 constexpr bool is_VECT = (_TYPE_ == Type_Champ::VECTORIEL), is_EXPLICIT = (_SCHEMA_ == Type_Schema::EXPLICITE), is_STAB = _IS_STAB_, is_RANS = _IS_RANS_;
533
534 const auto *z_class = static_cast<const DERIVED_T*>(this); // CRTP --> I love you :*
535
536 const Domaine_Cl_VEF& domaine_Cl_VEF = z_class->domaine_cl_vef();
537 const Domaine_VEF& domaine_VEF = z_class->domaine_vef();
538 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
539 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
540 const Periodique& la_cl_perio = ref_cast(Periodique, la_cl.valeur());
541 const int nb_faces_elem = domaine_VEF.domaine().nb_faces_elem(), nb_faces = domaine_VEF.nb_faces(), nb_comp = tab_inconnue.line_size();
542 int num1 = 0, num2 = le_bord.nb_faces_tot(), nb_faces_bord_reel = le_bord.nb_faces();
543
544 // on ne parcourt que la moitie des faces volontairement ... GF il ne faut pas s'occuper des faces virtuelles
545 num2 = is_EXPLICIT ? num2 : nb_faces_bord_reel / 2; // XXX : attention si ecarts car version multicompo, num2 /= 2 .... et aussi je garde l'explicite comme num2
546
547 CIntArrView le_bord_num_face = le_bord.num_face().view_ro();
548 CIntArrView face_associee = la_cl_perio.face_associee().view_ro();
549 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
550 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
551 CDoubleArrView volumes = domaine_VEF.volumes().view_ro();
552 CDoubleArrView inverse_volumes = domaine_VEF.inverse_volumes().view_ro();
553 CDoubleTabView face_normale = domaine_VEF.face_normales().view_ro();
554 CDoubleArrView porosite_eventuelle = tab_porosite_eventuelle.view_ro();
555 CDoubleTabView nu = tab_nu.view_ro();
556 CDoubleTabView nu_turb = tab_nu_turb.view_ro();
557 CDoubleTabView inconnue = tab_inconnue.view_ro();
558 DoubleTabView resu;
559 Matrice_Morse_View matrice;
560 if (is_EXPLICIT)
561 {
562 assert(tab_resu != nullptr);
563 assert(!is_VECT && !_IS_STAB_);
564 resu = tab_resu->view_rw();
565 }
566 else
567 {
568 assert(matrice_morse != nullptr);
569 matrice.set(*matrice_morse);
570 }
571 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
572 Kokkos::RangePolicy<>(num1, num2), KOKKOS_LAMBDA(
573 const int ind_face)
574 {
575 int fac_asso = face_associee(ind_face);
576 fac_asso = le_bord_num_face(fac_asso);
577 int num_face0 = le_bord_num_face(ind_face);
578
579 for (int l = 0; l < 2; l++)
580 {
581 int elem = face_voisins(num_face0, l);
582 for (int i0 = 0; i0 < nb_faces_elem; i0++)
583 {
584 int j = elem_faces(elem, i0);
585
586 if (is_EXPLICIT)
587 {
588 if ((j > num_face0) && (j != fac_asso))
589 for (int nc = 0; nc < nb_comp; nc++)
590 {
591 const double d_nu = nu(elem, (is_RANS ? 0 : nc)) + nu_turb(elem, (is_RANS ? nc : 0));
592 const double valA = z_class->viscA(num_face0, j, elem, d_nu, face_voisins, face_normale, inverse_volumes);
593 const double flux = valA * inconnue(j, nc) - valA * inconnue(num_face0, nc);
594 Kokkos::atomic_add(&resu(num_face0, nc), +flux);
595 if (j < nb_faces) // face reelle
596 Kokkos::atomic_add(&resu(j, nc), -0.5 * flux);
597 }
598 }
599 else // pour l'implicite
600 {
601 if (j > num_face0)
602 {
603 int orientation = 1, fac_loc = 0, ok = 1, contrib = 1;
604
605 if ((elem == face_voisins(j, l)) ||
606 (face_voisins(num_face0, (l + 1) % 2) == face_voisins(j, (l + 1) % 2)))
607 orientation = -1;
608
609 while ((fac_loc < nb_faces_elem) && (elem_faces(elem, fac_loc) != num_face0))
610 fac_loc++;
611
612 if (fac_loc == nb_faces_elem)
613 ok = 0;
614
615 if (j >= nb_faces) // C'est une face virtuelle
616 {
617 int el1 = face_voisins(j, 0), el2 = face_voisins(j, 1);
618 if ((el1 == -1) || (el2 == -1))
619 contrib = 0;
620 }
621
622 if (contrib)
623 for (int nc = 0; nc < nb_comp; nc++)
624 {
625 double d_nu = nu(elem, (is_VECT || is_RANS ) ? 0 : nc) + nu_turb(elem, (is_RANS ? nc : 0));
626 double valA = z_class->viscA(num_face0, j, elem, d_nu, face_voisins, face_normale, inverse_volumes);
627 if (is_STAB && valA < 0.)
628 valA = 0.;
629
630 int n0 = num_face0 * nb_comp + nc;
631 int n0perio = fac_asso * nb_comp + nc;
632 int j0 = j * nb_comp + nc;
633 matrice.atomic_add(n0, n0, + valA * porosite_eventuelle(num_face0));
634 matrice.atomic_add(n0, j0, - valA * porosite_eventuelle(j));
635
636 if (j < nb_faces) // On traite les faces reelles
637 {
638 if (ok == 1)
639 matrice.atomic_add(j0, n0, - valA * porosite_eventuelle(num_face0));
640 else
641 matrice.atomic_add(j0, n0perio, - valA * porosite_eventuelle(num_face0));
642 matrice.atomic_add(j0, j0, + valA * porosite_eventuelle(j));
643 }
644
645 // XXX : On a l'equation QDM et donc on ajoute grad_U transpose
646 if (is_VECT)
647 for (int nc2 = 0; nc2 < nb_comp; nc2++)
648 {
649 int n1 = num_face0 * nb_comp + nc2;
650 int j1 = j * nb_comp + nc2;
651 double coeff_s = orientation * nu_turb(elem,0) / volumes(elem) *
652 face_normale(num_face0, nc2) * face_normale(j, nc);
653 matrice.atomic_add(n0, n1, + coeff_s * porosite_eventuelle(num_face0));
654 matrice.atomic_add(n0, j1, - coeff_s * porosite_eventuelle(j));
655
656 if (j < nb_faces) // On traite les faces reelles
657 {
658 double coeff_s2 = orientation * nu_turb(elem,0) / volumes(elem) *
659 face_normale(num_face0, nc) * face_normale(j, nc2);
660
661 if (ok == 1)
662 matrice.atomic_add(j0, n1, - coeff_s2 * porosite_eventuelle(num_face0));
663 else
664 matrice.atomic_add(j0, fac_asso * nb_comp + nc2, - coeff_s2 * porosite_eventuelle(num_face0));
665
666 matrice.atomic_add(j0, j1, + coeff_s2 * porosite_eventuelle(j));
667 }
668 }
669 }
670 }
671 }
672 }
673 }
674 });
675 end_gpu_timer(__KERNEL_NAME__);
676}
677
678template <typename DERIVED_T> template <Type_Champ _TYPE_, Type_Schema _SCHEMA_, bool _IS_STAB_>
679void Op_Dift_VEF_Face_Gen<DERIVED_T>::ajouter_bord_scalaire_impose_gen__(const int n_bord, const DoubleTab& tab_inconnue, DoubleTab* tab_resu /* Si explicite */, Matrice_Morse* matrice_morse /* Si implicite */,
680 const DoubleTab& tab_nu, const DoubleTab& tab_nu_turb, const DoubleVect& tab_porosite_eventuelle, DoubleTab* tab_flux_bords) const
681{
682 constexpr bool is_EXPLICIT = (_SCHEMA_ == Type_Schema::EXPLICITE);
683
684 const auto *z_class = static_cast<const DERIVED_T*>(this); // CRTP --> I love you :*
685
686 const Domaine_Cl_VEF& domaine_Cl_VEF = z_class->domaine_cl_vef();
687 const RefObjU& modele_turbulence = domaine_Cl_VEF.equation().get_modele(TURBULENCE);
688 if (sub_type(Modele_turbulence_scal_base, modele_turbulence.valeur()))
689 {
690 const Modele_turbulence_scal_base& mod_turb_scal = ref_cast(Modele_turbulence_scal_base, modele_turbulence.valeur());
691 const Turbulence_paroi_scal_base& loiparth = mod_turb_scal.loi_paroi();
692 if (loiparth.use_equivalent_distance())
693 {
694 // Les lois de parois ne s'appliquent qu'aux cas ou la CL est de type temperature imposee, car dans les autres cas
695 // (flux impose et adiabatique) le flux a la paroi est connu et fixe.
696 const Cond_lim_base& cl_base = domaine_Cl_VEF.les_conditions_limites(n_bord).valeur();
697 int ldp_appli = 0;
698 if (sub_type(Scalaire_impose_paroi, cl_base))
699 ldp_appli = 1;
700 else if (loiparth.get_flag_calcul_ldp_en_flux_impose())
701 if ((sub_type(Neumann_paroi, cl_base)) || (sub_type(Neumann_homogene, cl_base)))
702 ldp_appli = 1;
703
704 if (ldp_appli)
705 {
706 const Domaine_VEF& domaine_VEF = z_class->domaine_vef();
707 const Front_VF& le_bord = ref_cast(Front_VF, domaine_Cl_VEF.les_conditions_limites(n_bord)->frontiere_dis());
708 const int nb_faces_elem = domaine_VEF.domaine().nb_faces_elem(), nb_comp = tab_inconnue.line_size(), size_flux_bords = domaine_VEF.nb_faces_bord();
709 int num1 = 0, num2 = le_bord.nb_faces_tot();
710 int dim = Objet_U::dimension;
711 // d_equiv contient la distance equivalente pour le bord
712 // Dans d_equiv, pour les faces qui ne sont pas paroi_fixe (eg periodique, symetrie, etc...)
713 // il y a la distance geometrique grace a l'initialisation du tableau dans la loi de paroi.
714 CDoubleArrView d_equiv = loiparth.equivalent_distance(n_bord).view_ro();
715 CIntArrView le_bord_num_face = le_bord.num_face().view_ro();
716 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
717 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
718 CDoubleTabView face_normale = domaine_VEF.face_normales().view_ro();
719 CDoubleArrView volumes = domaine_VEF.volumes().view_ro();
720 CDoubleArrView face_surfaces = domaine_VEF.face_surfaces().view_ro();
721 CDoubleArrView porosite_eventuelle = tab_porosite_eventuelle.view_ro();
722 CDoubleTabView nu = tab_nu.view_ro();
723 CDoubleTabView nu_turb = tab_nu_turb.view_ro();
724 CDoubleTabView inconnue = tab_inconnue.view_ro();
725 DoubleTabView flux_bords;
726 DoubleTabView resu;
727 Matrice_Morse_View matrice;
728 if (is_EXPLICIT)
729 {
730 assert(tab_resu != nullptr);
731 flux_bords = tab_flux_bords->view_rw();
732 resu = tab_resu->view_rw();
733 }
734 else
735 {
736 assert(matrice_morse != nullptr);
737 matrice.set(*matrice_morse);
738 }
739 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
740 Kokkos::RangePolicy<>(num1, num2), KOKKOS_LAMBDA(
741 const int ind_face)
742 {
743 double le_mauvais_gradient[3] = { 0., 0., 0. };
744 for (int nc = 0; nc < nb_comp; nc++)
745 {
746 int num_face = le_bord_num_face(ind_face);
747 // Tf est la temperature fluide moyenne dans le premier element sans tenir compte de la temperature de paroi.
748 double Tf = 0.;
749 double bon_gradient = 0.; // c'est la norme du gradient de temperature normal a la paroi
750
751 for (int kk = 0; kk < dim; kk++)
752 le_mauvais_gradient[kk] = 0.;
753
754 int elem1 = face_voisins(num_face, 0);
755 if (elem1 == -1) elem1 = face_voisins(num_face, 1);
756
757 // inconnue(num_face) est la temperature de paroi : Tw.
758 // On se fiche du signe de bon gradient car c'est la norme du gradient de temperature dans l'element.
759 // Ensuite ce sera multiplie par le vecteur normal a la face de paroi qui lui a les bons signes.
760
761 if (!is_EXPLICIT)
762 bon_gradient = 1. / d_equiv(ind_face) * (-oriente_normale(num_face, elem1, face_voisins));
763
764 double surface_face = face_surfaces(num_face);
765 double nutotal = nu(elem1, nc) + nu_turb(elem1,0);
766
767 if (is_EXPLICIT)
768 {
769 for (int i = 0; i < nb_faces_elem; i++)
770 {
771 const int j = elem_faces(elem1, i);
772 if (j != num_face)
773 {
774 double surface_pond = 0.;
775 double signe_j = oriente_normale(j, elem1, face_voisins);
776 double signe_num_face = oriente_normale(num_face, elem1, face_voisins);
777 for (int kk = 0; kk < dim; kk++)
778 surface_pond -= (face_normale(j, kk) * signe_j *
779 face_normale(num_face, kk) * signe_num_face) /
780 (surface_face * surface_face);
781
782 Tf += inconnue(j, nc) * surface_pond;
783 }
784
785 double signe_j = oriente_normale(j, elem1, face_voisins);
786 for (int kk = 0; kk < dim; kk++)
787 le_mauvais_gradient[kk] += inconnue(j, nc) * face_normale(j, kk) * signe_j;
788 }
789 for (int kk = 0; kk < dim; kk++)
790 le_mauvais_gradient[kk] /= volumes(elem1);
791
792 double mauvais_gradient = 0;
793 for (int kk = 0; kk < dim; kk++)
794 mauvais_gradient += le_mauvais_gradient[kk] * face_normale(num_face, kk) / surface_face;
795
796 // inconnue(num_face) est la temperature de paroi : Tw.
797 // On se fiche du signe de bon gradient car c'est la norme du gradient de temperature dans l'element.
798 // Ensuite ce sera multiplie par le vecteur normal a la face de paroi qui lui a les bons signes.
799 double signe_num_face = oriente_normale(num_face, elem1, face_voisins);
800 bon_gradient = (Tf - inconnue(num_face, nc)) / d_equiv(ind_face) * (-signe_num_face);
801
802 for (int i = 0; i < nb_faces_elem; i++)
803 {
804 const int j = elem_faces(elem1, i);
805 double correction = 0.;
806 double signe_j = oriente_normale(j, elem1, face_voisins);
807 for (int kk = 0; kk < dim; kk++)
808 {
809 double resu2 =
810 nutotal * (bon_gradient - mauvais_gradient) * face_normale(num_face, kk) *
811 face_normale(j, kk) * (-signe_j) / surface_face;
812 correction += resu2;
813 }
814
815 Kokkos::atomic_add(&resu(j, nc), +correction);
816 if (j == num_face && j < size_flux_bords)
817 Kokkos::atomic_add(&flux_bords(j, nc), -correction);
818 }
819 }
820 else // implicite
821 {
822 for (int i0 = 0; i0 < nb_faces_elem; i0++)
823 {
824 int j = elem_faces(elem1, i0);
825 for (int ii = 0; ii < nb_faces_elem; ii++)
826 {
827 for (int kk = 0; kk < dim; kk++)
828 le_mauvais_gradient[kk] = 0;
829 int jj = elem_faces(elem1, ii);
830 double surface_pond = 0;
831 double signe_jj = oriente_normale(jj, elem1, face_voisins);
832 double signe_num_face = oriente_normale(num_face, elem1, face_voisins);
833 for (int kk = 0; kk < dim; kk++)
834 surface_pond -= (face_normale(jj, kk) * signe_jj *
835 face_normale(num_face, kk) * signe_num_face) /
836 (surface_face * surface_face);
837
838 Tf = surface_pond;
839 for (int kk = 0; kk < dim; kk++)
840 le_mauvais_gradient[kk] += face_normale(jj, kk) * signe_jj;
841
842 for (int kk = 0; kk < dim; kk++)
843 le_mauvais_gradient[kk] /= volumes(elem1);
844
845 double mauvais_gradient = 0;
846 for (int kk = 0; kk < dim; kk++)
847 mauvais_gradient +=
848 le_mauvais_gradient[kk] * face_normale(num_face, kk) / surface_face;
849
850 double resu1 = 0, resu2 = 0;
851 double signe_j = oriente_normale(j, elem1, face_voisins);
852 for (int kk = 0; kk < dim; kk++)
853 {
854 double coeff = -nutotal * face_normale(num_face, kk) * face_normale(j, kk) * signe_j / surface_face;
855 resu1 += mauvais_gradient * coeff;
856 resu2 += bon_gradient * coeff;
857 }
858 // bon gradient_reel = bongradient*(Tf-T_face) d'ou les derivees... & mauvais gradient_reel=mauvai_gradient_j*Tj
859 if (jj == num_face)
860 resu2 *= -1;
861 else
862 resu2 *= Tf;
863
864 int j0 = j * nb_comp + nc, jj0 = jj * nb_comp + nc;
865 matrice.atomic_add(j0, jj0, (resu1 - resu2) * porosite_eventuelle(jj0));
866 }
867 }
868 }
869 }
870 });
871 end_gpu_timer(__KERNEL_NAME__);
872 }
873 }
874 }
875}
876
877template <typename DERIVED_T> template <Type_Champ _TYPE_, Type_Schema _SCHEMA_, bool _IS_STAB_, bool _IS_RANS_>
878void Op_Dift_VEF_Face_Gen<DERIVED_T>::ajouter_bord_gen__(const int n_bord, const DoubleTab& tab_inconnue, DoubleTab* tab_resu /* Si explicite */, Matrice_Morse* matrice_morse /* Si implicite */,
879 const DoubleTab& tab_nu, const DoubleTab& tab_nu_turb, const DoubleVect& tab_porosite_eventuelle, DoubleTab* tab_flux_bords) const
880{
881 constexpr bool is_VECT = (_TYPE_ == Type_Champ::VECTORIEL), is_EXPLICIT = (_SCHEMA_ == Type_Schema::EXPLICITE), is_STAB = _IS_STAB_, is_RANS = _IS_RANS_;
882
883 const auto *z_class = static_cast<const DERIVED_T*>(this); // CRTP --> I love you :*
884
885 const Domaine_Cl_VEF& domaine_Cl_VEF = z_class->domaine_cl_vef();
886 const Domaine_VEF& domaine_VEF = z_class->domaine_vef();
887 const int nb_faces_elem = domaine_VEF.domaine().nb_faces_elem(), nb_faces = domaine_VEF.nb_faces(), nb_comp = tab_inconnue.line_size(), premiere_face_int = domaine_VEF.premiere_face_int();;
888
889 const Front_VF& le_bord = ref_cast(Front_VF, domaine_Cl_VEF.les_conditions_limites(n_bord)->frontiere_dis());
890 const int num1 = 0, num2 = le_bord.nb_faces_tot(), nb_faces_bord_reel = le_bord.nb_faces();
891
892 CIntArrView le_bord_num_face = le_bord.num_face().view_ro();
893 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
894 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
895 CDoubleTabView face_normale = domaine_VEF.face_normales().view_ro();
896 CDoubleArrView volumes = domaine_VEF.volumes().view_ro();
897 CDoubleArrView inverse_volumes = domaine_VEF.inverse_volumes().view_ro();
898 CDoubleArrView porosite_eventuelle = tab_porosite_eventuelle.view_ro();
899 CDoubleTabView nu = tab_nu.view_ro();
900 CDoubleTabView nu_turb = tab_nu_turb.view_ro();
901 CDoubleTabView inconnue = tab_inconnue.view_ro();
902 DoubleTabView flux_bords;
903 DoubleTabView resu;
904 Matrice_Morse_View matrice;
905 if (is_EXPLICIT)
906 {
907 assert(tab_resu != nullptr);
908 assert(!is_VECT && !_IS_STAB_);
909 flux_bords = tab_flux_bords->view_rw();
910 resu = tab_resu->view_rw();
911 }
912 else
913 {
914 assert(matrice_morse != nullptr);
915 matrice.set(*matrice_morse);
916 }
917 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
918 Kokkos::RangePolicy<>(num1, num2), KOKKOS_LAMBDA(
919 const int ind_face)
920 {
921 const int num_face = le_bord_num_face(ind_face), elem = face_voisins(num_face, 0);
922 for (int i = 0; i < nb_faces_elem; i++)
923 {
924 int j = elem_faces(elem, i);
925 if ((j > num_face) || (ind_face >= nb_faces_bord_reel))
926 {
927 int orientation = 1;
928 if ((elem == face_voisins(j, 0)) || (face_voisins(num_face, (0 + 1) % 2) == face_voisins(j, (0 + 1) % 2)))
929 orientation = -1;
930
931 for (int nc = 0; nc < nb_comp; nc++)
932 {
933 const double d_nu = nu(elem, (is_VECT || is_RANS) ? 0 : nc) + nu_turb(elem, (is_RANS ? nc : 0));
934 double valA = z_class->viscA(num_face, j, elem, d_nu, face_voisins, face_normale, inverse_volumes);
935
936 if (is_STAB && valA < 0.) valA = 0.;
937
938 if (is_EXPLICIT)
939 {
940 if (ind_face < nb_faces_bord_reel)
941 {
942 double flux = valA * (inconnue(j, nc) - inconnue(num_face, nc));
943 Kokkos::atomic_add(&resu(num_face, nc), +flux);
944 Kokkos::atomic_add(&flux_bords(num_face, nc), -flux);
945 }
946 if (j < nb_faces) // face reelle
947 {
948 double flux = valA * (inconnue(num_face, nc) - inconnue(j, nc));
949 Kokkos::atomic_add(&resu(j, nc), +flux);
950 if (j < premiere_face_int)
951 Kokkos::atomic_add(&flux_bords(j, nc), -flux);
952 }
953 }
954 else // implicite
955 {
956 const int n0 = num_face * nb_comp + nc, j0 = j * nb_comp + nc;
957 if (ind_face < nb_faces_bord_reel)
958 {
959 matrice.atomic_add(n0, n0, + valA * porosite_eventuelle(num_face));
960 matrice.atomic_add(n0, j0, - valA * porosite_eventuelle(j));
961 }
962
963 if (j < nb_faces) // face reelle
964 {
965 matrice.atomic_add(j0, n0, - valA * porosite_eventuelle(num_face));
966 matrice.atomic_add(j0, j0, + valA * porosite_eventuelle(j));
967 }
968
969 // XXX : On a l'equation QDM et donc on ajoute grad_U transpose
970 if (is_VECT)
971 for (int nc2 = 0; nc2 < nb_comp; nc2++)
972 {
973 const int n1 = num_face * nb_comp + nc2, j1 = j * nb_comp + nc2;
974 if (ind_face < nb_faces_bord_reel)
975 {
976 double coeff_s = orientation * nu_turb(elem,0) / volumes(elem) * face_normale(num_face, nc2) * face_normale(j, nc);
977 matrice.atomic_add(n0, n1, + coeff_s * porosite_eventuelle(num_face));
978 matrice.atomic_add(n0, j1, - coeff_s * porosite_eventuelle(j));
979 }
980
981 if (j < nb_faces) // face reelle
982 {
983 double coeff_s = orientation * nu_turb(elem,0) / volumes(elem) * face_normale(num_face, nc) * face_normale(j, nc2);
984 matrice.atomic_add(j0, n1, - coeff_s * porosite_eventuelle(num_face));
985 matrice.atomic_add(j0, j1, + coeff_s * porosite_eventuelle(j));
986 }
987 }
988 }
989 }
990 }
991 }
992 });
993 end_gpu_timer(__KERNEL_NAME__);
994}
995
996template <typename DERIVED_T> template <Type_Champ _TYPE_, Type_Schema _SCHEMA_, bool _IS_STAB_, bool _IS_RANS_>
997void Op_Dift_VEF_Face_Gen<DERIVED_T>::ajouter_interne_gen__(const DoubleTab& tab_inconnue, DoubleTab* tab_resu /* Si explicite */, Matrice_Morse* matrice_morse /* Si implicite */,
998 const DoubleTab& tab_nu, const DoubleTab& tab_nu_turb, const DoubleVect& tab_porosite_eventuelle) const
999{
1000 constexpr bool is_VECT = (_TYPE_ == Type_Champ::VECTORIEL), is_EXPLICIT = (_SCHEMA_ == Type_Schema::EXPLICITE), is_STAB = _IS_STAB_, is_RANS = _IS_RANS_;
1001
1002 const auto *z_class = static_cast<const DERIVED_T*>(this); // CRTP --> I love you :*
1003
1004 const Domaine_VEF& domaine_VEF = z_class->domaine_vef();
1005 const int premiere_face_int = domaine_VEF.premiere_face_int(), nb_faces = domaine_VEF.nb_faces(), nb_faces_elem = domaine_VEF.domaine().nb_faces_elem(), nb_comp = tab_inconnue.line_size();
1006
1007 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
1008 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
1009 CDoubleTabView face_normale = domaine_VEF.face_normales().view_ro();
1010 CDoubleArrView inverse_volumes = domaine_VEF.inverse_volumes().view_ro();
1011 CDoubleArrView porosite_eventuelle = tab_porosite_eventuelle.view_ro();
1012 CDoubleTabView nu = tab_nu.view_ro();
1013 CDoubleTabView nu_turb = tab_nu_turb.view_ro();
1014 CDoubleTabView inconnue = tab_inconnue.view_ro();
1015 DoubleTabView resu;
1016 Matrice_Morse_View matrice;
1017 if (is_EXPLICIT)
1018 {
1019 assert(tab_resu != nullptr);
1020 resu = tab_resu->view_rw();
1021 }
1022 else
1023 {
1024 assert(matrice_morse != nullptr);
1025 matrice.set(*matrice_morse);
1026 }
1027 Kokkos::MDRangePolicy<Kokkos::Rank<2>> policy({premiere_face_int, 0}, {nb_faces, 2});
1028 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), policy, KOKKOS_LAMBDA(const int num_face, const int kk)
1029 {
1030 int elem = face_voisins(num_face, kk);
1031 for (int i0 = 0; i0 < nb_faces_elem; i0++)
1032 {
1033 int j = elem_faces(elem, i0);
1034 if (j > num_face)
1035 {
1036 int contrib = 1;
1037 if (j >= nb_faces) // C'est une face virtuelle
1038 {
1039 const int el1 = face_voisins(j, 0), el2 = face_voisins(j, 1);
1040 if ((el1 == -1) || (el2 == -1))
1041 contrib = 0;
1042 }
1043
1044 if (contrib)
1045 {
1046 double tmp = 0.;
1047 // XXX : On a l'equation QDM et donc on ajoute grad_U transpose
1048 if (!is_EXPLICIT && is_VECT)
1049 {
1050 int orientation = 1;
1051 if ((elem == face_voisins(j, kk)) ||
1052 (face_voisins(num_face, 1 - kk) == face_voisins(j, 1 - kk)))
1053 orientation = -1;
1054 tmp = orientation * nu_turb(elem,0) * inverse_volumes(elem);
1055 }
1056 for (int nc = 0; nc < nb_comp; nc++)
1057 {
1058 double d_nu = nu(elem, (is_VECT || is_RANS) ? 0 : nc) + nu_turb(elem, (is_RANS ? nc : 0));
1059 double valA = z_class->viscA(num_face, j, elem, d_nu, face_voisins, face_normale, inverse_volumes);
1060
1061 if (is_STAB && valA < 0.) valA = 0.;
1062
1063 if (is_EXPLICIT)
1064 {
1065 const double flux = valA * inconnue(j, nc) - valA * inconnue(num_face, nc);
1066 Kokkos::atomic_add(&resu(num_face, nc), flux);
1067 if (j < nb_faces) // On traite les faces reelles
1068 Kokkos::atomic_sub(&resu(j, nc), flux);
1069 }
1070 else // METHODE IMPLICITE
1071 {
1072 double contrib_num_face = valA * porosite_eventuelle(num_face);
1073 double contrib_j = valA * porosite_eventuelle(j);
1074 const int n0 = num_face * nb_comp + nc, j0 = j * nb_comp + nc;
1075 matrice.atomic_add(n0, n0, contrib_num_face);
1076 matrice.atomic_add(n0, j0, -contrib_j);
1077 if (j < nb_faces) // On traite les faces reelles
1078 {
1079 matrice.atomic_add(j0, n0, -contrib_num_face);
1080 matrice.atomic_add(j0, j0, contrib_j);
1081 }
1082
1083 // XXX : On a l'equation QDM et donc on ajoute grad_U transpose
1084 if (is_VECT)
1085 {
1086 double poro_num_face = porosite_eventuelle(num_face);
1087 double poro_j = porosite_eventuelle(j);
1088 double face_normale_num_face = face_normale(num_face, nc);
1089 double face_normale_j = face_normale(j, nc);
1090 for (int nc2 = 0; nc2 < nb_comp; nc2++)
1091 {
1092 const int n1 = num_face * nb_comp + nc2;
1093 const int j1 = j * nb_comp + nc2;
1094 double coeff_s = is_STAB ? 0. : tmp * face_normale(num_face, nc2) * face_normale_j;
1095
1096 matrice.atomic_add(n0, n1, coeff_s * poro_num_face);
1097 matrice.atomic_add(n0, j1, -coeff_s * poro_j);
1098 if (j < nb_faces) // On traite les faces reelles
1099 {
1100 double coeff_s2 = is_STAB ? 0. : tmp * face_normale_num_face * face_normale(j, nc2);
1101 matrice.atomic_add(j0, n1, -coeff_s2 * poro_num_face);
1102 matrice.atomic_add(j0, j1, coeff_s2 * poro_j);
1103 }
1104 }
1105 }
1106 }
1107 }
1108 }
1109 }
1110 }
1111 });
1112 end_gpu_timer(__KERNEL_NAME__);
1113}
1114
1115#endif /* Op_Dift_VEF_Face_Gen_TPP_included */
static DoubleTab & calcul_gradient(const DoubleTab &, DoubleTab &, const Domaine_Cl_VEF &)
static DoubleTab & calcul_duidxj_paroi(DoubleTab &, const DoubleTab &, const DoubleTab &, const DoubleTab &, const Domaine_Cl_VEF &)
classe Cond_lim_base Classe de base pour la hierarchie des classes qui representent les differentes c...
classe Cond_lim Classe generique servant a representer n'importe quelle classe
Definition Cond_lim.h:31
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
virtual void creer_tableau_elements(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
creation d'un tableau parallele de valeurs aux elements.
Definition Domaine.cpp:851
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
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
class Domaine_VEF
Definition Domaine_VEF.h:54
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
virtual double face_normales(int face, int comp) const
Definition Domaine_VF.h:47
double volumes(int i) const
Definition Domaine_VF.h:113
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 premiere_face_int() const
une face est interne ssi elle separe deux elements.
Definition Domaine_VF.h:463
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_faces_bord() const
renvoie le nombre de faces sur lesquelles sont appliquees les conditions limites :
Definition Domaine_VF.h:513
double inverse_volumes(int i) const
Definition Domaine_VF.h:114
int nb_front_Cl() const
const Domaine & domaine() const
Classe Echange_externe_impose: Cette classe represente le cas particulier de la classe.
const DoubleTab & tab_h_imp(double temps=DMAXFLOAT) const
const DoubleTab & tab_T_ext(double temps=DMAXFLOAT) const
virtual const RefObjU & get_modele(Type_modele type) const
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
int nb_faces_tot() const
Definition Front_VF.h:58
int num_face(const int) const
Definition Front_VF.h:68
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
Classe Modele_turbulence_scal_base Cette classe represente un modele de turbulence pour une equation ...
const Turbulence_paroi_scal_base & loi_paroi() const
Renvoie la loi de turbulence sur la paroi (version const).
const Equation_base & equation() const
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
Classe Neumann_homogene Cette classe est la classe de base de la hierarchie des conditions aux limite...
Classe Neumann_paroi Cette condition limite correspond a un flux impose pour l'equation de.
classe Neumann_sortie_libre Cette classe represente une frontiere ouverte sans vitesse imposee
virtual double flux_impose(int i) const
Renvoie la valeur du flux impose sur la i-eme composante du champ representant le flux a la frontiere...
Definition Neumann.cpp:35
static int dimension
Definition Objet_U.h:99
std::enable_if_t< _TYPE_==Type_Champ::VECTORIEL, void > ajouter_bord_gen(const DoubleTab &, DoubleTab &, DoubleTab &, const DoubleTab &, const DoubleTab &) const
void modifie_pour_cl_gen(const DoubleTab &, DoubleTab &, DoubleTab &) const
void fill_grad_Re(const DoubleTab &, const DoubleTab &, const DoubleTab &, const DoubleTab &) const
void ajouter_contribution_bord_gen(const DoubleTab &, Matrice_Morse &, const DoubleTab &, const DoubleTab &, const DoubleVect &) const
std::enable_if_t< _TYPE_==Type_Champ::VECTORIEL, void > ajouter_interne_gen(const DoubleTab &, DoubleTab &, DoubleTab &, const DoubleTab &, const DoubleTab &) const
classe Periodique Cette classe represente une condition aux limites periodique.
Definition Periodique.h:31
int face_associee(int i) const
Definition Periodique.h:35
classe Scalaire_impose_paroi Impose un scalaire a la paroi dans une equation de type Convection-Difus...
classe Symetrie Sur les faces de symetrie on a les proprietes suivantes:
Definition Symetrie.h:37
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, View< _TYPE_, _SHAPE_ > > view_wo()
Definition TRUSTTab.h:276
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
int line_size() const
Definition TRUSTVect.tpp:67
const Objet_U & valeur() const
Definition TRUST_Ref.h:134
Classe Turbulence_paroi_scal_base Classe de base pour la hierarchie des classes representant les mode...
virtual bool use_equivalent_distance() const
Give a boolean indicating if we need to use equivant distance by default we consider that we use the ...
const DoubleVects & equivalent_distance() const
const int & get_flag_calcul_ldp_en_flux_impose() const