From 61d92c8e43cab2fdf936b02664a657d6c0850cb5 Mon Sep 17 00:00:00 2001 From: Anthony Geay Date: Wed, 30 Dec 2015 15:52:42 +0100 Subject: [PATCH] debug EDF11911. For serialkiller users having families on mesh lying both on cells and nodes. --- src/MEDLoader/MEDFileMesh.cxx | 18 ++++ src/MEDLoader/MEDFileMesh.hxx | 2 + src/MEDLoader/MEDFileMeshLL.cxx | 149 +++++++++++++++++++++++++-- src/MEDLoader/MEDFileMeshLL.hxx | 10 ++ src/MEDLoader/Swig/MEDLoaderCommon.i | 2 + src/MEDLoader/Swig/MEDLoaderTest3.py | 31 ++++++ 6 files changed, 202 insertions(+), 10 deletions(-) diff --git a/src/MEDLoader/MEDFileMesh.cxx b/src/MEDLoader/MEDFileMesh.cxx index 761578f27..f9ac17e96 100644 --- a/src/MEDLoader/MEDFileMesh.cxx +++ b/src/MEDLoader/MEDFileMesh.cxx @@ -513,6 +513,24 @@ std::vector MEDFileMesh::getFamiliesNames() const return ret; } +/*! + * Returns names of all families of \a this mesh but like they would be in file. + * This method is here only for MED file families gurus. If you are a kind user forget this method :-) + * This method is only useful for aggressive users that want to have in their file a same family lying both on cells and on nodes. This is not a good idea for lisibility ! + * For your information internaly in memory such families are renamed to have a nicer API. + */ +std::vector MEDFileMesh::getFamiliesNamesWithFilePointOfView() const +{ + std::vector ret(getFamiliesNames()); + MEDFileMeshL2::RenameFamiliesFromMemToFile(ret); + return ret; +} + +std::string MEDFileMesh::GetMagicFamilyStr() +{ + return std::string(MEDFileMeshL2::ZE_SEP_FOR_FAMILY_KILLERS); +} + /*! * Changes a name of every family, included in one group only, to be same as the group name. * \throw If there are families with equal names in \a this mesh. diff --git a/src/MEDLoader/MEDFileMesh.hxx b/src/MEDLoader/MEDFileMesh.hxx index 65c39d1c2..fd7992c40 100644 --- a/src/MEDLoader/MEDFileMesh.hxx +++ b/src/MEDLoader/MEDFileMesh.hxx @@ -116,6 +116,8 @@ namespace ParaMEDMEM MEDLOADER_EXPORT void setGroupsOnFamily(const std::string& famName, const std::vector& grps); MEDLOADER_EXPORT std::vector getGroupsNames() const; MEDLOADER_EXPORT std::vector getFamiliesNames() const; + MEDLOADER_EXPORT std::vector getFamiliesNamesWithFilePointOfView() const; + MEDLOADER_EXPORT static std::string GetMagicFamilyStr(); MEDLOADER_EXPORT void assignFamilyNameWithGroupName(); MEDLOADER_EXPORT std::vector removeEmptyGroups(); MEDLOADER_EXPORT void removeGroup(const std::string& name); diff --git a/src/MEDLoader/MEDFileMeshLL.cxx b/src/MEDLoader/MEDFileMeshLL.cxx index 6adf25496..22626830a 100644 --- a/src/MEDLoader/MEDFileMeshLL.cxx +++ b/src/MEDLoader/MEDFileMeshLL.cxx @@ -30,6 +30,7 @@ #include "CellModel.hxx" #include +#include extern med_geometry_type typmai[MED_N_CELL_FIXED_GEO]; extern INTERP_KERNEL::NormalizedCellType typmai2[MED_N_CELL_FIXED_GEO]; @@ -37,6 +38,10 @@ extern med_geometry_type typmainoeud[1]; using namespace ParaMEDMEM; +const char MEDFileMeshL2::ZE_SEP_FOR_FAMILY_KILLERS[]="!/__\\!";//important start by - because ord('!')==33 the smallest (!=' ') to preserve orders at most. + +int MEDFileMeshL2::ZE_SEP2_FOR_FAMILY_KILLERS=4; + MEDFileMeshL2::MEDFileMeshL2():_name(MED_NAME_SIZE),_description(MED_COMMENT_SIZE),_univ_name(MED_LNAME_SIZE),_dt_unit(MED_LNAME_SIZE) { } @@ -199,6 +204,7 @@ void MEDFileMeshL2::ReadFamiliesAndGrps(med_idt fid, const std::string& meshName char nomfam[MED_NAME_SIZE+1]; med_int numfam; int nfam=MEDnFamily(fid,meshName.c_str()); + std::vector< std::pair > > > crudeFams(nfam); for(int i=0;i attdes=new char[MED_COMMENT_SIZE*natt+1]; INTERP_KERNEL::AutoPtr gro=new char[MED_LNAME_SIZE*ngro+1]; MEDfamily23Info(fid,meshName.c_str(),i+1,nomfam,attide,attval,attdes,&numfam,gro); - std::string famName=MEDLoaderBase::buildStringFromFortran(nomfam,MED_NAME_SIZE); - fams[famName]=numfam; + std::string famName(MEDLoaderBase::buildStringFromFortran(nomfam,MED_NAME_SIZE)); + std::vector grps(ngro); for(int j=0;j > >(famName,std::pair >(numfam,grps)); + } + RenameFamiliesFromFileToMemInternal(crudeFams); + for(std::vector< std::pair > > >::const_iterator it0=crudeFams.begin();it0!=crudeFams.end();it0++) + { + fams[(*it0).first]=(*it0).second.first; + for(std::vector::const_iterator it1=(*it0).second.second.begin();it1!=(*it0).second.second.end();it1++) + grps[*it1].push_back((*it0).first); } } void MEDFileMeshL2::WriteFamiliesAndGrps(med_idt fid, const std::string& mname, const std::map& fams, const std::map >& grps, int tooLongStrPol) { - for(std::map::const_iterator it=fams.begin();it!=fams.end();it++) + std::vector< std::pair > > > crudeFams(fams.size()); + std::size_t ii(0); + for(std::map::const_iterator it=fams.begin();it!=fams.end();it++,ii++) { std::vector grpsOfFam; for(std::map >::const_iterator it1=grps.begin();it1!=grps.end();it1++) @@ -228,18 +241,134 @@ void MEDFileMeshL2::WriteFamiliesAndGrps(med_idt fid, const std::string& mname, if(std::find((*it1).second.begin(),(*it1).second.end(),(*it).first)!=(*it1).second.end()) grpsOfFam.push_back((*it1).first); } - int ngro=grpsOfFam.size(); + crudeFams[ii]=std::pair > >((*it).first,std::pair >((*it).second,grpsOfFam)); + } + RenameFamiliesFromMemToFileInternal(crudeFams); + for(std::vector< std::pair > > >::const_iterator it=crudeFams.begin();it!=crudeFams.end();it++) + { + int ngro((*it).second.second.size()); INTERP_KERNEL::AutoPtr groName=MEDLoaderBase::buildEmptyString(MED_LNAME_SIZE*ngro); int i=0; - for(std::vector::const_iterator it2=grpsOfFam.begin();it2!=grpsOfFam.end();it2++,i++) + for(std::vector::const_iterator it2=(*it).second.second.begin();it2!=(*it).second.second.end();it2++,i++) MEDLoaderBase::safeStrCpy2((*it2).c_str(),MED_LNAME_SIZE-1,groName+i*MED_LNAME_SIZE,tooLongStrPol); INTERP_KERNEL::AutoPtr famName=MEDLoaderBase::buildEmptyString(MED_NAME_SIZE); MEDLoaderBase::safeStrCpy((*it).first.c_str(),MED_NAME_SIZE,famName,tooLongStrPol); - int ret=MEDfamilyCr(fid,mname.c_str(),famName,(*it).second,ngro,groName); + int ret=MEDfamilyCr(fid,mname.c_str(),famName,(*it).second.first,ngro,groName); ret++; } } +void MEDFileMeshL2::RenameFamiliesPatternInternal(std::vector< std::pair > > >& crudeFams, RenameFamiliesPatternFunc func) +{ + std::size_t ii(0); + std::vector fams(crudeFams.size()); + for(std::vector< std::pair > > >::const_iterator it=crudeFams.begin();it!=crudeFams.end();it++,ii++) + fams[ii]=(*it).first; + if(!func(fams)) + return ; + ii=0; + for(std::vector< std::pair > > >::iterator it=crudeFams.begin();it!=crudeFams.end();it++,ii++) + (*it).first=fams[ii]; +} + +/*! + * This method is dedicated to the killers that use a same family name to store different family ids. MED file API authorizes it. + * So this method renames families (if needed generaly not !) in order to have a discriminant name for families. + */ +void MEDFileMeshL2::RenameFamiliesFromFileToMemInternal(std::vector< std::pair > > >& crudeFams) +{ + RenameFamiliesPatternInternal(crudeFams,RenameFamiliesFromFileToMem); +} + +bool MEDFileMeshL2::RenameFamiliesFromFileToMem(std::vector< std::string >& famNames) +{ + std::map m; + std::set s; + for(std::vector< std::string >::const_iterator it=famNames.begin();it!=famNames.end();it++) + { + if(s.find(*it)!=s.end()) + m[*it]=0; + s.insert(*it); + } + if(m.empty()) + return false;// the general case ! + for(std::vector< std::string >::iterator it=famNames.begin();it!=famNames.end();it++) + { + std::map::iterator it2(m.find(*it)); + if(it2!=m.end()) + { + std::ostringstream oss; oss << *it << ZE_SEP_FOR_FAMILY_KILLERS << std::setfill('0') << std::setw(ZE_SEP2_FOR_FAMILY_KILLERS) << (*it2).second++; + *it=oss.str(); + } + } + return true; +} + +/*! + * This method is dedicated to the killers that use a same family name to store different family ids. MED file API authorizes it. + * So this method renames families (if needed generaly not !) in order to have a discriminant name for families. + */ +void MEDFileMeshL2::RenameFamiliesFromMemToFileInternal(std::vector< std::pair > > >& crudeFams) +{ + RenameFamiliesPatternInternal(crudeFams,RenameFamiliesFromMemToFile); +} + +bool MEDFileMeshL2::RenameFamiliesFromMemToFile(std::vector< std::string >& famNames) +{ + bool isSmthingStrange(false); + for(std::vector< std::string >::const_iterator it=famNames.begin();it!=famNames.end();it++) + { + std::size_t found((*it).find(ZE_SEP_FOR_FAMILY_KILLERS)); + if(found!=std::string::npos) + isSmthingStrange=true; + } + if(!isSmthingStrange) + return false; + // pattern matching + std::map< std::string, std::vector > m; + for(std::vector< std::string >::const_iterator it=famNames.begin();it!=famNames.end();it++) + { + std::size_t found((*it).find(ZE_SEP_FOR_FAMILY_KILLERS)); + if(found!=std::string::npos && found>=1) + { + std::string s1((*it).substr(found+sizeof(ZE_SEP_FOR_FAMILY_KILLERS)-1)); + if(s1.size()!=ZE_SEP2_FOR_FAMILY_KILLERS) + continue; + int k(-1); + std::istringstream iss(s1); + iss >> k; + bool isOK((iss.rdstate() & ( std::istream::failbit | std::istream::eofbit)) == std::istream::eofbit); + if(isOK && k>=0) + { + std::string s0((*it).substr(0,found)); + m[s0].push_back(*it); + } + } + } + if(m.empty()) + return false; + // filtering + std::map zeMap; + for(std::map< std::string, std::vector >::const_iterator it=m.begin();it!=m.end();it++) + { + if((*it).second.size()==1) + continue; + for(std::vector::const_iterator it1=(*it).second.begin();it1!=(*it).second.end();it1++) + zeMap[*it1]=(*it).first; + } + if(zeMap.empty()) + return false; + // traduce + for(std::vector< std::string >::iterator it=famNames.begin();it!=famNames.end();it++) + { + std::map::iterator it1(zeMap.find(*it)); + if(it1!=zeMap.end()) + *it=(*it1).second; + } + + return true; +} + MEDFileUMeshL2::MEDFileUMeshL2() { } diff --git a/src/MEDLoader/MEDFileMeshLL.hxx b/src/MEDLoader/MEDFileMeshLL.hxx index a65e0c106..9a8f0e8e3 100644 --- a/src/MEDLoader/MEDFileMeshLL.hxx +++ b/src/MEDLoader/MEDFileMeshLL.hxx @@ -58,6 +58,16 @@ namespace ParaMEDMEM static double CheckMeshTimeStep(med_idt fid, const std::string& mname, int nstep, int dt, int it); static void ReadFamiliesAndGrps(med_idt fid, const std::string& mname, std::map& fams, std::map >& grps, MEDFileMeshReadSelector *mrs); static void WriteFamiliesAndGrps(med_idt fid, const std::string& mname, const std::map& fams, const std::map >& grps, int tooLongStrPol); + static bool RenameFamiliesFromFileToMem(std::vector< std::string >& famNames); + static bool RenameFamiliesFromMemToFile(std::vector< std::string >& famNames); + private: + typedef bool (*RenameFamiliesPatternFunc)(std::vector< std::string >&); + static void RenameFamiliesPatternInternal(std::vector< std::pair > > >& crudeFams, RenameFamiliesPatternFunc func); + static void RenameFamiliesFromFileToMemInternal(std::vector< std::pair > > >& crudeFams); + static void RenameFamiliesFromMemToFileInternal(std::vector< std::pair > > >& crudeFams); + public: + static const char ZE_SEP_FOR_FAMILY_KILLERS[]; + static int ZE_SEP2_FOR_FAMILY_KILLERS; protected: MEDFileString _name; MEDFileString _description; diff --git a/src/MEDLoader/Swig/MEDLoaderCommon.i b/src/MEDLoader/Swig/MEDLoaderCommon.i index 310810e20..db8a4aa1a 100644 --- a/src/MEDLoader/Swig/MEDLoaderCommon.i +++ b/src/MEDLoader/Swig/MEDLoaderCommon.i @@ -922,6 +922,8 @@ namespace ParaMEDMEM void setGroupsOnFamily(const std::string& famName, const std::vector& grps) throw(INTERP_KERNEL::Exception); std::vector getGroupsNames() const throw(INTERP_KERNEL::Exception); std::vector getFamiliesNames() const throw(INTERP_KERNEL::Exception); + std::vector getFamiliesNamesWithFilePointOfView() const throw(INTERP_KERNEL::Exception); + static std::string GetMagicFamilyStr(); void assignFamilyNameWithGroupName() throw(INTERP_KERNEL::Exception); std::vector removeEmptyGroups() throw(INTERP_KERNEL::Exception); void removeGroup(const std::string& name) throw(INTERP_KERNEL::Exception); diff --git a/src/MEDLoader/Swig/MEDLoaderTest3.py b/src/MEDLoader/Swig/MEDLoaderTest3.py index ec4cf3132..9bacf90f9 100644 --- a/src/MEDLoader/Swig/MEDLoaderTest3.py +++ b/src/MEDLoader/Swig/MEDLoaderTest3.py @@ -4709,6 +4709,37 @@ class MEDLoaderTest(unittest.TestCase): self.assertTrue(mm.isEqual(mm3,1e-12)[0]) pass + def testMEDFileForFamiliesPlayer1(self): + """Non regression bug EDF11911. For serial killers using same family name to store both cells and nodes ! Only sky is the limit.""" + fileName="Pyfile98.med" + meshName="mesh" + magicSt="%s%%04i"%(MEDFileMesh.GetMagicFamilyStr()) + arr=DataArrayDouble(4) ; arr.iota() + m=MEDCouplingCMesh() ; m.setCoords(arr,arr) + m=m.buildUnstructured() + mm=MEDFileUMesh() + mm[0]=m + mm.setName(meshName) + mm.setFamilyId("FAMILLE_ZERO",0) + mm.getFamilyFieldAtLevel(0)[-3:]=-4 + mm.setFamilyId("RIDF%s"%(magicSt%0),-4) + mm.setGroupsOnFamily("RIDF%s"%(magicSt%0),["RID"]) + d=DataArrayInt(16) ; d[:]=0 ; d[[1,2,4,5]]=3 + mm.setFamilyFieldArr(1,d) + mm.setFamilyId("RIDF%s"%(magicSt%1),3) + mm.setGroupsOnFamily("RIDF%s"%(magicSt%1),["RID"]) + self.assertEqual(mm.getFamiliesNames(),("FAMILLE_ZERO",'RIDF!/__\\!0000','RIDF!/__\\!0001')) + self.assertEqual(mm.getFamiliesNamesWithFilePointOfView(),("FAMILLE_ZERO","RIDF","RIDF")) # <- the aim of test is here ! + self.assertEqual(mm.getFamiliesIdsOnGroup("RID"),(-4,3)) + mm.write(fileName,2) + # now read such funny file ! + mm2=MEDFileMesh.New(fileName) # <- normaly mdump of Pyfile98.med must contain only RID and FAMILLE_ZERO families. + self.assertTrue(mm.isEqual(mm2,1e-16)) + self.assertEqual(mm2.getFamiliesNames(),("FAMILLE_ZERO",'RIDF!/__\\!0000','RIDF!/__\\!0001')) + self.assertEqual(mm2.getFamiliesNamesWithFilePointOfView(),("FAMILLE_ZERO","RIDF","RIDF")) + self.assertEqual(mm2.getFamiliesIdsOnGroup("RID"),(-4,3))# <- very important too ! + pass + pass if __name__ == "__main__": -- 2.39.2