1 // Copyright (C) 2007-2023 CEA, EDF
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // Author : Anthony Geay (EDF R&D)
21 #include "ParaMEDFileMesh.hxx"
23 #include "MEDFileMesh.hxx"
24 #include "MEDFileMeshLL.hxx"
25 #include "MEDLoader.hxx"
26 #include "MEDFileField1TS.hxx"
27 #include "MEDFileUtilities.hxx"
28 #include "MEDFileEntities.hxx"
33 // From MEDLOader.cxx TU
34 extern med_geometry_type typmai3[INTERP_KERNEL::NORM_MAXTYPE];
36 using namespace MEDCoupling;
38 void checkDistribution(const MPI_Comm& com, mcIdType totalNumberOfElements, const std::vector<mcIdType>& distrib)
40 mcIdType nbEltsInDistribLoc = distrib.size();
41 mcIdType nbEltsInDistribTot = -1;
43 MPI_Allreduce(&nbEltsInDistribLoc, &nbEltsInDistribTot, 1, MPI_LONG, MPI_SUM, com);
45 throw INTERP_KERNEL::Exception("not(HAVE_MPI) incompatible with MPI_World_Size>1");
47 if(nbEltsInDistribTot != totalNumberOfElements)
49 if(nbEltsInDistribTot > totalNumberOfElements)
50 throw INTERP_KERNEL::Exception("ParaMEDFileMesh : Some of your partitions overlap each other ! Each element in your distribution vector must appear only once ! ");
52 throw INTERP_KERNEL::Exception("ParaMEDFileMesh : The distribution does not cover the whole mesh ! Each element of the mesh must appear once in your distribution vector ");
57 MEDFileMesh *ParaMEDFileMesh::New(int iPart, int nbOfParts, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
59 MEDFileUtilities::CheckFileForRead(fileName);
60 MEDCoupling::MEDCouplingMeshType meshType;
61 MEDFileUtilities::AutoFid fid(MEDfileOpen(fileName.c_str(),MED_ACC_RDONLY));
64 MEDCoupling::MEDCouplingAxisType dummy3;
65 MEDFileMeshL2::GetMeshIdFromName(fid,mName,meshType,dummy3,dummy0,dummy1,dummy2);
70 return ParaMEDFileUMesh::New(iPart,nbOfParts,fileName,mName,dt,it,mrs);
73 throw INTERP_KERNEL::Exception("ParaMEDFileMesh::New : only unstructured mesh supported for the moment !");
77 MEDFileMesh *ParaMEDFileMesh::ParaNew(int iPart, int nbOfParts, const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
79 MEDFileUtilities::CheckFileForRead(fileName);
80 MEDCoupling::MEDCouplingMeshType meshType;
81 MEDFileUtilities::AutoFid fid(MEDfileOpen(fileName.c_str(),MED_ACC_RDONLY));
84 MEDCoupling::MEDCouplingAxisType dummy3;
85 MEDFileMeshL2::GetMeshIdFromName(fid,mName,meshType,dummy3,dummy0,dummy1,dummy2);
90 return ParaMEDFileUMesh::ParaNew(iPart,nbOfParts,com,nfo,fileName,mName,dt,it,mrs);
93 throw INTERP_KERNEL::Exception("ParaMEDFileMesh::ParaNew : only unstructured mesh supported for the moment !");
97 MEDFileUMesh *ParaMEDFileUMesh::New(int iPart, int nbOfParts, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
99 MEDFileUtilities::CheckFileForRead(fileName);
100 MEDFileUtilities::AutoFid fid(MEDfileOpen(fileName.c_str(),MED_ACC_RDONLY));
101 return ParaMEDFileUMesh::NewPrivate(fid,iPart,nbOfParts,fileName,mName,dt,it,mrs);
105 * Opens the given file in parallel so that each processor can load a specific part of the mesh \a mName.
106 * Each processor will load the cells contained in the vector \a distrib (only nodes lying on those cells will be loaded),
107 * in order to read the entire mesh in parallel (memory consumption is thus distributed among all the processes).
108 * \param [in] distrib - map defining for each geometric type, the corresponding vector of cells we want to load with c-type indexing (starting from zero).
109 * Each vector in this map has an independant numerotation, which means on one processor, vectors of different types may contain the same numbers, they will not refer to the same cells
110 * (the i-th cell of a type A does not correspond to the i-th cell of type B)
111 * However they have to differ from one processor to another, as to ensure that:
112 * 1) each processor only loads a unique part of the mesh
113 * 2) the combined distribution vectors cover the entire mesh
114 * \param [in] com - group of MPI processes that will read the file
115 * \param [in] nfo- MPI info object (used to manage MPI routines)
116 * \param [in] filename - name of the file we want to read
117 * \param [in] mName - name of the mesh we want to read
118 * \param [in] dt - order at which to read the mesh
119 * \param [in] it - iteration at which to read the mesh
120 * \param [in] mrs - object used to read additional low-level information
121 * \return MEDFileUMesh* - a new instance of MEDFileUMesh. The
122 * caller is to delete this mesh using decrRef() as it is no more needed.
123 * \throw exception if the mesh contains multiple types of cells
124 * \throw exception if the partition of the mesh cells defined by \a distrib does not cover the whole mesh
126 MEDFileUMesh *ParaMEDFileUMesh::ParaNew(const std::map<INTERP_KERNEL::NormalizedCellType,std::vector<mcIdType>> &distrib, const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
128 MEDFileUtilities::CheckFileForRead(fileName);
129 #ifdef HDF5_IS_PARALLEL
130 MEDFileUtilities::AutoFid fid(MEDparFileOpen(fileName.c_str(),MED_ACC_RDONLY,com,nfo));
132 MEDFileUtilities::AutoFid fid(MEDfileOpen(fileName.c_str(),MED_ACC_RDONLY));
134 return ParaMEDFileUMesh::NewPrivate(fid,com,distrib,fileName,mName,dt,it,mrs);
139 * Opens the given file in parallel so that each processor can load its part of the mesh \a mName.
140 * The mesh will be equally and linearly distributed among all processes:
141 * the list of cells will be divided into \a nbOfParts slices and only slice \a iPart (cells and nodes lying on those cells) will be loaded by the current processor.
142 * The entire mesh is thus read in parallel and memory consumption is divided among the group of processes.
143 * \param [in] iPart - part of the mesh that will be loaded
144 * \param [in] nbOfParts - total number of parts in which to divide the mesh
145 * \param [in] com - group of MPI processes that will read the file
146 * \param [in] nfo- MPI info object (used to manage MPI routines)
147 * \param [in] filename - name of the file we want to read
148 * \param [in] mName - name of the mesh we want to read
149 * \param [in] dt - Time order at which to read the mesh
150 * \param [in] it - Time iteration at which to read the mesh
151 * \param [in] mrs - object used to read additional low-level information
152 * \return MEDFileUMesh* - a new instance of MEDFileUMesh. The
153 * caller is to delete this mesh using decrRef() as it is no more needed.
155 MEDFileUMesh *ParaMEDFileUMesh::ParaNew(int iPart, int nbOfParts, const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
157 MEDFileUtilities::CheckFileForRead(fileName);
158 #ifdef HDF5_IS_PARALLEL
159 MEDFileUtilities::AutoFid fid(MEDparFileOpen(fileName.c_str(),MED_ACC_RDONLY,com,nfo)); // MPI_COMM_WORLD, MPI_INFO_NULL
161 MEDFileUtilities::AutoFid fid(MEDfileOpen(fileName.c_str(),MED_ACC_RDONLY));
163 return ParaMEDFileUMesh::NewPrivate(fid,iPart,nbOfParts,fileName,mName,dt,it,mrs);
167 * Loads mesh \a mName in parallel using a custom partition of the mesh cells among the processes.
168 * See ParaMEDFileUMesh::ParaNew for detailed description.
170 MEDFileUMesh *ParaMEDFileUMesh::NewPrivate(med_idt fid, const MPI_Comm& com, const std::map<INTERP_KERNEL::NormalizedCellType,std::vector<mcIdType>>& distrib, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
172 MCAuto<MEDFileUMesh> ret;
173 for(std::map<INTERP_KERNEL::NormalizedCellType,std::vector<mcIdType>>::const_iterator iter=distrib.begin(); iter!= distrib.end(); iter++)
175 med_geometry_type geoMedType(typmai3[iter->first /*current geometric type*/]);
176 med_bool changement,transformation;
177 med_int totalNumberOfElements(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_CELL,geoMedType,MED_CONNECTIVITY,MED_NODAL,&changement,&transformation));
178 checkDistribution(com,totalNumberOfElements,iter->second /*distrib over this geometric type*/);
180 ret=MEDFileUMesh::LoadPartOfFromUserDistrib(fid,mName,distrib,dt,it,mrs);
185 * Loads mesh \a mName in parallel using a slice partition of the mesh cells among the processes
186 * See ParaMEDFileUMesh::ParaNew for detailed description.
188 MEDFileUMesh *ParaMEDFileUMesh::NewPrivate(med_idt fid, int iPart, int nbOfParts, const std::string& fileName, const std::string& mName, int dt, int it, MEDFileMeshReadSelector *mrs)
190 MCAuto<MEDFileUMesh> ret;
191 int meshDim, spaceDim;
192 mcIdType numberOfNodes;
193 std::vector< std::vector< std::pair<INTERP_KERNEL::NormalizedCellType,int> > > typesDistrib(GetUMeshGlobalInfo(fileName,mName,meshDim,spaceDim,numberOfNodes));
194 std::vector<INTERP_KERNEL::NormalizedCellType> types;
195 std::vector<mcIdType> distrib;
196 for(std::vector< std::vector< std::pair<INTERP_KERNEL::NormalizedCellType,int> > >::const_iterator it0=typesDistrib.begin();it0!=typesDistrib.end();it0++)
197 for(std::vector< std::pair<INTERP_KERNEL::NormalizedCellType,int> >::const_iterator it1=(*it0).begin();it1!=(*it0).end();it1++)
199 types.push_back((*it1).first);
201 DataArray::GetSlice(0,(*it1).second,1,iPart,nbOfParts,tmp[0],tmp[1]);
203 distrib.insert(distrib.end(),tmp,tmp+3);
205 ret=MEDFileUMesh::LoadPartOf(fid,mName,types,distrib,dt,it,mrs);
210 * Loads field \a fName laying on mesh \a mName from the filename \a fileName in parallel:
211 * each processor will load their portion of the field (ie the portion laying on the cells/nodes in the vector \a distrib given in the parameters).
212 * WARNING : this will only load the array of values of the field, additionnal information of the local field such as the number of its tuples might be incorrect
213 * \param [in] com - group of MPI processes that will read the file
214 * \param [in] nfo- MPI info object (used to manage MPI routines)
215 * \param [in] fileName - name of the file containing the field
216 * \param [in] fName - name of the field we want to load
217 * \param [in] mName - name of the mesh on which the field is defined
218 * \param [in] distrib - vector of cells/nodes on which we want to load the field \a fName (with c-type indexing, so starting from zero).
219 * \param [in] loc - localisation of the field
220 * \param [in] geoType - geometrical type of the cells on which the field is laying (only needed if the field is located on cells)
221 * \param [in] dt - Time order at which to read the field
222 * \param [in] it - Time iteration at which to read the field
223 * \return MEDFileField1TS* - a new instance of MEDFileField1TS. The
224 * caller is to delete it using decrRef() as it is no more needed.
225 * \throw exception if the field is not of type FLOAT64
226 * \throw exception if the mesh contains more than one geometric type
227 * \throw exception if the given distribution does not cover the entire mesh on which the field is defined
229 MEDFileField1TS *ParaMEDFileField1TS::ParaNew(const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName, const std::string& fName, const std::string& mName, const std::vector<mcIdType>& distrib, TypeOfField loc, INTERP_KERNEL::NormalizedCellType geoType, int dt, int it)
231 MEDFileUtilities::CheckFileForRead(fileName);
232 #ifdef HDF5_IS_PARALLEL
233 MEDFileUtilities::AutoFid fid(MEDparFileOpen(fileName.c_str(),MED_ACC_RDONLY,com,nfo));
235 MEDFileUtilities::AutoFid fid(MEDfileOpen(fileName.c_str(),MED_ACC_RDONLY));
237 return ParaMEDFileField1TS::NewPrivate(fid,com,fName,mName,distrib,loc,geoType,dt,it);
241 * Loads field \a fName in parallel using a custom partition of the mesh entities (cells or nodes) on which the field is defined among the processes.
242 * See ParaMEDFileField1TS::ParaNew for detailed description.
244 MEDFileField1TS *ParaMEDFileField1TS::NewPrivate(med_idt fid, const MPI_Comm& com, const std::string& fName, const std::string& mName, const std::vector<mcIdType>& distrib, TypeOfField loc, INTERP_KERNEL::NormalizedCellType geoType, int dt, int it)
246 if(loc==ON_CELLS) //if distribution is on nodes, no fast way to check it (as a node can be shared by multiple processors)
248 med_geometry_type geoMedType(typmai3[geoType]);
249 med_bool changement,transformation;
250 med_int totalNumberOfElements(MEDmeshnEntity(fid,mName.c_str(),dt,it,MED_CELL,geoMedType,MED_FAMILY_NUMBER,MED_NODAL,&changement,&transformation));
251 checkDistribution(com,totalNumberOfElements,distrib);
253 std::vector<std::pair<TypeOfField,INTERP_KERNEL::NormalizedCellType>> tmp={ {loc, geoType} };
254 INTERP_KERNEL::AutoCppPtr<MEDFileEntities> entities(MEDFileEntities::BuildFrom(&tmp));
255 MCAuto<MEDFileAnyTypeField1TS> partFile(MEDFileAnyTypeField1TS::NewAdv(fid,fName,dt,it,entities,distrib));
257 MCAuto<MEDFileField1TS> ret(MEDCoupling::DynamicCast<MEDFileAnyTypeField1TS,MEDFileField1TS>(partFile));
261 throw INTERP_KERNEL::Exception("ParaMEDFileField1TS::ParaNew : only FLOAT64 field supported for the moment !");
265 MEDFileMeshes *ParaMEDFileMeshes::New(int iPart, int nbOfParts, const std::string& fileName)
267 std::vector<std::string> ms(GetMeshNames(fileName));
268 MCAuto<MEDFileMeshes> ret(MEDFileMeshes::New());
269 for(std::vector<std::string>::const_iterator it=ms.begin();it!=ms.end();it++)
271 MCAuto<MEDFileMesh> mesh(ParaMEDFileMesh::New(iPart,nbOfParts,fileName,(*it)));
277 MEDFileMeshes *ParaMEDFileMeshes::ParaNew(int iPart, int nbOfParts, const MPI_Comm& com, const MPI_Info& nfo, const std::string& fileName)
279 std::vector<std::string> ms(GetMeshNames(fileName));
280 MCAuto<MEDFileMeshes> ret(MEDFileMeshes::New());
281 for(std::vector<std::string>::const_iterator it=ms.begin();it!=ms.end();it++)
283 MCAuto<MEDFileMesh> mesh(ParaMEDFileMesh::ParaNew(iPart,nbOfParts,com,nfo,fileName,(*it)));