TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Assembleur_P_PolyMAC_HFV.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_PolyMAC_HFV.h>
17#include <Champ_Face_PolyMAC_HFV.h>
18#include <Domaine_PolyMAC_HFV.h>
19#include <Neumann_sortie_libre.h>
20#include <Domaine_Cl_PolyMAC_family.h>
21#include <Matrice_Morse_Sym.h>
22#include <Matrice_Diagonale.h>
23#include <Static_Int_Lists.h>
24#include <Matrice_Bloc_Sym.h>
25#include <Operateur_Grad.h>
26#include <TRUSTTab_parts.h>
27#include <Pb_Multiphase.h>
28#include <Matrix_tools.h>
29#include <Array_tools.h>
30#include <Dirichlet.h>
31#include <Debog.h>
32#include <Perf_counters.h>
33
34Implemente_instanciable(Assembleur_P_PolyMAC_HFV, "Assembleur_P_PolyMAC_HFV", Assembleur_P_PolyMAC_CDO);
35
36Sortie& Assembleur_P_PolyMAC_HFV::printOn(Sortie& s) const { return s << que_suis_je() << " " << le_nom(); }
37
39
40
41int Assembleur_P_PolyMAC_HFV::assembler_mat(Matrice& la_matrice,const DoubleVect& diag,int incr_pression,int resoudre_en_u)
42{
44 set_resoudre_en_u(resoudre_en_u);
45 Cerr << "Assemblage de la matrice de pression ... " ;
46 statistics().begin_count(STD_COUNTERS::matrix_assembly,statistics().get_last_opened_counter_level()+1);
47 la_matrice.typer("Matrice_Morse");
48 Matrice_Morse& mat = ref_cast(Matrice_Morse, la_matrice.valeur());
49
50 const Domaine_PolyMAC_HFV& domaine = ref_cast(Domaine_PolyMAC_HFV, le_dom_PolyMAC_CDO.valeur());
51 const Champ_Face_PolyMAC_HFV& ch = ref_cast(Champ_Face_PolyMAC_HFV, mon_equation->inconnue());
52 const IntTab& e_f = domaine.elem_faces(), &fcl = ch.fcl();
53 const DoubleVect& pe = equation().milieu().porosite_elem(), &pf = equation().milieu().porosite_face(), &vf = domaine.volumes_entrelaces();
54 int i, j, e, f, fb, ne = domaine.nb_elem(), ne_tot = domaine.nb_elem_tot(), nf = domaine.nb_faces(), nf_tot = domaine.nb_faces_tot();
55
56 DoubleTrav w2; //matrice W2 (de Domaine_PolyMAC_HFV) par element
57
58
59 /* 1. stencil de la matrice en pression : seulement au premier passage */
60 if (!stencil_done) /* premier passage: calcul */
61 {
62 Stencil stencil(0, 2);
63
64 for (e = 0; e < ne; e++)
65 for (stencil.append_line(e, e), i = 0; i < e_f.dimension(1) && (f = e_f(e, i)) >= 0; i++) /* blocs "elem-elem" et "elem-face" */
66 stencil.append_line(e, ne_tot + f); //toutes les faces (sauf bord de Neumann)
67 for (e = 0; e < ne_tot; e++)
68 for (domaine.W2(nullptr, e, w2), i = 0; i < w2.dimension(1); i++) /* blocs "face-elem" et "face-face" */
69 if (fcl(f = e_f(e, i), 0) == 1 && f < nf) stencil.append_line(ne_tot + f, ne_tot + f); //Neumann : ligne "dpf = 0"
70 else if (f < nf)
71 for (stencil.append_line(ne_tot + f, e), j = 0; j < w2.dimension(1); j++) /* sinon : ligne sum w2_{ff'} (pf' - pe) */
72 if (w2(i, j, 0)) stencil.append_line(ne_tot + f, ne_tot + e_f(e, j));
73
74 tableau_trier_retirer_doublons(stencil);
75 Matrix_tools::allocate_morse_matrix(ne_tot + nf_tot, ne_tot + nf_tot, stencil, mat);
76 tab1.ref_array(mat.get_set_tab1()), tab2.ref_array(mat.get_set_tab2());
77 stencil_done = 1;
78 }
79 else /* passages suivants : recyclage */
80 {
81 mat.get_set_tab1().ref_array(tab1);
82 mat.get_set_tab2().ref_array(tab2);
83 mat.get_set_coeff().resize(tab2.size_array()), mat.get_set_coeff() = 0;
84 mat.set_nb_columns(ne_tot + nf_tot);
85 }
86
87 /* 2. coefficients */
88 for (e = 0; e < ne_tot; e++)
89 {
90 domaine.W2(nullptr, e, w2); //calcul de W2
91 double m_ee = 0, m_fe, m_ef, coeff; //coefficients (elem, elem), (elem, face) et (face, elem)
92 for (i = 0; i < w2.dimension(0); i++, m_ee += m_ef)
93 {
94 f = e_f(e, i), coeff = diag.size_totale() ? pf(f) * vf(f) / diag(f) : 1;
95 for (m_ef = 0, m_fe = 0, j = 0; j < w2.dimension(1); j++)
96 if (w2(i, j, 0))
97 {
98 fb = e_f(e, j);
99 if (f < domaine.nb_faces() && fcl(f, 0) != 1) mat(ne_tot + f, ne_tot + fb) += coeff * pe(e) * w2(i, j, 0); //interne ou Dirichlet
100 else if (f < domaine.nb_faces() && i == j) mat(ne_tot + f, ne_tot + fb) = 1; //f Neumann : ligne dpf = 0
101 m_ef += coeff * pe(e) * w2(i, j, 0), m_fe += coeff * pe(e) * w2(i, j, 0); //accumulation dans m_ef, m_fe
102 }
103 if (e < domaine.nb_elem()) mat(e, ne_tot + f) -= m_ef;
104 if (f < domaine.nb_faces() && fcl(f, 0) != 1) mat(ne_tot + f, e) -= m_fe; //si f non Neumann : coef (face, elem)
105 }
106 if (e < domaine.nb_elem()) mat(e, e) += m_ee; //coeff (elem, elem)
107 }
108
109 //en l'absence de CLs en pression, on ajoute P(0) = 0 sur le process 0
110 has_P_ref=0;
111 for (int n_bord=0; n_bord<le_dom_PolyMAC_CDO->nb_front_Cl(); n_bord++)
112 if (sub_type(Neumann_sortie_libre, le_dom_Cl_PolyMAC_CDO->les_conditions_limites(n_bord).valeur()) )
113 has_P_ref=1;
114 if (!has_P_ref && !Process::me()) mat(0, 0) *= 2;
115 Cerr << statistics().get_time_since_last_open(STD_COUNTERS::matrix_assembly) << " s" << finl;
116 statistics().end_count(STD_COUNTERS::matrix_assembly);
117 return 1;
118}
119
120/* equations sum_k alpha_k = 1, [grad p]_{fe} = [grad p]_{fe'} en Pb_Multiphase */
121void Assembleur_P_PolyMAC_HFV::dimensionner_continuite(matrices_t matrices, int aux_only) const
122{
123 const Domaine_PolyMAC_HFV& domaine = ref_cast(Domaine_PolyMAC_HFV, le_dom_PolyMAC_CDO.valeur());
124 int i, j, e, f, fb, n, N = equation().inconnue().valeurs().line_size(), m, M = equation().get_champ("pression").valeurs().line_size(),
125 ne_tot = domaine.nb_elem_tot(), nf_tot = domaine.nb_faces_tot();
126 const IntTab& fcl = ref_cast(Champ_Face_PolyMAC_HFV, mon_equation->inconnue()).fcl(), &e_f = domaine.elem_faces();
127 Stencil sten_a(0, 2), sten_p(0, 2), sten_v(0, 2);
128 DoubleTrav w2;
129
130 /* equations sum alpha_k = 1 */
131 if (!aux_only)
132 for (e = 0; e < domaine.nb_elem(); e++)
133 for (n = 0; n < N; n++) sten_a.append_line(e, N * e + n);
134 /* equations sur les p_f : continuite du gradient si interne, p = p_f si Neumann, sum_k alpha_k v_k = sum_k alpha_k v_k,imp si Dirichlet */
135 for (e = 0; e < domaine.nb_elem_tot(); e++)
136 for (domaine.W2(nullptr, e, w2), i = 0; i < w2.dimension(0); i++)
137 if ((f = e_f(e, i)) >= domaine.nb_faces()) continue; //faces virtuelles
138 else if (!fcl(f, 0))
139 for (sten_p.append_line(!aux_only * ne_tot + f, e), j = 0; j < w2.dimension(1); j++) //face interne
140 {
141 if (w2(i, j, 0) && fcl(fb = e_f(e, j), 0) != 1)
142 for (m = 0; m < M; m++)
143 sten_p.append_line(M * (!aux_only * ne_tot + f) + m, M * (ne_tot + fb) + m);
144 }
145 else if (fcl(f, 0) == 1)
146 for (m = 0; m < M; m++) sten_p.append_line(M * (!aux_only * ne_tot + f) + m, M * (ne_tot + f) + m); //Neumann
147 else for (n = 0, m = 0; n < N; n++, m += (M > 1)) sten_v.append_line(M * (!aux_only * ne_tot + f) + m, N * f + n); //Dirichlet
148
149 tableau_trier_retirer_doublons(sten_v), tableau_trier_retirer_doublons(sten_p);
150 if (!aux_only) Matrix_tools::allocate_morse_matrix(ne_tot + nf_tot, N * ne_tot, sten_a, *matrices.at("alpha"));
151 Matrix_tools::allocate_morse_matrix(M * (!aux_only * ne_tot + nf_tot), M * (ne_tot + nf_tot), sten_p, *matrices.at("pression"));
152 Matrix_tools::allocate_morse_matrix(M * (!aux_only * ne_tot + nf_tot), equation().inconnue().valeurs().size_totale(), sten_v, *matrices.at("vitesse"));
153}
154
155void Assembleur_P_PolyMAC_HFV::assembler_continuite(matrices_t matrices, DoubleTab& secmem, int aux_only) const
156{
157 const Domaine_PolyMAC_HFV& domaine = ref_cast(Domaine_PolyMAC_HFV, le_dom_PolyMAC_CDO.valeur());
158 const Pb_Multiphase* pbm = sub_type(Pb_Multiphase, equation().probleme()) ? &ref_cast(Pb_Multiphase, equation().probleme()) : nullptr;
159 const Conds_lim& cls = le_dom_Cl_PolyMAC_CDO->les_conditions_limites();
160 const DoubleTab *alpha = pbm ? &pbm->equation_masse().inconnue().valeurs() : nullptr, &press = equation().probleme().get_champ("pression").valeurs(),
161 &vit = equation().inconnue().valeurs(), *alpha_rho = pbm ? &pbm->equation_masse().champ_conserve().passe() : nullptr, &nf = domaine.face_normales();
162 const IntTab& fcl = ref_cast(Champ_Face_PolyMAC_HFV, mon_equation->inconnue()).fcl(), &e_f = domaine.elem_faces();
163 const DoubleVect& ve = domaine.volumes(), &pe = equation().milieu().porosite_elem(), &fs = domaine.face_surfaces(), &vf = domaine.volumes_entrelaces();
164 int i, j, e, f, fb, n, N = vit.line_size(), m, M = press.line_size(), ne_tot = domaine.nb_elem_tot(), d, D = dimension;
165 Matrice_Morse *mat_a = alpha ? matrices.at("alpha") : nullptr, &mat_p = *matrices.at("pression"), &mat_v = *matrices.at("vitesse");
166 DoubleTrav w2, fac(N);
167 double ar_tot, acc;
168
169 secmem = 0, fac = 1;
170
171 /* equations sum alpha_k = 1 */
172 /* second membre : on multiplie par porosite * volume pour que le systeme en P soit symetrique en cartesien */
173 if (!aux_only)
174 for (e = 0; e < domaine.nb_elem(); e++)
175 for (secmem(e) = -pe(e) * ve(e), n = 0; n < N; n++) secmem(e) += pe(e) * ve(e) * (*alpha)(e, n);
176 /* matrice */
177 if (!aux_only)
178 for (e = 0; e < domaine.nb_elem(); e++)
179 for (n = 0; n < N; n++) (*mat_a)(e, N * e + n) = -pe(e) * ve(e);
180
181 /* equations sur les p_f : continuite du gradient si interne, p = p_f si Neumann, sum_k alpha_k v_k = sum_k alpha_k v_k,imp si Dirichlet */
182 for (mat_p.get_set_coeff() = 0, mat_v.get_set_coeff() = 0, e = 0; e < ne_tot; e++)
183 for (domaine.W2(nullptr, e, w2), i = 0; i < w2.dimension(0); i++)
184 if ((f = e_f(e, i)) >= domaine.nb_faces()) continue; //faces virtuelles
185 else if (!fcl(f, 0)) //face interne
186 {
187 for (acc = 0, j = 0; j < w2.dimension(1); acc+= pe(e) * vf(f) * w2(i, j, 0), j++)
188 for (m = 0; m < M; m++) //second membre
189 secmem(!aux_only * ne_tot + f, m) -= pe(e) * vf(f) * w2(i, j, 0) * (press(ne_tot + e_f(e, j), m) - press(e, m));
190 for (m = 0; m < M; m++) mat_p(M * (!aux_only * ne_tot + f) + m, M * e + m) -= acc;
191 for (j = 0; j < w2.dimension(1); j++) //matrice (sauf bords de Meumann)
192 if (w2(i, j, 0) && fcl(fb = e_f(e, j), 0) != 1)
193 for (m = 0; m <M; m++)
194 mat_p(M * (!aux_only * ne_tot + f) + m, M * (ne_tot + fb) + m) += pe(e) * vf(f) * w2(i, j, 0);
195 }
196 else if (fcl(f, 0) == 1) //Neumann -> egalites p_f = p_imp
197 {
198 for (m = 0; m < M; m++) secmem(M * (!aux_only * ne_tot + f) + m) = fs(f) * (ref_cast(Neumann, cls[fcl(f, 1)].valeur()).flux_impose(fcl(f, 2), m) - press(ne_tot + f, m));
199 for (m = 0; m < M; m++) mat_p(M * (!aux_only * ne_tot + f) + m, M * (ne_tot + f) + m) = fs(f);
200 }
201 else //Dirichlet -> egalite flux_tot_imp - flux_tot = 0
202 {
203 if (M == 1 && N > 1) //une pression, plusieurs vitesses -> on ne peut imposer qu'une ponderation : on choisit celle ocrrespondant aux flux de masse total
204 {
205 for (ar_tot = 0, n = 0; n < N; n++) ar_tot += (*alpha_rho)(e, n);
206 for (n = 0; n < N; n++) fac(n) = (*alpha_rho)(e, n) / ar_tot;
207 }
208 else if (M != N) abort(); //sinon, il faut autant de pressions que de vitesses
209
210 for (n = 0, m = 0; n < N; n++, m += (M > 1)) secmem(!aux_only * ne_tot + f, m) += vf(f) * fac(n) * vit(f, n);
211 if (fcl(f, 0) == 3)
212 for (d = 0; d < D; d++)
213 for (n = 0, m = 0; n < N; n++, m += (M > 1)) //contrib de la valeur imposee: Dirichlet non homogene seulement
214 secmem(!aux_only * ne_tot + f, m) -= vf(f) * fac(n) * nf(f, d) / fs(f) * ref_cast(Dirichlet, cls[fcl(f, 1)].valeur()).val_imp(fcl(f, 2), N * d + n);
215 for (n = 0, m = 0; n < N; n++, m += (M > 1)) mat_v(M * (!aux_only * ne_tot + f) + m, N * f + n) -= vf(f) * fac(n);
216 }
217}
218
219void Assembleur_P_PolyMAC_HFV::modifier_secmem_pour_incr_p(const DoubleTab& press, const double fac, DoubleTab& secmem) const
220{
221 const Domaine_PolyMAC_HFV& domaine = ref_cast(Domaine_PolyMAC_HFV, le_dom_PolyMAC_CDO.valeur());
222 const Champ_Face_PolyMAC_HFV& ch = ref_cast(Champ_Face_PolyMAC_HFV, mon_equation->inconnue());
223 const Conds_lim& cls = le_dom_Cl_PolyMAC_CDO->les_conditions_limites();
224 const IntTab& fcl = ch.fcl();
225 int f, ne_tot = domaine.nb_elem_tot(), m, M = equation().probleme().get_champ("pression").valeurs().line_size();
226 for (f = 0; f < domaine.premiere_face_int(); f++)
227 if (fcl(f, 0) == 1)
228 for (m = 0; m < M; m++)
229 secmem(ne_tot + f, m) = (ref_cast(Neumann_sortie_libre, cls[fcl(f, 1)].valeur()).flux_impose(fcl(f, 2), m) - press(ne_tot + f, m)) / fac;
230}
231
232/* norme pour assembler_continuite */
234{
235 const DoubleVect& pe= equation().milieu().porosite_elem(), &ve = le_dom_PolyMAC_CDO->volumes();
236 DoubleTab norm(le_dom_PolyMAC_CDO->nb_elem());
237 for (int e = 0; e < le_dom_PolyMAC_CDO->nb_elem(); e++) norm(e) = pe(e) * ve(e);
238 return norm;
239}
240
242{
243 Debog::verifier("pression dans modifier solution in",pression);
244 if(!has_P_ref) pression -= mp_min_vect(pression);
245 return 1;
246}
const Equation_base & equation() const
int modifier_solution(DoubleTab &) override
void assembler_continuite(matrices_t matrices, DoubleTab &secmem, int aux_only=0) const override
void dimensionner_continuite(matrices_t matrices, int aux_only=0) const override
void modifier_secmem_pour_incr_p(const DoubleTab &press, const double fac, DoubleTab &incr) const override
int assembler_mat(Matrice &, const DoubleVect &, int incr_pression, int resoudre_en_u) override
DoubleTab norme_continuite() const override
int set_resoudre_en_u(int flag)
Definit la valeur du drapeau resoudre_en_u__.
int set_resoudre_increment_pression(int flag)
Definit la valeur du drapeau resoudre_increment_pression_.
: class Champ_Face_PolyMAC_HFV
const IntTab & fcl() const
DoubleTab & passe(int i=1) override
Renvoie les valeurs du champs a l'instant t-i.
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
virtual DoubleTab & valeurs()=0
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
static void verifier(const char *const msg, double)
Definition Debog.cpp:21
classe Dirichlet Cette classe est la classe de base de la hierarchie des conditions aux limites de ty...
Definition Dirichlet.h:31
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual const Milieu_base & milieu() const =0
Champ_Inc_base & champ_conserve() const
virtual const Champ_Inc_base & inconnue() const =0
const Champ_base & get_champ(const Motcle &nom) const override
Probleme_base & probleme()
Renvoie le probleme associe a l'equation.
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
auto & get_set_tab2()
void set_nb_columns(const int)
auto & get_set_coeff()
auto & get_set_tab1()
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)
DoubleVect & porosite_elem()
Definition Milieu_base.h:58
DoubleVect & porosite_face()
Definition Milieu_base.h:62
classe Neumann_sortie_libre Cette classe represente une frontiere ouverte sans vitesse imposee
Classe Neumann Cette classe est la classe de base de la hierarchie des conditions aux limites de type...
Definition Neumann.h:31
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
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
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
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
classe Pb_Multiphase Cette classe represente un probleme de thermohydraulique multiphase de type "3*N...
virtual Equation_base & equation_masse()
const Champ_base & get_champ(const Motcle &nom) const override
static void abort()
Routine de sortie de Trio-U sur une erreur abort().
Definition Process.cpp:570
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
Classe de base des flux de sortie.
Definition Sortie.h:52
void append_line(_TYPE_)
Definition TRUSTTab.tpp:213
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
int line_size() const
Definition TRUSTVect.tpp:67