TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
mon_main.cpp
1/****************************************************************************
2* Copyright (c) 2026, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <mon_main.h>
17#include <LecFicDiffuse_JDD.h>
18#include <TClearable.h> // To clear caches before exiting, notably Domaine_dis_cache
19#include <instancie_appel.h>
20#include <SFichier.h>
21#include <Comm_Group_MPI.h>
22#include <PE_Groups.h>
23#include <Journal.h>
24#include <cstdio>
25#include <Perf_counters.h>
26#include <communications.h>
27#include <petsc_for_kernel.h>
28#ifdef PETSCKSP_H
29#include <petscdevice.h>
30#include <petscsys.h>
31#endif
32#include <Baltik_Version.h>
33#include <info_atelier.h>
34#include <unistd.h> // Pour chdir for other compiler
35#ifndef __CYGWIN__
36#include <catch_and_trace.h>
37#endif
38
39#include <kokkos++.h>
40
41namespace
42{
43static bool TRUST_LIBRARY_MODE = false;
44}
45
46void TRUST_set_library_mode(bool b)
47{
48 TRUST_LIBRARY_MODE = b;
49}
50
51void TRUST_global_finalize()
52{
53 if (!TRUST_LIBRARY_MODE) return;
54
55#ifdef PETSCKSP_H
56 // On PetscFinalize que si c'est necessaire
57 PetscBool isInitialized;
58 PetscInitialized(&isInitialized);
59 if (isInitialized==PETSC_TRUE)
60 {
61 PetscPopErrorHandler(); // Removes the latest error handler that was pushed with PetscPushErrorHandler in init_petsc
62 PetscFinalize();
63 }
64#endif
65
66 if (Kokkos::is_initialized())
67 Kokkos::finalize();
68}
69
70mon_main::mon_main(int verbose_level, bool journal_master, Nom log_directory, bool apply_verification, bool disable_stop)
71{
72 verbose_level_ = verbose_level;
73 journal_master_ = journal_master;
74 log_directory_ = log_directory;
75 LecFicDiffuse_JDD::apply_verif = apply_verification;
76 // Creation d'un journal temporaire qui ecrit dans Cerr
77 init_journal_file(verbose_level, 0 /* filename = 0 => Cerr */, 0 /* append */);
78 trio_began_mpi_=false;
79 disable_stop_=disable_stop;
80 change_disable_stop(disable_stop);
81}
82
83static int init_petsc(int argc, char **argv, bool with_mpi,bool& trio_began_mpi_)
84{
85#ifdef PETSCKSP_H
86 PetscBool isInitialized;
87 PetscInitialized(&isInitialized);
88 if (isInitialized)
89 return 1;
90
91 static char help[] = "TRUST may solve linear systems with Petsc library.\n\n" ;
92 Nom pwd(::pwd());
93 // On initialise Petsc
94#ifdef MPI_INIT_NEEDS_MPIRUN
95 int flag;
96 MPI_Initialized(&flag);
97 // si MPI initialise ou si argc>2
98 if ((argc>2)||(flag))
99 {
100 PetscInitialize(&argc, &argv, (char*)0, help);
101 }
102#else
103 PetscInitialize(&argc, &argv, (char*)0, help);
104#endif
105#ifdef TRUST_USE_GPU
106 PetscDevice device;
107 PetscDeviceCreate(PETSC_DEVICE_DEFAULT(), PETSC_DECIDE, &device);
108 PetscDeviceView(device, PETSC_VIEWER_STDERR_WORLD);
109 //if (instance==1) PetscLogGpuTime(); // Slow down calculation ! Use -log_view_gpu_time
110#endif
111 // Bizarrerie qui se produit sur une machine (ioulia, MPICH natif): PetscInitialize change le pwd()
112 // en sequentiel et si le binaire n'est pas dans le repertoire de l'etude, le pwd est perdu...
113 int ierr;
114 if (!with_mpi)
115 {
116 ierr=chdir(pwd);
117 if (ierr)
118 {
119 Cerr << "Error on chdir into mon_main.cpp. Contact TRUST support." << finl;
121 }
122 }
123 // Equivalent de -abort_on_error (aucune erreur PETSc n'est tolere):
124 PetscPushErrorHandler(PetscAbortErrorHandler, PETSC_NULLPTR);
125 // Desactive le signal handler en optimise pour eviter d'etre trop bavard
126 // et de "masquer" les messages d'erreur TRUST:
127 PetscPopSignalHandler();
128
129#ifndef __CYGWIN__
130 Cerr << "Enabling error handlers catching SIGFPE and SIGABORT and giving a trace of where the fault happened." << finl;
131 install_handlers();
132#endif
133#else
134#ifdef MPI_
135 // MPI_Init pour les machines ou Petsc n'est pas installe
136 int flag;
137 MPI_Initialized(&flag);
138 if (!flag)
139 {
140 MPI_Init(&argc,&argv);
141 trio_began_mpi_=true;
142 }
143#endif
144#endif
145
146 return 1;
147}
148
149static int init_parallel_mpi(OWN_PTR(Comm_Group) & groupe_trio)
150{
151#ifdef MPI_
152 groupe_trio.typer("Comm_Group_MPI");
153 Comm_Group_MPI& mpi = ref_cast(Comm_Group_MPI, groupe_trio.valeur());
154 mpi.init_group_trio();
155 return 1;
156#else
157 return 0;
158#endif
159}
160
161static void instantiate_node_mpi(OWN_PTR(Comm_Group) & ngrp, OWN_PTR(Comm_Group) & mgrp, int with_mpi)
162{
163 if (with_mpi)
164 {
165 ngrp.typer("Comm_Group_MPI");
166 mgrp.typer("Comm_Group_MPI");
167 }
168 else
169 {
170 ngrp.typer("Comm_Group_NoParallel");
171 mgrp.typer("Comm_Group_NoParallel");
172 }
173}
174
175static void init_node_mpi(OWN_PTR(Comm_Group) & ngrp)
176{
177#ifdef MPI_
178 assert(ngrp);
179 Comm_Group_MPI& mpi_on_node = ref_cast(Comm_Group_MPI, ngrp.valeur());
180 mpi_on_node.init_comm_on_numa_node();
181#endif
182}
183
184static void init_node_masters(OWN_PTR(Comm_Group) & master)
185{
186#ifdef MPI_
187 assert(master);
188 Comm_Group_MPI& mm = ref_cast(Comm_Group_MPI, master.valeur());
189 mm.init_comm_on_node_master();
190#endif
191}
192
193///////////////////////////////////////////////////////////
194// Desormais Petsc/MPI_Initialize et Petsc/MPI_Finalize
195// sont dans un seul fichier: mon_main
196// On ne doit pas en voir ailleurs !
197//////////////////////////////////////////////////////////
198void mon_main::init_parallel(const int argc, char **argv, bool with_mpi, bool check_enabled, bool with_petsc)
199{
200 bool init_kokkos_before_mpi = (getenv("KOKKOS_AFTER_MPI") == nullptr);
201 // https://kokkos.org/kokkos-core-wiki/ProgrammingGuide/Initialization.html say after !
202 if (init_kokkos_before_mpi && !Kokkos::is_initialized())
203 {
204 // Kokkos initialization
205 int argc2 = argc;
206 Kokkos::initialize(argc2, argv);
207 }
208 Nom arguments_info = "";
209 arguments_info += "Kokkos initialized!\n";
210
211 bool must_mpi_initialize = true;
212 if (with_petsc)
213 {
214 if (init_petsc(argc, argv, with_mpi, trio_began_mpi_))
215 {
216 must_mpi_initialize = false; // Deja fait par Petsc
217 arguments_info += "Petsc initialization succeeded.\n";
218 }
219 else
220 {
221 arguments_info += "Petsc initialization failed (not compiled ?). Not fatal...\n";
222 }
223 }
224 else
225 {
226 arguments_info += "Petsc initialization skipped (-petsc=0).\n";
227 }
228#ifdef MPI_
229 Comm_Group_MPI::set_must_mpi_initialize(must_mpi_initialize);
230#else
231 // avoid variable 'must_mpi_initialize' set but not used error when MPI disabled
232 if (must_mpi_initialize) abort();
233#endif
234 // ***************** Initialisation du parallele *************************
235 Comm_Group::set_check_enabled(check_enabled);
236
237 if (with_mpi)
238 {
239 if (!init_parallel_mpi(groupe_trio_))
240 {
241 Cerr << "MPI initialization failed (not compiled ?). Fatal." << finl;
243 }
244 }
245 else
246 groupe_trio_.typer("Comm_Group_NoParallel");
247
248 // Initialisation des groupes de communication.
249 PE_Groups::initialize(groupe_trio_);
250 arguments_info += "Parallel engine initialized : ";
251 arguments_info += groupe_trio_->que_suis_je();
252 arguments_info += " with ";
253 arguments_info += Nom(Process::nproc());
254 arguments_info += " processors\n";
255
257 Cerr << arguments_info;
258
259 // the node group is instantiated here, so that it's done only once (necessary with ICoCo)
260 // however, it is initialized later, as it involves communication operations, which require statistics to be initialized first...
261 instantiate_node_mpi(node_group_, node_master_, with_mpi);
262
263 if (!init_kokkos_before_mpi && !Kokkos::is_initialized())
264 {
265 // Kokkos initialization
266 int argc2 = argc;
267 Kokkos::initialize(argc2, argv);
269 Cerr << "Kokkos initialized after MPI !" << finl;
270 }
272 {
273#ifdef TRUST_USE_GPU
274 Kokkos::print_configuration(std::cerr, true);
275#endif
276 Cerr << "You can run --kokkos-help option." << finl;
277 }
278}
279
281{
282 // Clear all things that were registered by Register_clearable() method (typically the Domaine_dis_cache instance
283 // to make sure all Kokkos views are freed before doing Kokkos finalize):
285
286#ifdef MPI_
287 // MPI_Group_free before MPI_Finalize (not freeing comm as we can not free MPI_COMM_WORLD)
288 if (sub_type(Comm_Group_MPI,groupe_trio_.valeur()))
289 ref_cast(Comm_Group_MPI,groupe_trio_.valeur()).free();
290
291 if (sub_type(Comm_Group_MPI,node_master_.valeur()))
292 ref_cast(Comm_Group_MPI,node_master_.valeur()).free_all(); // free comm + group
293
294 if (sub_type(Comm_Group_MPI,node_group_.valeur()))
295 ref_cast(Comm_Group_MPI,node_group_.valeur()).free_all(); // free comm + group
296
297 // user defined groups (if any !)
299 {
301 if (sub_type(Comm_Group_MPI,grp))
302 ref_cast_non_const(Comm_Group_MPI,grp).free_all(); // free comm + group
303 }
304
305#endif
306
307#ifdef PETSCKSP_H
308 if (!TRUST_LIBRARY_MODE)
309 {
310 // On PetscFinalize que si c'est necessaire
311 PetscBool isInitialized;
312 PetscInitialized(&isInitialized);
313 if (isInitialized==PETSC_TRUE)
314 {
315 PetscPopErrorHandler(); // Removes the latest error handler that was pushed with PetscPushErrorHandler in init_petsc
316#ifdef MPI_
318 PETSC_COMM_WORLD = ref_cast(Comm_Group_MPI,PE_Groups::current_group()).get_mpi_comm();
319#endif
320 PetscFinalize();
321 }
322 }
323#endif
324
325#ifdef MPI_
326 if (!TRUST_LIBRARY_MODE && trio_began_mpi_)
327 {
328 // On MPI_Finalize si MPI_Initialized and not MPI_Finalized
329 int flag;
330 MPI_Initialized(&flag);
331 if (flag)
332 {
333 MPI_Finalized(&flag);
334 if (!flag)
335 MPI_Finalize();
336 }
337 }
338#endif
339 if (!TRUST_LIBRARY_MODE && Kokkos::is_initialized())
340 Kokkos::finalize();
341}
342
343void mon_main::dowork(const Nom& nom_du_cas)
344{
345 // Le processeur maitre envoie le nom du cas a tous les processeurs
346 // car avec une distribution MPICH 1.2.7 (Debian)
347 // la ligne de commande recuperee avec argv ne contient
348 // pas le nom du jeu de donnees pour les processeurs autres
349 // que le processeur maitre
350 Nom tmp = nom_du_cas;
351 envoyer(tmp, 0, -1, 0);
352 recevoir(tmp, 0, -1, 0);
354
355 // ******************* Journal ***************************
356 // Initialisation du journal parallele (maintenant qu'on connait le rang
357 // du processeur et le nom du cas)
358 {
359 // Master process creates log directory if needed
360 if (Process::je_suis_maitre() && log_directory_!="")
361 {
362 Nom mkdir_command("mkdir -p ");
363 mkdir_command += log_directory_;
364 if(system(mkdir_command))
365 {
366 Cerr << "Error while creating directory: " << log_directory_ << "\n";
368 }
369 }
370 Process::barrier(); // Otherwise, non-master processes try to write .log file before mkdir is done
371 Nom filename = log_directory_ + nom_du_cas;
372 if (Process::nproc() > 1)
373 {
374 filename += "_";
375 char s[20];
376 snprintf(s, 20, "%05d", (int)Process::me());
377 filename += s;
378 }
379 filename += ".log";
380 // Si journal_master_, seul le process maitre ecrit dans le journal:
381 if (journal_master_ && !Process::je_suis_maitre())
382 verbose_level_ = 0;
383
384 // Si un journal unique n'est pas active, alors desactive les journaux logs au dela d'un certain nombre de rangs MPI:
385 // Dans le cas ou l'option "-journal" est specifiee
386 if (verbose_level_ < 0)
387 {
388 if (!journal_master_ && Process::force_single_file(Process::nproc(), nom_du_cas+".log"))
389 verbose_level_ = 0;
390 else
391 verbose_level_ = 1;
392 }
393
394 init_journal_file(verbose_level_,filename, 0 /* append=0 */);
395 Process::Journal() << "Journal logging started" << finl;
396 }
397
398#ifdef TRUST_USE_GPU
399 // PL: It will be better to do it sooner (near Cuda init or Kokkos init) but need stat and journal initialized
400 // Soon obsolete:
401 init_device();
402 self_test();
403#endif
404
405 Nom nomfic( nom_du_cas );
406 nomfic += ".stop";
407 if (!get_disable_stop() && Process::je_suis_maitre())
408 {
409 SFichier ficstop( nomfic );
410 ficstop << "Running..."<<finl;
411 }
412
413 //---------------------------------------------//
414 // Chargement des modules : //
415 // on ne les charges que pour le cas nul, pour verifier avec valgrind
416 if (Objet_U::nom_du_cas()=="nul")
417 {
418 Cerr<<"Chargement des modules:"<<finl;
419#include <instancie_appel_c.h>
420 Cerr<<"Fin chargement des modules "<<finl;
421 }
422
423 // initializing communicators on node
425 init_node_mpi(node_group_);
426 PE_Groups::initialize_node(node_group_);
427
428 // Node_master needs node_group to be initialized first
430 init_node_masters(node_master_);
432
433 Cout<< " " << finl;
434 Cout<< " * * * * * * * * * * * * * * * * * * * * * * * * * * * * " << finl;
435 Cout<< " * _________ _______ _______ _________ * " << finl;
436 Cout<< " * \\__ __/ ( ____ ) |\\ /| ( ____ \\ \\__ __/ * " << finl;
437 Cout<< " * ) ( | ( )| | ) ( | | ( \\/ ) ( * " << finl;
438 Cout<< " * | | | (____)| | | | | | (_____ | | * " << finl;
439 Cout<< " * | | | __) | | | | (_____ ) | | * " << finl;
440 Cout<< " * | | | (\\ ( | | | | ) | | | * " << finl;
441 Cout<< " * | | | ) \\ \\__ | (___) | /\\____) | | | * " << finl;
442 Cout<< " * )_( |/ \\__/ (_______) \\_______) )_( * " << finl;
443 Cout<< " * * " << finl;
444 Cout<< " * version : " << TRUST_VERSION << " * " << finl;
445 Cout<< " * * " << finl;
446#ifdef BALTIK_VERSION
447 Cout<< " * Using " << BALTIK_NAME << " version : " << BALTIK_VERSION << " *" << finl;
448#endif
449 Cout<< " * * " << finl;
450 Cout<< " * CEA - DES * " << finl;
451 Cout<< " * * " << finl;
452 Cout<< " * * * * * * * * * * * * * * * * * * * * * * * * * * * * " << finl;
453 Cout<< " " << finl;
454
455 info_atelier(Cout);
456 Cout<<" " << finl;
457 Cout<<" Vous traitez le cas " << Objet_U::nom_du_cas() << "\n";
458 Cout<<" " << finl;
459
460 // GF on ecrit la hierarchie que si on a un erreur
461 //---------------------------------------------//
462 Cerr<<"Debut de l'execution " << finl;
463 {
464 Nom nomentree = nom_du_cas;
465 nomentree+=".data";
466 /*
467 #ifndef NDEBUG
468 if (Process::je_suis_maitre())
469 {
470 SFichier es("convert_jdd");
471 }
472 #endif */
473 // La verfication est faite maintenant dans LecFicDiffuse_JDD
474 // mias je garde les lignes au cas ou
475 if (0)
476 {
477 Cerr << "MAIN: Checking data file for matching { and }" << finl;
478 {
479 LecFicDiffuse_JDD verifie_entree(nomentree, ios::in);
480 interprete_principal_.interpreter_bloc(verifie_entree,
481 Interprete_bloc::FIN /* on attend FIN a la fin */,
482 1 /* verifie_sans_interpreter */);
483 }
484 }
485 Cerr << "MAIN: Reading and executing data file" << finl;
486 {
487 LecFicDiffuse_JDD lit_entree(nomentree, ios::in);
488 lit_entree.set_check_types(1);
489 interprete_principal_.interpreter_bloc(lit_entree,
490 Interprete_bloc::FIN /* on attend FIN a la fin */,
491 0 /* interprete pour de vrai */);
492 }
493 }
494
495 Cerr << "MAIN: End of data file" << finl;
497
498 statistics().print_TU_files("Post-resolution statistics");
499
500 double temps = statistics().get_computation_time();
501 Cout << finl;
502 Cout << "--------------------------------------------" << finl;
503 Cout << "clock: Total execution: " << temps << " s" << finl;
504 if (!get_disable_stop() && Process::je_suis_maitre())
505 {
506 SFichier ficstop ( nomfic);
507 ficstop << "Finished correctly"<<finl;
508 }
509}
510
512{
513 // On peut arreter le journal apres les communications:
514 // EDIT 12/02/2020: journal needs communication to be turned on if it's written in HDF5 format
515 Process::Journal() << "End of Journal logging" << finl;
516 end_journal(verbose_level_);
517 // Destruction de l'interprete principal avant d'arreter le parallele
518 interprete_principal_.vide();
519 // PetscFinalize/MPI_Finalize
520 finalize();
521 // on peut arreter maintenant que l'on a arrete les journaux
523 groupe_trio_.detach();
524 node_group_.detach();
525
526}
: Classe Comm_Group_MPI, derivee de la classe abstraite Comm_Group.
: Cette classe decrit un groupe de processeurs sur lesquels
Definition Comm_Group.h:40
static void set_check_enabled(int flag)
void init_group_trio(int nproc, int rank)
Initialise le groupe_TRUST().
Cette classe implemente les operateurs et les methodes virtuelles de la classe EFichier de la facon s...
static bool apply_verif
! whether obsolete keywords should be checked or not. True by default.
void set_check_types(bool flag) override
appelle get_entree_master().
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
static const Nom & nom_du_cas()
Renvoie une reference constante vers le nom du cas.
Definition Objet_U.cpp:146
static Nom & get_set_nom_du_cas()
Renvoie une reference non constante vers le nom du cas (pour pouvoir le modifier).
Definition Objet_U.cpp:156
static void initialize_node_master(const Comm_Group &ngrp)
Methode a appeler apres l'initialisation de trio_u_world et de node_group et l'initialisation des com...
static void finalize()
Methode a appeler en fin d'execution, une fois qu'on est revenu dans le groupe_TRUST() et juste avant...
static void initialize(const Comm_Group &groupe_trio_u)
Methode a appeler au debut de l'execution (MAIN.
static void initialize_node(const Comm_Group &ngrp)
Methode a appeler apres l'initialisation de trio_u_world et l'initialisation des compteurs statistiqu...
static const Comm_Group & get_user_defined_group()
Renvoie une reference au groupe sur defini par l'utilisateur.
static bool has_user_defined_group()
static const Comm_Group & current_group()
renvoie une reference au groupe de processeurs actif courant
Definition PE_Groups.h:65
static bool is_parallel()
Definition Process.cpp:110
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
static void imprimer_ram_totale(int all_process=0)
Definition Process.cpp:651
static void barrier()
Synchronise tous les processeurs du groupe courant (attend que tous les processeurs soient arrives a ...
Definition Process.cpp:136
static bool force_single_file(const int ranks, const Nom &filename)
Definition Process.cpp:60
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
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
Definition Process.cpp:86
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
static void Clear_all()
Definition TClearable.h:43
void finalize()
Definition mon_main.cpp:280
void dowork(const Nom &nom_du_cas)
Definition mon_main.cpp:343
mon_main(int verbose_level=9, bool journal_master=false, Nom log_directory="", bool apply_verification=true, bool disable_stop=false)
Definition mon_main.cpp:70
void init_parallel(const int argc, char **argv, bool with_mpi, bool check_enabled=false, bool with_petsc=true)
Definition mon_main.cpp:198