TrioCFD 1.9.9_beta
TrioCFD documentation
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> // For chdir for other compilers
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 // Call PetscFinalize only if necessary
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 // Create a temporary journal that writes to 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 // Initialize Petsc
94#ifdef MPI_INIT_NEEDS_MPIRUN
95 int flag;
96 MPI_Initialized(&flag);
97 // if MPI is initialised or if 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 // Quirk observed on one machine (ioulia, native MPICH): PetscInitialize changes pwd()
112 // in sequential mode and, if the binary is not in the study directory, the pwd is lost...
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 to -abort_on_error (no PETSc error is tolerated):
124 PetscPushErrorHandler(PetscAbortErrorHandler, PETSC_NULLPTR);
125 // Disable the signal handler in optimised mode to avoid too much verbosity
126 // and to avoid "masking" TRUST error messages:
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 for machines where Petsc is not installed
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// From now on, Petsc/MPI_Initialize and Petsc/MPI_Finalize
195// are in a single file: mon_main.
196// They must not appear anywhere else!
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; // Already done by 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 // ***************** Parallel initialisation *************************
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 of the communication groups.
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 it is done only once (necessary with ICoCo).
260 // It is initialised later because it involves communication operations, which require statistics to be initialised 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 // Call PetscFinalize only if necessary
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 // Call MPI_Finalize if 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 // The master processor broadcasts the case name to all processors,
346 // because with MPICH 1.2.7 (Debian) the command line retrieved via argv
347 // does not contain the dataset name on processors other than the master
348 Nom tmp = nom_du_cas;
349 envoyer(tmp, 0, -1, 0);
350 recevoir(tmp, 0, -1, 0);
352
353 // ******************* Journal ***************************
354 // Initialisation of the parallel journal (now that the processor rank
355 // and the case name are known)
356 {
357 // Master process creates log directory if needed
358 if (Process::je_suis_maitre() && log_directory_!="")
359 {
360 Nom mkdir_command("mkdir -p ");
361 mkdir_command += log_directory_;
362 if(system(mkdir_command))
363 {
364 Cerr << "Error while creating directory: " << log_directory_ << "\n";
366 }
367 }
368 Process::barrier(); // Otherwise, non-master processes try to write .log file before mkdir is done
369 Nom filename = log_directory_ + nom_du_cas;
370 if (Process::nproc() > 1)
371 {
372 filename += "_";
373 char s[20];
374 snprintf(s, 20, "%05d", (int)Process::me());
375 filename += s;
376 }
377 filename += ".log";
378 // If journal_master_ is set, only the master process writes to the journal:
379 if (journal_master_ && !Process::je_suis_maitre())
380 verbose_level_ = 0;
381
382 // If a single journal is not enabled, disable individual logs beyond a certain number of MPI ranks.
383 // Applied when the "-journal" option is not specified.
384 if (verbose_level_ < 0)
385 {
386 if (!journal_master_ && Process::force_single_file(Process::nproc(), nom_du_cas+".log"))
387 verbose_level_ = 0;
388 else
389 verbose_level_ = 1;
390 }
391
392 init_journal_file(verbose_level_,filename, 0 /* append=0 */);
393 Process::Journal() << "Journal logging started" << finl;
394 }
395
396#ifdef TRUST_USE_GPU
397 // PL: It will be better to do it sooner (near Cuda init or Kokkos init) but need stat and journal initialized
398 // Soon obsolete:
399 init_device();
400 self_test();
401#endif
402
403 Nom nomfic( nom_du_cas );
404 nomfic += ".stop";
405 if (!get_disable_stop() && Process::je_suis_maitre())
406 {
407 SFichier ficstop( nomfic );
408 ficstop << "Running..."<<finl;
409 }
410
411 //---------------------------------------------//
412 // Module loading:
413 // only loaded for the "nul" case, for valgrind verification
414 if (Objet_U::nom_du_cas()=="nul")
415 {
416 Cerr<<"Loading modules:"<<finl;
417#include <instancie_appel_c.h>
418 Cerr<<"Finished loading modules "<<finl;
419 }
420
421 // initializing communicators on node
423 init_node_mpi(node_group_);
424 PE_Groups::initialize_node(node_group_);
425
426 // Node_master needs node_group to be initialized first
428 init_node_masters(node_master_);
430
431 Cout<< " " << finl;
432 Cout<< " * * * * * * * * * * * * * * * * * * * * * * * * * * * * " << finl;
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<< " * version : " << TRUST_VERSION << " * " << finl;
443 Cout<< " * * " << finl;
444#ifdef BALTIK_VERSION
445 Cout<< " * Using " << BALTIK_NAME << " version : " << BALTIK_VERSION << " *" << finl;
446#endif
447 Cout<< " * * " << finl;
448 Cout<< " * CEA - DES * " << finl;
449 Cout<< " * * " << finl;
450 Cout<< " * * * * * * * * * * * * * * * * * * * * * * * * * * * * " << finl;
451 Cout<< " " << finl;
452
453 info_atelier(Cout);
454 Cout<<" " << finl;
455 Cout<<" Processing case: " << Objet_U::nom_du_cas() << "\n";
456 Cout<<" " << finl;
457
458 // GF: the class hierarchy is written only on error
459 //---------------------------------------------//
460 Cerr<<"Beginning execution" << finl;
461 {
462 Nom nomentree = nom_du_cas;
463 nomentree+=".data";
464 /*
465 #ifndef NDEBUG
466 if (Process::je_suis_maitre())
467 {
468 SFichier es("convert_jdd");
469 }
470 #endif */
471 // Verification is now done in LecFicDiffuse_JDD;
472 // keeping these lines just in case
473 if (0)
474 {
475 Cerr << "MAIN: Checking data file for matching { and }" << finl;
476 {
477 LecFicDiffuse_JDD verifie_entree(nomentree, ios::in);
478 interprete_principal_.interpreter_bloc(verifie_entree,
479 Interprete_bloc::FIN /* wait for FIN at the end */,
480 1 /* verifie_sans_interpreter */);
481 }
482 }
483 Cerr << "MAIN: Reading and executing data file" << finl;
484 {
485 LecFicDiffuse_JDD lit_entree(nomentree, ios::in);
486 lit_entree.set_check_types(1);
487 interprete_principal_.interpreter_bloc(lit_entree,
488 Interprete_bloc::FIN /* wait for FIN at the end */,
489 0 /* truly interpret */);
490 }
491 }
492
493 Cerr << "MAIN: End of data file" << finl;
495
496 statistics().print_TU_files("Post-resolution statistics");
497
498 double temps = statistics().get_computation_time();
499 Cout << finl;
500 Cout << "--------------------------------------------" << finl;
501 Cout << "clock: Total execution: " << temps << " s" << finl;
502 if (!get_disable_stop() && Process::je_suis_maitre())
503 {
504 SFichier ficstop ( nomfic);
505 ficstop << "Finished correctly"<<finl;
506 }
507}
508
510{
511 // The journal can be stopped after communications:
512 // EDIT 12/02/2020: journal needs communication to be turned on if it's written in HDF5 format
513 Process::Journal() << "End of Journal logging" << finl;
514 end_journal(verbose_level_);
515 // Destroy the main interpreter before stopping the parallel layer
516 interprete_principal_.vide();
517 // PetscFinalize/MPI_Finalize
518 finalize();
519 // Can now finalize now that journals have been stopped
521 groupe_trio_.detach();
522 node_group_.detach();
523
524}
: Class Comm_Group_MPI, derived from the abstract class Comm_Group.
: This class describes a group of processors on which
Definition Comm_Group.h:37
static void set_check_enabled(int flag)
void init_group_trio(int nproc, int rank)
Initializes groupe_TRUST().
This class implements the operators and virtual methods of the EFichier class as follows: The file to...
static bool apply_verif
! whether obsolete keywords should be checked or not. True by default.
void set_check_types(bool flag) override
Calls get_entree_master().
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
static const Nom & nom_du_cas()
Returns a constant reference to the case name. This method is static.
Definition Objet_U.cpp:145
static Nom & get_set_nom_du_cas()
Returns a non-constant reference to the case name (to allow modification). This method is static.
Definition Objet_U.cpp:154
static void initialize_node_master(const Comm_Group &ngrp)
Method to call after the initialization of trio_u_world, node_group, and TRUST's statistical counters...
static void finalize()
Method to call at the end of execution, once back in groupe_TRUST() and just before destroying the ma...
static void initialize(const Comm_Group &groupe_trio_u)
Method to call at the beginning of execution (MAIN.cpp). Initializes current_group() with groupe_trio...
static void initialize_node(const Comm_Group &ngrp)
Method to call after the initialization of trio_u_world and TRUST's statistical counters.
static const Comm_Group & get_user_defined_group()
Returns a reference to the user-defined group.
static bool has_user_defined_group()
static const Comm_Group & current_group()
Returns a reference to the current active processor group.
Definition PE_Groups.h:64
static bool is_parallel()
Definition Process.cpp:108
static Sortie & Journal(int message_level=0)
Returns a static Sortie object used as an event journal.
Definition Process.cpp:592
static int nproc()
Returns the number of processors in the current group. See Comm_Group::nproc() and PE_Groups::current...
Definition Process.cpp:102
static void imprimer_ram_totale(int all_process=0)
Definition Process.cpp:655
static void barrier()
Synchronizes all processors in the current group (waits until all processors have reached the barrier...
Definition Process.cpp:133
static bool force_single_file(const int ranks, const Nom &filename)
Definition Process.cpp:57
static int me()
Returns the rank of the local processor in the current communication group. See Comm_Group::rank() an...
Definition Process.cpp:122
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
static int je_suis_maitre()
Returns 1 if on the master processor of the current group (i.e. me() == 0), 0 otherwise.
Definition Process.cpp:82
SFichier is to the C++ ofstream class what Sortie is to the C++ ostream class.
Definition SFichier.h:29
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