* 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()
{
* 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()
{
*
* 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()
{
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).
*/
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> MEDFileUMesh::Aggregate(const std::vector<const MEDFileUMesh *>& meshes)
{
if(meshes.empty())
std::map<std::string,int> famNumMap;
std::map<int, std::string> famNumMap_rev;
std::map<std::string, std::vector<std::string> > grpFamMap;
+ std::set< MCAuto<DataArrayInt> > 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);
// Family field - substitute new family number if needed:
if(fam_conflict)
{
- DataArrayInt *dai(msh->getFamilyFieldAtLevel(level)->deepCopy()); // Need a copy
+ DataArrayInt* dai(msh->getFamilyFieldAtLevel(level)->deepCopy()); // Need a copy
+ mem_cleanup.insert(MCAuto<DataArrayInt>(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);
const std::map<std::string, std::vector<std::string> >& locMap2(msh->getGroupInfo());
for(const auto& grpItem : locMap2)
{
- const auto& famLst = grpItem.second;
+ const std::string& grpName = grpItem.first;
+ std::vector<std::string> famLst;
// Substitute family name in group description if needed:
if (fam_conflict)
{
- std::vector<std::string> newLst(famLst); // Copy needed.
+ famLst = grpItem.second;
for (const auto& sub : substitute)
- std::replace(newLst.begin(), newLst.end(), sub.first, sub.second);
- grpFamMap[grpItem.first]=newLst;
+ std::replace(famLst.begin(), famLst.end(), sub.first, sub.second);
}
else
- grpFamMap[grpItem.first]=famLst;
+ 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<std::string>& famLstCur = (*it).second;
+ famLstCur.insert(famLstCur.end(), famLst.begin(), famLst.end());
+ }
+ else
+ grpFamMap[grpName] = famLst;
}
}
// Easy part : nodes
{
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 !");