X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSMESHDS%2FSMESHDS_GroupOnFilter.cxx;h=e5b2fb736bd3d75362f0f6aae9a85343fc3cf8bf;hb=aa574473cfc2112ef654904d6f2af9fd6e46d4c7;hp=32bd8c7f3485553f1dcb7cc7e7bfd4bba304db29;hpb=bd4e115a78b52e3fbc016e5e30bb0e19b2a9e7d6;p=modules%2Fsmesh.git diff --git a/src/SMESHDS/SMESHDS_GroupOnFilter.cxx b/src/SMESHDS/SMESHDS_GroupOnFilter.cxx index 32bd8c7f3..e5b2fb736 100644 --- a/src/SMESHDS/SMESHDS_GroupOnFilter.cxx +++ b/src/SMESHDS/SMESHDS_GroupOnFilter.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -6,7 +6,7 @@ // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either -// version 2.1 of the License. +// version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,11 +25,19 @@ // #include "SMESHDS_GroupOnFilter.hxx" -#include "SMESHDS_Mesh.hxx" #include "SMDS_SetIterator.hxx" +#include "ObjectPool.hxx" +#include "SMESHDS_Mesh.hxx" + +#include +#include + +#include using namespace std; +//#undef WITH_TBB + //============================================================================= /*! * Creates a group based on thePredicate @@ -40,9 +48,13 @@ SMESHDS_GroupOnFilter::SMESHDS_GroupOnFilter (const int theID, const SMESHDS_Mesh* theMesh, const SMDSAbs_ElementType theType, const SMESH_PredicatePtr& thePredicate) - : SMESHDS_GroupBase(theID,theMesh,theType), myMeshModifTime(0), myPredicateTic(0) + : SMESHDS_GroupBase( theID, theMesh, theType ), + SMDS_ElementHolder( theMesh ), + myMeshInfo( SMDSEntity_Last, 0 ), + myMeshModifTime( 0 ), + myPredicateTic( 0 ), + myNbElemToSkip( 0 ) { - setChanged(); SetPredicate( thePredicate ); } @@ -52,7 +64,7 @@ SMESHDS_GroupOnFilter::SMESHDS_GroupOnFilter (const int theID, */ //================================================================================ -void SMESHDS_GroupOnFilter::SetPredicate( const SMESH_PredicatePtr& thePredicate) +void SMESHDS_GroupOnFilter::SetPredicate( const SMESH_PredicatePtr& thePredicate ) { myPredicate = thePredicate; ++myPredicateTic; @@ -70,7 +82,36 @@ void SMESHDS_GroupOnFilter::SetPredicate( const SMESH_PredicatePtr& thePredicate int SMESHDS_GroupOnFilter::Extent() const { update(); - return myElements.size(); + return std::accumulate( myMeshInfo.begin(), myMeshInfo.end(), 0 ); +} + +//================================================================================ +/*! + * \brief Checks emptyness + */ +//================================================================================ + +bool SMESHDS_GroupOnFilter::IsEmpty() +{ + if ( IsUpToDate() ) + { + return ( Extent() == 0 ); + } + else // not up-to-date + { + setChanged(); + SMDS_ElemIteratorPtr okElemIt = GetElements(); + if ( !okElemIt->more() ) + { + // no satisfying elements + setChanged( false ); + } + else + { + return false; + } + } + return true; } //================================================================================ @@ -81,7 +122,7 @@ int SMESHDS_GroupOnFilter::Extent() const bool SMESHDS_GroupOnFilter::Contains (const int theID) { - return myPredicate ? myPredicate->IsSatisfy( theID ) : false; + return myPredicate && myPredicate->IsSatisfy( theID ); } //================================================================================ @@ -92,7 +133,106 @@ bool SMESHDS_GroupOnFilter::Contains (const int theID) bool SMESHDS_GroupOnFilter::Contains (const SMDS_MeshElement* elem) { - return myPredicate ? myPredicate->IsSatisfy( elem->GetID() ) : false; + return myPredicate && myPredicate->IsSatisfy( elem->GetID() ); +} + +//================================================================================ +namespace // Iterator +{ + struct TIterator : public SMDS_ElemIterator + { + SMESH_PredicatePtr myPredicate; + SMDS_ElemIteratorPtr myElemIt; + const SMDS_MeshElement* myNextElem; + size_t myNbToFind, myNbFound, myTotalNb; + vector< const SMDS_MeshElement*>& myFoundElems; + bool & myFoundElemsOK; + + TIterator( const SMESH_PredicatePtr& filter, + SMDS_ElemIteratorPtr& elems, + size_t nbToFind, + size_t totalNb, + vector< const SMDS_MeshElement*>& foundElems, + bool & foundElemsOK): + myPredicate( filter ), + myElemIt( elems ), + myNextElem( 0 ), + myNbToFind( nbToFind ), + myNbFound( 0 ), + myTotalNb( totalNb ), + myFoundElems( foundElems ), + myFoundElemsOK( foundElemsOK ) + { + myFoundElemsOK = false; + next(); + } + ~TIterator() + { + if ( !myFoundElemsOK ) + clearVector( myFoundElems ); + } + virtual bool more() + { + return myNextElem; + } + virtual const SMDS_MeshElement* next() + { + const SMDS_MeshElement* res = myNextElem; + myNbFound += bool( res ); + myNextElem = 0; + if ( myNbFound < myNbToFind ) + { + while ( myElemIt->more() && !myNextElem ) + { + myNextElem = myElemIt->next(); + if ( !myPredicate->IsSatisfy( myNextElem->GetID() )) + myNextElem = 0; + } + if ( myNextElem ) + myFoundElems.push_back( myNextElem ); + else + keepOrClearElemVec(); + } + else + { + keepOrClearElemVec(); + } + return res; + } + void keepOrClearElemVec() + { + if ( myNbFound == myTotalNb ) + { + myFoundElemsOK = false; // all elems are OK, no need to keep them + } + else + { + // nb of bytes used for myFoundElems + size_t vecMemSize = myFoundElems.size() * sizeof( SMDS_MeshElement* ) / sizeof(char); + size_t aMB = 1024 * 1024; + if ( vecMemSize < aMB ) + { + myFoundElemsOK = true; // < 1 MB - do not clear + } + else + { + int freeRamMB = SMDS_Mesh::CheckMemory( /*doNotRaise=*/true ); + if ( freeRamMB < 0 ) + myFoundElemsOK = true; // hope it's OK + else + myFoundElemsOK = ( freeRamMB * aMB > 10 * vecMemSize ); + } + } + if ( !myFoundElemsOK ) + clearVector( myFoundElems ); + } + }; + + struct TEmptyIterator : public SMDS_ElemIterator + { + virtual bool more() { return false; } + virtual const SMDS_MeshElement* next() { return 0; } + }; } //================================================================================ @@ -103,25 +243,96 @@ bool SMESHDS_GroupOnFilter::Contains (const SMDS_MeshElement* elem) SMDS_ElemIteratorPtr SMESHDS_GroupOnFilter::GetElements() const { - update(); + size_t nbToFind = std::numeric_limits::max(); + size_t totalNb = GetMesh()->GetMeshInfo().NbElements( GetType() ); + + SMDS_ElemIteratorPtr elemIt; // iterator on all elements to initialize TIterator + if ( myPredicate ) + { + myPredicate->SetMesh( GetMesh() ); // hope myPredicate updates self here if necessary + + if ( !IsUpToDate() ) + updateParallel(); + + elemIt = GetMesh()->elementsIterator( GetType() ); + if ( IsUpToDate() ) + { + if ( myElementsOK ) + return SMDS_ElemIteratorPtr( new SMDS_ElementVectorIterator( myElements.begin(), + myElements.end() )); + nbToFind = Extent(); + if ( nbToFind == totalNb ) + return elemIt; // all elements are OK + for ( size_t i = 0; i < myNbElemToSkip; ++i ) + elemIt->next(); // skip w/o check + } + } + else + { + elemIt = SMDS_ElemIteratorPtr( new TEmptyIterator ); + } + + // the iterator fills myElements if all elements are checked + SMESHDS_GroupOnFilter* me = const_cast( this ); return SMDS_ElemIteratorPtr - ( new SMDS_ElementVectorIterator( myElements.begin(), myElements.end() )); + ( new TIterator( myPredicate, elemIt, nbToFind, totalNb, me->myElements, me->myElementsOK )); } //================================================================================ /*! - * \brief return ID of theIndex-th element - * \param theIndex - index countered from 1 - * \retval int - element ID + * \brief Return info on sub-types of elements */ //================================================================================ -int SMESHDS_GroupOnFilter::GetID (const int theIndex) +std::vector< int > SMESHDS_GroupOnFilter::GetMeshInfo() const { update(); - if ( theIndex < 1 || theIndex > myElements.size() ) - return -1; - return myElements[ theIndex-1 ]->GetID(); + return myMeshInfo; +} + +//================================================================================ +/*! + * \brief Fill ids of elements. And return their number. + * \a ids must be pre-allocated using nb of elements of type == GetType() + */ +//================================================================================ + +int SMESHDS_GroupOnFilter::getElementIds( void* ids, size_t idSize ) const +{ + SMESHDS_GroupOnFilter* me = const_cast( this ); + + if ( !IsUpToDate() ) + me->setChanged(); + + char* curID = (char*) ids; + SMDS_ElemIteratorPtr elIt = GetElements(); + if ( elIt->more() ) + { + if ( IsUpToDate() ) + { + for ( ; elIt->more(); curID += idSize ) + (*(int*) curID) = elIt->next()->GetID(); + } + else + { + // find out nb of elements to skip w/o check before the 1st OK element + const SMDS_MeshElement* firstOkElem = me->setNbElemToSkip( elIt ); + + me->myMeshInfo.assign( SMDSEntity_Last, 0 ); + me->myMeshInfo[ firstOkElem->GetEntityType() ]++; + + (*(int*) curID) = firstOkElem->GetID(); + for ( curID += idSize; elIt->more(); curID += idSize ) + { + const SMDS_MeshElement* e = elIt->next(); + (*(int*) curID) = e->GetID(); + me->myMeshInfo[ e->GetEntityType() ]++; + } + } + } + me->setChanged( false ); + + return ( curID - (char*)ids ) / idSize; } //================================================================================ @@ -154,23 +365,20 @@ bool SMESHDS_GroupOnFilter::IsUpToDate() const void SMESHDS_GroupOnFilter::update() const { + SMESHDS_GroupOnFilter* me = const_cast( this ); if ( !IsUpToDate() ) { - SMESHDS_GroupOnFilter* me = const_cast( this ); - me->myElements.clear(); - if ( myPredicate ) + me->setChanged(); + if ( !updateParallel() ) { - myPredicate->SetMesh( GetMesh() ); // hope myPredicate updates self here if necessary - me->myElements.reserve( GetMesh()->GetMeshInfo().NbElements(GetType())); - SMDS_ElemIteratorPtr elIt = GetMesh()->elementsIterator(GetType()); - while ( elIt->more() ) - { - const SMDS_MeshElement* e = elIt->next(); - if ( myPredicate->IsSatisfy( e->GetID() )) - me->myElements.push_back( e ); + SMDS_ElemIteratorPtr elIt = GetElements(); + if ( elIt->more() ) { + // find out nb of elements to skip w/o check before the 1st OK element + const SMDS_MeshElement* e = me->setNbElemToSkip( elIt ); + ++me->myMeshInfo[ e->GetEntityType() ]; + while ( elIt->more() ) + ++me->myMeshInfo[ elIt->next()->GetEntityType() ]; } - vector< const SMDS_MeshElement*> elems( me->myElements.begin(), me->myElements.end() ); - me->myElements.swap( elems ); } me->setChanged( false ); } @@ -178,7 +386,118 @@ void SMESHDS_GroupOnFilter::update() const //================================================================================ /*! - * \brief Sets myMeshModifTime according to modification state + * \brief Updates myElements in parallel + */ +//================================================================================ +#ifdef WITH_TBB + +#include +#include "tbb/enumerable_thread_specific.h" + +// a predicate per a thread +typedef tbb::enumerable_thread_specific TLocalPredicat; + +struct IsSatisfyParallel +{ + vector< char >& myIsElemOK; + SMESH_PredicatePtr myPredicate; + TLocalPredicat& myLocalPredicates; + IsSatisfyParallel( SMESH_PredicatePtr mainPred, TLocalPredicat& locPred, vector< char >& isOk ) + : myIsElemOK(isOk), myPredicate( mainPred ), myLocalPredicates( locPred ) + {} + void operator() ( const tbb::blocked_range& r ) const + { + SMESH_PredicatePtr& pred = myLocalPredicates.local(); + if ( !pred ) + { + if ( r.begin() == 0 ) + pred = myPredicate; + else + pred.reset( myPredicate->clone() ); + } + for ( size_t i = r.begin(); i != r.end(); ++i ) + myIsElemOK[ i ] = char( pred->IsSatisfy( i )); + } +}; + +bool SMESHDS_GroupOnFilter::updateParallel() const +{ + // if ( !getenv("updateParallel")) + // return false; + size_t nbElemsOfType = GetMesh()->GetMeshInfo().NbElements( GetType() ); + if ( nbElemsOfType == 0 ) + return true; + if ( nbElemsOfType < 1000000 ) + return false; // no sense in parallel work + + SMDS_ElemIteratorPtr elemIt = GetMesh()->elementsIterator( GetType() ); + const int minID = elemIt->next()->GetID(); + myPredicate->IsSatisfy( minID ); // make myPredicate fully initialized for clone() + SMESH_PredicatePtr clone( myPredicate->clone() ); + if ( !clone ) + return false; + + TLocalPredicat threadPredicates; + threadPredicates.local() = clone; + + int maxID = ( GetType() == SMDSAbs_Node ) ? GetMesh()->MaxNodeID() : GetMesh()->MaxElementID(); + vector< char > isElemOK( 1 + maxID ); + + tbb::parallel_for ( tbb::blocked_range( 0, isElemOK.size() ), + IsSatisfyParallel( myPredicate, threadPredicates, isElemOK ), + tbb::simple_partitioner()); + + SMESHDS_GroupOnFilter* me = const_cast( this ); + + int nbOkElems = 0; + for ( size_t i = minID; i < isElemOK.size(); ++i ) + nbOkElems += ( isElemOK[ i ]); + me->myElements.resize( nbOkElems ); + + const SMDS_MeshElement* e; + size_t iElem = 0; + if ( GetType() == SMDSAbs_Node ) + { + for ( size_t i = minID; i < isElemOK.size(); ++i ) + if (( isElemOK[ i ] ) && + ( e = GetMesh()->FindNode( i ))) + { + me->myElements[ iElem++ ] = e; + } + me->myMeshInfo[ SMDSEntity_Node ] = myElements.size(); + } + else + { + for ( size_t i = minID; i < isElemOK.size(); ++i ) + if (( isElemOK[ i ] ) && + ( e = GetMesh()->FindElement( i )) && + ( e->GetType() == GetType() )) + { + me->myElements[ iElem++ ] = e; + ++me->myMeshInfo[ e->GetEntityType() ]; + } + } + me->myElementsOK = ( iElem < nbElemsOfType ); + if ( !myElementsOK ) + clearVector( me->myElements ); // all elements satisfy myPredicate + else + me->myElements.resize( iElem ); + + me->setChanged( false ); + return true; +} +#else + +bool SMESHDS_GroupOnFilter::updateParallel() const +{ + return false; +} + +#endif + +//================================================================================ +/*! + * \brief Sets myMeshModifTime and clear fields according to modification state */ //================================================================================ @@ -187,4 +506,68 @@ void SMESHDS_GroupOnFilter::setChanged(bool changed) myMeshModifTime = GetMesh()->GetMTime(); if ( changed && myMeshModifTime != 0 ) --myMeshModifTime; + if ( changed ) { + clearVector( myElements ); + myElementsOK = false; + myNbElemToSkip = 0; + myMeshInfo.assign( SMDSEntity_Last, 0 ); + } +} + +//================================================================================ +/*! + * \brief Sets myNbElemToSkip + * \param okElemIt - iterator on OK elements + * \retval const SMDS_MeshElement* - the first OK element + */ +//================================================================================ + +const SMDS_MeshElement* +SMESHDS_GroupOnFilter::setNbElemToSkip( SMDS_ElemIteratorPtr& okElemIt ) +{ + // find out nb of elements to skip w/o check before the 1st OK element + const SMDS_MeshElement* firstOkElem = okElemIt->next(); + if ( myNbElemToSkip == 0 ) + { + SMDS_ElemIteratorPtr elemIt = GetMesh()->elementsIterator( GetType() ); + myNbElemToSkip = 0; + while ( elemIt->next() != firstOkElem ) + ++myNbElemToSkip; + } + return firstOkElem; +} + +//================================================================================ +/*! + * \brief Return elements before mesh compacting + */ +//================================================================================ + +SMDS_ElemIteratorPtr SMESHDS_GroupOnFilter::getElements() +{ + return boost::make_shared< SMDS_ElementVectorIterator >( myElements.begin(), myElements.end() ); +} + +//================================================================================ +/*! + * \brief clear myElements before re-filling after mesh compacting + */ +//================================================================================ + +void SMESHDS_GroupOnFilter::tmpClear() +{ + std::vector< const SMDS_MeshElement*> newElems( myElements.size() ); + myElements.swap( newElems ); + myElements.clear(); +} + +//================================================================================ +/*! + * \brief Re-fill myElements after mesh compacting + */ +//================================================================================ + +void SMESHDS_GroupOnFilter::add( const SMDS_MeshElement* element ) +{ + myElements.push_back( element ); }