From 8bae03a55f48814db1d747c9ef8a8ee51d64e6d4 Mon Sep 17 00:00:00 2001 From: Anthony Geay Date: Fri, 18 Oct 2019 14:18:29 +0200 Subject: [PATCH] Addition of MEDFileMesh.zipFamilies --- src/MEDLoader/MEDFileMesh.cxx | 82 +++++++++++++++++++++++++++- src/MEDLoader/MEDFileMesh.hxx | 1 + src/MEDLoader/Swig/MEDLoaderCommon.i | 1 + src/MEDLoader/Swig/MEDLoaderTest3.py | 70 ++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 2 deletions(-) diff --git a/src/MEDLoader/MEDFileMesh.cxx b/src/MEDLoader/MEDFileMesh.cxx index fdeb3e13e..49d4755ae 100644 --- a/src/MEDLoader/MEDFileMesh.cxx +++ b/src/MEDLoader/MEDFileMesh.cxx @@ -766,7 +766,7 @@ std::vector MEDFileMesh::removeOrphanGroups() * family field whatever its level. Groups are updated in consequence, that is to say all groups lying on orphan family, will see their families list modified. * * \return - The list of removed families names. - * \sa MEDFileMesh::removeOrphanGroups. + * \sa MEDFileMesh::removeOrphanGroups , MEDFileMesh::removeFamiliesReferedByNoGroups */ std::vector MEDFileMesh::removeOrphanFamilies() { @@ -807,6 +807,7 @@ std::vector MEDFileMesh::removeOrphanFamilies() * this family is orphan or not. * * \warning this method is different from removeOrphanFamilies that scans family field array to find orphan families. + * \sa MEDFileMesh::removeOrphanFamilies */ void MEDFileMesh::removeFamiliesReferedByNoGroups() { @@ -829,7 +830,7 @@ void MEDFileMesh::removeFamiliesReferedByNoGroups() * * This method also raises an exception if a family belonging to a group has also id 0 (which is not right in MED file format). You should never encounter this case using addGroup method. * - * \sa MEDFileMesh::removeOrphanFamilies + * \sa MEDFileMesh::removeOrphanFamilies, MEDFileMesh::zipFamilies */ void MEDFileMesh::rearrangeFamilies() { @@ -874,6 +875,83 @@ void MEDFileMesh::rearrangeFamilies() removeOrphanFamilies(); } +/*! + * This method has no impact on existing groups. This method has only impact on families behind the groups. + * This method is especially useful for MED file structures having used too much families to define their groups and that need to be merged without modification of their groups. + * To zip families, firstly this method first removes families refered by no groups (see MEDFileMesh::removeFamiliesReferedByNoGroups), then this method puts together families lying on a same set of groups. If the set of families having same groups has a length higher than 1, the families are merged into a single family + * having the name of the first family appearing in family definition and with the corresponding family ID. + */ +void MEDFileMesh::zipFamilies() +{ + checkOrphanFamilyZero(); + removeFamiliesReferedByNoGroups(); + std::map< std::set , std::vector > setOfFamilies; + // firstly, store in setOfFamilies as key the common set of groups, and as value the families having such same set of groups + for(auto fam : _families) + { + std::vector grps( this->getGroupsOnFamily( fam.first ) ); + std::set sgrps(grps.begin(),grps.end()); + setOfFamilies[sgrps].push_back(fam.first); + } + // + std::map > newGroups(_groups); + std::map newFams(_families); + std::vector levels(getNonEmptyLevelsExt()); + std::map > famIdsToSubstitute; + // iterate on all different set of groups + std::set familiesToKill; + for(auto setOfCommonGrp : setOfFamilies) + { + if( setOfCommonGrp.second.size()<=1 ) + continue; + for(auto fam=setOfCommonGrp.second.begin()+1 ; fam != setOfCommonGrp.second.end() ; fam++) + familiesToKill.insert(*fam); + } + // iterate on all different set of groups + for(auto setOfCommonGrp : setOfFamilies) + { + if( setOfCommonGrp.second.size()<=1 ) + continue; + std::string newFamName(setOfCommonGrp.second[0]); + auto newFamID(_families[newFamName]); + for(auto grpToBeModified : setOfCommonGrp.first) + { + std::vector newFamiliesForCurGrp(1,newFamName); + const std::vector& familiesOnCurGrp(_groups[grpToBeModified]); + const std::vector& familiesToZip(setOfCommonGrp.second); + std::for_each(familiesToZip.begin(),familiesToZip.end(),[&famIdsToSubstitute,this,newFamID](const std::string& elt) { famIdsToSubstitute[newFamID].push_back(this->getFamilyId(elt)); }); + // for each family shared by the current group only keep those not sharing setOfCommonGrp.second + std::for_each(familiesOnCurGrp.begin(),familiesOnCurGrp.end(),[&familiesToKill,&newFamiliesForCurGrp](const std::string& elt) + { if( familiesToKill.find(elt) == familiesToKill.end() ) { newFamiliesForCurGrp.push_back(elt); } }); + newGroups[grpToBeModified] = newFamiliesForCurGrp; + } + for(auto familyToKill = setOfCommonGrp.second.begin()+1 ; familyToKill != setOfCommonGrp.second.end(); ++familyToKill) + { + newFams.erase( newFams.find(*familyToKill) ); + } + + } + // apply modifications in datastructure + for(auto famIdsSubstSession : famIdsToSubstitute) + { + for(std::vector::const_iterator it=levels.begin();it!=levels.end();it++) + { + DataArrayInt *fams(nullptr); + try + { + fams=getFamilyFieldAtLevel(*it); + } + catch(INTERP_KERNEL::Exception& e) { } + if(!fams) + continue; + MCAuto idsToModif(fams->findIdsEqualList(famIdsSubstSession.second.data(),famIdsSubstSession.second.data()+famIdsSubstSession.second.size())); + fams->setPartOfValuesSimple3(famIdsSubstSession.first,idsToModif->begin(),idsToModif->end(),0,1,1); + } + } + _groups = newGroups; + _families = newFams; +} + /*! * This method only checks that "FAMILLE_ZERO" is orphan (not belonging to a group). */ diff --git a/src/MEDLoader/MEDFileMesh.hxx b/src/MEDLoader/MEDFileMesh.hxx index 28b4e379a..4b54ed0ce 100644 --- a/src/MEDLoader/MEDFileMesh.hxx +++ b/src/MEDLoader/MEDFileMesh.hxx @@ -143,6 +143,7 @@ namespace MEDCoupling MEDLOADER_EXPORT std::vector removeOrphanFamilies(); MEDLOADER_EXPORT void removeFamiliesReferedByNoGroups(); MEDLOADER_EXPORT void rearrangeFamilies(); + MEDLOADER_EXPORT void zipFamilies(); MEDLOADER_EXPORT void checkOrphanFamilyZero() const; MEDLOADER_EXPORT void changeGroupName(const std::string& oldName, const std::string& newName); MEDLOADER_EXPORT void changeFamilyName(const std::string& oldName, const std::string& newName); diff --git a/src/MEDLoader/Swig/MEDLoaderCommon.i b/src/MEDLoader/Swig/MEDLoaderCommon.i index 45a411744..dd03b5580 100644 --- a/src/MEDLoader/Swig/MEDLoaderCommon.i +++ b/src/MEDLoader/Swig/MEDLoaderCommon.i @@ -1118,6 +1118,7 @@ namespace MEDCoupling std::vector removeOrphanFamilies(); void removeFamiliesReferedByNoGroups(); void rearrangeFamilies(); + void zipFamilies(); void checkOrphanFamilyZero() const; void changeGroupName(const std::string& oldName, const std::string& newName); void changeFamilyName(const std::string& oldName, const std::string& newName); diff --git a/src/MEDLoader/Swig/MEDLoaderTest3.py b/src/MEDLoader/Swig/MEDLoaderTest3.py index 158a046cf..1b51583a4 100644 --- a/src/MEDLoader/Swig/MEDLoaderTest3.py +++ b/src/MEDLoader/Swig/MEDLoaderTest3.py @@ -6658,6 +6658,76 @@ class MEDLoaderTest3(unittest.TestCase): self.assertIn(fmts.getHeapMemorySize(),range(refSize,refSize+refSize//10)) pass + def testZipFamilies1(self): + """ + MEDFileMesh.zipFamilies tries to reduce family partitions under groups. + """ + mname="mesh" + arr=DataArrayDouble(10) ; arr.iota() + m=MEDCouplingCMesh() + m.setCoords(arr,arr) + m=m.buildUnstructured() + m.setName(mname) + # + mm=MEDFileUMesh() + mm[0]=m + for i in range(m.getNumberOfCells()): + d = DataArrayInt([i]) + d.setName("grp%d"%i) + mm.addGroup(0,d) + pass + + grp_all = DataArrayInt.Range(0,m.getNumberOfCells(),1) + grp_all.setName("grp_all") + mm.addGroup(0,grp_all) + for i in range(m.getNumberOfCells()): + mm.removeGroup("grp{}".format(i)) + pass + # + mm.zipFamilies() # the method to test + # + self.assertEqual(mm.getGroupsNames(),("grp_all",)) + self.assertEqual(len(mm.getFamiliesNames()),1) + self.assertTrue(mm.getGroupArr(0,"grp_all").isEqualWithoutConsideringStr(DataArrayInt.Range(0,81,1))) + pass + + def testZipFamilies2(self): + """ + MEDFileMesh.zipFamilies tries to reduce family partitions under groups. + """ + mname="mesh" + arr=DataArrayDouble(21) ; arr.iota() + m=MEDCouplingCMesh() + m.setCoords(arr) + m=m.buildUnstructured() + m.setName(mname) + # + mm=MEDFileUMesh() + mm[0]=m + # 1 and 3 to be merged + # 2 and 5 to be merged + mm.setFamilyFieldArr(0,DataArrayInt([-1,-1,-2,-3,-8, 0,-7,-7,-1,0, -6,-2,-5,-5,-2, -2,-2,-5,-4,-3])) + for i in range(1,9): + mm.setFamilyId("Fam_{}".format(i),-i) + mm.setFamiliesOnGroup("grp0",["Fam_1","Fam_3","Fam_6"]) + mm.setFamiliesOnGroup("grp1",["Fam_1","Fam_2","Fam_3","Fam_5","Fam_6"]) + mm.setFamiliesOnGroup("grp2",["Fam_2","Fam_5","Fam_6","Fam_7"]) + # + grp0=DataArrayInt([0,1,3,8,10,19]) + grp1=DataArrayInt([0,1,2,3,8,10,11,12,13,14,15,16,17,19]) + grp2=DataArrayInt([2,6,7,10,11,12,13,14,15,16,17]) + self.assertTrue(mm.getGroupArr(0,"grp0").isEqualWithoutConsideringStr(grp0)) + self.assertTrue(mm.getGroupArr(0,"grp1").isEqualWithoutConsideringStr(grp1)) + self.assertTrue(mm.getGroupArr(0,"grp2").isEqualWithoutConsideringStr(grp2)) + self.assertEqual(mm.getGroupsNames(),('grp0','grp1','grp2')) + mm.zipFamilies() + self.assertEqual(mm.getGroupsNames(),('grp0','grp1','grp2')) + self.assertTrue(mm.getGroupArr(0,"grp0").isEqualWithoutConsideringStr(grp0)) + self.assertTrue(mm.getGroupArr(0,"grp1").isEqualWithoutConsideringStr(grp1)) + self.assertTrue(mm.getGroupArr(0,"grp2").isEqualWithoutConsideringStr(grp2)) + self.assertEqual(mm.getFamiliesNames(),('Fam_1','Fam_2','Fam_6','Fam_7')) + pass + pass if __name__ == "__main__": -- 2.39.2