]> SALOME platform Git repositories - tools/medcoupling.git/commitdiff
Salome HOME
Bug fix: MEDFileUMesh::Aggregate was incorrectly merging groups abn/aggreg
authorabn <adrien.bruneton@cea.fr>
Wed, 21 Aug 2019 11:48:12 +0000 (13:48 +0200)
committerabn <adrien.bruneton@cea.fr>
Wed, 21 Aug 2019 11:48:12 +0000 (13:48 +0200)
+ family number conflicts were not handled properly.

src/MEDLoader/MEDFileMesh.cxx
src/MEDLoader/MEDFileMesh.hxx
src/MEDLoader/Swig/MEDLoaderTest3.py

index 3cbf7d4e60ad9acf8832f9345254cb42aecc1e47..8cdf00b688f3e4ce13bea4a21d0cc77e96021e8c 100644 (file)
@@ -4673,7 +4673,7 @@ MCAuto<MEDFileUMesh> MEDFileUMesh::Aggregate(const std::vector<const MEDFileUMes
   std::size_t sz(meshes.size()),i(0);
   std::vector<const DataArrayDouble *> coos(sz);
   std::vector<const DataArrayInt *> fam_coos(sz),num_coos(sz);
-  for(std::vector<const MEDFileUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,i++)
+  for(auto it=meshes.begin();it!=meshes.end();it++,i++)
     {
       if(!(*it))
         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : presence of NULL pointer in input vector !");
@@ -4687,29 +4687,108 @@ MCAuto<MEDFileUMesh> MEDFileUMesh::Aggregate(const std::vector<const MEDFileUMes
   std::map<int, std::vector<const DataArrayInt *> > m_fam,m_renum;
   std::map<int, std::vector< MCAuto< MEDCouplingUMesh > > > m_mesh2;
   std::map<int, std::vector<const MEDCouplingUMesh *> > m_mesh;
-  std::map<std::string,int> map1;
-  std::map<std::string, std::vector<std::string> > map2;
-  for(std::vector<const MEDFileUMesh *>::const_iterator it=meshes.begin();it!=meshes.end();it++,i++)
+  std::map<std::string,int> famNumMap;
+  std::map<int, std::string> famNumMap_rev;
+  std::map<std::string, std::vector<std::string> > grpFamMap;
+
+  // Identify min family number used:
+  int min_fam_num(0);
+  for(const auto& msh : meshes)
+    {
+      const std::map<std::string,int>& locMap1(msh->getFamilyInfo());
+      for(const auto& it3 : locMap1)
+        if(it3.second < min_fam_num)
+          min_fam_num = it3.second;
+    }
+
+  for(const auto& msh : meshes)
     {
-      if((*it)->getSpaceDimension()!=spaceDim)
+      if(msh->getSpaceDimension()!=spaceDim)
         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : space dimension must be homogeneous !");
-      if((*it)->getMeshDimension()!=meshDim)
+      if(msh->getMeshDimension()!=meshDim)
         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : mesh dimension must be homogeneous !");
-      if((*it)->getNonEmptyLevels()!=levs)
+      if(msh->getNonEmptyLevels()!=levs)
         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : levels must be the same for elements in input vector !");
-      for(std::vector<int>::const_iterator it2=levs.begin();it2!=levs.end();it2++)
+
+      const std::map<std::string,int>& locMap1(msh->getFamilyInfo());
+      std::map<std::string, std::string> substitute;
+      std::map<int, int> substituteN;
+      bool fam_conflict(false);
+      for(const auto& it3 : locMap1)
+        {
+          const std::string& famName = it3.first;
+          int famNum = it3.second;
+          if (famNumMap_rev.find(famNum) != famNumMap_rev.end()) // Family number is already used!
+            {
+              // Is it used by a group of the current mesh or a group from a previous mesh?
+              // If not, this is OK (typically -1 familly).
+              bool used = false;
+              //    Current mesh
+              const std::map<std::string, std::vector<std::string> >& locMap2(msh->getGroupInfo());
+              for(const auto& it4 : locMap2)
+                {
+                  const auto& famLst = it4.second;
+                  if (std::find(famLst.begin(), famLst.end(), famName) != famLst.end())
+                    { used = true; break; }
+                }
+              //    Previous meshes ...
+              if (!used)
+                for(const auto& it4 : grpFamMap)
+                  {
+                    const auto& famLst = it4.second;
+                    if (std::find(famLst.begin(), famLst.end(), famName) != famLst.end())
+                      { used = true; break; }
+                  }
+
+              if(used)
+                { // Generate a new family name, and a new family number
+                  fam_conflict = true;
+                  std::ostringstream oss;
+                  oss << "Family_" << --min_fam_num;  // New ID
+                  std::string new_name(oss.str());
+                  substitute[famName] = new_name;
+                  substituteN[famNum] = min_fam_num;
+                  famNumMap[new_name] = min_fam_num;
+                  famNumMap_rev[min_fam_num] = new_name;
+                }
+            }
+          famNumMap[famName] = famNum;
+          famNumMap_rev[famNum] = famName;
+        }
+
+      for(const auto& level : levs)
+        {
+          MCAuto<MEDCouplingUMesh> locMesh(msh->getMeshAtLevel(level));
+          m_mesh[level].push_back(locMesh); m_mesh2[level].push_back(locMesh);
+          m_renum[level].push_back(msh->getNumberFieldAtLevel(level));
+
+          // Family field - substitute new family number if needed:
+          if(fam_conflict)
+            {
+              DataArrayInt *dai(msh->getFamilyFieldAtLevel(level)->deepCopy());  // Need a copy
+              for (const auto& subN : substituteN)
+                dai->changeValue(subN.first, subN.second);
+              m_fam[level].push_back(dai);
+            }
+          else
+            m_fam[level].push_back(msh->getFamilyFieldAtLevel(level));      // No copy needed
+        }
+
+      const std::map<std::string, std::vector<std::string> >& locMap2(msh->getGroupInfo());
+      for(const auto& grpItem : locMap2)
         {
-          MCAuto<MEDCouplingUMesh> locMesh((*it)->getMeshAtLevel(*it2));
-          m_mesh[*it2].push_back(locMesh); m_mesh2[*it2].push_back(locMesh);
-          m_fam[*it2].push_back((*it)->getFamilyFieldAtLevel(*it2));
-          m_renum[*it2].push_back((*it)->getNumberFieldAtLevel(*it2));
+          const auto& famLst = grpItem.second;
+          // Substitute family name in group description if needed:
+          if (fam_conflict)
+            {
+              std::vector<std::string> newLst(famLst);   // Copy needed.
+              for (const auto& sub : substitute)
+                std::replace(newLst.begin(), newLst.end(), sub.first, sub.second);
+              grpFamMap[grpItem.first]=newLst;
+            }
+          else
+            grpFamMap[grpItem.first]=famLst;
         }
-      const std::map<std::string,int>& locMap1((*it)->getFamilyInfo());
-      for(std::map<std::string,int>::const_iterator it3=locMap1.begin();it3!=locMap1.end();it3++)
-        map1[(*it3).first]=(*it3).second;
-      const std::map<std::string, std::vector<std::string> >& locMap2((*it)->getGroupInfo());
-      for(std::map<std::string, std::vector<std::string> >::const_iterator it4=locMap2.begin();it4!=locMap2.end();it4++)
-        map2[(*it4).first]=(*it4).second;
     }
   // Easy part : nodes
   MCAuto<MEDFileUMesh> ret(MEDFileUMesh::New());
@@ -4726,40 +4805,40 @@ MCAuto<MEDFileUMesh> MEDFileUMesh::Aggregate(const std::vector<const MEDFileUMes
       ret->setRenumFieldArr(1,num_coo);
     }
   // cells
-  for(std::vector<int>::const_iterator it=levs.begin();it!=levs.end();it++)
+  for(const auto& level : levs)
     {
-      std::map<int, std::vector<const MEDCouplingUMesh *> >::const_iterator it2(m_mesh.find(*it));
+      auto it2(m_mesh.find(level));
       if(it2==m_mesh.end())
         throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : internal error 1 !");
       MCAuto<MEDCouplingUMesh> mesh(MEDCouplingUMesh::MergeUMeshes((*it2).second));
       mesh->setCoords(coo); mesh->setName(ref->getName());
       MCAuto<DataArrayInt> renum(mesh->sortCellsInMEDFileFrmt());
-      ret->setMeshAtLevel(*it,mesh);
-      std::map<int, std::vector<const DataArrayInt *> >::const_iterator it3(m_fam.find(*it)),it4(m_renum.find(*it));
-      if(it3!=m_fam.end())
+      ret->setMeshAtLevel(level,mesh);
+      auto it3(m_fam.find(level)),it4(m_renum.find(level));
+      if(it3==m_fam.end()) // Should never happen (all levels exist for all meshes)
+        throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : internal error 2!");
+      if(it4==m_renum.end())
+        throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : internal error 3!");
+      // Set new family field if it was defined for all input meshes
+      const std::vector<const DataArrayInt *>& fams((*it3).second);
+      if(std::find(fams.begin(),fams.end(),(const DataArrayInt *)0)==fams.end())
         {
-          const std::vector<const DataArrayInt *>& fams((*it3).second);
-          if(std::find(fams.begin(),fams.end(),(const DataArrayInt *)0)==fams.end())
-            {
-              MCAuto<DataArrayInt> famm(DataArrayInt::Aggregate(fams));
-              famm->renumberInPlace(renum->begin());
-              ret->setFamilyFieldArr(*it,famm);
-            }
+          MCAuto<DataArrayInt> famm(DataArrayInt::Aggregate(fams));
+          famm->renumberInPlace(renum->begin());
+          ret->setFamilyFieldArr(level,famm);
         }
-      if(it4!=m_renum.end())
+      // Set optional number field if defined for all input meshes:
+      const std::vector<const DataArrayInt *>& renums((*it4).second);
+      if(std::find(renums.begin(),renums.end(),(const DataArrayInt *)0)==renums.end())
         {
-          const std::vector<const DataArrayInt *>& renums((*it4).second);
-          if(std::find(renums.begin(),renums.end(),(const DataArrayInt *)0)==renums.end())
-            {
-              MCAuto<DataArrayInt> renumm(DataArrayInt::Aggregate(renums));
-              renumm->renumberInPlace(renum->begin());
-              ret->setRenumFieldArr(*it,renumm);
-            }
+          MCAuto<DataArrayInt> renumm(DataArrayInt::Aggregate(renums));
+          renumm->renumberInPlace(renum->begin());
+          ret->setRenumFieldArr(level,renumm);
         }
     }
   //
-  ret->setFamilyInfo(map1);
-  ret->setGroupInfo(map2);
+  ret->setFamilyInfo(famNumMap);
+  ret->setGroupInfo(grpFamMap);
   ret->setName(ref->getName());
   return ret;
 }
index ff7eb59f6e0e692cb9d9ed884bc10a102c08c01c..28b4e379a4e35c264d5116c647c40a4ecb787b04 100644 (file)
@@ -389,7 +389,7 @@ namespace MEDCoupling
   private:
     std::vector< MCAuto<MEDFileUMeshSplitL1> > _ms;
     MCAuto<DataArrayDouble> _coords;
-    MCAuto<DataArrayInt> _fam_coords;
+    MCAuto<DataArrayInt> _fam_coords;     ///< Node family indices
     MCAuto<DataArrayInt> _num_coords;
     MCAuto<DataArrayInt> _global_num_coords;
     MCAuto<DataArrayAsciiChar> _name_coords;
index 7117bd5c66b4c9d264d6d9144c378683ac63c83b..f476f9ad7429f5d0cad11c42b36f7c6b573f9520 100644 (file)
@@ -5900,6 +5900,37 @@ class MEDLoaderTest3(unittest.TestCase):
         CheckMFD(self,mfd)
         pass
 
+    @WriteInTmpDir
+    def testAggregateWithGroups(self):
+        """ Testing MEDFileUMesh::Aggretate when groups are present. """
+        def generate(grp_name, offset):
+            coo = DataArrayDouble([0., 1., 2.])
+            coo += offset
+            m = MEDCouplingCMesh("toto")
+            m.setCoords(coo, coo)
+            m = m.buildUnstructured()
+            mu = MEDFileUMesh.New()
+            mu.setMeshAtLevel(0, m)
+            g = DataArrayInt([0])
+            g.setName(grp_name)
+            mu.setGroupsAtLevel(0, [g])
+            return mu
+
+        m1 = generate("A", 0.)
+        m2 = generate("B", 2.)
+        mm = MEDFileUMesh.Aggregate([m1,m2])
+
+        self.assertEqual(mm.getFamilyFieldAtLevel(0).getValues(), [-2, -1, -1, -1, -3, -1, -1, -1])
+        self.assertEqual(mm.getNumberFieldAtLevel(0), None)
+        refFamIds=[('Family_-1',-1),('Family_-2',-2),('Family_-3',-3)]
+        self.assertEqual(set(mm.getFamiliesNames()),set([elt[0] for elt in refFamIds]))
+        self.assertEqual(set([mm.getFamilyId(elt) for elt in mm.getFamiliesNames()]),set([elt[1] for elt in refFamIds]))
+        self.assertEqual(mm.getGroupsNames(),('A','B'))
+        self.assertEqual(mm.getGroupArr(0, 'A').getValues(), [0])
+        self.assertEqual(mm.getGroupArr(0, 'B').getValues(), [4])
+
+        pass
+
     @WriteInTmpDir
     def testExtrudedMesh1(self):
         fname="Pyfile107.med"