TrioCFD 1.9.9_beta
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 and 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 // To change basis and recover 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 // Multiply by mass density at faces
179 if (!sub_type(Champ_Fonc_P1NC, rho))
180 {
181 Cerr << "The mass density is not at faces in 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 // Assemble the matrix
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 // Set the flags of 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()) // Read the matrix from a file (only supported by PETSc for now)
222 {
223 la_matrice.typer("Matrice_Petsc");
224 }
225 else // Assemble the matrix
226 {
227 const Domaine_VEF& domaine_vef = domaine_Vef();
228 Cerr << "Assembling pressure matrix" << (domaine_vef.get_alphaE() ? " P0" : "")
229 << (domaine_vef.get_alphaS() ? " P1" : "") << (domaine_vef.get_alphaA() ? " Pa" : "") << " in progress..." << finl;
230
231 // Partitions must have ghost cell width of 2
232 // if P1 or Pa support is used...
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 // Assemble the complete matrix according to the chosen supports
261 Matrice la_matrice_de_travail_; // Working matrix
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 // Set the matrix to zero even if it was correctly built and filled by the
292 // assemblerPiPi methods, then refill it. Why? To have sufficient test coverage
293 // of the updatePiPi methods while waiting to properly factorize the
294 // assemblerPiPi and updatePiPi methods
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 // Verification method
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 // Optional basis change P0P1->P1Bulle
334 ////////////////////////////////////////////
335 if (changement_base())
336 changer_base_matrice(la_matrice_de_travail_); // A->A~
337
338 /////////////////////////////////////////////////////////////
339 // Modify the matrix if there is no reference pressure
340 /////////////////////////////////////////////////////////////
341 modifier_matrice(la_matrice_de_travail_);
342
343 // Optional conversion to 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) // We are not in P0 only
346 {
347 //////////////////////////////////////////////////////////
348 // The returned matrix is a cleaned Matrice_Morse_Sym
349 // if the solver used supports this matrix type
350 // and if we are not in P0 only (in that case,
351 // conversion to Mat_Morse_Sym brings nothing and crashes SSOR
352 // because the Morse matrix then contains virtual parts
353 // with no shared items and we hit
354 // the assert assert(*tab2_ptr<=n); Two other solutions:
355 // -Modify SSOR to solve only the real part
356 // -For P0 only, empty VV and RV in 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);// Removal of zero and near-zero coefficients
363 }
364 else
365 {
366 /////////////////////////////////////////////////////////
367 // The returned matrix is a cleaned Matrice_Bloc_Sym
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); // Removal of zero and near-zero coefficients
377 }
378 }
379 }
380
381 // If not already done, use a solver (SolveurPP1B) that will perform basis changes for the solution and the right-hand side
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 // Optional display of the matrix condition number
392 //////////////////////////////////////////////////////
393 char* theValue2 = getenv("TRUST_CONDITIONNEMENT_MATRICE");
394 if(theValue2 != nullptr)
395 Cout << "Estimation of the matrix condition number: " << estim_cond(la_matrice)<<finl;
396
397 return 1;
398}
399
401{
402 const Domaine_VEF& le_dom = domaine_Vef();
403
404 // Verification on the Pa support
405 if (le_dom.get_alphaA())
406 {
407 // Verify on edges that:
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 does not necessarily have its virtual space up to date
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.) // Superfluous edges have a zero value
416 {
417 Cerr << "Pb div Edges, the pressure on edge " << i << " (which is superfluous) is not zero." << finl;
419 }
420 else if ( (renum_arete_perio[i]!=i) && b(npa+i)!=0.) // Periodic edges have a zero value
421 {
422 Cerr << "Pb div Periodic Edges, the pressure on edge " << i << " (which is periodic) is not zero." << finl;
424 }
425 }
426
427 // Verification on the P1 support
428 if (le_dom.get_alphaS())
429 {
430 // Verify that the pressure on periodic vertices is zero
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, the pressure on vertex %ld (which is periodic) is not zero.\n",(long)i);
443 printf("In plain terms, the right-hand side is not zero on a periodic vertex.\n");
444 if (b_v(nps+i)!=b_v(nps+k))
445 {
446 printf("Moreover, the right-hand side does not have the same value on the 2 periodic vertices.\n");
447 printf("b(nps+i)=%f <> b(nps+k)=%f\n",b_v(nps+i),b_v(nps+k));
448 }
449 Kokkos::abort("There is a probability that the model used is poorly implemented for\na periodicity condition. Contact TRUST support.");
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 /* Retrieval of Gpoint */
466 /**************************/
467 DoubleTrav tab_Gpoint(equation().inconnue().valeurs());
468 DoubleTabView Gpoint = tab_Gpoint.view_wo();
469
470 //Gpoint=0.; A DoubleTrav is initialized to 0
471 int Gpoint_nul = 1; // Flag to potentially save a echange_espace_virtuel call
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 on the nature of the field at the domain boundary */
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 //For parallelism
501 if (!Gpoint_nul) tab_Gpoint.echange_espace_virtuel();
502
503 /******************************/
504 /* End of Gpoint retrieval */
505 /******************************/
506
507 /*********************************/
508 /* Modification of the right-hand side */
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 /* End of right-hand side modification */
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 on the nature of the field at the domain boundary */
537 if (sub_type(Entree_fluide_vitesse_imposee, cl_base) && champ_front.instationnaire() )
538 {
539 // Build the list of faces to process (real + virtual)
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 on the nature of the field at the domain boundary */
583 if (sub_type(Entree_fluide_vitesse_imposee, cl_base) && champ_front.instationnaire())
584 {
585 // Build the list of faces to process (real + virtual)
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 //Compute the velocity at the element centre
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 //Compute the divergence of the velocity
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 //End of velocity divergence computation
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 on edges
664 if (le_dom.get_alphaA())
665 {
666 // Impose pressure = 0 on superfluous edges:
667 const IntVect& ok_arete=le_dom.get_ok_arete();
668 const ArrOfInt& renum_arete_perio=le_dom.get_renum_arete_perio();
669 // Number of real edges
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: pressure on superfluous edge, 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: pressure on superfluous periodic edge, P(" << npa+i << ")=" << tab_pression(npa+i) << finl;
683 tab_pression(npa+i)=0;
685 }
686 }
687 }
688
689 // Apply periodicity on vertices for the pressure:
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 // to remove the pressure minimum if no Pref and if only P0, otherwise filter later
708 if (le_dom.get_alphaE() && (le_dom.get_alphaS()==0) && (le_dom.get_alphaA()==0) )
710 // Verification possible via environment variable:
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 does not yet work with your discretization" << finl;
723 }
724 // Various verifications of boundary conditions
725 // by post-processing the result in the Divergence_U field
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 << "Element " << elem << " has " << Faces_de_Dirichlet(elem) << " Dirichlet faces separated by a ";
764 const IntVect& ok_arete=domaine_Vef().get_ok_arete();
765 const IntTab& aretes_som=domaine_Vef().domaine().aretes_som();
766 // Loop over edges to verify boundary edges
767 for (int k=0; k<6; k++)
768 {
769 int arete=domaine_Vef().domaine().elem_aretes(elem,k);
770 // The 2 vertices of the edge
771 int S0=aretes_som(arete,0);
772 int S1=aretes_som(arete,1);
773 // Verify if they appear twice in the vertices of the faces,
774 // in which case this is the edge shared by 2 Dirichlet faces
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 << "edge " << (ok_arete(arete)==0?"superfluous":"") << finl;
786 // Count the superfluous edges
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 only works in P0+P1+Pa mode" << 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 Optionally modify the matrix to make it definite if it is not. Default values:
836 *
837 * Constraints:
838 * Access: input
839 *
840 * @return 1 if the matrix was modified, 0 otherwise.
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 // Check if there is a reference pressure; if so, the matrix is not modified
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 // Also verify that the pressure is indeed zero on Pa support
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 << "Non-zero imposed pressure boundary condition is not yet" << finl;
862 Cerr << "supported in VEF with edge support Pa." << finl;
863 // Work to be done in 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 // Impose a reference pressure on an element if no Neumann boundary condition
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 // Impose a reference pressure on a vertex if P0 support or if no Neumann boundary condition
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 << "Modifying vertex row " << 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 // Impose a reference pressure on an edge in P0+Pa mode only
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 << "Modifying edge row " << 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 // Traverse the elements of matrix 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]; // Compute 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 // Traverse the elements of matrix 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); // Vertex s1
1066 double prod = -beta * coeff[n]; // Compute -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)); // Vertex 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 // Iterate over the coefficients of 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]; // Compute -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 << "Basis change for the matrix: 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 of block A11
1146 // As1s2~=As1s2-beta*[somme(Ak1s2)(s1 belongs to k1)+somme(Ak1s1)(s2 belonging to k1)]+beta*beta*somme(Ak1k2)(s1 belonging to k1 and s2 belonging to k2)
1147 operation11(A00,A01,A11,beta_,domaine_Vef().domaine());
1148
1149 // Modification of block A01
1150 // Ak1s~=alpha*Ak1s - alpha*beta*somme(Ak1k2)(s belonging to k2)
1151 A01*=alpha_;
1152 operation01(A00,A01,alpha_,beta_,domaine_Vef().domaine());
1153
1154 // Modification of block A00
1155 // Ak1k2~ = alpha * alpha * Ak1k2
1156 A00*=alpha_*alpha_;
1157}
1158
1159
1161{
1162 // ys~ = ys - beta * somme(yk)(s belonging to k)
1163 // yk~ = alpha * yk
1166}
1167
1169{
1170 // xk = alpha * xk~ - beta * somme(xs~)(s belonging to k)
1171 // xs = xs~
1173 assert(check_espace_virtuel_vect(x));
1174}
1175
1177{
1178 // xk~ = xk / alpha + beta / alpha * somme(xs)(s belonging to 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 belonging to 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
Assembly of the matrix div(porosity/rho * grad P) The type of the "rho" field to be provided depends ...
const Domaine_VEF & domaine_Vef() const
int modifier_secmem(DoubleTab &) override
int assembler(Matrice &) override
int modifier_matrice(Matrice &) override
Optionally modify the matrix to make it definite if it is not. Default values:
void completer(const Equation_base &) override
virtual int modifier_matrice(Matrice &)
Optionally modifies the matrix to make it definite if it is not.
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
Returns the value of the resoudre_en_u_ flag (0 or 1) Returns -1 if the flag has not been initialized...
int set_resoudre_en_u(int flag)
Sets the value of the resoudre_en_u__ flag.
int set_resoudre_increment_pression(int flag)
Sets the value of the resoudre_increment_pression_ flag.
class Champ_Don_base base class of Given Fields (not calculated)
DoubleTab & valeurs() override
Overrides Champ_base::valeurs() Returns the array of values.
class Champ_Fonc_P1NC
class Champ_front_base Base class for the hierarchy of boundary fields.
virtual const DoubleTab & derivee_en_temps() const
virtual bool instationnaire() const
class Cond_lim_base Base class for the hierarchy of classes that represent the different boundary con...
virtual Frontiere_dis_base & frontiere_dis()
Returns the discretized boundary to which the boundary conditions apply.
Champ_front_base & champ_front()
class Cond_lim Generic class used to represent any class
Definition Cond_lim.h:31
class Conds_lim This class represents a vector of boundary conditions.
Definition Conds_lim.h:32
Classe Dirichlet_homogene This class is the base class of the hierarchy of homogeneous Dirichlet-type...
Dirichlet This class is the base class of the hierarchy of Dirichlet-type boundary conditions.
Definition Dirichlet.h:31
int_t nb_elem_tot() const
Definition Domaine.h:132
const IntTab_t & aretes_som() const
returns the connectivity array edges/vertices.
Definition Domaine.h:156
virtual void creer_tableau_elements(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
Creates a parallel array of values at elements.
Definition Domaine.cpp:850
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
Returns the number of real edges.
Definition Domaine.h:143
const DoubleTab_t & coord_sommets() const
Definition Domaine.h:112
int_t elem_aretes(int_t i, int j) const
returns the number of the j-th edge of the i-th element.
Definition Domaine.h:154
int_t nb_som() const
Returns the number of vertices of the domain.
Definition Domaine.h:121
class Domaine_Cl_dis_base Domaine_Cl_dis_base objects represent discretized boundary conditions
int nb_cond_lim() const
Returns the number of boundary conditions.
const Cond_lim & les_conditions_limites(int) const
Returns the i-th boundary condition.
class Domaine_VEF
Definition Domaine_VEF.h:53
int numero_premiere_arete() const
const IntVect & get_ok_arete() const
Definition Domaine_VEF.h:98
int numero_premier_sommet() const
int get_cl_pression_sommet_faible() const
Definition Domaine_VEF.h:96
int get_alphaA() const
Definition Domaine_VEF.h:93
const ArrOfInt & get_renum_arete_perio() const
Definition Domaine_VEF.h:97
int get_alphaS() const
Definition Domaine_VEF.h:92
int get_alphaE() const
Definition Domaine_VEF.h:91
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
Returns the index of the i-th vertex of face num_face.
Definition Domaine_VF.h:582
int elem_faces(int i, int j) const
Returns the index of the i-th face of element num_elem; the face numbering convention is.
Definition Domaine_VF.h:542
int face_voisins(int num_face, int i) const
Returns the neighbouring element of num_face in direction i.
Definition Domaine_VF.h:418
class Domaine_dis_base This class is the base of the hierarchy of discretized domains.
int nb_elem_tot() const
const Domaine & domaine() const
Entree_fluide_vitesse_imposee Special case of the class Dirichlet_entree_fluide.
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
class Equation_base The role of an equation is the calculation of one or more fields....
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
Matrice_Morse_Sym class - Represents a sparse symmetric matrix M stored in Morse format.
Matrice_Morse class - Represents a (sparse) matrix M, not necessarily square,.
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
Matrice class - Generic class in the matrix hierarchy.
Definition Matrice.h:34
DoubleVect & porosite_face()
Definition Milieu_base.h:62
const Equation_base & equation() const
Returns the reference to the equation pointed to by MorEqn::mon_equation.
Definition MorEqn.h:62
Navier_Stokes_std This class carries the terms of the momentum equation.
Neumann_sortie_libre This class represents an open boundary without imposed velocity.
static int dimension
Definition Objet_U.h:94
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
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:391
static double mp_max(double)
Definition Process.cpp:379
static bool is_parallel()
Definition Process.cpp:108
static int me()
Returns the rank of the local processor in the current communication group. See Comm_Group::rank() an...
Definition Process.cpp:122
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
Class Robin_VEF for Robin boundary conditions.
Definition Robin_VEF.h:44
int associer(const Assembleur_P_VEFPreP1B &, const SolveurSys &)
class SolveurSys A SolveurSys represents any class
Definition SolveurSys.h:32
Base class for output streams.
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")