X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FMEDLoader%2FMEDFileMesh.cxx;h=49d4755ae2f54b4e6003d36b6e23d7c220aabc70;hb=8bae03a55f48814db1d747c9ef8a8ee51d64e6d4;hp=3d59c0b9544d51bdee37dc4971d4b9ba9c913750;hpb=6ebb06512fe4733596a3e5414d97303d67ee5cc0;p=tools%2Fmedcoupling.git diff --git a/src/MEDLoader/MEDFileMesh.cxx b/src/MEDLoader/MEDFileMesh.cxx index 3d59c0b95..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 @@ -513,7 +513,7 @@ std::vector MEDFileMesh::getFamiliesNames() const * Returns names of all families of \a this mesh but like they would be in file. * This method is here only for MED file families gurus. If you are a kind user forget this method :-) * This method is only useful for aggressive users that want to have in their file a same family lying both on cells and on nodes. This is not a good idea for lisibility ! - * For your information internaly in memory such families are renamed to have a nicer API. + * For your information internally in memory such families are renamed to have a nicer API. */ std::vector MEDFileMesh::getFamiliesNamesWithFilePointOfView() const { @@ -673,6 +673,35 @@ std::vector MEDFileMesh::removeEmptyGroups() return ret; } +void MEDFileMesh::removeGroupAtLevel(int meshDimRelToMaxExt, const std::string& name) +{ + std::map >::iterator it(_groups.find(name)); + std::vector grps(getGroupsNames()); + if(it==_groups.end()) + { + std::ostringstream oss; oss << "No such groupname \"" << name << "\" !\nAvailable groups are :"; + std::copy(grps.begin(),grps.end(),std::ostream_iterator(oss," ")); + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + const std::vector &famsOnGrp((*it).second); + std::vector famIds(getFamiliesIdsOnGroup(name)); + const DataArrayInt *famArr(getFamilyFieldAtLevel(meshDimRelToMaxExt)); + if(!famArr) + return ; + MCAuto vals(famArr->getDifferentValues()); + MCAuto famIds2(DataArrayInt::NewFromStdVector(famIds)); + MCAuto idsToKill(famIds2->buildIntersection(vals)); + if(idsToKill->empty()) + return ; + std::vector newFamsOnGrp; + for(std::vector::const_iterator it=famsOnGrp.begin();it!=famsOnGrp.end();it++) + { + if(!idsToKill->presenceOfValue(getFamilyId(*it))) + newFamsOnGrp.push_back(*it); + } + (*it).second=newFamsOnGrp; +} + /*! * Removes a group from \a this mesh. * \param [in] name - the name of the group to remove. @@ -680,9 +709,8 @@ std::vector MEDFileMesh::removeEmptyGroups() */ void MEDFileMesh::removeGroup(const std::string& name) { - std::string oname(name); - std::map >::iterator it=_groups.find(oname); - std::vector grps=getGroupsNames(); + std::map >::iterator it=_groups.find(name); + std::vector grps(getGroupsNames()); if(it==_groups.end()) { std::ostringstream oss; oss << "No such groupname \"" << name << "\" !\nAvailable groups are :"; @@ -738,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() { @@ -779,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() { @@ -795,11 +824,13 @@ void MEDFileMesh::removeFamiliesReferedByNoGroups() } /*! - * This method has no impact on groups. This method only works on families. This method firstly removes families not refered by any groups in \a this, then all unused entities + * 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() { @@ -809,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); @@ -834,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). */ @@ -1256,6 +1374,19 @@ void MEDFileMesh::addFamilyOnAllGroupsHaving(const std::string& famName, const s } } +void MEDFileMesh::checkNoGroupClash(const DataArrayInt *famArr, const std::string& grpName) const +{ + std::vector grpsNames(getGroupsNames()); + if(std::find(grpsNames.begin(),grpsNames.end(),grpName)==grpsNames.end()) + return ; + std::vector famIds(getFamiliesIdsOnGroup(grpName)); + if(famArr->presenceOfValue(famIds)) + { + std::ostringstream oss; oss << "MEDFileUMesh::addGroup : Group with name \"" << grpName << "\" already exists at specified level ! Destroy it before calling this method !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } +} + /*! * \param [in] ids ids and group name of the new group to add. The ids should be sorted and different each other (MED file norm). * \parma [in,out] famArr family array on level of interest to be renumbered. The input pointer should be not \c NULL (no check of that will be performed) @@ -1268,13 +1399,8 @@ void MEDFileMesh::addGroupUnderground(bool isNodeGroup, const DataArrayInt *ids, if(grpName.empty()) throw INTERP_KERNEL::Exception("MEDFileUMesh::addGroup : empty group name ! MED file format do not accept empty group name !"); ids->checkStrictlyMonotonic(true); - famArr->incrRef(); MCAuto famArrTmp(famArr); - std::vector grpsNames=getGroupsNames(); - if(std::find(grpsNames.begin(),grpsNames.end(),grpName)!=grpsNames.end()) - { - std::ostringstream oss; oss << "MEDFileUMesh::addGroup : Group with name \"" << grpName << "\" already exists ! Destroy it before calling this method !"; - throw INTERP_KERNEL::Exception(oss.str().c_str()); - } + checkNoGroupClash(famArr,grpName); + MCAuto famArrTmp; famArrTmp.takeRef(famArr); std::list< MCAuto > allFamIds(getAllNonNullFamilyIds()); allFamIds.erase(std::find(allFamIds.begin(),allFamIds.end(),famArrTmp)); MCAuto famIds=famArr->selectByTupleIdSafe(ids->begin(),ids->end()); @@ -1297,7 +1423,7 @@ void MEDFileMesh::addGroupUnderground(bool isNodeGroup, const DataArrayInt *ids, bool isFamPresent=false; for(std::list< MCAuto >::const_iterator itl=allFamIds.begin();itl!=allFamIds.end() && !isFamPresent;itl++) isFamPresent=(*itl)->presenceOfValue(*famId); - if(!isFamPresent) + if(!isFamPresent && *famId!=0) { familyIds.push_back(*famId); idsPerfamiliyIds.push_back(ret0); fams.push_back(FindOrCreateAndGiveFamilyWithId(families,*famId,created)); } // adding *famId in grp else { @@ -1331,8 +1457,15 @@ void MEDFileMesh::addGroupUnderground(bool isNodeGroup, const DataArrayInt *ids, famArr->setPartOfValuesSimple3(familyIds[i],da->begin(),da->end(),0,1,1); } _families=families; + std::map >::iterator itt(groups.find(grpName)); + if(itt!=groups.end()) + { + std::vector& famsOnGrp((*itt).second); + famsOnGrp.insert(famsOnGrp.end(),fams.begin(),fams.end()); + } + else + groups[grpName]=fams; _groups=groups; - _groups[grpName]=fams; } void MEDFileMesh::changeAllGroupsContainingFamily(const std::string& familyNameToChange, const std::vector& newFamiliesNames) @@ -2282,7 +2415,7 @@ MEDFileUMesh *MEDFileUMesh::New(med_idt fid, MEDFileMeshReadSelector *mrs) } /*! - * \b WARNING this implementation is dependant from MEDCouplingMappedExtrudedMesh::buildUnstructured ! + * \b WARNING this implementation is dependent from MEDCouplingMappedExtrudedMesh::buildUnstructured ! * \sa MEDCouplingMappedExtrudedMesh::buildUnstructured , MEDCouplingMappedExtrudedMesh::build3DUnstructuredMesh */ MEDFileUMesh *MEDFileUMesh::New(const MEDCouplingMappedExtrudedMesh *mem) @@ -2357,6 +2490,7 @@ std::vector MEDFileUMesh::getDirectChildrenWithNull() c ret.push_back((const DataArrayDouble*)_coords); ret.push_back((const DataArrayInt *)_fam_coords); ret.push_back((const DataArrayInt *)_num_coords); + ret.push_back((const DataArrayInt *)_global_num_coords); ret.push_back((const DataArrayInt *)_rev_num_coords); ret.push_back((const DataArrayAsciiChar *)_name_coords); ret.push_back((const PartDefinition *)_part_coords); @@ -2382,15 +2516,17 @@ MEDFileUMesh *MEDFileUMesh::deepCopy() const { MCAuto ret(new MEDFileUMesh(*this)); ret->deepCpyEquivalences(*this); - if((const DataArrayDouble*)_coords) + if(_coords.isNotNull()) ret->_coords=_coords->deepCopy(); - if((const DataArrayInt*)_fam_coords) + if(_fam_coords.isNotNull()) ret->_fam_coords=_fam_coords->deepCopy(); - if((const DataArrayInt*)_num_coords) + if(_num_coords.isNotNull()) ret->_num_coords=_num_coords->deepCopy(); - if((const DataArrayInt*)_rev_num_coords) + if(_global_num_coords.isNotNull()) + ret->_global_num_coords=_global_num_coords->deepCopy(); + if(_rev_num_coords.isNotNull()) ret->_rev_num_coords=_rev_num_coords->deepCopy(); - if((const DataArrayAsciiChar*)_name_coords) + if(_name_coords.isNotNull()) ret->_name_coords=_name_coords->deepCopy(); std::size_t i=0; for(std::vector< MCAuto >::const_iterator it=_ms.begin();it!=_ms.end();it++,i++) @@ -2438,54 +2574,74 @@ bool MEDFileUMesh::isEqual(const MEDFileMesh *other, double eps, std::string& wh return false; } } - const DataArrayInt *famc1=_fam_coords; - const DataArrayInt *famc2=otherC->_fam_coords; - if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0)) - { - what="Mismatch of families arr on nodes ! One is defined and not other !"; - return false; - } - if(famc1) - { - bool ret=famc1->isEqual(*famc2); - if(!ret) - { - what="Families arr on node differ !"; - return false; - } - } - const DataArrayInt *numc1=_num_coords; - const DataArrayInt *numc2=otherC->_num_coords; - if((numc1==0 && numc2!=0) || (numc1!=0 && numc2==0)) - { - what="Mismatch of numbering arr on nodes ! One is defined and not other !"; - return false; - } - if(numc1) - { - bool ret=numc1->isEqual(*numc2); - if(!ret) - { - what="Numbering arr on node differ !"; - return false; - } - } - const DataArrayAsciiChar *namec1=_name_coords; - const DataArrayAsciiChar *namec2=otherC->_name_coords; - if((namec1==0 && namec2!=0) || (namec1!=0 && namec2==0)) - { - what="Mismatch of naming arr on nodes ! One is defined and not other !"; - return false; - } - if(namec1) - { - bool ret=namec1->isEqual(*namec2); - if(!ret) - { - what="Names arr on node differ !"; - return false; - } - } + { + const DataArrayInt *famc1(_fam_coords),*famc2(otherC->_fam_coords); + if((famc1==0 && famc2!=0) || (famc1!=0 && famc2==0)) + { + what="Mismatch of families arr on nodes ! One is defined and not other !"; + return false; + } + if(famc1) + { + bool ret=famc1->isEqual(*famc2); + if(!ret) + { + what="Families arr on node differ !"; + return false; + } + } + } + { + const DataArrayInt *numc1(_num_coords),*numc2(otherC->_num_coords); + if((numc1==0 && numc2!=0) || (numc1!=0 && numc2==0)) + { + what="Mismatch of numbering arr on nodes ! One is defined and not other !"; + return false; + } + if(numc1) + { + bool ret=numc1->isEqual(*numc2); + if(!ret) + { + what="Numbering arr on node differ !"; + return false; + } + } + } + { + const DataArrayInt *gnumc1(_global_num_coords),*gnumc2(otherC->_global_num_coords); + if((gnumc1==0 && gnumc2!=0) || (gnumc1!=0 && gnumc2==0)) + { + what="Mismatch of numbering arr on nodes ! One is defined and not other !"; + return false; + } + if(gnumc1) + { + bool ret=gnumc1->isEqual(*gnumc2); + if(!ret) + { + what="Global numbering arr on node differ !"; + return false; + } + } + } + { + const DataArrayAsciiChar *namec1(_name_coords),*namec2(otherC->_name_coords); + if((namec1==0 && namec2!=0) || (namec1!=0 && namec2==0)) + { + what="Mismatch of naming arr on nodes ! One is defined and not other !"; + return false; + } + if(namec1) + { + bool ret=namec1->isEqual(*namec2); + if(!ret) + { + what="Names arr on node differ !"; + return false; + } + } + } if(_ms.size()!=otherC->_ms.size()) { what="Number of levels differs !"; @@ -2534,15 +2690,15 @@ void MEDFileUMesh::checkConsistency() const throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): coords are null but some mesh parts are present!"); if (!_fam_coords) throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): coords are null but not the internal node family array!"); - if (!_num_coords || !_rev_num_coords) + if (_num_coords.isNotNull() || _rev_num_coords.isNotNull() || _global_num_coords.isNotNull()) throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): coords are null but not the internal node numbering array!"); } else { int nbCoo = _coords->getNumberOfTuples(); - if (_fam_coords) + if (_fam_coords.isNotNull()) _fam_coords->checkNbOfTuplesAndComp(nbCoo,1,"MEDFileUMesh::checkConsistency(): inconsistent internal node family array!"); - if (_num_coords) + if (_num_coords.isNotNull()) { _num_coords->checkNbOfTuplesAndComp(nbCoo,1,"MEDFileUMesh::checkConsistency(): inconsistent internal node numbering array!"); int pos; @@ -2550,6 +2706,10 @@ void MEDFileUMesh::checkConsistency() const if (!_rev_num_coords || _rev_num_coords->getNumberOfTuples() != (maxValue+1)) throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): inconsistent internal revert node numbering array!"); } + if (_global_num_coords.isNotNull()) + { + _global_num_coords->checkNbOfTuplesAndComp(nbCoo,1,"MEDFileUMesh::checkConsistency(): inconsistent global node numbering array!"); + } if ((_num_coords && !_rev_num_coords) || (!_num_coords && _rev_num_coords)) throw INTERP_KERNEL::Exception("MEDFileUMesh::checkConsistency(): inconsistent internal numbering arrays (one is null)!"); if (_num_coords && !_num_coords->hasUniqueValues()) @@ -2600,13 +2760,14 @@ void MEDFileUMesh::checkSMESHConsistency() const */ void MEDFileUMesh::clearNodeAndCellNumbers() { - _num_coords = 0; - _rev_num_coords = 0; - for (std::vector< MCAuto >::iterator it=_ms.begin(); - it != _ms.end(); it++) + _num_coords.nullify(); + _rev_num_coords.nullify(); + _global_num_coords.nullify(); + for (std::vector< MCAuto >::iterator it=_ms.begin(); it != _ms.end(); it++) { - (*it)->_num = 0; - (*it)->_rev_num = 0; + (*it)->_num.nullify(); + (*it)->_rev_num.nullify(); + (*it)->_global_num.nullify(); } } @@ -2616,30 +2777,25 @@ void MEDFileUMesh::clearNodeAndCellNumbers() void MEDFileUMesh::clearNonDiscrAttributes() const { MEDFileMesh::clearNonDiscrAttributes(); - const DataArrayDouble *coo1=_coords; - if(coo1) - (const_cast(coo1))->setName("");//This parameter is not discriminant for comparison - const DataArrayInt *famc1=_fam_coords; - if(famc1) - (const_cast(famc1))->setName("");//This parameter is not discriminant for comparison - const DataArrayInt *numc1=_num_coords; - if(numc1) - (const_cast(numc1))->setName("");//This parameter is not discriminant for comparison - const DataArrayAsciiChar *namc1=_name_coords; - if(namc1) - (const_cast(namc1))->setName("");//This parameter is not discriminant for comparison + if(_coords.isNotNull()) + _coords.iAmATrollConstCast()->setName("");//This parameter is not discriminant for comparison + if(_fam_coords.isNotNull()) + _fam_coords.iAmATrollConstCast()->setName("");//This parameter is not discriminant for comparison + if(_num_coords.isNotNull()) + _num_coords.iAmATrollConstCast()->setName("");//This parameter is not discriminant for comparison + if(_name_coords.isNotNull()) + _name_coords.iAmATrollConstCast()->setName("");//This parameter is not discriminant for comparison for(std::vector< MCAuto >::const_iterator it=_ms.begin();it!=_ms.end();it++) { - const MEDFileUMeshSplitL1 *tmp=(*it); - if(tmp) - tmp->clearNonDiscrAttributes(); + if((*it).isNotNull()) + (*it)->clearNonDiscrAttributes(); } } void MEDFileUMesh::setName(const std::string& name) { for(std::vector< MCAuto >::iterator it=_ms.begin();it!=_ms.end();it++) - if((MEDFileUMeshSplitL1 *)(*it)!=0) + if((*it).isNotNull()) (*it)->setName(name); MEDFileMesh::setName(name); } @@ -2753,7 +2909,7 @@ void MEDFileMesh::checkCartesian() const if(getAxisType()!=AX_CART) { std::ostringstream oss; oss << "MEDFileMesh::checkCartesian : request for method that is dedicated to a cartesian convention ! But you are not in cartesian convention (" << DataArray::GetAxisTypeRepr(getAxisType()) << ")."; - oss << std::endl << "To perform operation you have two possiblities :" << std::endl; + oss << std::endl << "To perform operation you have two possibilities :" << std::endl; oss << " - call setAxisType(AX_CART)" << std::endl; oss << " - call cartesianize()"; throw INTERP_KERNEL::Exception(oss.str().c_str()); @@ -2847,6 +3003,8 @@ void MEDFileUMesh::dispatchLoadedPart(med_idt fid, const MEDFileUMeshL2& loaderl _num_coords=loaderl2.getCoordsNum(); if(!mrs || mrs->isNodeNameFieldReading()) _name_coords=loaderl2.getCoordsName(); + if(!mrs || mrs->isGlobalNodeNumFieldReading()) + _global_num_coords=loaderl2.getCoordsGlobalNum(); _part_coords=loaderl2.getPartDefOfCoo(); computeRevNum(); } @@ -2880,7 +3038,7 @@ void MEDFileUMesh::writeMeshLL(med_idt fid) const if(_univ_wr_status) MEDFILESAFECALLERWR0(MEDmeshUniversalNameWr,(fid,maa)); std::string meshName(MEDLoaderBase::buildStringFromFortran(maa,MED_NAME_SIZE)); - MEDFileUMeshL2::WriteCoords(fid,meshName,_iteration,_order,_time,_coords,_fam_coords,_num_coords,_name_coords); + MEDFileUMeshL2::WriteCoords(fid,meshName,_iteration,_order,_time,_coords,_fam_coords,_num_coords,_name_coords,_global_num_coords); for(std::vector< MCAuto >::const_iterator it=_ms.begin();it!=_ms.end();it++) if((const MEDFileUMeshSplitL1 *)(*it)!=0) (*it)->write(fid,meshName,mdim); @@ -2939,8 +3097,7 @@ std::vector MEDFileUMesh::getFamArrNonEmptyLevelsExt() const std::vector MEDFileUMesh::getNumArrNonEmptyLevelsExt() const { std::vector ret; - const DataArrayInt *numCoo(_num_coords); - if(numCoo) + if(_num_coords.isNotNull()) ret.push_back(1); int lev=0; for(std::vector< MCAuto >::const_iterator it=_ms.begin();it!=_ms.end();it++,lev--) @@ -3230,6 +3387,13 @@ const DataArrayAsciiChar *MEDFileUMesh::getNameFieldAtLevel(int meshDimRelToMaxE return l1->getNameField(); } +MCAuto MEDFileUMesh::getGlobalNumFieldAtLevel(int meshDimRelToMaxExt) const +{ + if(meshDimRelToMaxExt!=1) + throw INTERP_KERNEL::Exception("MEDFileUMesh::getGlobalNumFieldAtLevel : not implemented yet for structured mesh !"); + return _global_num_coords; +} + /*! * This method returns for a specified relative level \a meshDimRelToMaxExt the part effectively read (if the instance is the result of the read of a file). * @@ -3339,11 +3503,11 @@ const DataArrayInt *MEDFileUMesh::getRevNumberFieldAtLevel(int meshDimRelToMaxEx { if(meshDimRelToMaxExt==1) { - if(!((const DataArrayInt *)_num_coords)) + if(_num_coords.isNull()) throw INTERP_KERNEL::Exception("MEDFileUMesh::getRevNumberFieldAtLevel : no coordinates renum specified !"); return _rev_num_coords; } - const MEDFileUMeshSplitL1 *l1=getMeshAtLevSafe(meshDimRelToMaxExt); + const MEDFileUMeshSplitL1 *l1(getMeshAtLevSafe(meshDimRelToMaxExt)); return l1->getRevNumberField(); } @@ -3604,7 +3768,7 @@ MEDCouplingUMesh *MEDFileUMesh::getLevelM3Mesh(bool renum) const /*! * This method is for advanced users. There is two storing strategy of mesh in \a this. * Either MEDCouplingUMesh, or vector of MEDCoupling1GTUMesh instances. - * When assignement is done the first one is done, which is not optimal in write mode for MED file. + * When assignment is done the first one is done, which is not optimal in write mode for MED file. * This method allows to switch from MEDCouplingUMesh mode to MEDCoupling1GTUMesh mode. */ void MEDFileUMesh::forceComputationOfParts() const @@ -3784,12 +3948,11 @@ void MEDFileUMesh::setCoords(DataArrayDouble *coords) return ; coords->checkAllocated(); int nbOfTuples(coords->getNumberOfTuples()); - _coords=coords; - coords->incrRef(); + _coords.takeRef(coords); _fam_coords=DataArrayInt::New(); _fam_coords->alloc(nbOfTuples,1); _fam_coords->fillWithZero(); - _num_coords=0; _rev_num_coords=0; _name_coords=0; + _num_coords.nullify(); _rev_num_coords.nullify(); _name_coords.nullify(); _global_num_coords.nullify(); for(std::vector< MCAuto >::iterator it=_ms.begin();it!=_ms.end();it++) if((MEDFileUMeshSplitL1 *)(*it)) (*it)->setCoords(coords); @@ -3914,7 +4077,7 @@ void MEDFileUMesh::buildInnerBoundaryAlongM1Group(const std::string& grpNameM1, std::vector levs=getNonEmptyLevels(); if(std::find(levs.begin(),levs.end(),0)==levs.end() || std::find(levs.begin(),levs.end(),-1)==levs.end()) - throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group : This method works only for mesh definied on level 0 and -1 !"); + throw INTERP_KERNEL::Exception("MEDFileUMesh::buildInnerBoundaryAlongM1Group : This method works only for mesh defined on level 0 and -1 !"); MUMesh m0=getMeshAtLevel(0); MUMesh m1=getMeshAtLevel(-1); int nbNodes=m0->getNumberOfNodes(); @@ -4007,8 +4170,8 @@ void MEDFileUMesh::buildInnerBoundaryAlongM1Group(const std::string& grpNameM1, _fam_coords=newFam; } - _num_coords = 0; - _rev_num_coords = 0; + _num_coords.nullify(); _rev_num_coords.nullify(); _global_num_coords.nullify(); + for (std::vector< MCAuto >::iterator it=_ms.begin(); it != _ms.end(); it++) { @@ -4103,12 +4266,12 @@ struct MEDLoaderAccVisit1 /*! \endcond */ /*! - * Array returned is the correspondance in \b old \b to \b new format. The returned array is newly created and should be dealt by the caller. + * Array returned is the correspondence in \b old \b to \b new format. The returned array is newly created and should be dealt by the caller. * The maximum value stored in returned array is the number of nodes of \a this minus 1 after call of this method. * The size of returned array is the number of nodes of the old (previous to the call of this method) number of nodes. * -1 values in returned array means that the corresponding old node is no more used. * - * \return newly allocated array containing correspondance in \b old \b to \b new format. If all nodes in \a this are fetched \c NULL pointer is returned and nothing + * \return newly allocated array containing correspondence in \b old \b to \b new format. If all nodes in \a this are fetched \c NULL pointer is returned and nothing * is modified in \a this. * \throw If no coordinates are set in \a this or if there is in any available mesh in \a this a cell having a nodal connectivity containing a node id not in the range of * set coordinates. @@ -4148,12 +4311,14 @@ DataArrayInt *MEDFileUMesh::zipCoords() MCAuto newNameCoords; if((const DataArrayInt *)_fam_coords) newFamCoords=_fam_coords->selectByTupleIdSafe(ret2->begin(),ret2->end()); - MCAuto newNumCoords; - if((const DataArrayInt *)_num_coords) + MCAuto newNumCoords,newGlobalNumCoords; + if(_num_coords.isNotNull()) newNumCoords=_num_coords->selectByTupleIdSafe(ret2->begin(),ret2->end()); - if((const DataArrayAsciiChar *)_name_coords) + if(_global_num_coords.isNotNull()) + newGlobalNumCoords=_global_num_coords->selectByTupleIdSafe(ret2->begin(),ret2->end()); + if(_name_coords.isNotNull()) newNameCoords=static_cast(_name_coords->selectByTupleIdSafe(ret2->begin(),ret2->end())); - _coords=newCoords; _fam_coords=newFamCoords; _num_coords=newNumCoords; _name_coords=newNameCoords; _rev_num_coords=0; + _coords=newCoords; _fam_coords=newFamCoords; _num_coords=newNumCoords; _global_num_coords=newGlobalNumCoords; _name_coords=newNameCoords; _rev_num_coords.nullify(); for(std::vector< MCAuto >::iterator it=_ms.begin();it!=_ms.end();it++) { if((MEDFileUMeshSplitL1*)*it) @@ -4579,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()) @@ -4586,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 !"); @@ -4600,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) { - 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& 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) + { + 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()); @@ -4639,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; } @@ -4842,7 +5106,7 @@ void MEDFileUMesh::addNodeGroup(const DataArrayInt *ids) if(!coords) throw INTERP_KERNEL::Exception("MEDFileUMesh::addNodeGroup : no coords set !"); int nbOfNodes(coords->getNumberOfTuples()); - if(!((DataArrayInt *)_fam_coords)) + if(_fam_coords.isNull()) { _fam_coords=DataArrayInt::New(); _fam_coords->alloc(nbOfNodes,1); _fam_coords->fillWithZero(); } // addGroupUnderground(true,ids,_fam_coords); @@ -4973,7 +5237,7 @@ MCAuto& MEDFileUMesh::checkAndGiveEntryInSplitL1(int meshDi * * \param [in] ms - List of unstructured meshes lying on the same coordinates and having different mesh dimesnion. * \param [in] renum - the parameter (set to false by default) that tells the beheviour if there is a mesh on \a ms that is not geo type sorted. - * If false, an exception ois thrown. If true the mesh is reordered automatically. It is highly recommanded to let this parameter to false. + * If false, an exception is thrown. If true the mesh is reordered automatically. It is highly recommended to let this parameter to false. * * \throw If \a there is a null pointer in \a ms. * \sa MEDFileUMesh::setMeshAtLevel @@ -5142,8 +5406,7 @@ void MEDFileUMesh::setFamilyFieldArr(int meshDimRelToMaxExt, DataArrayInt *famAr if(!coo) throw INTERP_KERNEL::Exception("MEDFileUMesh::setFamilyFieldArr : the coordinates have not been set !"); famArr->checkNbOfTuplesAndComp(coo->getNumberOfTuples(),1,"MEDFileUMesh::setFamilyFieldArr : Problem in size of node family arr ! "); - famArr->incrRef(); - _fam_coords=famArr; + _fam_coords.takeRef(famArr); return ; } if(meshDimRelToMaxExt>1) @@ -5169,16 +5432,14 @@ void MEDFileUMesh::setRenumFieldArr(int meshDimRelToMaxExt, DataArrayInt *renumA { if(!renumArr) { - _num_coords=0; - _rev_num_coords=0; + _num_coords.nullify(); + _rev_num_coords.nullify(); return ; } - DataArrayDouble *coo(_coords); - if(!coo) + if(_coords.isNull()) throw INTERP_KERNEL::Exception("MEDFileUMesh::setRenumFieldArr : the coordinates have not been set !"); - renumArr->checkNbOfTuplesAndComp(coo->getNumberOfTuples(),1,"MEDFileUMesh::setRenumArr : Problem in size of node numbering arr ! "); - renumArr->incrRef(); - _num_coords=renumArr; + renumArr->checkNbOfTuplesAndComp(_coords->getNumberOfTuples(),1,"MEDFileUMesh::setRenumArr : Problem in size of node numbering arr ! "); + _num_coords.takeRef(renumArr); computeRevNum(); return ; } @@ -5212,8 +5473,7 @@ void MEDFileUMesh::setNameFieldAtLevel(int meshDimRelToMaxExt, DataArrayAsciiCha if(!coo) throw INTERP_KERNEL::Exception("MEDFileUMesh::setNameFieldAtLevel : the coordinates have not been set !"); nameArr->checkNbOfTuplesAndComp(coo->getNumberOfTuples(),MED_SNAME_SIZE,"MEDFileUMesh::setNameFieldAtLevel : Problem in size of node numbering arr ! "); - nameArr->incrRef(); - _name_coords=nameArr; + _name_coords.takeRef(nameArr); return ; } if(meshDimRelToMaxExt>1) @@ -5226,6 +5486,15 @@ void MEDFileUMesh::setNameFieldAtLevel(int meshDimRelToMaxExt, DataArrayAsciiCha return _ms[traducedRk]->setNameArr(nameArr); } +void MEDFileUMesh::setGlobalNumFieldAtLevel(int meshDimRelToMaxExt, DataArrayInt *globalNumArr) +{ + if(meshDimRelToMaxExt!=1) + throw INTERP_KERNEL::Exception("MEDFileUMesh::setGlobalNumFieldAtLevel : Only implemented for meshDimRelToMaxExt==1 for the moment !"); + if(globalNumArr) + globalNumArr->checkNbOfTuplesAndComp(_coords->getNumberOfTuples(),1,"MEDFileUMesh::setGlobalNumFieldAtLevel : Problem in size of node global numbering arr ! "); + _global_num_coords.takeRef(globalNumArr); +} + void MEDFileUMesh::synchronizeTinyInfoOnLeaves() const { for(std::vector< MCAuto >::const_iterator it=_ms.begin();it!=_ms.end();it++) @@ -5272,7 +5541,7 @@ std::list< MCAuto > MEDFileUMesh::getAllNonNullFamilyIds() const void MEDFileUMesh::computeRevNum() const { - if((const DataArrayInt *)_num_coords) + if(_num_coords.isNotNull()) { int pos; int maxValue=_num_coords->getMaxValue(pos); @@ -5745,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 !"); @@ -5754,6 +6023,11 @@ void MEDFileStructuredMesh::setNameFieldAtLevel(int meshDimRelToMaxExt, DataArra nameArr->incrRef(); } +void MEDFileStructuredMesh::setGlobalNumFieldAtLevel(int meshDimRelToMaxExt, DataArrayInt *globalNumArr) +{ + throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::setGlobalNumFieldAtLevel : not implemented yet !"); +} + /*! * Adds a group of nodes to \a this mesh. * \param [in] ids - a DataArrayInt providing ids and a name of the group to add. @@ -5915,6 +6189,11 @@ const DataArrayAsciiChar *MEDFileStructuredMesh::getNameFieldAtLevel(int meshDim } } +MCAuto MEDFileStructuredMesh::getGlobalNumFieldAtLevel(int meshDimRelToMaxExt) const +{ + throw INTERP_KERNEL::Exception("MEDFileStructuredMesh::getGlobalNumFieldAtLevel : not implemented yet for structured mesh !"); +} + /*! * Returns relative dimensions of mesh entities (excluding nodes) present in \a this mesh. * \return std::vector - a sequence of the relative dimensions: [0]. @@ -6048,7 +6327,7 @@ void MEDFileStructuredMesh::deepCpyAttributes() } /*! - * Returns a pointer to mesh at the specified level (here 0 is compulsary for cartesian mesh). + * Returns a pointer to mesh at the specified level (here 0 is compulsory for cartesian mesh). * * \return a pointer to cartesian mesh that need to be managed by the caller. * \warning the returned pointer has to be managed by the caller.