TrioCFD 1.9.9_beta
TrioCFD documentation
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; //W2 matrix (from Domaine_PolyMAC_HFV) per element
57
58
59 /* 1. pressure matrix stencil: only on the first pass */
60 if (!stencil_done) /* first pass: compute */
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++) /* "elem-elem" and "elem-face" blocks */
66 stencil.append_line(e, ne_tot + f); //all faces (except Neumann boundaries)
67 for (e = 0; e < ne_tot; e++)
68 for (domaine.W2(nullptr, e, w2), i = 0; i < w2.dimension(1); i++) /* "face-elem" and "face-face" blocks */
69 if (fcl(f = e_f(e, i), 0) == 1 && f < nf) stencil.append_line(ne_tot + f, ne_tot + f); //Neumann: row "dpf = 0"
70 else if (f < nf)
71 for (stencil.append_line(ne_tot + f, e), j = 0; j < w2.dimension(1); j++) /* otherwise: row 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 /* subsequent passes: recycle */
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); //compute W2
91 double m_ee = 0, m_fe, m_ef, coeff; //coefficients (elem, elem), (elem, face) and (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); //internal or Dirichlet
100 else if (f < domaine.nb_faces() && i == j) mat(ne_tot + f, ne_tot + fb) = 1; //f Neumann: row dpf = 0
101 m_ef += coeff * pe(e) * w2(i, j, 0), m_fe += coeff * pe(e) * w2(i, j, 0); //accumulation in 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; //if f not Neumann: coeff (face, elem)
105 }
106 if (e < domaine.nb_elem()) mat(e, e) += m_ee; //coeff (elem, elem)
107 }
108
109 //in the absence of pressure BCs, we add P(0) = 0 on 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'} in 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 on p_f: gradient continuity if internal, p = p_f if Neumann, sum_k alpha_k v_k = sum_k alpha_k v_k,imp if 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; //virtual faces
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++) //internal face
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 /* right-hand side: multiply by porosity * volume so the P system is symmetric in Cartesian coordinates */
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 /* matrix */
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 on p_f: gradient continuity if internal, p = p_f if Neumann, sum_k alpha_k v_k = sum_k alpha_k v_k,imp if 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; //virtual faces
185 else if (!fcl(f, 0)) //internal face
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++) //right-hand side
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++) //matrix (except Neumann boundaries)
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 -> equalities 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 -> equality flux_tot_imp - flux_tot = 0
202 {
203 if (M == 1 && N > 1) //one pressure, multiple velocities -> only one weighting can be imposed: choose the one corresponding to total mass flux
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(); //otherwise, there must be as many pressures as velocities
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)) //contribution of the imposed value: non-homogeneous Dirichlet only
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/* norm for 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)
Sets the value of the resoudre_en_u__ flag.
int set_resoudre_increment_pression(int flag)
Sets the value of the resoudre_increment_pression_ flag.
: class Champ_Face_PolyMAC_HFV
const IntTab & fcl() const
DoubleTab & passe(int i=1) override
Returns field values at instant t-i.
DoubleTab & valeurs() override
Returns the array of field values at the current time.
virtual DoubleTab & valeurs()=0
class Conds_lim This class represents a vector of boundary conditions.
Definition Conds_lim.h:32
static void verifier(const char *const msg, double)
Definition Debog.cpp:21
Dirichlet This class is the base class of the hierarchy of Dirichlet-type boundary conditions.
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()
Returns the problem associated with the equation.
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
auto & get_set_tab2()
void set_nb_columns(const int)
auto & get_set_coeff()
auto & get_set_tab1()
Matrice class - Generic class in the matrix hierarchy.
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
Neumann_sortie_libre This class represents an open boundary without imposed velocity.
Classe Neumann This class is the base class of the hierarchy of Neumann-type boundary conditions.
Definition Neumann.h:31
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
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
virtual const Nom & le_nom() const
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
Definition Objet_U.cpp:317
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
Multiphase thermohydraulics problem of type "3*N equations":
virtual Equation_base & equation_masse()
const Champ_base & get_champ(const Motcle &nom) const override
static void abort()
Abort routine for TRUST on a fatal error.
Definition Process.cpp:573
static int me()
Returns the rank of the local processor in the current communication group. See Comm_Group::rank() an...
Definition Process.cpp:122
Base class for output streams.
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