From d490155524053adbbb27320a9d8b985ee276648a Mon Sep 17 00:00:00 2001 From: abn Date: Wed, 21 Aug 2019 13:48:12 +0200 Subject: [PATCH] Bug fix: MEDFileUMesh::Aggregate was incorrectly merging groups + family number conflicts were not handled properly. --- src/MEDLoader/MEDFileMesh.cxx | 159 ++++++++++++++++++++------- src/MEDLoader/MEDFileMesh.hxx | 2 +- src/MEDLoader/Swig/MEDLoaderTest3.py | 31 ++++++ 3 files changed, 151 insertions(+), 41 deletions(-) diff --git a/src/MEDLoader/MEDFileMesh.cxx b/src/MEDLoader/MEDFileMesh.cxx index 3cbf7d4e6..8cdf00b68 100644 --- a/src/MEDLoader/MEDFileMesh.cxx +++ b/src/MEDLoader/MEDFileMesh.cxx @@ -4673,7 +4673,7 @@ MCAuto MEDFileUMesh::Aggregate(const std::vector coos(sz); std::vector fam_coos(sz),num_coos(sz); - for(std::vector::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::Aggregate(const std::vector > m_fam,m_renum; std::map > > m_mesh2; std::map > m_mesh; - std::map map1; - std::map > map2; - for(std::vector::const_iterator it=meshes.begin();it!=meshes.end();it++,i++) + std::map famNumMap; + std::map famNumMap_rev; + std::map > grpFamMap; + + // Identify min family number used: + int min_fam_num(0); + for(const auto& msh : meshes) + { + const std::map& 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::const_iterator it2=levs.begin();it2!=levs.end();it2++) + + const std::map& locMap1(msh->getFamilyInfo()); + std::map substitute; + std::map 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 >& 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 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 >& locMap2(msh->getGroupInfo()); + for(const auto& grpItem : locMap2) { - MCAuto 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 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& locMap1((*it)->getFamilyInfo()); - for(std::map::const_iterator it3=locMap1.begin();it3!=locMap1.end();it3++) - map1[(*it3).first]=(*it3).second; - const std::map >& locMap2((*it)->getGroupInfo()); - for(std::map >::const_iterator it4=locMap2.begin();it4!=locMap2.end();it4++) - map2[(*it4).first]=(*it4).second; } // Easy part : nodes MCAuto ret(MEDFileUMesh::New()); @@ -4726,40 +4805,40 @@ MCAuto MEDFileUMesh::Aggregate(const std::vectorsetRenumFieldArr(1,num_coo); } // cells - for(std::vector::const_iterator it=levs.begin();it!=levs.end();it++) + for(const auto& level : levs) { - std::map >::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 mesh(MEDCouplingUMesh::MergeUMeshes((*it2).second)); mesh->setCoords(coo); mesh->setName(ref->getName()); MCAuto renum(mesh->sortCellsInMEDFileFrmt()); - ret->setMeshAtLevel(*it,mesh); - std::map >::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& fams((*it3).second); + if(std::find(fams.begin(),fams.end(),(const DataArrayInt *)0)==fams.end()) { - const std::vector& fams((*it3).second); - if(std::find(fams.begin(),fams.end(),(const DataArrayInt *)0)==fams.end()) - { - MCAuto famm(DataArrayInt::Aggregate(fams)); - famm->renumberInPlace(renum->begin()); - ret->setFamilyFieldArr(*it,famm); - } + MCAuto 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& renums((*it4).second); + if(std::find(renums.begin(),renums.end(),(const DataArrayInt *)0)==renums.end()) { - const std::vector& renums((*it4).second); - if(std::find(renums.begin(),renums.end(),(const DataArrayInt *)0)==renums.end()) - { - MCAuto renumm(DataArrayInt::Aggregate(renums)); - renumm->renumberInPlace(renum->begin()); - ret->setRenumFieldArr(*it,renumm); - } + MCAuto 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; } diff --git a/src/MEDLoader/MEDFileMesh.hxx b/src/MEDLoader/MEDFileMesh.hxx index ff7eb59f6..28b4e379a 100644 --- a/src/MEDLoader/MEDFileMesh.hxx +++ b/src/MEDLoader/MEDFileMesh.hxx @@ -389,7 +389,7 @@ namespace MEDCoupling private: std::vector< MCAuto > _ms; MCAuto _coords; - MCAuto _fam_coords; + MCAuto _fam_coords; ///< Node family indices MCAuto _num_coords; MCAuto _global_num_coords; MCAuto _name_coords; diff --git a/src/MEDLoader/Swig/MEDLoaderTest3.py b/src/MEDLoader/Swig/MEDLoaderTest3.py index 7117bd5c6..f476f9ad7 100644 --- a/src/MEDLoader/Swig/MEDLoaderTest3.py +++ b/src/MEDLoader/Swig/MEDLoaderTest3.py @@ -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" -- 2.39.2