From 92d0a06d69d569d46e4d90f8644a3f4154e11f58 Mon Sep 17 00:00:00 2001 From: Anthony Geay Date: Wed, 28 Aug 2024 18:08:47 +0200 Subject: [PATCH] [EDF30179] : fuse of MEDFileUMesh instances. Management of family field arr management. --- src/MEDCoupling/MCAuto.hxx | 2 +- src/MEDCoupling/MEDCouplingMemArray.hxx | 36 ++++++- src/MEDCoupling/MEDCouplingMemArray.txx | 121 ++++++++++++++++++------ 3 files changed, 127 insertions(+), 32 deletions(-) diff --git a/src/MEDCoupling/MCAuto.hxx b/src/MEDCoupling/MCAuto.hxx index 4b6347704..b2125aed1 100644 --- a/src/MEDCoupling/MCAuto.hxx +++ b/src/MEDCoupling/MCAuto.hxx @@ -44,7 +44,7 @@ namespace MEDCoupling bool operator==(const T *other) const { return _ptr==other; } MCAuto &operator=(const MCAuto& other) { if(_ptr!=other._ptr) { destroyPtr(); referPtr(other._ptr); } return *this; } MCAuto &operator=(T *ptr) { if(_ptr!=ptr) { destroyPtr(); _ptr=ptr; } return *this; } - void takeRef(T *ptr) { if(_ptr!=ptr) { destroyPtr(); _ptr=ptr; if(_ptr) _ptr->incrRef(); } } + void takeRef(T *ptr) { if(_ptr!=ptr) { destroyPtr(); referPtr(ptr); } } T *operator->() { return _ptr ; } const T *operator->() const { return _ptr; } T& operator*() { return *_ptr; } diff --git a/src/MEDCoupling/MEDCouplingMemArray.hxx b/src/MEDCoupling/MEDCouplingMemArray.hxx index d4b9ab5e2..bde9a3816 100755 --- a/src/MEDCoupling/MEDCouplingMemArray.hxx +++ b/src/MEDCoupling/MEDCouplingMemArray.hxx @@ -273,7 +273,8 @@ namespace MEDCoupling void rearrange(std::size_t newNbOfCompo); void transpose(); void pushBackSilent(T val); - void pushBackValsSilent(const T *valsBg, const T *valsEnd); + template + void pushBackValsSilent(InputIterator valsBg, InputIterator valsEnd); T popBackSilent(); T front() const; T back() const; @@ -656,14 +657,14 @@ namespace MEDCoupling void sortToHaveConsecutivePairs(); MCAuto fromLinkedListOfPairToList() const; DataArrayType *getDifferentValues() const; + MCAuto forThisAsPartitionBuildReduction(const MCAuto& commonEntities, const MCAuto& commonEntitiesIndex, + MCAuto& partitionsToBeModified, MCAuto& partitionsToBeModifiedIndex) const; std::vector partitionByDifferentValues(std::vector& differentIds) const; std::vector< std::pair > splitInBalancedSlices(mcIdType nbOfSlices) const; static DataArrayType *Modulus(const DataArrayType *a1, const DataArrayType *a2); void modulusEqual(const DataArrayType *other); static DataArrayType *Pow(const DataArrayType *a1, const DataArrayType *a2); void powEqual(const DataArrayType *other); - //MemArray& accessToMemArray() { return _mem; } - //const MemArray& accessToMemArray() const { return _mem; } public: static DataArrayIdType *FindPermutationFromFirstToSecond(const DataArrayType *ids1, const DataArrayType *ids2); static DataArrayIdType *FindPermutationFromFirstToSecondDuplicate(const DataArrayType *ids1, const DataArrayType *ids2); @@ -1086,4 +1087,33 @@ namespace MEDCoupling else throw INTERP_KERNEL::Exception("DataArrayDouble::insertAtTheEnd : not available for DataArrayDouble with number of components different than 1 !"); } + + /*! + * This method adds at the end of \a this a series of values [\c valsBg,\c valsEnd). This method do \b not update its time label to avoid useless incrementation + * of counter. So the caller is expected to call TimeLabel::declareAsNew on \a this at the end of the push session. + * + * \param [in] valsBg - an array of values to push at the end of \c this. + * \param [in] valsEnd - specifies the end of the array \a valsBg, so that + * the last value of \a valsBg is \a valsEnd[ -1 ]. + * \throw If \a this has already been allocated with number of components different from one. + * \sa DataArrayDouble::pushBackSilent + */ + template + template + void DataArrayTemplate::pushBackValsSilent(InputIterator valsBg, InputIterator valsEnd) + { + std::size_t nbCompo(getNumberOfComponents()); + if(nbCompo==1) + _mem.insertAtTheEnd(valsBg,valsEnd); + else if(nbCompo==0) + { + _info_on_compo.resize(1); + _mem.insertAtTheEnd(valsBg,valsEnd); + } + else + { + std::ostringstream oss; oss << Traits::ArrayTypeName << "::pushBackValsSilent : not available for DataArrayDouble with number of components different than 1 !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + } } diff --git a/src/MEDCoupling/MEDCouplingMemArray.txx b/src/MEDCoupling/MEDCouplingMemArray.txx index b3d517532..b284360d3 100755 --- a/src/MEDCoupling/MEDCouplingMemArray.txx +++ b/src/MEDCoupling/MEDCouplingMemArray.txx @@ -30,10 +30,12 @@ #include "MCAuto.hxx" #include "MEDCouplingMap.txx" +#include #include #include #include #include +#include namespace MEDCoupling { @@ -893,34 +895,6 @@ namespace MEDCoupling } } - /*! - * This method adds at the end of \a this a series of values [\c valsBg,\c valsEnd). This method do \b not update its time label to avoid useless incrementation - * of counter. So the caller is expected to call TimeLabel::declareAsNew on \a this at the end of the push session. - * - * \param [in] valsBg - an array of values to push at the end of \c this. - * \param [in] valsEnd - specifies the end of the array \a valsBg, so that - * the last value of \a valsBg is \a valsEnd[ -1 ]. - * \throw If \a this has already been allocated with number of components different from one. - * \sa DataArrayDouble::pushBackSilent - */ - template - void DataArrayTemplate::pushBackValsSilent(const T *valsBg, const T *valsEnd) - { - std::size_t nbCompo(getNumberOfComponents()); - if(nbCompo==1) - _mem.insertAtTheEnd(valsBg,valsEnd); - else if(nbCompo==0) - { - _info_on_compo.resize(1); - _mem.insertAtTheEnd(valsBg,valsEnd); - } - else - { - std::ostringstream oss; oss << Traits::ArrayTypeName << "::pushBackValsSilent : not available for DataArrayDouble with number of components different than 1 !"; - throw INTERP_KERNEL::Exception(oss.str().c_str()); - } - } - /*! * This method returns silently ( without updating time label in \a this ) the last value, if any and suppress it. * \throw If \a this is already empty. @@ -6460,6 +6434,97 @@ struct NotInRange return ret2.retn(); } + template + class PartitionCfg : public std::set + { + public: + PartitionCfg() = default; + void setID(T id) { _id = id; } + T getID() const { return _id; } + bool operator<(const PartitionCfg& other) { return std::set::operator<( other._data ); } + bool operator>(const PartitionCfg& other) { return std::set::operator>( other._data ); } + bool operator==(const PartitionCfg& other) { return std::set::operator==( other._data ); } + private: + T _id = 0; + }; + + /*! + * \a this is considered as an array defining a partition. It means that values in \a this define partition-ids. All tuples in \a this with same value can be considered as partition. + * Typically MED stores families uses this compact storage method. + * + * This method computes and returns the partition stored in \a this on reduced space using a reduction operation specified by pairs \a commonEntities and \a commonEntitiesIndex parameters. + * The reduction operation is the consequence of a fusion of enties. It explains the storage format defining reduction. + * + * An another way to consider this method : This method can be seen as an interpolation on integer field (\a this). For fused entities it returns in compact way all combinations of partition configuration. + * + * \param [out] partitionsToBeModified - For all partitions impacted by the reduction a n-uplet is returned (n is deduced thanks to \a partitionsToBeModifiedIndex) + * Each n-uplet represents a list of partitions impacted by reduction. The first element of n-uplet represents the ID to locate entities (using for example findIdsEqual in returned array) + * Remaining IDs in n-uplet are Partition IDs impacted. + * \param [out] partitionsToBeModifiedIndex - Index attached to \a partitionsToBeModified to interprete. + * + * \return - The partition array that is the output of the reduction of \a this. + * + * \sa MEDCouplingUMesh::findCommonCells, DataArrayDouble::findCommonTuples + */ + template + MCAuto< typename DataArrayDiscrete::DataArrayType > DataArrayDiscrete::forThisAsPartitionBuildReduction(const MCAuto& commonEntities, const MCAuto& commonEntitiesIndex, MCAuto& partitionsToBeModified, MCAuto& partitionsToBeModifiedIndex) const + { + constexpr char MSG[] = "this should have only one component"; + this->checkAllocated(); this->checkNbOfComps(1,MSG); + commonEntities->checkAllocated(); commonEntities->checkNbOfComps(1,MSG); + commonEntitiesIndex->checkAllocated(); commonEntitiesIndex->checkNbOfComps(1,MSG); + std::size_t initialSpaceSz( this->getNumberOfTuples() ); + mcIdType returnedSpaceSz( 0 );// store size of reducted returned size + // + MCAuto sizeOfPacks( commonEntitiesIndex->deltaShiftIndex() ); + mcIdType maxSizeOfPacks = sizeOfPacks->getMaxValueInArray();// store the max size of common entities + T newValueInThis = this->getMaxValueInArray() + 1; + // + MCAuto o2n( DataArrayIdType::ConvertIndexArrayToO2N(initialSpaceSz,commonEntities->begin(),commonEntitiesIndex->begin(),commonEntitiesIndex->end(),returnedSpaceSz) ); + MCAuto< DataArrayType > ret( DataArrayDiscrete::New() ); + ret->alloc( returnedSpaceSz, 1 ); + ret->fillWithValue( std::numeric_limits::max() ); + // First deal with entities not fused. + MCAuto eltsNotFused( commonEntities->copySorted() ); + eltsNotFused = eltsNotFused->buildComplement( initialSpaceSz ); + MCAuto partionIdsOfNotFused = this->mySelectByTupleIdSafe(eltsNotFused->begin(),eltsNotFused->end()); + MCAuto tupleIdsToSelect = o2n->selectByTupleIdSafe(eltsNotFused->begin(),eltsNotFused->end()); + ret->setPartOfValues3(partionIdsOfNotFused,tupleIdsToSelect->begin(),tupleIdsToSelect->end(),0,1,1); + T *retPt( ret->getPointer() ); + const mcIdType *o2nPt( o2n->begin() ); + // + partitionsToBeModified = DataArrayType::New(); partitionsToBeModified->alloc(0,1); + partitionsToBeModifiedIndex = DataArrayIdType::New(); partitionsToBeModifiedIndex->alloc(1,1); partitionsToBeModifiedIndex->setIJSilent(0,0,0); + const T *ptOfThisData( this->begin() ); + const mcIdType *ceBg( commonEntities->begin() ), *ceiBg( commonEntitiesIndex->begin() ); + for(mcIdType szOfPack = 2 ; szOfPack <= maxSizeOfPacks ; ++szOfPack) + { + MCAuto idsInThisWithSamePackSz = findIdsEqual( FromIdType( szOfPack ) ); + std::set< PartitionCfg > partitionCfgHolder; + for( const mcIdType *idsInThisWithSamePackSzIt = idsInThisWithSamePackSz->begin() ; idsInThisWithSamePackSzIt != idsInThisWithSamePackSz->end() ; ++idsInThisWithSamePackSzIt ) + { + PartitionCfg partitionCfg; + std::transform(ceBg + ceiBg[*idsInThisWithSamePackSzIt],ceBg + ceiBg[*idsInThisWithSamePackSzIt + 1], std::inserter(partitionCfg,partitionCfg.end()),[ptOfThisData](mcIdType elt) { return ptOfThisData[elt]; }); + auto existCfg = partitionCfgHolder.find( partitionCfg ); + if( existCfg != partitionCfgHolder.end() ) + {//partition already exist by a previous pack -> reuse it ! + T newPartitionID = existCfg->getID(); + retPt[ o2nPt[ ceBg [ ceiBg[*idsInThisWithSamePackSzIt] ] ] ] = newPartitionID;// hypothesis that o2n is so that all o2n[ceBg + ceiBg[*idsInThisWithSamePackSzIt],ceBg + ceiBg[*idsInThisWithSamePackSzIt + 1]) points to the same point in new renumbering + } + else + {//partition does not exist yet -> create it ! + partitionCfg.setID( newValueInThis++ ); + partitionCfgHolder.insert( partitionCfg ); + retPt[ o2nPt[ ceBg [ ceiBg[*idsInThisWithSamePackSzIt] ] ] ] = partitionCfg.getID(); + partitionsToBeModified->pushBackSilent( partitionCfg.getID() ); + partitionsToBeModified->pushBackValsSilent(partitionCfg.begin(),partitionCfg.end()); + partitionsToBeModifiedIndex->pushBackSilent( partitionsToBeModifiedIndex->back() + szOfPack + 1 ); + } + } + } + return ret; + } + /*! * This method is a refinement of DataArrayInt::getDifferentValues because it returns not only different values in \a this but also, for each of * them it tells which tuple id have this id. -- 2.39.2