TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Assembleur_P_VEFPreP1B.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_VEFPreP1B.h>
17#include <Matrice_Bloc_Sym.h>
18#include <Domaine.h>
19#include <Dirichlet.h>
20#include <Dirichlet_homogene.h>
21#include <Dirichlet_entree_fluide_leaves.h>
22#include <Neumann_sortie_libre.h>
23#include <Milieu_base.h>
24#include <Navier_Stokes_std.h>
25#include <TRUSTLists.h>
26#include <Op_Grad_VEF_P1B_Face.h>
27#include <Op_Div_VEFP1B_Elem.h>
28#include <SFichier.h>
29#include <Champ_Fonc_P1NC.h>
30#include <SolveurPP1B.h>
31#include <Check_espace_virtuel.h>
32#include <Solv_Petsc.h>
33#include <Solv_AMG.h>
34#include <Matrice_Petsc.h>
35#include <Robin_VEF.h>
36
37Implemente_instanciable(Assembleur_P_VEFPreP1B,"Assembleur_P_VEFPreP1B",Assembleur_P_VEF);
38
39// printOn et readOn
40
42{
44}
45
47{
48 return Assembleur_base::readOn(is);
49}
50
51static double estim_cond(Matrice& A)
52{
53 int i=A.valeur( ).nb_lignes();
54 //Cout << "rang " << i << finl;
55 DoubleVect p(A.valeur( ).nb_lignes());
56 for(int j=0; j<i; j++)
57 p(j)=drand48();
58 double normep=sqrt(mp_prodscal(p,p));
59 p/=normep;
60 DoubleVect r(A.valeur( ).nb_lignes());
61 double lmax=1.e-36, lmin=1.e24;
62 //double cond=-1;
63 i=10000;
64 while(i-- )
65 {
66 //cond=lmax/lmin;
67 A.valeur( ).multvect(p,r);
68 double pscpr=mp_prodscal(p,r);
69 //Cout << "lambda " << i << " : " << pscpr << " , " << lmax/lmin << finl;
70 double pscrr=mp_prodscal(r,r);
71 double epsilon=-pscpr/pscrr;
72 p.ajoute(epsilon,r);
73 double normepbis=sqrt(mp_prodscal(p,p));
74 //Cout << "normep : " << normep << finl;
75 p/=normepbis;
76 if(pscpr>lmax)
77 lmax=pscpr;
78 else if(pscpr<lmin)
79 lmin=pscpr;
80 }
81 //Cout << "lmax " << lmax << " lmin = " << lmin << finl;
82 //Cout << p << finl;
83 if (A.valeur( ).nb_lignes()<30) A.valeur( ).imprimer_formatte(Cerr);
84
85 return(lmax/lmin);
86}
87
89{
90 mon_equation=eqn;
92 if (domaine_Vef().get_P1Bulle())
93 {
94 // Pour changer de base et retrouver le P1Bulle
97 }
98}
99
101{
102 return ref_cast(Domaine_VEF, le_dom_VEF.valeur());
103}
104
105extern void assemblerP0P0(const Domaine_dis_base& z,
106 const Domaine_Cl_dis_base& zcl,
107 Matrice& matrice,
108 const DoubleTab& inverse_quantitee_entrelacee);
109
110extern void assemblerP1P1(const Domaine_dis_base& z,
111 const Domaine_Cl_dis_base& zcl,
112 Matrice& matrice,
113 const DoubleTab& inverse_quantitee_entrelacee, const ArrOfDouble& coef_som);
114
115extern void assemblerPaPa(const Domaine_dis_base& z,
116 const Domaine_Cl_dis_base& zcl,
117 Matrice& matrice, const DoubleTab& inverse_quantitee_entrelacee);
118
119extern void assemblerP0P1(const Domaine_dis_base& z,
120 const Domaine_Cl_dis_base& zcl,
121 Matrice& matrice, const DoubleTab& inverse_quantitee_entrelacee, const ArrOfDouble& coef_som);
122
123extern void assemblerP0Pa(const Domaine_dis_base& z,
124 const Domaine_Cl_dis_base& zcl,
125 Matrice& matrice,
126 const DoubleTab& inverse_quantitee_entrelacee);
127
128extern void assemblerP1Pa(const Domaine_dis_base& z,
129 const Domaine_Cl_dis_base& zcl,
130 Matrice& matrice,
131 const DoubleTab& inverse_quantitee_entrelacee, const ArrOfDouble& coef_som);
132
133extern void updateP0P0(const Domaine_dis_base& z,
134 const Domaine_Cl_dis_base& zcl,
135 Matrice& matrice,
136 const DoubleTab& inverse_quantitee_entrelacee);
137
138extern void updateP1P1(const Domaine_dis_base& z,
139 const Domaine_Cl_dis_base& zcl,
140 Matrice& matrice,
141 const DoubleTab& inverse_quantitee_entrelacee, const ArrOfDouble& coef_som);
142extern void modifieP1P1neumann(const Domaine_dis_base& z,
143 const Domaine_Cl_dis_base& zcl,
144 Matrice& matrice,
145 const DoubleTab& inverse_quantitee_entrelacee, const ArrOfDouble& coef_som);
146extern void updatePaPa(const Domaine_dis_base& z,
147 const Domaine_Cl_dis_base& zcl,
148 Matrice& matrice,
149 const DoubleTab& inverse_quantitee_entrelacee);
150
151extern void updateP0P1(const Domaine_dis_base& z,
152 const Domaine_Cl_dis_base& zcl,
153 Matrice& matrice,
154 const DoubleTab& inverse_quantitee_entrelacee, const ArrOfDouble& coef_som);
155
156extern void updateP0Pa(const Domaine_dis_base& z,
157 const Domaine_Cl_dis_base& zcl,
158 Matrice& matrice,
159 const DoubleTab& inverse_quantitee_entrelacee);
160
161extern void updateP1Pa(const Domaine_dis_base& z,
162 const Domaine_Cl_dis_base& zcl,
163 Matrice& matrice,
164 const DoubleTab& inverse_quantitee_entrelacee, const ArrOfDouble& coef_som);
165
166extern int verifier( const Assembleur_P_VEFPreP1B& ass,
167 const Matrice_Bloc_Sym& matrice,
168 const Domaine_VEF& domaine_VEF,
169 const DoubleTab& inverse_quantitee_entrelacee);
170
172{
173 return Assembleur_P_VEF::assembler(la_matrice);
174}
175
177{
178 // On multiplie par la masse volumique aux faces
179 if (!sub_type(Champ_Fonc_P1NC, rho))
180 {
181 Cerr << "La masse volumique n'est pas aux faces dans Assembleur_P_VEFPreP1B::assembler_rho_variable." << finl;
183 }
184 const DoubleVect& volumes_entrelaces=domaine_Vef().volumes_entrelaces();
185 const DoubleVect& masse_volumique=rho.valeurs();
186 DoubleVect quantitee_entrelacee(volumes_entrelaces);
187 int size=quantitee_entrelacee.size_array();
188 for (int i=0; i<size; i++)
189 quantitee_entrelacee(i)=(volumes_entrelaces(i)*masse_volumique(i));
190
191 // On assemble la matrice
192 return assembler_mat(la_matrice,quantitee_entrelacee,1,1);
193}
194
195void zero(Matrice_Bloc_Sym& matrice)
196{
197 int nombre_supports = matrice.ordre();
198 for(int i=0; i<nombre_supports; i++)
199 for(int j=i; j<nombre_supports; j++)
200 {
201 Matrice_Bloc& bloc_ij=ref_cast(Matrice_Bloc, matrice.get_bloc(i,j).valeur());
202 ref_cast(Matrice_Morse, bloc_ij.get_bloc(0,0).valeur()).clean();
204 {
205 ref_cast(Matrice_Morse, bloc_ij.get_bloc(0,1).valeur()).clean();
206 ref_cast(Matrice_Morse, bloc_ij.get_bloc(1,0).valeur()).clean();
207 ref_cast(Matrice_Morse, bloc_ij.get_bloc(1,1).valeur()).clean();
208 }
209 }
210}
211
212
213
214int Assembleur_P_VEFPreP1B::assembler_mat(Matrice& la_matrice,const DoubleVect& quantitee_entrelacee, int incr_pression, int resoudre_en_u)
215{
216 // On fixe les drapeaux de Assembleur_base
217 set_resoudre_increment_pression(incr_pression);
218 set_resoudre_en_u(resoudre_en_u);
219
220 SolveurSys& solveur_pression = ref_cast(Navier_Stokes_std, mon_equation.valeur()).solveur_pression();
221 if (solveur_pression->read_matrix()) // Lecture de la matrice dans un fichier (uniquement supporte par PETSc pour le moment)
222 {
223 la_matrice.typer("Matrice_Petsc");
224 }
225 else // Assemblage de la matrice
226 {
227 const Domaine_VEF& domaine_vef = domaine_Vef();
228 Cerr << "Assemblage de la matrice de pression" << (domaine_vef.get_alphaE() ? " P0" : "")
229 << (domaine_vef.get_alphaS() ? " P1" : "") << (domaine_vef.get_alphaA() ? " Pa" : "") << " en cours..." << finl;
230
231 // Les decoupages doivent etre de largeur de joint de 2
232 // si le support P1 ou Pa est utilise...
233 if (Process::is_parallel() &&
234 domaine_vef.domaine().nb_joints() &&
235 domaine_vef.domaine().joint(0).epaisseur() < 2 &&
236 (domaine_vef.get_alphaS() || domaine_vef.get_alphaA()))
237 {
238 Cerr << "Ghost cells width of " << domaine_vef.domaine().joint(0).epaisseur()
239 << " is not enough for assembling VEFPreP1B pressure matrix" << finl;
240 Cerr << "for parallel calculation. Partition your mesh with larg_joint option set to 2." << finl;
242 }
243
244 DoubleTab inverse_quantitee_entrelacee;
245 const Domaine_Cl_VEF& domaine_Cl_VEF = le_dom_Cl_VEF.valeur();
246 calculer_inv_volume(inverse_quantitee_entrelacee, domaine_Cl_VEF, quantitee_entrelacee);
247 int P0 = 0;
248 int P1 = P0 + domaine_vef.get_alphaE();
249 int Pa = P1 + domaine_vef.get_alphaS();
250 int nombre_supports = Pa + domaine_vef.get_alphaA();
251 DoubleVect coef_som;
252 if (domaine_vef.get_alphaS())
253 {
254 domaine_vef.domaine().creer_tableau_elements(coef_som);
255 for (int elem = 0; elem < coef_som.size_totale(); elem++)
256 coef_som[elem] = Op_Grad_VEF_P1B_Face::calculer_coef_som(elem, domaine_Cl_VEF, domaine_vef);
257 coef_som.echange_espace_virtuel();
258 }
259
260 // Assemblage de la matrice complete selon les supports choisis
261 Matrice la_matrice_de_travail_; // Matrice de travail
262 la_matrice_de_travail_.typer("Matrice_Bloc_Sym");
263 Matrice_Bloc_Sym& la_matrice_bloc_sym_de_travail = ref_cast(Matrice_Bloc_Sym, la_matrice_de_travail_.valeur());
264 if (la_matrice_bloc_sym_de_travail.nb_bloc_lignes()==0)
265 {
266 la_matrice_bloc_sym_de_travail.dimensionner(nombre_supports, nombre_supports);
267 if (domaine_vef.get_alphaE())
268 assemblerP0P0(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(P0, P0),
269 inverse_quantitee_entrelacee);
270
271 if (domaine_vef.get_alphaS())
272 assemblerP1P1(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(P1, P1),
273 inverse_quantitee_entrelacee, coef_som);
274
275 if (domaine_vef.get_alphaE() && domaine_vef.get_alphaS())
276 assemblerP0P1(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(P0, P1),
277 inverse_quantitee_entrelacee, coef_som);
278
279 if (domaine_vef.get_alphaA())
280 assemblerPaPa(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(Pa, Pa),
281 inverse_quantitee_entrelacee);
282
283 if (domaine_vef.get_alphaS() && domaine_vef.get_alphaA())
284 assemblerP1Pa(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(P1, Pa),
285 inverse_quantitee_entrelacee, coef_som);
286
287 if (domaine_vef.get_alphaE() && domaine_vef.get_alphaA())
288 assemblerP0Pa(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(P0, Pa),
289 inverse_quantitee_entrelacee);
290 }
291 // On met a zero la matrice meme si elle a ete correctement construite et remplie dans les methodes
292 // assemblerPiPi et on la remplit a nouveau. Pourquoi? Pour avoir une couverture de tests
293 // suffisante des methodes updatePiPi en attendant de factoriser correctement les
294 // methodes assemblerPiPi et updatePiPi
295 zero(la_matrice_bloc_sym_de_travail);
296 {
297 if (domaine_vef.get_alphaE())
298 updateP0P0(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(P0, P0),
299 inverse_quantitee_entrelacee);
300
301 if (domaine_vef.get_alphaS())
302 {
303 updateP1P1(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(P1, P1),
304 inverse_quantitee_entrelacee, coef_som);
305 if (domaine_vef.get_cl_pression_sommet_faible() == 0)
306 modifieP1P1neumann(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(P1, P1),
307 inverse_quantitee_entrelacee, coef_som);
308 }
309 if (domaine_vef.get_alphaE() && domaine_vef.get_alphaS())
310 updateP0P1(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(P0, P1),
311 inverse_quantitee_entrelacee, coef_som);
312
313 if (domaine_vef.get_alphaA())
314 updatePaPa(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(Pa, Pa),
315 inverse_quantitee_entrelacee);
316
317 if (domaine_vef.get_alphaS() && domaine_vef.get_alphaA())
318 updateP1Pa(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(P1, Pa),
319 inverse_quantitee_entrelacee, coef_som);
320
321 if (domaine_vef.get_alphaE() && domaine_vef.get_alphaA())
322 updateP0Pa(domaine_vef, domaine_Cl_VEF, la_matrice_bloc_sym_de_travail.get_bloc(P0, Pa),
323 inverse_quantitee_entrelacee);
324 }
325 //trustIdType ordre_matrice = mp_sum(la_matrice_bloc_sym_de_travail.nb_lignes());
326 //Cerr << "Order of the matrix = " << ordre_matrice << finl;
327
328 // Methode verifier
329 char *theValue = getenv("TRUST_VERIFIE_MATRICE_VEF");
330 if (theValue != nullptr) verifier(*this, la_matrice_bloc_sym_de_travail, domaine_vef, inverse_quantitee_entrelacee);
331
332 ////////////////////////////////////////////
333 // Changement de base eventuel P0P1->P1Bulle
334 ////////////////////////////////////////////
335 if (changement_base())
336 changer_base_matrice(la_matrice_de_travail_); // A->A~
337
338 /////////////////////////////////////////////////////////////
339 // Modification de la matrice si pas de pression de reference
340 /////////////////////////////////////////////////////////////
341 modifier_matrice(la_matrice_de_travail_);
342
343 // Conversion eventuelle en Matrice_Morse_Sym
344 if (ref_cast(Navier_Stokes_std, mon_equation.valeur()).solveur_pression()->supporte_matrice_morse_sym() &&
345 domaine_vef.get_alphaE() != nombre_supports) // On n'est pas en P0
346 {
347 //////////////////////////////////////////////////////////
348 // La matrice retournee est une Matrice_Morse_Sym nettoyee
349 // si le solveur utilisee supporte ce type de matrice
350 // et si on n'est pas en P0 seulement (dans ce cas la, la
351 // conversion en Mat_Morse_Sym n'apporte rien, et plante le SSOR
352 // car la matrice morse contient alors des parties virtuelles
353 // alors qu'il n'y a pas d'items communs et on tombe sur
354 // l'assert assert(*tab2_ptr<=n); Deux autres solutions:
355 // -Modifier le SSOR pour ne resoudre que la partie reelle
356 // -Dans le cas de P0 seul, il faudrait vider VV et RV dans la Mat_Bloc_Sym
357 //////////////////////////////////////////////////////////
358 la_matrice.typer("Matrice_Morse_Sym");
359 ref_cast(Matrice_Bloc_Sym, la_matrice_de_travail_.valeur()).BlocSymToMatMorseSym(
360 ref_cast(Matrice_Morse_Sym, la_matrice.valeur()));
361 ref_cast(Matrice_Morse_Sym, la_matrice.valeur()).compacte(
362 2);// Suppression des coefficients nuls et quasi non nuls
363 }
364 else
365 {
366 /////////////////////////////////////////////////////////
367 // La matrice retournee est une Matrice_Bloc_Sym nettoyee
368 /////////////////////////////////////////////////////////
369 la_matrice = la_matrice_de_travail_;
370 for (int i = 0; i < nombre_supports; i++)
371 for (int j = i; j < nombre_supports; j++)
372 {
373 Matrice_Bloc_Sym& mat_bloc_sym = ref_cast(Matrice_Bloc_Sym, la_matrice.valeur());
374 Matrice_Bloc& bloc_ij = ref_cast(Matrice_Bloc, mat_bloc_sym.get_bloc(i, j).valeur());
375 ref_cast(Matrice_Morse, bloc_ij.get_bloc(0, 0).valeur()).compacte(
376 2); // Suppression des coefficients nuls et quasi non nuls
377 }
378 }
379 }
380
381 // Si pas deja fait, on prends un solveur (SolveurPP1B) qui fera les changements de base pour la solution et le second membre
382 if (changement_base() && solveur_pression->que_suis_je() != "SolveurPP1B")
383 {
384 SolveurSys solveur_pression_lu = solveur_pression;
385 solveur_pression.typer("SolveurPP1B");
386 SolveurPP1B& solveur_pression_PP1B = ref_cast(SolveurPP1B, solveur_pression.valeur());
387 solveur_pression_PP1B.associer(*this, solveur_pression_lu);
388 }
389
390 //////////////////////////////////////////////////////
391 // Affichage eventuel du conditionnement de la matrice
392 //////////////////////////////////////////////////////
393 char* theValue2 = getenv("TRUST_CONDITIONNEMENT_MATRICE");
394 if(theValue2 != nullptr)
395 Cout << "Estimation du conditionnement de la matrice: " << estim_cond(la_matrice)<<finl;
396
397 return 1;
398}
399
401{
402 const Domaine_VEF& le_dom = domaine_Vef();
403
404 // Verification sur le support Pa
405 if (le_dom.get_alphaA())
406 {
407 // Verification sur les aretes que:
408 const ArrOfInt& renum_arete_perio=le_dom.get_renum_arete_perio();
409 const ArrOfInt& ok_arete=le_dom.get_ok_arete();
410 int npa=le_dom.numero_premiere_arete();
411 // b n'a pas forcement son espace virtuel a jour
412 int nb_aretes=le_dom.domaine().nb_aretes();
413 ToDo_Kokkos("critical");
414 for(int i=0; i<nb_aretes; i++)
415 if(!ok_arete[i] && b(npa+i)!=0.) // Les aretes superflues ont une valeur nulle
416 {
417 Cerr << "Pb div Aretes, la pression sur l'arete " << i << " (qui est superflue) n'est pas nulle." << finl;
419 }
420 else if ( (renum_arete_perio[i]!=i) && b(npa+i)!=0.) // Les aretes periodiques ont une valeur nulle
421 {
422 Cerr << "Pb div Aretes Perio, la pression sur l'arete " << i << " (qui est periodique) n'est pas nulle." << finl;
424 }
425 }
426
427 // Verification sur le support P1
428 if (le_dom.get_alphaS())
429 {
430 // Verification que la pression sur les sommets periodiques est nulle
431 const Domaine& dom=le_dom.domaine();
432 int nps=le_dom.numero_premier_sommet();
433 int ns=le_dom.domaine().nb_som();
434 CIntArrView renum_som_perio = dom.get_renum_som_perio().view_ro();
435 CDoubleArrView b_v = static_cast<const DoubleVect&>(b).view_ro();
436 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), ns, KOKKOS_LAMBDA(
437 const int i)
438 {
439 int k=renum_som_perio(i);
440 if((k!=i)&& b_v(nps+i)!=0.)
441 {
442 printf("Pb div Som, la pression sur le sommet %ld (qui est periodique) n'est pas nulle.\n",(long)i);
443 printf("En terme clair, le second membre n'est pas nul sur un sommet periodique.\n");
444 if (b_v(nps+i)!=b_v(nps+k))
445 {
446 printf("En outre, le second membre n'a pas la meme valeur sur les 2 sommets periodiques.\n");
447 printf("b(nps+i)=%f <> b(nps+k)=%f\n",b_v(nps+i),b_v(nps+k));
448 }
449 Kokkos::abort("Il y'a probabilite que le modele utilise soit mal implemente pour\nune condition de periodicite. Contacter le support TRUST.");
450 }
451 });
452 end_gpu_timer(__KERNEL_NAME__);
453 }
454
455 if (get_resoudre_en_u())
456 {
457 const Domaine_VEF& domaine_VEF = domaine_Vef();
458 const Domaine_Cl_VEF& domaine_Cl = le_dom_Cl_VEF.valeur();
459
460 CDoubleArrView porosite_face = domaine_Cl.equation().milieu().porosite_face().view_ro();
461
462 const int nb_cond_lim = domaine_Cl.nb_cond_lim();
463
464 /**************************/
465 /* Recuperation de Gpoint */
466 /**************************/
467 DoubleTrav tab_Gpoint(equation().inconnue().valeurs());
468 DoubleTabView Gpoint = tab_Gpoint.view_wo();
469
470 //Gpoint=0.; Un DoubleTrav initialise a 0
471 int Gpoint_nul = 1; // Drapeau pour economiser potentiellement un echange_espace_virtuel
472 for (int cond_lim=0; cond_lim<nb_cond_lim; cond_lim++)
473 {
474 const Cond_lim_base& cl_base = domaine_Cl.les_conditions_limites(cond_lim).valeur();
475
476 const Front_VF& front_VF = ref_cast(Front_VF,cl_base.frontiere_dis());
477 const Champ_front_base& champ_front = cl_base.champ_front();
478
479 const int ndeb = front_VF.num_premiere_face();
480 const int nfin = ndeb+front_VF.nb_faces();
481
482 /* Test sur la nature du champ au bord du domaine */
483 if (sub_type(Entree_fluide_vitesse_imposee, cl_base) && champ_front.instationnaire())
484 {
485 Gpoint_nul = 0;
486 CDoubleTabView gpoint = champ_front.derivee_en_temps().view_ro();
487 CDoubleArrView arr_gpoint = static_cast<const DoubleVect&>(champ_front.derivee_en_temps()).view_ro();
488 bool ch_unif = (champ_front.derivee_en_temps().nb_dim()==1);
489 int dimension_ = Objet_U::dimension;
490 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), Kokkos::RangePolicy<>(ndeb, nfin),
491 KOKKOS_LAMBDA(const int num_face)
492 {
493 for (int dim=0; dim<dimension_; dim++)
494 Gpoint(num_face,dim) = porosite_face(num_face) * (ch_unif ? arr_gpoint(dim) : gpoint(num_face-ndeb,dim));
495 });
496 end_gpu_timer(__KERNEL_NAME__);
497 }
498 }
499
500 //Pour le parallele
501 if (!Gpoint_nul) tab_Gpoint.echange_espace_virtuel();
502
503 /******************************/
504 /* Fin recuperation de Gpoint */
505 /******************************/
506
507 /*********************************/
508 /* Modification du second membre */
509 /*********************************/
510
511 if (domaine_VEF.get_alphaE()) modifier_secmem_elem(tab_Gpoint,b);
512 if (domaine_VEF.get_alphaS()) modifier_secmem_som(tab_Gpoint,b);
513 if (domaine_VEF.get_alphaA()) modifier_secmem_aretes(tab_Gpoint,b);
514
515 /**********************************/
516 /* Fin modification second membre */
517 /**********************************/
518
520 }
521
522 return 1;
523}
524
525int Assembleur_P_VEFPreP1B::modifier_secmem_elem(const DoubleTab& tab_Gpoint, DoubleTab& tab_b)
526{
527 const Domaine_VEF& domaine_VEF = domaine_Vef();
528 const Domaine_Cl_VEF& domaine_Cl = le_dom_Cl_VEF.valeur();
529 const int nb_cond_lim = domaine_Cl.nb_cond_lim();
530 for (int cond_lim=0; cond_lim<nb_cond_lim; cond_lim++)
531 {
532 const Cond_lim_base& cl_base = domaine_Cl.les_conditions_limites(cond_lim).valeur();
533
534 const Front_VF& front_VF = ref_cast(Front_VF,cl_base.frontiere_dis());
535 const Champ_front_base& champ_front = cl_base.champ_front();
536 /* Test sur la nature du champ au bord du domaine */
537 if (sub_type(Entree_fluide_vitesse_imposee, cl_base) && champ_front.instationnaire() )
538 {
539 // Construction de la liste des faces a traiter (reelles + virtuelles)
540 const int nb_faces_bord_tot = front_VF.nb_faces_tot();
541 int dimension_ = Objet_U::dimension;
542 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
543 CDoubleTabView face_normales = domaine_VEF.face_normales().view_ro();
544 CDoubleTabView Gpoint = tab_Gpoint.view_ro();
545 CIntArrView front_num_face = front_VF.num_face().view_ro();
546 DoubleArrView b = static_cast<DoubleVect&>(tab_b).view_rw();
547 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nb_faces_bord_tot, KOKKOS_LAMBDA(const int ind_face)
548 {
549 const int num_face = front_num_face(ind_face);
550 const int elem = face_voisins(num_face,0);
551 assert(elem!=-1);
552
553 for (int dim=0; dim<dimension_; dim++)
554 Kokkos::atomic_add(&b(elem), -Gpoint(num_face,dim)*face_normales(num_face,dim));
555 });
556 end_gpu_timer(__KERNEL_NAME__);
557 }
558 }
559
560 return 1;
561}
562
563int Assembleur_P_VEFPreP1B::modifier_secmem_som(const DoubleTab& tab_Gpoint, DoubleTab& tab_b)
564{
565 const Domaine_VEF& domaine_VEF = domaine_Vef();
566 const Domaine_Cl_VEF& domaine_Cl = le_dom_Cl_VEF.valeur();
567 const Domaine& domaine = domaine_VEF.domaine();
568
569 const int nb_cond_lim = domaine_Cl.nb_cond_lim();
570 const int nb_elem_tot = (domaine_VEF.get_alphaE()?domaine.nb_elem_tot():0);
571 const int nb_faces_elem = domaine.nb_faces_elem();
572
573 const double coeff_dim = Objet_U::dimension*(Objet_U::dimension+1);
574
575 for (int cond_lim=0; cond_lim<nb_cond_lim; cond_lim++)
576 {
577 const Cond_lim_base& cl_base = domaine_Cl.les_conditions_limites(cond_lim).valeur();
578
579 const Front_VF& front_VF = ref_cast(Front_VF,cl_base.frontiere_dis());
580 const Champ_front_base& champ_front = cl_base.champ_front();
581
582 /* Test sur la nature du champ au bord du domaine */
583 if (sub_type(Entree_fluide_vitesse_imposee, cl_base) && champ_front.instationnaire())
584 {
585 // Construction de la liste des faces a traiter (reelles + virtuelles)
586 const int nb_faces_bord_tot = front_VF.nb_faces_tot();
587 int dimension_ = Objet_U::dimension;
588 CIntTabView elem_faces = domaine_VEF.elem_faces().view_ro();
589 CIntTabView face_sommets = domaine_VEF.face_sommets().view_ro();
590 CIntTabView face_voisins = domaine_VEF.face_voisins().view_ro();
591 CIntTabView elem_sommets = domaine.les_elems().view_ro();
592 CDoubleTabView face_normales = domaine_VEF.face_normales().view_ro();
593 CDoubleTabView Gpoint = tab_Gpoint.view_ro();
594 CIntArrView renum_som_perio = domaine.get_renum_som_perio().view_ro();
595 CIntArrView front_num_face = front_VF.num_face().view_ro();
596 DoubleArrView b = static_cast<DoubleVect&>(tab_b).view_rw();
597 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nb_faces_bord_tot, KOKKOS_LAMBDA(const int ind_face)
598 {
599 double sigma[3];
600 const int num_face = front_num_face(ind_face);
601 const int elem = face_voisins(num_face,0);
602 assert(elem!=-1);
603
604 //Calcul de la vitesse au centre de l'element
605 for (int i_sigma = 0; i_sigma < 3; ++i_sigma)
606 sigma[i_sigma] = 0;
607
608 for (int face_loc=0; face_loc<nb_faces_elem; face_loc++)
609 {
610 const int face = elem_faces(elem,face_loc);
611
612 for(int comp=0; comp<dimension_; comp++)
613 sigma[comp] += Gpoint(face, comp);
614 }
615
616 //Calcul de la divergence de la vitesse
617 for(int face_loc=0; face_loc<nb_faces_elem; face_loc++)
618 {
619 const int som = nb_elem_tot + renum_som_perio(elem_sommets(elem,face_loc));
620 const int face = elem_faces(elem,face_loc);
621
622 double psc=0;
623 double signe=1.;
624 if(elem != face_voisins(face,0)) signe=-1.;
625
626 for(int comp=0; comp<dimension_; comp++)
627 psc += sigma[comp]*face_normales(face,comp);
628
629 Kokkos::atomic_add(&b(som), -signe*psc/coeff_dim);
630 }
631
632 double flux = 0. ;
633 for (int comp=0; comp<dimension_; comp++)
634 flux += Gpoint(num_face,comp) * face_normales(num_face,comp) ;
635
636 flux*=1./dimension_;
637 for(int som_loc=0; som_loc<nb_faces_elem-1; som_loc++)
638 {
639 const int som = nb_elem_tot + renum_som_perio(face_sommets(num_face,som_loc));
640 // DOUBT_HARI: Should it be atomic?
641 Kokkos::atomic_add(&b(som), -flux);
642 }
643 //Fin du calcul de la divergence de la vitesse
644 });
645 end_gpu_timer(__KERNEL_NAME__);
646 }
647 }
648
649 return 1;
650}
651
652int Assembleur_P_VEFPreP1B::modifier_secmem_aretes(const DoubleTab& Gpoint, DoubleTab& b)
653{
654 return 1;
655}
656
658{
659
660 // if (!has_P_ref) exit();
661 const Domaine_VEF& le_dom = domaine_Vef();
662
663 // Verification sur les aretes
664 if (le_dom.get_alphaA())
665 {
666 // On impose la pression a 0 sur les aretes superflues:
667 const IntVect& ok_arete=le_dom.get_ok_arete();
668 const ArrOfInt& renum_arete_perio=le_dom.get_renum_arete_perio();
669 // Nombre d'aretes reelles
670 int nb_aretes=ok_arete.size();
671 int npa=le_dom.numero_premiere_arete();
672 for(int i=0; i<nb_aretes; i++)
673 {
674 if(!ok_arete(i) && tab_pression(npa+i)!=0.)
675 {
676 Cerr << "Pb pression arete superflue, P(" << npa+i << ")=" << tab_pression(npa+i) << finl;
677 tab_pression(npa+i)=0;
679 }
680 else if ( (renum_arete_perio[i]!=i) && tab_pression(npa+i)!=0.)
681 {
682 Cerr << "Pb pression arete superflue periodique, P(" << npa+i << ")=" << tab_pression(npa+i) << finl;
683 tab_pression(npa+i)=0;
685 }
686 }
687 }
688
689 // On applique la periodicite sur les sommets pour la pression:
690 if (le_dom.get_alphaS())
691 {
692 const Domaine& dom=le_dom.domaine();
693 int nps=le_dom.numero_premier_sommet();
694 int ns=le_dom.domaine().nb_som();
695 CIntArrView renum_som_perio = dom.get_renum_som_perio().view_ro();
696 DoubleArrView pression = static_cast<DoubleVect&>(tab_pression).view_rw();
697 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__),
698 Kokkos::RangePolicy<>(0, ns), KOKKOS_LAMBDA(
699 const int i)
700 {
701 int k=renum_som_perio(i);
702 if (k!=i) pression(nps+i)=pression(nps+k);
703 });
704 end_gpu_timer(__KERNEL_NAME__);
705 }
706 // pression.echange_espace_virtuel();
707 // pour retirer le min de la pression si pas de Pref et si que PO sinon on filtre plus tard
708 if (le_dom.get_alphaE() && (le_dom.get_alphaS()==0) && (le_dom.get_alphaA()==0) )
710 // Verification possible par variable d'environnement:
711 char* theValue = getenv("TRUST_VERIFIE_DIRICHLET");
712 if(theValue != nullptr) verifier_dirichlet();
713
714 return 1;
715}
716
718{
719 if (domaine_Vef().get_alphaE()+domaine_Vef().get_alphaS()+domaine_Vef().get_alphaA()!=dimension)
720 {
721 Cerr << "Assembleur_P_VEFPreP1B::verifier_dirichlet ne fonctionne pas encore avec votre discretisation" << finl;
723 }
724 // Verifications diverses des conditions limites
725 // en postraitant le resultat dans le champ Divergence_U
726 IntVect Faces_de_Dirichlet(domaine_Vef().nb_elem_tot());
727 IntTab faces(domaine_Vef().nb_elem_tot(),2);
728 faces=-1;
729 const IntTab& face_sommets=domaine_Vef().face_sommets();
730 Faces_de_Dirichlet=0;
731 const Conds_lim& les_cl = le_dom_Cl_VEF->les_conditions_limites();
732 for(int i=0; i<les_cl.size(); i++)
733 {
734 const Cond_lim& la_cl = les_cl[i];
735 const Front_VF& le_bord = ref_cast(Front_VF,la_cl->frontiere_dis());
736 int num1 = le_bord.num_premiere_face();
737 int num2 = num1 + le_bord.nb_faces();
738 if ((sub_type(Dirichlet, la_cl.valeur()))
739 || (sub_type(Dirichlet_homogene, la_cl.valeur())))
740 {
741 for (int face=num1; face<num2; face++)
742 {
743 int elem=domaine_Vef().face_voisins(face,0);
744 if (elem!=-1)
745 {
746 Faces_de_Dirichlet(elem)++;
747 if (faces(elem,0)==-1) faces(elem,0)=face;
748 else faces(elem,1)=face;
749
750 }
751 elem=domaine_Vef().face_voisins(face,1);
752 if (elem!=-1) Faces_de_Dirichlet(elem)++;
753 }
754 }
755 }
756 DoubleVect& post=ref_cast(Navier_Stokes_std,mon_equation.valeur()).div().valeurs();
757 post=0;
758 for (int elem=0; elem<Faces_de_Dirichlet.size_array(); elem++)
759 {
760 //post(elem)=Faces_de_Dirichlet(elem);
761 if (Faces_de_Dirichlet(elem)>1)
762 {
763 Cerr << "L'element " << elem << " a " << Faces_de_Dirichlet(elem) << " faces de Dirichlet separees par une ";
764 const IntVect& ok_arete=domaine_Vef().get_ok_arete();
765 const IntTab& aretes_som=domaine_Vef().domaine().aretes_som();
766 // Parcours des aretes pour verifier les aretes de bord
767 for (int k=0; k<6; k++)
768 {
769 int arete=domaine_Vef().domaine().elem_aretes(elem,k);
770 // Les 2 sommets de l'arete
771 int S0=aretes_som(arete,0);
772 int S1=aretes_som(arete,1);
773 // On verifie s'ils sont 2 fois dans les sommets des faces
774 // auquels cas c'est l'arete qui partage 2 faces de Dirichlet
775 int ok=0;
776 for (int l=0; l<2; l++)
777 {
778 int face=faces(elem,l);
779 for (int s=0; s<3; s++)
780 {
781 if (face_sommets(face,s)==S0) ok++;
782 if (face_sommets(face,s)==S1) ok++;
783 }
784 }
785 if (ok==4) Cerr << "arete " << (ok_arete(arete)==0?"superflue":"") << finl;
786 // On compte les aretes superflues
787 post(elem)+=(ok_arete(arete)==0);
788 }
789 //Process::exit();
790 }
791 }
792}
793
794void Assembleur_P_VEFPreP1B::projete_L2(DoubleTab& pression)
795{
796 if (domaine_Vef().get_alphaE()+domaine_Vef().get_alphaS()+domaine_Vef().get_alphaA()!=3)
797 {
798 Cerr << "Assembleur_P_VEFPreP1B::projete_L2 ne fonctionne qu'en P0+P1+Pa" << finl;
800 }
801 //Cerr << "Projection L2" << finl;
802 const Domaine_VEF& domaine_vef = domaine_Vef();
803 const Domaine& domaine = domaine_vef.domaine();
804 int nb_elem_tot=domaine.nb_elem_tot();
805 int ns=domaine.nb_som_tot();
806 int nb_elem=domaine.nb_elem();
807 int i,j;
808 const IntTab& som_elem=domaine_vef.domaine().les_elems();
809 const DoubleVect& volumes=domaine_vef.volumes();
810 double volume_tot=0;
811 double somme=0;
812 int nsr=nb_elem_tot+ns;
813 int nse=domaine.nb_som_elem();
814 for(i=nb_elem_tot; i<nsr; i++)
815 somme+=pression(i);
816 somme/=ns;
817 for(i=nb_elem_tot; i<nsr; i++)
818 pression(i)-=somme;
819 static double dalpha =(1./dimension*(dimension+1));
820 double pmoy=0;
821 for(i=0; i<nb_elem; i++)
822 {
823 double p=pression(i);
824 double v=volumes(i);
825 for(j=0; j<nse; j++)
826 p+=pression(nb_elem_tot+som_elem(i,j))*dalpha;
827 pmoy+=p*v;
828 volume_tot+=v;
829 }
830 pmoy/=volume_tot;
831 for(i=0; i<nb_elem; i++)
832 pression(i)-=pmoy;
833}
834
835/*! @brief Modifier eventuellement la matrice pour la rendre definie si elle ne l'est pas Valeurs par defaut:
836 *
837 * Contraintes:
838 * Acces: entree
839 *
840 * @return (int) renvoie 1 si la matrice est modifiee 0 sinon
841 */
843{
844 int matrice_modifiee=0;
845 has_P_ref=0;
846 const Conds_lim& les_cl = le_dom_Cl_VEF->les_conditions_limites();
847 const Domaine_VEF& domaine_VEF = domaine_Vef();
848 // Recherche s'il y'a une pression de reference, et si oui la matrice n'est pas modifiee
849 for(int i=0; i<les_cl.size(); i++)
850 if (sub_type(Neumann_sortie_libre,les_cl[i].valeur()) ||sub_type(Robin_VEF, les_cl[i].valeur()))
851 {
852 has_P_ref=1;
853 if (domaine_VEF.get_alphaA())
854 {
855 // On en profite pour verifier si la pression est bien nulle si support Pa
856 const DoubleTab& val=ref_cast(Neumann_sortie_libre,les_cl[i].valeur()).champ_front().valeurs();
857 int nbval=val.dimension(0);
858 for (int n=0; n<nbval; n++)
859 if (val(n,0)!=0)
860 {
861 Cerr << "La condition limite pression imposee non nulle n'est pas encore" << finl;
862 Cerr << "supportee en VEF avec support arete Pa." << finl;
863 // Le travail est a faire dans Assembleur_P_VEFPreP1B::modifier_secmem_aretes
865 }
866 }
867 }
868
869 Matrice_Bloc_Sym& matrice=ref_cast(Matrice_Bloc_Sym, la_matrice.valeur());
870 int P0 = 0;
871 int P1 = P0 + domaine_VEF.get_alphaE();
872 int Pa = P1 + domaine_VEF.get_alphaS();
873
874
875
876 int CL_neumann=has_P_ref;
877 ////////////
878 // Partie P0
879 ////////////
880 if (domaine_VEF.get_alphaE())
881 {
882 // On impose une pression de reference sur un element si pas de CL de Neumann
883 if (has_P_ref)
884 {
885 Matrice_Bloc& mat_bloc=ref_cast(Matrice_Bloc,matrice.get_bloc(P0,P0).valeur());
886 Matrice_Morse_Sym& A00RR = ref_cast(Matrice_Morse_Sym,mat_bloc.get_bloc(0,0).valeur());
887 A00RR.set_est_definie(1);
888 }
889 matrice_modifiee=Assembleur_P_VEF::modifier_matrice(matrice.get_bloc(P0,P0));
890 }
891
892 ////////////
893 // Partie P1
894 ////////////
895 if (domaine_VEF.get_alphaS())
896 {
897 Matrice_Bloc& mat_bloc_p1_p1 = ref_cast(Matrice_Bloc, matrice.get_bloc(P1,P1).valeur());
898 Matrice_Morse_Sym& A11RR = ref_cast(Matrice_Morse_Sym,mat_bloc_p1_p1.get_bloc(0,0).valeur());
899 // On impose une pression de reference sur un sommet si support P0 ou si pas de CL de Neumann
900 const bool is_first_proc_with_real_elems = Process::me() == Process::mp_min(le_dom_VEF->nb_elem() ? Process::me() : 1e8);
901 if (((!(Process::mp_max(CL_neumann))) || ((domaine_VEF.get_alphaE()) && (domaine_VEF.get_cl_pression_sommet_faible()==1) ) ) && is_first_proc_with_real_elems)
902 {
903 int sommet_referent=0;
904 double distance=DMAXFLOAT;
905 const DoubleTab& coord=domaine_VEF.domaine().coord_sommets();
906 int nb_som=domaine_VEF.domaine().nb_som();
907 for(int i=0; i<nb_som; i++)
908 {
909 double tmp=0;
910 for (int j=0; j<dimension; j++)
911 tmp+=coord(i,j)*coord(i,j);
912 if (inf_strict(tmp,distance) && !est_egal(A11RR(i,i),0.))
913 {
914 distance=tmp;
915 sommet_referent=i;
916 }
917 }
918 //Cerr << "On modifie la ligne (sommet) " << sommet_referent << finl;
919 A11RR(sommet_referent,sommet_referent)*=2;
920 // has_P_ref=1;
921 matrice_modifiee=1;
922 }
923 A11RR.set_est_definie(1);
924 }
925
926 ////////////
927 // Partie Pa
928 ////////////
929 if (domaine_VEF.get_alphaA())
930 {
931 Matrice_Bloc& mat_bloc_pa_pa = ref_cast(Matrice_Bloc, matrice.get_bloc(Pa,Pa).valeur());
932 Matrice_Morse_Sym& A22RR = ref_cast(Matrice_Morse_Sym,mat_bloc_pa_pa.get_bloc(0,0).valeur());
933 // On impose une pression de reference sur une arete en P0+Pa uniquement
934 const bool is_first_proc_with_real_elems = Process::me() == Process::mp_min(le_dom_VEF->nb_elem() ? Process::me() : 1e8);
935 if ((domaine_VEF.get_alphaE() && !domaine_VEF.get_alphaS()) && is_first_proc_with_real_elems)
936 {
937 int arete_referente=0;
938 double distance=DMAXFLOAT;
939 const DoubleTab& coord=domaine_VEF.xa();
940 int nb_aretes=domaine_VEF.domaine().nb_aretes();
941 for(int i=0; i<nb_aretes; i++)
942 {
943 double tmp=0;
944 for (int j=0; j<dimension; j++)
945 tmp+=coord(i,j)*coord(i,j);
946 if (tmp<distance && A22RR(i,i)!=0)
947 {
948 distance=tmp;
949 arete_referente=i;
950 }
951 }
952 //Cerr << "On modifie la ligne (arete) " << arete_referente << finl;
953 A22RR(arete_referente,arete_referente)*=2;
954 //has_P_ref=1;
955 matrice_modifiee=1;
956 }
957 A22RR.set_est_definie(1);
958 }
959
960 {
961 Matrice_Bloc& bloc_P0_P0 = ref_cast( Matrice_Bloc,matrice.get_bloc(P0,P0).valeur( ) );
962 Matrice_Morse_Sym& A00RR = ref_cast( Matrice_Morse_Sym, bloc_P0_P0.get_bloc(0,0).valeur() );
963 matrice.set_est_definie( A00RR.get_est_definie( ) );
964 }
965
966 return matrice_modifiee;
967}
968
969inline void range(double& prod, int& i, int& n, int& j, int& m, Matrice_Morse& ARR, Matrice_Morse& ARV, Matrice_Morse& AVR, Matrice_Morse& AVV)
970{
971 if (i<n)
972 if (j<m)
973 ARR(i,j)+=prod;
974 else
975 ARV(i,j-m)+=prod;
976 else if (j<m)
977 AVR(i-n,j)+=prod;
978 else
979 AVV(i-n,j-m)+=prod;
980}
981
982void operation11(Matrice_Bloc& A00, Matrice_Bloc& A01, Matrice_Bloc& A11, double beta, const Domaine& domaine)
983{
984 //Cerr << "Operation11" << finl;
985 Matrice_Morse_Sym& A11RR=ref_cast(Matrice_Morse_Sym, A11.get_bloc(0,0).valeur());
986 Matrice_Morse& A11RV=ref_cast(Matrice_Morse, A11.get_bloc(0,1).valeur());
987 Matrice_Morse& A11VR=ref_cast(Matrice_Morse, A11.get_bloc(1,0).valeur());
988 Matrice_Morse& A11VV=ref_cast(Matrice_Morse, A11.get_bloc(1,1).valeur());
989 const IntTab& les_elems=domaine.les_elems();
990 const Domaine& dom=domaine;
991 int nb_som=A11RR.nb_lignes();
992 int nb_som_elem=les_elems.dimension(1);
993 // On parcours les elements de la matrice A00
994 //Cerr << "[" << Process::me() << "] Contribution de A00 dans A11~" << finl;
995 int ligne=0;
996 for (int i_bloc=0; i_bloc<A00.nb_bloc_lignes(); i_bloc++)
997 {
998 int colonne=0;
999 int nb_lignes=0;
1000 for (int j_bloc=0; j_bloc<A00.nb_bloc_colonnes(); j_bloc++)
1001 {
1002 Matrice_Morse& A00ij=ref_cast(Matrice_Morse, A00.get_bloc(i_bloc,j_bloc).valeur());
1003 const auto* tab1=A00ij.get_tab1().addr();
1004 const int* tab2=A00ij.get_tab2().addr();
1005 const double* coeff=A00ij.get_coeff().addr();
1006 nb_lignes=A00ij.nb_lignes();
1007 int nb_colonnes=A00ij.nb_colonnes();
1008 for (int i=0; i<nb_lignes; i++)
1009 {
1010 int k1=ligne+i; // Element k1
1011 for (auto n=tab1[i]-1; n<tab1[i+1]-1; n++)
1012 {
1013 int k2=colonne+tab2[n]-1; // Element k2
1014 if (k2>=k1)
1015 {
1016 double prod = beta * beta * coeff[n]; // Calcul de beta*beta*Ak1k2
1017 for (int som1=0; som1<nb_som_elem; som1++)
1018 {
1019 int s1 = dom.get_renum_som_perio(les_elems(k1,som1));
1020 for (int som2=0; som2<nb_som_elem; som2++)
1021 {
1022 int s2 = dom.get_renum_som_perio(les_elems(k2,som2));
1023 if (s2>=s1) range(prod,s1,nb_som,s2,nb_som,A11RR,A11RV,A11VR,A11VV);
1024 }
1025 }
1026 if (k1!=k2)
1027 {
1028 for (int som1=0; som1<nb_som_elem; som1++)
1029 {
1030 int s1 = dom.get_renum_som_perio(les_elems(k2,som1));
1031 for (int som2=0; som2<nb_som_elem; som2++)
1032 {
1033 int s2 = dom.get_renum_som_perio(les_elems(k1,som2));
1034 if (s2>=s1) range(prod,s1,nb_som,s2,nb_som,A11RR,A11RV,A11VR,A11VV);
1035 }
1036 }
1037 }
1038 }
1039 }
1040 }
1041 colonne+=nb_colonnes;
1042 }
1043 ligne+=nb_lignes;
1044 }
1045 // On parcours les elements de la matrice A01
1046 //Cerr << "[" << Process::me() << "] Contribution de A01 dans A11~" << finl;
1047 ligne=0;
1048 for (int i_bloc=0; i_bloc<A01.nb_bloc_lignes(); i_bloc++)
1049 {
1050 int colonne=0;
1051 int nb_lignes=0;
1052 for (int j_bloc=0; j_bloc<A01.nb_bloc_colonnes(); j_bloc++)
1053 {
1054 Matrice_Morse& A01ij=ref_cast(Matrice_Morse, A01.get_bloc(i_bloc,j_bloc).valeur());
1055 const auto* tab1=A01ij.get_tab1().addr();
1056 const int* tab2=A01ij.get_tab2().addr();
1057 const double* coeff=A01ij.get_coeff().addr();
1058 nb_lignes=A01ij.nb_lignes();
1059 int nb_colonnes=A01ij.nb_colonnes();
1060 for (int i=0; i<nb_lignes; i++)
1061 {
1062 int k=ligne+i; // Element k
1063 for (auto n=tab1[i]-1; n<tab1[i+1]-1; n++)
1064 {
1065 int s1 = dom.get_renum_som_perio(colonne+tab2[n]-1); // Sommet s1
1066 double prod = -beta * coeff[n]; // Calcul de -beta*Aks
1067 for (int som=0; som<nb_som_elem; som++)
1068 {
1069 int s2 = dom.get_renum_som_perio(les_elems(k,som)); // Sommet s2
1070 if (s2>=s1) range(prod,s1,nb_som,s2,nb_som,A11RR,A11RV,A11VR,A11VV);
1071 if (s1>=s2) range(prod,s2,nb_som,s1,nb_som,A11RR,A11RV,A11VR,A11VV);
1072 }
1073 }
1074 }
1075 colonne+=nb_colonnes;
1076 }
1077 ligne+=nb_lignes;
1078 }
1079}
1080
1081void operation01(Matrice_Bloc& A00, Matrice_Bloc& A01, double alpha, double beta, const Domaine& domaine)
1082{
1083 //Cerr << "[" << Process::me() << "] Operation01" << finl;
1084 Matrice_Morse& A01RR=ref_cast(Matrice_Morse, A01.get_bloc(0,0).valeur());
1085 Matrice_Morse& A01RV=ref_cast(Matrice_Morse, A01.get_bloc(0,1).valeur());
1086 Matrice_Morse& A01VR=ref_cast(Matrice_Morse, A01.get_bloc(1,0).valeur());
1087 Matrice_Morse& A01VV=ref_cast(Matrice_Morse, A01.get_bloc(1,1).valeur());
1088 const IntTab& les_elems=domaine.les_elems();
1089 const Domaine& dom=domaine;
1090 int nb_elem=A01RR.nb_lignes();
1091 int nb_som=A01RR.nb_colonnes();
1092 int nb_som_elem=les_elems.dimension(1);
1093 // On parcours les coefficients de A00
1094 int ligne=0;
1095 for (int i_bloc=0; i_bloc<A00.nb_bloc_lignes(); i_bloc++)
1096 {
1097 int colonne=0;
1098 int nb_lignes=0;
1099 for (int j_bloc=0; j_bloc<A00.nb_bloc_colonnes(); j_bloc++)
1100 {
1101 Matrice_Morse& A00ij=ref_cast(Matrice_Morse, A00.get_bloc(i_bloc,j_bloc).valeur());
1102 const auto* tab1=A00ij.get_tab1().addr();
1103 const int* tab2=A00ij.get_tab2().addr();
1104 const double* coeff=A00ij.get_coeff().addr();
1105 nb_lignes=A00ij.nb_lignes();
1106 int nb_colonnes=A00ij.nb_colonnes();
1107 int s;
1108 for (int i=0; i<nb_lignes; i++)
1109 {
1110 int k1=ligne+i; // Element k1
1111 for (auto n=tab1[i]-1; n<tab1[i+1]-1; n++)
1112 {
1113 int k2=colonne+tab2[n]-1; // Element k2
1114 if (k2>=k1)
1115 {
1116 double prod = -alpha * beta * coeff[n]; // Calcul de -alpha*beta*Ak1k2
1117 for (int som=0; som<nb_som_elem; som++)
1118 {
1119 s = dom.get_renum_som_perio(les_elems(k2,som));
1120 range(prod,k1,nb_elem,s,nb_som,A01RR,A01RV,A01VR,A01VV);
1121 if (k1!=k2)
1122 {
1123 s = dom.get_renum_som_perio(les_elems(k1,som));
1124 range(prod,k2,nb_elem,s,nb_som,A01RR,A01RV,A01VR,A01VV);
1125 }
1126 }
1127 }
1128 }
1129 }
1130 colonne+=nb_colonnes;
1131 }
1132 ligne+=nb_lignes;
1133 }
1134}
1135
1137{
1138 assert(domaine_Vef().get_alphaE() && domaine_Vef().get_alphaS() && !domaine_Vef().get_alphaA()); // P0+P1 uniquement
1139 Cerr << "Changement de base pour la matrice: P0+P1->P1Bulle" << finl;
1140 Matrice_Bloc_Sym& matrice=ref_cast(Matrice_Bloc_Sym, la_matrice.valeur());
1141 Matrice_Bloc& A00=ref_cast(Matrice_Bloc, matrice.get_bloc(0,0).valeur());
1142 Matrice_Bloc& A01=ref_cast(Matrice_Bloc, matrice.get_bloc(0,1).valeur());
1143 Matrice_Bloc& A11=ref_cast(Matrice_Bloc, matrice.get_bloc(1,1).valeur());
1144
1145 // Modification du bloc A11
1146 // As1s2~=As1s2-beta*[somme(Ak1s2)(s1 appartient a k1)+somme(Ak1s1)(s2 appartenant a k1)]+beta*beta*somme(Ak1k2)(s1 appartenant a k1 et s2 appartenant a k2)
1147 operation11(A00,A01,A11,beta_,domaine_Vef().domaine());
1148
1149 // Modification du bloc A01
1150 // Ak1s~=alpha*Ak1s - alpha*beta*somme(Ak1k2)(s appartenant a k2)
1151 A01*=alpha_;
1152 operation01(A00,A01,alpha_,beta_,domaine_Vef().domaine());
1153
1154 // Modification du bloc A00
1155 // Ak1k2~ = alpha * alpha * Ak1k2
1156 A00*=alpha_*alpha_;
1157}
1158
1159
1161{
1162 // ys~ = ys - beta * somme(yk)(s appartenant a k)
1163 // yk~ = alpha * yk
1166}
1167
1169{
1170 // xk = alpha * xk~ - beta * somme(xs~)(s appartenant a k)
1171 // xs = xs~
1173 assert(check_espace_virtuel_vect(x));
1174}
1175
1177{
1178 // xk~ = xk / alpha + beta / alpha * somme(xs)(s appartenant a k)
1179 // xs~ = xs
1181 assert(check_espace_virtuel_vect(x));
1182}
1183
1184template<vecteur _v_>
1186{
1187 assert(domaine_Vef().get_alphaE() && domaine_Vef().get_alphaS() && !domaine_Vef().get_alphaA()); // P0+P1 uniquement
1188 // xk~ = xk / alpha + beta / alpha * somme(xs)(s appartenant a k)
1189 // xs~ = xs
1190 double alpha = alpha_;
1191 double beta = beta_;
1192 int nb_elem_tot = domaine_Vef().nb_elem_tot();
1193 int nb_som_elem = domaine_Vef().domaine().les_elems().dimension(1);
1194 CIntTabView les_elems = domaine_Vef().domaine().les_elems().view_ro();
1195 CIntArrView renum_som_perio = domaine_Vef().domaine().get_renum_som_perio().view_ro();
1196 DoubleArrView v = tab_v.view_rw();
1197 Kokkos::parallel_for(start_gpu_timer(__KERNEL_NAME__), nb_elem_tot, KOKKOS_LAMBDA(const int k)
1198 {
1199 if (_v_==vecteur::pression) v(k) /= alpha;
1200 double somme=0;
1201 for (int som=0; som<nb_som_elem; som++)
1202 {
1203 int s = nb_elem_tot + renum_som_perio(les_elems(k, som));
1204 if (_v_==vecteur::pression) somme += v(s);
1205 if (_v_==vecteur::pression_inverse) somme += v(s);
1206 if (_v_==vecteur::second_membre) Kokkos::atomic_sub(&v(s), beta * v(k));
1207 }
1208 if (_v_==vecteur::pression) v(k) += beta / alpha * somme;
1209 if (_v_==vecteur::pression_inverse) v(k) = alpha * v(k) - beta * somme;
1210 if (_v_==vecteur::second_membre) v(k) *= alpha;
1211 });
1212 end_gpu_timer(__KERNEL_NAME__);
1213}
const Equation_base & equation() const
int modifier_solution(DoubleTab &) override
void changer_base_second_membre(DoubleVect &)
void changer_base_pression_inverse(DoubleVect &)
int assembler_mat(Matrice &, const DoubleVect &, int incr_pression, int resoudre_en_u) override
void changer_base_pression(DoubleVect &)
int modifier_secmem_aretes(const DoubleTab &, DoubleTab &)
int modifier_secmem_elem(const DoubleTab &, DoubleTab &)
int modifier_secmem_som(const DoubleTab &, DoubleTab &)
int assembler_rho_variable(Matrice &, const Champ_Don_base &) override
Assemblage de la matrice div( porosite/rho * grad P ) Le type du champ "rho" a fournir depend de la d...
const Domaine_VEF & domaine_Vef() const
int modifier_secmem(DoubleTab &) override
int assembler(Matrice &) override
int modifier_matrice(Matrice &) override
Modifier eventuellement la matrice pour la rendre definie si elle ne l'est pas Valeurs par defaut:
void completer(const Equation_base &) override
virtual int modifier_matrice(Matrice &)
Modifier eventuellement la matrice pour la rendre definie si elle ne l'est pas Valeurs par defaut:
void calculer_inv_volume(DoubleTab &inv_volumes_entrelaces, const Domaine_Cl_VEF &domaine_Cl_VEF, const DoubleVect &volumes_entrelaces)
int modifier_solution(DoubleTab &) override
int assembler(Matrice &) override
void completer(const Equation_base &) override
int get_resoudre_en_u() const
Renvoie la valeur du drapeau resoudre_en_u_ (0 ou 1) Renvoie -1 si le drapeau n'a pas ete initialise.
int set_resoudre_en_u(int flag)
Definit la valeur du drapeau resoudre_en_u__.
int set_resoudre_increment_pression(int flag)
Definit la valeur du drapeau resoudre_increment_pression_.
classe Champ_Don_base classe de base des Champs donnes (non calcules)
DoubleTab & valeurs() override
Surcharge Champ_base::valeurs() Renvoie le tableau des valeurs.
classe Champ_Fonc_P1NC
classe Champ_front_base Classe de base pour la hierarchie des champs aux frontieres.
virtual const DoubleTab & derivee_en_temps() const
virtual bool instationnaire() const
classe Cond_lim_base Classe de base pour la hierarchie des classes qui representent les differentes c...
virtual Frontiere_dis_base & frontiere_dis()
Renvoie la frontiere discretisee a laquelle les conditions aux limites s'appliquent.
Champ_front_base & champ_front()
classe Cond_lim Classe generique servant a representer n'importe quelle classe
Definition Cond_lim.h:31
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
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_t nb_elem_tot() const
Definition Domaine.h:132
const IntTab_t & aretes_som() const
renvoie le tableau de connectivite aretes/sommets.
Definition Domaine.h:156
virtual void creer_tableau_elements(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
creation d'un tableau parallele de valeurs aux elements.
Definition Domaine.cpp:851
int_t get_renum_som_perio(int_t i) const
Definition Domaine.h:281
int nb_joints() const
Definition Domaine.h:259
IntTab_t & les_elems()
Definition Domaine.h:129
Joint_t & joint(int i)
Definition Domaine.h:261
int_t nb_aretes() const
Renvoie le nombre d'aretes reelles.
Definition Domaine.h:143
const DoubleTab_t & coord_sommets() const
Definition Domaine.h:112
int_t elem_aretes(int_t i, int j) const
renvoie le numero de la jeme arete du ieme element.
Definition Domaine.h:154
int_t nb_som() const
Renvoie le nombre de sommets du domaine.
Definition Domaine.h:121
classe Domaine_Cl_dis_base Les objets Domaine_Cl_dis_base representent les conditions aux limites
int nb_cond_lim() const
Renvoie le nombre de conditions aux limites.
const Cond_lim & les_conditions_limites(int) const
Renvoie la i-ieme condition aux limites.
class Domaine_VEF
Definition Domaine_VEF.h:54
int numero_premiere_arete() const
const IntVect & get_ok_arete() const
Definition Domaine_VEF.h:99
int numero_premier_sommet() const
int get_cl_pression_sommet_faible() const
Definition Domaine_VEF.h:97
int get_alphaA() const
Definition Domaine_VEF.h:94
const ArrOfInt & get_renum_arete_perio() const
Definition Domaine_VEF.h:98
int get_alphaS() const
Definition Domaine_VEF.h:93
int get_alphaE() const
Definition Domaine_VEF.h:92
DoubleVect & volumes_entrelaces()
Definition Domaine_VF.h:99
double xa(int num_arete, int k) const
Definition Domaine_VF.h:78
virtual double face_normales(int face, int comp) const
Definition Domaine_VF.h:47
double volumes(int i) const
Definition Domaine_VF.h:113
int face_sommets(int i, int j) const
renvoie le numero du ieme sommet de la face num_face.
Definition Domaine_VF.h:583
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 face_voisins(int num_face, int i) const
renvoie l'element voisin de numface dans la direction i.
Definition Domaine_VF.h:418
classe Domaine_dis_base Cette classe est la base de la hierarchie des domaines discretisees.
int nb_elem_tot() const
const Domaine & domaine() const
classe Entree_fluide_vitesse_imposee Cas particulier de la classe Dirichlet_entree_fluide
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
classe Equation_base Le role d'une equation est le calcul d'un ou plusieurs champs....
virtual const Milieu_base & milieu() const =0
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
int epaisseur() const
Definition Joint.h:50
const Matrice & get_bloc(int i, int j) const override
void dimensionner(int N, int M) override
int nb_bloc_lignes() const
int ordre() const override
If square matrix, returns number of lines, otherwise 0.
int nb_bloc_colonnes(void) const
virtual const Matrice & get_bloc(int i, int j) const
Classe Matrice_Morse_Sym Represente une matrice M (creuse) symetrique stockee au format Morse.
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
const auto & get_tab2() const
const auto & get_tab1() const
int nb_colonnes() const override
Return local number of columns (=size on the current proc).
const auto & get_coeff() const
int nb_lignes() const override
Return local number of lines (=size on the current proc).
void set_est_definie(int)
int get_est_definie() const
Classe Matrice Classe generique de la hierarchie des matrices.
Definition Matrice.h:34
DoubleVect & porosite_face()
Definition Milieu_base.h:62
const Equation_base & equation() const
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
classe Navier_Stokes_std Cette classe porte les termes de l'equation de la dynamique
classe Neumann_sortie_libre Cette classe represente une frontiere ouverte sans vitesse imposee
static int dimension
Definition Objet_U.h:99
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
static double calculer_coef_som(int elem, const Domaine_Cl_VEF &zcl, const Domaine_VEF &domaine_VEF)
static double mp_min(double)
Definition Process.cpp:386
static double mp_max(double)
Definition Process.cpp:376
static bool is_parallel()
Definition Process.cpp:110
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
Class Robin_VEF for Robin boundary conditions.
Definition Robin_VEF.h:44
int associer(const Assembleur_P_VEFPreP1B &, const SolveurSys &)
class SolveurSys Un SolveurSys represente n'importe qu'elle classe
Definition SolveurSys.h:32
Classe de base des flux de sortie.
Definition Sortie.h:52
_SIZE_ size_array() const
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, View< _TYPE_, _SHAPE_ > > view_wo()
Definition TRUSTTab.h:276
std::enable_if_t< is_default_exec_space< EXEC_SPACE >, ConstView< _TYPE_, _SHAPE_ > > view_ro() const
Definition TRUSTTab.h:261
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")