TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Decouper.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#include <Decouper.h>
16#include <Domaine.h>
17#include <DomaineCutter.h>
18#include <Format_Post_Lata.h>
19#include <EChaine.h>
20#include <SFichier.h>
21#include <Param.h>
22#include <communications.h>
23#include <Synonyme_info.h>
24#include <vector>
25#include <set>
26
27Implemente_instanciable_32_64(Decouper_32_64,"Decouper",Interprete);
28Add_synonym(Decouper, "Partition");
29Add_synonym(Decouper_64, "Partition_64");
30
31template <typename _SIZE_>
33{
35 return os;
36}
37
38template <typename _SIZE_>
40{
42 return is;
43}
44
45/*! @brief Read the partitioner from the data set (reads the type and the parameters and initializes d_part).
46 */
47template <typename _SIZE_>
48void Decouper_32_64<_SIZE_>::lire_partitionneur(Entree& is)
49{
50 Nom n;
51 is >> n;
52 Nom type_partitionneur("Partitionneur_");
53 type_partitionneur += n;
54 Cerr << " Creation of a partitioner of type: " << type_partitionneur << finl;
55 deriv_partitionneur_.typer(type_partitionneur);
56 // In case of failure (if the type name is invalid): exit
57 if (!deriv_partitionneur_)
59
60 // Initialization of the partitioner parameters
61 Partitionneur_base_32_64<_SIZE_>& part = deriv_partitionneur_.valeur();
62 part.associer_domaine(this->domaine());
63 is >> part;
64}
65
66template <typename _SIZE_>
67void Decouper_32_64<_SIZE_>::ecrire_fichier_decoupage() const
68{
69 Cerr << "Writing of the splitting array at the format IntVect ascii\n"
70 << " in the file " << nom_fichier_decoupage_
71 << "\n(for each element, number of the destination processor)" << finl;
72 SFichier file; // ASCII file
73 if (! file.ouvrir(nom_fichier_decoupage_))
74 {
75 Cerr << " Error in the opening of the file." << finl;
77 }
78 file << elem_part_;
79 file << nb_parts_tot_;
80}
81
82template <typename _SIZE_>
83void Decouper_32_64<_SIZE_>::ecrire_fichier_decoupage_som() const
84{
85 Cerr << "Writing of the splitting array at the format IntVect ascii\n"
86 << " in the file " << nom_fichier_decoupage_sommets_
87 << "\n(for each node, list of the destination processors)" << finl;
88 SFichier file; // ASCII file
89 if (! file.ouvrir(nom_fichier_decoupage_sommets_))
90 Process::exit(" Error in the opening of the file.");
91
92 const Domaine_t& domaine = this->domaine();
93 const IntTab_t& elems = domaine.les_elems();
94 int nbOfNodesPerElems = elems.dimension_int(1);
95 int_t nbSom = domaine.nb_som();
96 std::vector<std::set<int_t>> node_part(nbSom);
97 for(int i=0; i<elem_part_.size(); i++)
98 {
99 for (int j = 0; j < nbOfNodesPerElems; j++)
100 {
101 int_t node = elems(i, j);
102 node_part[node].insert(elem_part_[i]);
103 }
104 }
105 file << domaine.nb_som() << finl;
106 for(int_t i=0; i<nbSom; i++)
107 {
108 file << i << " " << node_part[i].size() << " ";
109 for(const auto& set_elem: node_part[i])
110 file << set_elem << " ";
111 file << finl;
112 }
113}
114
115template <typename _SIZE_>
116void Decouper_32_64<_SIZE_>::postraiter_decoupage(const Nom& nom_fichier) const
117{
118 if (!std::is_same<_SIZE_,int>::value)
119 Process::exit("Postprocessing of partitioning is not yet implemented for big (64b) domains!");
120
121 const Domaine& domaine = reinterpret_cast<const Domaine&>(this->domaine());
122 // Check and strip ".lata" :
123 Nom basename;
124 if (nom_fichier.finit_par(".lata"))
125 {
126 basename = nom_fichier;
127 basename.prefix(".lata");
128 }
129 else if (nom_fichier.finit_par(".med"))
130 {
131 basename = nom_fichier;
132 basename.prefix(".med");
133 }
134 else
135 Process::exit("Decouper: postraiter_decoupage(): the file name for postprocessing the domain should end with extension '.lata' or '.med' !!");
136
137 // Compute dummy field indicating partitioning:
138 if (!std::is_same<_SIZE_,int>::value)
139 {
140 // FOR DEVELOPPERS : remove cast to int below if you are porting this for 64b!
141 Cerr << "did you remove cast?" << finl;
142 Process::exit(-1);
143 }
144 const int n = (int)elem_part_.size_reelle();
145
146 DoubleTab data(n);
147 for (int i = 0; i < n; i++)
148 data(i) = static_cast<double>(elem_part_[i]);
149
150 Noms units, noms_compo;
151 units.add("");
152 noms_compo.add("I");
153 constexpr int IS_FIRST = 1;
154
155 if (nom_fichier.finit_par(".lata"))
156 {
157 Cerr << "Postprocessing of the splitting at the lata (V2) format: " << nom_fichier << finl;
158 Format_Post_Lata post;
159
161 post.ecrire_entete(0.0, 0, IS_FIRST);
162 post.ecrire_domaine(domaine, IS_FIRST);
163 post.ecrire_temps(0.0);
164 post.ecrire_champ(domaine,
165 units,
166 noms_compo,
167 1, // ncomp,
168 0.0, //time,
169 "partition", // field_id,
170 domaine.le_nom(), // domain_id
171 "ELEM", // localisation,
172 "scalar", //nature,
173 data // values
174 );
175 post.finir(1);
176 }
177 else if (nom_fichier.finit_par(".med"))
178 {
179 Cerr << "Postprocessing of the splitting at the MED format: " << nom_fichier << finl;
180 OWN_PTR(Format_Post_base) post;
181 post.typer("Format_Post_Med");
182 Nom filename(nom_fichier.getPrefix(".med"));
183 post->initialize(filename, 1, "SIMPLE");
184 post->ecrire_entete(0.0, 0, IS_FIRST);
185 post->ecrire_domaine(domaine, IS_FIRST);
186 post->ecrire_temps(0.0);
187 post->ecrire_champ(domaine,
188 units,
189 noms_compo,
190 -1, // ncomp,
191 0.0, //time,
192 "partition", // field_id,
193 "domain", // domain_id
194 "ELEM", // localisation,
195 "scalar", //nature,
196 data // values
197 );
198 post->finir(1);
199 }
200}
201
202template <typename _SIZE_>
203void Decouper_32_64<_SIZE_>::ecrire_sous_domaines(const int nb_parties, const Static_Int_Lists_t* som_raccord) const
204{
206 cutter.initialiser(this->domaine(), elem_part_, nb_parties, epaisseur_joint_);
207 // Provisional thought:
208 // Joints are built in ecrire_domaines -> construire_sous_domaine
209 // Therefore after renumbering of PEs and hence of elem_part_, one would need
210 // to re-initialize? Or renumber everything after computing the joints...
211 // The latter seems better...
212 cutter.ecrire_domaines(nom_domaines_decoup_, format_, reorder_, som_raccord);
213}
214
216#if INT_is_64_ == 2
218#endif
219
220// XD partition interprete decouper INHERITS_BRACE Class for parallel calculation to cut a domain for each processor. By
221// XD_CONT default, this keyword is commented in the reference test cases.
222// XD attr domaine ref_domaine domaine REQ Name of the domain to be cut.
223// XD attr bloc_decouper bloc_decouper bloc_decouper REQ Description how to cut a domain.
224// XD bloc_decouper objet_lecture nul BRACE Auxiliary class to cut a domain.
225// XD attr partitionneur|Partition_tool partitionneur_deriv partitionneur OPT Defines the partitionning algorithm (the
226// XD_CONT effective C++ object used is \'Partitionneur_ALGORITHM_NAME\').
227// XD attr larg_joint entier larg_joint OPT This keyword specifies the thickness of the virtual ghost domaine (data
228// XD_CONT known by one processor though not owned by it). The default value is 1 and is generally correct for all
229// XD_CONT algorithms except the QUICK convection scheme that require a thickness of 2. Since the 1.5.5 version, the VEF
230// XD_CONT discretization imply also a thickness of 2 (except VEF P0). Any non-zero positive value can be used, but the
231// XD_CONT amount of data to store and exchange between processors grows quickly with the thickness.
232// XD attr nom_zones chaine zones_name OPT Name of the files containing the different partition of the domain. The files
233// XD_CONT will be : NL2 name_0001.Zones NL2 name_0002.Zones NL2 ... NL2 name_000n.Zones. If this keyword is not
234// XD_CONT specified, the geometry is not written on disk (you might just want to generate a \'ecrire_decoupage\' or
235// XD_CONT \'ecrire_lata\').
236// XD attr ecrire_decoupage chaine ecrire_decoupage OPT After having called the partitionning algorithm, the resulting
237// XD_CONT partition is written on disk in the specified filename. See also partitionneur Fichier_Decoupage. This
238// XD_CONT keyword is useful to change the partition numbers: first, you write the partition into a file with the option
239// XD_CONT ecrire_decoupage. This file contains the domaine number for each element\'s mesh. Then you can easily permute
240// XD_CONT domaine numbers in this file. Then read the new partition to create the .Zones files with the
241// XD_CONT Fichier_Decoupage keyword.
242// XD attr ecrire_lata chaine ecrire_lata OPT Save the partition field in a LATA format file for visualization
243// XD attr ecrire_med chaine ecrire_med OPT Save the partition field in a MED format file for visualization
244// XD attr nb_parts_tot entier nb_parts_tot OPT Keyword to generates N .Domaine files, instead of the default number M
245// XD_CONT obtained after the partitionning algorithm. N must be greater or equal to M. This option might be used to
246// XD_CONT perform coupled parallel computations. Supplemental empty domaines from M to N-1 are created. This keyword is
247// XD_CONT used when you want to run a parallel calculation on several domains with for example, 2 processors on a first
248// XD_CONT domain and 10 on the second domain because the first domain is very small compare to second one. You will
249// XD_CONT write Nb_parts 2 and Nb_parts_tot 10 for the first domain and Nb_parts 10 for the second domain.
250// XD attr reorder entier reorder OPT If this option is set to 1 (0 by default), the partition is renumbered in order
251// XD_CONT that the processes which communicate the most are nearer on the network. This may slighlty improves parallel
252// XD_CONT performance.
253// XD attr single_hdf rien single_hdf OPT Optional keyword to enable you to write the partitioned domaines in a single
254// XD_CONT file in hdf5 format.
255// XD attr print_more_infos entier print_more_infos OPT If this option is set to 1 (0 by default), print infos about
256// XD_CONT number of remote elements (ghosts) and additional infos about the quality of partitionning. Warning, it slows
257// XD_CONT down the cutting operations.
258template <typename _SIZE_>
260{
261 Cerr << "Decouper: Splitting of a domain" << finl;
262 // Reading parameters
263 lire(is);
264
265 // Generating partition
266 Partitionneur_base_t& partitionneur = deriv_partitionneur_.valeur();
268
269 // Writing out various files (including .zones)
270 ecrire();
271
272 Cerr << "End of the interpreter Decouper" << finl;
273 return is;
274}
275
276template <typename _SIZE_>
278{
279 // Reading the name of the domain to split:
280 is >> nom_domaine_;
281 Cerr << " Domain name to split : " << nom_domaine_ << finl;
283 // Before splitting, print some info
284 const auto& dom = this->domaine();
285 dom.imprimer();
286
287 Noms liste_bords_perio;
288
289 Param param(this->que_suis_je());
290 bool hdf = false;
291 param.ajouter_non_std("partitionneur|partition_tool",(this),Param::REQUIRED);
292 param.ajouter("larg_joint",&epaisseur_joint_);
293 param.ajouter_condition("value_of_larg_joint_ge_1","The joint thickness must greater or equal to 1.");
294 param.ajouter("nom_zones|zones_name",&nom_domaines_decoup_);
295 param.ajouter("ecrire_decoupage",&nom_fichier_decoupage_);
296 param.ajouter("ecrire_decoupage_sommets",&nom_fichier_decoupage_sommets_);
297 param.ajouter("ecrire_lata",&nom_fichier_lata_);
298 param.ajouter("ecrire_med",&nom_fichier_med_);
299 param.ajouter("nb_parts_tot",&nb_parts_tot_);
300 param.ajouter("reorder",&reorder_);
301 param.ajouter_flag("single_hdf",&hdf);
302 param.ajouter("periodique",&liste_bords_perio); // should not be used anymore ... keeping it to have a nice error message.
303 param.ajouter("print_more_infos",&print_more_infos_);
305
306 // TRUST 1.9.8, attribute 'periodique' is now deprecated:
307 if (liste_bords_perio.size() > 0)
308 {
309 Cerr << finl << "ERROR: Option 'periodique' in Decouper/Partition keyword is now obsolete! It must be removed." << finl;
310 Cerr << "Your periodic boundaries in the domain now only needs to be declared once using the 'Declarer_bord_perio|Corriger_frontiere_periodique' keyword." << finl << finl;
312 }
313
314 if (hdf) format_ = DomainesFileOutputType::HDF5_SINGLE;
315
316 return is;
317}
318
319template <typename _SIZE_>
321{
322 // Compute the number of parts generated by the partitioner
323 int nb_parties = 0;
324 if (elem_part_.size_array() > 0)
325 nb_parties = static_cast<int>(max_array(elem_part_)) + 1; // cast to int, because max among number of procs (or numb of parts)
326 nb_parties = Process::mp_max(nb_parties);
327 Cerr << "The partitioner has generated " << nb_parties << " parts." << finl;
328
329 // Take into account the nb_parts_tot_ directive
330 if (nb_parts_tot_ >= 0)
331 {
332 if (nb_parties > nb_parts_tot_)
333 {
334 Cerr << "Error: nb_parts_tot_ is less than the number of parts generated by the partitioner."
335 << finl;
337 }
338 Cerr << "Number of parts requested : " << nb_parts_tot_ << finl
339 << "Generation of " << nb_parts_tot_ - nb_parties << " empty parts." << finl;
340 nb_parties = nb_parts_tot_;
341 }
342 // Force a single .Zones file beyond a certain number of MPI ranks:
343 if (Process::force_single_file(nb_parties, nom_domaines_decoup_+".Zones"))
344 format_ = DomainesFileOutputType::HDF5_SINGLE;
345
346 if (nom_fichier_decoupage_ != "?")
347 ecrire_fichier_decoupage();
348
350 ecrire_fichier_decoupage_som();
351
352 if (nom_domaines_decoup_ != "?")
353 ecrire_sous_domaines(nb_parties, som_raccord);
354
355 if (nom_fichier_lata_ != "?")
356 postraiter_decoupage(nom_fichier_lata_);
357 if (nom_fichier_med_ != "?")
358 postraiter_decoupage(nom_fichier_med_);
359
360 Cout << finl << "Quality of partitioning --------------------------------------------" << finl;
361 trustIdType total_elem = Process::mp_sum(elem_part_.size_reelle());
362 Cout << "\nTotal number of elements = " << total_elem << finl;
363 Cout << "Number of Domaines : " << nb_parties << finl;
364
366 {
367 DoubleVect A(nb_parties);
368 A = 0;
369 for (int i = 0; i < elem_part_.size_reelle(); i++)
370 A(elem_part_[i]) = static_cast<double>(A(elem_part_[i])) + 1;
371
373 {
374 for(int proc=1; proc<Process::nproc(); proc++)
375 {
376 DoubleVect tmp(nb_parties);
377 tmp = 0;
378 recevoir(tmp, proc, 0, proc+2005);
379
380 for(int i_part=0; i_part<nb_parties; i_part++)
381 A(i_part) += tmp(i_part);
382 }
383
384 double mean_element_domaine = static_cast<double>(total_elem/nb_parties);
385 if (mean_element_domaine>0)
386 {
387 double load_imbalance = double(local_max_vect(A) / mean_element_domaine);
388 Cout << "Number of cells per Domaine (min/mean/max) : " << local_min_vect(A) << " / " << mean_element_domaine << " / "
389 << local_max_vect(A) << " Load imbalance: " << load_imbalance << "\n" << finl;
390 }
391 }
392 else
393 envoyer(A, Process::me(), 0, Process::me()+2005);
394
395 // we could do it as below, but if nb_parties is big, it would involve a lot of collective communication
396 // for (int i = 0; i < nb_parties; i++)
397 // A[i] = Process::mp_sum(A[i]);
398 }
399
400 Cerr << "End of the interpreter Decouper" << finl;
401 if (reorder_==0 && nb_parties>128)
402 {
403 Cerr << "Performance tip: You could add \"reorder 1\" option to have less distance between communicating processes on the network." << finl;
404 Cerr << "Add also \"Ecrire_lata filename.lata\" to post-process the partition numeration and see the difference." << finl;
405 }
406}
407
408template <typename _SIZE_>
410{
411 //Motcle motlu;
412 if (mot=="partitionneur|partition_tool")
413 {
414 Cerr << "domaine = " << nom_domaine_ << finl;
415 lire_partitionneur(is);
416 return 1;
417 }
418 return -1;
419}
420
421template class Decouper_32_64<int>;
422#if INT_is_64_ == 2
423template class Decouper_32_64<trustIdType>;
424#endif
Interprete Decouper.
Definition Decouper.h:36
void ecrire(const Static_Int_Lists_t *som_raccord=nullptr)
Definition Decouper.cpp:320
static int print_more_infos_
Definition Decouper.h:60
BigIntVect_t elem_part_
Definition Decouper.h:67
Entree & lire(Entree &is)
Definition Decouper.cpp:277
Partitionneur_base_32_64< _SIZE_ > Partitionneur_base_t
Definition Decouper.h:47
Nom nom_fichier_lata_
Definition Decouper.h:75
Nom nom_domaines_decoup_
Definition Decouper.h:72
Nom nom_fichier_decoupage_
Definition Decouper.h:73
Nom nom_fichier_med_
Definition Decouper.h:76
int nb_parts_tot_
Definition Decouper.h:65
Entree & interpreter(Entree &is) override
Definition Decouper.cpp:259
Static_Int_Lists_32_64< _SIZE_ > Static_Int_Lists_t
Definition Decouper.h:48
DomainesFileOutputType format_
Definition Decouper.h:77
Nom nom_fichier_decoupage_sommets_
Definition Decouper.h:74
int lire_motcle_non_standard(const Motcle &, Entree &) override
Reads non-simple-type parameters of an Objet_U from an input stream.
Definition Decouper.cpp:409
int epaisseur_joint_
Definition Decouper.h:71
Tool class to generate sub-domains for a parallel computation from a starting domain (domaine_global)...
void ecrire_domaines(const Nom &basename, const DomainesFileOutputType format, const int reorder, const Static_Int_Lists_t *som_raccord=nullptr)
Generation of all sub-domains of the computation and writing to disk of the files basename_000n.
void initialiser(const Domaine_t &domaine_global, const BigIntVect_t &elem_part, const int nb_parts, const int epaisseur_joint, const bool permissif=false)
Prepares the data structures for building sub-domains based on a partitioning provided in elem_part.
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
: Post-processing class for Eulerian fields in LATA format.
int ecrire_entete(const double temps_courant, const int reprise, const int est_le_premier_post) override
Opens the master file in ERASE mode and writes the lata file header (on the master processor only).
virtual int initialize_lata(const Nom &file_basename, const Format format=ASCII, const Options_Para options_para=SINGLE_FILE)
Initializes the class, opens the file and writes the header.
@ BINAIRE
@ SINGLE_FILE
int ecrire_domaine(const Domaine &domaine, const int est_le_premier_post) override
See Format_Post_base::ecrire_domaine. Writing a domain within a time step is accepted,...
int ecrire_temps(const double temps) override
Starts writing a new time step. For the LATA format specifically:
int ecrire_champ(const Domaine &domaine, const Noms &unite_, const Noms &noms_compo, int ncomp, double temps_, const Nom &id_du_champ, const Nom &id_du_domaine, const Nom &localisation, const Nom &nature, const DoubleTab &data) override
voir Format_Post_base::ecrire_champ
int finir(const int est_le_dernier_post) override
int initialize(const Nom &file_basename, const int format, const Nom &option_para) override
Base class for post-processing output formats for fields (lata, med, cgns, lml, single_lata).
Base class for "interpreter" objects.
Definition Interprete.h:38
A character string (Nom) in uppercase.
Definition Motcle.h:26
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
An array of character strings (VECT(Nom)).
Definition Noms.h:26
friend class Entree
Definition Objet_U.h:71
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter_flag(const char *keyword, const bool *value)
Register a boolean flag whose mere presence switches it to true.
Definition Param.cpp:474
void ajouter_condition(const char *condition, const char *message, const char *name=0)
Declare a post-read logical condition that must hold on the parameter values.
Definition Param.cpp:496
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
@ REQUIRED
Definition Param.h:115
void ajouter_non_std(const char *keyword, const Objet_U *value, Param::Nature nat=Param::OPTIONAL)
Register a keyword handled by Objet_U::lire_motcle_non_standard.
Definition Param.cpp:489
int lire_avec_accolades_depuis(Entree &is)
Parse the parameter block { ... } from is.
Definition Param.cpp:32
Base class for domain partitioners (for splitting a mesh before a parallel computation).
virtual void associer_domaine(const Domaine_t &domaine)=0
virtual void construire_partition(BigIntVect_ &elem_part, int &nb_parts_tot) const =0
static double mp_max(double)
Definition Process.cpp:379
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 double mp_sum(double)
Computes the sum of x over all processors in the current group.
Definition Process.cpp:145
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
virtual int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::out)
Base class for output streams.
Definition Sortie.h:52