TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Source_Con_Phase_field_Naire.cpp
1/****************************************************************************
2* Copyright (c) 2021, 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 <Convection_Diffusion_Phase_field.h>
17#include <Source_Qdm_VDF_Phase_field.h>
18#include <Navier_Stokes_phase_field.h>
19#include <Source_Con_Phase_field.h>
20#include <Source_Con_Phase_field_Naire.h>
21#include <Check_espace_virtuel.h>
22#include <MD_Vector_composite.h>
23#include <Milieu_Phase_field.h>
24#include <Champ_Fonc_Tabule.h>
25#include <Domaine_Cl_VDF.h>
26#include <TRUSTTab_parts.h>
27#include <Champ_Uniforme.h>
28#include <Equation_base.h>
29#include <Probleme_base.h>
30#include <Domaine_VDF.h>
31#include <Milieu_base.h>
32#include <SolveurSys.h>
33#include <Dimension.h>
34#include <EChaine.h>
35#include <Param.h>
36
37Implemente_instanciable(Source_Con_Phase_field_Naire,"Source_Con_Phase_field_Naire_VDF_P0_VDF",Source_Con_Phase_field);
38
39// XD Source_Con_Phase_field_Naire_VDF_P0_VDF Source_Con_Phase_field Source_Con_Phase_field_Naire_VDF_P0_VDF INHERITS_BRACE Source for phase field
40
42{
43 return s << que_suis_je();
44}
45
47{
48 Cerr << "Source_Con_Phase_field_Naire::readOn" << finl;
49
51 return is;
52}
53
54DoubleTab& Source_Con_Phase_field_Naire::laplacien(const DoubleTab& F, DoubleTab& resu) const
55{
56 const Navier_Stokes_std& eq_ns = ref_cast(Navier_Stokes_std, pb_->equation(0));
57 const Operateur_Grad& opgrad = eq_ns.operateur_gradient();
58 const Operateur_Div& opdiv = eq_ns.operateur_divergence();
59 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
60 const int nb_comp = mil.get_fermeture().get_nb_constituants();
61
62 resu = 0.;
63
64 // Dans cette partie, le laplacien s'obtient comme div(grad F) ou F est un DoubleTab avec nb_comp colonnes.
65 // On introduit des fonctions temporaires (temp) pour le calcul de chaque colonne avant de les regrouper dans un DoubleTab a la fin
66 DoubleTab& prov_face = ref_cast_non_const(DoubleTab, prov_face_);
67 if (prov_face.size() == 0)
68 prov_face = eq_ns.inconnue().valeurs();
69 prov_face = 0.;
70 // Grad(F)
71 DoubleTab temp_resu(resu.dimension_tot(0), 1);
72 temp_resu = 0;
73 DoubleTab temp_F(F.dimension_tot(0), 1);
74 for (int j = 0; j < nb_comp; j++)
75 {
76 prov_face = 0.;
77 for (int i = 0; i < temp_F.dimension(0); i++)
78 temp_F(i, 0) = F(i, j);
79 opgrad.calculer(temp_F, prov_face);
80
81 // Application solveur masse
82 eq_ns.solv_masse().appliquer(prov_face);
83
84 // Laplacien = Div(Grad(F))
85 opdiv.calculer(prov_face, temp_resu);
86 for (int i = 0; i < temp_resu.dimension(0); i++)
87 resu(i, j) = temp_resu(i, 0);
88 }
89
90 return resu;
91}
92
93DoubleTab& Source_Con_Phase_field_Naire::div_kappa_grad(const DoubleTab& F, const DoubleTab& kappa_var, DoubleTab& resu) const
94{
95 // NOTE: Le tableau F en entrée, dont on calcule le gradient, a la forme suivante :
96 // Deux colonnes, la première porte sur les éléments du volume de simulation, la deuxième porte sur le nombre d'équations de Cahn-Hilliard
97
98 const Navier_Stokes_std& eq_ns = ref_cast(Navier_Stokes_std, pb_->equation(0));
99 const Operateur_Grad& opgrad = eq_ns.operateur_gradient();
100 const Operateur_Div& opdiv = eq_ns.operateur_divergence();
101 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
102
103 // const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
104 const int nb_comp = mil.get_fermeture().get_nb_constituants();
105
106 const Domaine_VDF& domaine_VDF = le_dom_VDF_.valeur();
107 const IntTab& face_voisins = domaine_VDF.face_voisins();
108 const DoubleVect& volumes = domaine_VDF.volumes();
109
110 DoubleTab& prov_face = ref_cast_non_const(DoubleTab, prov_face_);
111 if (prov_face.size() == 0)
112 prov_face = eq_ns.inconnue().valeurs();
113 prov_face = 0.;
114 resu = 0.;
115
116 // Grad(F)
117 DoubleTab temp_resu(resu.dimension_tot(0), 1);
118 temp_resu = 0;
119 DoubleTab temp_F(F.dimension_tot(0), 1);
120 DoubleTab temp_prov_face(prov_face.dimension_tot(0), F.line_size());
121 for (int j = 0; j < nb_comp; j++)
122 {
123 for (int i = 0; i < temp_F.dimension(0); i++)
124 temp_F(i, 0) = F(i, j);
125 opgrad.calculer(temp_F, prov_face);
126
127 for (int i = 0; i < prov_face.dimension(0); i++)
128 temp_prov_face(i, j) = prov_face(i, 0);
129 }
130
131 // Determine kappa_face et cface (faces interieures)
132 int ndeb = domaine_VDF.premiere_face_int();
133 int nbfaces = domaine_VDF.nb_faces();
134 int el0, el1;
135 double vol0, vol1;
136 DoubleTab kappa_face(prov_face.dimension(0), nb_comp * nb_comp);
137 //DoubleTab cface(prov_face.dimension(0),nb_comp);
138 for (int j = 0; j < nb_comp * nb_comp; j++)
139 {
140 for (int fac = ndeb; fac < nbfaces; fac++)
141 {
142 el0 = face_voisins(fac, 0);
143 el1 = face_voisins(fac, 1);
144 vol0 = volumes(el0);
145 vol1 = volumes(el1);
146 // on calcule kappa_face comme la moyenne des kappa des voisins
147 kappa_face(fac, j) = (vol0 * kappa_var(el0, j) + vol1 * kappa_var(el1, j)) / (vol0 + vol1);
148 }
149 }
150
151 // kappa*Grad(F) - sur les faces
152 DoubleTab temp_prov_face2 = temp_prov_face;
153 temp_prov_face2 = 0;
154 for (int j = 0; j < nb_comp; j++)
155 {
156 for (int i = 0; i < prov_face.dimension(0); i++)
157 {
158 prov_face(i, 0) = temp_prov_face(i, j);
159 for (int k = 0; k < nb_comp; k++)
160 temp_prov_face2(i, k) += prov_face(i, 0) * kappa_face(i, j + k * nb_comp);
161 }
162 }
163
164 // Application solveur masse (/M)
165 eq_ns.solv_masse().appliquer(temp_prov_face2);
166
167 // Div(Kappa*Grad(F))
168 for (int j = 0; j < nb_comp; j++)
169 {
170 for (int i = 0; i < prov_face.dimension(0); i++)
171 prov_face(i, 0) = temp_prov_face2(i, j);
172 opdiv.calculer(prov_face, temp_resu);
173 for (int i = 0; i < temp_resu.dimension(0); i++)
174 resu(i, j) = temp_resu(i, 0);
175 }
176
177 return resu;
178}
179
180/*! @brief Calcule le premier demi pas de temps dans le cas implicite Calcule le pas de temps dans le cas explicite
181 *
182 */
184{
185 const Domaine_VDF& domaine_VDF = le_dom_VDF_.valeur();
186 const int nb_elem = domaine_VDF.nb_elem_tot();
187
188 Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
189 DoubleTab& c = eq_c.inconnue().valeurs();
190
191 DoubleTab& mutilde = eq_c.set_mutilde_().valeurs();
192 DoubleTab& mutilde_demi = eq_c.set_mutilde_demi();
193 DoubleTab& c_demi = eq_c.set_c_demi();
194
195 Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
196 Fermeture_Phase_field_base& fermeture = mil.get_fermeture();
197
198 // Utilise dans l'ancien modele de Didier Jamet
199
200 /* commente par mr264902 car pas utilise dans la version presente
201 //DoubleTab& alpha_gradC_carre=eq_c.set_alpha_gradC_carre();
202 //calculer_alpha_gradC_carre(alpha_gradC_carre);
203 //DoubleTab& div_alpha_rho_gradC=eq_c.set_div_alpha_rho_gradC();
204 //
205 //calculer_div_alpha_rho_gradC(div_alpha_rho_gradC);
206 */
207 DoubleTab& div_alpha_gradC = eq_c.set_div_alpha_gradC();
208 // NOTE : La taille de div_alpha_gradC est la suivante :
209 // Deux colonnes, une sur le nombre d'éléments et une sur le nombre d'équations de Cahn-Hilliard
210 calculer_div_alpha_grad(c, div_alpha_gradC);
211 // commente par mr264902 car pas utilise dans la version presente
212 //DoubleTab& pression_thermo=eq_c.set_pression_thermo();
213 //calculer_pression_thermo(pression_thermo);
214
215 accr_ = c; // on copie la structure // !!
216 c_demi = c; // on copie la structure // !!
217
218 accr_ = 0.; // initialise a 0
219 c_demi = 0.; // initialise a 0
220
221 if (implicitation_ == 1)
222 {
223 Matrice_Morse matrice_diffusion_CH;
224 mutilde_demi = c; // on copie la structure // !!
225 mutilde_demi = 0.; // initialise a 0
226
227 // Pour le JFNK ----------------------------
228
229 // Commente par DJ
230 //----------------
231 // DoubleTab x1(2*nb_elem);
232 // x1=0.;
233 // if(gmres_==1)
234 // {
235
236 // // Ecriture de x1(0)
237 // for(int n_elem=0;n_elem<nb_elem;n_elem++)
238 // {
239 // x1(n_elem)=c(n_elem);
240 // x1(n_elem+nb_elem)=mutilde(n_elem);
241 // }
242 // }
243 //----------------
244 // ---------------------------------------------
245
247 assembler_matrice_mobilite_explicite(matrice_diffusion_CH);
248
249 // Modifie par DJ
250 //---------------
251 // resolution_jfnk(c, mutilde, matrice_diffusion_CH, x1);
252
253 if (getenv("TRUST_GMRES"))
254 {
255 // Creation d'un solveur et typage:
256 SolveurSys solveur_;
257 //Nom str = "Petsc Gmres { precond diag { } seuil 1.e-6 impr }";
258 Nom str = "Petsc Cholesky { impr }";
259
260 EChaine chl(str);
261 chl >> solveur_;
262
263 //DoubleVect x,b;
264 // Remplissage guess x et second membre
265
266 //const int ns = 2*c.size_totale();
267 int nb_elem_tot = c.size_totale();
268 DoubleTab X_c(c.size_totale());
269 DoubleTab X_mutilde(mutilde.size_totale());
270 DoubleTab x1(nb_elem, 2);
271 x1 = 0.;
272 domaine_VDF.domaine().creer_tableau_elements(x1, RESIZE_OPTIONS::NOCOPY_NOINIT);
273 double *x1_addr = x1.addr();
274 for (int j = 0; j < nb_equation_CH_; j++)
275 for (int i = 0; i < nb_elem; i++)
276 {
277 X_c(i + (j * nb_elem)) = c(i, j);
278 X_mutilde(i + (j * nb_elem)) = mutilde(i, j);
279 }
280
281 for (int n_elem = 0; n_elem < c.size_totale(); n_elem++)
282 {
283 x1_addr[n_elem] = X_c(n_elem);
284 x1_addr[n_elem + c.size_totale()] = X_mutilde(n_elem);
285 }
286
287 DoubleTab sm_c(nb_elem_tot);
288 DoubleTab sm_mutilde(nb_elem_tot);
289 DoubleTab second_membre(nb_elem_tot, 2);
290 domaine_VDF.domaine().creer_tableau_elements(second_membre, RESIZE_OPTIONS::NOCOPY_NOINIT);
291
292 // Assemblage du second membre
293 const DoubleVect& betaMatrix = fermeture.get_betaMatrix();
294 double *sm_addr = second_membre.addr();
295 for (int j = 0; j < nb_equation_CH_; j++)
296 for (int i = 0; i < nb_elem; i++)
297 {
298 sm_c(i + (j * nb_elem)) = c(i, j);
299
300 sm_mutilde(i + (j * nb_elem)) = betaMatrix(j) * fermeture.call_dWdc(c(i, j));
301 }
302 for (int n_elem = 0; n_elem < nb_elem_tot; n_elem++)
303 {
304 sm_addr[n_elem] = sm_c(n_elem);
305 sm_addr[n_elem + nb_elem] = sm_mutilde(n_elem);
306 }
307
308 // Resolution:
309 solveur_->reinit();
310 solveur_.resoudre_systeme(matrice_diffusion_CH, second_membre, x1);
311
312 // remplissage des resultats dans mutilde demi et cdemi
313
314 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
315 {
316 c_demi(n_elem) = x1_addr[n_elem];
317 mutilde_demi(n_elem) = x1_addr[n_elem + nb_elem];
318 }
319 c_demi.echange_espace_virtuel();
320 mutilde_demi.echange_espace_virtuel();
321 }
322 else
323 resolution_jfnk(c, mutilde, matrice_diffusion_CH, c_demi, mutilde_demi);
324
325 const double theta = 0.6;
326 // On stocke les nouveaux c et mutilde
327
328 //Cerr<<"c_demi apres resolution_jfnk"<<c_demi<<finl;
329 //Cerr<<"c apres resolution_jfnk"<<c<<finl;
330
331 for (int j = 0; j < nb_equation_CH_; j++)
332 {
333 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
334 {
335 // Commente par DJ
336 //----------------
337 // c_demi(n_elem)=x1(n_elem);
338 //----------------
339 c_demi(n_elem, j) -= (1 - theta) * c(n_elem, j);
340 c_demi(n_elem, j) /= theta;
341
342 // Commente par DJ
343 //----------------
344 // mutilde_demi(n_elem)=x1(n_elem+nb_elem);
345 //----------------
346 //c=c_demi;
347 //calculer_mutilde_demi(mutilde_demi, c_demi);
348 //calculer_mutilde(mutilde_demi);
349 //mutilde=mutilde_demi;
350 mutilde_demi(n_elem, j) -= (1 - theta) * mutilde(n_elem, j);
351 mutilde_demi(n_elem, j) /= theta;
352 }
353 }
354
355 c_demi.echange_espace_virtuel();
357 mutilde.echange_espace_virtuel();
358
359 // ATTENTION : A VERIFIER
360 //=======================
361 // c_demi.echange_espace_virtuel();
362 // mutilde_demi.echange_espace_virtuel();
363 // c.echange_espace_virtuel();
364 // mutilde.echange_espace_virtuel();
365
366 // Mise a jour
367
368 if (couplage_ == 0)
369 {
370 // Si traitement explicite de mutilde dans le cas implicite
371 calculer_mutilde(mutilde);
372 }
373 else if (couplage_ == 1)
374 {
375 // Si traitement implicite de mutilde dans le cas implicite
376 mutilde = mutilde_demi;
377 }
378 mutilde.echange_espace_virtuel();
379
380 // Calcul de l'accroissement entre n et n+1/2
381 // Utile pour pouvoir utiliser n'importe quel dt
382 accr_ = 0.;
383 //Cerr<<"c_demi avant } fin implicitation ==1"<<c_demi<<finl;
384
385 }
386 else if (implicitation_ == 0)
387 {
388 // Cerr<<"Schema explicite"<<finl;
390 calculer_mutilde(mutilde);
391 mutilde.echange_espace_virtuel();
392
393 DoubleTab& prov_elem = prov_elem_;
394 if (prov_elem.size() == 0)
395 prov_elem = mutilde;
396
397 if (fermeture.get_type_kappa_auto_diffusion() == 0)
398 {
399 DoubleTab temp_mutilde(mutilde.dimension(0), 1);
400 temp_mutilde = 0;
401 DoubleTab temp_prov_elem = temp_mutilde;
402
403 // laplacien(mutilde)
404 laplacien(mutilde, prov_elem);
405 // Cerr << "laplacien mutilde " << prov_elem<<finl;
406
407 //kappa*laplacien(mutilde)
408 DoubleTab temp_prov_elem2 = prov_elem;
409 temp_prov_elem2 = 0;
410 const int nb_comp = fermeture.get_nb_constituants();
411 for (int j = 0; j < prov_elem.line_size(); j++)
412 {
413 for (int i = 0; i < prov_elem.dimension(0); i++)
414 {
415 temp_prov_elem(i, 0) = prov_elem(i, j);
416 for (int k = 0; k < nb_comp; k++)
417 {
418 temp_prov_elem2(i, k) += temp_prov_elem(i, 0) * fermeture.get_kappaMatrix()(j + k * nb_comp);
419 }
420 }
421 }
422 prov_elem = temp_prov_elem2;
423 }
424 else if (fermeture.get_type_kappa_auto_diffusion() == 1)
425 {
426 DoubleTab kappaMatrix_variable(prov_elem.dimension(0), c.line_size() * c.line_size()); //or (nb_elem,nb_comp*nb_comp)
427 kappaMatrix_variable = fermeture.call_kappa_func_c_naire(c);
428
429 //Div_kappa_grad
430 div_kappa_grad(mutilde, kappaMatrix_variable, prov_elem);
431
432 }
433
434 // Pour equation Allen-Cahn (kappa constant)
435 //------------------------------------------
436 // prov_elem=F;
437 // prov_elem*=-kappa;
438
439 accr_ += prov_elem;
440 //eq_c.solv_masse().appliquer(prov_elem);
441 //Cerr<<"masse de la force sur c "<<prov_elem.max_abs()<<finl;
442
443 // Utile pour pouvoir utiliser n'importe quel dt - voir Schema_Phase_Field
444 c_demi = c;
445 //Cerr <<"c_demi"<<c_demi<<finl;
446 }
447 else
448 {
449 Cerr << "Type de schema errone !!" << finl;
450 }
451}
452
453/*! @brief Calcul de Div(alpha*rho*Grad((C)) au centre des elements
454 *
455 * @param (DoubleTab& div_alpha_gradC) Div(alpha*Grad((C)) au centre des elements
456 */
457void Source_Con_Phase_field_Naire::calculer_div_alpha_grad(const DoubleTab& c, DoubleTab& div_alpha_gradC) const
458{
459 // NOTE: Le tableau c donné en entrée est une concentration, ou doit être similaire à une concentration
460 // Dans le cas n-aire, la concentration est un tableau à deux colonnes : une sur les éléments du domaine, et une autre sur le
461 // nombre d'équations de Cahn-Hilliard.
462
463 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
464 const Navier_Stokes_std& eq_ns = ref_cast(Navier_Stokes_std, pb_->equation(0));
465 const Operateur_Grad& opgrad = eq_ns.operateur_gradient();
466 const Operateur_Div& opdiv = eq_ns.operateur_divergence();
467 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
468 const auto& fermeture = mil.get_fermeture();
469
470 const int nb_comp = fermeture.get_nb_constituants();
471 // Attention ici, nb_comp est le nombre de phases du système, pas la dimension du domaine ( /= nb_compo)
472
473 DoubleTab& prov_face = ref_cast_non_const(DoubleTab, prov_face_);
474 if (prov_face.size() == 0)
475 prov_face = eq_ns.inconnue().valeurs();
476 prov_face = 0.;
477 DoubleTab temp_prov_face2(prov_face.dimension(0), nb_comp);
478 temp_prov_face2 = 0;
479 // Grad(c)
480 DoubleTab temp_resu(div_alpha_gradC.dimension_tot(0), 1);
481 temp_resu = 0;
482 DoubleTab temp_c(c.dimension_tot(0), 1);
483 for (int j = 0; j < nb_comp; j++)
484 {
485 prov_face = 0.;
486 for (int i = 0; i < temp_c.dimension(0); i++)
487 {
488 temp_c(i, 0) = c(i, j);
489 }
490 opgrad.calculer(temp_c, prov_face);
491
492 // Application solveur masse
493 eq_ns.solv_masse().appliquer(prov_face);
494
495 // alpha*Grad(C)
496 for (int i = 0; i < prov_face.dimension(0); i++)
497 {
498 for (int k = 0; k < nb_comp; k++)
499 temp_prov_face2(i, k) += prov_face(i) * fermeture.get_alphaMatrix()(j + k * nb_comp);
500 prov_face(i) = temp_prov_face2(i, j);
501 }
502
503 // Div(Grad(c))
504 opdiv.calculer(prov_face, temp_resu);
505 //opdiv.calculer(temp_prov_face2,div_alpha_gradC);
506 eq_c.solv_masse().appliquer(temp_resu);
507
508 for (int i = 0; i < temp_resu.dimension(0); i++)
509 div_alpha_gradC(i, j) = temp_resu(i, 0);
510 }
511
512}
513
514/*! @brief Calcul de Div(alpha*rho*Grad((C)) au centre des elements
515 *
516 * @param (DoubleTab& div_alpha_rho_gradC) Div(alpha*rho*Grad((C)) au centre des elements
517 */
518void Source_Con_Phase_field_Naire::calculer_div_alpha_rho_grad(const DoubleTab& c, DoubleTab& div_alpha_rho_gradC) const
519{
520 // const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
521 // const DoubleTab& c = eq_c.inconnue().valeurs();
522// const Navier_Stokes_phase_field& eq_ns = ref_cast(Navier_Stokes_phase_field, pb_->equation(0));
523// const Operateur_Grad& opgrad = eq_ns.operateur_gradient();
524// const Operateur_Div& opdiv = eq_ns.operateur_divergence();
525// const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
526// const auto& fermeture = mil.get_fermeture();
527//
528// const Domaine_VDF& domaine_VDF = le_dom_VDF_.valeur();
529// const IntTab& face_voisins = domaine_VDF.face_voisins();
530// const DoubleVect& volumes = domaine_VDF.volumes();
531// const int ndeb = domaine_VDF.premiere_face_int();
532// const int nbfaces = domaine_VDF.nb_faces();
533//
534// int el0, el1;
535// double vol0, vol1;
536
537 // To do ?
538
539}
540
541/*! @brief Assemble la matrice pour le calcul du point fixe
542 *
543 */
545{
546 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
547 const DoubleTab& c = eq_c.inconnue().valeurs();
548 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
549 const auto& fermeture = mil.get_fermeture();
550
551 const Domaine_VDF& domaine_VDF = le_dom_VDF_.valeur();
552 const IntTab& face_voisins = domaine_VDF.face_voisins();
553 const IntTab& elem_faces = domaine_VDF.elem_faces();
554 const DoubleTab& positions = domaine_VDF.xp();
555 const IntVect& ori = domaine_VDF.orientation();
556
557 int compt = 0;
558 int compt1 = 0;
559 int compt2 = 0;
560
561 const int nb_elem = domaine_VDF.nb_elem_tot();
562 int nb_compo_;
563 int f0;
564 int min_tri;
565 int old_tri;
566 int voisin;
567 int nb_faces_au_bord;
568 int dimensionnement;
569 double dvar2 = 0.;
570 double dvarkeep = 0.;
571 double dt;
572 const double theta = 0.6;
573 double kappa_naire_interpolee = 0.;
574
575 if (mobilite_explicite_ == 1)
576 {
577 Cerr << "Explicit mobility: Building matrix A used in JFNK..." << finl;
578
579 // Cerr<<"Assemblage de la matrice du point fixe"<<finl;
580
581 // Dimension du pb
582 nb_compo_ = dimension;
583
584 // Forme de la matrice : ( I A )
585 // ( B I )
586
587 // Assemblage de la moitie superieure de la matrice : I et A
588
589 // On dimensionne la matrice A et donc en meme temps B (meme nombre de termes non nuls)
590 // Pour cela : dimension du vecteur coeff = (2 * dim + 1) * nb_elem - nombre_de_bords
591
592 DoubleTab kappa_Matrix_var(nb_elem, nb_equation_CH_ * nb_equation_CH_);
593 if (fermeture.get_kappa_ind() == 0)
594 {
595 for (int i = 0; i < nb_elem; i++)
596 for (int j = 0; j < nb_equation_CH_ * nb_equation_CH_; j++)
597 kappa_Matrix_var(i, j) = fermeture.get_kappaMatrix()(j);
598 }
599 else
600 {
601 kappa_Matrix_var = fermeture.call_kappa_func_c_naire(c);
602 }
603 //Cerr <<"kappaMatrix_Var = "<< kappa_Matrix_var<< finl;
604
605 // Forme de la matrice pour un systeme -naire :
606 // ici on montre uniquement pour un systeme quaternaire
607 // ( 1 0 0 A B C )
608 // ( 0 1 0 D E F )
609 // ( 0 0 1 G H J )
610 // ( K L M 1 0 0 )
611 // ( N P Q 0 1 0 )
612 // ( U V W 0 0 1 )
613
614 // Assemblage de la moitie superieure de la matrice : 1 0 0 A B C
615
616 // On dimensionne la matrice A et donc en meme temps toutes les matrices non unitaire B, C, ...(meme nombre de termes non nuls)
617 // Pour cela : dimension du vecteur coeff pour chaque matrice A = (2 * dim + 1) * nb_elem - nombre_de_bords
618
619 dimensionnement = (2 * nb_compo_ + 1) * nb_elem;
620
621 for (int elem = 0; elem < nb_elem; elem++)
622 {
623 for (int ncomp = 0; ncomp < 2 * nb_compo_; ncomp++)
624 {
625 f0 = elem_faces(elem, ncomp);
626 voisin = face_voisins(f0, 0);
627 if (face_voisins(f0, 0) == elem)
628 voisin = face_voisins(f0, 1);
629
630 if (voisin == -1)
631 dimensionnement--;
632 }
633 }
634 // Sur la meme ligne, on a 1 matrice unitaire et nb_equation_CH* matrice non_unitaire et non nul. Pour cela,
635 // On multiplie donc le nombre d'elements non nuls de la matrice A par le nb_equation_CH pour avoir le nombre d'element nnz sur la meme ligne
636 // Puis on ajoute le nombre de 1 venant de la matrice unitaire sur la premiere ligne.
637 // dimensionnement est le nombre d'element non nuls (nnz) dans la grosse matrice_diffusion_CH
638 // Le dimensionnement total est donc le nnz de la premiere ligne multiplie par 2*nb_equation_CH
639 dimensionnement *= nb_equation_CH_;
640 dimensionnement += nb_elem;
641 dimensionnement *= 2 * nb_equation_CH_;
642
643 // Allocation des tableaux specifiques a la matrice morse
644 matrice_diffusion_CH.dimensionner(nb_equation_CH_ * (2 * nb_elem), dimensionnement);
645 auto& coeff = matrice_diffusion_CH.get_set_coeff();
646 auto& tab2 = matrice_diffusion_CH.get_set_tab2();
647 auto& tab1 = matrice_diffusion_CH.get_set_tab1();
648
649 DoubleVect valeur_diag_naire(nb_equation_CH_);
650 //double valeur_diag_naire;
651
652 // Boucle sur le nombre de matrice dans la grosse matrice (matrice d'une matrice)
653 for (int ligne = 0; ligne < nb_equation_CH_; ligne++)
654 {
655 // Boucle sur le nombre d'elements
656 for (int elem = 0; elem < nb_elem; elem++)
657 {
658 valeur_diag_naire = 0.;
659 old_tri = -1;
660 nb_faces_au_bord = 0;
661
662 // On ajoute le 1 de la diagonale de la sous-matrice I du haut a gauche
663 coeff(compt) = 1;
664 tab2(compt2) = (ligne * nb_elem) + elem;
665 compt++;
666 compt2++;
667 tab1(compt1) = compt2;
668 compt1++;
669
670 // Calcul du nombre de bords
671 for (int ncomp = 0; ncomp < 2 * nb_compo_; ncomp++)
672 {
673 f0 = elem_faces(elem, ncomp);
674 voisin = face_voisins(f0, 0);
675 if (face_voisins(f0, 0) == elem)
676 voisin = face_voisins(f0, 1);
677
678 // On connait le voisin associe a la face en cours. On regarde s'il est au bord
679 if (voisin == -1)
680 nb_faces_au_bord++;
681 }
682
683 for (int ncomp = 0; ncomp < 2 * nb_compo_ - nb_faces_au_bord; ncomp++)
684 {
685 min_tri = nb_elem + 1; //initialisation de min_tri pour chaque face (une sorte de reference car le numero des voisins ne doit pas depasser nb_elem+1)
686 dt = eq_c.schema_temps().pas_de_temps(); // on fait un calcul sur un demi pas de temps
687 for (int mat = 0; mat < nb_equation_CH_; mat++)
688 {
689 int j = (ligne * nb_equation_CH_) + mat;
690 for (int ncomp_tri = 0; ncomp_tri < 2 * nb_compo_; ncomp_tri++)
691 {
692 f0 = elem_faces(elem, ncomp_tri);
693
694 // Voisin associe a la face - On s'assure de traiter un voisin et pas l'element resident
695 voisin = face_voisins(f0, 0);
696 if (face_voisins(f0, 0) == elem)
697 voisin = face_voisins(f0, 1);
698
699 // On va compter le nombre de voisins existants (faces non aux bords de l'element elem)
700 // Ceci sert a calculer la contribution au terme relatif a l'element elem
701 // Cas kappa variable : on utilise la moyenne (geometrique, harmonique ou arithmetique) des valeurs des mobilites
702 // des elements concernes par la face de calcul ("kappa_naire_interpolee")
703
704 //Cerr <<"f0 = "<<f0<<finl;
705
706 if (voisin != -1 && old_tri == -1)
707 {
708 dvar2 = pow((positions(elem, ori(f0)) - positions(voisin, ori(f0))), 2);
709 if (kappa_moy_ == 2)
710 kappa_naire_interpolee = pow(std::fabs(kappa_Matrix_var(elem, j) * kappa_Matrix_var(voisin, j)), 0.5); // Moyenne geometrique
711 else if (kappa_moy_ == 1)
712 {
713 if (kappa_Matrix_var(elem, j) == 0 || kappa_Matrix_var(voisin, j) == 0)
714 kappa_naire_interpolee = 0;
715 else
716 kappa_naire_interpolee = 2. / (1. / kappa_Matrix_var(elem, j) + 1. / kappa_Matrix_var(voisin, j)); // Moyenne harmonique
717 }
718 else if (kappa_moy_ == 0)
719 kappa_naire_interpolee = (kappa_Matrix_var(elem, j) + kappa_Matrix_var(voisin, j)) / 2.; // Moyenne arithmetique
720 valeur_diag_naire(mat) += theta * kappa_naire_interpolee * (dt / dvar2);
721 }
722
723 // Si le voisin a un numero plus petit que l'ancien minimum, on ne le prend pas en compte
724 // En effet, le nouveau minimum est un numero d'element qui lui sera superieur
725 // Rq : voisin>old_tri => voisin != -1 donc pour une face au bord le if est false
726 if (voisin > old_tri)
727 {
728 min_tri = std::min(min_tri, voisin);
729 if (min_tri == voisin)
730 dvarkeep = pow((positions(elem, ori(f0)) - positions(voisin, ori(f0))), 2);
731 }
732 }
733
734 // Si l'ancien minimum est inferieur a elem et le nouveau superieur, il faut traiter elem juste avant le nouveau voisin
735 if (old_tri < elem && min_tri > elem)
736 {
737 coeff(compt) = valeur_diag_naire(mat);
738 tab2(compt2) = nb_elem * (mat + nb_equation_CH_) + elem; //la ou commence les matrices A, B, C, etc... donc (nb_elem*nb_equation_CH)+1 ??
739 compt++;
740 compt2++;
741 }
742
743 // On complete les tableaux avec les valeurs dans les voisins non aux bords du domaine
744 if (kappa_moy_ == 2)
745 kappa_naire_interpolee = pow(std::fabs(kappa_Matrix_var(elem, j) * kappa_Matrix_var(min_tri, j)), 0.5); // Moyenne geometrique
746 else if (kappa_moy_ == 1)
747 {
748 if (kappa_Matrix_var(elem, j) == 0 || kappa_Matrix_var(min_tri, j) == 0)
749 kappa_naire_interpolee = 0;
750 else
751 kappa_naire_interpolee = 2. / (1. / kappa_Matrix_var(elem, j) + 1. / kappa_Matrix_var(min_tri, j)); // Moyenne harmonique
752 }
753 else if (kappa_moy_ == 0)
754 kappa_naire_interpolee = (kappa_Matrix_var(elem, j) + kappa_Matrix_var(min_tri, j)) / 2.; // Moyenne arithmetique
755
756 coeff(compt) = -theta * kappa_naire_interpolee * (dt / dvarkeep);
757 tab2(compt2) = min_tri + nb_elem * (nb_equation_CH_ + mat);
758 compt++;
759 compt2++;
760
761 // Si on est a la fin et que elem n'a pas encore ete mis dans coeff, il faut le faire avant la fin de la boucle sur les faces de l'element
762 // Ceci arrive si elem > tous les numeros d'elements de ses voisins
763 if (ncomp == 2 * nb_compo_ - nb_faces_au_bord - 1 && min_tri < elem)
764 {
765 coeff(compt) = valeur_diag_naire(mat);
766 tab2(compt2) = elem + (nb_equation_CH_ + mat) * nb_elem;
767 compt++;
768 compt2++;
769 }
770 }
771 old_tri = min_tri;
772 }
773 }
774
775 }
776
777 // Assemblage de la moitie superieure de la matrice : B et I
778 // Boucle sur le nombre de matrice dans la grosse matrice (matrice d'une matrice)
779 for (int ligne = 0; ligne < nb_equation_CH_; ligne++)
780 {
781 // Boucle sur le nombre d'elements
782 for (int elem = 0; elem < nb_elem; elem++)
783 {
784 valeur_diag_naire = 0.;
785 old_tri = -1;
786 nb_faces_au_bord = 0;
787
788 // On saute de ligne en prenant la valeur de compte2 -1
789 tab1(compt1) = compt2 + 1;
790 compt1++;
791
792 // Calcul du nombre de bords
793 for (int ncomp = 0; ncomp < 2 * nb_compo_; ncomp++)
794 {
795 f0 = elem_faces(elem, ncomp);
796 voisin = face_voisins(f0, 0);
797 if (face_voisins(f0, 0) == elem)
798 voisin = face_voisins(f0, 1);
799
800 // On connait le voisin associe a la face en cours. On regarde s'il est au bord
801 if (voisin == -1)
802 nb_faces_au_bord++;
803 }
804
805
806 for (int ncomp = 0; ncomp < 2 * nb_compo_ - nb_faces_au_bord; ncomp++)
807 {
808 min_tri = nb_elem + 1; //initialisation de min_tri pour chaque face (une sorte de reference car le numero des voisins ne doit pas depasser nb_elem+1)
809 for (int mat = 0; mat < nb_equation_CH_; mat++)
810 {
811 int j = (ligne * nb_equation_CH_) + mat;
812 for (int ncomp_tri = 0; ncomp_tri < 2 * nb_compo_; ncomp_tri++)
813 {
814 f0 = elem_faces(elem, ncomp_tri);
815
816 // Voisin associe a la face - On s'assure de traiter un voisin et pas l'element resident
817 voisin = face_voisins(f0, 0);
818 if (face_voisins(f0, 0) == elem)
819 voisin = face_voisins(f0, 1);
820
821 // On va compter le nombre de voisins existants (faces non aux bords de l'element elem)
822 // Ceci sert a calculer la contribution au terme relatif a l'element elem
823 // Cas kappa variable : on utilise la moyenne (geometrique, harmonique ou arithmetique) des valeurs des mobilites
824 // des elements concernes par la face de calcul ("kappa_naire_interpolee")
825
826 if (voisin != -1 && old_tri == -1)
827 {
828 dvar2 = pow((positions(elem, ori(f0)) - positions(voisin, ori(f0))), 2);
829 valeur_diag_naire(mat) += -fermeture.get_alphaMatrix()(j) / dvar2;
830 }
831
832 // Si le voisin a un numero plus petit que l'ancien minimum, on ne le prend pas en compte
833 // En effet, le nouveau minimum est un numero d'element qui lui sera superieur
834 // Rq : voisin>old_tri => voisin != -1 donc pour une face au bord le if est false
835 if (voisin > old_tri)
836 {
837 min_tri = std::min(min_tri, voisin);
838 if (min_tri == voisin)
839 dvarkeep = pow((positions(elem, ori(f0)) - positions(voisin, ori(f0))), 2);
840 }
841 }
842
843 // Si l'ancien minimum est inferieur a elem et le nouveau superieur, il faut traiter elem juste avant le nouveau voisin
844 if (old_tri < elem && min_tri > elem)
845 {
846 coeff(compt) = valeur_diag_naire(mat);
847 tab2(compt2) = nb_elem * (mat) + elem; //la ou commence les matrices A, B, C, etc... donc (nb_elem*nb_equation_CH)+1 ??
848 compt++;
849 compt2++;
850 }
851
852 // On complete les tableaux avec les valeurs dans les voisins non aux bords du domaine
853 coeff(compt) = fermeture.get_alphaMatrix()(j) / dvarkeep;
854 tab2(compt2) = min_tri + nb_elem * (mat);
855 compt++;
856 compt2++;
857
858 // Si on est a la fin et que elem n'a pas encore ete mis dans coeff, il faut le faire avant la fin de la boucle sur les faces de l'element
859 // Ceci arrive si elem > tous les numeros d'elements de ses voisins
860 if (ncomp == 2 * nb_compo_ - nb_faces_au_bord - 1 && min_tri < elem)
861 {
862 coeff(compt) = valeur_diag_naire(mat);
863 tab2(compt2) = elem + (mat) * nb_elem;
864 compt++;
865 compt2++;
866 }
867 // On sauve le numero d'element "minimum"
868 }
869 old_tri = min_tri;
870 //}
871
872 }
873 coeff(compt) = 1;
874 tab2(compt2) = ((ligne + nb_equation_CH_) * nb_elem) + elem;
875 compt++;
876 compt2++;
877 }
878
879 }
880
881 // cf Mat_Morse.h/.cpp, tab1() et tab2() sont a utiliser au sens Fortran
882 // EXPLICATION :
883 // coeff stocke les valeurs des coefficients
884 // tab2 stocke les numeros de colonnes dans la matrice de ces coefficients, au sens FORTRAN (i-e 1 <= tab2[i] <= n)
885 // tab1 stocke le rang de l'element de tab2() pour lequel on change de ligne. Ainsi pour tab1[j], on est a la i-eme ligne avec :
886 // ( tab1[i] <= j < tab1[i+1] ) qui implique qu'on considere toujours la i-eme ligne,
887 // et des que cela n'est plus respecte, le passage a la ligne suivante est effectue
888
889 // De par l'algorithme, tab1() est deja au sens FORTRAN. Reste a le faire pour tab2()
890 // De plus on doit mettre le dernier terme de tab1() a dimensionnement+1
891 tab2 += 1;
892 tab1(compt1) = dimensionnement + 1;
893 compt1 += 1;
894
895 if (compt != dimensionnement)
896 {
897 Cerr << "Erreur lors du calcul de la matrice du point fixe : nombre d'elements non nuls calcules different du nombre d'elements non nuls prevus" << finl;
899 }
900 }
901 else if (mobilite_explicite_ == 0)
902 {
903 Cerr << "Implicit mobility: the matrix A used in JFNK is not implemented." << finl;
904 matrice_diffusion_CH.clean();
905 }
906 else
907 {
908 Cerr << "STOP: argument mobilite_explicite cannot be different than 0 or 1." << finl;
909 Cerr << "==> Must have an error in the code." << finl;
910 }
911
912}
913
914/*! @brief Construire le residu du JFNK
915 *
916 */
917void Source_Con_Phase_field_Naire::calculer_residu_jfnk(const DoubleTab& c, const Matrice_Morse& matrice_diffusion_CH, DoubleTab& v0, const DoubleTab& x1)
918{
919 const Domaine_VDF& domaine_VDF = le_dom_VDF_.valeur();
920 const int nb_elem = domaine_VDF.nb_elem_tot();
921 const int nb_elem_tot = c.size_totale(); // WARNING: dans le cas n-aire, size_totale comprend le nombre d'élément + le nombre de constituants
922 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
923 const auto& fermeture = mil.get_fermeture();
924 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
925
926 double dt;
927 const double theta = 0.6;
928
929 DoubleVect second_membre(2 * nb_elem_tot);
930 DoubleTab Ax1(2 * nb_elem_tot);
931 DoubleTab terme_non_lin(c);
932 DoubleTab x1_c(c);
933
934 for (int j = 0; j < nb_equation_CH_; j++)
935 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
936 x1_c(n_elem, j) = x1(n_elem + (j * nb_elem)); // Contient la concentration au temps intermédiaire
937
939
940 dt = eq_c.schema_temps().pas_de_temps(); // Pas de temps
941
942 // Assemblage du second membre
943 terme_non_lin = fermeture.call_dWdc_naire(x1_c);
944 for (int j = 0; j < nb_equation_CH_; j++)
945 {
946 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
947 {
948 second_membre(n_elem + (j * nb_elem)) = c(n_elem, j);
949 if (fermeture.get_type_potentiel_analytique() == 0)
950 terme_non_lin(n_elem, j) *= fermeture.get_betaMatrix()(j);
951 second_membre(nb_elem_tot + n_elem + (j * nb_elem)) = terme_non_lin(n_elem, j);
952 }
953 }
954
955 if (mobilite_explicite_ == 1)
956 {
957 // Calcul du produit matrice / vecteur utilise
958 matrice_diffusion_CH.multvect_(x1, Ax1);
959 // Modifie par DJ
960 //---------------
961 {
962 DoubleTab Ax1_c(nb_elem_tot);
963 DoubleTab Ax1_mutilde(nb_elem_tot);
964 for (int n_elem = 0; n_elem < nb_elem_tot; n_elem++)
965 {
966 Ax1_c(n_elem) = Ax1(n_elem);
967 Ax1_mutilde(n_elem) = Ax1(n_elem + nb_elem_tot);
968 }
969
971 Ax1_mutilde.echange_espace_virtuel();
972
973 for (int n_elem = 0; n_elem < nb_elem_tot; n_elem++)
974 {
975 Ax1(n_elem) = Ax1_c(n_elem);
976 Ax1(n_elem + nb_elem_tot) = Ax1_mutilde(n_elem);
977 }
978 }
979
980
981 // Calcul de v0 = [A(xn) xn - bn]
982 for (int n_elem = 0; n_elem < 2 * nb_elem_tot; n_elem++)
983 v0(n_elem) = (Ax1(n_elem) - second_membre(n_elem));
984 }
985 else if (mobilite_explicite_ == 0)
986 {
987
988 // Comme la matrice A n'est pas construite, on calcule directement sous forme de vecteur le produit AX
989 // (X contenant la concentration et le potentiel chimique au temps intermédiaire theta)
990 // Finalement le résidu évalué est H(X) = a(X) - b(X) [différence entre deux vecteurs dépendant de X]
991 DoubleTab x1_mutilde(c);
992 DoubleTab div_alpha_gradC(c);
993 DoubleTab div_kappa_grad_mu(c);
994 DoubleTab kappa_Matrix_var(nb_elem, nb_equation_CH_ * nb_equation_CH_);
995 int indice_tot=0;
996
997 for (int j = 0; j < nb_equation_CH_; j++)
998 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
999 x1_mutilde(n_elem, j) = x1(nb_elem_tot + n_elem + (j * nb_elem)); // Contient le potentiel chimique au temps intermédiaire
1000
1001 x1_mutilde.echange_espace_virtuel();
1002
1003 if (fermeture.get_kappa_ind() == 0)
1004 {
1005 for (int i = 0; i < nb_elem; i++)
1006 for (int j = 0; j < nb_equation_CH_ * nb_equation_CH_; j++)
1007 kappa_Matrix_var(i, j) = fermeture.get_kappaMatrix()(j);
1008 }
1009 else
1010 {
1011 kappa_Matrix_var = fermeture.call_kappa_func_c_naire(x1_c);
1012 }
1013
1014 calculer_div_alpha_grad(x1_c, div_alpha_gradC);
1015 div_kappa_grad(x1_mutilde, kappa_Matrix_var, div_kappa_grad_mu);
1016
1017 Cerr << "La taille de mu = " << x1_mutilde.dimension(0) << ", " << x1_mutilde.dimension(1) << finl;
1018 Cerr << "La taille de div_alpha = " << div_alpha_gradC.dimension(0) << ", " << div_alpha_gradC.dimension(1) << finl;
1019 Cerr << "La taille de div_kappa = " << div_kappa_grad_mu.dimension(0) << ", " << div_kappa_grad_mu.dimension(1) << finl;
1020
1021 for (int j = 0; j < nb_equation_CH_; j++)
1022 {
1023 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
1024 {
1025 indice_tot = n_elem + (j * nb_elem);
1026// Cerr << "indice n_elem = " << n_elem << finl;
1027// Cerr << "indice j = " << j << finl;
1028// Cerr << "indice indice_tot = " << indice_tot << finl;
1029 Ax1(indice_tot) = x1_c(n_elem, j) - theta * dt * div_kappa_grad_mu(n_elem, j);
1030 Ax1(indice_tot + nb_elem_tot) = x1_mutilde(n_elem, j) + div_alpha_gradC(n_elem, j);
1031 }
1032 }
1033
1034 // Calcul de v0 = [a(xn) - bn]
1035 for (int n_elem = 0; n_elem < 2 * nb_elem_tot; n_elem++)
1036 v0(n_elem) = (Ax1(n_elem) - second_membre(n_elem));
1037 }
1038
1039}
1040
1041/*! @brief Construire le residu du JFNK
1042 *
1043 */
1044void Source_Con_Phase_field_Naire::jacobian_vect(const DoubleTab& c, const Matrice_Morse& matrice_diffusion_CH, const DoubleTab& v0, const DoubleTab& x1, DoubleTab& v1)
1045{
1046 const double delta = 1.e-5;
1047
1048 DoubleTab v2(v1);
1049 DoubleTab x1_(v0);
1050
1051 v1 = 0.;
1052
1053 x1_ = v0;
1054 x1_ *= delta;
1055 x1_ += x1;
1056
1057 // Construction de la differentielle (dans la direction v0)
1058 calculer_residu_jfnk(c, matrice_diffusion_CH, v1, x1_);
1059 calculer_residu_jfnk(c, matrice_diffusion_CH, v2, x1);
1060
1061 v1 -= v2;
1062 v1 /= delta;
1063}
1064
1065/*! @brief Algorithme résolution non linéaire par JFNK
1066 *
1067 * @param (mutilde) inverse A x = b
1068 * @return (int)
1069 *
1070 * Solves Ax = b by GMRES with nit iterations (reinitializations) and nkr Krilov vectors.
1071 * Copied from Sch_Crank_Nicholson.cpp (scalar)//
1072 *
1073 */
1074int Source_Con_Phase_field_Naire::resolution_jfnk(const DoubleTab& c, const DoubleTab& mutilde, const Matrice_Morse& matrice_diffusion_CH, DoubleTab& c_demi, DoubleTab& mutilde_demi)
1075
1076{
1077 int i, j, nk, i0, im, it, ii;
1078 double tem = 1., res, ccos, ssin;
1079 const int ns = 2 * c.size_totale();
1080 const Domaine_VDF& domaine_VDF = le_dom_VDF_.valeur();
1081 const int nb_elem = domaine_VDF.nb_elem_tot();
1082
1083 // Ajoute par DJ
1084 //--------------
1085 int nb_elem_tot = c.size_totale();
1086 DoubleTab x1(ns);
1087 x1 = 0.;
1088 for (int ncomponent = 0; ncomponent < nb_equation_CH_; ncomponent++)
1089 {
1090 for (int nelem = 0; nelem < nb_elem; nelem++)
1091 {
1092 x1(nelem + (ncomponent * nb_elem)) = c(nelem, ncomponent);
1093 x1(nelem + (ncomponent * nb_elem) + nb_elem_tot) = mutilde(nelem, ncomponent);
1094 }
1095 }
1096
1097 DoubleTab v(ns, nkr_); // Krilov vectors
1098 DoubleTab h(nkr_ + 1, nkr_); // Heisenberg maatrix of coefficients
1099 DoubleVect r(nkr_ + 1);
1100 DoubleTab v0(x1);
1101 DoubleTab v1(x1);
1102
1103 // Initialisation
1104 v = 0.;
1105 v0 = 0.;
1106 v1 = 0.;
1107
1108 calculer_residu_jfnk(c, matrice_diffusion_CH, v0, x1);
1109 v0 *= -1.;
1110
1111 res = 0.;
1112
1113 for (ii = 0; ii < c.size(); ii++)
1114 res += v0(ii) * v0(ii);
1115 for (ii = c.size_totale(); ii < c.size_totale() + c.size(); ii++)
1116 res += v0(ii) * v0(ii);
1117
1118
1119 res = mp_sum(res);
1120 res = sqrt(res);
1121
1122 if (res < rtol_)
1123 return 0; // nothing to do
1124
1125 rtol_ = (rtol_ < res * atol_) ? res * atol_ : rtol_;
1126 rtol_ = (rtol_ < stol_) ? rtol_ : stol_;
1127
1128 Cout << "Source Concentration Phase Field - JFNK" << finl;
1129 Cout << "Stopping rule scalar : " << rtol_ << finl;
1130
1131 // iterations
1132 for (it = 0; it < maxit_gmres_; it++)
1133 {
1134 nk = nkr_;
1135
1136 //...Orthogonalisation of Arnoldi
1137 v0 /= res;
1138 r = 0.;
1139 r[0] = res;
1140 h = 0.;
1141
1142 for (j = 0; j < nkr_; j++)
1143 {
1144 for (ii = 0; ii < ns; ii++)
1145 v(ii, j) = v0(ii);
1146
1147 jacobian_vect(c, matrice_diffusion_CH, v0, x1, v1);
1148 v0 = v1;
1149
1150 // Modifie par DJ
1151 //---------------
1152 for (i = 0; i <= j; i++)
1153 {
1154 // for (ii=0; ii<ns;ii++) h(i,j) += v0(ii) * v(ii,i);
1155 for (ii = 0; ii < c.size(); ii++)
1156 h(i, j) += v0(ii) * v(ii, i);
1157 for (ii = c.size_totale(); ii < c.size_totale() + c.size(); ii++)
1158 h(i, j) += v0(ii) * v(ii, i);
1159
1160 //for (ii=0; ii<ns; ii++) h(i,j) += v0(ii) * v(ii,i);
1161
1162 h(i, j) = mp_sum(h(i, j));
1163 // Debog::verifier("JFNK h(i,j) : ",h(i,j));
1164 for (ii = 0; ii < ns; ii++)
1165 v0(ii) -= h(i, j) * v(ii, i);
1166 }
1167 //---------------
1168 // tem = sqrt(v0 * v0);
1169 tem = 0.;
1170 // Modifie par DJ
1171 //---------------
1172 // for (ii=0; ii<ns;ii++) tem += v0(ii) * v0(ii) ;
1173
1174 for (ii = 0; ii < c.size(); ii++)
1175 tem += v0(ii) * v0(ii);
1176 for (ii = c.size_totale(); ii < c.size_totale() + c.size(); ii++)
1177 tem += v0(ii) * v0(ii);
1178
1179
1180 //---------------
1181 tem = mp_sum(tem);
1182 // Debog::verifier("JFNK tem apres mp_sum : ",tem);
1183 tem = sqrt(tem);
1184 h(j + 1, j) = tem;
1185 if (tem < rtol_)
1186 {
1187 nk = j + 1;
1188 goto l5naire;
1189 }
1190 v0 /= tem;
1191 }
1192
1193 //...Triangularisation
1194l5naire:
1195 for (i = 0; i < nk; i++)
1196 {
1197 im = i + 1;
1198 tem = 1. / sqrt(h(i, i) * h(i, i) + h(im, i) * h(im, i));
1199 ccos = h(i, i) * tem;
1200 ssin = -h(im, i) * tem;
1201 for (j = i; j < nk; j++)
1202 {
1203 tem = h(i, j);
1204 h(i, j) = ccos * tem - ssin * h(im, j);
1205 h(im, j) = ssin * tem + ccos * h(im, j);
1206 }
1207 r[im] = ssin * r[i];
1208 r[i] *= ccos;
1209 }
1210
1211 //...Solution of linear system
1212 for (i = nk - 1; i >= 0; i--)
1213 {
1214 r[i] /= h(i, i);
1215 for (i0 = i - 1; i0 >= 0; i0--)
1216 r[i0] -= h(i0, i) * r[i];
1217 }
1218 for (i = 0; i < nk; i++)
1219 for (ii = 0; ii < ns; ii++)
1220 x1(ii) += r[i] * v(ii, i);
1221
1222 calculer_residu_jfnk(c, matrice_diffusion_CH, v0, x1);
1223 v0 *= -1.;
1224
1225
1226 res = 0.;
1227
1228 for (ii = 0; ii < c.size(); ii++)
1229 res += v0(ii) * v0(ii);
1230 for (ii = c.size_totale(); ii < c.size_totale() + c.size(); ii++)
1231 res += v0(ii) * v0(ii);
1232
1233 res = mp_sum(res);
1234 res = sqrt(res);
1235
1236 Cerr << " - At it = " << it << ", residu scalar = " << res << finl;
1237
1238 if (res < rtol_)
1239 {
1240 // Ajoute par DJ
1241 //--------------
1242 for (int ncomponent = 0; ncomponent < nb_equation_CH_; ncomponent++)
1243 {
1244 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
1245 {
1246 c_demi(n_elem, ncomponent) = x1(n_elem + (ncomponent * nb_elem));
1247 mutilde_demi(n_elem, ncomponent) = x1(n_elem + nb_elem_tot + (ncomponent * nb_elem));
1248 }
1249 }
1250 // L'echange espace virtuel est fait dans premier_demi_dt()
1251 Cerr << "Number of iterations to reach convergence : " << it + 1 << finl;
1252 Cerr << "" << finl;
1253
1254 return it;
1255 }
1256 else if (it == maxit_gmres_ - 1)
1257 {
1258 // Ajoute par DJ
1259 //--------------
1260 // On fait le choix de mettre a jour c_demi et mutilde_demi meme s'il n'y a pas convergence...
1261 for (int ncomponent = 0; ncomponent < nb_equation_CH_; ncomponent++)
1262 {
1263 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
1264 {
1265 c_demi(n_elem, ncomponent) = x1(n_elem + (ncomponent * nb_elem));
1266 mutilde_demi(n_elem, ncomponent) = x1(n_elem + nb_elem_tot + (ncomponent * nb_elem));
1267 }
1268 }
1269
1270 Cerr << "Stopped before convergence" << finl;
1271 Cerr << "" << finl;
1272 }
1273 }
1274
1275 return -1;
1276}
1277
1278/*! @brief Calcul de mutilde au centre des elements
1279 *
1280 * @param (mutilde) mutilde au centre des elements
1281 */
1283{
1284 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
1285 const DoubleTab& c = eq_c.inconnue().valeurs();
1286 const DoubleTab& div_alpha_gradC = eq_c.get_div_alpha_gradC();
1287 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
1288 const auto& fermeture = mil.get_fermeture();
1289
1290 // Calcul de mutilde
1291
1292 mutilde = div_alpha_gradC;
1293 mutilde *= -1.;
1294
1295 //Cerr << "mutilde = -div_alpha_gradC " << mutilde << finl;
1296
1297 DoubleTab potent_chimique(mutilde);
1298
1299 potent_chimique = fermeture.call_dWdc_naire(c);
1300 if (fermeture.get_type_potentiel_analytique() == 0)
1301 {
1302 for (int j = 0; j < c.line_size(); j++)
1303 for (int i = 0; i < c.dimension(0); i++)
1304 potent_chimique(i, j) *= fermeture.get_betaMatrix()(j);
1305 }
1306
1307 for (int j = 0; j < mutilde.line_size(); j++)
1308 for (int i = 0; i < mutilde.dimension(0); i++)
1309 {
1310 mutilde(i, j) += potent_chimique(i, j);
1311 if (mutype_ == 1) //avec Ec, n'est pas implemente pour le cas multicomposant
1312 Cerr << "potentiel_chimique_generalisee avec_energie_cinetique not implemented for multicomponent system" << finl;
1313 }
1314
1315
1316// L'espace virtuel n'est pas a jour
1317 assert_invalide_items_non_calcules(mutilde);
1318}
1319
1320void Source_Con_Phase_field_Naire::calculer_mutilde_demi(DoubleTab& mutilde_demi, DoubleTab& c_demi) const
1321{
1322 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
1323 const Navier_Stokes_std& eq_ns = ref_cast(Navier_Stokes_std, pb_->equation(0));
1324 const Operateur_Grad& opgrad = eq_ns.operateur_gradient();
1325 const Operateur_Div& opdiv = eq_ns.operateur_divergence();
1326 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
1327 const auto& fermeture = mil.get_fermeture();
1328
1329 mutilde_demi = 0.;
1330
1331 const int nb_comp = fermeture.get_nb_constituants();
1332
1333 DoubleTab& prov_face = ref_cast_non_const(DoubleTab, prov_face_);
1334 if (prov_face.size() == 0)
1335 prov_face = eq_ns.inconnue().valeurs();
1336 prov_face = 0.;
1337 DoubleTab temp_prov_face2(prov_face.dimension(0), nb_comp);
1338 temp_prov_face2 = 0;
1339 // Grad(c)
1340 DoubleTab temp_resu(mutilde_demi.dimension_tot(0), 1);
1341 temp_resu = 0;
1342 DoubleTab temp_c(c_demi.dimension_tot(0), 1);
1343 for (int j = 0; j < nb_comp; j++)
1344 {
1345 prov_face = 0.;
1346 for (int i = 0; i < temp_c.dimension(0); i++)
1347 {
1348 temp_c(i, 0) = c_demi(i, j);
1349 }
1350 opgrad.calculer(temp_c, prov_face);
1351
1352 // Application solveur masse
1353 eq_ns.solv_masse().appliquer(prov_face);
1354
1355 // alpha*Grad(C)
1356
1357 for (int i = 0; i < prov_face.dimension(0); i++)
1358 {
1359 for (int k = 0; k < nb_comp; k++)
1360 temp_prov_face2(i, k) += prov_face(i) * fermeture.get_alphaMatrix()(j + k * nb_comp);
1361
1362 prov_face(i) = temp_prov_face2(i, j);
1363 }
1364
1365 // Div(Grad(c))
1366 opdiv.calculer(prov_face, temp_resu);
1367 //opdiv.calculer(temp_prov_face2,div_alpha_gradC);
1368 eq_c.solv_masse().appliquer(temp_resu);
1369
1370 for (int i = 0; i < temp_resu.dimension(0); i++)
1371 {
1372 mutilde_demi(i, j) = temp_resu(i, 0);
1373 }
1374 }
1375
1376 mutilde_demi *= -1.;
1377
1378 DoubleTab potent_chimique(mutilde_demi);
1379
1380 potent_chimique = fermeture.call_dWdc_naire(c_demi);
1381 if (fermeture.get_type_potentiel_analytique() == 0)
1382 {
1383 for (int j = 0; j < c_demi.line_size(); j++)
1384 for (int i = 0; i < c_demi.dimension(0); i++)
1385 potent_chimique(i, j) *= fermeture.get_betaMatrix()(j);
1386 }
1387 for (int j = 0; j < mutilde_demi.line_size(); j++)
1388 for (int i = 0; i < mutilde_demi.dimension(0); i++)
1389 {
1390 mutilde_demi(i, j) += potent_chimique(i, j);
1391 if (mutype_ == 1) //avec Ec, n'est pas implemente pour le cas multicomposant
1392 Cerr << "potentiel_chimique_generalisee avec_energie_cinetique not implemented for multicomponent system" << finl;
1393 }
1394
1395// L'espace virtuel n'est pas a jour
1396 assert_invalide_items_non_calcules(mutilde_demi);
1397}
DoubleTab & valeurs() override
Surcharge Champ_base::valeurs() Renvoie le tableau des valeurs.
DoubleTab & valeurs() override
Renvoie le tableau des valeurs du champ au temps courant.
const Champ_Inc_base & inconnue() const override
Renvoie le champ inconnue de l'equation: la concentration.
classe Convection_Diffusion_Phase_field Cas particulier de Convection_Diffusion_Concentration
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
class Domaine_VDF
Definition Domaine_VDF.h:64
int orientation(int) const override
inline DoubleVect& Domaine_VDF::porosite_face() {
int nb_faces() const
renvoie le nombre global de faces.
Definition Domaine_VF.h:471
double volumes(int i) const
Definition Domaine_VF.h:113
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
double xp(int num_elem, int k) const
Definition Domaine_VF.h:77
int premiere_face_int() const
une face est interne ssi elle separe deux elements.
Definition Domaine_VF.h:463
int face_voisins(int num_face, int i) const
renvoie l'element voisin de numface dans la direction i.
Definition Domaine_VF.h:418
int nb_elem_tot() const
const Domaine & domaine() const
Une entree dont la source est une chaine de caracteres.
Definition EChaine.h:31
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
Solveur_Masse_base & solv_masse()
Renvoie le solveur de masse associe a l'equation.
Schema_Temps_base & schema_temps()
Renvoie le schema en temps associe a l'equation.
const DoubleVect & get_kappaMatrix() const
DoubleTab call_kappa_func_c_naire(const DoubleTab &d) const
double call_dWdc(const double d) const
const DoubleVect & get_betaMatrix() const
virtual DoubleVect & multvect_(const DoubleVect &, DoubleVect &) const
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
void clean() override
Remplit la matrice avec des zeros.
auto & get_set_tab2()
void dimensionner(int n, _SIZE_ nnz)
Size the matrix with n lines and n columns and nnz zero-values coefficients.
auto & get_set_coeff()
auto & get_set_tab1()
const Fermeture_Phase_field_base & get_fermeture() const
classe Navier_Stokes_std Cette classe porte les termes de l'equation de la dynamique
const Champ_Inc_base & inconnue() const override
Renvoie la vitesse (champ inconnue de l'equation) (version const).
Operateur_Div & operateur_divergence()
Renvoie l'operateur de calcul de la divergence associe a l'equation.
Operateur_Grad & operateur_gradient()
Renvoie l'operateur de calcul du gradient associe a l'equation.
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
static int dimension
Definition Objet_U.h:99
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
classe Operateur_Div Classe generique de la hierarchie des operateurs calculant la divergence
DoubleTab & calculer(const DoubleTab &, DoubleTab &) const override
Initialise le tableau passe en parametre avec la contribution de l'operateur.
Classe Operateur_Grad Classe generique de la hierarchie des operateurs calculant le gradient.
DoubleTab & calculer(const DoubleTab &, DoubleTab &) const override
Initialise le tableau passe en parametre avec la contribution de l'operateur.
static double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
double pas_de_temps() const
Renvoie le pas de temps (delta_t) courant.
class SolveurSys Un SolveurSys represente n'importe qu'elle classe
Definition SolveurSys.h:32
int resoudre_systeme(const Matrice_Base &matrice, const DoubleVect &secmem, DoubleVect &solution)
virtual DoubleTab & appliquer(DoubleTab &) const
renvoie appliquer_impl(x/coeffient_temporelle) si on a un coefficient temporel sinon renvoie applique...
Classe de base des flux de sortie.
Definition Sortie.h:52
void calculer_div_alpha_grad(const DoubleTab &, DoubleTab &) const
Calcul de Div(alpha*rho*Grad((C)) au centre des elements.
void calculer_residu_jfnk(const DoubleTab &, const Matrice_Morse &, DoubleTab &, const DoubleTab &)
Construire le residu du JFNK.
void calculer_mutilde_demi(DoubleTab &, DoubleTab &) const
DoubleTab & laplacien(const DoubleTab &, DoubleTab &) const
void calculer_mutilde(DoubleTab &) const
Calcul de mutilde au centre des elements.
void assembler_matrice_mobilite_explicite(Matrice_Morse &)
Assemble la matrice pour le calcul du point fixe.
int resolution_jfnk(const DoubleTab &, const DoubleTab &, const Matrice_Morse &, DoubleTab &, DoubleTab &)
Algorithme résolution non linéaire par JFNK.
void calculer_div_alpha_rho_grad(const DoubleTab &, DoubleTab &) const
Calcul de Div(alpha*rho*Grad((C)) au centre des elements.
void jacobian_vect(const DoubleTab &, const Matrice_Morse &, const DoubleTab &, const DoubleTab &, DoubleTab &)
Construire le residu du JFNK.
DoubleTab & div_kappa_grad(const DoubleTab &, const DoubleTab &, DoubleTab &) const
void premier_demi_dt() override
Calcule le premier demi pas de temps dans le cas implicite Calcule le pas de temps dans le cas explic...
virtual void calculer_u2_elem(DoubleVect &)
_TYPE_ * addr()
_SIZE_ dimension_tot(int) const override
Definition TRUSTTab.tpp:160
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
_SIZE_ size_totale() const
Definition TRUSTVect.tpp:61
int line_size() const
Definition TRUSTVect.tpp:67
virtual void echange_espace_virtuel(IsExchangeBlocking exchange_type=IsExchangeBlocking::DefaultBlocking, const std::string kernel_name="noname")