1 // Copyright (C) 2007-2016 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;
151 TIterator( const SMESH_PredicatePtr& filter,
152 SMDS_ElemIteratorPtr& elems,
155 vector< const SMDS_MeshElement*>& foundElems,
156 bool & foundElemsOK):
157 myPredicate( filter ),
160 myNbToFind( nbToFind ),
162 myTotalNb( totalNb ),
163 myFoundElems( foundElems ),
164 myFoundElemsOK( foundElemsOK )
166 myFoundElemsOK = false;
171 if ( !myFoundElemsOK )
172 clearVector( myFoundElems );
178 virtual const SMDS_MeshElement* next()
180 const SMDS_MeshElement* res = myNextElem;
181 myNbFound += bool( res );
183 if ( myNbFound < myNbToFind )
185 while ( myElemIt->more() && !myNextElem )
187 myNextElem = myElemIt->next();
188 if ( !myPredicate->IsSatisfy( myNextElem->GetID() ))
192 myFoundElems.push_back( myNextElem );
194 keepOrClearElemVec();
198 keepOrClearElemVec();
202 void keepOrClearElemVec()
204 if ( myNbFound == myTotalNb )
206 myFoundElemsOK = false; // all elems are OK, no need to keep them
210 // nb of bytes used for myFoundElems
211 size_t vecMemSize = myFoundElems.size() * sizeof( SMDS_MeshElement* ) / sizeof(char);
212 size_t aMB = 1024 * 1024;
213 if ( vecMemSize < aMB )
215 myFoundElemsOK = true; // < 1 MB - do not clear
219 int freeRamMB = SMDS_Mesh::CheckMemory( /*doNotRaise=*/true );
221 myFoundElemsOK = true; // hope it's OK
223 myFoundElemsOK = ( freeRamMB * aMB > 10 * vecMemSize );
226 if ( !myFoundElemsOK )
227 clearVector( myFoundElems );
231 struct TEmptyIterator : public SMDS_ElemIterator
233 virtual bool more() { return false; }
234 virtual const SMDS_MeshElement* next() { return 0; }
238 //================================================================================
240 * \brief Return iterator on all elements
242 //================================================================================
244 SMDS_ElemIteratorPtr SMESHDS_GroupOnFilter::GetElements() const
246 size_t nbToFind = std::numeric_limits<size_t>::max();
247 size_t totalNb = GetMesh()->GetMeshInfo().NbElements( GetType() );
249 SMDS_ElemIteratorPtr elemIt; // iterator on all elements to initialize TIterator
252 myPredicate->SetMesh( GetMesh() ); // hope myPredicate updates self here if necessary
257 elemIt = GetMesh()->elementsIterator( GetType() );
261 return SMDS_ElemIteratorPtr( new SMDS_ElementVectorIterator( myElements.begin(),
264 if ( nbToFind == totalNb )
265 return elemIt; // all elements are OK
266 for ( size_t i = 0; i < myNbElemToSkip; ++i )
267 elemIt->next(); // skip w/o check
272 elemIt = SMDS_ElemIteratorPtr( new TEmptyIterator );
275 // the iterator fills myElements if all elements are checked
276 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
277 return SMDS_ElemIteratorPtr
278 ( new TIterator( myPredicate, elemIt, nbToFind, totalNb, me->myElements, me->myElementsOK ));
281 //================================================================================
283 * \brief Return info on sub-types of elements
285 //================================================================================
287 std::vector< int > SMESHDS_GroupOnFilter::GetMeshInfo() const
293 //================================================================================
295 * \brief Fill ids of elements. And return their number.
296 * \a ids must be pre-allocated using nb of elements of type == GetType()
298 //================================================================================
300 int SMESHDS_GroupOnFilter::getElementIds( void* ids, size_t idSize ) const
302 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
307 char* curID = (char*) ids;
308 SMDS_ElemIteratorPtr elIt = GetElements();
313 for ( ; elIt->more(); curID += idSize )
314 (*(int*) curID) = elIt->next()->GetID();
318 // find out nb of elements to skip w/o check before the 1st OK element
319 const SMDS_MeshElement* firstOkElem = me->setNbElemToSkip( elIt );
321 me->myMeshInfo.assign( SMDSEntity_Last, 0 );
322 me->myMeshInfo[ firstOkElem->GetEntityType() ]++;
324 (*(int*) curID) = firstOkElem->GetID();
325 for ( curID += idSize; elIt->more(); curID += idSize )
327 const SMDS_MeshElement* e = elIt->next();
328 (*(int*) curID) = e->GetID();
329 me->myMeshInfo[ e->GetEntityType() ]++;
333 me->setChanged( false );
335 return ( curID - (char*)ids ) / idSize;
338 //================================================================================
340 * \brief Return a value allowing to find out if a group has changed or not
342 //================================================================================
344 int SMESHDS_GroupOnFilter::GetTic() const
346 return GetMesh()->GetMTime() * myPredicateTic;
349 //================================================================================
351 * \brief Return false if update() is needed
353 //================================================================================
355 bool SMESHDS_GroupOnFilter::IsUpToDate() const
357 return !( myMeshModifTime < GetMesh()->GetMTime() );
360 //================================================================================
362 * \brief Updates myElements if necessary
364 //================================================================================
366 void SMESHDS_GroupOnFilter::update() const
368 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
372 if ( !updateParallel() )
374 SMDS_ElemIteratorPtr elIt = GetElements();
375 if ( elIt->more() ) {
376 // find out nb of elements to skip w/o check before the 1st OK element
377 const SMDS_MeshElement* e = me->setNbElemToSkip( elIt );
378 ++me->myMeshInfo[ e->GetEntityType() ];
379 while ( elIt->more() )
380 ++me->myMeshInfo[ elIt->next()->GetEntityType() ];
383 me->setChanged( false );
387 //================================================================================
389 * \brief Updates myElements in parallel
391 //================================================================================
394 #include <tbb/parallel_for.h>
395 #include "tbb/enumerable_thread_specific.h"
397 // a predicate per a thread
398 typedef tbb::enumerable_thread_specific<SMESH_PredicatePtr> TLocalPredicat;
400 struct IsSatisfyParallel
402 vector< char >& myIsElemOK;
403 SMESH_PredicatePtr myPredicate;
404 TLocalPredicat& myLocalPredicates;
405 IsSatisfyParallel( SMESH_PredicatePtr mainPred, TLocalPredicat& locPred, vector< char >& isOk )
406 : myIsElemOK(isOk), myPredicate( mainPred ), myLocalPredicates( locPred )
408 void operator() ( const tbb::blocked_range<size_t>& r ) const
410 SMESH_PredicatePtr& pred = myLocalPredicates.local();
413 if ( r.begin() == 0 )
416 pred.reset( myPredicate->clone() );
418 for ( size_t i = r.begin(); i != r.end(); ++i )
419 myIsElemOK[ i ] = char( pred->IsSatisfy( i ));
423 bool SMESHDS_GroupOnFilter::updateParallel() const
425 // if ( !getenv("updateParallel"))
427 size_t nbElemsOfType = GetMesh()->GetMeshInfo().NbElements( GetType() );
428 if ( nbElemsOfType == 0 )
430 if ( nbElemsOfType < 1000000 )
431 return false; // no sense in parallel work
433 SMDS_ElemIteratorPtr elemIt = GetMesh()->elementsIterator( GetType() );
434 const int minID = elemIt->next()->GetID();
435 myPredicate->IsSatisfy( minID ); // make myPredicate fully initialized for clone()
436 SMESH_PredicatePtr clone( myPredicate->clone() );
440 TLocalPredicat threadPredicates;
441 threadPredicates.local() = clone;
443 int maxID = ( GetType() == SMDSAbs_Node ) ? GetMesh()->MaxNodeID() : GetMesh()->MaxElementID();
444 vector< char > isElemOK( 1 + maxID );
446 tbb::parallel_for ( tbb::blocked_range<size_t>( 0, isElemOK.size() ),
447 IsSatisfyParallel( myPredicate, threadPredicates, isElemOK ),
448 tbb::simple_partitioner());
450 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
453 for ( size_t i = minID; i < isElemOK.size(); ++i )
454 nbOkElems += ( isElemOK[ i ]);
455 me->myElements.resize( nbOkElems );
457 const SMDS_MeshElement* e;
459 if ( GetType() == SMDSAbs_Node )
461 for ( size_t i = minID; i < isElemOK.size(); ++i )
462 if (( isElemOK[ i ] ) &&
463 ( e = GetMesh()->FindNode( i )))
465 me->myElements[ iElem++ ] = e;
467 me->myMeshInfo[ SMDSEntity_Node ] = myElements.size();
471 for ( size_t i = minID; i < isElemOK.size(); ++i )
472 if (( isElemOK[ i ] ) &&
473 ( e = GetMesh()->FindElement( i )) &&
474 ( e->GetType() == GetType() ))
476 me->myElements[ iElem++ ] = e;
477 ++me->myMeshInfo[ e->GetEntityType() ];
480 me->myElementsOK = ( iElem < nbElemsOfType );
482 clearVector( me->myElements ); // all elements satisfy myPredicate
484 me->myElements.resize( iElem );
486 me->setChanged( false );
491 bool SMESHDS_GroupOnFilter::updateParallel() const
498 //================================================================================
500 * \brief Sets myMeshModifTime and clear fields according to modification state
502 //================================================================================
504 void SMESHDS_GroupOnFilter::setChanged(bool changed)
506 myMeshModifTime = GetMesh()->GetMTime();
507 if ( changed && myMeshModifTime != 0 )
510 clearVector( myElements );
511 myElementsOK = false;
513 myMeshInfo.assign( SMDSEntity_Last, 0 );
517 //================================================================================
519 * \brief Sets myNbElemToSkip
520 * \param okElemIt - iterator on OK elements
521 * \retval const SMDS_MeshElement* - the first OK element
523 //================================================================================
525 const SMDS_MeshElement*
526 SMESHDS_GroupOnFilter::setNbElemToSkip( SMDS_ElemIteratorPtr& okElemIt )
528 // find out nb of elements to skip w/o check before the 1st OK element
529 const SMDS_MeshElement* firstOkElem = okElemIt->next();
530 if ( myNbElemToSkip == 0 )
532 SMDS_ElemIteratorPtr elemIt = GetMesh()->elementsIterator( GetType() );
534 while ( elemIt->next() != firstOkElem )
540 //================================================================================
542 * \brief Return elements before mesh compacting
544 //================================================================================
546 SMDS_ElemIteratorPtr SMESHDS_GroupOnFilter::getElements()
548 return boost::make_shared< SMDS_ElementVectorIterator >( myElements.begin(), myElements.end() );
551 //================================================================================
553 * \brief clear myElements before re-filling after mesh compacting
555 //================================================================================
557 void SMESHDS_GroupOnFilter::tmpClear()
559 std::vector< const SMDS_MeshElement*> newElems( myElements.size() );
560 myElements.swap( newElems );
564 //================================================================================
566 * \brief Re-fill myElements after mesh compacting
568 //================================================================================
570 void SMESHDS_GroupOnFilter::add( const SMDS_MeshElement* element )
572 myElements.push_back( element );