TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Assembleur_P_VDF.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 <Assembleur_P_VDF.h>
17#include <Domaine_Cl_VDF.h>
18#include <Domaine_VDF.h>
19#include <Periodique.h>
20#include <Symetrie.h>
21#include <Neumann_sortie_libre.h>
22#include <Dirichlet_entree_fluide_leaves.h>
23#include <Dirichlet_paroi_fixe.h>
24#include <Dirichlet_paroi_defilante.h>
25#include <Matrice_Bloc.h>
26#include <Option_VDF.h>
27#include <Champ_Fonc_Face_VDF.h>
28#include <Matrice_Morse_Sym.h>
29#include <Milieu_base.h>
30#include <Matrix_tools.h>
31#include <Pb_Multiphase.h>
32
33Implemente_instanciable_sans_constructeur(Assembleur_P_VDF,"Assembleur_P_VDF",Assembleur_base);
34
35Assembleur_P_VDF::Assembleur_P_VDF() : has_P_ref(0) { }
36
38{
39 return s << que_suis_je() << " " << le_nom() ;
40}
41
43{
45}
46
47/*! @brief Remplit le tableau faces avec la liste des indices des faces periodiques dans le tableau faces_voisins.
48 *
49 * Chaque face periodique figure deux fois
50 * dans faces_voisins (a chaque face correspond la face opposee). On ne
51 * met dans le tableau faces que celle des deux qui a l'indice le + petit
52 * dans la liste des faces de chaque bord periodique.
53 * Valeur de retour:
54 * nombre de faces periodiques (egal a la taille du tableau faces).
55 *
56 */
58{
59 // On commence par surestimer largement la taille du tableau :
60 // nombre de faces de bord
61 const int nb_faces_bord = le_dom_VDF->nb_faces_bord();
62 faces.resize_array(nb_faces_bord);
63
64 // Recherche des faces periodiques dans les conditions aux limites:
65 const Conds_lim& les_cl = le_dom_Cl_VDF->les_conditions_limites();
66 const int nb_cl = les_cl.size();
67 int nb_faces_periodiques = 0;
68 for (int num_cl = 0; num_cl < nb_cl; num_cl++)
69 {
70 const Cond_lim_base& la_cl = les_cl[num_cl].valeur();
71 // Selectionne uniquement les conditions Periodique
72 if ( ! sub_type(Periodique,la_cl))
73 continue;
74 const Periodique& la_cl_perio = ref_cast(Periodique, la_cl);
75 const Front_VF& frontiere = ref_cast(Front_VF, la_cl.frontiere_dis());
76 const int nb_faces_cl = frontiere.nb_faces();
77 const int num_premiere_face = frontiere.num_premiere_face();
78 for (int i = 0; i < nb_faces_cl; i++)
79 {
80 // Numero de la face opposee dans le tableau des faces du bord:
81 const int face_associee = la_cl_perio.face_associee(i);
82 if (face_associee > i)
83 {
84 const int num_face_global = num_premiere_face + i;
85 faces[nb_faces_periodiques] = num_face_global;
86 nb_faces_periodiques++;
87 }
88 }
89 }
90
91 // Taille finale du tableau faces
92 faces.resize_array(nb_faces_periodiques);
93 return nb_faces_periodiques;
94}
95
96/*! @brief Determine les elements non nuls de la matrice et prepare le stockage.
97 *
98 * Matrice creuse de taille nb_elements (lignes) * nb_elem_tot (colonnes)
99 * Codee comme une matrice bloc composee de deux matrices morse:
100 * * Matrice carree symetrique nb_elements * nb_elements
101 * (contient les termes M(i,j) ou i et j sont des numeros d'elements reels)
102 * * Matrice rectangle nb_elements * (nb_elem_tot - nb_elem)
103 * (contient les termes M(i,j) ou i est reel et j est virtuel
104 *
105 */
107{
108 int i;
109 const Domaine_VDF& domaine_vdf = le_dom_VDF.valeur();
110 const IntTab& face_voisins = domaine_vdf.face_voisins();
111
112 // Comptage du nombre total d'elements non nuls:
113 // matrice carree : nombre de faces internes / 2 + nb_elem + nbfaces periodiques
114 // (chaque face interne donne un coef, et on a un element
115 // diagonal et chaque face periodique donne aussi un coef)
116 // matrice rectangle : nombre de faces de joint
117
118
119 // Premiere etape : comptage du nombre d'elements non nuls sur chaque ligne
120 // Pour chaque ligne de la matrice carree, nombre d'elements non nuls
121 const int nb_elem = domaine_vdf.nb_elem();
122 const int nb_elem_tot = domaine_vdf.nb_elem_tot();
123 ArrOfInt carre_nb_non_zero(nb_elem);
124 // Idem pour le rectangle
125 ArrOfInt rect_nb_non_zero(nb_elem);
126 // Il y a l'element sur la diagonale :
127 carre_nb_non_zero = 1;
128 rect_nb_non_zero = 0;
129 int carre_nb_non_zero_tot = nb_elem;
130 int rect_nb_non_zero_tot = 0;
131
132 // Plus un element non nul pour chaque face interne et chaque face periodique
133 // (matrice symetrique, on ne stocke que l'element m(line,col) avec col>line)
134
135 ArrOfInt liste_faces_perio;
136 const int nb_faces_periodiques = liste_faces_periodiques(liste_faces_perio);
137 const int nb_faces_internes = domaine_vdf.nb_faces_internes();
138 const int premiere_face_interne = domaine_vdf.premiere_face_int();
139 for (i = 0; i < nb_faces_internes + nb_faces_periodiques; i++)
140 {
141 int face;
142 if (i < nb_faces_internes) // Astuce pour boucler sur les faces internes et periodiques
143 face = premiere_face_interne + i;
144 else
145 face = liste_faces_perio[i - nb_faces_internes];
146
147 int elem0 = face_voisins(face,0);
148 int elem1 = face_voisins(face,1);
149 if (elem0 > elem1)
150 {
151 int tmp = elem1;
152 elem1 = elem0;
153 elem0 = tmp;
154 }
155 if (elem0 < nb_elem) // elem0 est reel
156 {
157 if (elem1 < nb_elem) // elem1 reel
158 {
159 carre_nb_non_zero[elem0] ++;
160 carre_nb_non_zero_tot ++;
161 }
162 else // elem1 virtuel
163 {
164 rect_nb_non_zero[elem0] ++;
165 rect_nb_non_zero_tot ++;
166 }
167 }
168 }
169
170 // Typage et dimensionnement de la matrice de pression
171 la_matrice.typer("Matrice_Bloc");
172 Matrice_Bloc& matrice =ref_cast(Matrice_Bloc , la_matrice.valeur());
173 matrice.dimensionner(1,2);
174 matrice.get_bloc(0,0).typer("Matrice_Morse_Sym");
175 matrice.get_bloc(0,1).typer("Matrice_Morse");
176 Matrice_Morse_Sym& carre = ref_cast(Matrice_Morse_Sym ,matrice.get_bloc(0,0).valeur());
177 Matrice_Morse& rect = ref_cast(Matrice_Morse , matrice.get_bloc(0,1).valeur());
178
179 carre.dimensionner(nb_elem, carre_nb_non_zero_tot);
180 rect.dimensionner(nb_elem, nb_elem_tot - nb_elem, rect_nb_non_zero_tot);
181
182 {
183 const int nb_faces_bord = domaine_vdf.nb_faces_bord();
184 les_coeff_pression.resize_array(nb_faces_bord);
185 }
186 auto& carre_tab1 = carre.get_set_tab1();
187 auto& rect_tab1 = rect.get_set_tab1();
188
189 // Matrice creuse, stockage morse avec des indices fortran:
190 // lignes numerotees 1..n, colonnes 1..m
191 // Le k-ieme coefficient non nul de la ligne i (1<=i<=n) est (avec 1<=k)
192 // M(i,j) = coeff_[tab1_[k]] en fortran
193 // M(i,j) = coeff_[tab1_[k-1]-1] en C
194 // Le numero j de la colonne ou se trouve ce coefficient (1<=j<=m) est
195 // j = tab2_[tab1_[k]] en fortran
196 // j = tab2_[tab1_[k-1]-1] en C
197 //
198 // Calcul de l'indice du premier coefficient de la ligne i
199 // dans le tableau d'indices morse des deux matrices (tab1_)
200 {
201 int indice = 1; // tab1_ contient un indice fortran (1er element en 1)
202 for (i = 0; i < nb_elem; i++)
203 {
204 carre_tab1[i] = indice;
205 indice += carre_nb_non_zero[i];
206 }
207 carre_tab1[i] = indice;
208
209 indice = 1;
210 for (i = 0; i < nb_elem; i++)
211 {
212 rect_tab1[i] = indice;
213 indice += rect_nb_non_zero[i];
214 }
215 rect_tab1[i] = indice;
216 }
217
218 // Deuxieme etape : remplissage de tab2_ = numero de la colonne de chaque
219 // terme non nul de la matrice
220 auto& carre_tab2 = carre.get_set_tab2();
221 auto& rect_tab2 = rect.get_set_tab2();
222
223 carre_tab2 = -1;
224 rect_tab2 = -1;
225
226 // Terme diagonal:
227 for (i = 1; i <= nb_elem; i++)
228 carre_tab2[carre_tab1[i-1]-1] = i; // Indice fortran 1<=i<=nb_elem
229
230 carre_nb_non_zero = 1; // Nombre de coefficients non nuls sur chaque ligne
231 rect_nb_non_zero = 0;
232
233 // Termes extra-diagonaux:
234 for (int i_face = 0; i_face < nb_faces_internes + nb_faces_periodiques; i_face++)
235 {
236
237 // Calcul du numero de la face a traiter
238 const int face = (i_face < nb_faces_internes)
239 ? premiere_face_interne + i_face
240 : liste_faces_perio[i_face - nb_faces_internes];
241
242 int elem0 = face_voisins(face,0);
243 int elem1 = face_voisins(face,1);
244 if (elem0 > elem1)
245 {
246 int tmp = elem1;
247 elem1 = elem0;
248 elem0 = tmp;
249 }
250 assert(elem0 >= 0); // Verifie qu'on a bien deux elements voisins
251 if (elem0 < nb_elem) // elem0 est reel
252 {
253 const int ligne = elem0 + 1; // Indice fortran
254 if (elem1 < nb_elem) // elem1 est reel aussi
255 {
256 const int colonne = elem1 + 1; // Indice fortran
257 const int n = carre_nb_non_zero[ligne-1]++;
258 const auto index = carre_tab1[ligne-1] + n; // Indice fortran dans tab2
259 carre_tab2[index - 1] = colonne;
260 }
261 else // elem1 est virtuel
262 {
263 const int colonne = elem1 - nb_elem + 1; // Indice fortran
264 const int n = rect_nb_non_zero[ligne-1]++;
265 const auto index = rect_tab1[ligne-1] + n; // Indice fortran dans tab2
266 rect_tab2[index - 1] = colonne;
267 }
268 }
269 }
270
271 return 1;
272}
273
274/*! @brief Calcul des coefficients de la matrice de pression avec un champ de rho.
275 *
276 * Si rho_ptr == 0, on calcule la matrice -div( porosite * grad P ),
277 * sinon on calcule -div( porosite/rho grad P ) et *rho_ptr doit etre un Champ_Fonc_Face_VDF.
278 *
279 */
280
281int Assembleur_P_VDF::remplir(Matrice& la_matrice, const DoubleVect& volumes_entrelaces,const Champ_Don_base * rho_ptr)
282{
283 const Domaine_VDF& domaine_vdf = le_dom_VDF.valeur();
284 const IntTab& face_voisins = domaine_vdf.face_voisins();
285 const DoubleVect& face_surfaces = domaine_vdf.face_surfaces();
286 //const DoubleVect & volumes_entrelaces = domaine_vdf.volumes_entrelaces();
287 const DoubleVect& porosite_face = le_dom_Cl_VDF->equation().milieu().porosite_face();
288
289
290 const DoubleVect * valeurs_rho = 0;
291 if (rho_ptr)
292 {
293 assert(sub_type(Champ_Fonc_Face_VDF, *rho_ptr));
294 valeurs_rho = & (rho_ptr->valeurs());
295 }
296
297 // Raccourcis vers la partie carree (coefficients elements reels/reels)
298 // et la partie rectangulaire (elements reels / elements virtuels) de la matrice
299 Matrice_Bloc& matrice = ref_cast(Matrice_Bloc, la_matrice.valeur());
300 Matrice_Morse_Sym& carre = ref_cast(Matrice_Morse_Sym, matrice.get_bloc(0,0).valeur());
301 Matrice_Morse& rect = ref_cast(Matrice_Morse, matrice.get_bloc(0,1).valeur());
302
303 const int nb_elem = domaine_vdf.nb_elem();
304 ArrOfInt carre_nb_non_zero(nb_elem);
305 ArrOfInt rect_nb_non_zero(nb_elem);
306 carre_nb_non_zero = 1;
307 rect_nb_non_zero = 0;
308
309 auto& carre_tab1 = carre.get_set_tab1();
310 auto& rect_tab1 = rect.get_set_tab1();
311 auto& carre_coeff = carre.get_set_coeff();
312 auto& rect_coeff = rect.get_set_coeff();
313
314 carre_coeff = 0.;
315 rect_coeff = 0.;
316
317 // Traitement des faces internes et periodiques :
318 // Pour chaque face entre deux elements elem0 et elem1, y a quatre termes a ajouter :
319 // M(elem0,elem0)
320 // M(elem0,elem1)
321 // M(elem1,elem1)
322 // M(elem1,elem0) (omis car la matrice est stockee symetrique)
323
324 // Construction de la liste des faces periodiques
325 ArrOfInt liste_faces_perio;
326 const int nb_faces_periodiques = liste_faces_periodiques(liste_faces_perio);
327 const int nb_faces_internes = domaine_vdf.nb_faces_internes();
328 const int premiere_face_interne = domaine_vdf.premiere_face_int();
329 for (int i_face = 0; i_face < nb_faces_internes + nb_faces_periodiques; i_face++)
330 {
331
332 // Calcul du numero de la face a traiter
333 const int num_face = (i_face < nb_faces_internes)
334 ? premiere_face_interne + i_face
335 : liste_faces_perio[i_face - nb_faces_internes];
336 // Calcul de rho sur cette face
337 const double rho_face = (valeurs_rho) ? (*valeurs_rho)[num_face] : 1.;
338 // Calcul du coefficient
339 const double surface = face_surfaces[num_face];
340 const double volume = volumes_entrelaces[num_face];
341 const double porosite = porosite_face[num_face];
342 const double coefficient = surface * surface * porosite / (volume * rho_face);
343 // Numeros des deux elements voisins (le plus petit dans elem0)
344 int elem0 = face_voisins(num_face,0);
345 int elem1 = face_voisins(num_face,1);
346 if (elem0 > elem1)
347 {
348 int tmp = elem1;
349 elem1 = elem0;
350 elem0 = tmp;
351 }
352 if (elem0 < nb_elem)
353 {
354 // elem0 est reel
355 const int ligne = elem0 + 1; // Indice fortran
356 // Indice fortran de l'element diagonal (elem0, elem0)
357 const auto index_diag = carre_tab1[ligne-1];
358 carre_coeff[index_diag - 1] += coefficient;
359 if (elem1 < nb_elem)
360 {
361 // elem1 est reel aussi
362 // Indice fortran de l'element diagonal (elem1, elem1)
363 const auto index_diag1 = carre_tab1[elem1]; // a la ligne elem1+1
364 // Indice fortran de l'element extradiagonal (elem0, elem1)
365 const int n = carre_nb_non_zero[ligne-1]++;
366 const auto index = index_diag + n;
367 // Coefficient diagonal
368 carre_coeff[index_diag1 - 1] += coefficient;
369 // Coefficient extra-diagonal
370 carre_coeff[index - 1] = - coefficient;
371 assert(carre.get_tab2()(index - 1) == elem1 + 1);
372 }
373 else
374 {
375 // elem1 est virtuel
376 const int n = rect_nb_non_zero[ligne-1]++;
377 const auto index = rect_tab1[ligne-1] + n; // Indice fortran dans tab2
378 // Coefficient extra-diagonal
379 rect_coeff[index - 1] = - coefficient;
380 assert(rect.get_tab2()(index - 1) == elem1 - nb_elem + 1);
381 }
382 }
383 }
384
385 // Traitement des conditions aux limites
386 const Conds_lim& les_cl = le_dom_Cl_VDF->les_conditions_limites();
387 const int nb_cl = les_cl.size();
388 for (int num_cl = 0; num_cl < nb_cl; num_cl++)
389 {
390 const Cond_lim_base& la_cl = les_cl[num_cl].valeur();
391 const Front_VF& la_front_dis = ref_cast(Front_VF,la_cl.frontiere_dis());
392
393 // Test sur les conditions limites en 2D RZ (on doit avoir symetrie selon l'axe de revolution)
394 if (bidim_axi && !sub_type(Symetrie,la_cl))
395 {
396 const int ndeb = la_front_dis.num_premiere_face();
397 const int nfin = ndeb + la_front_dis.nb_faces();
398 if (nfin>ndeb && est_egal(face_surfaces[ndeb],0))
399 {
400 Cerr << "\nFirst face surface is smaller than PrecisionGeom = " << precision_geom << finl;
401 Cerr << "May be you have an error in the definition of the boundary conditions." << finl;
402 Cerr << "The axis of revolution for this 2D calculation is along Y." << finl;
403 Cerr << "So you must specify symmetry boundary condition (symetrie keyword) for the boundary " << la_front_dis.le_nom() << finl;
404 exit();
405 }
406 }
407
408 // Pour chaque face de bord entre elem0 et un element fictif exterieur
409 // a pression imposee P0, on a :
410 // grad P = (P(elem0) - P0) * surface / volume_entrelace
411 // elem0 est une inconnue, P0 est ajoute au second membre dans "modifier_secmem".
412 if (sub_type(Neumann_sortie_libre,la_cl))
413 {
414 has_P_ref = 1;
415 carre.set_est_definie(1);
416 const int ndeb = la_front_dis.num_premiere_face();
417 const int nfin = ndeb + la_front_dis.nb_faces();
418 for (int num_face = ndeb; num_face < nfin; num_face++)
419 {
420 // Calcul de rho sur cette face
421 const double rho_face = (valeurs_rho) ? (*valeurs_rho)[num_face] : 1.;
422 // Calcul du coefficient a ajouter dans la matrice
423 const double surface = face_surfaces[num_face];
424 // Attention: le volume entrelace a une valeur particuliere au bord
425 // (voir Domaine_VDF::calculer_volumes_entrelaces() )
426 const double volume = volumes_entrelaces[num_face];
427 const double porosite = porosite_face[num_face];
428 const double coefficient = Option_VDF::coeff_P_neumann * surface * surface * porosite / (volume * rho_face);
429 assert(coefficient > 0.);
430 // Numero de l'element voisin (l'un est -1, l'autre est un element reel)
431 const int elem0 = face_voisins(num_face, 0);
432 const int elem1 = face_voisins(num_face, 1);
433 assert(elem0 == -1 || elem1 == -1);
434 const int elem = elem0 + elem1 + 1;
435 // Ajout du coefficient a la matrice
436 assert(elem < nb_elem);
437 const auto index = carre_tab1[elem]; // Indice fortran
438 carre_coeff[index - 1] += coefficient;
439 les_coeff_pression[num_face] = coefficient;
440 }
441 }
442 else
443 {
444 // Pour les autres conditions aux limites, aucun terme supplementaire dans
445 // la matrice (grad P scalaire n = 0 sur le bord,
446 // ou derivee en temps de grad P scalaire n = 0 sur le bord)
447 }
448 }
449 has_P_ref = (int)mp_max(has_P_ref);
450
451 // Verification sanitaire: pas d'element nul sur la diagonale
452 for (int i = 0; i < nb_elem; i++)
453 {
454 const auto index = carre_tab1[i];
455 const double coeff_diagonal = carre_coeff[index - 1];
456 if (coeff_diagonal == 0.)
457 {
458 // La maille i n'a pas de voisin: pression quelconque
459 carre_coeff[index - 1] = 1.;
460 }
461 }
462
463 carre.compacte();
464 rect.compacte();
465 return 1;
466}
467
468/*! @brief Modification du second membre pour appliquer les conditions aux limites.
469 *
470 * Les conditions prises en charge sont
471 * Neumann_sortie_libre,
472 * Entree_fluide_vitesse_imposee,
473 * Dirichlet_paroi_defilante (rien a faire),
474 * Dirichlet_paroi_fixe (rien a faire),
475 * Symetrie (rien a faire)
476 *
477 */
479{
480 const Domaine_Cl_VDF& le_dom_cl = le_dom_Cl_VDF.valeur();
481 int nb_cond_lim = le_dom_cl.nb_cond_lim();
482
483 for (int indice_cl = 0; indice_cl < nb_cond_lim; indice_cl++)
484 {
485 const Cond_lim_base& la_cl_base =
486 le_dom_cl.les_conditions_limites(indice_cl).valeur();
487
488 const Front_VF& frontiere_vf = ref_cast(Front_VF, la_cl_base.frontiere_dis());
489
490 if (sub_type(Neumann_sortie_libre, la_cl_base))
491 {
493 frontiere_vf,
494 secmem);
495 }
496 else if (sub_type(Entree_fluide_vitesse_imposee, la_cl_base))
497 {
499 frontiere_vf,
500 secmem);
501 }
502 else if (sub_type(Dirichlet_paroi_defilante, la_cl_base))
503 {
504 // Pour une paroi defilante, rien a faire.
505 }
506 else if (sub_type(Dirichlet_paroi_fixe, la_cl_base))
507 {
508 // Rien a faire non plus.
509 }
510 else if (sub_type(Symetrie, la_cl_base))
511 {
512 // Encore rien a faire
513 }
514 else if (sub_type(Periodique, la_cl_base))
515 {
516 // Rien a faire
517 }
518 else
519 {
520 Cerr << "Erreur dans Assembleur_P_VDF::modifier_secmem\n la condition aux limites ";
521 Cerr << la_cl_base.que_suis_je() << " n'est pas prise en charge." << finl;
522 assert(0);
523 exit();
524 }
525 }
526 secmem.echange_espace_virtuel();
527 return 1;
528}
529
530/*! @brief Modification du second membre du solveur en pression pour une condition "Neumann_sortie_libre".
531 *
532 * Calcul en "increment de pression" :
533 * ajouter l'increment de pression, c'est a dire zero (c.l. instationnaire non supportee)
534 * Calcul en "pression" :
535 * Ajout du terme Pimpose * surface / volume_entrelace au second membre dans la discretisation de la
536 * pression au bord (entre un element elem0 et un element fictif exterieur a pression imposee) :
537 * grad P = (P(elem0) - Pimpose) * surface / volume_entrelace
538 *
539 */
540
542 const Front_VF& frontiere_vf,
543 DoubleTab& secmem)
544{
545 const Domaine_VDF& le_dom = le_dom_VDF.valeur();
546 const IntTab& face_voisins = le_dom.face_voisins();
548 {
549 /*
550 const Champ_front_base & champ_front = cond_lim.champ_front();
551 if (sub_type(Champ_front_instationnaire_base, champ_front)
552 || sub_type(Champ_front_var_instationnaire, champ_front)) {
553 Cerr << "Erreur dans Assembleur_P_VDF::modifier_secmem_pression_imposee\n ";
554 Cerr << champ_front.que_suis_je();
555 Cerr << " + resoudre_increment_pression non code" << finl;
556 assert(0);
557 exit();
558 } else {
559 // Champ stationnaire, on ajoute un increment de pression nul.
560 // Donc rien a faire.
561 }
562 */
563 }
564 else
565 {
566 const int nb_faces = frontiere_vf.nb_faces();
567 const int num_premiere_face = frontiere_vf.num_premiere_face();
568 for (int i = 0; i < nb_faces; i++)
569 {
570 const int num_face = num_premiere_face + i;
571 const double Pimp = cond_lim.flux_impose(i);
572 const double coef = les_coeff_pression[num_face] * Pimp;
573 const int elem = face_voisins(num_face, 0) + face_voisins(num_face, 1) + 1;
574 secmem[elem] += coef;
575 }
576 }
577}
578
579/*! @brief Modification du second membre du systeme en pression pour une condition aux limites de vitesse imposee.
580 *
581 * Si on resout en increment de pression, ...
582 * sinon rien a faire.
583 *
584 */
586 const Front_VF& frontiere_vf,
587 DoubleTab& secmem)
588{
589 const Champ_front_base& champ_front = cond_lim.champ_front();
590 const Domaine_VDF& le_dom = le_dom_VDF.valeur();
591 const DoubleVect& face_surfaces = le_dom.face_surfaces();
592 const IntTab& face_voisins = le_dom.face_voisins();
593
594 if (get_resoudre_en_u())
595 {
596 if (champ_front.instationnaire())
597 {
598 const DoubleTab& tab_gpoint = champ_front.derivee_en_temps();
599 int nb_dim = tab_gpoint.nb_dim();
600 bool ch_unif = (tab_gpoint.nb_dim()==1 || tab_gpoint.dimension(0)==1);
601 const int nb_faces = frontiere_vf.nb_faces();
602 const int num_premiere_face = frontiere_vf.num_premiere_face();
603 for (int i = 0; i < nb_faces; i++)
604 {
605 const int num_face = num_premiere_face + i;
606 const double surface = face_surfaces(num_face);
607 const int elem0 = face_voisins(num_face, 0);
608 const int elem1 = face_voisins(num_face, 1);
609 // gpoint est relatif a la normale a la face (elle pointe vers elem1)
610 // La normale est-elle entrante ou sortante ?
611 const double signe = (elem0 < 0) ? 1. : -1.;
612 // Numero de l'element adjacent a la face de bord
613 const int elem = elem0 + elem1 + 1;
614 const int ori = le_dom.orientation(num_face);
615 const double gpoint = nb_dim==1 ? tab_gpoint(ori) : tab_gpoint(ch_unif ? 0 : i, ori);
616
617 secmem[elem] += signe * surface * gpoint;
618 }
619 }
620 else
621 {
622 // Le champ frontiere est stationnaire, rien a faire.
623 }
624 }
625 else
626 {
627 // Resolution en pression: la condition aux limites est imposee ailleurs
628 }
629}
630
632{
633 // Projection :
634 double press_0;
635 if(!has_P_ref)
636 {
637 // On prend la pression minimale comme pression de reference
638 // afin d'avoir la meme pression de reference en sequentiel et parallele
639 press_0=DMAXFLOAT;
640 int nb_elem=le_dom_VDF->domaine().nb_elem();
641 for(int n=0; n<nb_elem; n++)
642 if (pression[n] < press_0)
643 press_0 = pression[n];
644 press_0 = mp_min(press_0);
645 pression -=press_0;
646 pression.echange_espace_virtuel();
647 }
648 return 1;
649}
650int Assembleur_P_VDF::assembler_mat(Matrice& matrice,const DoubleVect& volumes_entrelaces,int incr_pression,int resoudre_en_u)
651{
652 if (!matrice)
653 {
654 if (je_suis_maitre())
655 Cerr << "Assemblage de la matrice pression : Assembleur_P_VDF::assembler" << finl;
656 // Par defaut, resolution en increment de pression
657 construire(matrice);
658 }
659 set_resoudre_increment_pression(incr_pression);
660 set_resoudre_en_u(resoudre_en_u);
661
662 remplir(matrice,volumes_entrelaces, 0);
663 return 1;
664}
665
666/*! @brief Assemblage de la matrice de pression M telle que M*P = div(porosite * grad (P))
667 *
668 * et calcul des coefficients pour modifier_secmem.
669 *
670 */
672{
673 if (je_suis_maitre())
674 Cerr << "Assemblage de la matrice pression : Assembleur_P_VDF::assembler" << finl;
675 // Par defaut, resolution en increment de pression
678 construire(matrice);
679 const Domaine_VDF& domaine_vdf = le_dom_VDF.valeur();
680
681 const DoubleVect& volumes_entrelaces = domaine_vdf.volumes_entrelaces();
682 remplir(matrice,volumes_entrelaces, 0);
683 return 1;
684}
685
686/*! @brief Assemblage de la matrice de pression M telle que M*P = div(porosite/rho * grad (P))
687 *
688 * et calcul des coefficients pour modifier_secmem.
689 *
690 * @param (matrice) La matrice a assembler. Contrainte: Soit la matrice n'est pas encore typee (alors on la "construit"), soit c'est la meme que lors de l'appel precedent.
691 * @param (rho)
692 */
694 const Champ_Don_base& rho)
695{
696 // assembler_rho_variable a ete introduit pour le front-tracking:
697 // il faut dire explicitement si on resout en increment de pression
698 assert(get_resoudre_increment_pression() >= 0);
699 // idem pour resoudre en u
700 assert(get_resoudre_en_u() >= 0);
701 // Si la matrice n'a pas encore ete typee, il faut la construire :
702 if (!matrice)
703 {
704 if (je_suis_maitre())
705 {
706 Cerr << "Assemblage de la matrice pression : ";
707 Cerr << "Assembleur_P_VDF::assembler_rho_variable" << finl;
708 }
709 construire(matrice);
710 }
711 const Domaine_VDF& domaine_vdf = le_dom_VDF.valeur();
712
713 const DoubleVect& volumes_entrelaces = domaine_vdf.volumes_entrelaces();
714 remplir(matrice,volumes_entrelaces, & rho);
715 return 1;
716}
717
718/*! @brief Assemble la matrice de pression pour un fluide quasi compressible.
719 *
720 * La matrice M est telle que M*P = div( porosite * grad(P) ).
721 * Le drapeau resoudre_increment_pression est mis a zero s'il n'a pas
722 * encore ete assigne.
723 *
724 * @param (DoubleTab& tab_rho) mass volumique
725 * @return (int) renvoie toujours 1
726 */
727int Assembleur_P_VDF::assembler_QC(const DoubleTab& tab_rho, Matrice& matrice)
728{
729 // Par defaut pour le qc: resolution en pression et pas en increment pression.
731 {
734 }
735 if (!matrice)
736 {
737 if (je_suis_maitre())
738 {
739 Cerr << "Assemblage de la matrice pression : ";
740 Cerr << "Assembleur_P_VDF::assembler_QC" << finl;
741 }
742 construire(matrice);
743 const Domaine_VDF& domaine_vdf = le_dom_VDF.valeur();
744
745 const DoubleVect& volumes_entrelaces = domaine_vdf.volumes_entrelaces();
746 remplir(matrice,volumes_entrelaces, 0);
747
748 Matrice_Bloc& matrice_bloc=ref_cast(Matrice_Bloc,matrice.valeur());
749 Matrice_Morse_Sym& la_matrice =ref_cast(Matrice_Morse_Sym,matrice_bloc.get_bloc(0,0).valeur());
750 if (la_matrice.get_est_definie()!=1)
751 {
752 if ((je_suis_maitre()) && (la_matrice.nb_lignes()==0) && (la_matrice.nb_colonnes()==0))
753 {
754 Cerr<<"Pressure matrix will not be defined."<<finl;
755 exit();
756 }
757
758 if ((la_matrice.nb_lignes()>0) && (la_matrice.nb_colonnes()>0))
759 {
760 Cerr<<"la_matrice(0,0)"<<la_matrice(0,0)<<finl;
761 Cerr<<"Pas de pression imposee --> P(0)=0"<<finl;
762 if (je_suis_maitre()) la_matrice(0,0) *= 2;
763 }
764 la_matrice.set_est_definie(1);
765 }
766 }
767 return 1;
768}
769
770/* equation sum_k alpha_k = 1 en Pb_Multiphase */
771void Assembleur_P_VDF::dimensionner_continuite(matrices_t matrices, int aux_only) const
772{
773 if (aux_only) return; //rien a faire
774 int e, n, N = ref_cast(Pb_Multiphase, le_dom_Cl_VDF->equation().probleme()).nb_phases(), ne_tot = le_dom_VDF->nb_elem_tot();
775 Stencil stencil(0, 2);
776
777 for (e = 0; e < le_dom_VDF->nb_elem(); e++)
778 for (n = 0; n < N; n++) stencil.append_line(e, N * e + n);
779 Matrix_tools::allocate_morse_matrix(ne_tot, N * ne_tot, stencil, *matrices.at("alpha"));
780}
781
782void Assembleur_P_VDF::assembler_continuite(matrices_t matrices, DoubleTab& secmem, int aux_only) const
783{
784 if (aux_only) return;
785 const DoubleTab& alpha = ref_cast(Pb_Multiphase, le_dom_Cl_VDF->equation().probleme()).equation_masse().inconnue().valeurs();
786 Matrice_Morse& mat = *matrices.at("alpha");
787 const DoubleVect& ve = le_dom_VDF->volumes(), &pe = le_dom_Cl_VDF->equation().milieu().porosite_elem();
788 int e, n, N = alpha.line_size();
789 /* second membre : on multiplie par porosite * volume pour que le systeme en P soit symetrique en cartesien */
790 for (e = 0; e < le_dom_VDF->nb_elem(); e++)
791 for (secmem(e) = -pe(e) * ve(e), n = 0; n < N; n++) secmem(e) += pe(e) * ve(e) * alpha(e, n);
792 /* matrice */
793 for (e = 0; e < le_dom_VDF->nb_elem(); e++)
794 for (n = 0; n < N; n++) mat(e, N * e + n) = -pe(e) * ve(e);
795}
796
797/* norme pour assembler_continuite */
799{
800 const DoubleVect& pe = le_dom_Cl_VDF->equation().milieu().porosite_elem(), &ve = le_dom_VDF->volumes();
801 DoubleTab norm(le_dom_VDF->nb_elem());
802 for (int e = 0; e < le_dom_VDF->nb_elem(); e++) norm(e) = pe(e) * ve(e);
803 return norm;
804}
805
807{
808 return le_dom_VDF.valeur();
809}
810
812{
813 return le_dom_Cl_VDF.valeur();
814}
815
817{
818 le_dom_VDF = ref_cast(Domaine_VDF, le_dom_dis);
819}
820
822{
823 le_dom_Cl_VDF = ref_cast(Domaine_Cl_VDF, le_dom_Cl_dis);
824}
825
827{
828 // CCa 30/04/99 : je ne sais pas si je dois faire qqchose
829 ;
830}
const Domaine_dis_base & domaine_dis_base() const override
int assembler_mat(Matrice &, const DoubleVect &, int incr_pression, int resoudre_en_u) override
void modifier_secmem_pression_imposee(const Neumann_sortie_libre &cond_lim, const Front_VF &frontiere_vf, DoubleTab &secmem)
Modification du second membre du solveur en pression pour une condition "Neumann_sortie_libre".
int modifier_secmem(DoubleTab &) override
Modification du second membre pour appliquer les conditions aux limites.
int liste_faces_periodiques(ArrOfInt &faces)
Remplit le tableau faces avec la liste des indices des faces periodiques dans le tableau faces_voisin...
int assembler_QC(const DoubleTab &, Matrice &) override
Assemble la matrice de pression pour un fluide quasi compressible.
int modifier_solution(DoubleTab &) override
void assembler_continuite(matrices_t matrices, DoubleTab &secmem, int aux_only=0) const override
void modifier_secmem_vitesse_imposee(const Entree_fluide_vitesse_imposee &cond_lim, const Front_VF &frontiere_vf, DoubleTab &secmem)
Modification du second membre du systeme en pression pour une condition aux limites de vitesse impose...
DoubleTab norme_continuite() const override
int construire(Matrice &la_matrice)
Determine les elements non nuls de la matrice et prepare le stockage.
int assembler_rho_variable(Matrice &, const Champ_Don_base &rho) override
Assemblage de la matrice de pression M telle que M*P = div(porosite/rho * grad (P)).
const Domaine_Cl_dis_base & domaine_Cl_dis_base() const override
void associer_domaine_dis_base(const Domaine_dis_base &) override
void dimensionner_continuite(matrices_t matrices, int aux_only=0) const override
int assembler(Matrice &) override
Assemblage de la matrice de pression M telle que M*P = div(porosite * grad (P)).
void associer_domaine_cl_dis_base(const Domaine_Cl_dis_base &) override
void completer(const Equation_base &) override
int remplir(Matrice &la_matrice, const DoubleVect &volumes_entrelaces, const Champ_Don_base *rho_ptr)
Calcul des coefficients de la matrice de pression avec un champ de rho.
ArrOfDouble les_coeff_pression
int get_resoudre_en_u() const
Renvoie la valeur du drapeau resoudre_en_u_ (0 ou 1) Renvoie -1 si le drapeau n'a pas ete initialise.
int set_resoudre_en_u(int flag)
Definit la valeur du drapeau resoudre_en_u__.
int get_resoudre_increment_pression() const
Renvoie la valeur du drapeau resoudre_increment_pression_ (0 ou 1) Renvoie -1 si le drapeau n'a pas e...
int set_resoudre_increment_pression(int flag)
Definit la valeur du drapeau resoudre_increment_pression_.
classe Champ_Don_base classe de base des Champs donnes (non calcules)
DoubleTab & valeurs() override
Surcharge Champ_base::valeurs() Renvoie le tableau des valeurs.
classe Champ_Fonc_Face_VDF
classe Champ_front_base Classe de base pour la hierarchie des champs aux frontieres.
virtual const DoubleTab & derivee_en_temps() const
virtual bool instationnaire() const
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.
Champ_front_base & champ_front()
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
classe Dirichlet_paroi_defilante Impose la vitesse de paroi dnas une equation de type Navier_Stokes.
classe Dirichlet_paroi_fixe Represente une paroi immobile dans une equation de type Navier_Stokes.
class Domaine_Cl_VDF
classe Domaine_Cl_dis_base Les objets Domaine_Cl_dis_base representent les conditions aux limites
int nb_cond_lim() const
Renvoie le nombre de conditions aux limites.
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
class Domaine_VDF
Definition Domaine_VDF.h:64
int orientation(int) const override
inline DoubleVect& Domaine_VDF::porosite_face() {
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
DoubleVect & volumes_entrelaces()
Definition Domaine_VF.h:99
int nb_faces_internes() const
une face est interne ssi elle separe deux elements.
Definition Domaine_VF.h:533
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
classe Domaine_dis_base Cette classe est la base de la hierarchie des domaines discretisees.
int nb_elem_tot() const
classe Entree_fluide_vitesse_imposee Cas particulier de la classe Dirichlet_entree_fluide
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
classe Equation_base Le role d'une equation est le calcul d'un ou plusieurs champs....
Probleme_base & probleme()
Renvoie le probleme associe a l'equation.
class Front_VF
Definition Front_VF.h:36
int nb_faces() const
Definition Front_VF.h:53
int num_premiere_face() const
Definition Front_VF.h:63
const Nom & le_nom() const override
Renvoie le nom de la frontiere geometrique.
virtual void dimensionner(int N, int M)
virtual const Matrice & get_bloc(int i, int j) const
Classe Matrice_Morse_Sym 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.
auto & get_set_coeff()
int nb_colonnes() const override
Return local number of columns (=size on the current proc).
auto & get_set_tab1()
int nb_lignes() const override
Return local number of lines (=size on the current proc).
void compacte(int elim_coeff_nul=0)
Method to check/clean the Matrice_Morse matrix: -Suppress coefficient defined several times.
void set_est_definie(int)
int get_est_definie() const
Classe Matrice Classe generique de la hierarchie des matrices.
Definition Matrice.h:34
static void allocate_morse_matrix(const int nb_lines, const int nb_columns, const Stencil &stencil, Matrice_Morse &matrix, const bool &attach_stencil_to_matrix=false)
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
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
static double precision_geom
Definition Objet_U.h:86
virtual const Nom & le_nom() const
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Objet_U.cpp:319
static int bidim_axi
Definition Objet_U.h:102
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
static double coeff_P_neumann
Definition Option_VDF.h:31
classe Pb_Multiphase Cette classe represente un probleme de thermohydraulique multiphase de type "3*N...
const Equation_base & equation(int) const override
Renvoie l'equation d'hydraulique de type Navier_Stokes_std si i=0 Renvoie l'equation de la thermique ...
classe Periodique Cette classe represente une condition aux limites periodique.
Definition Periodique.h:31
int face_associee(int i) const
Definition Periodique.h:35
static double mp_min(double)
Definition Process.cpp:386
static double mp_max(double)
Definition Process.cpp:376
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
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
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
int nb_dim() const
Definition TRUSTTab.h:199
void append_line(_TYPE_)
Definition TRUSTTab.tpp:213
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
int line_size() const
Definition TRUSTVect.tpp:67
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")