TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Op_VEF_Face.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 <Op_VEF_Face.h>
17#include <Matrice_Morse.h>
18#include <Equation_base.h>
19#include <Sortie.h>
20#include <Probleme_base.h>
21
22#include <Champ_Uniforme.h>
23#include <Schema_Temps_base.h>
24#include <Milieu_base.h>
25#include <Operateur_base.h>
26#include <Operateur_Diff_base.h>
27#include <Op_Conv_VEF_base.h>
28#include <EcrFicPartage.h>
29#include <SFichier.h>
30#include <Process.h>
31#include <Matrice_Morse_Diag.h>
32#include <TRUSTTrav.h>
33#include <Dirichlet_homogene.h>
34#include <Periodique.h>
35#include <Symetrie.h>
36
37/*! @brief Dimensionnement de la matrice qui devra recevoir les coefficients provenant de la convection, de la diffusion pour le cas des faces.
38 *
39 * Cette matrice a une structure de matrice morse.
40 * Nous commencons par calculer les tailles des tableaux tab1 et tab2.
41 *
42 */
43
44void Op_VEF_Face::dimensionner(const Domaine_VEF& le_dom, const Domaine_Cl_VEF& le_dom_cl, Matrice_Morse& la_matrice) const
45{
46 // Dimensionnement de la matrice qui devra recevoir les coefficients provenant de
47 // la convection, de la diffusion pour le cas des faces.
48 // Cette matrice a une structure de matrice morse.
49 // Nous commencons par calculer les tailles des tableaux tab1 et tab2.
50 // Pour ce faire il faut chercher les faces voisines de la face consideree.
51
52 int nfin = le_dom.nb_faces_tot();
53 int nb_faces_elem = le_dom.domaine().nb_faces_elem();
54 const int nb_comp = le_dom_cl.equation().inconnue().valeurs().line_size();
55 la_matrice.dimensionner(nfin * nb_comp, nfin * nb_comp, 0);
56
57 auto& tab1 = la_matrice.get_set_tab1();
58 auto& tab2 = la_matrice.get_set_tab2();
59 auto& coeff = la_matrice.get_set_coeff();
60 coeff = 0;
61
62 const IntTab& elem_faces = le_dom.elem_faces();
63 const IntTab& face_voisins = le_dom.face_voisins();
64
65 // A chaque face on associe un tableau d'entiers et une liste de reels:
66 // voisines[i] = {j t.q j>i et M(i,j) est non nul }
67
68 // IntVect rang_voisin(nfin*nb_comp);
69 IntTrav rang_voisin(nfin * nb_comp);
70 rang_voisin = nb_comp;
71 // On traite toutes les faces
72 int j;
73 ToDo_Kokkos("Port with kokkos ? It will be called once...");
74 for (int num_face = 0; num_face < nfin; num_face++)
75 {
76 int elem1 = face_voisins(num_face, 0);
77 int elem2 = face_voisins(num_face, 1);
78
79 for (int i = 0; i < nb_faces_elem; i++)
80 {
81 if ((j = elem_faces(elem1, i)) != num_face)
82 {
83 for (int k = 0; k < nb_comp; k++)
84 {
85 rang_voisin(num_face * nb_comp + k) += nb_comp;
86 }
87 }
88 if (elem2 != -1)
89 if ((j = elem_faces(elem2, i)) != num_face)
90 {
91 for (int k = 0; k < nb_comp; k++)
92 {
93 rang_voisin(num_face * nb_comp + k) += nb_comp;
94 }
95 }
96 }
97 }
98
99 // les faces voisines de num_face etant desormais comtabilisees
100 // nous dimensionnons tab1 et tab2 au nombre de faces
101
102 tab1(0) = 1;
103 for (int num_face = 0; num_face < nfin; num_face++)
104 {
105 for (int k = 0; k < nb_comp; k++)
106 {
107 tab1(num_face * nb_comp + 1 + k) = rang_voisin(num_face * nb_comp + k) + tab1(num_face * nb_comp + k);
108 }
109 }
110 la_matrice.dimensionner(nfin * nb_comp, tab1(nfin * nb_comp) - 1);
111
112 for (int num_face = 0; num_face < nfin; num_face++)
113 {
114 for (int k = 0; k < nb_comp; k++)
115 {
116 for (int kk = 0; kk < nb_comp; kk++)
117 {
118 int modulo = (k + kk) % nb_comp;
119 tab2[tab1[num_face * nb_comp + k] - 1 + kk] = num_face * nb_comp + 1 + modulo;
120 }
121 rang_voisin[num_face * nb_comp + k] = (int)(tab1[num_face * nb_comp + k] + nb_comp - 1);
122 }
123 }
124
125 // On traite toutes les faces
126 for (int num_face = 0; num_face < nfin; num_face++)
127 {
128 int elem1 = face_voisins(num_face, 0);
129 int elem2 = face_voisins(num_face, 1);
130
131 for (int i = 0; i < nb_faces_elem; i++)
132 {
133 if ((j = elem_faces(elem1, i)) != num_face)
134 {
135 for (int k = 0; k < nb_comp; k++)
136 {
137 for (int kk = 0; kk < nb_comp; kk++)
138 {
139 int modulo = (k + kk) % nb_comp;
140 tab2[rang_voisin[num_face * nb_comp + k] + kk] = j * nb_comp + 1 + modulo;
141 }
142 rang_voisin[num_face * nb_comp + k] += nb_comp;
143 }
144 }
145 if (elem2 != -1)
146 {
147 if ((j = elem_faces(elem2, i)) != num_face)
148 {
149 for (int k = 0; k < nb_comp; k++)
150 {
151 for (int kk = 0; kk < nb_comp; kk++)
152 {
153 int modulo = (k + kk) % nb_comp;
154 tab2[rang_voisin[num_face * nb_comp + k] + kk] = j * nb_comp + 1 + modulo;
155 }
156 rang_voisin[num_face * nb_comp + k] += nb_comp;
157 }
158 }
159 }
160 }
161 }
162}
163
164/*! @brief Modification des coef de la matrice et du second membre pour les conditions de Dirichlet
165 *
166 */
167
168void Op_VEF_Face::modifier_pour_Cl(const Domaine_VEF& le_dom, const Domaine_Cl_VEF& le_dom_cl, Matrice_Morse& la_matrice, DoubleTab& tab_secmem) const
169{
170 // Dimensionnement de la matrice qui devra recevoir les coefficients provenant de
171 // la convection, de la diffusion pour le cas des faces.
172 // Cette matrice a une structure de matrice morse.
173 // Nous commencons par calculer les tailles des tableaux tab1 et tab2.
174 const Conds_lim& les_cl = le_dom_cl.les_conditions_limites();
175 const DoubleTab& champ_inconnue = le_dom_cl.equation().inconnue().valeurs();
176 const int nb_comp = champ_inconnue.line_size();
177 ArrOfDouble normale(nb_comp);
178 for (const auto &itr : les_cl)
179 {
180 const Cond_lim_base& la_cl = itr.valeur();
181 const Front_VF& la_front_dis = ref_cast(Front_VF, la_cl.frontiere_dis());
182 int nfaces = la_front_dis.nb_faces_tot();
183 if (sub_type(Dirichlet, la_cl) || sub_type(Dirichlet_homogene, la_cl))
184 {
185 bool has_val_imp = sub_type(Dirichlet, la_cl);
186 CDoubleTabView val_imp;
187 if (has_val_imp) val_imp = ref_cast(Dirichlet, la_cl).tab_val_imp().view_ro();
188 auto tab1 = la_matrice.get_tab1().view_ro();
189 CIntArrView num_face = la_front_dis.num_face().view_ro();
190 DoubleArrView coeff = la_matrice.get_set_coeff().view_wo();
191 DoubleTabView secmem = tab_secmem.view_wo();
192 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nfaces, KOKKOS_LAMBDA(const int ind_face)
193 {
194 int face = num_face(ind_face);
195 for (int comp = 0; comp < nb_comp; comp++)
196 {
197 auto idiag = tab1[face * nb_comp + comp] - 1;
198 coeff[idiag] = 1;
199 // pour les voisins
200 auto nbvois = tab1[face * nb_comp + 1 + comp] - tab1[face * nb_comp + comp];
201 for (auto k = 1; k < nbvois; k++)
202 coeff[idiag + k] = 0;
203 // pour le second membre
204 int j = nb_comp == 1 ? 0 : comp;
205 secmem(face, j) = has_val_imp ? val_imp(ind_face, j) : 0.;
206 }
207 });
208 end_gpu_timer(__KERNEL_NAME__);
209 }
210 else if (sub_type(Symetrie, la_cl) && le_dom_cl.equation().inconnue().nature_du_champ() == vectoriel)
211 {
212 const auto& tab1 = la_matrice.get_tab1();
213 const auto& tab2 = la_matrice.get_tab2();
214 const DoubleTab& face_normales = le_dom.face_normales();
215 ArrOfDouble somme(la_matrice.nb_colonnes()); // On dimensionne au plus grand
216 ToDo_Kokkos("critical");
217 for (int ind_face = 0; ind_face < nfaces; ind_face++)
218 {
219 int face = la_front_dis.num_face(ind_face);
220 double max_coef = 0;
221 int ind_max = -1;
222 double n2 = 0;
223 for (int comp = 0; comp < nb_comp; comp++)
224 {
225 normale[comp] = face_normales(face, comp);
226 if (std::fabs(normale[comp]) > std::fabs(max_coef))
227 {
228 max_coef = normale[comp];
229 ind_max = comp;
230 }
231 n2 += normale[comp] * normale[comp];
232 }
233 normale /= sqrt(n2);
234 max_coef = normale[ind_max];
235
236 // On commence par recalculer secmem=secmem-A *present pour pouvoir modifier A (on en profite pour projeter)
237 auto nb_coeff_ligne = tab1[face * nb_comp + 1] - tab1[face * nb_comp];
238 for (auto k = 0; k < nb_coeff_ligne; k++)
239 {
240 for (int comp = 0; comp < nb_comp; comp++)
241 {
242 int j = tab2[tab1[face * nb_comp + comp] - 1 + k] - 1;
243 //assert(j!=(face*nb_comp+comp));
244 //if ((j>=(face*nb_comp))&&(j<(face*nb_comp+nb_comp)))
245 const double coef_ij = la_matrice(face * nb_comp + comp, j);
246 int face2 = j / nb_comp;
247 int comp2 = j - face2 * nb_comp;
248 tab_secmem(face, comp) -= coef_ij * champ_inconnue(face2, comp2);
249 }
250 }
251 double somme_b = 0;
252
253 for (int comp = 0; comp < nb_comp; comp++)
254 somme_b += tab_secmem(face, comp) * normale[comp];
255
256 // on retire secmem.n n
257 for (int comp = 0; comp < nb_comp; comp++)
258 tab_secmem(face, comp) -= somme_b * normale[comp];
259
260 // on doit remettre la meme diagonale partout on prend la moyenne
261 double ref = 0;
262 for (int comp = 0; comp < nb_comp; comp++)
263 {
264 int j0 = face * nb_comp + comp;
265 ref += la_matrice(j0, j0);
266 }
267 ref /= nb_comp;
268
269 for (int comp = 0; comp < nb_comp; comp++)
270 {
271 int j0 = face * nb_comp + comp;
272 double rap = ref / la_matrice(j0, j0);
273 for (auto k = 0; k < nb_coeff_ligne; k++)
274 {
275 int j = tab2[tab1[j0] - 1 + k] - 1;
276 la_matrice(j0, j) *= rap;
277 }
278 assert(est_egal(la_matrice(j0, j0), ref));
279 }
280 // on annule tous les coef extra diagonaux du bloc
281 //
282 for (auto k = 1; k < nb_coeff_ligne; k++)
283 {
284 for (int comp = 0; comp < nb_comp; comp++)
285 {
286 int j = tab2[tab1[face * nb_comp + comp] - 1 + k] - 1;
287 assert(j != (face * nb_comp + comp));
288 if ((j >= (face * nb_comp)) && (j < (face * nb_comp + nb_comp)))
289 la_matrice(face * nb_comp + comp, j) = 0;
290 }
291 }
292
293 // pour les blocs extra diagonaux on assure que Aij.ni=0
294 //ArrOfDouble somme(nb_coeff_ligne);
295 for (auto k = 0; k < nb_coeff_ligne; k++)
296 {
297 somme[(int)k] = 0;
298 int j = tab2[tab1[face * nb_comp] - 1 + k] - 1;
299
300 // le coeff j doit exister sur les nb_comp lignes
301 double dsomme = 0;
302 for (int comp = 0; comp < nb_comp; comp++)
303 dsomme += la_matrice(face * nb_comp + comp, j) * normale[comp];
304
305 // on retire somme ni
306
307 for (int comp = 0; comp < nb_comp; comp++)
308 // on modifie que les coefficients ne faisant pas intervenir u(face,comp)
309 if ((j < (face * nb_comp)) || (j >= (face * nb_comp + nb_comp)))
310 la_matrice(face * nb_comp + comp, j) -= (dsomme) * normale[comp];
311 }
312 // Finalement on recalcule secmem=secmem+A*champ_inconnue (A a ete beaucoup modiife)
313 for (auto k = 0; k < nb_coeff_ligne; k++)
314 {
315 for (int comp = 0; comp < nb_comp; comp++)
316 {
317 int j = tab2[tab1[face * nb_comp + comp] - 1 + k] - 1;
318 int face2 = j / nb_comp;
319 int comp2 = j - face2 * nb_comp;
320 const double coef_ij = la_matrice(face * nb_comp + comp, j);
321 tab_secmem(face, comp) += coef_ij * champ_inconnue(face2, comp2);
322 }
323 }
324 {
325 // verification
326 double somme_c = 0;
327 for (int comp = 0; comp < nb_comp; comp++)
328 somme_c += tab_secmem(face, comp) * normale[comp];
329 // on retire secmem.n n
330 for (int comp = 0; comp < nb_comp; comp++)
331 tab_secmem(face, comp) -= somme_c * normale[comp];
332 }
333 }
334 }
335 }
336}
337
339{
340 controle_modifier_flux_ = 1;
341 DoubleTab& flux_bords_ = op.flux_bords();
342 if (flux_bords_.nb_dim() != 2)
343 return;
344 const Probleme_base& pb = op.equation().probleme();
345
346 const Domaine_VEF& le_dom_vef = ref_cast(Domaine_VEF, op.equation().domaine_dis());
347 int nb_compo = flux_bords_.dimension(1);
348 // On multiplie le flux au bord par rho*Cp sauf si c'est un operateur de diffusion avec la conductivite comme champ
349 if (op.equation().inconnue().le_nom() == "temperature" && !( sub_type(Operateur_Diff_base,op) && ref_cast(Operateur_Diff_base,op).diffusivite().le_nom() == "conductivite"))
350 {
351 const Champ_base& rho = op.equation().milieu().masse_volumique();
353 bool rho_uniforme = sub_type(Champ_Uniforme,rho);
354 bool cp_uniforme = sub_type(Champ_Uniforme,Cp);
355 bool is_rho_u = (sub_type(Op_Conv_VEF_base, op) && ref_cast(Op_Conv_VEF_base,op).vitesse().le_nom() == "rho_u") ? true : false;
356 const int nb_faces_bords = le_dom_vef.nb_faces_bord();
357 CDoubleArrView rho_face = static_cast<const DoubleVect&>(rho.valeurs()).view_ro();
358 CDoubleArrView Cp_face = static_cast<const DoubleVect&>(Cp.valeurs()).view_ro();
359 DoubleArrView flux_bords = static_cast<DoubleVect&>(flux_bords_).view_rw();
360 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nb_faces_bords, KOKKOS_LAMBDA(
361 const int face)
362 {
363 // si on est en QC temperature et si on a calcule div(rhou * T)
364 // il ne faut pas remultiplier par rho
365 flux_bords(face) *= (is_rho_u ? 1 : rho_face(rho_uniforme?0:face)) * Cp_face(cp_uniforme?0:face);
366 });
367 end_gpu_timer(__KERNEL_NAME__);
368 }
369
370 // On multiplie par rho si Navier Stokes incompressible
371 Nom nom_eqn = op.equation().que_suis_je();
372 if (nom_eqn.debute_par("Navier_Stokes") && pb.milieu().que_suis_je() == "Fluide_Incompressible")
373 {
374 const Champ_base& rho = op.equation().milieu().masse_volumique();
375 if (sub_type(Champ_Uniforme, rho))
376 {
377 double coef = rho.valeurs()(0, 0);
378 int nb_faces_bord = le_dom_vef.nb_faces_bord();
379 DoubleTabView flux_bords = flux_bords_.view_rw();
380
381 Kokkos::parallel_for(
382 start_gpu_timer(__KERNEL_NAME__),
383 range_2D({0,0}, {nb_faces_bord,nb_compo}),
384 KOKKOS_LAMBDA (int face, int k)
385 {
386 flux_bords(face, k) *= coef;
387 });
388 end_gpu_timer(__KERNEL_NAME__);
389 }
390 }
391}
392
393/*! @brief Impression des flux d'un operateur VEF aux faces (ie: diffusion, convection)
394 *
395 */
396int Op_VEF_Face::impr(Sortie& os, const Operateur_base& op) const
397{
398 const Domaine_VEF& le_dom_vef = ref_cast(Domaine_VEF, op.equation().domaine_dis());
399 const DoubleTab& flux_bords_ = op.flux_bords();
400 if (flux_bords_.nb_dim() != 2)
401 {
402 Cout << "L'impression des flux n'est pas codee pour l'operateur " << op.que_suis_je() << finl;
403 return 1;
404 }
405 if (controle_modifier_flux_ == 0)
406 if (max_abs_array(flux_bords_) != 0)
407 {
408 Cerr << op.que_suis_je() << " appelle Op_VEF_Face::impr sans avoir appeler Op_VEF_Face::modifier_flux, on arrete tout " << finl;
410 }
411 int nb_compo = flux_bords_.dimension(1);
412 const Probleme_base& pb = op.equation().probleme();
413 const Schema_Temps_base& sch = pb.schema_temps();
414 // On n'imprime les moments que si demande et si on traite l'operateur de diffusion de la vitesse
415 int impr_mom = 0;
416 if (le_dom_vef.domaine().moments_a_imprimer() && sub_type(Operateur_Diff_base, op) && op.equation().inconnue().le_nom() == "vitesse")
417 impr_mom = 1;
418
419 const int impr_sum = (le_dom_vef.domaine().bords_a_imprimer_sum().est_vide() ? 0 : 1);
420 const int impr_bord = (le_dom_vef.domaine().bords_a_imprimer().est_vide() ? 0 : 1);
421
422 // Calcul des moments
423 DoubleTab xgr;
424 if (impr_mom)
425 xgr = le_dom_vef.calculer_xgr();
426
427 // On parcours les frontieres pour sommer les flux par frontiere dans le tableau flux_bord
428 DoubleVect bilan(nb_compo);
429 bilan = 0;
430 int nb_cl = le_dom_vef.nb_front_Cl();
431 DoubleTrav flux_bords(4, nb_cl, nb_compo);
432 flux_bords = 0.;
433 /*
434 flux_bord(k) -> flux_bords(0,num_cl,k)
435 flux_bord_perio1(k) -> flux_bords(1,num_cl,k)
436 flux_bord_perio2(k) -> flux_bords(2,num_cl,k)
437 moment(k) -> flux_bords(3,num_cl,k)
438 */
439 for (int num_cl = 0; num_cl < nb_cl; num_cl++)
440 {
441 const Cond_lim& la_cl = op.equation().domaine_Cl_dis().les_conditions_limites(num_cl);
442 const Front_VF& frontiere_dis = ref_cast(Front_VF, la_cl->frontiere_dis());
443 int ndeb = frontiere_dis.num_premiere_face();
444 int nfin = ndeb + frontiere_dis.nb_faces();
445 int perio = (sub_type(Periodique,la_cl.valeur()) ? 1 : 0);
446 for (int face = ndeb; face < nfin; face++)
447 {
448 for (int k = 0; k < nb_compo; k++)
449 {
450 flux_bords(0, num_cl, k) += flux_bords_(face, k);
451 if (perio)
452 {
453 if (face < (ndeb + frontiere_dis.nb_faces() / 2))
454 flux_bords(1, num_cl, k) += flux_bords_(face, k);
455 else
456 flux_bords(2, num_cl, k) += flux_bords_(face, k);
457 }
458 }
459 if (impr_mom)
460 {
461 // Calcul du moment exerce par le fluide sur le bord (OM/\F)
462 if (Objet_U::dimension == 2)
463 flux_bords(3, num_cl, 0) += flux_bords_(face, 1) * xgr(face, 0) - flux_bords_(face, 0) * xgr(face, 1);
464 else
465 {
466 flux_bords(3, num_cl, 0) += flux_bords_(face, 2) * xgr(face, 1) - flux_bords_(face, 1) * xgr(face, 2);
467 flux_bords(3, num_cl, 1) += flux_bords_(face, 0) * xgr(face, 2) - flux_bords_(face, 2) * xgr(face, 0);
468 flux_bords(3, num_cl, 2) += flux_bords_(face, 1) * xgr(face, 0) - flux_bords_(face, 0) * xgr(face, 1);
469 }
470 }
471 } // fin for face
472 } // fin for num_cl
473
474 // On somme les contributions de chaque processeur
476
477 // Ecriture dans les fichiers
479 {
480 op.ouvrir_fichier(Flux, "", 1);
481 op.ouvrir_fichier(Flux_moment, "moment", impr_mom);
482 op.ouvrir_fichier(Flux_sum, "sum", impr_sum);
483
484 // Write time
485 Flux.add_col(sch.temps_courant());
486 if (impr_mom)
487 Flux_moment.add_col(sch.temps_courant());
488 if (impr_sum)
489 Flux_sum.add_col(sch.temps_courant());
490
491 // Write flux on boundaries
492 for (int num_cl = 0; num_cl < nb_cl; num_cl++)
493 {
494 const Frontiere_dis_base& la_fr = op.equation().domaine_Cl_dis().les_conditions_limites(num_cl)->frontiere_dis();
495 const Cond_lim& la_cl = op.equation().domaine_Cl_dis().les_conditions_limites(num_cl);
496 int perio = (sub_type(Periodique,la_cl.valeur()) ? 1 : 0);
497 for (int k = 0; k < nb_compo; k++)
498 {
499 if (perio)
500 {
501 Flux.add_col(flux_bords(1, num_cl, k));
502 Flux.add_col(flux_bords(2, num_cl, k));
503 }
504 else
505 Flux.add_col(flux_bords(0, num_cl, k));
506 if (impr_mom)
507 Flux_moment.add_col(flux_bords(3, num_cl, k));
508 if (le_dom_vef.domaine().bords_a_imprimer_sum().contient(la_fr.le_nom()))
509 Flux_sum.add_col(flux_bords(0, num_cl, k));
510
511 // On somme les flux de toutes les frontieres pour mettre dans le tableau bilan
512 bilan(k) += flux_bords(0, num_cl, k);
513 }
514 }
515
516 // On imprime les bilans et on va a la ligne
517 for (int k = 0; k < nb_compo; k++)
518 Flux.add_col(bilan(k));
519 Flux << finl;
520 if (impr_mom)
521 Flux_moment << finl;
522 if (impr_sum)
523 Flux_sum << finl;
524 }
525
526 const LIST(Nom) &Liste_bords_a_imprimer = le_dom_vef.domaine().bords_a_imprimer();
527 if (!Liste_bords_a_imprimer.est_vide())
528 {
529 EcrFicPartage Flux_face;
530 op.ouvrir_fichier_partage(Flux_face, "", impr_bord);
531 // Impression sur chaque face si demande
532 for (int num_cl = 0; num_cl < nb_cl; num_cl++)
533 {
534 const Frontiere_dis_base& la_fr = op.equation().domaine_Cl_dis().les_conditions_limites(num_cl)->frontiere_dis();
535 const Cond_lim& la_cl = op.equation().domaine_Cl_dis().les_conditions_limites(num_cl);
536 const Front_VF& frontiere_dis = ref_cast(Front_VF, la_cl->frontiere_dis());
537 int ndeb = frontiere_dis.num_premiere_face();
538 int nfin = ndeb + frontiere_dis.nb_faces();
539 // Impression sur chaque face
540 if (Liste_bords_a_imprimer.contient(la_fr.le_nom()))
541 {
542 Flux_face << "# Flux par face sur " << la_fr.le_nom() << " au temps ";
543 sch.imprimer_temps_courant(Flux_face);
544 Flux_face << " : " << finl;
545 const DoubleTab& xv = le_dom_vef.xv();
546 for (int face = ndeb; face < nfin; face++)
547 {
548 if (Objet_U::dimension == 2)
549 Flux_face << "# Face a x= " << xv(face, 0) << " y= " << xv(face, 1);
550 else if (Objet_U::dimension == 3)
551 Flux_face << "# Face a x= " << xv(face, 0) << " y= " << xv(face, 1) << " z= " << xv(face, 2);
552 for (int k = 0; k < nb_compo; k++)
553 Flux_face << " surface_face(m2)= " << le_dom_vef.face_surfaces(face) << " flux_par_surface(W/m2)= " << flux_bords_(face, k) / le_dom_vef.face_surfaces(face) << " flux(W)= "
554 << flux_bords_(face, k);
555 Flux_face << finl;
556 }
557 Flux_face.syncfile();
558 }
559 }
560 }
561 return 1;
562}
563
564/////////////////////////////////////////
565// Methode pour l'implicite
566/////////////////////////////////////////
567void modif_matrice_pour_periodique_avant_contribuer(Matrice_Morse& matrice_morse, const Equation_base& eqn)
568{
569 const int nb_comp = eqn.inconnue().valeurs().line_size();
570 const Domaine_Cl_dis_base& domaine_Cl_VEF = eqn.domaine_Cl_dis();
571 const Domaine_VF& domaine_VEF = ref_cast(Domaine_VF, eqn.domaine_dis());
572 int nb_bords = domaine_VEF.nb_front_Cl();
573 int nb_faces_elem = domaine_VEF.elem_faces().dimension(1);
574 for (int n_bord = 0; n_bord < nb_bords; n_bord++)
575 {
576 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
577 if (sub_type(Periodique, la_cl.valeur()))
578 {
579 const Periodique& la_cl_perio = ref_cast(Periodique, la_cl.valeur());
580 // on ne parcourt que la moitie des faces periodiques
581 // on copiera a la fin le resultat dans la face associe..
582 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
583 int num1 = le_bord.num_premiere_face();
584 int num2 = num1 + le_bord.nb_faces() / 2;
585 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
586 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
587 CIntArrView face_associee = la_cl_perio.face_associee().view_ro();
588 Matrice_Morse_View matrice;
589 matrice.set(matrice_morse);
590 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(num1, num2),
591 KOKKOS_LAMBDA(const int num_face)
592 {
593 for (int dir = 0; dir < 2; dir++)
594 {
595 int elem1 = face_voisins(num_face, dir);
596 int fac_asso = face_associee(num_face - num1) + num1;
597 for (int i = 0; i < nb_faces_elem; i++)
598 {
599 int j = elem_faces(elem1, i);
600 for (int nc = 0; nc < nb_comp; nc++)
601 {
602 int n0 = num_face * nb_comp + nc;
603 int n0perio = fac_asso * nb_comp + nc;
604 if (((j == num_face) || (j == fac_asso)))
605 {
606 if (dir == 0)
607 {
608 assert(matrice(n0, n0perio) == 0);
609 assert(matrice(n0perio, n0) == 0);
610 assert(matrice(n0, n0) == matrice(n0perio, n0perio));
611 double coeff = (matrice(n0, n0)) / 2.;
612 matrice.store(n0, n0, coeff);
613 matrice.store(n0perio, n0perio, coeff);
614 }
615 }
616 else
617 {
618 for (int nc2 = 0; nc2 < nb_comp; nc2++)
619 {
620 int j20 = j * nb_comp + nc2;
621 assert(matrice(n0, j20) == matrice(n0perio, j20));
622 double coeff = (matrice(n0, j20) / 2.);
623 matrice.store(n0, j20, coeff);
624 matrice.store(n0perio, j20, coeff);
625 }
626 }
627 }
628 }
629 }
630 });
631 end_gpu_timer(__KERNEL_NAME__);
632 }
633 // matrice.imprimer(Cerr);
634 }
635}
636
637void modif_matrice_pour_periodique_apres_contribuer(Matrice_Morse& matrice_morse, const Equation_base& eqn)
638{
639 const int nb_comp = eqn.inconnue().valeurs().line_size();
640 const Domaine_Cl_dis_base& domaine_Cl_VEF = eqn.domaine_Cl_dis();
641 const Domaine_VF& domaine_VEF = ref_cast(Domaine_VF, eqn.domaine_dis());
642 int nb_bords = domaine_VEF.nb_front_Cl();
643 int nb_faces_elem = domaine_VEF.elem_faces().dimension(1);
644 for (int n_bord = 0; n_bord < nb_bords; n_bord++)
645 {
646 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
647 if (sub_type(Periodique, la_cl.valeur()))
648 {
649 const Periodique& la_cl_perio = ref_cast(Periodique, la_cl.valeur());
650 // on ne parcourt que la moitie des faces periodiques
651 // on copiera a la fin le resultat dans la face associe..
652 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
653 int num1 = le_bord.num_premiere_face();
654 int num2 = num1 + le_bord.nb_faces() / 2;
655 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
656 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
657 CIntArrView face_associee = la_cl_perio.face_associee().view_ro();
658 Matrice_Morse_View matrice;
659 matrice.set(matrice_morse);
660 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(num1, num2),
661 KOKKOS_LAMBDA(const int num_face)
662 {
663 for (int dir = 0; dir < 2; dir++)
664 {
665 int elem1 = face_voisins(num_face, dir);
666 int fac_asso = face_associee(num_face - num1) + num1;
667 for (int i = 0; i < nb_faces_elem; i++)
668 {
669 int j = elem_faces(elem1, i);
670 //if (j!=num_face)
671 for (int nc = 0; nc < nb_comp; nc++)
672 {
673 int n0 = num_face * nb_comp + nc;
674 // int j0=j*nb_comp+nc;
675 int n0perio = fac_asso * nb_comp + nc;
676 if (((j == num_face) || (j == fac_asso)))
677 {
678 if (dir == 0)
679 {
680 for (int nc2 = 0; nc2 < nb_comp; nc2++)
681 {
682 int j0 = num_face * nb_comp + nc2;
683 int j0perio = fac_asso * nb_comp + nc2;
684 matrice.atomic_add(n0, j0, matrice(n0, j0perio));
685 matrice.store(n0, j0perio, 0);
686 matrice.atomic_add(n0perio, j0perio, matrice(n0perio, j0));
687 matrice.store(n0perio, j0, 0);
688 double coeff = (matrice(n0, j0) +
689 matrice(n0perio, j0perio));
690 matrice.store(n0, j0, coeff);
691 if (nc != nc2)
692 {
693 matrice.store(n0perio, j0, coeff);
694 matrice.store(n0perio, j0perio, 0);
695 }
696 else
697 matrice.store(n0perio, j0perio, coeff);
698 }
699 }
700 }
701 else
702 {
703 for (int nc2 = 0; nc2 < nb_comp; nc2++)
704 {
705 int j20 = j * nb_comp + nc2;
706 double coeff = (matrice(n0, j20) + matrice(n0perio, j20));
707 matrice.store(n0, j20, coeff);
708 matrice.store(n0perio, j20, coeff);
709 }
710 }
711 }
712 }
713 }
714 });
715 end_gpu_timer(__KERNEL_NAME__);
716 }
717 // matrice.imprimer(Cerr);
718 }
719}
720
721/*! @brief divise les coefficients sur les ligne des faces periodiques par 2 en prevision de l'application modifier_matrice_pour_periodique_apres_contribuer qui va sommer les 2 lignes des faces periodiques associees
722 *
723 */
724
726{
727 // si matrice_morse_diag pas de contribution n0 n0perio
728 if (sub_type(Matrice_Morse_Diag, matrice))
729 return;
730 modif_matrice_pour_periodique_avant_contribuer(matrice, eqn);
731}
732/*! @brief Somme les 2 lignes des faces periodiques associees permet de calculer dans le code sans se poser de question pour retrouver la face_associee
733 *
734 * on ne parcourt que la moitiee des faces periodiques dans contribuer_a_avec (en general).
735 *
736 */
737
739{
740 // si matrice_morse_diag pas de contribution n0 n0perio
741 if (sub_type(Matrice_Morse_Diag, matrice))
742 return;
743
744 modif_matrice_pour_periodique_apres_contribuer(matrice, eqn);
745
746 // verification que la matrice est bien periodique
747#ifndef NDEBUG
748
749 const int nb_comp = eqn.inconnue().valeurs().line_size();
750
751 const Domaine_Cl_dis_base& domaine_Cl_VEF = eqn.domaine_Cl_dis();
752 const Domaine_VF& domaine_VEF = ref_cast(Domaine_VF, eqn.domaine_dis());
753 int nb_bords = domaine_VEF.nb_front_Cl();
754
755 const auto& tab1 = matrice.get_tab1();
756 const auto& tab2 = matrice.get_tab2();
757
758 for (int n_bord = 0; n_bord < nb_bords; n_bord++)
759 {
760 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
761 const Front_VF& le_bord = ref_cast(Front_VF, la_cl->frontiere_dis());
762 int num1 = le_bord.num_premiere_face();
763 // int num2 = num1 + le_bord.nb_faces();
764
765 if (sub_type(Periodique, la_cl.valeur()))
766 {
767 const Periodique& la_cl_perio = ref_cast(Periodique, la_cl.valeur());
768 int fac_asso;
769 // on ne parcourt que la moitie des faces periodiques
770 // on copiera a la fin le resultat dans la face associe..
771 int num2 = num1 + le_bord.nb_faces() / 2;
772 for (int num_face = num1; num_face < num2; num_face++)
773 for (int nc = 0; nc < nb_comp; nc++)
774 {
775 fac_asso = la_cl_perio.face_associee(num_face - num1) + num1;
776 int n0 = num_face * nb_comp + nc;
777 int n0perio = fac_asso * nb_comp + nc;
778 // on verifie que les 2 lignes sont identiques ( sauf la case diagonale qui n'est pas au meme endroit)
779 for (auto j = tab1[n0] - 1; j < tab1[n0 + 1] - 1; j++)
780 {
781 int c = tab2[j] - 1;
782 if ((c != n0) && (c != n0perio))
783 {
784 double test = matrice(n0, c) - matrice(n0perio, c);
785 if (test != 0)
786 {
787 Cerr << "Pb matrice non periodique face" << num_face << " composante " << nc << " colonne " << c << finl;
788 Cerr << " diff " << test << " coef1 " << matrice(n0, c) << " coef2 " << matrice(n0perio, c) << finl;
790 }
791 }
792 }
793 if ((matrice(n0, n0perio) != 0) || (matrice(n0perio, n0) != 0))
794 {
795 Cerr << "Pb matrice non periodique face" << num_face << " composante " << nc << finl;
796 Cerr << " coef non nul" << matrice(n0, n0perio) << " " << matrice(n0perio, n0) << finl;
798 }
799 if (matrice(n0, n0) != matrice(n0perio, n0perio))
800 {
801 double test = matrice(n0, n0perio) - matrice(n0perio, n0);
802 Cerr << "Pb matrice non periodique face" << num_face << " composante " << nc << finl;
803 Cerr << " diff " << test << " coef different " << matrice(n0, n0) << " " << matrice(n0perio, n0perio) << finl;
805 }
806 }
807 }
808 }
809
810 /*
811 Matrice_Morse es(matrice);
812 modif_matrice_pour_periodique_avant_contribuer(es,eqn);
813 modif_matrice_pour_periodique_apres_contribuer(es,eqn);
814 es.coeff_-=(matrice.coeff_);
815 Cerr<<" erreur apres modifier_matrice_pour_periodique_apres_contribuer"<< mp_max_abs_vect(es.coeff_)<<finl;
816 assert(mp_max_abs_vect(es.coeff_)<1e-9);
817 */
818
819#endif
820}
classe Champ_Don_base classe de base des Champs donnes (non calcules)
DoubleTab & valeurs() override
Surcharge Champ_base::valeurs() Renvoie le tableau des valeurs.
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
virtual DoubleTab & valeurs()=0
classe Champ_Uniforme Represente un champ constant dans l'espace et dans le temps.
classe Champ_base Cette classe est la base de la hierarchie des champs.
Definition Champ_base.h:43
classe Cond_lim_base Classe de base pour la hierarchie des classes qui representent les differentes c...
virtual Frontiere_dis_base & frontiere_dis()
Renvoie la frontiere discretisee a laquelle les conditions aux limites s'appliquent.
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
Classe Dirichlet_homogene Cette classe est la classe de base de la hierarchie des conditions aux limi...
classe Dirichlet Cette classe est la classe de base de la hierarchie des conditions aux limites de ty...
Definition Dirichlet.h:31
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
classe Domaine_Cl_dis_base Les objets Domaine_Cl_dis_base representent les conditions aux limites
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
class Domaine_VEF
Definition Domaine_VEF.h:54
class Domaine_VF
Definition Domaine_VF.h:44
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
int nb_faces_tot() const
renvoie le nombre total de faces.
Definition Domaine_VF.h:481
virtual double face_normales(int face, int comp) const
Definition Domaine_VF.h:47
double xv(int num_face, int k) const
Definition Domaine_VF.h:76
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
DoubleTab calculer_xgr() const
calcul le tableau xgr pour le calcul des moments des forces aux bords :
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
int moments_a_imprimer() const
int nb_front_Cl() const
const Domaine & domaine() const
Sortie & syncfile() override
Provoque l'ecriture sur disque des donnees accumulees sur les differents processeurs depuis le dernie...
classe Equation_base Le role d'une equation est le calcul d'un ou plusieurs champs....
virtual const Milieu_base & milieu() const =0
virtual const Champ_Inc_base & inconnue() const =0
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Renvoie le domaine des conditions aux limite discretisee associee a l'equation.
Probleme_base & probleme()
Renvoie le probleme associe a l'equation.
Domaine_dis_base & domaine_dis()
Renvoie le domaine discretise associe a l'equation.
const Nom & le_nom() const override
Renvoie le nom du champ.
virtual Nature_du_champ nature_du_champ() const
Definition Field_base.h:77
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 Frontiere_dis_base Classe representant une frontiere discretisee.
const Nom & le_nom() const override
Renvoie le nom de la frontiere geometrique.
Classe Matrice_Morse_Diag Represente une matrice M (creuse) symetrique stockee au format Morse.
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
auto & get_set_tab2()
const auto & get_tab2() const
void dimensionner(int n, _SIZE_ nnz)
Size the matrix with n lines and n columns and nnz zero-values coefficients.
const auto & get_tab1() const
auto & get_set_coeff()
int nb_colonnes() const override
Return local number of columns (=size on the current proc).
auto & get_set_tab1()
virtual const Champ_Don_base & capacite_calorifique() const
Renvoie la capacite calorifique du milieu.
virtual const Champ_base & masse_volumique() const
Renvoie la masse volumique du milieu.
const Equation_base & equation() const
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
virtual int debute_par(const char *const n) const
Definition Nom.cpp:319
static int dimension
Definition Objet_U.h:99
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
class Op_Conv_VEF_base
void modifier_matrice_pour_periodique_apres_contribuer(Matrice_Morse &matrice, const Equation_base &) const
Somme les 2 lignes des faces periodiques associees permet de calculer dans le code sans se poser de q...
void dimensionner(const Domaine_VEF &, const Domaine_Cl_VEF &, Matrice_Morse &) const
Dimensionnement de la matrice qui devra recevoir les coefficients provenant de la convection,...
int impr(Sortie &, const Operateur_base &) const
Impression des flux d'un operateur VEF aux faces (ie: diffusion, convection).
void modifier_matrice_pour_periodique_avant_contribuer(Matrice_Morse &matrice, const Equation_base &) const
divise les coefficients sur les ligne des faces periodiques par 2 en prevision de l'application modif...
void modifier_flux(const Operateur_base &) const
void modifier_pour_Cl(const Domaine_VEF &, const Domaine_Cl_VEF &, Matrice_Morse &, DoubleTab &) const
Modification des coef de la matrice et du second membre pour les conditions de Dirichlet.
classe Operateur_Diff_base Cette classe est la base de la hierarchie des operateurs representant
classe Operateur_base Classe est la base de la hierarchie des objets representant un
void ouvrir_fichier_partage(EcrFicPartage &, const Nom &, const int flag=1) const
Ouverture/creation d'un fichier d'impression d'un operateur A surcharger dans les classes derivees.
DoubleTab & flux_bords()
void ouvrir_fichier(SFichier &os, const Nom &, const int flag=1) const
Ouverture/creation d'un fichier d'impression d'un operateur A surcharger dans les classes derivees.
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 Probleme_base C'est un Probleme_U qui n'est pas un couplage.
virtual const Milieu_base & milieu() const
Renvoie le milieu physique associe au probleme.
const Schema_Temps_base & schema_temps() const
Renvoie le schema en temps associe au probleme.
static void mp_sum_for_each_item(TRUSTArray< _TYPE_ > &x, int n=-1)
Definition Process.cpp:193
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
Definition Process.cpp:86
class Schema_Temps_base
double temps_courant() const
Renvoie le temps courant.
void imprimer_temps_courant(SFichier &) const
Classe de base des flux de sortie.
Definition Sortie.h:52
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
int nb_dim() const
Definition TRUSTTab.h:199
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, View< _TYPE_, _SHAPE_ > > view_rw()
Definition TRUSTTab.h:291
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
int line_size() const
Definition TRUSTVect.tpp:67