1 // Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // File : SMESHDS_GroupOnFilter.cxx
26 #include "SMESHDS_GroupOnFilter.hxx"
28 #include "SMDS_SetIterator.hxx"
29 #include "ObjectPool.hxx"
30 #include "SMESHDS_Mesh.hxx"
35 #include <boost/make_shared.hpp>
41 //=============================================================================
43 * Creates a group based on thePredicate
45 //=============================================================================
47 SMESHDS_GroupOnFilter::SMESHDS_GroupOnFilter (const int theID,
48 const SMESHDS_Mesh* theMesh,
49 const SMDSAbs_ElementType theType,
50 const SMESH_PredicatePtr& thePredicate)
51 : SMESHDS_GroupBase( theID, theMesh, theType ),
52 SMDS_ElementHolder( theMesh ),
53 myMeshInfo( SMDSEntity_Last, 0 ),
58 SetPredicate( thePredicate );
61 //================================================================================
63 * \brief Sets a new predicate
65 //================================================================================
67 void SMESHDS_GroupOnFilter::SetPredicate( const SMESH_PredicatePtr& thePredicate )
69 myPredicate = thePredicate;
73 myPredicate->SetMesh( GetMesh() );
76 //================================================================================
78 * \brief Returns nb of elements
80 //================================================================================
82 int SMESHDS_GroupOnFilter::Extent() const
85 return std::accumulate( myMeshInfo.begin(), myMeshInfo.end(), 0 );
88 //================================================================================
90 * \brief Checks emptyness
92 //================================================================================
94 bool SMESHDS_GroupOnFilter::IsEmpty()
98 return ( Extent() == 0 );
100 else // not up-to-date
103 SMDS_ElemIteratorPtr okElemIt = GetElements();
104 if ( !okElemIt->more() )
106 // no satisfying elements
117 //================================================================================
119 * \brief Checks if the element belongs to the group
121 //================================================================================
123 bool SMESHDS_GroupOnFilter::Contains (const int theID)
125 return myPredicate && myPredicate->IsSatisfy( theID );
128 //================================================================================
130 * \brief Checks if the element belongs to the group
132 //================================================================================
134 bool SMESHDS_GroupOnFilter::Contains (const SMDS_MeshElement* elem)
136 return myPredicate && myPredicate->IsSatisfy( elem->GetID() );
139 //================================================================================
140 namespace // Iterator
142 struct TIterator : public SMDS_ElemIterator
144 SMESH_PredicatePtr myPredicate;
145 SMDS_ElemIteratorPtr myElemIt;
146 const SMDS_MeshElement* myNextElem;
147 size_t myNbToFind, myNbFound, myTotalNb;
148 vector< const SMDS_MeshElement*>& myFoundElems;
149 bool & myFoundElemsOK;
150 bool myFoundElemsChecked;
152 TIterator( const SMESH_PredicatePtr& filter,
153 SMDS_ElemIteratorPtr& elems,
156 vector< const SMDS_MeshElement*>& foundElems,
157 bool & foundElemsOK):
158 myPredicate( filter ),
161 myNbToFind( nbToFind ),
163 myTotalNb( totalNb ),
164 myFoundElems( foundElems ),
165 myFoundElemsOK( foundElemsOK ),
166 myFoundElemsChecked( false )
168 myFoundElemsOK = false;
173 if ( !myFoundElemsChecked && !myFoundElemsOK )
174 clearVector( myFoundElems );
180 virtual const SMDS_MeshElement* next()
182 const SMDS_MeshElement* res = myNextElem;
183 myNbFound += bool( res );
185 if ( myNbFound < myNbToFind )
187 while ( myElemIt->more() && !myNextElem )
189 myNextElem = myElemIt->next();
190 if ( !myPredicate->IsSatisfy( myNextElem->GetID() ))
194 myFoundElems.push_back( myNextElem );
196 keepOrClearElemVec();
200 keepOrClearElemVec();
204 void keepOrClearElemVec()
206 if ( myNbFound == myTotalNb )
208 myFoundElemsOK = false; // all elems are OK, no need to keep them
212 // nb of bytes used for myFoundElems
213 size_t vecMemSize = myFoundElems.size() * sizeof( SMDS_MeshElement* ) / sizeof(char);
214 size_t aMB = 1024 * 1024;
215 if ( vecMemSize < aMB )
217 myFoundElemsOK = true; // < 1 MB - do not clear
221 int freeRamMB = SMDS_Mesh::CheckMemory( /*doNotRaise=*/true );
223 myFoundElemsOK = true; // hope it's OK
225 myFoundElemsOK = ( freeRamMB * aMB > 10 * vecMemSize );
228 if ( !myFoundElemsOK )
229 clearVector( myFoundElems );
231 myFoundElemsChecked = true; // in destructor: not to clearVector() which may already die
235 struct TEmptyIterator : public SMDS_ElemIterator
237 virtual bool more() { return false; }
238 virtual const SMDS_MeshElement* next() { return 0; }
242 //================================================================================
244 * \brief Return iterator on all elements
246 //================================================================================
248 SMDS_ElemIteratorPtr SMESHDS_GroupOnFilter::GetElements() const
250 size_t nbToFind = std::numeric_limits<size_t>::max();
251 size_t totalNb = GetMesh()->GetMeshInfo().NbElements( GetType() );
253 SMDS_ElemIteratorPtr elemIt; // iterator on all elements to initialize TIterator
256 myPredicate->SetMesh( GetMesh() ); // hope myPredicate updates self here if necessary
261 elemIt = GetMesh()->elementsIterator( GetType() );
265 return SMDS_ElemIteratorPtr( new SMDS_ElementVectorIterator( myElements.begin(),
268 if ( nbToFind == totalNb )
269 return elemIt; // all elements are OK
270 for ( size_t i = 0; i < myNbElemToSkip; ++i )
271 elemIt->next(); // skip w/o check
276 elemIt = SMDS_ElemIteratorPtr( new TEmptyIterator );
279 // the iterator fills myElements if all elements are checked
280 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
281 return SMDS_ElemIteratorPtr
282 ( new TIterator( myPredicate, elemIt, nbToFind, totalNb, me->myElements, me->myElementsOK ));
285 //================================================================================
287 * \brief Return info on sub-types of elements
289 //================================================================================
291 std::vector< int > SMESHDS_GroupOnFilter::GetMeshInfo() const
297 //================================================================================
299 * \brief Fill ids of elements. And return their number.
300 * \a ids must be pre-allocated using nb of elements of type == GetType()
302 //================================================================================
304 int SMESHDS_GroupOnFilter::getElementIds( void* ids, size_t idSize ) const
306 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
311 char* curID = (char*) ids;
312 SMDS_ElemIteratorPtr elIt = GetElements();
317 for ( ; elIt->more(); curID += idSize )
318 (*(int*) curID) = elIt->next()->GetID();
322 // find out nb of elements to skip w/o check before the 1st OK element
323 const SMDS_MeshElement* firstOkElem = me->setNbElemToSkip( elIt );
325 me->myMeshInfo.assign( SMDSEntity_Last, 0 );
326 me->myMeshInfo[ firstOkElem->GetEntityType() ]++;
328 (*(int*) curID) = firstOkElem->GetID();
329 for ( curID += idSize; elIt->more(); curID += idSize )
331 const SMDS_MeshElement* e = elIt->next();
332 (*(int*) curID) = e->GetID();
333 me->myMeshInfo[ e->GetEntityType() ]++;
337 me->setChanged( false );
339 return ( curID - (char*)ids ) / idSize;
342 //================================================================================
344 * \brief Return a value allowing to find out if a group has changed or not
346 //================================================================================
348 int SMESHDS_GroupOnFilter::GetTic() const
350 return GetMesh()->GetMTime() * myPredicateTic;
353 //================================================================================
355 * \brief Return false if update() is needed
357 //================================================================================
359 bool SMESHDS_GroupOnFilter::IsUpToDate() const
361 return !( myMeshModifTime < GetMesh()->GetMTime() );
364 //================================================================================
366 * \brief Updates myElements if necessary
368 //================================================================================
370 void SMESHDS_GroupOnFilter::update() const
372 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
376 if ( !updateParallel() )
378 SMDS_ElemIteratorPtr elIt = GetElements();
379 if ( elIt->more() ) {
380 // find out nb of elements to skip w/o check before the 1st OK element
381 const SMDS_MeshElement* e = me->setNbElemToSkip( elIt );
382 ++me->myMeshInfo[ e->GetEntityType() ];
383 while ( elIt->more() )
384 ++me->myMeshInfo[ elIt->next()->GetEntityType() ];
387 me->setChanged( false );
391 //================================================================================
393 * \brief Updates myElements in parallel
395 //================================================================================
398 #include <tbb/parallel_for.h>
399 #include "tbb/enumerable_thread_specific.h"
401 // a predicate per a thread
402 typedef tbb::enumerable_thread_specific<SMESH_PredicatePtr> TLocalPredicat;
404 struct IsSatisfyParallel
406 vector< char >& myIsElemOK;
407 SMESH_PredicatePtr myPredicate;
408 TLocalPredicat& myLocalPredicates;
409 IsSatisfyParallel( SMESH_PredicatePtr mainPred, TLocalPredicat& locPred, vector< char >& isOk )
410 : myIsElemOK(isOk), myPredicate( mainPred ), myLocalPredicates( locPred )
412 void operator() ( const tbb::blocked_range<size_t>& r ) const
414 SMESH_PredicatePtr& pred = myLocalPredicates.local();
417 if ( r.begin() == 0 )
420 pred.reset( myPredicate->clone() );
422 for ( size_t i = r.begin(); i != r.end(); ++i )
423 myIsElemOK[ i ] = char( pred->IsSatisfy( i ));
427 bool SMESHDS_GroupOnFilter::updateParallel() const
429 // if ( !getenv("updateParallel"))
431 size_t nbElemsOfType = GetMesh()->GetMeshInfo().NbElements( GetType() );
432 if ( nbElemsOfType == 0 )
434 if ( nbElemsOfType < 1000000 )
435 return false; // no sense in parallel work
437 SMDS_ElemIteratorPtr elemIt = GetMesh()->elementsIterator( GetType() );
438 const int minID = elemIt->next()->GetID();
439 myPredicate->IsSatisfy( minID ); // make myPredicate fully initialized for clone()
440 SMESH_PredicatePtr clone( myPredicate->clone() );
444 TLocalPredicat threadPredicates;
445 threadPredicates.local() = clone;
447 int maxID = ( GetType() == SMDSAbs_Node ) ? GetMesh()->MaxNodeID() : GetMesh()->MaxElementID();
448 vector< char > isElemOK( 1 + maxID );
450 tbb::parallel_for ( tbb::blocked_range<size_t>( 0, isElemOK.size() ),
451 IsSatisfyParallel( myPredicate, threadPredicates, isElemOK ),
452 tbb::simple_partitioner());
454 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
457 for ( size_t i = minID; i < isElemOK.size(); ++i )
458 nbOkElems += ( isElemOK[ i ]);
459 me->myElements.resize( nbOkElems );
461 const SMDS_MeshElement* e;
463 if ( GetType() == SMDSAbs_Node )
465 for ( size_t i = minID; i < isElemOK.size(); ++i )
466 if (( isElemOK[ i ] ) &&
467 ( e = GetMesh()->FindNode( i )))
469 me->myElements[ iElem++ ] = e;
471 me->myMeshInfo[ SMDSEntity_Node ] = myElements.size();
475 for ( size_t i = minID; i < isElemOK.size(); ++i )
476 if (( isElemOK[ i ] ) &&
477 ( e = GetMesh()->FindElement( i )) &&
478 ( e->GetType() == GetType() ))
480 me->myElements[ iElem++ ] = e;
481 ++me->myMeshInfo[ e->GetEntityType() ];
484 me->myElementsOK = ( iElem < nbElemsOfType );
486 clearVector( me->myElements ); // all elements satisfy myPredicate
488 me->myElements.resize( iElem );
490 me->setChanged( false );
495 bool SMESHDS_GroupOnFilter::updateParallel() const
502 //================================================================================
504 * \brief Sets myMeshModifTime and clear fields according to modification state
506 //================================================================================
508 void SMESHDS_GroupOnFilter::setChanged(bool changed)
510 myMeshModifTime = GetMesh()->GetMTime();
511 if ( changed && myMeshModifTime != 0 )
514 clearVector( myElements );
515 myElementsOK = false;
517 myMeshInfo.assign( SMDSEntity_Last, 0 );
521 //================================================================================
523 * \brief Sets myNbElemToSkip
524 * \param okElemIt - iterator on OK elements
525 * \retval const SMDS_MeshElement* - the first OK element
527 //================================================================================
529 const SMDS_MeshElement*
530 SMESHDS_GroupOnFilter::setNbElemToSkip( SMDS_ElemIteratorPtr& okElemIt )
532 // find out nb of elements to skip w/o check before the 1st OK element
533 const SMDS_MeshElement* firstOkElem = okElemIt->next();
534 if ( myNbElemToSkip == 0 )
536 SMDS_ElemIteratorPtr elemIt = GetMesh()->elementsIterator( GetType() );
538 while ( elemIt->next() != firstOkElem )
544 //================================================================================
546 * \brief Return elements before mesh compacting
548 //================================================================================
550 SMDS_ElemIteratorPtr SMESHDS_GroupOnFilter::getElements()
552 return boost::make_shared< SMDS_ElementVectorIterator >( myElements.begin(), myElements.end() );
555 //================================================================================
557 * \brief clear myElements before re-filling after mesh compacting
559 //================================================================================
561 void SMESHDS_GroupOnFilter::tmpClear()
563 std::vector< const SMDS_MeshElement*> newElems( myElements.size() );
564 myElements.swap( newElems );
568 //================================================================================
570 * \brief Re-fill myElements after mesh compacting
572 //================================================================================
574 void SMESHDS_GroupOnFilter::add( const SMDS_MeshElement* element )
576 myElements.push_back( element );