TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Operateur_Conv_sensibility_VEF.cpp
1/****************************************************************************
2* Copyright (c) 2020, 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 <Operateur_Conv_sensibility_VEF.h>
17#include <Op_Conv_VEF_base.h>
18#include <Navier_Stokes_std_sensibility.h>
19#include <Convection_Diffusion_Temperature_sensibility.h>
20#include <Fluide_Incompressible.h>
21#include <TRUSTTrav.h>
22#include <Op_Conv_VEF_Face.h>
23#include <Probleme_base.h>
24#include <Schema_Temps_base.h>
25#include <Periodique.h>
26#include <Symetrie.h>
27#include <Neumann_homogene.h>
28#include <Neumann_paroi.h>
29#include <Echange_externe_impose.h>
30#include <Neumann_sortie_libre.h>
31#include <Debog.h>
32#include <Champ_P1NC.h>
33#include <Porosites_champ.h>
34#include <Convection_tools.h>
35#include <CL_Types_include.h>
36#include <Perf_counters.h>
37
38Implemente_instanciable( Operateur_Conv_sensibility_VEF, "Op_Conv_sensibility_VEF_P1NC",Operateur_Conv_sensibility ) ;
39
40
42{
43 return os;
44}
45
46
48{
49 Cerr << " Operateur_Conv_sensibility_VEF ::readOn " << finl;
50 op_conv.associer_eqn(equation());
51 op_conv.associer_vitesse(la_vitesse.valeur());
52 op_conv.lire(is);
53 Cerr << "Operateur_Conv_sensibility_VEF : " << op_conv.que_suis_je() << finl;
54 return is;
55}
56
58 const Domaine_Cl_dis_base& domaine_cl_dis,
59 const Champ_Inc_base& inco )
60{
61 Cerr << " Operateur_Conv_sensibility_VEF::associer" << finl;
62 const Domaine_VEF& zvef = ref_cast(Domaine_VEF,domaine_dis);
63 const Domaine_Cl_VEF& zclvef = ref_cast(Domaine_Cl_VEF,domaine_cl_dis);
64
65 le_dom_vef = zvef;
66 la_zcl_vef = zclvef;
67 le_dom_vef->creer_tableau_faces(fluent);
68 Operateur_Conv_sensibility::associer(domaine_dis,domaine_cl_dis,inco);
69}
70
71DoubleTab& Operateur_Conv_sensibility_VEF::ajouter(const DoubleTab& inco, DoubleTab& resu) const
72{
73 Cerr << "Operateur_Conv_sensibility_VEF::ajouter" << finl;
74
75 //Check convection scheme discretization type:
76 const Op_Conv_VEF_base& opConvVEFbase = ref_cast(Op_Conv_VEF_base, op_conv.valeur());
77 const Op_Conv_VEF_Face& opConvVEFFace = ref_cast(Op_Conv_VEF_Face, op_conv.valeur());
78 int convectionSchemeDiscrType; // amont=0, muscl=1, centre=2
79 opConvVEFFace.get_type_op(convectionSchemeDiscrType);
80 const Domaine_VEF& domaine_VEF = ref_cast(Domaine_VEF, le_dom_vef.valeur());
81
82 if(convectionSchemeDiscrType==0 || convectionSchemeDiscrType==1 || convectionSchemeDiscrType==2) // Convection scheme discr "amont".
83 {
84 if(equation().que_suis_je()=="Navier_Stokes_standard_sensibility")
85 {
87 const Champ_Inc_base& state = eq.get_state();
88 const DoubleTab& state_field = eq.get_state_field();
89 const Motcle& uncertain_var = eq.get_uncertain_variable_name();
90 const double& poly_chaos_value= eq.get_poly_chaos_value();
91 const bool& adjoint= eq.get_adjoint_value();
92
93 // Dimensionnement du tableau des flux convectifs au bord du domaine de calcul
94 DoubleTab& flux_b = flux_bords_;
95 int nb_faces_bord=domaine_VEF.nb_faces_bord();
96 flux_b.resize(nb_faces_bord,inco.dimension(1));
97 flux_b = 0.;
98
99 if(adjoint==false)
100 {
101 ajouter_conv_term(state,inco ,resu, flux_b);
102 ajouter_conv_term(la_vitesse,state_field ,resu, flux_b);
103 }
104 else
105 {
106 Matrice_Morse mat;
107 opConvVEFFace.dimensionner(mat);
108 opConvVEFFace.contribuer_a_avec(inco, mat);
109 opConvVEFFace.modifier_pour_Cl(mat, resu);
110 const double coeff=-1.;
111 DoubleTab neg_state(state_field);
112 neg_state.operator*=(coeff);
113 mat.ajouter_multvectT_(neg_state ,resu); // add -(v. grad^t).u where u=state (direct velocity) and v=adjoint velocity
114 opConvVEFFace.contribue_au_second_membre(resu);
115 ajouter_conv_term(la_vitesse,state_field, resu, flux_b); // add (u.grad)v where u=state (direct velocity) and v=adjoint velocity
116 }
117
118 //If we treat the Navier Stokes equations by the polynomial chaos method to calculate the sensitivity equations of this system,
119 //we find that we have to add one more convection term on the Navier_Stokes_standard_sensibility which is +2*\sigma u_a. grad u_a
120 // where \sigma is the variance of the uncertain parameter
121
122 if(poly_chaos_value !=0.)
123 {
124 double coeff= 2*poly_chaos_value;
125 DoubleTab var = inco;
126 var *= coeff;
127 const Champ_Inc_base& vitesse = eq.vitesse();
128 ajouter_conv_term(vitesse ,var, resu, flux_b);
129 }
130
131 if(uncertain_var=="MU")
132 add_diffusion_term(state.valeurs(), resu);
133 opConvVEFbase.modifier_flux(*this); // Multiplication by rho
134
135 }
136 else if (equation().que_suis_je()=="Convection_Diffusion_Temperature_sensibility")
137 {
138
140 const Champ_Inc_base& velocity_state = eq.get_velocity_state();
141 const DoubleTab& temperature_state = eq.get_temperature_state_field();
142 const Motcle& uncertain_var = eq.get_uncertain_variable_name();
143 const double& poly_chaos_value= eq.get_poly_chaos_value();
144
145 DoubleTab& flux_b = flux_bords_;
146 int nb_faces_bord=domaine_VEF.nb_faces_bord();
147 flux_b.resize(nb_faces_bord,inco.dimension(0));
148 flux_b = 0.;
149
150 ajouter_conv_term(velocity_state,inco ,resu, flux_b);
151 ajouter_conv_term(vitesse(), temperature_state,resu, flux_b);
152
153 if(poly_chaos_value !=0.)
154 {
155 double coeff= 2*poly_chaos_value;
156 DoubleTab inco_sigma = inco;
157 inco_sigma *=coeff;
158 ajouter_conv_term(vitesse(), inco_sigma, resu, flux_b);
159 }
160
161 opConvVEFbase.modifier_flux(*this); // Multiplication by rhoCp
162 if(uncertain_var=="LAMBDA")
163 {
164 add_diffusion_scalar_term(temperature_state, resu);
165 }
166 if(uncertain_var=="CP")
167 {
168 double lambda_div_Cp=-1.;
169 const double Cp = eq.fluide().capacite_calorifique().valeurs()(0, 0);
170 const double lambda = eq.fluide().conductivite().valeurs()(0, 0);
171 lambda_div_Cp*=(lambda/Cp);
172 add_diffusion_scalar_term(temperature_state, resu,lambda_div_Cp);
173 }
174
175
176 if(uncertain_var!="TEMPERATURE" && uncertain_var!="BOUSSINESQ_TEMPERATURE"
177 && uncertain_var!="BETA_TH" && uncertain_var!="LAMBDA" && uncertain_var!="CP")
178 {
179 Cout << "Variable "<<uncertain_var<<" Is not available yet."<<" "
180 "Try available TEMPERATURE or BOUSSINESQ_TEMPERATURE or BETA_TH or LAMBDA or CP variable." << finl;
182 }
183
184
185 }
186 else
187 {
188 Cout << "Operateur_Conv_sensibility_VEF::ajouter() => Sensibility cannot use currently equation " << equation().que_suis_je()
189 <<". Try available Navier_Stokes_standard_sensibility or Convection_Diffusion_Temperature_sensibility." << finl;
191 }
192
193 }
194 else
195 {
196 Cout << "Sensibility cannot use currently convection scheme " << op_conv.type() <<". Try available Sensibility -centre -amont -muscl convection scheme." << finl;
198 }
200 Debog::verifier("resu dansOperateur_Conv_sensibility_VEF::ajouter", resu);
201 return resu;
202}
203
204void Operateur_Conv_sensibility_VEF::ajouter_conv_term(const Champ_Inc_base& velocity, const DoubleTab& transporte, DoubleTab& resu, DoubleTab& flux_b) const
205{
206 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
207 const Domaine_VEF& domaine_VEF = ref_cast(Domaine_VEF, le_dom_vef.valeur());
208 const Op_Conv_VEF_base& opConvVEFbase = ref_cast(Op_Conv_VEF_base, op_conv.valeur());
209 const Op_Conv_VEF_Face& opConvVEFFace = ref_cast(Op_Conv_VEF_Face, op_conv.valeur());
210
211 int ordre;
212 opConvVEFFace.get_ordre(ordre);
213
214 double alpha_;
215 opConvVEFFace.get_alpha(alpha_);
216
217 Motcle type_limit;
218 if(op_conv.type()=="MUSCL") //type_lumit has default value set in Op_Conv_Muscl_VEF_Face.cpp .
219 {
220 type_limit="vanleer";
221 }
222 else // In case of: "convection { { generic muscl [limiter] [order of accuracy] [alpha] } }". op_conv.type()=="GENERIC" .
223 {
224 opConvVEFFace.get_type_lim(type_limit);
225 }
226 enum type_operateur { amont, muscl, centre };
227
228 const DoubleTab& vitesse_face_absolue=velocity.valeurs();
229 const DoubleVect& porosite_face = la_zcl_vef->equation().milieu().porosite_face();
230
231 int marq=opConvVEFbase.phi_u_transportant(equation());
232 DoubleTab transporte_face_;
233 DoubleTab vitesse_face_;
234 // soit on a transporte_face=phi*transporte et vitesse_face=vitesse
235 // soit on a transporte_face=transporte et vitesse_face=phi*vitesse
236 // cela depend si on transporte avec phi*u ou avec u.
237 const DoubleTab& transporte_face = modif_par_porosite_si_flag(transporte,transporte_face_,!marq,porosite_face);
238 const DoubleTab& vitesse_face = modif_par_porosite_si_flag(vitesse_face_absolue,vitesse_face_,marq,porosite_face);
239
240 const IntTab& elem_faces = domaine_VEF.elem_faces();
241 const DoubleTab& facenormales = domaine_VEF.face_normales();
242 const auto& facette_normales = domaine_VEF.facette_normales();
243 const Domaine& domaine = domaine_VEF.domaine();
244 const int nfa7 = domaine_VEF.type_elem().nb_facette();
245 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
246 const IntVect& rang_elem_non_std = domaine_VEF.rang_elem_non_std();
247 const IntTab& face_voisins = domaine_VEF.face_voisins();
248 const DoubleTab& normales_facettes_Cl = domaine_Cl_VEF.normales_facettes_Cl();
249 int premiere_face_int = domaine_VEF.premiere_face_int();
250 int nfac = domaine.nb_faces_elem();
251 int nsom = domaine.nb_som_elem();
252 const IntTab& sommet_elem = domaine.les_elems();
253 const DoubleTab& vecteur_face_facette = ref_cast_non_const(Domaine_VEF,domaine_VEF).vecteur_face_facette();
254 const DoubleTab& vecteur_face_facette_Cl = domaine_Cl_VEF.vecteur_face_facette_Cl();
255 int nb_bord = domaine_VEF.nb_front_Cl();
256 const IntTab& les_elems=domaine.les_elems();
257
258 // Permet d'avoir un flux_bord coherent avec les CLs (mais parfois diverge?)
259 // Active uniquement pour ordre 3
260 int option_appliquer_cl_dirichlet = (ordre==3 ? 1 : 0);
261 int option_calcul_flux_en_un_point = 0;//(ordre==3 ? 1 : 0);
262 // Definition d'un tableau pour un traitement special des schemas pres des bords
263 if (traitement_pres_bord_.size_array()!=nb_elem_tot)
264 {
265 traitement_pres_bord_.resize_array(nb_elem_tot);
267 // Pour muscl3 on applique le minmod sur les elements ayant une face de Dirichlet
268 if (ordre==3)
269 {
270 for (int n_bord=0; n_bord<nb_bord; n_bord++)
271 {
272 const Cond_lim_base& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord).valeur();
273 if ( sub_type(Dirichlet,la_cl) || sub_type(Dirichlet_homogene,la_cl) )
274 {
275 const Front_VF& le_bord = ref_cast(Front_VF,la_cl.frontiere_dis());
276 int nb_faces_tot = le_bord.nb_faces_tot();
277 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
278 {
279 int num_face = le_bord.num_face(ind_face);
280 int elem = face_voisins(num_face,0);
281 traitement_pres_bord_[elem]=1;
282 }
283 }
284 }
285 }
286 else
287 {
288 // Pour le muscl/centre actuels on utilise un calcul de flux a l'ordre 1
289 // aux mailles de bord ou aux mailles ayant un sommet de Dirichlet
290 ArrOfInt est_un_sommet_de_bord_(domaine_VEF.nb_som_tot());
291 for (int n_bord=0; n_bord<nb_bord; n_bord++)
292 {
293 const Cond_lim_base& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord).valeur();
294 if ( sub_type(Dirichlet,la_cl) || sub_type(Dirichlet_homogene,la_cl) )
295 {
296 const Front_VF& le_bord = ref_cast(Front_VF,la_cl.frontiere_dis());
297 int nb_faces_tot = le_bord.nb_faces_tot();
298 int size = domaine_VEF.face_sommets().dimension(1);
299 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
300 for (int som=0; som<size; som++)
301 {
302 int face = le_bord.num_face(ind_face);
303 est_un_sommet_de_bord_[domaine_VEF.face_sommets(face,som)]=1;
304 }
305 }
306 }
307 for (int elem=0; elem<nb_elem_tot; elem++)
308 {
309 if (rang_elem_non_std(elem)!=-1)
310 traitement_pres_bord_[elem]=1;
311 else
312 {
313 for (int n_som=0; n_som<nsom; n_som++)
314 if (est_un_sommet_de_bord_[les_elems(elem,n_som)])
315 traitement_pres_bord_[elem]=1;
316 }
317 }
318 }
319 // Construction du tableau est_une_face_de_dirichlet_
320 est_une_face_de_dirichlet_.resize_array(domaine_VEF.nb_faces_tot());
322 for (int n_bord=0; n_bord<nb_bord; n_bord++)
323 {
324 const Cond_lim_base& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord).valeur();
325 if ( sub_type(Dirichlet,la_cl) || sub_type(Dirichlet_homogene,la_cl) )
326 {
327 const Front_VF& le_bord = ref_cast(Front_VF,la_cl.frontiere_dis());
328 int nb_faces_tot = le_bord.nb_faces_tot();
329 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
330 {
331 int num_face = le_bord.num_face(ind_face);
332 est_une_face_de_dirichlet_[num_face] = 1;
333 }
334 }
335 }
336 }
337
338 // Pour le traitement de la convection on distingue les polyedres
339 // standard qui ne "voient" pas les conditions aux limites et les
340 // polyedres non standard qui ont au moins une face sur le bord.
341 // Un polyedre standard a n facettes sur lesquelles on applique le
342 // schema de convection.
343 // Pour un polyedre non standard qui porte des conditions aux limites
344 // de Dirichlet, une partie des facettes sont portees par les faces.
345 // En bref pour un polyedre le traitement de la convection depend
346 // du type (triangle, tetraedre ...) et du nombre de faces de Dirichlet.
347
348 const Elem_VEF_base& type_elemvef= domaine_VEF.type_elem();
349 int istetra=0;
350 Nom nom_elem=type_elemvef.que_suis_je();
351 if ((nom_elem=="Tetra_VEF")||(nom_elem=="Tri_VEF"))
352 istetra=1;
353
354 const DoubleVect& porosite_elem = la_zcl_vef->equation().milieu().porosite_elem();
355 double psc;
356 int poly,face_adj,fa7,i,j,n_bord;
357 int num_face, rang;
358 int num10,num20,num_som;
359 int ncomp_ch_transporte=(transporte_face.nb_dim() == 1?1:transporte_face.dimension(1));
360
361 // Traitement particulier pour les faces de periodicite
362 int nb_faces_perio = 0;
363 for (n_bord=0; n_bord<nb_bord; n_bord++)
364 {
365 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
366 if (sub_type(Periodique,la_cl.valeur()))
367 {
368 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
369 nb_faces_perio+=le_bord.nb_faces();
370 }
371 }
372
373 DoubleTab tab;
374 if (ncomp_ch_transporte == 1)
375 tab.resize(nb_faces_perio);
376 else
377 tab.resize(nb_faces_perio,ncomp_ch_transporte);
378
379 nb_faces_perio=0;
380 for (n_bord=0; n_bord<nb_bord; n_bord++)
381 {
382 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
383 if (sub_type(Periodique,la_cl.valeur()))
384 {
385 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
386 int num1 = le_bord.num_premiere_face();
387 int num2 = num1 + le_bord.nb_faces();
388 for (num_face=num1; num_face<num2; num_face++)
389 {
390 if (ncomp_ch_transporte == 1)
391 tab(nb_faces_perio) = resu(num_face);
392 else
393 for (int comp=0; comp<ncomp_ch_transporte; comp++)
394 tab(nb_faces_perio,comp) = resu(num_face,comp);
395 nb_faces_perio++;
396 }
397 }
398 }
399
400 int fac=0,elem1,elem2,comp0;
401 int nb_faces_ = domaine_VEF.nb_faces();
402 ArrOfInt face(nfac);
403
404 // Tableau gradient base sur gradient_elem selon schema
405 DoubleTab gradient_elem(nb_elem_tot,ncomp_ch_transporte,dimension); // (du/dx du/dy dv/dx dv/dy) pour un poly
406 if(op_conv.type()=="CENTRE" || op_conv.type()=="MUSCL")
407 {
408 Champ_P1NC::calcul_gradient(transporte_face,gradient_elem,domaine_Cl_VEF);
409 }
410 DoubleTab gradient;
411 if (op_conv.type()=="CENTRE")
412 {
413 gradient.ref(gradient_elem);
414 }
415 else if(op_conv.type()=="MUSCL")
416 {
417 // application du limiteur
418 gradient.resize(0, ncomp_ch_transporte, dimension); // (du/dx du/dy dv/dx dv/dy) pour une face
419 domaine_VEF.creer_tableau_faces(gradient);
420 for (n_bord=0; n_bord<nb_bord; n_bord++)
421 {
422 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
423 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
424 int num1 = le_bord.num_premiere_face();
425 int num2 = num1 + le_bord.nb_faces();
426 if (sub_type(Periodique,la_cl.valeur()))
427 {
428 for (fac=num1; fac<num2; fac++)
429 {
430 elem1=face_voisins(fac,0);
431 elem2=face_voisins(fac,1);
432 for (comp0=0; comp0<ncomp_ch_transporte; comp0++)
433 for (i=0; i<dimension; i++)
434 {
435 double grad1=gradient_elem(elem1, comp0, i);
436 double grad2=gradient_elem(elem2, comp0, i);
437 gradient(fac, comp0, i) =application_LIMITEUR(grad1, grad2, type_limit);
438 }
439 }
440 }
441 else if (sub_type(Symetrie,la_cl.valeur()))
442 {
443 for (fac=num1; fac<num2; fac++)
444 {
445 elem1=face_voisins(fac,0);
446 for (comp0=0; comp0<ncomp_ch_transporte; comp0++)
447 for (i=0; i<dimension; i++)
448 gradient(fac, comp0, i) = gradient_elem(elem1, comp0, i);
449
450 if (ordre==3)
451 {
452 // On enleve la composante normale (on pourrait le faire pour les autres schemas...)
453 // mais pour le moment, on ne veut pas changer le comportement par defaut du muscl...
454 //const DoubleTab& facenormales = domaine_VEF.face_normales();
455 for (comp0=0; comp0<ncomp_ch_transporte; comp0++)
456 for (i=0; i<dimension; i++)
457 {
458 double carre_surface=0;
459 double tmp=0;
460 for (j=0; j<dimension; j++)
461 {
462 double ndS=facenormales(fac,j);
463 carre_surface += ndS*ndS;
464 tmp += gradient(fac, comp0, j)*ndS;
465 }
466 gradient(fac, comp0, i) -= tmp*facenormales(fac,i)/carre_surface;
467 }
468 }
469 }
470 }
471 }
472
473 for (fac=premiere_face_int; fac<nb_faces_; fac++)
474 {
475 elem1=face_voisins(fac,0);
476 elem2=face_voisins(fac,1);
477 int minmod_pres_du_bord = 0;
478 if (ordre==3 && (traitement_pres_bord_[elem1] || traitement_pres_bord_[elem2])) minmod_pres_du_bord = 1;
479 for (comp0=0; comp0<ncomp_ch_transporte; comp0++)
480 for (i=0; i<dimension; i++)
481 {
482 double grad1=gradient_elem(elem1, comp0, i);
483 double grad2=gradient_elem(elem2, comp0, i);
484 if (minmod_pres_du_bord)
485 gradient(fac, comp0, i) = minmod(grad1, grad2);
486 else
487 gradient(fac, comp0, i) =application_LIMITEUR(grad1, grad2, type_limit);
488 }
489 } // fin du for faces
490 gradient.echange_espace_virtuel();
491 }// fin if(type_op==muscl)
492
493 ArrOfDouble vs(dimension);
494 ArrOfDouble vc(dimension);
495 ArrOfDouble cc(dimension);
496 DoubleVect xc(dimension);
497 DoubleTab vsom(nsom,dimension);
498 DoubleTab xsom(nsom,dimension);
499
500
501 int nb_faces_bord=domaine_VEF.nb_faces_bord();
502 const IntTab& KEL=type_elemvef.KEL();
503 const DoubleTab& xv=domaine_VEF.xv();
504 const DoubleTab& coord_sommets=domaine.coord_sommets();
505
506 // Boucle ou non selon la valeur de alpha (uniquement a l'ordre 3 pour le moment)
507 // Si alpha=1, la boucle se limite a une simple passe avec le schema choisi (muscl, amont, centre)
508 // Si alpha<1, la boucle se compose de 2 passes:
509 // -la premiere avec le schema choisi et une ponderation de alpha
510 // -la seconde avec le schema centre et une ponderation de 1-alpha
511 double alpha = alpha_;
512 int nombre_passes = (alpha==1 ? 1 : 2);
513 for (int passe=1; passe<=nombre_passes; passe++)
514 {
515 type_operateur type_op_boucle;
516 if(op_conv.type()=="MUSCL")
517 type_op_boucle = muscl;
518 else if (op_conv.type()=="AMONT")
519 type_op_boucle = amont;
520 else
521 type_op_boucle =centre;
522 if (passe==2)
523 {
524 type_op_boucle = centre;
525 gradient.ref(gradient_elem);
526 }
527 // Les polyedres non standard sont ranges en 2 groupes dans le Domaine_VEF:
528 // - polyedres bords et joints
529 // - polyedres bords et non joints
530 // On traite les polyedres en suivant l'ordre dans lequel ils figurent
531 // dans le domaine
532 // boucle sur les polys
533 for (poly=0; poly<nb_elem_tot; poly++)
534 {
535 int contrib = 0;
536 // calcul des numeros des faces du polyedre
537 for (face_adj=0; face_adj<nfac; face_adj++)
538 {
539 int face_ = elem_faces(poly,face_adj);
540 face[face_adj]= face_;
541 if (face_<nb_faces_) contrib=1; // Une face reelle sur l'element virtuel
542 }
543 //
544 if (contrib)
545 {
546 int calcul_flux_en_un_point = (ordre != 3) && (ordre==1 || traitement_pres_bord_[poly]);
547 for (j=0; j<dimension; j++)
548 {
549 vs[j] = vitesse_face_absolue(face[0],j)*porosite_face[face[0]];
550 for (i=1; i<nfac; i++)
551 vs[j]+= vitesse_face_absolue(face[i],j)*porosite_face[face[i]];
552 }
553 // calcul de la vitesse aux sommets des polyedres
554 // On va utliser les fonctions de forme implementees dans la classe Champs_P1_impl ou Champs_Q1_impl
555 if (istetra==1)
556 {
557 for (i=0; i<nsom; i++)
558 for (j=0; j<dimension; j++)
559 vsom(i,j) = (vs[j] - dimension*vitesse_face_absolue(face[i],j)*porosite_face[face[i]]);
560 }
561 else
562 {
563 // pour que cela soit valide avec les hexa (c'est + lent a calculer...)
564 for (j=0; j<nsom; j++)
565 {
566 num_som = sommet_elem(poly,j);
567 for (int ncomp=0; ncomp<dimension; ncomp++)
568 vsom(j,ncomp) =velocity.valeur_a_sommet_compo(num_som,poly,ncomp);
569 }
570 }
571
572 // Determination du type de CL selon le rang
573 rang = rang_elem_non_std(poly);
574 int itypcl = (rang==-1 ? 0 : domaine_Cl_VEF.type_elem_Cl(rang));
575
576 // calcul de vc (a l'intersection des 3 facettes) vc vs vsom proportionnelles a la porosite
577 type_elemvef.calcul_vc(face,vc,vs,vsom,velocity,itypcl,porosite_face);
578
579 // calcul de xc (a l'intersection des 3 facettes) necessaire pour muscl3
580 if (ordre==3)
581 {
582 int idirichlet;
583 int n1,n2,n3;
584 for (i=0; i<nsom; i++)
585 for (j=0; j<dimension; j++)
586 xsom(i,j) = coord_sommets(les_elems(poly,i),j);
587 type_elemvef.calcul_xg(xc,xsom,itypcl,idirichlet,n1,n2,n3);
588 }
589
590 // Gestion de la porosite
591 if (marq==0)
592 {
593 double coeff=1./porosite_elem(poly);
594 vsom*=coeff;
595 vc*=coeff;
596 }
597 // Boucle sur les facettes du polyedre non standard:
598 for (fa7=0; fa7<nfa7; fa7++)
599 {
600 num10 = face[KEL(0,fa7)];
601 num20 = face[KEL(1,fa7)];
602 // normales aux facettes
603 if (rang==-1)
604 for (i=0; i<dimension; i++)
605 cc[i] = facette_normales(poly, fa7, i);
606 else
607 for (i=0; i<dimension; i++)
608 cc[i] = normales_facettes_Cl(rang,fa7,i);
609
610 // Calcul des vitesses en C,S,S2 les 3 extremites de la fa7 et M le centre de la fa7
611 double psc_c=0,psc_s=0,psc_m,psc_s2=0;
612 if (dimension==2)
613 {
614 for (i=0; i<2; i++)
615 {
616 psc_c+=vc[i]*cc[i];
617 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
618 }
619 psc_m=(psc_c+psc_s)/2.;
620 }
621 else
622 {
623 for (i=0; i<3; i++)
624 {
625 psc_c+=vc[i]*cc[i];
626 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
627 psc_s2+=vsom(KEL(3,fa7),i)*cc[i];
628 }
629 psc_m=(psc_c+psc_s+psc_s2)/3.;
630 }
631 // On applique les CL de Dirichlet si num1 ou num2 est une face avec CL de Dirichlet
632 // auquel cas la fa7 coincide avec la face num1 ou num2 -> C est au centre de la face
633 int appliquer_cl_dirichlet=0;
634 if (option_appliquer_cl_dirichlet)
636 {
637 appliquer_cl_dirichlet = 1;
638 psc_m = psc_c;
639 }
640
641 // Determination de la face amont pour M
642 int face_amont_m,dir;
643 if (psc_m >= 0)
644 {
645 face_amont_m = num10;
646 dir=0;
647 }
648 else
649 {
650 face_amont_m = num20;
651 dir=1;
652 }
653 // Determination des faces amont pour les points C,S,S2
654 int face_amont_c=face_amont_m;
655 int face_amont_s=face_amont_m;
656 int face_amont_s2=face_amont_m;
657 if (type_op_boucle==muscl && ordre==3)
658 {
659 face_amont_c = (psc_c >= 0) ? num10 : num20;
660 face_amont_s = (psc_s >= 0) ? num10 : num20;
661 face_amont_s2 = (psc_s2 >= 0) ? num10 : num20;
662 }
663 // gradient aux items element (schema centre) ou aux items face (schemas muscl)
664 int item_m=poly;
665 int item_c=poly;
666 int item_s=poly;
667 int item_s2=poly;
668 if (type_op_boucle==muscl)
669 {
670 item_m = face_amont_m;
671 item_c = face_amont_c;
672 item_s = face_amont_s;
673 item_s2 = face_amont_s2;
674 }
675
676 for (comp0=0; comp0<ncomp_ch_transporte; comp0++)
677 {
678 double flux;
679 double inco_m = (ncomp_ch_transporte==1?transporte_face(face_amont_m):transporte_face(face_amont_m,comp0));
680 if (type_op_boucle==amont || appliquer_cl_dirichlet)
681 {
682 flux = inco_m*psc_m;
683 }
684 else // muscl ou centre
685 {
686 // Calcul de l'inconnue au centre M de la fa7
687 if (rang==-1)
688 for (j=0; j<dimension; j++)
689 inco_m+= gradient(item_m,comp0,j)*vecteur_face_facette(poly,fa7,j,dir);
690 else
691 for (j=0; j<dimension; j++)
692 inco_m+= gradient(item_m,comp0,j)*vecteur_face_facette_Cl(rang,fa7,j,dir);
693
694 // Calcul de l'inconnue au sommet S, une premiere extremite de la fa7
695 double inco_s = (ncomp_ch_transporte==1?transporte_face(face_amont_s):transporte_face(face_amont_s,comp0));
696 int sommet_s = sommet_elem(poly,KEL(2,fa7));
697 for (j=0; j<dimension; j++)
698 inco_s+= gradient(item_s,comp0,j)*(-xv(face_amont_s,j)+coord_sommets(sommet_s,j));
699
700 // Calcul de l'inconnue au sommet S2, la derniere extremite de la fa7 en 3D
701 double inco_s2=0;
702 if (dimension==3)
703 {
704 inco_s2 = (ncomp_ch_transporte==1?transporte_face(face_amont_s2):transporte_face(face_amont_s2,comp0));
705 int sommet_s2 = sommet_elem(poly,KEL(3,fa7));
706 for (j=0; j<dimension; j++)
707 inco_s2+= gradient(item_s2,comp0,j)*(-xv(face_amont_s2,j)+coord_sommets(sommet_s2,j));
708 }
709
710 // Calcul de l'inconnue a C, une autre extremite de la fa7, intersection avec les autres fa7
711 // du polyedre. C=G centre du polyedre si volume non etendu
712 // xc donne par elemvef.calcul_xg()
713 double inco_c;
714 if (ordre==3)
715 {
716 inco_c = (ncomp_ch_transporte==1?transporte_face(face_amont_c):transporte_face(face_amont_c,comp0));
717 for (j=0; j<dimension; j++)
718 inco_c+= gradient(item_c,comp0,j)*(-xv(face_amont_c,j)+xc(j));
719 }
720 else
721 {
722 inco_c = dimension*inco_m-inco_s-inco_s2;
723 }
724
725 // Calcul du flux sur 1 point
726 if (calcul_flux_en_un_point || option_calcul_flux_en_un_point)
727 {
728 flux = inco_m*psc_m;
729 }
730 else
731 {
732 // Calcul du flux sur 3 points
733 flux = (dimension==2) ? (inco_c*psc_c + inco_s*psc_s + 4*inco_m*psc_m)/6
734 : (inco_c*psc_c + inco_s*psc_s + inco_s2*psc_s2 + 9*inco_m*psc_m)/12;
735 }
736 }
737
738 // Ponderation par coefficient alpha
739 flux*=alpha;
740
741 if (ncomp_ch_transporte == 1)
742 {
743 resu(num10) -= flux;
744 resu(num20) += flux;
745 if (num10<nb_faces_bord) flux_b(num10,0) += flux;
746 if (num20<nb_faces_bord) flux_b(num20,0) -= flux;
747 }
748 else
749 {
750 resu(num10,comp0) -= flux;
751 resu(num20,comp0) += flux;
752 if (num10<nb_faces_bord) flux_b(num10,comp0) += flux;
753 if (num20<nb_faces_bord) flux_b(num20,comp0) -= flux;
754 }
755
756 }// boucle sur comp
757 } // fin de la boucle sur les facettes
758 }
759 } // fin de la boucle
760 alpha = 1 - alpha;
761 } // fin de la boucle
762 int voisine;
763 nb_faces_perio = 0;
764 double diff1,diff2;
765
766 // Boucle sur les bords pour traiter les conditions aux limites
767 // il y a prise en compte d'un terme de convection pour les
768 // conditions aux limites de Neumann_sortie_libre seulement
769 for (n_bord=0; n_bord<nb_bord; n_bord++)
770 {
771 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
772
773 if (sub_type(Neumann_sortie_libre,la_cl.valeur()))
774 {
775 const Neumann_sortie_libre& la_sortie_libre = ref_cast(Neumann_sortie_libre, la_cl.valeur());
776 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
777 int num1 = le_bord.num_premiere_face();
778 int num2 = num1 + le_bord.nb_faces();
779 for (num_face=num1; num_face<num2; num_face++)
780 {
781 psc =0;
782 for (i=0; i<dimension; i++)
783 psc += vitesse_face(num_face,i)*facenormales(num_face,i);
784 if (psc>0)
785 if (ncomp_ch_transporte == 1)
786 {
787 resu(num_face) -= psc*transporte_face(num_face);
788 flux_b(num_face,0) = -psc*transporte_face(num_face);
789 }
790 else
791 for (i=0; i<ncomp_ch_transporte; i++)
792 {
793 resu(num_face,i) -= psc*transporte_face(num_face,i);
794 flux_b(num_face,i) = -psc*transporte_face(num_face,i);
795 }
796 else
797 {
798 if (ncomp_ch_transporte == 1)
799 {
800 resu(num_face) -= psc*la_sortie_libre.val_ext(num_face-num1);
801 flux_b(num_face,0) = -psc*la_sortie_libre.val_ext(num_face-num1);
802 }
803 else
804 for (i=0; i<ncomp_ch_transporte; i++)
805 {
806 resu(num_face,i) -= psc*la_sortie_libre.val_ext(num_face-num1,i);
807 flux_b(num_face,i) = -psc*la_sortie_libre.val_ext(num_face-num1,i);
808 }
809 }
810 }
811 }
812 else if (sub_type(Periodique,la_cl.valeur()))
813 {
814 const Periodique& la_cl_perio = ref_cast(Periodique, la_cl.valeur());
815 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
816 int num1 = le_bord.num_premiere_face();
817 int num2 = num1 + le_bord.nb_faces();
818 ArrOfInt fait(le_bord.nb_faces());
819 fait = 0;
820 for (num_face=num1; num_face<num2; num_face++)
821 {
822 if (fait[num_face-num1] == 0)
823 {
824 voisine = la_cl_perio.face_associee(num_face-num1) + num1;
825
826 if (ncomp_ch_transporte == 1)
827 {
828 diff1 = resu(num_face)-tab(nb_faces_perio);
829 diff2 = resu(voisine)-tab(nb_faces_perio+voisine-num_face);
830 resu(voisine) += diff1;
831 resu(num_face) += diff2;
832 /* On ne doit pas ajouter a flux_b, c'est deja calcule au dessus
833 flux_b(voisine,0) += diff1;
834 flux_b(num_face,0) += diff2;*/
835 }
836 else
837 for (int comp=0; comp<ncomp_ch_transporte; comp++)
838 {
839 diff1 = resu(num_face,comp)-tab(nb_faces_perio,comp);
840 diff2 = resu(voisine,comp)-tab(nb_faces_perio+voisine-num_face,comp);
841 resu(voisine,comp) += diff1;
842 resu(num_face,comp) += diff2;
843 /* On ne doit pas ajouter a flux_b, c'est deja calcule au dessus
844 flux_b(voisine,comp) += diff1;
845 flux_b(num_face,comp) += diff2; */
846 }
847
848 fait[num_face-num1]= 1;
849 fait[voisine-num1] = 1;
850 }
851 nb_faces_perio++;
852 }
853 }
854 }
855}
856
857
858//state_field grad_inco
859void Operateur_Conv_sensibility_VEF::ajouter_Lstate_sensibility_Amont(const DoubleTab& state_field, const DoubleTab& inco, DoubleTab& resu ) const
860{
861 Cout<<"ajouter_Lstate_sensibility "<<finl;
862 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
863 const Domaine_VEF& domaine_VEF = ref_cast(Domaine_VEF, le_dom_vef.valeur());
864 const IntTab& elem_faces = domaine_VEF.elem_faces();
865 const DoubleTab& facenormales = domaine_VEF.face_normales();
866 const auto& facette_normales = domaine_VEF.facette_normales();
867 const Domaine& domaine = domaine_VEF.domaine();
868 const int nfa7 = domaine_VEF.type_elem().nb_facette();
869 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
870 const IntVect& rang_elem_non_std = domaine_VEF.rang_elem_non_std();
871 const DoubleTab& normales_facettes_Cl = domaine_Cl_VEF.normales_facettes_Cl();
872 int nfac = domaine.nb_faces_elem();
873 int nsom = domaine.nb_som_elem();
874 int nb_bord = domaine_VEF.nb_front_Cl();
875 const IntTab& les_elems=domaine.les_elems();
876 int option_appliquer_cl_dirichlet = 0 ;
877
878 // Definition d'un tableau pour un traitement special des schemas pres des bords
879 if (traitement_pres_bord_.size_array()!=nb_elem_tot)
880 {
881 traitement_pres_bord_.resize_array(nb_elem_tot);
883 ArrOfInt est_un_sommet_de_bord_(domaine_VEF.nb_som_tot());
884 for (int n_bord=0; n_bord<nb_bord; n_bord++)
885 {
886 const Cond_lim_base& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord).valeur();
887 if ( sub_type(Dirichlet,la_cl) || sub_type(Dirichlet_homogene,la_cl) )
888 {
889 const Front_VF& le_bord = ref_cast(Front_VF,la_cl.frontiere_dis());
890 int nb_faces_tot = le_bord.nb_faces_tot();
891 int size = domaine_VEF.face_sommets().dimension(1);
892 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
893 for (int som=0; som<size; som++)
894 {
895 int face = le_bord.num_face(ind_face);
896 est_un_sommet_de_bord_[domaine_VEF.face_sommets(face,som)]=1;
897 }
898 }
899 }
900 for (int elem=0; elem<nb_elem_tot; elem++)
901 {
902 if (rang_elem_non_std(elem)!=-1)
903 traitement_pres_bord_[elem]=1;
904 else
905 {
906 for (int n_som=0; n_som<nsom; n_som++)
907 if (est_un_sommet_de_bord_[les_elems(elem,n_som)])
908 traitement_pres_bord_[elem]=1;
909 }
910 }
911 // Construction du tableau est_une_face_de_dirichlet_
912 est_une_face_de_dirichlet_.resize_array(domaine_VEF.nb_faces_tot());
914 for (int n_bord=0; n_bord<nb_bord; n_bord++)
915 {
916 const Cond_lim_base& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord).valeur();
917 if ( sub_type(Dirichlet,la_cl) || sub_type(Dirichlet_homogene,la_cl) )
918 {
919 const Front_VF& le_bord = ref_cast(Front_VF,la_cl.frontiere_dis());
920 int nb_faces_tot = le_bord.nb_faces_tot();
921 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
922 {
923 int num_face = le_bord.num_face(ind_face);
924 est_une_face_de_dirichlet_[num_face] = 1;
925 }
926 }
927 }
928 }
929
930 // Pour le traitement de la convection on distingue les polyedres
931 // standard qui ne "voient" pas les conditions aux limites et les
932 // polyedres non standard qui ont au moins une face sur le bord.
933 // Un polyedre standard a n facettes sur lesquelles on applique le
934 // schema de convection.
935 // Pour un polyedre non standard qui porte des conditions aux limites
936 // de Dirichlet, une partie des facettes sont portees par les faces.
937 // En bref pour un polyedre le traitement de la convection depend
938 // du type (triangle, tetraedre ...) et du nombre de faces de Dirichlet.
939
940 const Elem_VEF_base& type_elemvef= domaine_VEF.type_elem();
941 int istetra=0;
942 Nom nom_elem=type_elemvef.que_suis_je();
943 if ((nom_elem=="Tetra_VEF")||(nom_elem=="Tri_VEF"))
944 istetra=1;
945
946 double psc, psc_inco;
947 int poly,face_adj,fa7,i,j,n_bord;
948 int num_face, rang;
949 int num10,num20;
950 int ncomp_ch_transporte=(inco.nb_dim() == 1?1:inco.dimension(1));
951
952 // Traitement particulier pour les faces de periodicite
953 int nb_faces_perio = 0;
954 for (n_bord=0; n_bord<nb_bord; n_bord++)
955 {
956 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
957 if (sub_type(Periodique,la_cl.valeur()))
958 {
959 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
960 nb_faces_perio+=le_bord.nb_faces();
961 }
962 }
963
964 DoubleTab tab;
965 if (ncomp_ch_transporte == 1)
966 tab.resize(nb_faces_perio);
967 else
968 tab.resize(nb_faces_perio,ncomp_ch_transporte);
969
970 nb_faces_perio=0;
971 for (n_bord=0; n_bord<nb_bord; n_bord++)
972 {
973 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
974 if (sub_type(Periodique,la_cl.valeur()))
975 {
976 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
977 int num1 = le_bord.num_premiere_face();
978 int num2 = num1 + le_bord.nb_faces();
979 for (num_face=num1; num_face<num2; num_face++)
980 {
981 if (ncomp_ch_transporte == 1)
982 tab(nb_faces_perio) = resu(num_face);
983 else
984 for (int comp=0; comp<ncomp_ch_transporte; comp++)
985 tab(nb_faces_perio,comp) = resu(num_face,comp);
986 nb_faces_perio++;
987 }
988 }
989 }
990
991 int comp0;
992 int nb_faces_ = domaine_VEF.nb_faces();
993 ArrOfInt face(nfac);
994 ArrOfDouble vs(dimension);
995 ArrOfDouble vs_inco(dimension);
996 ArrOfDouble vc(dimension);
997 ArrOfDouble vc_inco(dimension);
998 ArrOfDouble cc(dimension);
999 //DoubleVect xc(dimension);
1000 DoubleTab vsom(nsom,dimension);
1001 DoubleTab vsom_inco(nsom,dimension);
1002 //DoubleTab xsom(nsom,dimension);
1003
1004
1005 // Dimensionnement du tableau des flux convectifs au bord du domaine de calcul
1006 DoubleTab& flux_b = flux_bords_;
1007 int nb_faces_bord=domaine_VEF.nb_faces_bord();
1008 flux_b.resize(nb_faces_bord,ncomp_ch_transporte);
1009 flux_b = 0.;
1010
1011 const IntTab& KEL=type_elemvef.KEL();
1012
1013
1014
1015 // Les polyedres non standard sont ranges en 2 groupes dans le Domaine_VEF:
1016 // - polyedres bords et joints
1017 // - polyedres bords et non joints
1018 // On traite les polyedres en suivant l'ordre dans lequel ils figurent
1019 // dans le domaine
1020 // boucle sur les polys
1021
1022 for (poly=0; poly<nb_elem_tot; poly++)
1023 {
1024 int contrib = 0;
1025 // calcul des numeros des faces du polyedre
1026 for (face_adj=0; face_adj<nfac; face_adj++)
1027 {
1028 int face_ = elem_faces(poly,face_adj);
1029 face[face_adj]= face_;
1030 if (face_<nb_faces_) contrib=1; // Une face reelle sur l'element virtuel
1031 }
1032 //
1033 if (contrib)
1034 {
1035 for (j=0; j<dimension; j++)
1036 {
1037 vs[j] = state_field(face[0],j);
1038 vs_inco[j] = inco(face[0],j);
1039 for (i=1; i<nfac; i++)
1040 {
1041 vs[j]+= state_field(face[i],j);
1042 vs_inco[j] = inco(face[i],j);
1043 }
1044 }
1045 // calcul de la vitesse aux sommets des polyedres
1046 if (istetra==1)
1047 {
1048 for (i=0; i<nsom; i++)
1049 for (j=0; j<dimension; j++)
1050 {
1051 vsom(i,j) = (vs[j] - dimension*state_field(face[i],j));
1052 vsom_inco(i,j) = (vs_inco[j] - dimension*inco(face[i],j));
1053 }
1054 }
1055 else
1056 {
1057 Cout << "Sensibility is currently working only with Tetra_VEF (3D) or Tri_VEF (2D)." << finl;
1058 Process::exit();
1059 }
1060
1061 // Determination du type de CL selon le rang
1062 rang = rang_elem_non_std(poly);
1063 int itypcl = (rang==-1 ? 0 : domaine_Cl_VEF.type_elem_Cl(rang));
1064
1065 // calcul de vc (a l'intersection des 3 facettes) vc vs vsom
1066 calcul_vc(face,vc,vs,vsom,state_field,itypcl);
1067 calcul_vc(face,vc_inco,vs_inco,vsom_inco,inco,itypcl);
1068
1069
1070 // Boucle sur les facettes du polyedre non standard:
1071 for (fa7=0; fa7<nfa7; fa7++)
1072 {
1073 num10 = face[KEL(0,fa7)];
1074 num20 = face[KEL(1,fa7)];
1075
1076 // normales aux facettes
1077 if (rang==-1)
1078 for (i=0; i<dimension; i++)
1079 cc[i] = facette_normales(poly, fa7, i);
1080 else
1081 for (i=0; i<dimension; i++)
1082 cc[i] = normales_facettes_Cl(rang,fa7,i);
1083
1084 // Calcul des vitesses en C,S,S2 les 3 extremites de la fa7 et M le centre de la fa7
1085 double psc_c=0,psc_s=0,psc_m,psc_s2=0;
1086 double psc_c_inco=0,psc_s_inco=0,psc_m_inco=0;
1087 if (dimension==2)
1088 {
1089 for (i=0; i<2; i++)
1090 {
1091 psc_c+=vc[i]*cc[i];
1092 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
1093 psc_c_inco+=vc_inco[i]*cc[i];
1094 psc_s_inco+=vsom_inco(KEL(2,fa7),i)*cc[i];
1095
1096 }
1097 psc_m=(psc_c+psc_s)/2.;
1098 psc_m_inco=(psc_c_inco+psc_s_inco)/2.;
1099 }
1100 else
1101 {
1102 for (i=0; i<3; i++)
1103 {
1104 psc_c+=vc[i]*cc[i];
1105 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
1106 psc_s2+=vsom(KEL(3,fa7),i)*cc[i];
1107 }
1108 psc_m=(psc_c+psc_s+psc_s2)/3.;
1109 }
1110 // On applique les CL de Dirichlet si num1 ou num2 est une face avec CL de Dirichlet
1111 // auquel cas la fa7 coincide avec la face num1 ou num2 -> C est au centre de la face
1112 if (option_appliquer_cl_dirichlet)
1114 {
1115 psc_m = psc_c;
1116 psc_m_inco = psc_c_inco;
1117 }
1118 // Determination de la face amont pour M
1119 int face_amont_m;
1120 if(false) Cout<<psc_m_inco<<finl;
1121 if (psc_m >= 0)
1122 //if (psc_m_inco >= 0)
1123 {
1124 face_amont_m = num10;
1125 }
1126 else
1127 {
1128 face_amont_m = num20;
1129 }
1130
1131 for (comp0=0; comp0<ncomp_ch_transporte; comp0++)
1132 {
1133 double flux;
1134 double inco_m = (ncomp_ch_transporte==1?inco(face_amont_m):inco(face_amont_m,comp0));
1135 flux = inco_m*psc_m;
1136
1137 if (ncomp_ch_transporte == 1)
1138 {
1139 resu(num10) -= flux;
1140 resu(num20) += flux;
1141 if (num10<nb_faces_bord) flux_b(num10,0) += flux;
1142 if (num20<nb_faces_bord) flux_b(num20,0) -= flux;
1143 }
1144 else
1145 {
1146 resu(num10,comp0) -= flux;
1147 resu(num20,comp0) += flux;
1148 if (num10<nb_faces_bord) flux_b(num10,comp0) += flux;
1149 if (num20<nb_faces_bord) flux_b(num20,comp0) -= flux;
1150 }
1151
1152 }// boucle sur comp
1153 } // fin de la boucle sur les facettes
1154 }
1155 } // fin de la boucle
1157 int voisine;
1158 nb_faces_perio = 0;
1159 double diff1,diff2;
1160
1161 // Boucle sur les bords pour traiter les conditions aux limites
1162 // il y a prise en compte d'un terme de convection pour les
1163 // conditions aux limites de Neumann_sortie_libre seulement
1164 for (n_bord=0; n_bord<nb_bord; n_bord++)
1165 {
1166 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1167
1168 if (sub_type(Neumann_sortie_libre,la_cl.valeur()))
1169 {
1170 const Neumann_sortie_libre& la_sortie_libre = ref_cast(Neumann_sortie_libre, la_cl.valeur());
1171 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1172 int num1 = le_bord.num_premiere_face();
1173 int num2 = num1 + le_bord.nb_faces();
1174 for (num_face=num1; num_face<num2; num_face++)
1175 {
1176 psc =0.;
1177 psc_inco = 0.;
1178 for (i=0; i<dimension; i++)
1179 {
1180 psc += state_field(num_face,i)*facenormales(num_face,i);
1181 psc_inco += inco(num_face,i)*facenormales(num_face,i);
1182 }
1183 if (psc>0)
1184 if (ncomp_ch_transporte == 1)
1185 {
1186 resu(num_face) -= psc*inco(num_face);
1187 flux_b(num_face,0) -= psc*inco(num_face);
1188 }
1189 else
1190 for (i=0; i<ncomp_ch_transporte; i++)
1191 {
1192 resu(num_face,i) -= psc*inco(num_face,i);
1193 flux_b(num_face,i) -= psc*inco(num_face,i);
1194 }
1195 else
1196 {
1197 if (ncomp_ch_transporte == 1)
1198 {
1199 resu(num_face) -= psc_inco*la_sortie_libre.val_ext(num_face-num1);
1200 flux_b(num_face,0) -= psc_inco*la_sortie_libre.val_ext(num_face-num1);
1201 }
1202 else
1203 for (i=0; i<ncomp_ch_transporte; i++)
1204 {
1205 resu(num_face,i) -= psc_inco*la_sortie_libre.val_ext(num_face-num1,i);
1206 flux_b(num_face,i) -= psc_inco*la_sortie_libre.val_ext(num_face-num1,i);
1207 }
1208 }
1209 }
1210 }
1211 else if (sub_type(Periodique,la_cl.valeur()))
1212 {
1213 const Periodique& la_cl_perio = ref_cast(Periodique, la_cl.valeur());
1214 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1215 int num1 = le_bord.num_premiere_face();
1216 int num2 = num1 + le_bord.nb_faces();
1217 ArrOfInt fait(le_bord.nb_faces());
1218 fait = 0;
1219 for (num_face=num1; num_face<num2; num_face++)
1220 {
1221 if (fait[num_face-num1] == 0)
1222 {
1223 voisine = la_cl_perio.face_associee(num_face-num1) + num1;
1224
1225 if (ncomp_ch_transporte == 1)
1226 {
1227 diff1 = resu(num_face)-tab(nb_faces_perio);
1228 diff2 = resu(voisine)-tab(nb_faces_perio+voisine-num_face);
1229 resu(voisine) += diff1;
1230 resu(num_face) += diff2;
1231 }
1232 else
1233 for (int comp=0; comp<ncomp_ch_transporte; comp++)
1234 {
1235 diff1 = resu(num_face,comp)-tab(nb_faces_perio,comp);
1236 diff2 = resu(voisine,comp)-tab(nb_faces_perio+voisine-num_face,comp);
1237 resu(voisine,comp) += diff1;
1238 resu(num_face,comp) += diff2;
1239 }
1240
1241 fait[num_face-num1]= 1;
1242 fait[voisine-num1] = 1;
1243 }
1244 nb_faces_perio++;
1245 }
1246 }
1247 }
1248}
1249//inco grad_state_field
1250void Operateur_Conv_sensibility_VEF::ajouter_Lsensibility_state_Amont(const DoubleTab& inco, const DoubleTab& state_field, DoubleTab& resu ) const
1251{
1252 Cout<<"ajouter_Lsensibility_state "<<finl;
1253 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
1254 const Domaine_VEF& domaine_VEF = ref_cast(Domaine_VEF, le_dom_vef.valeur());
1255 const IntTab& elem_faces = domaine_VEF.elem_faces();
1256 const DoubleTab& facenormales = domaine_VEF.face_normales();
1257 const auto& facette_normales = domaine_VEF.facette_normales();
1258 const Domaine& domaine = domaine_VEF.domaine();
1259 const int nfa7 = domaine_VEF.type_elem().nb_facette();
1260 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
1261 const IntVect& rang_elem_non_std = domaine_VEF.rang_elem_non_std();
1262 const DoubleTab& normales_facettes_Cl = domaine_Cl_VEF.normales_facettes_Cl();
1263 int nfac = domaine.nb_faces_elem();
1264 int nsom = domaine.nb_som_elem();
1265 int nb_bord = domaine_VEF.nb_front_Cl();
1266 const IntTab& les_elems=domaine.les_elems();
1267 int option_appliquer_cl_dirichlet = 0 ;
1268
1269
1270 // Definition d'un tableau pour un traitement special des schemas pres des bords
1271 if (traitement_pres_bord_.size_array()!=nb_elem_tot)
1272 {
1273 traitement_pres_bord_.resize_array(nb_elem_tot);
1275 ArrOfInt est_un_sommet_de_bord_(domaine_VEF.nb_som_tot());
1276 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1277 {
1278 const Cond_lim_base& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord).valeur();
1279 if ( sub_type(Dirichlet,la_cl) || sub_type(Dirichlet_homogene,la_cl) )
1280 {
1281 const Front_VF& le_bord = ref_cast(Front_VF,la_cl.frontiere_dis());
1282 int nb_faces_tot = le_bord.nb_faces_tot();
1283 int size = domaine_VEF.face_sommets().dimension(1);
1284 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
1285 for (int som=0; som<size; som++)
1286 {
1287 int face = le_bord.num_face(ind_face);
1288 est_un_sommet_de_bord_[domaine_VEF.face_sommets(face,som)]=1;
1289 }
1290 }
1291 }
1292 for (int elem=0; elem<nb_elem_tot; elem++)
1293 {
1294 if (rang_elem_non_std(elem)!=-1)
1295 traitement_pres_bord_[elem]=1;
1296 else
1297 {
1298 for (int n_som=0; n_som<nsom; n_som++)
1299 if (est_un_sommet_de_bord_[les_elems(elem,n_som)])
1300 traitement_pres_bord_[elem]=1;
1301 }
1302 }
1303
1304 // Construction du tableau est_une_face_de_dirichlet_
1305 est_une_face_de_dirichlet_.resize_array(domaine_VEF.nb_faces_tot());
1307 for (int n_bord=0; n_bord<nb_bord; n_bord++)
1308 {
1309 const Cond_lim_base& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord).valeur();
1310 if ( sub_type(Dirichlet,la_cl) || sub_type(Dirichlet_homogene,la_cl) )
1311 {
1312 const Front_VF& le_bord = ref_cast(Front_VF,la_cl.frontiere_dis());
1313 int nb_faces_tot = le_bord.nb_faces_tot();
1314 for (int ind_face=0; ind_face<nb_faces_tot; ind_face++)
1315 {
1316 int num_face = le_bord.num_face(ind_face);
1317 est_une_face_de_dirichlet_[num_face] = 1;
1318 }
1319 }
1320 }
1321 }
1322
1323 // Pour le traitement de la convection on distingue les polyedres
1324 // standard qui ne "voient" pas les conditions aux limites et les
1325 // polyedres non standard qui ont au moins une face sur le bord.
1326 // Un polyedre standard a n facettes sur lesquelles on applique le
1327 // schema de convection.
1328 // Pour un polyedre non standard qui porte des conditions aux limites
1329 // de Dirichlet, une partie des facettes sont portees par les faces.
1330 // En bref pour un polyedre le traitement de la convection depend
1331 // du type (triangle, tetraedre ...) et du nombre de faces de Dirichlet.
1332
1333 const Elem_VEF_base& type_elemvef= domaine_VEF.type_elem();
1334 int istetra=0;
1335 Nom nom_elem=type_elemvef.que_suis_je();
1336 if ((nom_elem=="Tetra_VEF")||(nom_elem=="Tri_VEF"))
1337 istetra=1;
1338
1339 double psc;
1340 int poly,face_adj,fa7,i,j,n_bord;
1341 int num_face, rang;
1342 int num10,num20;
1343 int ncomp_ch_transporte=(state_field.nb_dim() == 1?1:state_field.dimension(1));
1344
1345 // Traitement particulier pour les faces de periodicite
1346 int nb_faces_perio = 0;
1347 for (n_bord=0; n_bord<nb_bord; n_bord++)
1348 {
1349 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1350 if (sub_type(Periodique,la_cl.valeur()))
1351 {
1352 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1353 nb_faces_perio+=le_bord.nb_faces();
1354 }
1355 }
1356
1357 DoubleTab tab;
1358 if (ncomp_ch_transporte == 1)
1359 tab.resize(nb_faces_perio);
1360 else
1361 tab.resize(nb_faces_perio,ncomp_ch_transporte);
1362
1363 nb_faces_perio=0;
1364 for (n_bord=0; n_bord<nb_bord; n_bord++)
1365 {
1366 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1367 if (sub_type(Periodique,la_cl.valeur()))
1368 {
1369 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1370 int num1 = le_bord.num_premiere_face();
1371 int num2 = num1 + le_bord.nb_faces();
1372 for (num_face=num1; num_face<num2; num_face++)
1373 {
1374 if (ncomp_ch_transporte == 1)
1375 tab(nb_faces_perio) = resu(num_face);
1376 else
1377 for (int comp=0; comp<ncomp_ch_transporte; comp++)
1378 tab(nb_faces_perio,comp) = resu(num_face,comp);
1379 nb_faces_perio++;
1380 }
1381 }
1382 }
1383
1384 int comp0;
1385 int nb_faces_ = domaine_VEF.nb_faces();
1386 ArrOfInt face(nfac);
1387 ArrOfDouble vs(dimension);
1388 ArrOfDouble vs_state(dimension);
1389 ArrOfDouble vc(dimension);
1390 ArrOfDouble vc_state(dimension);
1391 ArrOfDouble cc(dimension);
1392 //DoubleVect xc(dimension);
1393 DoubleTab vsom(nsom,dimension);
1394 DoubleTab vsom_state(nsom,dimension);
1395 //DoubleTab xsom(nsom,dimension);
1396
1397
1398 // Dimensionnement du tableau des flux convectifs au bord du domaine de calcul
1399 DoubleTab& flux_b = flux_bords_;
1400 int nb_faces_bord=domaine_VEF.nb_faces_bord();
1401 flux_b.resize(nb_faces_bord,ncomp_ch_transporte);
1402 flux_b = 0.;
1403
1404 const IntTab& KEL=type_elemvef.KEL();
1405
1406 // Les polyedres non standard sont ranges en 2 groupes dans le Domaine_VEF:
1407 // - polyedres bords et joints
1408 // - polyedres bords et non joints
1409 // On traite les polyedres en suivant l'ordre dans lequel ils figurent
1410 // dans le domaine
1411 // boucle sur les polys
1412
1413 for (poly=0; poly<nb_elem_tot; poly++)
1414 {
1415 int contrib = 0;
1416 // calcul des numeros des faces du polyedre
1417 for (face_adj=0; face_adj<nfac; face_adj++)
1418 {
1419 int face_ = elem_faces(poly,face_adj);
1420 face[face_adj]= face_;
1421 if (face_<nb_faces_) contrib=1; // Une face reelle sur l'element virtuel
1422 }
1423 //
1424 if (contrib)
1425 {
1426 for (j=0; j<dimension; j++)
1427 {
1428 vs[j] = inco(face[0],j);
1429 vs_state[j] = state_field(face[0],j);
1430 for (i=1; i<nfac; i++)
1431 {
1432 vs[j]+= inco(face[i],j);
1433 vs_state[j] = state_field(face[i],j);
1434 }
1435 }
1436 // calcul de la vitesse aux sommets des polyedres
1437 if (istetra==1)
1438 {
1439 for (i=0; i<nsom; i++)
1440 for (j=0; j<dimension; j++)
1441 {
1442 vsom(i,j) = (vs[j] - dimension*inco(face[i],j));
1443 vsom_state(i,j) = (vs_state[j] - dimension*state_field(face[i],j));
1444 }
1445 }
1446 else
1447 {
1448 Cout << "Sensibility is currently working only with Tetra_VEF (3D) or Tri_VEF (2D)." << finl;
1449 Process::exit();
1450 }
1451
1452 // Determination du type de CL selon le rang
1453 rang = rang_elem_non_std(poly);
1454 int itypcl = (rang==-1 ? 0 : domaine_Cl_VEF.type_elem_Cl(rang));
1455
1456 // calcul de vc (a l'intersection des 3 facettes) vc vs vsom
1457 calcul_vc(face,vc,vs,vsom,inco,itypcl);
1458 calcul_vc(face,vc_state,vs_state,vsom_state,state_field,itypcl);
1459
1460 // Boucle sur les facettes du polyedre non standard:
1461 for (fa7=0; fa7<nfa7; fa7++)
1462 {
1463 num10 = face[KEL(0,fa7)];
1464 num20 = face[KEL(1,fa7)];
1465
1466 // normales aux facettes
1467 if (rang==-1)
1468 for (i=0; i<dimension; i++)
1469 cc[i] = facette_normales(poly, fa7, i);
1470 else
1471 for (i=0; i<dimension; i++)
1472 cc[i] = normales_facettes_Cl(rang,fa7,i);
1473
1474 // Calcul des vitesses en C,S,S2 les 3 extremites de la fa7 et M le centre de la fa7
1475 double psc_c=0,psc_s=0,psc_m,psc_s2=0;
1476 double psc_m_state=0.,psc_c_state=0.,psc_s_state=0.;
1477 if (dimension==2)
1478 {
1479 for (i=0; i<2; i++)
1480 {
1481 psc_c+=vc[i]*cc[i];
1482 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
1483 psc_c_state+=vc_state[i]*cc[i];
1484 psc_s_state+=vsom_state(KEL(2,fa7),i)*cc[i];
1485
1486 }
1487 psc_m=(psc_c+psc_s)/2.;
1488 psc_m_state=(psc_c_state+psc_s_state)/2.;
1489 }
1490 else
1491 {
1492 for (i=0; i<3; i++)
1493 {
1494 psc_c+=vc[i]*cc[i];
1495 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
1496 psc_s2+=vsom(KEL(3,fa7),i)*cc[i];
1497 }
1498 psc_m=(psc_c+psc_s+psc_s2)/3.;
1499 }
1500 // On applique les CL de Dirichlet si num1 ou num2 est une face avec CL de Dirichlet
1501 // auquel cas la fa7 coincide avec la face num1 ou num2 -> C est au centre de la face
1502 //int appliquer_cl_dirichlet=0;
1503 if (option_appliquer_cl_dirichlet)
1505 {
1506 //appliquer_cl_dirichlet = 1;
1507 psc_m = psc_c;
1508 psc_m_state = psc_c_state;
1509 }
1510
1511 // Determination de la face amont pour M
1512 int face_amont_m;
1513 if(false) Cout<<psc_m_state<<finl;
1514 if (psc_m >= 0)
1515 //if (psc_m_state >= 0)
1516 {
1517 face_amont_m = num10;
1518 }
1519 else
1520 {
1521 face_amont_m = num20;
1522 }
1523
1524 for (comp0=0; comp0<ncomp_ch_transporte; comp0++)
1525 {
1526 double flux;
1527 double inco_m = (ncomp_ch_transporte==1?state_field(face_amont_m):state_field(face_amont_m,comp0));
1528
1529 flux = inco_m*psc_m;
1530
1531 if (ncomp_ch_transporte == 1)
1532 {
1533 resu(num10) -= flux;
1534 resu(num20) += flux;
1535 if (num10<nb_faces_bord) flux_b(num10,0) += flux;
1536 if (num20<nb_faces_bord) flux_b(num20,0) -= flux;
1537 }
1538 else
1539 {
1540 resu(num10,comp0) -= flux;
1541 resu(num20,comp0) += flux;
1542 if (num10<nb_faces_bord) flux_b(num10,0) += flux;
1543 if (num20<nb_faces_bord) flux_b(num20,0) -= flux;
1544 }
1545
1546 }// boucle sur comp
1547 } // fin de la boucle sur les facettes
1548 }
1549 } // fin de la boucle
1551 int voisine;
1552 nb_faces_perio = 0;
1553 double diff1,diff2;
1554
1555 // Boucle sur les bords pour traiter les conditions aux limites
1556 // il y a prise en compte d'un terme de convection pour les
1557 // conditions aux limites de Neumann_sortie_libre seulement
1558 for (n_bord=0; n_bord<nb_bord; n_bord++)
1559 {
1560 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1561
1562 if (sub_type(Neumann_sortie_libre,la_cl.valeur()))
1563 {
1564 const Neumann_sortie_libre& la_sortie_libre = ref_cast(Neumann_sortie_libre, la_cl.valeur());
1565 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1566 int num1 = le_bord.num_premiere_face();
1567 int num2 = num1 + le_bord.nb_faces();
1568 for (num_face=num1; num_face<num2; num_face++)
1569 {
1570 psc =0;
1571 for (i=0; i<dimension; i++)
1572 psc += inco(num_face,i)*facenormales(num_face,i);
1573 if (psc>0)
1574 if (ncomp_ch_transporte == 1)
1575 {
1576 resu(num_face) -= psc*state_field(num_face);
1577 flux_b(num_face,0) -= psc*state_field(num_face);
1578 }
1579 else
1580 for (i=0; i<ncomp_ch_transporte; i++)
1581 {
1582 resu(num_face,i) -= psc*state_field(num_face,i);
1583 flux_b(num_face,i) -= psc*state_field(num_face,i);
1584 }
1585 else
1586 {
1587 if (ncomp_ch_transporte == 1)
1588 {
1589 resu(num_face) -= psc*la_sortie_libre.val_ext(num_face-num1);
1590 flux_b(num_face) -= psc*la_sortie_libre.val_ext(num_face-num1);
1591 }
1592 else
1593 for (i=0; i<ncomp_ch_transporte; i++)
1594 {
1595 resu(num_face,i) -= psc*la_sortie_libre.val_ext(num_face-num1,i);
1596 flux_b(num_face,i) -= psc*la_sortie_libre.val_ext(num_face-num1,i);
1597 }
1598 }
1599 }
1600 }
1601 else if (sub_type(Periodique,la_cl.valeur()))
1602 {
1603 const Periodique& la_cl_perio = ref_cast(Periodique, la_cl.valeur());
1604 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1605 int num1 = le_bord.num_premiere_face();
1606 int num2 = num1 + le_bord.nb_faces();
1607 ArrOfInt fait(le_bord.nb_faces());
1608 fait = 0;
1609 for (num_face=num1; num_face<num2; num_face++)
1610 {
1611 if (fait[num_face-num1] == 0)
1612 {
1613 voisine = la_cl_perio.face_associee(num_face-num1) + num1;
1614
1615 if (ncomp_ch_transporte == 1)
1616 {
1617 diff1 = resu(num_face)-tab(nb_faces_perio);
1618 diff2 = resu(voisine)-tab(nb_faces_perio+voisine-num_face);
1619 resu(voisine) += diff1;
1620 resu(num_face) += diff2;
1621 }
1622 else
1623 for (int comp=0; comp<ncomp_ch_transporte; comp++)
1624 {
1625 diff1 = resu(num_face,comp)-tab(nb_faces_perio,comp);
1626 diff2 = resu(voisine,comp)-tab(nb_faces_perio+voisine-num_face,comp);
1627 resu(voisine,comp) += diff1;
1628 resu(num_face,comp) += diff2;
1629 }
1630
1631 fait[num_face-num1]= 1;
1632 fait[voisine-num1] = 1;
1633 }
1634 nb_faces_perio++;
1635 }
1636 }
1637 }
1638}
1639
1640
1641void Operateur_Conv_sensibility_VEF::calcul_vc(const ArrOfInt& Face, ArrOfDouble& vc, const ArrOfDouble& vs, const DoubleTab& vsom,
1642 const DoubleTab& vitesse_face,int type_cl) const
1643{
1644// Operateur_Conv_sensibility_VEF::calcul_vc(...) is based on Tetra_VEF::calcul_vc(...) and on Tri_VEF::calcul_vc(...).
1645 if (dimension == 2) //Tri_VEF
1646 {
1647
1648 switch(type_cl)
1649 {
1650 case 0: // le triangle n'a pas de Face de Dirichlet
1651 {
1652 vc[0] = vs[0]/3;
1653 vc[1] = vs[1]/3;
1654 break;
1655 }
1656
1657 case 1: // le triangle a une Face de Dirichlet :la Face 2
1658 {
1659 vc[0]= vitesse_face(Face[2],0);
1660 vc[1]= vitesse_face(Face[2],1);
1661 break;
1662 }
1663
1664 case 2: // le triangle a une Face de Dirichlet :la Face 1
1665 {
1666 vc[0]= vitesse_face(Face[1],0);
1667 vc[1]= vitesse_face(Face[1],1);
1668 break;
1669 }
1670
1671 case 4: // le triangle a une Face de Dirichlet :la Face 0
1672 {
1673 vc[0]= vitesse_face(Face[0],0);
1674 vc[1]= vitesse_face(Face[0],1);
1675 break;
1676 }
1677
1678 case 3: // le triangle a deux faces de Dirichlet :les faces 1 et 2
1679 {
1680 vc[0]= vsom(0,0);
1681 vc[1]= vsom(0,1);
1682 break;
1683 }
1684
1685 case 5: // le triangle a deux faces de Dirichlet :les faces 0 et 2
1686 {
1687 vc[0]= vsom(1,0);
1688 vc[1]= vsom(1,1);
1689 break;
1690 }
1691
1692 case 6: // le triangle a deux faces de Dirichlet :les faces 0 et 1
1693 {
1694 vc[0]= vsom(2,0);
1695 vc[1]= vsom(2,1);
1696 break;
1697 }
1698
1699 } // switch end
1700
1701 } // 2D end
1702
1703 else if (dimension == 3) //Tetra_VEF
1704 {
1705
1706 int comp;
1707 switch(type_cl)
1708 {
1709
1710 case 0: // le tetraedre n'a pas de Face de Dirichlet
1711 {
1712 for (comp=0; comp<3; comp++)
1713 vc[comp] = 0.25*vs[comp];
1714 break;
1715 }
1716
1717 case 1: // le tetraedre a une Face de Dirichlet : KEL3
1718 {
1719 for (comp=0; comp<3; comp++)
1720 vc[comp] = vitesse_face(Face[3],comp);
1721 break;
1722 }
1723
1724 case 2: // le tetraedre a une Face de Dirichlet : KEL2
1725 {
1726 for (comp=0; comp<3; comp++)
1727 vc[comp] = vitesse_face(Face[2],comp);
1728 break;
1729 }
1730
1731 case 4: // le tetraedre a une Face de Dirichlet : KEL1
1732 {
1733 for (comp=0; comp<3; comp++)
1734 vc[comp] = vitesse_face(Face[1],comp);
1735 break;
1736 }
1737
1738 case 8: // le tetraedre a une Face de Dirichlet : KEL0
1739 {
1740 for (comp=0; comp<3; comp++)
1741 vc[comp] = vitesse_face(Face[0],comp);
1742 break;
1743 }
1744
1745 case 3: // le tetraedre a deux faces de Dirichlet : KEL3 et KEL2
1746 {
1747 for (comp=0; comp<3; comp++)
1748 vc[comp] = 0.5* (vsom(0,comp) + vsom(1,comp));
1749 break;
1750 }
1751
1752 case 5: // le tetraedre a deux faces de Dirichlet : KEL3 et KEL1
1753 {
1754 for (comp=0; comp<3; comp++)
1755 vc[comp] = 0.5* (vsom(0,comp) + vsom(2,comp));
1756 break;
1757 }
1758
1759 case 6: // le tetraedre a deux faces de Dirichlet : KEL1 et KEL2
1760 {
1761 for (comp=0; comp<3; comp++)
1762 vc[comp] = 0.5* (vsom(0,comp) + vsom(3,comp));
1763 break;
1764 }
1765
1766 case 9: // le tetraedre a deux faces de Dirichlet : KEL0 et KEL3
1767 {
1768 for (comp=0; comp<3; comp++)
1769 vc[comp] = 0.5* (vsom(1,comp) + vsom(2,comp));
1770 break;
1771 }
1772
1773 case 10: // le tetraedre a deux faces de Dirichlet : KEL0 et KEL2
1774 {
1775 for (comp=0; comp<3; comp++)
1776 vc[comp] = 0.5* (vsom(1,comp) + vsom(3,comp));
1777 break;
1778 }
1779
1780 case 12: // le tetraedre a deux faces de Dirichlet : KEL0 et KEL1
1781 {
1782 for (comp=0; comp<3; comp++)
1783 vc[comp] = 0.5*(vsom(2,comp) + vsom(3,comp));
1784 break;
1785 }
1786
1787 case 7: // le tetraedre a trois faces de Dirichlet : KEL1, KEL2 et KEL3
1788 {
1789 for (comp=0; comp<3; comp++)
1790 vc[comp] = vsom(0,comp);
1791 break;
1792 }
1793
1794 case 11: // le tetraedre a trois faces de Dirichlet : KEL0,KEL2 et KEL3
1795 {
1796 for (comp=0; comp<3; comp++)
1797 vc[comp] = vsom(1,comp);
1798 break;
1799 }
1800
1801 case 13: // le tetraedre a trois faces de Dirichlet : KEL0, KEL1 et KEL3
1802 {
1803 for (comp=0; comp<3; comp++)
1804 vc[comp] = vsom(2,comp);
1805 break;
1806 }
1807
1808 case 14: // le tetraedre a trois faces de Dirichlet : KEL0, KEL1 et KEL2
1809 {
1810 for (comp=0; comp<3; comp++)
1811 vc[comp] = vsom(3,comp);
1812 break;
1813 }
1814
1815 } // switch end
1816
1817 } // 3D end
1818}
1819void Operateur_Conv_sensibility_VEF::remplir_fluent(DoubleVect& tab_fluent) const
1820{
1821
1822 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
1823 const Domaine_VEF& domaine_VEF = ref_cast(Domaine_VEF, le_dom_vef.valeur());
1824 const Champ_Inc_base& velocity=vitesse();
1825 const DoubleTab& vitesse_face=velocity.valeurs();
1826 const IntTab& elem_faces = domaine_VEF.elem_faces();
1827 const DoubleTab& face_normales = domaine_VEF.face_normales();
1828 const auto& facette_normales = domaine_VEF.facette_normales();
1829 const Domaine& domaine = domaine_VEF.domaine();
1830 const int nfa7 = domaine_VEF.type_elem().nb_facette();
1831 const int nb_elem_tot = domaine_VEF.nb_elem_tot();
1832 const IntVect& rang_elem_non_std = domaine_VEF.rang_elem_non_std();
1833 const DoubleTab& normales_facettes_Cl = domaine_Cl_VEF.normales_facettes_Cl();
1834 int nfac = domaine.nb_faces_elem();
1835 int nsom = domaine.nb_som_elem();
1836 const IntTab& sommet_elem = domaine.les_elems();
1837 DoubleVect& fluent_ = tab_fluent;
1838
1839
1840 const Elem_VEF_base& type_elemvef= domaine_VEF.type_elem();
1841 int istetra=0;
1842 Nom nom_elem=type_elemvef.que_suis_je();
1843 if ((nom_elem=="Tetra_VEF")||(nom_elem=="Tri_VEF"))
1844 istetra=1;
1845
1846
1847 double psc;
1848 int poly,face_adj,fa7,i,j,n_bord;
1849 int num_face, rang ,itypcl;
1850 int num1,num2,num_som;
1851
1852 ArrOfInt face(nfac);
1853 ArrOfDouble vs(dimension);
1854 ArrOfDouble vc(dimension);
1855 DoubleTab vsom(nsom,dimension);
1856 ArrOfDouble cc(dimension);
1857
1858 // Dimensionnement du tableau des flux convectifs au bord du domaine de calcul
1859 const IntTab& KEL=type_elemvef.KEL();
1860
1861 // On remet a zero le tableau qui sert pour
1862 // le calcul du pas de temps de stabilite
1863 fluent_ = 0;
1864
1865 // Les polyedres non standard sont ranges en 2 groupes dans le Domaine_VEF:
1866 // - polyedres bords et joints
1867 // - polyedres bords et non joints
1868 // On traite les polyedres en suivant l'ordre dans lequel ils figurent
1869 // dans le domaine
1870
1871 // boucle sur les polys
1872 for (poly=0; poly<nb_elem_tot; poly++)
1873 {
1874 rang = rang_elem_non_std(poly);
1875 // On cherche, pour un elem qui n'est pas de bord (rang==-1),
1876 // si un des sommets est sur un bord (tableau des sommets) (C MALOD 17/07/2007)
1877
1878 if (rang==-1)
1879 itypcl=0;
1880 else
1881 itypcl=domaine_Cl_VEF.type_elem_Cl(rang);
1882
1883 // calcul des numeros des faces du polyedre
1884 for (face_adj=0; face_adj<nfac; face_adj++)
1885 face[face_adj]= elem_faces(poly,face_adj);
1886
1887 for (j=0; j<dimension; j++)
1888 {
1889 vs[j] = vitesse_face(face[0],j);
1890 for (i=1; i<nfac; i++)
1891 vs[j]+= vitesse_face(face[i],j);
1892 }
1893 // calcul de la vitesse aux sommets des polyedres
1894 if (istetra==1)
1895 {
1896 for (i=0; i<nsom; i++)
1897 for (j=0; j<dimension; j++)
1898 vsom(i,j) = (vs[j] - dimension*vitesse_face(face[i],j));
1899 }
1900 else
1901 {
1902 // pour que cela soit valide avec les hexa (c'est + lent a calculer...)
1903 int ncomp;
1904 for (j=0; j<nsom; j++)
1905 {
1906 num_som = sommet_elem(poly,j);
1907 for (ncomp=0; ncomp<dimension; ncomp++)
1908 vsom(j,ncomp) =velocity.valeur_a_sommet_compo(num_som,poly,ncomp);
1909 }
1910 }
1911
1912 // calcul de vc (a l'intersection des 3 facettes) vc vs vsom proportionnelles a la prosite
1913 calcul_vc(face,vc,vs,vsom,vitesse().valeurs(),itypcl);
1914 // Boucle sur les facettes du polyedre non standard:
1915 for (fa7=0; fa7<nfa7; fa7++)
1916 {
1917 num1 = face[KEL(0,fa7)];
1918 num2 = face[KEL(1,fa7)];
1919 // normales aux facettes
1920 if (rang==-1)
1921 {
1922 for (i=0; i<dimension; i++)
1923 cc[i] = facette_normales(poly, fa7, i);
1924 }
1925 else
1926 {
1927 for (i=0; i<dimension; i++)
1928 cc[i] = normales_facettes_Cl(rang,fa7,i);
1929 }
1930 // On applique le schema de convection a chaque sommet de la facette
1931
1932 double psc_c=0,psc_s=0,psc_m,psc_s2=0;
1933 if (dimension==2)
1934 {
1935 for (i=0; i<dimension; i++)
1936 {
1937 psc_c+=vc[i]*cc[i];
1938 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
1939 }
1940 psc_m=(psc_c+psc_s)/2.;
1941 }
1942 else
1943 {
1944 for (i=0; i<dimension; i++)
1945 {
1946 psc_c+=vc[i]*cc[i];
1947 psc_s+=vsom(KEL(2,fa7),i)*cc[i];
1948 psc_s2+=vsom(KEL(3,fa7),i)*cc[i];
1949 }
1950 psc_m=(psc_c+psc_s+psc_s2)/3.;
1951 }
1952
1953 // int amont,dir;
1954 if (psc_m >= 0)
1955 {
1956 // amont = num1;
1957 fluent_(num2) += psc_m;
1958 //dir=0;
1959 }
1960 else
1961 {
1962 //amont = num2;
1963 fluent_(num1) -= psc_m;
1964 //dir=1;
1965 }
1966
1967 } // fin de la boucle sur les facettes
1968 } // fin de la boucle
1969
1970 // Boucle sur les bords pour traiter les conditions aux limites
1971 // il y a prise en compte d'un terme de convection pour les
1972 // conditions aux limites de Neumann_sortie_libre seulement
1973 int nb_bord = domaine_VEF.nb_front_Cl();
1974 for (n_bord=0; n_bord<nb_bord; n_bord++)
1975 {
1976 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
1977 if (sub_type(Neumann_sortie_libre,la_cl.valeur()))
1978 {
1979 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
1980 int num1b = le_bord.num_premiere_face();
1981 int num2b = num1b + le_bord.nb_faces();
1982 for (num_face=num1b; num_face<num2b; num_face++)
1983 {
1984 psc = 0;
1985 for (i=0; i<dimension; i++)
1986 psc += vitesse_face(num_face,i)*face_normales(num_face,i);
1987 if (psc>0)
1988 ;
1989 else
1990 fluent_(num_face) -= psc;
1991 }
1992 }
1993 }
1994}
1996{
1997 return 1e9; //on resout la sensibilite avec le meme dt que l'etat
1998}
1999
2000
2001
2002void Operateur_Conv_sensibility_VEF::add_diffusion_term(const DoubleTab& state, DoubleTab& resu) const
2003{
2004 Cerr << "add_diffusion_term" << finl;
2005 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
2006 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
2007
2008 int nb_comp = 1;
2009 int nb_dim = resu.nb_dim();
2010 if(nb_dim==2)
2011 nb_comp=resu.dimension(1);
2012
2013 DoubleTab& tab_flux_bords = flux_bords_;
2014
2015 const IntTab& elemfaces = domaine_VEF.elem_faces();
2016 const IntTab& face_voisins = domaine_VEF.face_voisins();
2017 int i0,j,num_face;
2018 int nb_faces = domaine_VEF.nb_faces();
2019 int nb_faces_elem = domaine_VEF.domaine().nb_faces_elem();
2020 int n_bord0;
2021 double valA;//,flux;
2022 //DoubleVect n(Objet_U::dimension);
2023 //DoubleTrav Tgrad(Objet_U::dimension,Objet_U::dimension);
2024
2025 // On dimensionne et initialise le tableau des bilans de flux:
2026 tab_flux_bords.resize(domaine_VEF.nb_faces_bord(),nb_comp);
2027 tab_flux_bords=0.;
2028
2029 assert(nb_comp>1);
2030 int nb_bords=domaine_VEF.nb_front_Cl();
2031 int ind_face;
2032
2033 for (n_bord0=0; n_bord0<nb_bords; n_bord0++)
2034 {
2035 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord0);
2036 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2037 // const IntTab& elemfaces = domaine_VEF.elem_faces();
2038 int num1 = 0;
2039 int num2 = le_bord.nb_faces_tot();
2040 int nb_faces_bord_reel = le_bord.nb_faces();
2041
2042 if (sub_type(Periodique,la_cl.valeur()))
2043 {
2044 const Periodique& la_cl_perio = ref_cast(Periodique,la_cl.valeur());
2045 int fac_asso;
2046 for (ind_face=num1; ind_face<nb_faces_bord_reel; ind_face++)
2047 {
2048 fac_asso = la_cl_perio.face_associee(ind_face);
2049 fac_asso = le_bord.num_face(fac_asso);
2050 num_face = le_bord.num_face(ind_face);
2051 for (int kk=0; kk<2; kk++)
2052 {
2053 int elem = face_voisins(num_face, kk);
2054 for (i0=0; i0<nb_faces_elem; i0++)
2055 {
2056 if ( ( (j= elemfaces(elem,i0)) > num_face ) && (j != fac_asso ) )
2057 {
2058 valA = viscA(num_face,j,elem);
2059 for (int nc=0; nc<nb_comp; nc++)
2060 {
2061 resu(num_face,nc)+=valA*state(j,nc);
2062 resu(num_face,nc)-=valA*state(num_face,nc);
2063 if(j<nb_faces) // face reelle
2064 {
2065 resu(j,nc)+=0.5*valA*state(num_face,nc);
2066 resu(j,nc)-=0.5*valA*state(j,nc);
2067 }
2068 }
2069 }
2070 }
2071 }
2072
2073 }
2074 }// fin if periodique
2075 else
2076 {
2077 for (ind_face=num1; ind_face<num2; ind_face++)
2078 {
2079 num_face = le_bord.num_face(ind_face);
2080 int elem=face_voisins(num_face,0);
2081
2082 // Boucle sur les faces :
2083 for (int i=0; i<nb_faces_elem; i++)
2084 if (( (j= elemfaces(elem,i)) > num_face ) || (ind_face>=nb_faces_bord_reel))
2085 {
2086 valA = viscA(num_face,j,elem);
2087 for (int nc=0; nc<nb_comp; nc++)
2088 {
2089 double flux=valA*(state(j,nc)-state(num_face,nc));
2090 if (ind_face<nb_faces_bord_reel)
2091 {
2092 resu(num_face,nc)+=flux;
2093 tab_flux_bords(num_face,nc)+=flux;
2094 }
2095
2096 if(j<nb_faces) // face reelle
2097 {
2098 resu(j,nc)-=flux;
2099 }
2100 }
2101 }
2102 }
2103 }
2104 }//Fin for n_bord
2105
2106 // On traite les faces internes
2107
2108 for (num_face=domaine_VEF.premiere_face_int(); num_face<nb_faces; num_face++)
2109 {
2110 for (int k=0; k<2; k++)
2111 {
2112 int elem = face_voisins(num_face,k);
2113 for (i0=0; i0<nb_faces_elem; i0++)
2114 {
2115 if ( (j= elemfaces(elem,i0)) > num_face )
2116 {
2117 int el1,el2;
2118 int contrib=1;
2119 if(j>=nb_faces) // C'est une face virtuelle
2120 {
2121 el1 = face_voisins(j,0);
2122 el2 = face_voisins(j,1);
2123 if((el1==-1)||(el2==-1))
2124 contrib=0;
2125 }
2126 if(contrib)
2127 {
2128 valA = viscA(num_face,j,elem);
2129 for (int nc=0; nc<nb_comp; nc++)
2130 {
2131 resu(num_face,nc)+=valA*state(j,nc);
2132 resu(num_face,nc)-=valA*state(num_face,nc);
2133 if(j<nb_faces) // On traite les faces reelles
2134 {
2135 resu(j,nc)+=valA*state(num_face,nc);
2136 resu(j,nc)-=valA*state(j,nc);
2137 }
2138 else
2139 {
2140 // La face j est virtuelle
2141 }
2142 }
2143 }
2144 }
2145 }
2146 }
2147 }// Fin faces internes
2148
2149 for (int n_bord=0; n_bord<nb_bords; n_bord++)
2150 {
2151 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
2152 if (sub_type(Symetrie,la_cl.valeur()))
2153 {
2154 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2155 int ndeb = le_bord.num_premiere_face();
2156 int nfin = ndeb + le_bord.nb_faces();
2157 for (int face=ndeb; face<nfin; face++)
2158 tab_flux_bords(face,0) = 0.;
2159 }
2160 }
2161
2162
2163}
2164
2165
2166inline double Operateur_Conv_sensibility_VEF::viscA(int i, int j, int num_elem, double diffu) const
2167{
2168 const Domaine_VEF& domaine=le_dom_vef.valeur();
2169 const IntTab& face_voisins=domaine.face_voisins();
2170 const DoubleTab& face_normales=domaine.face_normales();
2171 const DoubleVect& inverse_volumes=domaine.inverse_volumes();
2172 double pscal = face_normales(i,0)*face_normales(j,0)
2173 + face_normales(i,1)*face_normales(j,1);
2174 if (Objet_U::dimension == 3)
2175 pscal += face_normales(i,2)*face_normales(j,2);
2176
2177
2178 if ( (face_voisins(i,0) == face_voisins(j,0)) ||
2179 (face_voisins(i,1) == face_voisins(j,1)) )
2180 return -(pscal*diffu)*inverse_volumes(num_elem);
2181 else
2182 return (pscal*diffu)*inverse_volumes(num_elem);
2183}
2184
2185void Operateur_Conv_sensibility_VEF::add_diffusion_scalar_term(const DoubleTab& inconnue, DoubleTab& resu, double diffu) const
2186{
2187
2188 Cerr << "add_diffusion_scalar_term" << finl;
2189 const Domaine_Cl_VEF& domaine_Cl_VEF = la_zcl_vef.valeur();
2190 const Domaine_VEF& domaine_VEF = le_dom_vef.valeur();
2191 DoubleTab& tab_flux_bords = flux_bords_;
2192
2193 const IntTab& elemfaces = domaine_VEF.elem_faces();
2194 const IntTab& face_voisins = domaine_VEF.face_voisins();
2195 int i,j,num_face;
2196 int nb_faces = domaine_VEF.nb_faces();
2197 int nb_faces_elem = domaine_VEF.domaine().nb_faces_elem();
2198 double valA,flux;
2199 int n_bord, ind_face;
2200 int nb_bords=domaine_VEF.nb_front_Cl();
2201 // On dimensionne et initialise le tableau des bilans de flux:
2202 tab_flux_bords.resize(domaine_VEF.nb_faces_bord(),1);
2203 tab_flux_bords=0.;
2204 const int premiere_face_int=domaine_VEF.premiere_face_int();
2205
2206 // On traite les faces bord
2207 for (n_bord=0; n_bord<nb_bords; n_bord++)
2208 {
2209 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
2210 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2211 //const IntTab& elemfaces = domaine_VEF.elem_faces();
2212 int num1=0;
2213 int num2=le_bord.nb_faces_tot();
2214 int nb_faces_bord_reel = le_bord.nb_faces();
2215
2216 if (sub_type(Periodique,la_cl.valeur()))
2217 {
2218 const Periodique& la_cl_perio = ref_cast(Periodique,la_cl.valeur());
2219 int fac_asso;
2220 for (ind_face=num1; ind_face<nb_faces_bord_reel; ind_face++)
2221 {
2222 num_face = le_bord.num_face(ind_face);
2223 fac_asso = la_cl_perio.face_associee(ind_face);
2224 fac_asso = le_bord.num_face(fac_asso);
2225 for (int kk=0; kk<2; kk++)
2226 {
2227 int elem = face_voisins(num_face,kk);
2228 for (i=0; i<nb_faces_elem; i++)
2229 {
2230 if ( ( (j= elemfaces(elem,i)) > num_face ) && (j != fac_asso) )
2231 {
2232 valA = viscA(num_face,j,elem, diffu);
2233 resu(num_face)+=valA*inconnue(j);
2234 resu(num_face)-=valA*inconnue(num_face);
2235 if(j<nb_faces) // face reelle
2236 {
2237 resu(j)+=0.5*valA*inconnue(num_face);
2238 resu(j)-=0.5*valA*inconnue(j);
2239 }
2240 }
2241 }
2242 }
2243 }
2244 }
2245 else // Il n'y a qu'une seule composante, donc on traite
2246 // une equation scalaire (pas la vitesse) on a pas a utiliser
2247 // le tau tangentiel (les lois de paroi thermiques ne calculent pas
2248 // d'echange turbulent a la paroi pour l'instant
2249 {
2250 for (ind_face=num1; ind_face<num2; ind_face++)
2251 {
2252 num_face = le_bord.num_face(ind_face);
2253 int elem = face_voisins(num_face,0);
2254
2255 for (i=0; i<nb_faces_elem; i++)
2256 {
2257 if (( (j= elemfaces(elem,i)) > num_face ) || (ind_face>=nb_faces_bord_reel))
2258 {
2259 valA = viscA(num_face,j,elem,diffu);
2260
2261 if (ind_face<nb_faces_bord_reel)
2262 {
2263 flux=valA*(inconnue(j)-inconnue(num_face));
2264 // PL : c'est bien un - ici pour flux_bords. Cette valeur est ensuite
2265 // ecrasee pour les bords avec Neumann et ne sert donc que pour les bords
2266 // avec Dirichlet ou le volume de controle est nul
2267 tab_flux_bords(num_face,0)-=flux;
2268 resu(num_face)+=flux;
2269 }
2270
2271 if(j<nb_faces) // face reelle
2272 {
2273 flux=valA*(inconnue(num_face)-inconnue(j));
2274 if (j<premiere_face_int)
2275 tab_flux_bords(j,0)-=flux;
2276 resu(j)+=flux;
2277 }
2278 }
2279 }
2280 }
2281 }
2282 }
2283
2284 // Faces internes :
2285 for (num_face=premiere_face_int; num_face<nb_faces; num_face++)
2286 {
2287 for (int k=0; k<2; k++)
2288 {
2289 int elem = face_voisins(num_face,k);
2290 {
2291 for (i=0; i<nb_faces_elem; i++)
2292 {
2293 j=elemfaces(elem,i);
2294 if ( j > num_face )
2295 {
2296 int el1,el2;
2297 int contrib=1;
2298 if(j>=nb_faces) // C'est une face virtuelle
2299 {
2300 el1 = face_voisins(j,0);
2301 el2 = face_voisins(j,1);
2302 if((el1==-1)||(el2==-1))
2303 contrib=0;
2304 }
2305 if(contrib)
2306 {
2307 valA = viscA(num_face,j,elem,diffu);
2308 resu(num_face)+=valA*inconnue(j);
2309 resu(num_face)-=valA*inconnue(num_face);
2310 if(j<nb_faces) // On traite les faces reelles
2311 {
2312 resu(j)+=valA*inconnue(num_face);
2313 resu(j)-=valA*inconnue(j);
2314 }
2315 }
2316 }
2317 }
2318 }
2319 }
2320 }
2321
2322 // Neumann :
2323 for (n_bord=0; n_bord<nb_bords; n_bord++)
2324 {
2325 const Cond_lim& la_cl = domaine_Cl_VEF.les_conditions_limites(n_bord);
2326
2327 if (sub_type(Neumann_paroi,la_cl.valeur()))
2328 {
2329 const Neumann_paroi& la_cl_paroi = ref_cast(Neumann_paroi, la_cl.valeur());
2330 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2331 int ndeb = le_bord.num_premiere_face();
2332 int nfin = ndeb + le_bord.nb_faces();
2333 for (int face=ndeb; face<nfin; face++)
2334 {
2335 flux=la_cl_paroi.flux_impose(face-ndeb)*domaine_VEF.surface(face);
2336 resu[face] += flux;
2337 tab_flux_bords(face,0) = flux;
2338 }
2339 }
2340 else if (sub_type(Echange_externe_impose,la_cl.valeur()))
2341 {
2342 const Echange_externe_impose& la_cl_paroi = ref_cast(Echange_externe_impose, la_cl.valeur());
2343 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2344 int ndeb = le_bord.num_premiere_face();
2345 int nfin = ndeb + le_bord.nb_faces();
2346 for (int face=ndeb; face<nfin; face++)
2347 {
2348 flux=la_cl_paroi.h_imp(face-ndeb)*(la_cl_paroi.T_ext(face-ndeb)-inconnue(face))*domaine_VEF.surface(face);
2349 resu[face] += flux;
2350 tab_flux_bords(face,0) = flux;
2351 }
2352 }
2353 else if (sub_type(Neumann_homogene,la_cl.valeur())
2354 || sub_type(Symetrie,la_cl.valeur())
2355 || sub_type(Neumann_sortie_libre,la_cl.valeur()))
2356 {
2357 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
2358 int ndeb = le_bord.num_premiere_face();
2359 int nfin = ndeb + le_bord.nb_faces();
2360 for (int face=ndeb; face<nfin; face++)
2361 tab_flux_bords(face,0) = 0.;
2362 }
2363 }
2364}
2365
2366double Operateur_Conv_sensibility_VEF::application_LIMITEUR(double grad1, double grad2, Motcle& type_limit) const
2367{
2368 double gradlim=0.;
2369 if (type_limit=="minmod")
2370 gradlim=minmod(grad1,grad2);
2371 else if (type_limit=="vanleer")
2372 gradlim=vanleer(grad1,grad2);
2373 else if (type_limit=="vanalbada")
2374 gradlim=vanalbada(grad1,grad2);
2375 else if (type_limit=="chakravarthy")
2376 gradlim=chakravarthy(grad1,grad2);
2377 else if (type_limit=="superbee")
2378 gradlim=superbee(grad1,grad2);
2379 else
2380 {
2381 Cerr << type_limit << " is not implemented. " << finl;
2382 Cerr << " Choose from: minmod - vanleer - vanalbada - chakravarthy - superbee " << finl;
2383 Process::exit();
2384 }
2385
2386 return gradlim;
2387}
2388
2389
DoubleTab & valeurs() override
Surcharge Champ_base::valeurs() Renvoie le tableau des valeurs.
Classe Champ_Inc_base.
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
static DoubleTab & calcul_gradient(const DoubleTab &, DoubleTab &, const Domaine_Cl_VEF &)
virtual double valeur_a_sommet_compo(int, int, int) const
renvoi la compo eme corrdonne des valeurs a l'element le_poly au sommet sommet
classe Cond_lim_base Classe de base pour la hierarchie des classes qui representent les differentes c...
virtual Frontiere_dis_base & frontiere_dis()
Renvoie la frontiere discretisee a laquelle les conditions aux limites s'appliquent.
classe Cond_lim Classe generique servant a representer n'importe quelle classe
Definition Cond_lim.h:31
: class Convection_Diffusion_Temperature_sensibility
static void verifier(const char *const msg, double)
Definition Debog.cpp:21
Classe Dirichlet_homogene Cette classe est la classe de base de la hierarchie des conditions aux limi...
classe Dirichlet Cette classe est la classe de base de la hierarchie des conditions aux limites de ty...
Definition Dirichlet.h:31
int nb_faces_elem(int=0) const
Renvoie le nombre de face de type i des elements geometriques constituants le domaine.
Definition Domaine.h:484
int type_elem_Cl(int i) const
DoubleTab & vecteur_face_facette_Cl()
DoubleTab & normales_facettes_Cl()
classe Domaine_Cl_dis_base Les objets Domaine_Cl_dis_base representent les conditions aux limites
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
class Domaine_VEF
Definition Domaine_VEF.h:54
IntVect & rang_elem_non_std()
Definition Domaine_VEF.h:86
const Elem_VEF_base & type_elem() const
Definition Domaine_VEF.h:75
auto & facette_normales()
Definition Domaine_VEF.h:84
int nb_faces() const
renvoie le nombre global de faces.
Definition Domaine_VF.h:471
int nb_faces_tot() const
renvoie le nombre total de faces.
Definition Domaine_VF.h:481
void creer_tableau_faces(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
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 face_sommets(int i, int j) const
renvoie le numero du ieme sommet de la face num_face.
Definition Domaine_VF.h:583
virtual double surface(int i) const
Definition Domaine_VF.h:53
int elem_faces(int i, int j) const
renvoie le numero de le ieme face de la maille num_elem la facon dont ces faces sont numerotees est
Definition Domaine_VF.h:543
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
int nb_front_Cl() const
const Domaine & domaine() const
int nb_som_tot() const
Classe Echange_externe_impose: Cette classe represente le cas particulier de la classe.
virtual double h_imp(int num) const
Renvoie la valeur du coefficient d'echange de chaleur impose sur la i-eme composante.
virtual double T_ext(int num) const
Renvoie la valeur de la temperature imposee sur la i-eme composante du champ de frontiere.
virtual void calcul_xg(DoubleVect &, const DoubleTab &, const int, int &, int &, int &, int &) const =0
virtual void calcul_vc(const ArrOfInt &, ArrOfDouble &, const ArrOfDouble &, const DoubleTab &, const Champ_Inc_base &, int, const DoubleVect &) const =0
const IntTab & KEL() const
virtual int nb_facette() const =0
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
class Front_VF
Definition Front_VF.h:36
int nb_faces() const
Definition Front_VF.h:53
int num_premiere_face() const
Definition Front_VF.h:63
int nb_faces_tot() const
Definition Front_VF.h:58
int num_face(const int) const
Definition Front_VF.h:68
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
DoubleVect & ajouter_multvectT_(const DoubleVect &, DoubleVect &) const override
Operation de multiplication-accumulation (saxpy) matrice vecteur, par la matrice transposee.
virtual const Champ_Don_base & capacite_calorifique() const
Renvoie la capacite calorifique du milieu.
virtual const Champ_Don_base & conductivite() const
Renvoie la conductivite du milieu.
const Equation_base & equation() const
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
Une chaine de caractere (Nom) en majuscules.
Definition Motcle.h:26
: class Navier_Stokes_std_sensibility
virtual const Champ_Inc_base & vitesse() const
Classe Neumann_homogene Cette classe est la classe de base de la hierarchie des conditions aux limite...
Classe Neumann_paroi Cette condition limite correspond a un flux impose pour l'equation de.
classe Neumann_sortie_libre Cette classe represente une frontiere ouverte sans vitesse imposee
double val_ext(int i) const override
Renvoie la valeur de la i-eme composante du champ impose a l'exterieur de la frontiere.
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
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.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 Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
class Op_Conv_VEF_Face
void contribuer_a_avec(const DoubleTab &, Matrice_Morse &) const override
on assemble la matrice des inconnues implicite.
void contribue_au_second_membre(DoubleTab &) const
void get_type_op(int &) const
void get_type_lim(Motcle &) const
void get_ordre(int &) const
void dimensionner(Matrice_Morse &) const override
on dimensionne notre matrice au moyen de la methode dimensionner de la classe Op_VEF_Face.
void get_alpha(double &) const
void modifier_pour_Cl(Matrice_Morse &, DoubleTab &) const override
On modifie le second membre et la matrice dans le cas des conditions de dirichlet.
class Op_Conv_VEF_base
int phi_u_transportant(const Equation_base &eq) const
definit si l'on convecte psi avec phi*u ou avec u
void modifier_flux(const Operateur_base &) const
: class Operateur_Conv_sensibility_VEF
void ajouter_Lsensibility_state_Amont(const DoubleTab &, const DoubleTab &, DoubleTab &) const
void ajouter_conv_term(const Champ_Inc_base &, const DoubleTab &, DoubleTab &, DoubleTab &) const
virtual void remplir_fluent(DoubleVect &) const
void calcul_vc(const ArrOfInt &, ArrOfDouble &, const ArrOfDouble &s, const DoubleTab &, const DoubleTab &, int) const
double calculer_dt_stab() const override
Calcul dt_stab.
void ajouter_Lstate_sensibility_Amont(const DoubleTab &, const DoubleTab &, DoubleTab &) const
void add_diffusion_term(const DoubleTab &, DoubleTab &) const
DoubleTab & ajouter(const DoubleTab &, DoubleTab &) const override
void add_diffusion_scalar_term(const DoubleTab &, DoubleTab &, double diffu=1.) const
double application_LIMITEUR(double, double, Motcle &) const
void associer(const Domaine_dis_base &, const Domaine_Cl_dis_base &, const Champ_Inc_base &) override
double viscA(int face_i, int face_j, int num_elem, double diffu=1.) const
: class Operateur_Conv_sensibility
void associer(const Domaine_dis_base &, const Domaine_Cl_dis_base &, const Champ_Inc_base &inco) override
const Champ_Inc_base & vitesse() const
DoubleTab flux_bords_
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 void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
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
int nb_dim() const
Definition TRUSTTab.h:199
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")