TrioCFD 1.9.9_beta
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 Dimensioning of the matrix that will receive the coefficients from convection and diffusion for the face-based case.
38 *
39 * This matrix has a Morse matrix structure.
40 * We start by computing the sizes of arrays tab1 and 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 // Dimensioning of the matrix that will receive the coefficients from
47 // convection and diffusion for the face-based case.
48 // This matrix has a Morse matrix structure.
49 // We start by computing the sizes of arrays tab1 and tab2.
50 // To do so, we need to find the neighbouring faces of the current face.
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 // For each face, we associate an integer array and a list of reals:
66 // voisines[i] = {j such that j>i and M(i,j) is non-zero }
67
68 // IntVect rang_voisin(nfin*nb_comp);
69 IntTrav rang_voisin(nfin * nb_comp);
70 rang_voisin = nb_comp;
71 // Process all 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 // The neighbouring faces of num_face have now been counted;
100 // dimension tab1 and tab2 to the number of 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 // Process all 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 Modify the matrix coefficients and the right-hand side for Dirichlet boundary conditions.
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 // Dimensioning of the matrix that will receive the coefficients from
171 // convection and diffusion for the face-based case.
172 // This matrix has a Morse matrix structure.
173 // We start by computing the sizes of arrays tab1 and 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 // for the neighbours
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 // for the right-hand side
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()); // Dimensioned to the maximum size
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 // Start by recomputing secmem=secmem-A*present to allow modifying A (and project at the same time)
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 // subtract secmem.n * n
257 for (int comp = 0; comp < nb_comp; comp++)
258 tab_secmem(face, comp) -= somme_b * normale[comp];
259
260 // the same diagonal must be set everywhere, take the average
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 // zero all off-diagonal coefficients of the block
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 // for the off-diagonal blocks ensure that 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 // the coefficient j must exist on all nb_comp rows
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 // subtract sum*ni
306
307 for (int comp = 0; comp < nb_comp; comp++)
308 // only modify coefficients not involving 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 // Finally recompute secmem=secmem+A*champ_inconnue (A has been heavily modified)
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 // subtract 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 // Multiply the boundary flux by rho*Cp unless it is a diffusion operator with conductivity as the field
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 // if in QC temperature mode and div(rhou * T) has been computed,
364 // do not multiply by rho again
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 // Multiply by rho if incompressible Navier-Stokes
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 Print the face fluxes of a VEF operator (e.g. 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 << "Printing of fluxes is not implemented for the operator " << 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 // Print moments only if requested and if treating the velocity diffusion operator
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 // Compute moments
423 DoubleTab xgr;
424 if (impr_mom)
425 xgr = le_dom_vef.calculer_xgr();
426
427 // Loop over the boundaries to sum the fluxes per boundary into the flux_bord array
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 // Compute the moment exerted by the fluid on the boundary (OM x 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 } // end for face
472 } // end for num_cl
473
474 // Sum the contributions from each processor
476
477 // Write to files
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 // Sum the fluxes from all boundaries into the bilan array
512 bilan(k) += flux_bords(0, num_cl, k);
513 }
514 }
515
516 // Print the balance values and go to a new line
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 // Print per face if requested
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 // Print per 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// Method for the implicit scheme
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 // only iterate over half the periodic faces;
581 // the result will be copied to the associated face at the end
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 // only iterate over half the periodic faces;
651 // the result will be copied to the associated face at the end
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 Divides the coefficients on the periodic face rows by 2 in preparation for applying modifier_matrice_pour_periodique_apres_contribuer, which will sum the 2 rows of the associated periodic faces.
722 *
723 */
724
726{
727 // if matrice_morse_diag, no 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 Sums the 2 rows of the associated periodic faces, allowing computations in the code without needing to find the associated face.
733 *
734 * Only half the periodic faces are iterated over in contribuer_a_avec (in general).
735 *
736 */
737
739{
740 // if matrice_morse_diag, no 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 // verify that the matrix is properly periodic
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 // only iterate over half the periodic faces;
770 // the result will be copied to the associated face at the end
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 // verify that the 2 rows are identical (except for the diagonal entry which is not in the same position)
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 non-periodic matrix face" << num_face << " component " << nc << " column " << 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 non-periodic matrix face" << num_face << " component " << nc << finl;
796 Cerr << " non-zero coef" << 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 non-periodic matrix face" << num_face << " component " << nc << finl;
803 Cerr << " diff " << test << " differing coef " << 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<<" error after 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}
class Champ_Don_base base class of Given Fields (not calculated)
DoubleTab & valeurs() override
Overrides Champ_base::valeurs() Returns the array of values.
DoubleTab & valeurs() override
Returns the array of field values at the current time.
virtual DoubleTab & valeurs()=0
Champ_Uniforme Represents a field that is constant in space and time.
class Champ_base This class is the base of the fields hierarchy.
Definition Champ_base.h:43
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
class Conds_lim This class represents a vector of boundary conditions.
Definition Conds_lim.h:32
Classe Dirichlet_homogene This class is the base class of the hierarchy of homogeneous Dirichlet-type...
Dirichlet This class is the base class of the hierarchy of Dirichlet-type boundary conditions.
Definition Dirichlet.h:31
int nb_faces_elem(int=0) const
Returns the number of faces of type i of the geometric elements that make up the domain.
Definition Domaine.h:484
class Domaine_Cl_dis_base Domaine_Cl_dis_base objects represent discretized boundary conditions
const Cond_lim & les_conditions_limites(int) const
Returns the i-th boundary condition.
class Domaine_VEF
Definition Domaine_VEF.h:53
class Domaine_VF
Definition Domaine_VF.h:44
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
int nb_faces_tot() const
Returns the total number of 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
Returns the index of the i-th face of element num_elem; the face numbering convention is.
Definition Domaine_VF.h:542
DoubleTab calculer_xgr() const
Computes the xgr array for the computation of moments of forces at boundaries.
int face_voisins(int num_face, int i) const
Returns the neighbouring element of num_face in direction i.
Definition Domaine_VF.h:418
int nb_faces_bord() const
Returns the number of faces on which boundary conditions are applied:
Definition Domaine_VF.h:512
int moments_a_imprimer() const
int nb_front_Cl() const
const Domaine & domaine() const
Sortie & syncfile() override
Triggers writing to disk of the data accumulated on the different processors since the last call to s...
class Equation_base The role of an equation is the calculation of one or more fields....
virtual const Milieu_base & milieu() const =0
virtual const Champ_Inc_base & inconnue() const =0
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Returns the discretized boundary condition domain associated with the equation.
Probleme_base & probleme()
Returns the problem associated with the equation.
Domaine_dis_base & domaine_dis()
Returns the discretized domain associated with the equation.
const Nom & le_nom() const override
Returns the name of the field.
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
class Frontiere_dis_base Class representing a discretized boundary.
const Nom & le_nom() const override
Returns the name of the geometric boundary.
Matrice_Morse_Diag class - Represents a sparse symmetric matrix M stored in Morse format.
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
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
Returns the heat capacity of the medium (const version).
virtual const Champ_base & masse_volumique() const
Returns the mass density of the medium (const version).
const Equation_base & equation() const
Returns the reference to the equation pointed to by MorEqn::mon_equation.
Definition MorEqn.h:62
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
virtual int debute_par(const char *const n) const
Definition Nom.cpp:314
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
class Op_Conv_VEF_base
void modifier_matrice_pour_periodique_apres_contribuer(Matrice_Morse &matrice, const Equation_base &) const
Sums the 2 rows of the associated periodic faces, allowing computations in the code without needing t...
void dimensionner(const Domaine_VEF &, const Domaine_Cl_VEF &, Matrice_Morse &) const
Dimensioning of the matrix that will receive the coefficients from convection and diffusion for the f...
int impr(Sortie &, const Operateur_base &) const
Print the face fluxes of a VEF operator (e.g. diffusion, convection).
void modifier_matrice_pour_periodique_avant_contribuer(Matrice_Morse &matrice, const Equation_base &) const
Divides the coefficients on the periodic face rows by 2 in preparation for applying modifier_matrice_...
void modifier_flux(const Operateur_base &) const
void modifier_pour_Cl(const Domaine_VEF &, const Domaine_Cl_VEF &, Matrice_Morse &, DoubleTab &) const
Modify the matrix coefficients and the right-hand side for Dirichlet boundary conditions.
Operateur_Diff_base This class is the base of the hierarchy of operators representing.
class Operateur_base This class is the base of the hierarchy of objects representing an
void ouvrir_fichier_partage(EcrFicPartage &, const Nom &, const int flag=1) const
Opening/creation of a shared file for printing an operator. To override in derived classes.
DoubleTab & flux_bords()
void ouvrir_fichier(SFichier &os, const Nom &, const int flag=1) const
Opening/creation of a file for printing an operator. To override in derived classes.
class Periodique This class represents a periodic boundary condition.
Definition Periodique.h:31
int face_associee(int i) const
Definition Periodique.h:35
class Probleme_base It is a Probleme_U that is not a coupling.
virtual const Milieu_base & milieu() const
Returns the physical medium associated with the problem (const version).
const Schema_Temps_base & schema_temps() const
Returns the time scheme associated with the problem.
static void mp_sum_for_each_item(TRUSTArray< _TYPE_ > &x, int n=-1)
Definition Process.cpp:194
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
static int je_suis_maitre()
Returns 1 if on the master processor of the current group (i.e. me() == 0), 0 otherwise.
Definition Process.cpp:82
class Schema_Temps_base
double temps_courant() const
Returns the current time.
void imprimer_temps_courant(SFichier &) const
Base class for output streams.
Definition Sortie.h:52
Symetrie On symmetry faces, the following properties hold:
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