]> SALOME platform Git repositories - tools/medcoupling.git/commitdiff
Salome HOME
Addition of MEDFileMesh.zipFamilies
authorAnthony Geay <anthony.geay@edf.fr>
Fri, 18 Oct 2019 12:18:29 +0000 (14:18 +0200)
committerAnthony Geay <anthony.geay@edf.fr>
Fri, 18 Oct 2019 12:18:29 +0000 (14:18 +0200)
src/MEDLoader/MEDFileMesh.cxx
src/MEDLoader/MEDFileMesh.hxx
src/MEDLoader/Swig/MEDLoaderCommon.i
src/MEDLoader/Swig/MEDLoaderTest3.py

index fdeb3e13e84e73a655e43b21bcb1c87cf2bf2ed8..49d4755ae2f54b4e6003d36b6e23d7c220aabc70 100644 (file)
@@ -766,7 +766,7 @@ std::vector<std::string> 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<std::string> MEDFileMesh::removeOrphanFamilies()
 {
@@ -807,6 +807,7 @@ std::vector<std::string> 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::string> , std::vector<std::string> > 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<std::string> grps( this->getGroupsOnFamily( fam.first ) );
+      std::set<std::string> sgrps(grps.begin(),grps.end());
+      setOfFamilies[sgrps].push_back(fam.first);
+    }
+  //
+  std::map<std::string, std::vector<std::string> > newGroups(_groups);
+  std::map<std::string,int> newFams(_families);
+  std::vector<int> levels(getNonEmptyLevelsExt());
+  std::map<int, std::vector<int> > famIdsToSubstitute;
+  // iterate on all different set of groups
+  std::set<std::string> 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<std::string> newFamiliesForCurGrp(1,newFamName);
+          const std::vector<std::string>& familiesOnCurGrp(_groups[grpToBeModified]);
+          const std::vector<std::string>& 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<int>::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<DataArrayInt> 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).
  */
index 28b4e379a4e35c264d5116c647c40a4ecb787b04..4b54ed0ce177913ba62148c0a80270d4d82d434f 100644 (file)
@@ -143,6 +143,7 @@ namespace MEDCoupling
     MEDLOADER_EXPORT std::vector<std::string> 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);
index 45a411744012ddc9e9209d5ef68cbdc6f0117132..dd03b5580d858ba9103248928473bddf0e4823e4 100644 (file)
@@ -1118,6 +1118,7 @@ namespace MEDCoupling
     std::vector<std::string> 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);
index 158a046cfc0866a512f28637bb493082d344bfbc..1b51583a4ef23e938899336710d380c9d28b3cbd 100644 (file)
@@ -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__":