TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Source_Con_Phase_field_Binaire.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_Con_Phase_field_Binaire.h>
18#include <Source_Qdm_VDF_Phase_field.h>
19#include <Navier_Stokes_phase_field.h>
20#include <Source_Con_Phase_field.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 <Matrix_tools.h>
31#include <Domaine_VDF.h>
32#include <Milieu_base.h>
33#include <SolveurSys.h>
34#include <Dimension.h>
35#ifdef PETSCKSP_H
36#include <petscsnes.h>
37#endif
38#include <EChaine.h>
39#include <Param.h>
40#include <SFichier.h>
41#include <Perf_counters.h>
42
43
44Implemente_instanciable(Source_Con_Phase_field_Binaire,"Source_Con_Phase_field_Binaire_VDF_P0_VDF",Source_Con_Phase_field);
45
46// XD Source_Con_Phase_field_Binaire_VDF_P0_VDF Source_Con_Phase_field Source_Con_Phase_field_Binaire_VDF_P0_VDF INHERITS_BRACE Source for phase field
47
48
50{
51 return s << que_suis_je();
52}
53
55{
56 Cerr << "Source_Con_Phase_field_Binaire::readOn" << finl;
58 if (!Process::me())
59 {
60 SFichier fichier_residu("residu.txt");
61 fichier_residu << "# SAUVEGARDE DU RESIDU #" << finl;
62 fichier_residu << "# Time \t Time simu \t Residu" << finl;
63
64 SFichier fichier_eval("eval.txt");
65 fichier_eval << "# Time simu \t Number eval FormFunctionOld" << finl;
66 }
67 return is;
68}
69
70DoubleTab& Source_Con_Phase_field_Binaire::laplacien(const DoubleTab& F, DoubleTab& resu) const
71{
72 const Navier_Stokes_std& eq_ns = ref_cast(Navier_Stokes_std, pb_->equation(0));
73 const Operateur_Grad& opgrad = eq_ns.operateur_gradient();
74 const Operateur_Div& opdiv = eq_ns.operateur_divergence();
75
76 resu = 0.;
77
78 // Dans cette partie, le laplacien est obtenu comme div.(grad F) avec
79 // une application du solveur masse entre l'etape de gradient et de divergence
80
81 DoubleTab& prov_face = ref_cast_non_const(DoubleTab, prov_face_);
82 if (prov_face.size() == 0)
83 prov_face = eq_ns.inconnue().valeurs();
84
85 prov_face = 0.;
86 // Grad(F)
87 opgrad.calculer(F, prov_face);
88 // Application solveur masse
89 eq_ns.solv_masse().appliquer(prov_face);
90
91 // Div(M*Grad(F))
92 opdiv.calculer(prov_face, resu);
93
94 return resu;
95}
96
97DoubleTab& Source_Con_Phase_field_Binaire::div_kappa_grad(const DoubleTab& F, const DoubleTab& kappa_var, DoubleTab& resu) const
98{
99 const Navier_Stokes_std& eq_ns = ref_cast(Navier_Stokes_std, pb_->equation(0));
100 const Operateur_Grad& opgrad = eq_ns.operateur_gradient();
101 const Operateur_Div& opdiv = eq_ns.operateur_divergence();
102
103 // const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
104 // const DoubleTab& c = eq_c.inconnue().valeurs();
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 opgrad.calculer(F, prov_face);
118
119 // M*Kappa*Grad(F)
120 int ndeb = domaine_VDF.premiere_face_int();
121 int nbfaces = domaine_VDF.nb_faces();
122 int el0, el1;
123 double kappa_face, vol0, vol1; // cface
124
125 for (int fac = ndeb; fac < nbfaces; fac++)
126 {
127 el0 = face_voisins(fac, 0);
128 el1 = face_voisins(fac, 1);
129 vol0 = volumes(el0);
130 vol1 = volumes(el1);
131 kappa_face = (vol0 * kappa_var(el0) + vol1 * kappa_var(el1)) / (vol0 + vol1);
132 // cface = (vol0 * c(el0) + vol1 * c(el1)) / (vol0 + vol1);
133 // prov_face(fac) = kappa_face * mobilite(cface) * prov_face(fac);
134 prov_face(fac) = kappa_face * prov_face(fac); // Changement de Luis: mobilite = 1 de toute façon dans le code initial
135 }
136
137 // Application solveur masse (/M)
138 eq_ns.solv_masse().appliquer(prov_face);
139
140 // Div(Kappa*Grad(F))
141 opdiv.calculer(prov_face, resu);
142 //Cerr <<"div_kappa_grad"<<resu<<finl;
143
144 return resu;
145}
146
147/*! @brief Calcul de Div(alpha*rho*Grad((C)) au centre des elements
148 *
149 * @param (DoubleTab& div_alpha_gradC) Div(alpha*Grad((C)) au centre des elements
150 */
151void Source_Con_Phase_field_Binaire::calculer_div_alpha_grad(const DoubleTab& c, DoubleTab& div_alpha_gradC) const
152{
153 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
154 const Navier_Stokes_std& eq_ns = ref_cast(Navier_Stokes_std, pb_->equation(0));
155 const Operateur_Grad& opgrad = eq_ns.operateur_gradient();
156 const Operateur_Div& opdiv = eq_ns.operateur_divergence();
157 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
158 const auto& fermeture = mil.get_fermeture();
159
160 DoubleTab& prov_face = ref_cast_non_const(DoubleTab, prov_face_);
161 if (prov_face.size() == 0)
162 prov_face = eq_ns.inconnue().valeurs();
163 prov_face = 0.;
164
165 // Grad(C)
166 opgrad.calculer(c, prov_face);
167 eq_ns.solv_masse().appliquer(prov_face);
168 prov_face *= fermeture.get_alpha();
169
170 // Div(alpha*Grad(c))
171 opdiv.calculer(prov_face, div_alpha_gradC);
172 eq_c.solv_masse().appliquer(div_alpha_gradC);
173 //Cerr <<"div_alpha_gradC"<<div_alpha_gradC<<finl;
174
175}
176
177/*! @brief Calcul de Div(alpha*rho*Grad((C)) au centre des elements
178 *
179 * @param (DoubleTab& div_alpha_rho_gradC) Div(alpha*rho*Grad((C)) au centre des elements
180 */
181void Source_Con_Phase_field_Binaire::calculer_div_alpha_rho_grad(const DoubleTab& c, DoubleTab& div_alpha_rho_gradC) const
182{
183 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
184 const Navier_Stokes_phase_field& eq_ns = ref_cast(Navier_Stokes_phase_field, pb_->equation(0));
185 const Operateur_Grad& opgrad = eq_ns.operateur_gradient();
186 const Operateur_Div& opdiv = eq_ns.operateur_divergence();
187 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
188 const auto& fermeture = mil.get_fermeture();
189
190 const Domaine_VDF& domaine_VDF = le_dom_VDF_.valeur();
191 const IntTab& face_voisins = domaine_VDF.face_voisins();
192 const DoubleVect& volumes = domaine_VDF.volumes();
193 const int ndeb = domaine_VDF.premiere_face_int();
194 const int nbfaces = domaine_VDF.nb_faces();
195
196 int el0, el1;
197 double vol0, vol1;
198 DoubleTab& prov_face = ref_cast_non_const(DoubleTab, prov_face_);
199 if (prov_face.size() == 0)
200 prov_face = eq_ns.inconnue().valeurs();
201 prov_face = 0.;
202
203 // Grad(C)
204 opgrad.calculer(c, prov_face);
205 eq_ns.solv_masse().appliquer(prov_face);
206
207 const DoubleTab& rhoPF = mil.rho().valeurs();
208 double rho_face;
209
210 if (boussi_ == 1)
211 prov_face *= fermeture.get_alpha() * rho0_; // Cas approximation de Boussinesq
212 else if (boussi_ == 0)
213 {
214 for (int fac = ndeb; fac < nbfaces; fac++)
215 {
216 el0 = face_voisins(fac, 0);
217 el1 = face_voisins(fac, 1);
218 vol0 = volumes(el0);
219 vol1 = volumes(el1);
220
221 rho_face = (vol0 * rhoPF(el0) + vol1 * rhoPF(el1)) / (vol0 + vol1);
222 prov_face(fac) *= fermeture.get_alpha() * rho_face;
223 }
224 }
225
226 // Div(alpha*rho*Grad(c))
227 opdiv.calculer(prov_face, div_alpha_rho_gradC);
228 eq_c.solv_masse().appliquer(div_alpha_rho_gradC);
229
230}
231
232/*! @brief Calcule le premier demi pas de temps dans le cas implicite Calcule le pas de temps dans le cas explicite
233 *
234 */
236{
237 const Domaine_VDF& domaine_VDF = le_dom_VDF_.valeur();
238 const int nb_elem = domaine_VDF.nb_elem_tot();
239
240 Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
241 DoubleTab& c = eq_c.inconnue().valeurs();
242
243 DoubleTab& mutilde = eq_c.set_mutilde_().valeurs();
244 DoubleTab& mutilde_demi = eq_c.set_mutilde_demi();
245 DoubleTab& c_demi = eq_c.set_c_demi();
246
247 Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
248 Fermeture_Phase_field_base& fermeture = mil.get_fermeture();
249
250 // Utilise dans l'ancien modele de Didier Jamet
251
252 /* commente par mr264902 car pas utilise dans la version presente
253 //DoubleTab& alpha_gradC_carre=eq_c.set_alpha_gradC_carre();
254 //calculer_alpha_gradC_carre(alpha_gradC_carre);
255 //DoubleTab& div_alpha_rho_gradC=eq_c.set_div_alpha_rho_gradC();
256 //
257 //calculer_div_alpha_rho_grad(c, div_alpha_rho_gradC);
258 */
259 DoubleTab& div_alpha_gradC = eq_c.set_div_alpha_gradC();
260 calculer_div_alpha_grad(c, div_alpha_gradC);
261 // commente par mr264902 car pas utilise dans la version presente
262 //DoubleTab& pression_thermo=eq_c.set_pression_thermo();
263 //calculer_pression_thermo(pression_thermo);
264
265 accr_ = c; // on copie la structure // !!
266 c_demi = c; // on copie la structure // !!
267
268 accr_ = 0.; // initialise a 0
269 c_demi = 0.; // initialise a 0
270
271 if (implicitation_ == 1)
272 {
273 mutilde_demi = c; // on copie la structure // !!
274 mutilde_demi = 0.; // initialise a 0
275
276 // Pour le JFNK ----------------------------
277
278 // Commente par DJ
279 //----------------
280 // DoubleTab x1(2*nb_elem);
281 // x1=0.;
282 // if(gmres_==1)
283 // {
284
285 // // Ecriture de x1(0)
286 // for(int n_elem=0;n_elem<nb_elem;n_elem++)
287 // {
288 // x1(n_elem)=c(n_elem);
289 // x1(n_elem+nb_elem)=mutilde(n_elem);
290 // }
291 // }
292 //----------------
293 // ---------------------------------------------
294
296
297 // only once !
300
302
303 // Modifie par DJ
304 //---------------
305
306 // RESOLUTION JFNK
307 // =========================================================
308 resolution_jfnk(c, mutilde, c_demi, mutilde_demi);
309 // =========================================================
310 Cout << "C à la sortie de JFNK = " << c_demi << finl;
311 Cout << "mutilde à la sortie de JFNK = " << mutilde_demi << finl;
312
313 Cout << "C^n = " << c << finl;
314 Cout << "mutilde^n = " << mutilde << finl;
315
316 const double theta = 0.6;
317 // On stocke les nouveaux c et mutilde
318
319 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
320 {
321 // Commente par DJ
322 //----------------
323 // c_demi(n_elem)=x1(n_elem);
324 //----------------
325 c_demi(n_elem) -= (1 - theta) * c(n_elem);
326 c_demi(n_elem) /= theta;
327
328 // Commente par DJ
329 //----------------
330 // mutilde_demi(n_elem)=x1(n_elem+nb_elem);
331 //----------------
332 //c=c_demi;
333
334 //---------- Calcul de mutilde_demi = dw/dc (c_demi)-div_alpha_gradC(c_demi) ------------
335 //calculer_mutilde_demi(mutilde_demi, c_demi);
336 //calculer_mutilde(mutilde_demi);
337 //mutilde=mutilde_demi;
338 mutilde_demi(n_elem) -= (1 - theta) * mutilde(n_elem);
339 mutilde_demi(n_elem) /= theta;
340 }
341
342 Cout << " -------------------------------------- " << finl;
343 Cout << "C^n+1 = " << c_demi << finl;
344 Cout << "mutilde^n+1 = " << mutilde_demi << finl;
345
346 // ATTENTION : A VERIFIER
347 //=======================
348 // c_demi.echange_espace_virtuel();
349 // mutilde_demi.echange_espace_virtuel();
350 // c.echange_espace_virtuel();
351 // mutilde.echange_espace_virtuel();
352
353 // Mise a jour
354
355 if (couplage_ == 0)
356 {
357 // Si traitement explicite de mutilde dans le cas implicite
358 calculer_mutilde(mutilde);
359 }
360 else if (couplage_ == 1)
361 {
362 // Si traitement implicite de mutilde dans le cas implicite
363 mutilde = mutilde_demi;
364 }
365 mutilde.echange_espace_virtuel();
366
367 // Calcul de l'accroissement entre n et n+1/2
368 // Utile pour pouvoir utiliser n'importe quel dt
369 accr_ = 0.;
370
371 }
372 else if (implicitation_ == 0)
373 {
374 // Cerr<<"Schema explicite"<<finl;
376 calculer_mutilde(mutilde);
377 mutilde.echange_espace_virtuel();
378
379 DoubleTab& prov_elem = prov_elem_;
380 if (prov_elem.size() == 0)
381 prov_elem = mutilde;
382
383 if (fermeture.get_kappa_ind() == 1)
384 {
385 DoubleTab kappa_var(prov_elem);
386 kappa_var = 0.;
387 for (int ikappa = 0; ikappa < nb_elem; ikappa++)
388 kappa_var(ikappa) = fermeture.call_kappa_func_c(c(ikappa));
389 // Div(Kappa*Grad(mutilde))
390 div_kappa_grad(mutilde, kappa_var, prov_elem);
391 }
392 else if (fermeture.get_kappa_ind() == 0)
393 {
394 // Kappa*Laplacien(mutilde)
395 laplacien(mutilde, prov_elem);
396 prov_elem *= fermeture.get_kappa();
397 }
398
399 // Pour equation Allen-Cahn (kappa constant)
400 //------------------------------------------
401 // prov_elem=F;
402 // prov_elem*=-kappa;
403
404 accr_ += prov_elem;
405 //eq_c.solv_masse().appliquer(prov_elem);
406 //Cerr<<"masse de la force sur c "<<prov_elem.max_abs()<<finl;
407
408 // Utile pour pouvoir utiliser n'importe quel dt - voir Schema_Phase_Field
409 c_demi = c;
410 }
411 else
412 {
413 Cerr << "Type de schema errone !!" << finl;
414 }
415}
416
418{
419 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
420 const DoubleTab& c = eq_c.inconnue().valeurs();
421 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
422 const auto& fermeture = mil.get_fermeture();
423 const int nb_elem = le_dom_VDF_->nb_elem_tot();
424
425 kappa_tab_ = c; // on initialise la structure
426
427 /*
428 * Typage d'une operateur utile
429 */
430
431 ch_kappa_ou_alpha_ = eq_c.get_mutilde_(); // on copie la structure
432 ch_kappa_ou_alpha_->nommer("ch_kappa_ou_alpha");
433
434 terme_diffusif_vdf_.associer_eqn(eq_c);
435 terme_diffusif_vdf_.associer_diffusivite(ch_kappa_ou_alpha_.valeur());
436 EChaine diff( "{ }");
437 diff >> terme_diffusif_vdf_;
438 terme_diffusif_vdf_.associer_diffusivite_pour_pas_de_temps(ch_kappa_ou_alpha_.valeur());
439 terme_diffusif_vdf_->associer(le_dom_VDF_.valeur(), eq_c.domaine_Cl_dis(), eq_c.inconnue());
440 terme_diffusif_vdf_->completer();
441
442 Cerr << "------------ INITIALISER MATRICE ---------------" << finl;
443 Cerr << "le_dom_dCl_dis = " << eq_c.domaine_Cl_dis() << finl;
444
445
446 matrice_diffusion_CH_.dimensionner(2, 2);
447
448 for (int i = 0; i < 2; i++)
449 for (int j = 0; j < 2; j++)
450 {
451 matrice_diffusion_CH_.get_bloc(i, j).typer("Matrice_Morse");
452 Matrice_Morse& mat = ref_cast(Matrice_Morse, matrice_diffusion_CH_.get_bloc(i, j).valeur());
453
454 if (i == j) /* Si diagonale => identite */
455 {
456 Stencil stencil(0, 2);
457
458 for (int e = 0; e < nb_elem; e++)
459 stencil.append_line(e, e);
460
461 Matrix_tools::allocate_morse_matrix(nb_elem, nb_elem, stencil, mat);
462 mat.sort_stencil(); // XXX sort tab2 ... au cas ou ...
463
464 for (int e = 0; e < nb_elem; e++)
465 mat(e, e) = 1.0;
466 }
467 else
468 {
469 if (i == 1) /* Matrice de alpha */
470 {
471 ch_kappa_ou_alpha_->valeurs() = -fermeture.get_alpha();
472
473 /*
474 * XXX Elie Saikali : attention la y a pas le solveur de masse qui va diviser par V apres ....
475 */
476 const DoubleVect& vol = le_dom_VDF_->volumes();
477 tab_divide_any_shape(ch_kappa_ou_alpha_->valeurs(), vol);
478 terme_diffusif_vdf_.associer_diffusivite(ch_kappa_ou_alpha_.valeur());
479 terme_diffusif_vdf_->associer_diffusivite(ch_kappa_ou_alpha_.valeur());
480 terme_diffusif_vdf_->dimensionner(mat);
481 mat.sort_stencil(); // XXX sort tab2 ... au cas ou ...
482 terme_diffusif_vdf_->contribuer_a_avec(eq_c.inconnue().valeurs(), mat);
483 }
484 else /* j == 1 ==> Matrice de kappa */
485 {
486 terme_diffusif_vdf_.associer_diffusivite(ch_kappa_ou_alpha_.valeur());
487 terme_diffusif_vdf_->associer_diffusivite(ch_kappa_ou_alpha_.valeur());
488 terme_diffusif_vdf_->dimensionner(mat);
489 mat.sort_stencil(); // XXX sort tab2 ... au cas ou ...
491 }
492 }
493 }
494//
495 Cout << "MATRICE BLOCS =========== " << finl;
496 matrice_diffusion_CH_.imprimer_formatte(Cout);
497
499
500}
501
503{
504 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
505 const auto& fermeture = mil.get_fermeture();
506 const int nb_elem = le_dom_VDF_->nb_elem_tot();
507
508 if (fermeture.get_kappa_ind() == 0)
509 kappa_tab_ = fermeture.get_kappa();
510 else
511 {
512 for (int elem = 0; elem < nb_elem; elem++)
513 kappa_tab_(elem) = fermeture.call_kappa_func_c(donne(elem));
514 }
515}
516
518{
519 const auto& fermeture = ref_cast(Milieu_Phase_field, pb_->milieu()).get_fermeture();
520
521 if (is_matrix_initialised_ && fermeture.get_type_kappa() ==0)
522 return;
523
524 update_tab_kappa(donne);
525 Matrice_Morse& mat_kappa = ref_cast(Matrice_Morse, matrice_diffusion_CH_.get_bloc(0, 1).valeur());
526
527
528 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
529 double dt = eq_c.schema_temps().pas_de_temps(); // on fait un calcul sur un demi pas de temps
530 const double theta = 0.6;
531
532 ch_kappa_ou_alpha_->valeurs() = kappa_tab_;
533 ch_kappa_ou_alpha_->valeurs() *= (theta * dt);
534 const DoubleVect& vol = le_dom_VDF_->volumes();
535 tab_divide_any_shape(ch_kappa_ou_alpha_->valeurs(), vol);
536
537 terme_diffusif_vdf_.associer_diffusivite(ch_kappa_ou_alpha_.valeur());
538 terme_diffusif_vdf_->associer_diffusivite(ch_kappa_ou_alpha_.valeur());
539 terme_diffusif_vdf_->contribuer_a_avec(eq_c.inconnue().valeurs(), mat_kappa);
540}
541
542/*! @brief Ancien assemblage de matrice "à la main" : ne prend pas en compte les différents
543 * types de schémas numériques (que VDF, pas de VEF) et les différentes CL.
544 *
545 */
546
548{
549 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
550 const DoubleTab& c = eq_c.inconnue().valeurs();
551 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
552 const auto& fermeture = mil.get_fermeture();
553
554 const Domaine_VDF& domaine_VDF = le_dom_VDF_.valeur();
555 const IntTab& face_voisins = domaine_VDF.face_voisins();
556 const IntTab& elem_faces = domaine_VDF.elem_faces();
557 const DoubleTab& positions = domaine_VDF.xp();
558 const IntVect& ori = domaine_VDF.orientation();
559
560 int compt = 0;
561 int compt1 = 0;
562 int compt2 = 0;
563
564 const int nb_elem = domaine_VDF.nb_elem_tot();
565 int nb_compo_;
566 int f0;
567 int min_tri;
568 int old_tri;
569 int voisin;
570 int nb_faces_au_bord;
571 int dimensionnement;
572 double dvar2 = 0.;
573 double dvarkeep = 0.;
574 double dt;
575 double valeur_diag = 0.;
576 const double theta = 0.6;
577 double kappa_interpolee = 0.;
578
579 if (mobilite_explicite_ == 1)
580 {
581 Cout << "Explicit mobility: Building matrix A used in JFNK..." << finl;
582 // Cerr<<"Assemblage de la matrice du point fixe"<<finl;
583
584 // Dimension du pb
585 nb_compo_ = dimension;
586
587 // Forme de la matrice : ( I A )
588 // ( B I )
589
590 // Assemblage de la moitie superieure de la matrice : I et A
591
592 // On dimensionne la matrice A et donc en meme temps B (meme nombre de termes non nuls)
593 // Pour cela : dimension du vecteur coeff = (2 * dim + 1) * nb_elem - nombre_de_bords
594
595 DoubleTab kappa_var(c);
596
597 if (fermeture.get_kappa_ind() == 0)
598 kappa_var = fermeture.get_kappa();
599 else
600 {
601 for (int elem = 0; elem < nb_elem; elem++)
602 kappa_var(elem) = fermeture.call_kappa_func_c(c(elem));
603 }
604
605 dimensionnement = (2 * nb_compo_ + 1) * nb_elem;
606
607 for (int elem = 0; elem < nb_elem; elem++)
608 {
609 for (int ncomp = 0; ncomp < 2 * nb_compo_; ncomp++)
610 {
611 f0 = elem_faces(elem, ncomp);
612 voisin = face_voisins(f0, 0);
613 if (face_voisins(f0, 0) == elem)
614 voisin = face_voisins(f0, 1);
615
616 if (voisin == -1)
617 dimensionnement--;
618 }
619 }
620 // On ajoute le nombre de 1 venant de I, ceci valant pour I et A. Le dimensionnement total est donc le double
621 dimensionnement += nb_elem;
622 dimensionnement *= 2;
623
624 // Allocation des tableaux specifiques a la matrice morse
625 ancienne_matrice_.dimensionner(2 * nb_elem, dimensionnement);
626 auto& coeff = ancienne_matrice_.get_set_coeff();
627 auto& tab2 = ancienne_matrice_.get_set_tab2();
628 auto& tab1 = ancienne_matrice_.get_set_tab1();
629 //Cerr <<"ancienne_matrice_ = "<<ancienne_matrice_<<finl;
630
631 // Boucle sur le nombre d'elements
632 for (int elem = 0; elem < nb_elem; elem++)
633 {
634 valeur_diag = 0.;
635 old_tri = -1;
636 nb_faces_au_bord = 0;
637
638 // On ajoute le 1 de la diagonale de la sous-matrice I du haut a gauche
639 coeff(compt) = 1;
640 tab2(compt2) = elem;
641 compt++;
642 compt2++;
643 tab1(compt1) = compt2;
644 compt1++;
645
646 // Calcul du nombre de bords
647 for (int ncomp = 0; ncomp < 2 * nb_compo_; ncomp++)
648 {
649 f0 = elem_faces(elem, ncomp);
650 voisin = face_voisins(f0, 0);
651 if (face_voisins(f0, 0) == elem)
652 voisin = face_voisins(f0, 1);
653
654 // On connait le voisin associe a la face en cours. On regarde s'il est au bord
655 if (voisin == -1)
656 nb_faces_au_bord++;
657 }
658
659 // Boucle sur les faces
660 for (int ncomp = 0; ncomp < 2 * nb_compo_ - nb_faces_au_bord; ncomp++)
661 {
662
663 min_tri = nb_elem + 1;
664 dt = eq_c.schema_temps().pas_de_temps(); // on fait un calcul sur un demi pas de temps
665
666 for (int ncomp_tri = 0; ncomp_tri < 2 * nb_compo_; ncomp_tri++)
667 {
668 f0 = elem_faces(elem, ncomp_tri);
669
670 // Voisin associe a la face - On s'assure de traiter un voisin et pas l'element resident
671 voisin = face_voisins(f0, 0);
672 if (face_voisins(f0, 0) == elem)
673 voisin = face_voisins(f0, 1);
674
675 // On va compter le nombre de voisins existants (faces non aux bords de l'element elem)
676 // Ceci sert a calculer la contribution au terme relatif a l'element elem
677 // Cas kappa variable : on utilise la moyenne geometrique des valeurs des mobilites
678 // des elements concernes par la face de calcul ("kappa_interpolee")
679 if (voisin != -1 && old_tri == -1)
680 {
681 dvar2 = pow((positions(elem, ori(f0)) - positions(voisin, ori(f0))), 2);
682 if (kappa_moy_ == 2)
683 kappa_interpolee = pow(std::fabs(kappa_var(elem) * kappa_var(voisin)), 0.5); // Moyenne geometrique
684 else if (kappa_moy_ == 1)
685 {
686 if (kappa_var(elem) == 0 || kappa_var(voisin) == 0)
687 kappa_interpolee = 0;
688 else
689 kappa_interpolee = 2. / (1. / kappa_var(elem) + 1. / kappa_var(voisin)); // Moyenne harmonique
690 }
691 else if (kappa_moy_ == 0)
692 kappa_interpolee = (kappa_var(elem) + kappa_var(voisin)) / 2.; // Moyenne arithmetique
693
694 valeur_diag += theta * kappa_interpolee * (dt / dvar2);
695 }
696
697 // Si le voisin a un numero plus petit que l'ancien minimum, on ne le prend pas en compte
698 // En effet, le nouveau minimum est un numero d'element qui lui sera superieur
699 // Rq : voisin>old_tri => voisin != -1 donc pour une face au bord le if est false
700 if (voisin > old_tri)
701 {
702 min_tri = std::min(min_tri, voisin);
703 if (min_tri == voisin)
704 dvarkeep = pow((positions(elem, ori(f0)) - positions(voisin, ori(f0))), 2);
705 }
706 }
707
708 //Cerr <<" min_tri = std::min(min_tri,voisin) if voisin>old_tri ====== "<<min_tri<<finl;
709 // Si l'ancien minimum est inferieur a elem et le nouveau superieur, il faut traiter elem juste avant le nouveau voisin
710 if (old_tri < elem && min_tri > elem)
711 {
712 coeff(compt) = valeur_diag;
713 tab2(compt2) = elem + nb_elem;
714 compt++;
715 compt2++;
716 }
717
718 // On complete les tableaux avec les valeurs dans les voisins non aux bords du domaine
719 if (kappa_moy_ == 2)
720 kappa_interpolee = pow(std::fabs(kappa_var(elem) * kappa_var(min_tri)), 0.5); // Moyenne geometrique
721 else if (kappa_moy_ == 1)
722 {
723 if (kappa_var(elem) == 0 || kappa_var(min_tri) == 0)
724 kappa_interpolee = 0;
725 else
726 kappa_interpolee = 2. / (1. / kappa_var(elem) + 1. / kappa_var(min_tri)); // Moyenne harmonique
727 }
728 else if (kappa_moy_ == 0)
729 kappa_interpolee = (kappa_var(elem) + kappa_var(min_tri)) / 2.; // Moyenne arithmetique
730
731 coeff(compt) = -theta * kappa_interpolee * (dt / dvarkeep);
732 tab2(compt2) = min_tri + nb_elem;
733 compt++;
734 compt2++;
735
736 // 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
737 // Ceci arrive si elem > tous les numeros d'elements de ses voisins
738 if (ncomp == 2 * nb_compo_ - nb_faces_au_bord - 1 && min_tri < elem)
739 {
740 coeff(compt) = valeur_diag;
741 tab2(compt2) = elem + nb_elem;
742 compt++;
743 compt2++;
744 }
745
746 // On sauve le numero d'element "minimum"
747 old_tri = min_tri;
748 }
749
750 }
751
752 // Assemblage de la moitie superieure de la matrice : B et I
753
754 // Boucle sur le nombre d'elements
755 for (int elem = 0; elem < nb_elem; elem++)
756 {
757 valeur_diag = 0;
758 old_tri = -1;
759 nb_faces_au_bord = 0;
760
761 // Calcul du nombre de bords
762 for (int ncomp = 0; ncomp < 2 * nb_compo_; ncomp++)
763 {
764 f0 = elem_faces(elem, ncomp);
765 voisin = face_voisins(f0, 0);
766 if (face_voisins(f0, 0) == elem)
767 voisin = face_voisins(f0, 1);
768
769 // On connait le voisin associe a la face en cours. On regarde s'il est au bord
770 if (voisin == -1)
771 nb_faces_au_bord++;
772 }
773
774 // Boucle sur les faces
775 for (int ncomp = 0; ncomp < 2 * nb_compo_ - nb_faces_au_bord; ncomp++)
776 {
777
778 min_tri = nb_elem + 1;
779
780 for (int ncomp_tri = 0; ncomp_tri < 2 * nb_compo_; ncomp_tri++)
781 {
782 f0 = elem_faces(elem, ncomp_tri);
783
784 // Voisin associe a la face - On s'assure de traiter un voisin et pas l'element resident
785 voisin = face_voisins(f0, 0);
786 if (face_voisins(f0, 0) == elem)
787 voisin = face_voisins(f0, 1);
788
789 // On va compter le nombre de voisins existants (faces non aux bords de l'element elem)
790 // Ceci sert a calculer la contribution au terme relatif a l'element elem
791 if (voisin != -1 && old_tri == -1)
792 {
793 dvar2 = pow((positions(elem, ori(f0)) - positions(voisin, ori(f0))), 2);
794 valeur_diag += -fermeture.get_alpha() / dvar2;
795 }
796
797 // Si le voisin a un numero plus petit que l'ancien minimum, on ne le prend pas en compte
798 // En effet, le nouveau minimum est un numero d'element qui lui sera superieur
799 // Rq : voisin>old_tri => voisin != -1 donc pour une face au bord le if est false
800 if (voisin > old_tri)
801 {
802 min_tri = std::min(min_tri, voisin);
803 if (min_tri == voisin)
804 dvarkeep = pow((positions(elem, ori(f0)) - positions(voisin, ori(f0))), 2);
805 }
806
807 }
808
809 // Si l'ancien minimum est inferieur a elem et le nouveau superieur, il faut traiter elem juste avant le nouveau voisin
810 if (old_tri < elem && min_tri > elem)
811 {
812 coeff(compt) = valeur_diag;
813 tab2(compt2) = elem;
814 compt++;
815 compt2++;
816 if (old_tri == -1)
817 {
818 // On ajoute un terme a tab1 dans le cas ou l'element diagonal est le premier terme
819 tab1(compt1) = compt2;
820 compt1++;
821 old_tri = elem;
822 }
823 }
824
825 // On complete les tableaux avec les valeurs dans les voisins non aux bords du domaine
826 coeff(compt) = fermeture.get_alpha() / dvarkeep;
827 tab2(compt2) = min_tri;
828 compt++;
829 compt2++;
830 if (old_tri == -1)
831 {
832 // On ajoute un terme a tab1 dans le cas ou le premier terme est extradiagonal
833 tab1(compt1) = compt2;
834 compt1++;
835 }
836
837 // 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
838 // Ceci arrive si elem > tous les numeros d'elements de ses voisins
839 // Bien sur dans ce cas la, l'element diagonal est forcement le dernier mais pas le premier - il n'existe pas de maillage avec des mailles seules sans voisins
840 if (ncomp == 2 * nb_compo_ - nb_faces_au_bord - 1 && min_tri < elem)
841 {
842 coeff(compt) = valeur_diag;
843 tab2(compt2) = elem;
844 compt++;
845 compt2++;
846 }
847
848 // On sauve le numero d'element "minimum"
849 old_tri = min_tri;
850
851 }
852
853 // On ajoute le 1 de la diagonale de la sous-matrice I du bas a droite
854 coeff(compt) = 1;
855 tab2(compt2) = elem + nb_elem;
856 compt++;
857 compt2++;
858
859 }
860
861 // cf Mat_Morse.h/.cpp, tab1() et tab2() sont a utiliser au sens Fortran
862 // EXPLICATION :
863 // coeff stocke les valeurs des coefficients
864 // tab2 stocke les numeros de colonnes dans la matrice de ces coefficients, au sens FORTRAN (i-e 1 <= tab2[i] <= n)
865 // 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 :
866 // ( tab1[i] <= j < tab1[i+1] ) qui implique qu'on considere toujours la i-eme ligne,
867 // et des que cela n'est plus respecte, le passage a la ligne suivante est effectue
868
869 // De par l'algorithme, tab1() est deja au sens FORTRAN. Reste a le faire pour tab2()
870 // De plus on doit mettre le dernier terme de tab1() a dimensionnement+1
871 tab2 += 1;
872 tab1(compt1) = dimensionnement + 1;
873 compt1 += 1;
874
875 if (compt != dimensionnement)
876 {
877 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;
879 }
880 }
881 else if (mobilite_explicite_ == 0)
882 {
883 Cerr << "Implicit mobility: the matrix A used in JFNK is not implemented." << finl;
884 ancienne_matrice_.clean();
885 }
886 else
887 {
888 Cerr << "STOP: argument mobilite_explicite cannot be different than 0 or 1." << finl;
889 Cerr << "==> Must have an error in the code." << finl;
890 }
891
892// Cerr << "---------------------- Ancienne matrice = " << finl;
893// ancienne_matrice_.imprimer_formatte(Cerr);
894
895}
896
897/*! @brief Construire le residu du JFNK
898 *
899 */
900
901void Source_Con_Phase_field_Binaire::calculer_residu_jfnk(const DoubleTab& c, DoubleTab& v0, const DoubleTab& x1)
902{
903 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
904 const auto& fermeture = mil.get_fermeture();
905 const int nb_elem = le_dom_VDF_->nb_elem_tot();
906
907 DoubleVect term_cin(nb_elem);
908 // Ceci correspond a u2/2*drhodc=mutilde_dyn-mutilde
909
910 DoubleVect second_membre(2 * nb_elem);
911 DoubleTab Ax1(2 * nb_elem);
912
913 // Assemblage du second membre
914 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
915 {
916 second_membre(n_elem) = c(n_elem);
917
918 term_cin(n_elem) = 0.;
919 if (mutype_ == 1)
920 term_cin(n_elem) += (0.5 * u_carre_(n_elem)) * drhodc(n_elem);
921
922 second_membre(n_elem + nb_elem) = term_cin(n_elem) + fermeture.get_beta() * fermeture.call_dWdc(x1(n_elem));
923 }
924
925 // Calcul du produit matrice / vecteur utilise
926 matrice_diffusion_CH_.multvect_(x1, Ax1);
927 // ancienne_matrice_.multvect_(x1, Ax1);
928
929 // Modifie par DJ
930 //---------------
931 DoubleTab Ax1_c(c);
932 DoubleTab Ax1_mutilde(c);
933 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
934 {
935 Ax1_c(n_elem) = Ax1(n_elem);
936 Ax1_mutilde(n_elem) = Ax1(n_elem + nb_elem);
937 }
938
940 Ax1_mutilde.echange_espace_virtuel();
941
942 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
943 {
944 Ax1(n_elem) = Ax1_c(n_elem);
945 Ax1(n_elem + nb_elem) = Ax1_mutilde(n_elem);
946 }
947
948 // Calcul de v0 = [A(xn) xn - bn]
949 for (int n_elem = 0; n_elem < 2 * nb_elem; n_elem++)
950 v0(n_elem) = (Ax1(n_elem) - second_membre(n_elem));
951
952}
953
954/*! @brief Construire la jacobienne multipliée par un vecteur Y
955 *
956 */
957void Source_Con_Phase_field_Binaire::jacobian_vect(const DoubleTab& c, const DoubleTab& v0, const DoubleTab& x1, DoubleTab& v1)
958{
959 const double delta = 1.e-5;
960
961 DoubleTab v2(v1);
962 DoubleTab x1_(v0);
963
964 v1 = 0.;
965
966 x1_ = v0;
967 x1_ *= delta;
968 x1_ += x1;
969
970 // Construction de la differentielle (dans la direction v0)
971 calculer_residu_jfnk(c, v1, x1_);
972 calculer_residu_jfnk(c, v2, x1);
973
974 v1 -= v2;
975 v1 /= delta;
976}
977
978#ifdef PETSCKSP_H
979// Convertir DoubleTab -> PETSc Vec
980void tabToVecOld(const DoubleTab& tab, Vec& f)
981{
982 PetscScalar *f_array;
983 PetscInt size;
984 VecGetArray(f, &f_array);
985 VecGetSize(f, &size);
986 assert(size == tab.dimension_tot(0));
987 for (int i = 0; i < tab.dimension_tot(0); i++)
988 f_array[i] = tab(i);
989 VecRestoreArray(f, &f_array);
990}
991
992// Convertir PETSc Vec -> DoubleTab
993void vecToTabOld(const Vec& v, DoubleTab& result)
994{
995 PetscInt size;
996 const PetscScalar *array;
997 VecGetSize(v, &size);
998 VecGetArrayRead(v, &array);
999 assert((int)size == result.dimension_tot(0));
1000 for (PetscInt i = 0; i < size; ++i)
1001 result((int)i) = array[i];
1002 VecRestoreArrayRead(v, &array);
1003}
1004
1005/*! @brief ForFormFunctionOld de PETSc : calcule le résidu du JFNK
1006 *
1007 */
1008//PetscErrorCode FormFunctionOld(SNES snes, Vec x, Vec f, void* ctx)
1009//{
1010// Equation_base* eqn = static_cast<Equation_base*>(ctx);
1011// Source_Con_Phase_field_Binaire& source = ref_cast(Source_Con_Phase_field_Binaire, eqn->sources().dernier().valeur());
1012//
1013// const int nb_elem = eqn->inconnue().valeurs().dimension_tot(0);
1014// DoubleTab x_tab(2 * nb_elem);
1015// vecToTabOld(x, x_tab);
1016// DoubleTab c(nb_elem), mutilde(nb_elem);
1017// DoubleTab res(2 * nb_elem);
1018//
1019// for (int i = 0; i < nb_elem; ++i)
1020// {
1021// c(i) = x_tab(i);
1022// mutilde(i) = x_tab(i + nb_elem);
1023// }
1024//
1025// source.calculer_residu_jfnk(c, res, x_tab);
1026//
1027// tabToVecOld(res, f);
1028//
1029// // Cerr << "F(X) = " << res << finl;
1030//
1031// return 0;
1032//}
1033
1034PetscErrorCode FormFunctionOld(SNES snes, Vec x, Vec f, void* ctx)
1035{
1036 Equation_base* eqn = static_cast<Equation_base*>(ctx);
1038 const DoubleTab& C = eq_c.inconnue().valeurs();
1039
1040 Source_Con_Phase_field_Binaire& source = ref_cast(Source_Con_Phase_field_Binaire, eqn->sources().dernier().valeur());
1041 const int nb_elem = C.dimension_tot(0);
1042 DoubleTab x1(2*nb_elem);
1043 vecToTabOld(x,x1);
1044
1045// Cerr << "&&&&& D'abord Vec X = " << finl;
1046// VecView(x, PETSC_VIEWER_STDOUT_WORLD);
1047
1048// Cerr << "Et X1 = " << x1 << finl;
1049
1050 DoubleTrav Ax1(x1);
1051
1052// Cerr << "Ax1 avant calcul = " << Ax1 << finl;
1053
1054 source.get_matrice_diffusion_CH().multvect_(x1, Ax1);
1055
1056 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, eq_c.milieu());
1057 const auto& fermeture = mil.get_fermeture();
1058 // Assemblage du second membre
1059 DoubleTrav second_membre(x1);
1060
1061 for (int n_elem = 0; n_elem < nb_elem; n_elem++)
1062 {
1063 second_membre(n_elem) = C(n_elem);
1064 second_membre(n_elem + nb_elem) = fermeture.get_beta() * fermeture.call_dWdc(x1(n_elem));
1065 }
1066// Cerr << "second_membre = " << second_membre << finl;
1067
1068 second_membre -= Ax1;
1069
1070 tabToVecOld(second_membre, f);
1071
1072 // Cerr << "F =" << finl;
1073// VecView(f, PETSC_VIEWER_STDOUT_WORLD);
1074
1075// Cerr << "F(X) = " << second_membre << finl;
1076
1077 return 0;
1078}
1079
1080PetscErrorCode MySNESMonitor(SNES snes, PetscInt its, PetscReal norm, void* ctx)
1081{
1082 Equation_base* eqn = static_cast<Equation_base*>(ctx);
1083 // statistiques().set_debug_level(9);
1084 double temps_exec = statistics().get_time_since_last_open(STD_COUNTERS::total_execution_time);
1085
1086 Cout << "[SNES] Iteration " << its << " : ||F(x)|| = " << norm << finl;
1087
1088 if (!Process::me())
1089 {
1090 SFichier fichier_residu("residu.txt", ios::app);
1091 fichier_residu << temps_exec << "\t" << eqn->schema_temps().temps_courant() << "\t" << (double)norm << finl;
1092 }
1093
1094
1095// Vec x;
1096// SNESGetSolution(snes, &x);
1097//
1098// Vec r;
1099// SNESGetFunction(snes, &r, nullptr, nullptr); // récupère F(x) courant
1100// Facultatif : afficher x
1101// Cerr << "Solution Iteration " << its << " : x = " << finl;
1102// VecView(x, PETSC_VIEWER_STDOUT_WORLD);
1103// Cerr << "Résidu Iteration " << its << " : r = " << finl;
1104// VecView(r, PETSC_VIEWER_STDOUT_WORLD);
1105
1106 return 0;
1107}
1108
1109PetscErrorCode LuisKSPMonitor(KSP ksp, PetscInt its, PetscReal rnorm, void* ctx)
1110{
1111 Cout << " [KSP] Iteration " << its << " : residu = " << rnorm << finl;
1112 // Vec x;
1113 // KSPBuildSolution(ksp, nullptr, &x); // récupère x courant (solution approx.)
1114
1115// VecView(x, PETSC_VIEWER_STDOUT_WORLD); // affiche le contenu de x
1116
1117 return 0;
1118}
1119
1120int Source_Con_Phase_field_Binaire::petsc_snes(const DoubleTab& c, const DoubleTab& mutilde, DoubleTab& c_demi, DoubleTab& mutilde_demi)
1121{
1122
1123 const int ns = 2 * c.size_totale();
1124 const int nb_elem_tot = c.size_totale();
1125 DoubleTrav x1(ns); // inconnue (vector de C et mutilde)
1126 DoubleTrav v0(ns); // tableau TRUST du résidu
1127
1128 for (int n_elem = 0; n_elem < nb_elem_tot; n_elem++)
1129 {
1130 x1(n_elem) = c(n_elem);
1131 x1(n_elem + nb_elem_tot) = mutilde(n_elem);
1132 }
1133
1134 // Variables SNES ########################################
1135 SNES snes; // Contexte SNES
1136 Vec x, r; // Vecteurs : solution, résidu
1137 KSP ksp;
1138 Mat J;
1139 PC pc;
1140 // #######################################################
1141
1142 // INITIALISATION DU VECTEUR D'INCONNUES X
1143 VecCreate(PETSC_COMM_WORLD, &x);
1144 VecSetSizes(x, PETSC_DECIDE, ns);
1145 VecSetFromOptions(x);
1146
1147 // INITIAL GUESS of X
1148 tabToVecOld(x1, x);
1149
1150 VecDuplicate(x, &r);
1151
1152 // Vérification tailles
1153 PetscInt x_size, r_size;
1154 VecGetSize(x, &x_size);
1155 VecGetSize(r, &r_size);
1156 assert(x_size == ns);
1157 assert(r_size == ns);
1158
1159 // ---------------------- Compute real values of tolerances ---------------------------
1160 // Appel explicite de ta fonction de résidu
1161 FormFunctionOld(nullptr, x, r, &equation());
1162
1163 // Affiche le résidu (par exemple sa norme)
1164 PetscReal norm;
1165 VecNorm(r, NORM_2, &norm);
1166 PetscPrintf(PETSC_COMM_WORLD, "Résidu F(x) = %g\n", (double)norm);
1167
1168 // ------------------------------------ SNES ------------------------------------------
1169 SNESCreate(PETSC_COMM_WORLD, &snes);
1170
1171 SNESSetType(snes, SNESNEWTONLS);
1172
1173 // ========== Associate the FormFunctionOld to the SNES context ============
1174 SNESSetFunction(snes, r, FormFunctionOld, &equation());
1175 // ======================================================================
1176
1177 SNESLineSearch linesearch;
1178 SNESGetLineSearch(snes, &linesearch); // Newton Line Search ne marche pas dans notre cas
1179 // C'est pour ça qu'on le désactive ici
1180 SNESLineSearchSetType(linesearch, SNESLINESEARCHNONE); // Désactive la recherche de pas
1181
1182 // Checking if linesearch is desactivated
1183 const char* ls_type;
1184 SNESLineSearchGetType(linesearch, &ls_type);
1185 PetscPrintf(PETSC_COMM_WORLD, "Type of Line Search used: %s\n", ls_type); // Printing linesearch type
1186
1187 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1188
1189 // Crée la matrice matrix-free à partir du SNES
1190 MatCreateSNESMF(snes, &J);
1191
1192 // Fixe epsilon sur la vraie matrice MF
1193 // MatMFFDSetBase(J, delta);
1194 MatMFFDSetFunctionError(J, erel_);
1195 MatMFFDSetType(J, "ds"); // default: ds (difference scaled), alternative: wp (Walker–Pernice)
1196 MatMFFDDSSetUmin(J, umin_);
1197
1198 SNESSetJacobian(snes, J, J, MatMFFDComputeJacobian, nullptr);
1199 // SNESSetJacobian(snes, J, nullptr, nullptr, nullptr);
1200
1201 MatView(J, PETSC_VIEWER_STDOUT_WORLD);
1202
1203 // Pas de Jacobien explicite => JFNK par défaut : SNES construit la matrice par DF entre colonnes
1204 // SNESSetJacobian(snes, nullptr, nullptr, SNESComputeJacobianDefault, nullptr);
1205 // SNESSetUseMatrixFree(snes, PETSC_TRUE, PETSC_TRUE); // Impose l'option Matrix-Free
1206
1207 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1208
1209 // Tolerance for Newton
1210 SNESSetTolerances(snes, atol_, rtol_, stol_, maxit_newton_, 100000);
1211
1212 // TRES IMPORTANT : Force à continuer l'algorithme de Newton même si la méthode de Krylov n'a pas convergé
1213 SNESSetForceIteration(snes, PETSC_TRUE);
1214 SNESSetMaxLinearSolveFailures(snes, 200);
1215
1216 // Vérification
1217 PetscBool force_it;
1218 SNESGetForceIteration(snes, &force_it);
1219 PetscPrintf(PETSC_COMM_WORLD, "Force iteration: %s\n", force_it ? "ON" : "OFF");
1220
1221 // --------------------------------------- KSP ---------------------------------------------
1222 SNESGetKSP(snes, &ksp);
1223 KSPSetType(ksp, KSPGMRES); // GMRES
1224 KSPGMRESSetRestart(ksp, nkr_); // GMRES(m) avec m la dimension de l'espace de Krylov définie par l'utilisateur
1225 // KSPSetType(ksp, KSPCG); // CG
1226 // KSPSetInitialGuessNonzero(ksp, PETSC_TRUE); // XXX Luis : PAS BON DU TOUT
1227 // PetscOptionsSetValue(nullptr, "-ksp_gmres_orthogonalization", "classical"); // Facultatif : dans notre config, on ne peut pas changer le type d'orthogonalisation
1228 KSPSetTolerances(ksp, rtol_, atol_, 5000., maxit_gmres_);
1229
1230 // -------------------------------- Préconditionneur --------------------------------------
1231 KSPGetPC(ksp, &pc);
1232 PCSetType(pc, PCNONE); // No preconditionning
1233 // PCSetFromOptions(pc);
1234
1235 // Monitoring
1236 KSPMonitorSet(ksp, LuisKSPMonitor, nullptr, nullptr);
1237 SNESMonitorSet(snes, MySNESMonitor, &equation(), nullptr);
1238
1239 // =============================== Setting from options ===================================
1240 // KSPSetFromOptions(ksp); // Lire les options
1241
1242 // Injecte les options comme si elles venaient de la ligne de commande
1243 // PetscOptionsSetValue(nullptr, "-pc_type", "none"); // désactive le préconditionneur
1244 // PetscOptionsSetValue(nullptr, "-snes_mf", nullptr); // active matrix-free
1245 // PetscOptionsSetValue(nullptr, "-snes_mf_relstep", "1e-5"); // contrôle l’epsilon de l’approximation par différences finies
1246
1247 PetscOptionsView(nullptr, PETSC_VIEWER_STDOUT_WORLD); // Visu de la liste des options
1248 PetscOptionsLeft(nullptr); // Liste celles qui n'ont PAS été utilisées
1249
1250 // Lecture des options ligne de commande de SNES
1251 SNESSetOptionsPrefix(snes, "mysolver_");
1252
1253 SNESSetFromOptions(snes);
1254
1255 SNESView(snes, PETSC_VIEWER_STDOUT_WORLD);
1256
1257 // ############################### SOLVING ################################################
1258 SNESSolve(snes, nullptr, x); // #
1259 // ########################################################################################
1260
1261 PetscInt nfunc;
1262 SNESGetNumberFunctionEvals(snes, &nfunc);
1263
1264 if (!Process::me())
1265 {
1266 SFichier fichier_eval("eval.txt", ios::app);
1267 fichier_eval << equation().schema_temps().temps_courant() << "\t" << nfunc << finl;
1268 }
1269
1270
1271 const char *reasonstr;
1272 SNESGetConvergedReasonString(snes, &reasonstr);
1273 Cout << "SNES converged for this reason: " << reasonstr << finl;
1274
1275 DoubleTrav solution(ns); // inconnue (vector de C et mutilde)
1276
1277 vecToTabOld(x,solution);
1278
1279 for (int n_elem = 0; n_elem < nb_elem_tot; n_elem++)
1280 {
1281 c_demi(n_elem) = solution(n_elem);
1282 mutilde_demi(n_elem) = solution(n_elem + nb_elem_tot);
1283 }
1284
1285 // Nettoyage
1286 VecDestroy(&x);
1287 VecDestroy(&r);
1288 MatDestroy(&J);
1289 SNESDestroy(&snes);
1290
1291 return 1;
1292}
1293#endif
1294
1295/*! @brief Algorithme JFNK (ancienne version de D. Jamet et nouvelle version de PETSc)
1296 *
1297 * @param (mutilde) inverse A x = b
1298 * @return (int)
1299 *
1300 * Solves Ax = b by GMRES with nit iterations (reinitializations) and nkr Krilov vectors.
1301 * Copied from Sch_Crank_Nicholson.cpp (scalar)//
1302 *
1303 */
1304int Source_Con_Phase_field_Binaire::resolution_jfnk(const DoubleTab& c, const DoubleTab& mutilde, DoubleTab& c_demi, DoubleTab& mutilde_demi)
1305{
1306#ifdef PETSCKSP_H
1307 if (with_petsc_ == 1)
1308 return petsc_snes(c, mutilde, c_demi, mutilde_demi);
1309 else if (with_petsc_ == 0)
1310 {
1311 int i, j, nk, i0, im, it, ii;
1312 double tem = 1., res, ccos, ssin;
1313 const int ns = 2 * c.size_totale();
1314 const int nb_elem_tot = c.size_totale();
1315 double temps_exec = 0.;
1316 int nfunc=0;
1317// statistiques().set_debug_level(9);
1318
1319// Cout << "MATRICE BLOCS M =========== " << finl;
1320// matrice_diffusion_CH_.get_bloc(0,1)->imprimer_formatte(Cout);
1321// Cout << "MATRICE BLOCS K =========== " << finl;
1322// matrice_diffusion_CH_.get_bloc(1,0)->imprimer_formatte(Cout);
1323
1324 // Ajoute par DJ
1325 //--------------
1326 DoubleTrav x1(ns);
1327 DoubleTrav c_update(nb_elem_tot);
1328
1329 for (int n_elem = 0; n_elem < nb_elem_tot; n_elem++)
1330 {
1331 x1(n_elem) = c(n_elem);
1332 x1(n_elem + nb_elem_tot) = mutilde(n_elem);
1333 }
1334
1335 Cout << "Vecteur x1 = " << x1 << finl;
1336
1337 DoubleTab v(ns, nkr_); // Krilov vectors
1338 DoubleTab h(nkr_ + 1, nkr_); // Heisenberg maatrix of coefficients
1339 DoubleVect r(nkr_ + 1);
1340 DoubleTab v0(x1);
1341 DoubleTab v1(x1);
1342
1343 // Initialisation
1344 v = 0.;
1345 v0 = 0.;
1346 v1 = 0.;
1347
1348 // v0 = -1.*calculer_residu_jfnk(eqn, x1); // DJ
1349
1350 calculer_residu_jfnk(c, v0, x1);
1351 nfunc++;
1352 v0 *= -1.; // b - AX
1353
1354 Cout << "Residu v0 = " << v0 << finl;
1355
1356 res = 0.;
1357 // Modifie par DJ
1358 //---------------
1359 for (ii = 0; ii < c.size(); ii++) // Partie c
1360 res += v0(ii) * v0(ii);
1361 for (ii = c.size_totale(); ii < c.size_totale() + c.size(); ii++) // Partie mutilde
1362 res += v0(ii) * v0(ii);
1363
1364 res = mp_sum(res);
1365 res = sqrt(res);
1366
1367 // Cout << "Premier vecteur v0 = " << v0 << finl;
1368 Cout << "Norme du premier résidu = " << res << finl;
1369
1370 if (res < rtol_)
1371 return 0; // nothing to do
1372
1373 rtol_ = (rtol_ < res * atol_) ? res * atol_ : rtol_;
1374 rtol_ = (rtol_ < stol_) ? rtol_ : stol_;
1375
1376 Cout << "Source Concentration Phase Field - JFNK" << finl;
1377 Cout << "Stopping rule scalar : " << rtol_ << finl;
1378
1379 // iterations
1380 for (it = 0; it < maxit_newton_; it++)
1381 {
1382 nk = nkr_;
1383
1384 //...Orthogonalisation of Arnoldi
1385 v0 /= res;
1386 r = 0.;
1387 r[0] = res;
1388 h = 0.;
1389
1390 for (j = 0; j < nkr_; j++)
1391 {
1392 for (ii = 0; ii < ns; ii++)
1393 v(ii, j) = v0(ii);
1394
1395 jacobian_vect(c, v0, x1, v1);
1396 nfunc++;
1397 nfunc++;
1398 v0 = v1;
1399
1400 // Modifie par DJ
1401 //---------------
1402 for (i = 0; i <= j; i++)
1403 {
1404 for (ii = 0; ii < c.size(); ii++)
1405 h(i, j) += v0(ii) * v(ii, i);
1406 for (ii = c.size_totale(); ii < c.size_totale() + c.size(); ii++)
1407 h(i, j) += v0(ii) * v(ii, i);
1408 h(i, j) = mp_sum(h(i, j));
1409
1410 for (ii = 0; ii < ns; ii++)
1411 v0(ii) -= h(i, j) * v(ii, i);
1412 }
1413 // tem = sqrt(v0 * v0);
1414 tem = 0.;
1415 // Modifie par DJ
1416 //---------------
1417 for (ii = 0; ii < c.size(); ii++)
1418 tem += v0(ii) * v0(ii);
1419 for (ii = c.size_totale(); ii < c.size_totale() + c.size(); ii++)
1420 tem += v0(ii) * v0(ii);
1421
1422 tem = mp_sum(tem);
1423 tem = sqrt(tem);
1424 h(j + 1, j) = tem;
1425 if (tem < rtol_)
1426 {
1427 nk = j + 1;
1428 goto l5;
1429 }
1430 v0 /= tem;
1431 }
1432
1433 //...Triangularisation QR de la matrice de Hessenberg
1434l5:
1435 for (i = 0; i < nk; i++)
1436 {
1437 im = i + 1;
1438 tem = 1. / sqrt(h(i, i) * h(i, i) + h(im, i) * h(im, i));
1439 ccos = h(i, i) * tem;
1440 ssin = -h(im, i) * tem;
1441 for (j = i; j < nk; j++)
1442 {
1443 tem = h(i, j);
1444 h(i, j) = ccos * tem - ssin * h(im, j);
1445 h(im, j) = ssin * tem + ccos * h(im, j);
1446 }
1447 r[im] = ssin * r[i];
1448 r[i] *= ccos;
1449 }
1450
1451 //...Solution of linear system
1452 for (i = nk - 1; i >= 0; i--)
1453 {
1454 r[i] /= h(i, i);
1455 for (i0 = i - 1; i0 >= 0; i0--)
1456 r[i0] -= h(i0, i) * r[i];
1457 }
1458 for (i = 0; i < nk; i++)
1459 for (ii = 0; ii < ns; ii++)
1460 x1(ii) += r[i] * v(ii, i);
1461
1462 if (mobilite_explicite_ == 0) /* implicite */
1463 {
1464 for (int n_elem = 0; n_elem < nb_elem_tot; n_elem++)
1465 c_update(n_elem) = x1(n_elem);
1466
1467 update_bloc_kappa(c_update);
1468 }
1469
1470 calculer_residu_jfnk(c, v0, x1);
1471 nfunc++;
1472 v0 *= -1.;
1473
1474 res = 0.;
1475 // Modifie par DJ
1476 //---------------
1477 for (ii = 0; ii < c.size(); ii++)
1478 res += v0(ii) * v0(ii);
1479 for (ii = c.size_totale(); ii < c.size_totale() + c.size(); ii++)
1480 res += v0(ii) * v0(ii);
1481
1482 res = mp_sum(res);
1483 res = sqrt(res);
1484
1485 Cout << " - At it = " << it << ", residu scalar = " << res; // << finl;
1486 // Cout << " and vector R = " << v0 << finl;
1487
1488 temps_exec = statistics().get_time_since_last_open(STD_COUNTERS::total_execution_time);
1489
1490 if (!Process::me())
1491 {
1492 SFichier fichier_residu("residu.txt", ios::app);
1493 fichier_residu << temps_exec << "\t" << equation().schema_temps().temps_courant() << "\t" << res << finl;
1494 }
1495
1496 if (res < rtol_)
1497 {
1498 // Ajoute par DJ
1499 //--------------
1500 for (int n_elem = 0; n_elem < nb_elem_tot; n_elem++)
1501 {
1502 c_demi(n_elem) = x1(n_elem);
1503 mutilde_demi(n_elem) = x1(n_elem + nb_elem_tot);
1504 }
1505 // L'echange espace virtuel est fait dans premier_demi_dt()
1506 Cout << "Number of iterations to reach convergence : " << it + 1 << finl;
1507 Cout << "" << finl;
1508
1509 return it;
1510 }
1511 else if (it == maxit_newton_ - 1)
1512 {
1513 // Ajoute par DJ
1514 //--------------
1515 // On fait le choix de mettre a jour c_demi et mutilde_demi meme s'il n'y a pas convergence...
1516 for (int n_elem = 0; n_elem < nb_elem_tot; n_elem++)
1517 {
1518 c_demi(n_elem) = x1(n_elem);
1519 mutilde_demi(n_elem) = x1(n_elem + nb_elem_tot);
1520 }
1521
1522 Cout << "Stopped before convergence" << finl;
1523 Cout << "" << finl;
1524
1525 }
1526 }
1527 if (!Process::me())
1528 {
1529 SFichier fichier_eval("eval.txt", ios::app);
1530 fichier_eval << equation().schema_temps().temps_courant() << "\t" << nfunc << finl;
1531 }
1532 }
1533 else
1534 {
1535 Cerr << "Error: Phase_field - Bad input for choosing between resolution with PETSc or not." << finl;
1536 Process::exit();
1537 }
1538#endif
1539 return -1;
1540
1541}
1542
1543/*! @brief Calcul de mutilde au centre des elements
1544 *
1545 * @param (mutilde) mutilde au centre des elements
1546 */
1548{
1549 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
1550 const DoubleTab& c = eq_c.inconnue().valeurs();
1551 const DoubleTab& div_alpha_gradC = eq_c.get_div_alpha_gradC();
1552 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
1553 const auto& fermeture = mil.get_fermeture();
1554
1555 // Calcul de mutilde
1556
1557 mutilde = div_alpha_gradC;
1558 mutilde *= -1.;
1559
1560 //Cerr << "mutilde = -div_alpha_gradC " << mutilde << finl;
1561
1562 const int taille = mutilde.size();
1563 for (int i = 0; i < taille; i++)
1564 {
1565 mutilde(i) += fermeture.get_beta() * fermeture.call_dWdc(c(i));
1566 if (mutype_ == 1) //avec Ec
1567 mutilde(i) += (0.5 * u_carre_(i)) * drhodc(i);
1568 }
1569
1570// L'espace virtuel n'est pas a jour
1571 assert_invalide_items_non_calcules(mutilde);
1572
1573}
1574
1575void Source_Con_Phase_field_Binaire::calculer_mutilde_demi(DoubleTab& mutilde_demi, DoubleTab& c_demi) const
1576{
1577 const Convection_Diffusion_Phase_field& eq_c = ref_cast(Convection_Diffusion_Phase_field, pb_->equation(1));
1578 const Navier_Stokes_std& eq_ns = ref_cast(Navier_Stokes_std, pb_->equation(0));
1579 const Operateur_Grad& opgrad = eq_ns.operateur_gradient();
1580 const Operateur_Div& opdiv = eq_ns.operateur_divergence();
1581 const Milieu_Phase_field& mil = ref_cast(Milieu_Phase_field, pb_->milieu());
1582 const auto& fermeture = mil.get_fermeture();
1583
1584 mutilde_demi = 0.;
1585
1586 DoubleTab& prov_face = ref_cast_non_const(DoubleTab, prov_face_);
1587 if (prov_face.size() == 0)
1588 prov_face = eq_ns.inconnue().valeurs();
1589 prov_face = 0.;
1590
1591 // Grad(C)
1592 opgrad.calculer(c_demi, prov_face);
1593 eq_ns.solv_masse().appliquer(prov_face);
1594 prov_face *= fermeture.get_alpha();
1595
1596 // Div(alpha*Grad(c))
1597 opdiv.calculer(prov_face, mutilde_demi);
1598 eq_c.solv_masse().appliquer(mutilde_demi);
1599 //Cerr <<"div_alpha_gradC"<<div_alpha_gradC<<finl;
1600
1601 mutilde_demi *= -1.;
1602
1603 const int taille = mutilde_demi.size();
1604 for (int i = 0; i < taille; i++)
1605 {
1606 mutilde_demi(i) += fermeture.get_beta() * fermeture.call_dWdc(c_demi(i));
1607 if (mutype_ == 1) //avec Ec
1608 {
1609 mutilde_demi(i) += (0.5 * u_carre_(i)) * drhodc(i);
1610 }
1611 }
1612
1613// L'espace virtuel n'est pas a jour
1614 assert_invalide_items_non_calcules(mutilde_demi);
1615}
1616
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
const Milieu_base & milieu() const override
Renvoie le milieu physique de l'equation.
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
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
classe Equation_base Le role d'une equation est le calcul d'un ou plusieurs champs....
Sources & sources()
Renvoie les termes sources asssocies a l'equation.
Solveur_Masse_base & solv_masse()
Renvoie le solveur de masse associe a l'equation.
virtual Domaine_Cl_dis_base & domaine_Cl_dis()
Renvoie le domaine des conditions aux limite discretisee associee a l'equation.
Schema_Temps_base & schema_temps()
Renvoie le schema en temps associe a l'equation.
double call_kappa_func_c(const double d) const
void nommer(const Nom &) override
Donne un nom au champ.
virtual DoubleVect & multvect_(const DoubleVect &, DoubleVect &) const
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
static void allocate_morse_matrix(const int nb_lines, const int nb_columns, const Stencil &stencil, Matrice_Morse &matrix, const bool &attach_stencil_to_matrix=false)
const Champ_Don_base & rho() const
const Fermeture_Phase_field_base & get_fermeture() const
const Equation_base & equation() const
Renvoie la reference sur l'equation pointe par MorEqn::mon_equation.
Definition MorEqn.h:62
classe Navier_Stokes_phase_field Cette classe porte les termes de l'equation de la dynamique
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.
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 int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
Cette classe est a la classe C++ ofstream ce que la classe Sortie est a la classe C++ ostream Elle re...
Definition SFichier.h:27
double temps_courant() const
Renvoie le temps courant.
double pas_de_temps() const
Renvoie le pas de temps (delta_t) courant.
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_mutilde_demi(DoubleTab &, DoubleTab &) const
DoubleTab & div_kappa_grad(const DoubleTab &, const DoubleTab &, DoubleTab &) const
void calculer_residu_jfnk(const DoubleTab &, DoubleTab &, const DoubleTab &)
Construire le residu du JFNK.
void assembler_ancienne_matrice()
Ancien assemblage de matrice "à la main" : ne prend pas en compte les différents types de schémas num...
void calculer_mutilde(DoubleTab &) const
Calcul de mutilde au centre des elements.
int resolution_jfnk(const DoubleTab &, const DoubleTab &, DoubleTab &, DoubleTab &)
Algorithme JFNK (ancienne version de D. Jamet et nouvelle version de PETSc).
void calculer_div_alpha_grad(const DoubleTab &, DoubleTab &) const
Calcul de Div(alpha*rho*Grad((C)) au centre des elements.
int petsc_snes(const DoubleTab &, const DoubleTab &, DoubleTab &, DoubleTab &)
void jacobian_vect(const DoubleTab &, const DoubleTab &, const DoubleTab &, DoubleTab &)
Construire la jacobienne multipliée par un vecteur Y.
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...
DoubleTab & laplacien(const DoubleTab &, DoubleTab &) const
void calculer_div_alpha_rho_grad(const DoubleTab &, DoubleTab &) const
Calcul de Div(alpha*rho*Grad((C)) au centre des elements.
virtual void calculer_u2_elem(DoubleVect &)
double drhodc(const int n_elem) const
_SIZE_ dimension_tot(int) const override
Definition TRUSTTab.tpp:160
void append_line(_TYPE_)
Definition TRUSTTab.tpp:213
_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")