TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Format_Post_Lata.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 <EcrFicPartageMPIIO.h>
17#include <Format_Post_Lata.h>
18#include <EcrFicPartageBin.h>
19#include <communications.h>
20#include <Fichier_Lata.h>
21#include <EFichier.h>
22#include <sys/stat.h>
23#include <Param.h>
24#include <string> // Required with xlC for std::getline
25
26Implemente_instanciable_sans_constructeur(Format_Post_Lata,"Format_Post_Lata",Format_Post_base);
27
28#define _LATA_INT_TYPE_ trustIdType
29
30/*! @brief Default constructor: format_ ASCII and options_para_ = SINGLE_FILE.
31 *
32 */
37
38/*! @brief Resets the object to the state obtained by the default constructor.
39 *
40 */
42{
43 lata_basename_ = "??";
44 format_ = ASCII;
46 status = RESET;
48 tinit_ = -1.;
49 temps_courant_ = -1.;
50}
51
52void Format_Post_Lata::resetTime(double t, const std::string dirname)
53{
54 temps_courant_ = -1; // not using t - this will come from outside when calling 'ecrire_temps'
55}
56
58{
59 Process::exit("Format_Post_Lata::printOn : error");
60 return os;
61}
62
63/*! @brief Reads post-processing parameters in "data set" format. The expected format is:
64 *
65 * {
66 * nom_fichier nom required field
67 * [ format ascii|binaire ] default value: ascii
68 * [ parallel single_file|multiple_files ] default value: single_file
69 * }
70 *
71 */
73{
74 assert(status == RESET);
77 return is;
78}
79
81{
82 Cerr << "Format_Post_Lata::set_param: Not implemented." << finl;
84}
85
87{
88 Cerr << "Format_Post_Lata::lire_motcle_non_standard: Not implemented." << finl;
90 return 0;
91}
92
93/*! @brief Returns the conventional extension for lata files: ".lata"
94 *
95 */
97{
98 static const char * ext = ".lata";
99 return ext;
100}
101
102/*! @brief Returns the file name without its path: strips all characters before the last /
103 *
104 */
105const char * Format_Post_Lata::remove_path(const char * filename)
106{
107 int i = (int)strlen(filename);
108 while (i > 0 && filename[i-1] != '/')
109 i--;
110 return filename + i;
111}
112
113/*! @brief Opens the master file in ERASE mode and writes the lata file header (on the master processor only).
114 *
115 * void Format_Post_Lata::ecrire_entete_lata()
116 *
117 */
118int Format_Post_Lata::ecrire_entete(const double temps_courant, const int reprise, const int est_le_premier_post)
119{
121 return 1;
122}
123
124int Format_Post_Lata::completer_post(const Domaine&, const int , const Nature_du_champ&, const int , const Noms&, const Motcle&, const Nom&)
125{
126 return 1;
127}
128
129int Format_Post_Lata::preparer_post(const Nom& , const int , const int , const double )
130{
131 return 1;
132}
133
134namespace
135{
136
137template<typename TYP, typename LATA_TYP>
138void fill_tmp_array(const TRUSTTab<TYP,int>& tab, int upper, int offset, bool decal_fort, trustIdType decalage_partiel, LATA_TYP *tmp);
139
140template<typename TYP>
141typename std::enable_if_t<std::is_same<TYP, int>::value || std::is_same<TYP, trustIdType>::value, void>
142fill_tmp_array(const TRUSTTab<TYP,int>& tab, int upper, int offset, bool decal_fort, trustIdType decalage_partiel, _LATA_INT_TYPE_ *tmp)
143{
144 trustIdType decal_fort_val = decal_fort ? 1 : 0;
145 const TYP *data = tab.addr();
146 for (int i = 0; i < upper; i++)
147 {
148 // value to write (conversion to Fortran numbering if needed)
149 _LATA_INT_TYPE_ x = data[i+offset];
150 if (x > -1)
151 x += decalage_partiel;
152 else
153 x += decal_fort_val;
154 tmp[i] = x;
155 }
156}
157
158template<>
159void fill_tmp_array<double, float>(const TRUSTTab<double,int>& tab, int upper, int offset, bool , trustIdType , float *tmp)
160{
161 const double *data = tab.addr();
162 for (int i = 0; i < upper; i++)
163 tmp[i] = (float) data[i+offset]; // downcast to float
164}
165
166/** Generic method to write the block corresponding to an array of data in a LATA file
167 */
168template<typename TYP, typename LATA_TYP>
169trustIdType write_T_tab(Fichier_Lata& fichier, bool decal_fort, trustIdType decalage_partiel, const TRUSTTab<TYP,int>& tab, int& nb_colonnes, const Format_Post_Lata::Options_Para& option)
170{
171 int nb_lignes = tab.dimension(0);
172 int line_size = 1;
173 const int nb_dim = tab.nb_dim();
174
175 for (int i = 1; i < nb_dim; i++)
176 line_size *= tab.dimension(i);
177
178 trustIdType nb_lignes_tot = 0;
179
180 const int tab_size = line_size * nb_lignes;
181 trustIdType nb_octets = tab_size * (trustIdType) sizeof(LATA_TYP);
182 switch(option)
183 {
186 nb_lignes_tot = Process::mp_sum(nb_lignes);
187 // In parallel, all arrays must have the same number of columns (or be empty).
188 nb_colonnes = Process::mp_max(line_size);
189 nb_octets = nb_colonnes * nb_lignes_tot * (trustIdType) sizeof(LATA_TYP);
190 assert(nb_lignes == 0 || line_size == nb_colonnes);
191 break;
193 nb_lignes_tot = nb_lignes;
194 nb_colonnes = line_size;
195 break;
196 default:
197 Cerr << "Format_Post_Lata_write_tab: error nb_lignes_tot" << finl;
199 }
200
201 SFichier& sfichier = fichier.get_SFichier();
202
203 // Start of Fortran block
204 if (fichier.is_master())
205 sfichier << nb_octets << finl;
206
207 // Writing data.
208 if (sub_type(EcrFicPartageMPIIO, sfichier))
209 {
210 // Convert everything to LATA_TYP
211 LATA_TYP *tmp = new LATA_TYP[tab_size];
212 fill_tmp_array(tab, tab_size, 0, decal_fort, decalage_partiel, tmp);
213 sfichier.put(tmp, tab_size, line_size);
214 delete[] tmp;
215 // End of Fortran block
216 if (fichier.is_master())
217 sfichier << nb_octets << finl;
218 }
219 else
220 {
221 // Convert everything to _INT_TYPE_ in batches of N values
222 // Buffer whose size is a multiple of line_size:
223 const int N = 16384;
224 int bufsize = (N / line_size + 1) * line_size;
225 LATA_TYP *tmp = new LATA_TYP[bufsize];
226 for (int i = 0; i < tab_size; i += bufsize)
227 {
228 int j_max = bufsize;
229 if (j_max > tab_size - i)
230 j_max = tab_size - i;
231
232 // Convert the block to LATA_TYP:
233 fill_tmp_array(tab, j_max, i, decal_fort, decalage_partiel, tmp);
234
235 // Write with a newline at each row of the array
236 sfichier.put(tmp, j_max, line_size);
237 }
238 delete[] tmp;
239 fichier.syncfile();
240 // End of Fortran block
241 if (fichier.is_master())
242 sfichier << nb_octets << finl;
243 fichier.syncfile();
244 }
245 return nb_lignes_tot;
246}
247
248} // end anonymous namespace
249
250
251/*! @brief fichier is a lata data file (not the master file). The array tab is written as-is (in binary or ASCII, on one or
252 *
253 * several files in parallel).
254 * nb_colonnes is filled with the product of tab.dimension(i) for i>0.
255 *
256 */
257trustIdType Format_Post_Lata::write_doubletab(Fichier_Lata& fichier, const DoubleTab& tab, int& nb_colonnes, const Options_Para& option)
258{
259 return ::write_T_tab<double, float>(fichier, 0, 0, tab, nb_colonnes, option);
260}
261
262
263/*! @brief Writing an integer array to the given file.
264 *
265 * The values written are the array values incremented by "decalage". This value is used to switch to Fortran numbering
266 * (add 1), or to switch to global numbering (add the number of elements on previous processors).
267 *
268 * nb_colonnes is filled with the sum of dimension(i) for i>0.
269 * Return value: sum of the written dimension(0) values (depending on whether all processors write to the same file or not).
270 */
271trustIdType Format_Post_Lata::write_inttab(Fichier_Lata& fichier, bool decal_fort, trustIdType decalage_partiel, const IntTab& tab, int& nb_colonnes, const Options_Para& option)
272{
273 return ::write_T_tab<int, _LATA_INT_TYPE_>(fichier, decal_fort, decalage_partiel, tab, nb_colonnes, option);
274}
275
276/*! @brief Initializes the class with default parameters (ASCII format, SINGLE_FILE).
277 *
278 */
280{
281 assert(status == RESET);
282 initialize_lata(file_basename, ASCII, SINGLE_FILE);
283 return 1;
284}
285
286int Format_Post_Lata::initialize(const Nom& file_basename, const int format, const Nom& option_para)
287{
288 assert(status == RESET);
289 // Change the LATA format (default is binary)
291 if (format == 0)
292 format_ = ASCII;
293
294 if (Motcle(option_para) == "MPI-IO")
296 else if (Motcle(option_para) == "SIMPLE")
298 else if (Motcle(option_para) == "MULTIPLE")
300 else
301 {
302 Cerr << "The option " << option_para << " for lata format for the parallel is not correct." << finl;
304 }
305
306 initialize_lata(file_basename, format_, options_para_);
307
308 return 1;
309}
310
311/*! @brief Initializes the class, opens the file and writes the header.
312 *
313 */
314int Format_Post_Lata::initialize_lata(const Nom& file_basename, const Format format, const Options_Para options_para)
315{
316 assert(status == RESET);
317 lata_basename_ = file_basename;
318 format_ = format;
319 options_para_ = options_para;
321 return 1;
322}
323
324/*! @brief Modifying name of the post file, plus some clever management of previously saved data in case of restart.
325 */
326int Format_Post_Lata::modify_file_basename(const Nom file_basename, bool for_restart, const double tinit)
327{
328 Nom post_file;
329 post_file = file_basename + extension_lata();
330 // Check that the master file exists and has a correct header
331 bool master_file_exists = false;
333 {
334 struct stat f;
335 if (stat(post_file, &f) == 0)
336 {
337 EFichier tmp(post_file);
338 Nom cle;
339 tmp >> cle;
340 if (cle.debute_par("LATA"))
341 {
342 if (tinit == -1)
343 master_file_exists = true;
344 else
345 {
346 tmp >> cle;
347 while (!tmp.eof() && cle != "TEMPS")
348 tmp >> cle;
349 if (cle == "TEMPS")
350 {
351 double temps;
352 tmp >> temps;
353 // Check the time of the restart file
354 if (temps < tinit)
355 master_file_exists = true;
356 }
357 }
358 }
359 tmp.close();
360 }
361 }
362
363 // Saving what was there before:
364 master_file_exists = (bool) Process::mp_max((int)master_file_exists);
365 if (Process::je_suis_maitre() && master_file_exists && !restart_already_moved_ && for_restart)
366 {
367 Nom before_restart;
368 before_restart = file_basename + ".before_restart" + extension_lata();
369 rename(post_file, before_restart);
370 Cerr << "File " << post_file << " is moved to " << before_restart << " with times<=tinit=" << tinit << finl;
371 reconstruct(post_file, before_restart, tinit);
372 }
373 if (for_restart)
375
376 Process::barrier(); // really necessary?
377
378 lata_basename_ = file_basename;
379
380 if (master_file_exists && for_restart)
381 {
382 lata_basename_ += ".after_restart";
383 if (tinit == -1)
384 finir_sans_reprise(post_file);
385 }
386 return 1;
387}
388
389// Copy the beginning of the before_restart file into post_file (up to TEMPS=tinit)
390int Format_Post_Lata::reconstruct(const Nom post_file, const Nom before_restart, const double tinit)
391{
392 EFichier LataOld(before_restart);
393 SFichier LataNew(post_file);
394 LataNew.setf(ios::scientific);
395 LataNew.precision(8);
396 std::string line;
397 Nom mot;
398 double temps;
399 tinit_ = tinit;
400 while (!LataOld.eof())
401 {
402 LataOld >> mot; // read the first word of the line in .before_restart.lata
403 if (mot != "FIN") // If the word is not FIN
404 {
405 if (mot == "TEMPS") // If the next word is TEMPS
406 {
407 LataOld >> temps;
408 if (temps == tinit) // If the found time equals tinit then stop
409 break;
410 std::getline(LataOld.get_ifstream(), line); // read the rest of the line
411 LataNew.get_ofstream() << mot << " " << temps << line << std::endl; // write it all to the lata
412 }
413 else
414 {
415 std::getline(LataOld.get_ifstream(), line); // read the rest of the line
416 LataNew.get_ofstream() << mot << line << std::endl; // write it all to the lata
417 }
418 }
419 else
420 {
421 break; // Otherwise stop
422 }
423 }
424 LataNew.close();
425 LataOld.close();
426 Cerr << "File " << post_file << " is rebuilt but truncated to times<tinit=" << tinit << finl;
427 return 1;
428}
429
431{
432 Nom post_file;
433 post_file = lata_basename_ + extension_lata();
435 {
436 struct stat f;
437 if (stat(post_file, &f) == 0) // if file exists
438 {
439 EFichier Lata(file_basename);
440 SFichier LataRep(post_file, ios::app);
441 LataRep.setf(ios::scientific);
442 LataRep.precision(8);
443 std::string line;
444 Nom mot;
445 double temps;
446 while (!Lata.eof())
447 {
448 Lata >> mot; // read the first word of the line in .lata
449 if (mot == "TEMPS") // If the next word is not TEMPS
450 {
451 Lata >> temps;
452 if (temps == tinit_) // If the found time equals tinit
453 {
454 std::getline(Lata.get_ifstream(), line);
455 LataRep.get_ofstream() << mot << " " << temps << line << std::endl; // can start writing
456 break;
457 }
458 }
459 }
460 while (!Lata.eof())
461 {
462 std::getline(Lata.get_ifstream(), line); // read the rest of the .lata
463 LataRep.get_ofstream() << line << std::endl; // write it all to after_restart.lata
464 }
465 Lata.close();
466 LataRep.close();
467 Cerr << "File " << post_file << " is built with times from tinit=" << tinit_ << finl;
468 }
469 }
470 return 1;
471}
472
473/*! Write the "fileoffset=..." when needed in master lata file
474 */
475void Format_Post_Lata::ecrire_offset(SFichier& sfichier, long int offset_single_lata)
476{
478 sfichier << " file_offset=" << offset_single_lata;
479 else
480 {
481#ifdef INT_is_64_
482 // 64b binary file start with the tag "INT64" which is 6 bytes long with the \0 terminating char.
483 // In ASCII this is not needed.
484 if(format_ == BINAIRE)
485 sfichier << " file_offset=6";
486#endif
487 }
488}
489
490// E Saikali : adding this list which is useful for a coupled problem when writing to the same file
491static Noms liste_single_lata_ecrit;
492
493/*! @brief Low level routine to write a mesh into a LATA file.
494 *
495 * Also called directly in TrioCFD, by Postraitement_ft_lata for interface writing.
496 */
497void Format_Post_Lata::ecrire_domaine_low_level(const Nom& id_domaine, const DoubleTab& sommets, const IntTab& elements, const Motcle& type_element)
498{
499 const int dim = sommets.dimension(1);
500 Motcle type_elem(type_element);
501
502 // GF To ensure correct reading with the lata plugin
503 if (type_element == "PRISME") type_elem = "PRISM6";
504
505 trustIdType nb_som_tot, nb_elem_tot; // Number of vertices/elements in the file
506
507 // Build the geometry file name
508 Nom basename_geom(lata_basename_), extension_geom(extension_lata());
509
510 if (un_seul_fichier_lata_) extension_geom += "_single";
511 else
512 {
513 extension_geom += ".";
514 extension_geom += id_domaine;
515 extension_geom += ".";
516 char str_temps[100] = "0.0";
517 if (temps_courant_ >= 0.)
518 snprintf(str_temps, 100, "%.10f", temps_courant_);
519 extension_geom += Nom(str_temps);
520 }
521
522 Nom nom_fichier_geom;
523 trustIdType decalage_sommets = 1, decalage_elements = 1;
524
525 {
526 const bool not_in_list = !liste_single_lata_ecrit.contient_(lata_basename_),
527 should_erase = (!un_seul_fichier_lata_) ? true /* Always erase */ : (offset_elem_ < 0 && not_in_list);
528
529 Fichier_Lata fichier_geom(basename_geom, extension_geom, should_erase ? Fichier_Lata::ERASE : Fichier_Lata::APPEND, format_, options_para_);
530
531 // add to the list if not already in it and if un_seul_fichier_lata_ !!!
532 if (not_in_list && un_seul_fichier_lata_) liste_single_lata_ecrit.add(lata_basename_); // BOOM !
533
534 nom_fichier_geom = fichier_geom.get_filename();
535 int nb_col;
536
538 if (fichier_geom.is_master())
539 offset_som_ = fichier_geom.get_SFichier().get_ofstream().tellp();
540
541 // Vertex coordinates
542 if (axi)
543 {
544 DoubleTab sommets2(sommets);
545 int ns = sommets2.dimension_tot(0);
546 for (int s = 0; s < ns; s++)
547 {
548 double r = sommets(s, 0), theta = sommets(s, 1);
549 sommets2(s, 0) = r * cos(theta);
550 sommets2(s, 1) = r * sin(theta);
551 }
552 nb_som_tot = write_doubletab(fichier_geom, sommets2, nb_col, options_para_);
553 }
554 else
555 nb_som_tot = write_doubletab(fichier_geom, sommets, nb_col, options_para_);
556
557 assert(nb_som_tot == 0 || nb_col == dim);
558
559 // Elements: vertex, element and other indices in the lata file start at 1:
561 {
562 // All processors write to a single file; indices must be renumbered to global numbering.
563 // Processor 0 numbers its vertices from 1 to n0
564 // Processor 1 numbers its vertices from n0+1 to n0+n1, etc...
565 // Offset to add to indices for global numbering.
566 const int nbsom = sommets.dimension(0);
567 decalage_sommets += mppartial_sum(nbsom);
568 const int nbelem = elements.dimension(0);
569 decalage_elements += mppartial_sum(nbelem);
570 }
571
573 {
574 if (fichier_geom.is_master())
575 offset_elem_ = fichier_geom.get_SFichier().get_ofstream().tellp();
576
577 nb_elem_tot = write_inttab(fichier_geom, true, decalage_sommets, elements, nb_col, options_para_);
578 }
579 else
580 {
581 Fichier_Lata fichier_geom_elem(basename_geom, extension_geom + Nom(".elem"), Fichier_Lata::ERASE, format_, options_para_);
582 nb_elem_tot = write_inttab(fichier_geom_elem, true, decalage_sommets, elements, nb_col, options_para_);
583 }
584 }
585
586 {
587 // Note: the file must be closed before calling ecrire_item_int, which will reopen it.
589 SFichier& sfichier = fichier_lata.get_SFichier();
590
591 if (fichier_lata.is_master())
592 {
593 sfichier << "GEOM " << id_domaine;
594 sfichier << " type_elem=" << type_elem << finl;
595
596 // SOMMETS support
597 sfichier << "CHAMP SOMMETS " << remove_path(nom_fichier_geom);
598 sfichier << " geometrie=" << id_domaine;
599 sfichier << " size=" << nb_som_tot;
600 sfichier << " composantes=" << dim;
601 ecrire_offset(sfichier, offset_som_);
602 sfichier << finl;
603
604 // ELEMENTS support
605 sfichier << "CHAMP ELEMENTS " << remove_path(nom_fichier_geom);
606 if (!un_seul_fichier_lata_) sfichier << ".elem";
607 sfichier << " geometrie=" << id_domaine;
608 sfichier << " size=" << nb_elem_tot << " composantes=" << elements.dimension(1);
609
610 ecrire_offset(sfichier, offset_elem_);
611
612
613 switch(sizeof(_LATA_INT_TYPE_))
614 {
615 case 4:
616 sfichier << " format=INT32" << finl;
617 break;
618 case 8:
619 sfichier << " format=INT64" << finl;
620 break;
621 default:
622 Cerr << "Error in Format_Post_Lata::ecrire_entete\n" << " sizeof(int) not supported" << finl;
624 }
625
626 }
627 fichier_lata.syncfile();
628 }
629
630 // In parallel mode, additional files containing parallel data on vertices, elements and faces are written...
633 {
634 TIDTab data(1,2);
635 data(0, 0) = decalage_sommets;
636 data(0, 1) = sommets.dimension(0);
637 ecrire_item_tid("JOINTS_SOMMETS",
638 id_domaine,
639 "", /* id_domaine */
640 "", /* localisation */
641 "", /* reference */
642 data,
643 0); /* reference_size */
644 data(0, 0) = decalage_elements;
645 data(0, 1) = elements.dimension(0);
646 ecrire_item_tid("JOINTS_ELEMENTS",
647 id_domaine,
648 "", /* id_domaine */
649 "", /* localisation */
650 "", /* reference */
651 data,
652 0); /* reference_size */
653 }
654}
655
656/*! @brief See Format_Post_base::ecrire_domaine. Writing a domain within a time step is accepted, but
657 *
658 * all id_domaines must be distinct.
659 * Writes the file "basename(_XXXXX).lata.nom_domaine", which contains the vertex list and element list.
660 * If the PE is master, opens the master file in APPEND mode and adds a reference to this file.
661 */
662int Format_Post_Lata::ecrire_domaine(const Domaine& domaine,const int est_le_premier_post)
663{
664 if (status == RESET)
665 {
666 Cerr << "Error in Format_Post_Lata::ecrire_domaine\n" << " status = RESET. Uninitialized object" << finl;
668 }
669 Motcle type_elem = domaine.type_elem()->que_suis_je();
670
671 ecrire_domaine_low_level(domaine.le_nom(), domaine.les_sommets(), domaine.les_elems(), type_elem);
672
673 // If there are domain boundary sub-domains, write them too
674 const LIST(OBS_PTR(Domaine)) bords= domaine.domaines_frontieres();
675 for (int i=0; i<bords.size(); i++)
676 ecrire_domaine(bords[i].valeur(),est_le_premier_post);
677
678 return 1; // ok all is well
679}
680
681/*! @brief Starts writing a new time step. For the LATA format specifically:
682 *
683 * Opens the master file in APPEND mode and adds a line
684 * "TEMPS xxxxx" if this time has not yet been written.
685 *
686 */
687int Format_Post_Lata::ecrire_temps(const double temps)
688{
690 return 1;
691}
692
693/*! @brief voir Format_Post_base::ecrire_champ
694 *
695 */
696int Format_Post_Lata::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,
697 const Nom& localisation, const Nom& nature, const DoubleTab& valeurs)
698{
699 Motcle id_du_champ_modifie(id_du_champ), iddomaine(id_du_domaine);
700
701 //Using prefix with an uppercase argument
702 if ((Motcle) localisation == "SOM")
703 {
704 id_du_champ_modifie.prefix(id_du_domaine);
705 id_du_champ_modifie.prefix(iddomaine);
706 id_du_champ_modifie.prefix("_SOM_");
707 }
708 else if ((Motcle) localisation == "ELEM")
709 {
710 id_du_champ_modifie.prefix(id_du_domaine);
711 id_du_champ_modifie.prefix(iddomaine);
712 id_du_champ_modifie.prefix("_ELEM_");
713 }
714 else if ((Motcle) localisation == "FACES")
715 {
716 id_du_champ_modifie.prefix(id_du_domaine);
717 id_du_champ_modifie.prefix(iddomaine);
718 id_du_champ_modifie.prefix("_FACES_");
719 }
720 Nom& id_champ = id_du_champ_modifie;
721
722 // Build the file name
723 Nom basename_champ(lata_basename_), extension_champ(extension_lata());
724
725 if (un_seul_fichier_lata_) extension_champ += "_single";
726 else
727 {
728 extension_champ += ".";
729 extension_champ += id_champ;
730 extension_champ += ".";
731 extension_champ += localisation;
732 extension_champ += ".";
733 extension_champ += id_du_domaine;
734 extension_champ += ".";
735 char str_temps[100] = "0.0";
736 if (temps >= 0.)
737 snprintf(str_temps, 100, "%.10f", temps);
738 extension_champ += str_temps;
739 }
740
741 Nom filename_champ;
742 trustIdType size_tot;
743 int nb_compo;
744 {
745 const bool not_in_list = !liste_single_lata_ecrit.contient_(lata_basename_),
746 should_erase = (!un_seul_fichier_lata_) ? true /* Always erase */ : (offset_elem_ < 0 && not_in_list);
747
748 Fichier_Lata fichier_champ(basename_champ, extension_champ, should_erase ? Fichier_Lata::ERASE : Fichier_Lata::APPEND, format_, options_para_);
749
750 // add to the list if not already in it and if un_seul_fichier_lata_ !!!
751 if (not_in_list && un_seul_fichier_lata_) liste_single_lata_ecrit.add(lata_basename_); // BOOM !
752
753 // XXX Elie Saikali : attention offset ici avant write_doubletab ! sinon decalage d'un champ !
755 if (fichier_champ.is_master())
756 offset_elem_ = fichier_champ.get_SFichier().get_ofstream().tellp();
757
758 filename_champ = fichier_champ.get_filename();
759 size_tot = write_doubletab(fichier_champ, valeurs, nb_compo, options_para_);
760 }
761
762 // Opening the .lata file in append mode.
763 // Adding the field reference
765 SFichier& sfichier = fichier.get_SFichier();
766 if (fichier.is_master())
767 {
768 sfichier << "Champ " << id_champ << " ";
769 sfichier << remove_path(filename_champ);
770 sfichier << " geometrie=" << id_du_domaine;
771 sfichier << " localisation=" << localisation;
772 sfichier << " size=" << size_tot;
773 sfichier << " nature=" << nature;
774 sfichier << " noms_compo=" << noms_compo[0];
775 for (int k = 1; k < noms_compo.size(); k++)
776 sfichier << "," << noms_compo[k];
777
778 sfichier << " composantes=" << nb_compo;
779
780 ecrire_offset(sfichier, offset_elem_);
781
782 sfichier << finl;
783 }
784 fichier.syncfile();
785
786 return 1;
787}
788
789/*! @brief See Format_Post_base::ecrire_champ. WARNING: if "reference" is non-empty, 1 is added to all values to switch to Fortran numbering, and if furthermore a single lata file is written for all processors, an
790 *
791 * offset is added to all values (renumbering of indices to switch to global numbering; see ecrire_domaine for an example)
792 *
793 */
794template<typename TYP>
795int Format_Post_Lata::ecrire_item_integral_T(const Nom& id_item, const Nom& id_du_domaine, const Nom& id_domaine, const Nom& localisation,
796 const Nom& reference, const TRUSTVect<TYP, int>& val, const int reference_size)
797{
798 // Build the file name
799 Nom basename_champ(lata_basename_), extension_champ(extension_lata());
800
801 if (un_seul_fichier_lata_) extension_champ += "_single";
802 else
803 {
804 extension_champ += ".";
805 //extension_champ += id_champ;
806 extension_champ += id_item;
807 extension_champ += ".";
808 extension_champ += localisation;
809 extension_champ += ".";
810 extension_champ += id_du_domaine;
811 extension_champ += ".";
812 char str_temps[100] = "0.0";
813 if (temps_courant_ >= 0.)
814 snprintf(str_temps, 100, "%.10f", temps_courant_);
815 extension_champ += Nom(str_temps);
816 }
817
818 Nom filename_champ;
819 trustIdType size_tot;
820 int nb_compo = 0; // filled by ::write_T_tab() below, but my compiler doesn't see it since I templatized it.
821 const TRUSTTab<TYP, int> valeurs = static_cast<const TRUSTTab<TYP, int>&>(val);
822 {
823 const bool not_in_list = !liste_single_lata_ecrit.contient_(lata_basename_),
824 should_erase = (!un_seul_fichier_lata_) ? true /* Always erase */ : (offset_elem_ < 0 && not_in_list);
825
826 Fichier_Lata fichier_champ(basename_champ, extension_champ, should_erase ? Fichier_Lata::ERASE : Fichier_Lata::APPEND, format_, options_para_);
827
828 // add to the list if not already in it and if un_seul_fichier_lata_ !!!
829 if (not_in_list && un_seul_fichier_lata_) liste_single_lata_ecrit.add(lata_basename_); // BOOM !
830
832 if (fichier_champ.is_master())
833 offset_elem_ = fichier_champ.get_SFichier().get_ofstream().tellp();
834
835 filename_champ = fichier_champ.get_filename();
836 // Assuming that if reference is non-empty, it is an index into another array, so Fortran numbering applies:
837 bool decal = false;
838 trustIdType decal_partiel = 0;
839 if (reference != "")
840 {
841 decal = true;
842 decal_partiel = 1;
844 {
845 // All processors write to a single file; indices must be renumbered to global numbering.
846 // Offset to add to indices for global numbering.
847 decal_partiel += mppartial_sum(reference_size);
848 }
849 }
850 size_tot = ::write_T_tab<TYP, _LATA_INT_TYPE_>(fichier_champ, decal, decal_partiel, valeurs, nb_compo, options_para_);
851 }
852
853 {
854 // Opening the .lata file in append mode. Adding the field reference.
855 Fichier_Lata_maitre fichier(lata_basename_, extension_lata(), Fichier_Lata::APPEND, options_para_);
856 SFichier& sfichier = fichier.get_SFichier();
857 if (fichier.is_master())
858 {
859 sfichier << "Champ " << id_item << " ";
860 sfichier << remove_path(filename_champ);
861 sfichier << " geometrie=" << id_du_domaine;
862
863 if (localisation != "") sfichier << " localisation=" << localisation;
864
865 sfichier << " size=" << size_tot;
866 sfichier << " composantes=" << nb_compo;
867 if (reference != "") sfichier << " reference=" << reference;
868
869 ecrire_offset(sfichier, offset_elem_);
870
871 const int sz = (int) sizeof(_LATA_INT_TYPE_);
872 switch(sz)
873 {
874 case 4:
875 sfichier << " format=int32";
876 break;
877 case 8:
878 sfichier << " format=int64";
879 break;
880 default:
881 Cerr << "Error in Format_Post_Lata::ecrire_champ_lata\n" << " Integer type not supported: size=" << sz << finl;
882 exit();
883 }
884 sfichier << finl;
885 }
886 fichier.syncfile();
887 }
888
889 // Trick for parallel face data:
890 if ((id_item == "FACES" && Process::is_parallel()) && (options_para_ == SINGLE_FILE || options_para_ == SINGLE_FILE_MPIIO))
891 {
892 const int n = valeurs.dimension(0);
893 TIDTab data(1,2);
894 data(0, 0) = 1 + mppartial_sum(n);
895 data(0, 1) = n;
896 ecrire_item_tid("JOINTS_FACES",
897 id_du_domaine,
898 "", /* id_domaine */
899 "", /* localisation */
900 "", /* reference */
901 data,
902 0); /* reference_size */
903 }
904 return 1;
905}
906
907int Format_Post_Lata::ecrire_item_int(const Nom& id_item, const Nom& id_du_domaine, const Nom& id_domaine, const Nom& localisation,
908 const Nom& reference, const IntVect& val, const int reference_size)
909{
910 return ecrire_item_integral_T(id_item, id_du_domaine, id_domaine, localisation, reference, val, reference_size);
911}
912
913int Format_Post_Lata::ecrire_item_tid(const Nom& id_item, const Nom& id_du_domaine, const Nom& id_domaine, const Nom& localisation,
914 const Nom& reference, const TIDVect& val, const int reference_size)
915{
916 return ecrire_item_integral_T(id_item, id_du_domaine, id_domaine, localisation, reference, val, reference_size);
917}
918
919int Format_Post_Lata::ecrire_entete_lata(const Nom& base_name, const Options_Para& option, const Format& format, const int est_le_premier_post)
920{
921 if (est_le_premier_post)
922 {
923 // Determine the binary format:
924 // big endian => the 32-bit integer "1" is written as 0x00 0x00 0x00 0x01
925 // little endian => 0x01 0x00 0x00 0x00
926 const unsigned int one = 1;
927 const int big_endian = (*((unsigned char*) &one) == 0) ? 1 : 0;
928
929 // Erase the .lata file and write the header
931
932 SFichier& sfichier = fichier.get_SFichier();
933 if (fichier.is_master())
934 {
935 sfichier << "LATA_V2.1 TRUST version " << TRUST_VERSION << finl;
936 sfichier << Objet_U::nom_du_cas() << finl;
937 sfichier << "Trio_U verbosity=0" << finl;
938
939 sfichier << "Format ";
940 switch(format)
941 {
942 case ASCII:
943 sfichier << "ASCII,";
944 break;
945 case BINAIRE:
946 sfichier << "BINAIRE,";
947 if (big_endian)
948 sfichier << "BIG_ENDIAN,";
949 else
950 sfichier << "LITTLE_ENDIAN,";
951 break;
952 default:
953 Cerr << "Error in Format_Post_Lata::ecrire_entete\n" << " format not supported" << finl;
954 exit();
955 }
956 switch(sizeof(_LATA_INT_TYPE_))
957 {
958 case 4:
959 sfichier << "INT32,";
960 break;
961 case 8:
962 sfichier << "INT64,";
963 break;
964 default:
965 Cerr << "Error in Format_Post_Lata::ecrire_entete\n" << " sizeof(int) not supported" << finl;
966 exit();
967 }
968 sfichier << "F_INDEXING,C_ORDERING,F_MARKERS_SINGLE,REAL32" << finl;
969 }
970 fichier.syncfile();
971
972 }
973
974 return 1;
975}
976
977int Format_Post_Lata::ecrire_temps_lata(const double temps, double& temps_format, const Nom& base_name, Status& stat, const Options_Para& option)
978{
979 assert(stat != RESET);
980 // Write the time only if it has changed...
981 if (stat != WRITING_TIME || temps_format != temps)
982 {
983 temps_format = temps;
984 // Opening the .lata file in append mode
986 if (fichier.is_master())
987 fichier.get_SFichier() << "TEMPS " << temps << finl;
988 fichier.syncfile();
989 stat = WRITING_TIME;
990 }
991 return 1;
992}
993
994int Format_Post_Lata::finir(const int est_le_dernier_post)
995{
996 if (est_le_dernier_post)
997 {
999 SFichier& sfichier = fichier.get_SFichier();
1000 if (fichier.is_master()) sfichier << "FIN" << finl;
1001 fichier.syncfile();
1002 }
1003 return 1;
1004}
File for reading. This class is to the C++ ifstream class what the Entree class is to the.
Definition EFichier.h:29
Class to use MPI-IO to write in a single file.
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
: Specialization of Fichier_Lata for the master file: always in ASCII.
virtual int is_master() const
If the file is of shared type, returns 1 if me() equals the group master, 0 otherwise.
virtual SFichier & get_SFichier()
virtual const Nom & get_filename() const
Returns the file name with its path.
virtual void syncfile()
If the file is of shared type, calls the syncfile() method; otherwise does nothing.
: Post-processing class for Eulerian fields in LATA format.
void reset() override
Resets the object to the state obtained by the default constructor.
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).
static const char * remove_path(const char *filename)
Returns the file name without its path: strips all characters before the last /.
bool un_seul_fichier_lata_
int ecrire_item_int(const Nom &id_item, const Nom &id_du_domaine, const Nom &id_domaine, const Nom &localisation, const Nom &reference, const IntVect &data, const int reference_size) override
Writing an integer array to the post-processing file.
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.
int modify_file_basename(const Nom file_basename, bool for_restart, const double tinit) override
Modifying name of the post file, plus some clever management of previously saved data in case of rest...
double temps_courant_
Options_Para options_para_
int preparer_post(const Nom &id_du_domaine, const int est_le_premier_post, const int reprise, const double t_init) override
static trustIdType write_doubletab(Fichier_Lata &fichier, const DoubleTab &tab, int &nb_colonnes, const Options_Para &option)
fichier is a lata data file (not the master file). The array tab is written as-is (in binary or ASCII...
long int offset_som_
int ecrire_item_tid(const Nom &id_item, const Nom &id_du_domaine, const Nom &id_domaine, const Nom &localisation, const Nom &reference, const TIDVect &data, const int reference_size)
long int offset_elem_
Format format_
virtual int finir_sans_reprise(const Nom file_basename)
double tinit_
static int ecrire_entete_lata(const Nom &base_name, const Options_Para &option, const Format &format, const int est_le_premier_post)
Format
@ BINAIRE
@ ASCII
virtual int reconstruct(const Nom file_basename, const Nom, const double tinit)
Nom lata_basename_
Options_Para
@ SINGLE_FILE_MPIIO
@ SINGLE_FILE
@ MULTIPLE_FILES
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,...
Format_Post_Lata()
Default constructor: format_ ASCII and options_para_ = SINGLE_FILE.
Status
@ WRITING_TIME
@ RESET
@ INITIALIZED
int completer_post(const Domaine &dom, const int axi, const Nature_du_champ &nature, const int nb_compo, const Noms &noms_compo, const Motcle &loc_post, const Nom &le_nom_champ_post) override
bool restart_already_moved_
void set_param(Param &param) const override
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
static trustIdType write_inttab(Fichier_Lata &fichier, bool decal_fort, trustIdType decalage_partiel, const IntTab &tab, int &nb_colonnes, const Options_Para &option)
Writing an integer array to the given file.
Status status
void ecrire_domaine_low_level(const Nom &id_dom, const DoubleTab &sommets, const IntTab &elements, const Motcle &type_elem)
Low level routine to write a mesh into a LATA file.
int initialize_by_default(const Nom &file_basename) override
Initializes the class with default parameters (ASCII format, SINGLE_FILE).
int finir(const int est_le_dernier_post) override
int initialize(const Nom &file_basename, const int format, const Nom &option_para) override
static int ecrire_temps_lata(const double temps, double &temps_format, const Nom &base_name, Status &stat, const Options_Para &option)
static const char * extension_lata()
Returns the conventional extension for lata files: ".lata".
void resetTime(double t, const std::string dirname) override
int lire_motcle_non_standard(const Motcle &, Entree &) override
Reads non-simple-type parameters of an Objet_U from an input stream.
Base class for post-processing output formats for fields (lata, med, cgns, lml, single_lata).
OBS_PTR(Domaine_dis_base) domaine_dis_
Reference to the discretized domain - used for face fields.
A character string (Nom) in uppercase.
Definition Motcle.h:26
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
virtual int debute_par(const char *const n) const
Definition Nom.cpp:314
An array of character strings (VECT(Nom)).
Definition Noms.h:26
int contient_(const char *const ch) const
Definition Noms.cpp:60
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
static const Nom & nom_du_cas()
Returns a constant reference to the case name. This method is static.
Definition Objet_U.cpp:145
static int axi
Definition Objet_U.h:96
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
static trustIdType mppartial_sum(trustIdType i)
Computes the partial sum of x over processors 0 to me()-1 (returns 0 on processor 0).
Definition Process.cpp:403
static double mp_max(double)
Definition Process.cpp:379
static bool is_parallel()
Definition Process.cpp:108
static double mp_sum(double)
Computes the sum of x over all processors in the current group.
Definition Process.cpp:145
static void barrier()
Synchronizes all processors in the current group (waits until all processors have reached the barrier...
Definition Process.cpp:133
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
void precision(int pre) override
void setf(IOS_FORMAT code) override
Base class for output streams.
Definition Sortie.h:52
virtual int put(const unsigned *ob, std::streamsize n, std::streamsize nb_colonnes=1)
Definition Sortie.cpp:101
_TYPE_ * addr()
N-dimensional array for N <= 4.
Definition TRUSTTab.h:31
int nb_dim() const
Definition TRUSTTab.h:199
_SIZE_ dimension_tot(int) const override
Definition TRUSTTab.tpp:160
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133