X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FMEDLoader%2FMEDFileMesh.cxx;h=49d4755ae2f54b4e6003d36b6e23d7c220aabc70;hb=8bae03a55f48814db1d747c9ef8a8ee51d64e6d4;hp=13493cfdb2ed3f7dc29e2e1161bf371afa729b14;hpb=8210342873f7be4a650c18c7875cc4ec2a8e4d86;p=tools%2Fmedcoupling.git diff --git a/src/MEDLoader/MEDFileMesh.cxx b/src/MEDLoader/MEDFileMesh.cxx index 13493cfdb..49d4755ae 100644 --- a/src/MEDLoader/MEDFileMesh.cxx +++ b/src/MEDLoader/MEDFileMesh.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2016 CEA/DEN, EDF R&D +// Copyright (C) 2007-2019 CEA/DEN, EDF R&D // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -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() { @@ -826,8 +827,10 @@ void MEDFileMesh::removeFamiliesReferedByNoGroups() * This method has no impact on groups. This method only works on families. This method firstly removes families not referred by any groups in \a this, then all unused entities * are put as belonging to family 0 ("FAMILLE_ZERO"). Finally, all orphanFamilies are killed. * This method raises an exception if "FAMILLE_ZERO" is already belonging to a group. + * + * 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() { @@ -837,7 +840,17 @@ void MEDFileMesh::rearrangeFamilies() std::vector levels(getNonEmptyLevelsExt()); std::set idsRefed; for(std::map::const_iterator it=_families.begin();it!=_families.end();it++) - idsRefed.insert((*it).second); + { + idsRefed.insert((*it).second); + if((*it).second==0) + { + if(!getGroupsOnFamily((*it).first).empty()) + { + std::ostringstream oss; oss << "MEDFileMesh::rearrangeFamilies : Not orphan family \"" << (*it).first << "\" has id 0 ! This method may alterate groups in this for such a case !"; + throw INTERP_KERNEL::Exception(oss.str()); + } + } + } for(std::vector::const_iterator it=levels.begin();it!=levels.end();it++) { const DataArrayInt *fams(0); @@ -862,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). */ @@ -4654,6 +4744,11 @@ MCAuto MEDFileUMesh::symmetry3DPlane(const double point[3], const return ret; } +/*! + * Aggregate the given MEDFileUMesh objects into a single mesh. When groups are present, those are + * merged in such a way that the final mesh contain all of them. + * \return a new object. + */ MCAuto MEDFileUMesh::Aggregate(const std::vector& meshes) { if(meshes.empty()) @@ -4661,7 +4756,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 !"); @@ -4675,29 +4770,123 @@ 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; + std::set< MCAuto > mem_cleanup; // Memory clean-up. At set deletion (end of method), arrays will be deallocated. + + // Identify min family number used: + int min_fam_num(0); + for(const auto& msh : meshes) { - if((*it)->getSpaceDimension()!=spaceDim) + 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(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 + mem_cleanup.insert(MCAuto(dai)); // Make sure array will decrRef() at end of method + 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 std::string& grpName = grpItem.first; + std::vector famLst; + // Substitute family name in group description if needed: + if (fam_conflict) + { + famLst = grpItem.second; + for (const auto& sub : substitute) + std::replace(famLst.begin(), famLst.end(), sub.first, sub.second); + } + else + famLst = grpItem.second; + + // Potentially merge groups (if same name): + const auto& it = grpFamMap.find(grpName); + if (it != grpFamMap.end()) + { + // Group already exists, merge should be done. Normally we whould never + // have twice the same family name in famLstCur and famLst since we dealt with family number + // conflict just above ... + std::vector& famLstCur = (*it).second; + famLstCur.insert(famLstCur.end(), famLst.begin(), famLst.end()); + } + else + grpFamMap[grpName] = 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()); @@ -4714,40 +4903,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; } @@ -5825,7 +6014,7 @@ void MEDFileStructuredMesh::setNameFieldAtLevel(int meshDimRelToMaxExt, DataArra { int nbCells=mesh->getNumberOfCellsOfSubLevelMesh(); nameArr->checkNbOfTuplesAndComp(nbCells,MED_SNAME_SIZE,"MEDFileStructuredMesh::setNameFieldAtLevel : Problem in size of names arr ! Mismatch with number of faces of mesh !"); - _names_cells=nameArr; + _names_faces=nameArr; } default: throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setNameFieldAtLevel : Only available for levels 0 or 1 or -1 !");