TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Merge_MED.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 <Merge_MED.h>
17#include <glob.h>
18#include <Nom.h>
19
20#include <medcoupling++.h>
21
22#ifdef MEDCOUPLING_
23#include <MCAuto.hxx>
24#include <MEDLoader.hxx>
25#include <MEDFileMesh.hxx>
26#include <MEDCouplingFieldDouble.hxx>
27using namespace MEDCoupling;
28#endif
29
30Implemente_instanciable(Merge_MED,"Merge_MED",Interprete);
31// XD Merge_MED interprete Merge_MED NO_BRACE This keyword allows to merge multiple MED files produced during a parallel
32// XD_CONT computation into a single MED file.
33// XD attr med_files_base_name chaine med_files_base_name REQ Base name of multiple med files that should appear as
34// XD_CONT base_name_xxxxx.med, where xxxxx denotes the MPI rank number. If you specify NOM_DU_CAS, it will
35// XD_CONT automatically take the basename from your datafile's name.
36// XD attr time_iterations chaine(into=["all_times","last_time"]) time_iterations REQ Identifies whether to merge all
37// XD_CONT time iterations present in the MED files or only the last one.
38
39Sortie& Merge_MED::printOn(Sortie& os) const { return Interprete::printOn(os); }
41
42// Method that glob all med files found in the directory and returns
43// a list of strings
44std::vector<std::string> glob_med_files(const std::string& fileName)
45{
46#ifndef __CYGWIN__
47 glob_t glob_result;
48
49 glob(fileName.c_str(),GLOB_TILDE,nullptr,&glob_result);
50
51 std::vector<std::string> ls_med;
52 for(unsigned int i=0; i<glob_result.gl_pathc; ++i)
53 ls_med.push_back(std::string(glob_result.gl_pathv[i]));
54
55 globfree(&glob_result);
56
57 return ls_med;
58#else
59 throw;
60#endif
61}
62
63#ifdef MEDCOUPLING_
64// This is an internal function that performs the field merging
65// and write a single med file
66// Two cases are examined depending whether the field is a P0 or a P1 field
67void Merge_MED::mergeFields(const std::vector< std::string >& field_names,
68 const std::vector< std::string >& meshes_names,
69 const std::vector<std::string>& listmed,
70 const std::vector< std::pair< std::pair< int,int>,double >>& lst_dt,
71 const int mesh_numb,
72 const int iter_numb,
73 Nom out_file,
74 bool& first_time, const bool isCell) const
75{
76 // Wee loop on all field names
77 for (const auto & fld_name: field_names)
78 {
79 int fld_idx=0;
80 std::vector<const MEDCouplingFieldDouble *> fields(listmed.size());
81 // We loop over all med files
82 for (size_t i=0; i<listmed.size(); i++)
83 {
84 MEDCouplingFieldDouble *f = nullptr;
85 if (isCell)
86 {
87 f = dynamic_cast<MEDCouplingFieldDouble *>
88 (ReadFieldCell(listmed[i],meshes_names[mesh_numb] ,0,fld_name,
89 lst_dt[iter_numb].first.first,lst_dt[iter_numb].first.second));
90 }
91 else
92 {
93 f = dynamic_cast<MEDCouplingFieldDouble *>
94 (ReadFieldNode(listmed[i],meshes_names[mesh_numb] ,0,fld_name,
95 lst_dt[iter_numb].first.first,lst_dt[iter_numb].first.second));
96 }
97 if (f == nullptr)
98 {
99 Cerr << "Unexpected internal error!!" << finl;
100 Process::exit(-1);
101 }
102 fields[fld_idx] = f;
103 fld_idx++;
104 } // end loop over all med files
105 MCAuto<MEDCouplingFieldDouble> merged_field = MEDCouplingFieldDouble::MergeFields(fields);
106 merged_field->mergeNodes(Objet_U::precision_geom, 1.0e-12); // first epsilon for node coincidence, second for different field values if on nodes.
107
108 if (je_suis_maitre())
109 {
110 if (first_time)
111 WriteField(out_file.getString(),merged_field,true);
112 else
113 WriteField(out_file.getString(),merged_field,false); // append on the existing file
114 }
115 // the single med file is created. We will append it !
116 first_time=0;
117
118 // Memory release:
119 for (auto & f: fields)
120 f->decrRef();
121 } // end loop over all field names
122}
123
124/* Used for lexicographical ordering of time steps */
125struct less_than_key
126{
127 inline bool operator() (const std::pair< std::pair< int,int>,double >& a, const std::pair< std::pair< int,int>,double >& b) const
128 {
129 if (a.first.first == b.first.first)
130 return (a.first.second < b.first.second);
131 return (a.first.first < b.first.first);
132 }
133};
134
135/*! @brief Merge_MED::interpreter(Entree& is)
136 *
137 * @param (Entree& is) un flot d'entree
138 * @return (Entree&) le flot d'entree modifie
139 */
141{
142 Cerr<<"Syntax Merge_MED::interpreter [NOM_DU_CAS|med_files_base_name] [all_times|last_time]"<<finl;
143 Nom med_name,time_opt;
144 is >> med_name>> time_opt;
145
146 if (med_name == "NOM_DU_CAS")
147 med_name= nom_du_cas();
148
149 Nom files=med_name+"_*.med";
150
151 // call the magic glob function
152 std::vector<std::string> listmed=glob_med_files(files.getString());
153
154 if (listmed.size() == 0)
155 {
156 Cerr << "No multiple med files with a basename " << med_name << " are present in this directory !" << finl;
157 Cerr << "Verify your data file or check if the files " << med_name << "_xxxx.med are present in this directory !" << finl;
159 }
160 else
161 {
162 Cerr << "In process of merging " << (int)listmed.size() << " med files in a single med file ..." << finl;
163 }
164
165 const std::vector< std::string > meshes_names = GetMeshNames(listmed[0]);
166 // GetAllFieldNames() works very good if all fields are written on a single mesh
167 // see later GetAllFieldNamesOnMesh() while dealing with several meshes ...
168 const std::vector< std::string > all_field_names = GetAllFieldNames(listmed[0]);
169
170 // we use all_field_names[0] to check the iterations hoping that the med files are written correctly
171 // with same number of iterations for all fields ...
172 std::vector< std::pair< std::pair< int,int>,double >> lst_dt=GetAllFieldIterations(listmed[0],all_field_names[0]);
173 // Sort the iterations incrementally ...
174 std::sort(lst_dt.begin(), lst_dt.end(), less_than_key());
175
176 int nb_steps = (int)lst_dt.size();
177 Cerr << "Number of iterations detected : " << nb_steps << finl;
178 Cerr << "Number of meshes detected : " << (int)meshes_names.size() << finl;
179
180 // TODO : FIXME : use std::vector<std::vector<std::string>> to avoid multiple calls for MEDCoupling functions ??
181 //std::vector< std::string > field_names;
182 std::vector< std::string > cell_fields;
183 std::vector< std::string > node_fields;
184
185 int count = 0;
186 for (size_t i=0; i<meshes_names.size(); i++)
187 {
188 // field_names = GetAllFieldNamesOnMesh(listmed[0],meshes_names[i]);
189 cell_fields = GetCellFieldNamesOnMesh(listmed[0],meshes_names[i]);
190 node_fields = GetNodeFieldNamesOnMesh(listmed[0],meshes_names[i]);
191 int tot_fld_num = (int)cell_fields.size() + (int)node_fields.size();
192 Cerr << "Number of fields detected on mesh " << (int)i +1 << " : " << tot_fld_num << finl;
193 Cerr << " - Number of P0 fields : " << (int)cell_fields.size() << finl;
194 Cerr << " - Number of P1 fields : " << (int)node_fields.size() << finl;
195 count = count + tot_fld_num;
196 }
197 // check if it is ok
198 assert(count == (int)all_field_names.size());
199
200 // Output file we are waiting for
201 Nom out_file=med_name+".med";
202 // test if the single med file is created or no
203 bool first_time = 1;
204
205 size_t first_iter = time_opt == "last_time" ? (lst_dt.size()-1) : 0;
206 for (size_t iter=first_iter; iter<lst_dt.size(); iter++) // loop over all iterations
207 {
208 for (size_t msh=0; msh<meshes_names.size(); msh++) // loop over all meshes
209 {
210 cell_fields = GetCellFieldNamesOnMesh(listmed[0],meshes_names[msh]);
211 node_fields = GetNodeFieldNamesOnMesh(listmed[0],meshes_names[msh]);
212
213 mergeFields(cell_fields,meshes_names,listmed,lst_dt,(int)msh,(int)iter,out_file,first_time, true);
214 mergeFields(node_fields,meshes_names,listmed,lst_dt,(int)msh,(int)iter,out_file,first_time, false);
215 }
216 }
217
218 return is;
219}
220
221#else /* No MEDCOUPLING_ */
222
224{
225 Cerr << "Version compiled without MEDCoupling" << finl;
227
228 return is;
229}
230
231void Merge_MED::mergeFields(const std::vector< std::string >& field_names,
232 const std::vector< std::string >& meshes_names,
233 const std::vector<std::string>& listmed,
234 const std::vector< std::pair< std::pair< int,int>,double >>& lst_dt,
235 const int mesh_numb,
236 const int iter_numb,
237 Nom out_file,
238 bool& first_time, const bool isCell) const
239{
240 Cerr << "Version compiled without MEDCoupling" << finl;
242}
243
244#endif /* ifdef MEDCOUPLING_ */
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
Classe de base des objets "interprete".
Definition Interprete.h:38
Class Merge_MED Merge several MED files written by several procs into a single field object with a pr...
Definition Merge_MED.h:30
Entree & interpreter(Entree &) override
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
const std::string & getString() const
Definition Nom.h:92
friend class Entree
Definition Objet_U.h:76
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
static double precision_geom
Definition Objet_U.h:86
static const Nom & nom_du_cas()
Renvoie une reference constante vers le nom du cas.
Definition Objet_U.cpp:146
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
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
Classe de base des flux de sortie.
Definition Sortie.h:52