From f8450ef0af121a95729ca72d14d4b1f2a191d78a Mon Sep 17 00:00:00 2001 From: ageay Date: Tue, 6 Mar 2012 13:51:32 +0000 Subject: [PATCH] MEDFileMesh::createGroupOnAll --- src/MEDLoader/MEDFileMesh.cxx | 207 ++++++++++++++++++++++++++- src/MEDLoader/MEDFileMesh.hxx | 9 +- src/MEDLoader/Swig/MEDLoader.i | 16 ++- src/MEDLoader/Swig/MEDLoaderTest3.py | 21 +++ 4 files changed, 242 insertions(+), 11 deletions(-) diff --git a/src/MEDLoader/MEDFileMesh.cxx b/src/MEDLoader/MEDFileMesh.cxx index a29ccb091..dff6bf526 100644 --- a/src/MEDLoader/MEDFileMesh.cxx +++ b/src/MEDLoader/MEDFileMesh.cxx @@ -412,6 +412,10 @@ void MEDFileMesh::changeGroupName(const char *oldName, const char *newName) thro _groups[newName]=cpy; } +/*! + * This method changes the family ids in 'this'. It leads to a modification into '_families' attributes \b and in + * ids stored in arrays. This method calls MEDFileMesh::changeFamilyIdArr method. + */ void MEDFileMesh::changeFamilyId(int oldId, int newId) throw(INTERP_KERNEL::Exception) { changeFamilyIdArr(oldId,newId); @@ -523,6 +527,12 @@ bool MEDFileMesh::areGrpsEqual(const MEDFileMesh *other, std::string& what) cons return ret; } +bool MEDFileMesh::existsGroup(const char *groupName) const +{ + std::string grpName(groupName); + return _groups.find(grpName)!=_groups.end(); +} + bool MEDFileMesh::existsFamily(int famId) const { for(std::map::const_iterator it2=_families.begin();it2!=_families.end();it2++) @@ -573,12 +583,109 @@ void MEDFileMesh::addFamily(const char *familyName, int famId) throw(INTERP_KERN } } -void MEDFileMesh::addGrpOnFamily(const char *grpName, const char *famName) throw(INTERP_KERNEL::Exception) +/*! + * This method creates a new group called 'groupName' in 'this'. If it exists a group with the same name an INTERP_KERNEL::Exception will be thrown. + * If the 'meshDimRelToMaxExt' is not existing an INTERP_KERNEL::Exception will be thrown too. + * \b WARNING : This method does \b not garantee that 'groupName' lies only on a single level specified by 'meshDimRelToMaxExt'. + * in the case of a presence of one or more family id in family field at 'meshDimRelToMaxExt' level that appears in another level. + * If there is a risk of such case call MEDFileMesh::keepFamIdsOnlyOnLevs method \b before calling this method. + * (call to MEDFileMesh::keepFamIdsOnlyOnLevs should be done with MEDFileMesh::getFamiliesIdsOnGroup('groupName' as first input ). + */ +void MEDFileMesh::createGroupOnAll(int meshDimRelToMaxExt, const char *groupName) throw(INTERP_KERNEL::Exception) +{ + std::string grpName(groupName); + std::vector levs=getNonEmptyLevelsExt(); + if(std::find(levs.begin(),levs.end(),meshDimRelToMaxExt)==levs.end()) + { + std::ostringstream oss; oss << "MEDFileMesh::createGroupOnAll : The relative ext dimension " << meshDimRelToMaxExt << " is not available !" << std::endl; + oss << "Available relative ext levels are : "; + std::copy(levs.begin(),levs.end(),std::ostream_iterator(oss," ")); + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + if(existsGroup(groupName)) + { + std::ostringstream oss; oss << "MEDFileMesh::createGroupOnAll : The groups \"" << grpName << "\" already exists in this !" << std::endl; + oss << "Already existing groups are : "; + std::copy(levs.begin(),levs.end(),std::ostream_iterator(oss," ")); + oss << std::endl << "Please choose an another group name or call removeGroup(\"" << grpName << "\") method !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + const DataArrayInt *fieldFamIds=getFamilyFieldAtLevel(meshDimRelToMaxExt); + if(fieldFamIds==0) + throw INTERP_KERNEL::Exception("MEDFileMesh::createGroupOnAll : Family field arr ids is not defined for this level !"); + std::set famIds=fieldFamIds->getDifferentValues(); + std::vector familiesOnWholeGroup; + for(std::set::const_iterator it=famIds.begin();it!=famIds.end();it++) + { + bool tmp; + familiesOnWholeGroup.push_back(findOrCreateAndGiveFamilyWithId(*it,tmp)); + } + _groups[grpName]=familiesOnWholeGroup; +} + +/*! + * This method checks that family Ids in 'famIds' are not present in levels \b not in 'vMeshDimRelToMaxExt'. + * If it is the case true is returned and 'this' is not modified. + * If there is some levels not in 'vMeshDimRelToMaxExt' where one or more family ids in 'famIds' appear + * new families are created and groups are updated in consequence. + */ +bool MEDFileMesh::keepFamIdsOnlyOnLevs(const std::vector& famIds, const std::vector& vMeshDimRelToMaxExt) throw(INTERP_KERNEL::Exception) +{ + std::set levsInput(vMeshDimRelToMaxExt.begin(),vMeshDimRelToMaxExt.end()); + std::vector levs=getNonEmptyLevelsExt(); + std::set levs2(levs.begin(),levs.end()); + std::vector levsToTest; + std::set_difference(levs2.begin(),levs2.end(),levsInput.begin(),levsInput.end(),std::back_insert_iterator< std::vector >(levsToTest)); + std::set famIds2(famIds.begin(),famIds.end()); + bool ret=true; + int maxFamId=1; + if(!_families.empty()) + maxFamId=getMaxFamilyId()+1; + std::vector allFams=getFamiliesNames(); + for(std::vector::const_iterator it=levsToTest.begin();it!=levsToTest.end();it++) + { + const DataArrayInt *fieldFamIds=getFamilyFieldAtLevel(*it); + if(fieldFamIds) + { + std::set famIds3=fieldFamIds->getDifferentValues(); + std::vector tmp; + std::set_intersection(famIds3.begin(),famIds3.end(),famIds2.begin(),famIds2.end(),std::back_insert_iterator< std::vector >(tmp)); + for(std::vector::const_iterator it2=tmp.begin();it2!=tmp.end();it2++) + { + ret=false; + std::string famName=getFamilyNameGivenId(*it2); + std::ostringstream oss; oss << "Family_" << maxFamId; + std::string zeName=CreateNameNotIn(oss.str(),allFams); + addFamilyOnAllGroupsHaving(famName.c_str(),zeName.c_str()); + _families[zeName]=maxFamId; + (const_cast(fieldFamIds))->changeValue(*it2,maxFamId); + maxFamId++; + } + } + } + return ret; +} + +/*! + * This method add into the family list of a group 'grpName' the family with name 'famName'. + * If the group 'grpName' does not exist it is created and 'famName' is added to the list. + * If the group 'grpName' already exists, 'famName' will be added into family list of the existing group. + * This method throws an INTERP_KERNEL::Exception if 'famName' does not exit. + */ +void MEDFileMesh::addFamilyOnGrp(const char *grpName, const char *famName) throw(INTERP_KERNEL::Exception) { std::string grpn(grpName); std::string famn(famName); if(grpn.empty() || famn.empty()) - throw INTERP_KERNEL::Exception("MEDFileMesh::addGrpOnFamily : input strings must be non null !"); + throw INTERP_KERNEL::Exception("MEDFileMesh::addFamilyOnGrp : input strings must be non null !"); + std::vector fams=getFamiliesNames(); + if(std::find(fams.begin(),fams.end(),famn)==fams.end()) + { + std::ostringstream oss; oss << "MEDFileMesh::addFamilyOnGrp : Family \"" << famn << "\" does not exist !" << std::endl; + oss << "Create this family or choose an existing one ! Existing fams are : "; + std::copy(fams.begin(),fams.end(),std::ostream_iterator(oss," ")); oss << "."; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } std::map >::iterator it=_groups.find(grpn); if(it==_groups.end()) { @@ -592,6 +699,56 @@ void MEDFileMesh::addGrpOnFamily(const char *grpName, const char *famName) throw } } +/*! + * This method adds to all groups lying on family with name 'famName' the other family name 'otherFamName'. + * This method is quite underground because it can lead to unconsistency because family 'otherFamName' is \b not added into _families. + * This method is used by MEDFileMesh::keepFamIdsOnlyOnLevs method. + */ +void MEDFileMesh::addFamilyOnAllGroupsHaving(const char *famName, const char *otherFamName) throw(INTERP_KERNEL::Exception) +{ + std::string famNameCpp(famName); + std::string otherCpp(otherFamName); + for(std::map >::iterator it=_groups.begin();it!=_groups.end();it++) + { + std::vector& v=(*it).second; + if(std::find(v.begin(),v.end(),famNameCpp)!=v.end()) + { + v.push_back(otherCpp); + } + } +} + +/*! + * If it exists a family whose family id is equal to 'id' this method behaves as MEDFileMesh::getFamilyNameGivenId. + * In this case, 'this' internal states remains unchanged and 'created' out parameter will be set to false. + * If there is no family whose family id is equal to 'id' a family is created with a name different from those + * already existing. In this case 'created' will be returned with a value set to true, and internal state + * will be modified. + * This method will throws an exception if it is not possible to create a unique family name. + */ +std::string MEDFileMesh::findOrCreateAndGiveFamilyWithId(int id, bool& created) throw(INTERP_KERNEL::Exception) +{ + std::vector famAlreadyExisting(_families.size()); + int ii=0; + for(std::map::const_iterator it=_families.begin();it!=_families.end();it++,ii++) + { + if((*it).second!=id) + { + famAlreadyExisting[ii]=(*it).first; + } + else + { + created=false; + return (*it).first; + } + } + created=true; + std::ostringstream oss; oss << "Family_" << id; + std::string ret=CreateNameNotIn(oss.str(),famAlreadyExisting); + _families[ret]=id; + return ret; +} + void MEDFileMesh::setFamilyInfo(const std::map& info) { _families=info; @@ -796,6 +953,44 @@ void MEDFileMesh::TranslateFamilyIds(int offset, DataArrayInt *famArr, std::vect std::transform((*it1).begin(),(*it1).end(),(*it1).begin(),std::bind2nd(std::plus(),offset)); } +/*! + * Warning no check is done on 'nameTry' in parameter. It should be non empty. + * This method returns a name close to 'nameTry' so that it is not already into 'namesToAvoid'. + * If this method fails to find such a name it will throw an exception. + */ +std::string MEDFileMesh::CreateNameNotIn(const std::string& nameTry, const std::vector& namesToAvoid) throw(INTERP_KERNEL::Exception) +{ + //attempt #0 + if(std::find(namesToAvoid.begin(),namesToAvoid.end(),nameTry)==namesToAvoid.end()) + return nameTry; + //attempt #1 + std::size_t len=nameTry.length(); + for(std::size_t ii=1;ii=1) + { + for(std::size_t i=1;i<30;i++) + { + std::string tmp1(nameTry.at(0),i); + tmp1+=nameTry; + if(std::find(namesToAvoid.begin(),namesToAvoid.end(),tmp1)==namesToAvoid.end()) + return tmp1; + } + } + //attempt #3 + std::string tmp2; + for(std::vector::const_iterator it2=namesToAvoid.begin();it2!=namesToAvoid.end();it2++) + tmp2+=(*it2); + if(std::find(namesToAvoid.begin(),namesToAvoid.end(),tmp2)==namesToAvoid.end()) + return tmp2; + throw INTERP_KERNEL::Exception("MEDFileMesh::CreateNameNotIn : impossible to find a not already used name !"); +} + /*! * This method should be called by any set* method of subclasses to deal automatically with _name attribute. * If _name attribute is empty the name of 'm' if taken as _name attribute. @@ -1525,11 +1720,6 @@ void MEDFileUMesh::optimizeFamilies() throw(INTERP_KERNEL::Exception) _groups.erase(*it); } -void MEDFileUMesh::setFamilyField(DataArrayInt *arr, const std::vector< std::vector< int > > &userfids, const std::vector& grpNames, bool renum) throw(INTERP_KERNEL::Exception) -{ - -} - void MEDFileUMesh::addNodeGroup(const std::string& name, const std::vector& ids) throw(INTERP_KERNEL::Exception) { const DataArrayDouble *coords=_coords; @@ -1707,6 +1897,9 @@ void MEDFileUMesh::synchronizeTinyInfoOnLeaves() const (*it)->synchronizeTinyInfo(*this); } +/*! + * This method is called by MEDFileMesh::changeFamilyId. It performs only one part of the family id modification. + */ void MEDFileUMesh::changeFamilyIdArr(int oldId, int newId) throw(INTERP_KERNEL::Exception) { DataArrayInt *arr=_fam_coords; diff --git a/src/MEDLoader/MEDFileMesh.hxx b/src/MEDLoader/MEDFileMesh.hxx index 99bb2ba25..f25b1ef0e 100644 --- a/src/MEDLoader/MEDFileMesh.hxx +++ b/src/MEDLoader/MEDFileMesh.hxx @@ -60,11 +60,15 @@ namespace ParaMEDMEM // bool areFamsEqual(const MEDFileMesh *other, std::string& what) const; bool areGrpsEqual(const MEDFileMesh *other, std::string& what) const; + bool existsGroup(const char *groupName) const; bool existsFamily(int famId) const; bool existsFamily(const char *familyName) const; void setFamilyId(const char *familyName, int id); virtual void addFamily(const char *familyName, int id) throw(INTERP_KERNEL::Exception); - void addGrpOnFamily(const char *grpName, const char *famName) throw(INTERP_KERNEL::Exception); + virtual void createGroupOnAll(int meshDimRelToMaxExt, const char *groupName) throw(INTERP_KERNEL::Exception); + virtual bool keepFamIdsOnlyOnLevs(const std::vector& famIds, const std::vector& levs) throw(INTERP_KERNEL::Exception); + void addFamilyOnGrp(const char *grpName, const char *famName) throw(INTERP_KERNEL::Exception); + std::string findOrCreateAndGiveFamilyWithId(int id, bool& created) throw(INTERP_KERNEL::Exception); void setFamilyInfo(const std::map& info); void setGroupInfo(const std::map >&info); void copyFamGrpMapsFrom(const MEDFileMesh& other); @@ -109,6 +113,7 @@ namespace ParaMEDMEM virtual DataArrayInt *getNodeFamiliesArr(const std::vector& fams, bool renum=false) const throw(INTERP_KERNEL::Exception); protected: MEDFileMesh(); + void addFamilyOnAllGroupsHaving(const char *famName, const char *otherFamName) throw(INTERP_KERNEL::Exception); virtual void writeLL(med_idt fid) const throw(INTERP_KERNEL::Exception) = 0; void dealWithTinyInfo(const MEDCouplingMesh *m) throw(INTERP_KERNEL::Exception); virtual void synchronizeTinyInfoOnLeaves() const = 0; @@ -116,6 +121,7 @@ namespace ParaMEDMEM virtual void appendFamilyEntries(const std::set& famIds, const std::vector< std::vector >& fidsOfGrps, const std::vector& grpNames); virtual void changeFamilyIdArr(int oldId, int newId) throw(INTERP_KERNEL::Exception) = 0; static void TranslateFamilyIds(int offset, DataArrayInt *famArr, std::vector< std::vector >& famIdsPerGrp); + static std::string CreateNameNotIn(const std::string& nameTry, const std::vector& namesToAvoid) throw(INTERP_KERNEL::Exception); protected: int _order; int _iteration; @@ -177,7 +183,6 @@ namespace ParaMEDMEM void setFamilyNameAttachedOnId(int id, const std::string& newFamName) throw(INTERP_KERNEL::Exception); void setCoords(DataArrayDouble *coords) throw(INTERP_KERNEL::Exception); void eraseGroupsAtLevel(int meshDimRelToMaxExt) throw(INTERP_KERNEL::Exception); - void setFamilyField(DataArrayInt *arr, const std::vector< std::vector< int > > &userfids, const std::vector& grpNames, bool renum=false) throw(INTERP_KERNEL::Exception); void setFamilyFieldArr(int meshDimRelToMaxExt, DataArrayInt *famArr) throw(INTERP_KERNEL::Exception); void setRenumFieldArr(int meshDimRelToMaxExt, DataArrayInt *renumArr) throw(INTERP_KERNEL::Exception); void addNodeGroup(const std::string& name, const std::vector& ids) throw(INTERP_KERNEL::Exception); diff --git a/src/MEDLoader/Swig/MEDLoader.i b/src/MEDLoader/Swig/MEDLoader.i index e3d52a063..d0903d3c3 100644 --- a/src/MEDLoader/Swig/MEDLoader.i +++ b/src/MEDLoader/Swig/MEDLoader.i @@ -335,11 +335,14 @@ namespace ParaMEDMEM void write(const char *fileName, int mode) const throw(INTERP_KERNEL::Exception); int getSizeAtLevel(int meshDimRelToMaxExt) const throw(INTERP_KERNEL::Exception); // + bool existsGroup(const char *groupName) const; bool existsFamily(int famId) const; bool existsFamily(const char *familyName) const; void setFamilyId(const char *familyName, int id); void addFamily(const char *familyName, int id) throw(INTERP_KERNEL::Exception); - void addGrpOnFamily(const char *grpName, const char *famName) throw(INTERP_KERNEL::Exception); + void addFamilyOnGrp(const char *grpName, const char *famName) throw(INTERP_KERNEL::Exception); + virtual void createGroupOnAll(int meshDimRelToMaxExt, const char *groupName) throw(INTERP_KERNEL::Exception); + virtual bool keepFamIdsOnlyOnLevs(const std::vector& famIds, const std::vector& levs) throw(INTERP_KERNEL::Exception); void copyFamGrpMapsFrom(const MEDFileMesh& other); const std::map& getFamilyInfo() const; const std::map >& getGroupInfo() const; @@ -448,6 +451,16 @@ namespace ParaMEDMEM tmp->incrRef(); return SWIG_NewPointerObj(SWIG_as_voidptr(tmp),SWIGTYPE_p_ParaMEDMEM__DataArrayInt, SWIG_POINTER_OWN | 0 ); } + + PyObject *findOrCreateAndGiveFamilyWithId(int id, bool& created) throw(INTERP_KERNEL::Exception) + { + bool ret1; + std::string ret0=self->findOrCreateAndGiveFamilyWithId(id,ret1); + PyObject *ret=PyTuple_New(2); + PyTuple_SetItem(ret,0,PyString_FromString(ret0.c_str())); + PyTuple_SetItem(ret,1,SWIG_From_bool(ret1)); + return ret; + } } }; @@ -490,7 +503,6 @@ namespace ParaMEDMEM void setFamilyNameAttachedOnId(int id, const std::string& newFamName) throw(INTERP_KERNEL::Exception); void setCoords(DataArrayDouble *coords) throw(INTERP_KERNEL::Exception); void eraseGroupsAtLevel(int meshDimRelToMaxExt) throw(INTERP_KERNEL::Exception); - void setFamilyField(DataArrayInt *arr, const std::vector< std::vector< int > > &userfids, const std::vector& grpNames, bool renum=false) throw(INTERP_KERNEL::Exception); void addNodeGroup(const std::string& name, const std::vector& ids) throw(INTERP_KERNEL::Exception); void removeMeshAtLevel(int meshDimRelToMax) throw(INTERP_KERNEL::Exception); void setMeshAtLevel(int meshDimRelToMax, MEDCouplingUMesh *m, bool newOrOld=false) throw(INTERP_KERNEL::Exception); diff --git a/src/MEDLoader/Swig/MEDLoaderTest3.py b/src/MEDLoader/Swig/MEDLoaderTest3.py index 08b84a70b..15f3afaf8 100644 --- a/src/MEDLoader/Swig/MEDLoaderTest3.py +++ b/src/MEDLoader/Swig/MEDLoaderTest3.py @@ -145,6 +145,7 @@ class MEDLoaderTest(unittest.TestCase): g2_N.setValues(range(9),9,1) g2_N.setName("G2") mm.setGroupsAtLevel(1,[g1_N,g2_N],False) + mm.createGroupOnAll(0,"GrpOnAllCell") # check content of mm t=mm.getGroupArr(0,"G1",False) self.assertTrue(g1_2.isEqual(t)); @@ -158,6 +159,9 @@ class MEDLoaderTest(unittest.TestCase): self.assertTrue(g1_N.isEqual(t)); t=mm.getGroupArr(1,"G2",False) self.assertTrue(g2_N.isEqual(t)); + self.assertTrue(mm.existsGroup("GrpOnAllCell")); + t=mm.getGroupArr(0,"GrpOnAllCell") + self.assertTrue(t.getValues()==range(5)) # mm.write(outFileName,2); # @@ -252,11 +256,28 @@ class MEDLoaderTest(unittest.TestCase): self.assertTrue(g1_1.isEqual(t)); t=mm.getGroupArr(-1,"G2",True) self.assertTrue(g2_1.isEqual(t)); + self.assertTrue(not mm.existsGroup("GrpOnAllCell")); # mm.write(outFileName,2); mm2=MEDFileMesh.New(outFileName) res=mm.isEqual(mm2,1e-12) self.assertTrue(res[0]) + l=list(mm2.getFamiliesOnGroup("G2")) ; l.sort() + self.assertEqual(['Family_10','Family_11','Family_3','Family_4','Family_7'],l) + mm2.keepFamIdsOnlyOnLevs([3],[-1]) + for lev in mm.getGrpNonEmptyLevelsExt("G2"): + self.assertEqual(mm.getGroupArr(lev,"G2").getValues(),mm2.getGroupArr(lev,"G2").getValues()) + pass + l=list(mm2.getFamiliesOnGroup("G2")) ; l.sort() + self.assertEqual(['Family_10','Family_11','Family_12','Family_3','Family_4','Family_7'],l) + # + self.assertEqual([7,7,6],mm2.getFamilyFieldAtLevel(-1).getValues()) + mm2.getFamilyFieldAtLevel(-1).setIJ(1,0,8) + self.assertEqual([7,8,6],mm2.getFamilyFieldAtLevel(-1).getValues()) + self.assertTrue(not mm2.existsFamily("Family_8")) + mm2.createGroupOnAll(-1,"GrpOnAllFace") + self.assertTrue(mm2.existsFamily("Family_8")) + self.assertEqual(range(3),mm2.getGroupArr(-1,"GrpOnAllFace").getValues()) pass #testing persistence of retrieved arrays -- 2.39.2