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 "SMESHDS_Mesh.hxx"
38 //=============================================================================
40 * Creates a group based on thePredicate
42 //=============================================================================
44 SMESHDS_GroupOnFilter::SMESHDS_GroupOnFilter (const int theID,
45 const SMESHDS_Mesh* theMesh,
46 const SMDSAbs_ElementType theType,
47 const SMESH_PredicatePtr& thePredicate)
48 : SMESHDS_GroupBase(theID,theMesh,theType),
49 myMeshInfo( SMDSEntity_Last, 0 ),
54 SetPredicate( thePredicate );
57 //================================================================================
59 * \brief Sets a new predicate
61 //================================================================================
63 void SMESHDS_GroupOnFilter::SetPredicate( const SMESH_PredicatePtr& thePredicate )
65 myPredicate = thePredicate;
69 myPredicate->SetMesh( GetMesh() );
72 //================================================================================
74 * \brief Returns nb of elements
76 //================================================================================
78 int SMESHDS_GroupOnFilter::Extent() const
81 return std::accumulate( myMeshInfo.begin(), myMeshInfo.end(), 0 );
84 //================================================================================
86 * \brief Checks emptyness
88 //================================================================================
90 bool SMESHDS_GroupOnFilter::IsEmpty()
94 return ( Extent() == 0 );
96 else // not up-to-date
99 SMDS_ElemIteratorPtr okElemIt = GetElements();
100 if ( !okElemIt->more() )
102 // no satisfying elements
113 //================================================================================
115 * \brief Checks if the element belongs to the group
117 //================================================================================
119 bool SMESHDS_GroupOnFilter::Contains (const int theID)
121 return myPredicate && myPredicate->IsSatisfy( theID );
124 //================================================================================
126 * \brief Checks if the element belongs to the group
128 //================================================================================
130 bool SMESHDS_GroupOnFilter::Contains (const SMDS_MeshElement* elem)
132 return myPredicate && myPredicate->IsSatisfy( elem->GetID() );
135 //================================================================================
136 namespace // Iterator
138 struct TIterator : public SMDS_ElemIterator
140 SMESH_PredicatePtr myPredicate;
141 SMDS_ElemIteratorPtr myElemIt;
142 const SMDS_MeshElement* myNextElem;
143 size_t myNbToFind, myNbFound, myTotalNb;
144 vector< const SMDS_MeshElement*>& myFoundElems;
145 bool & myFoundElemsOK;
147 TIterator( const SMESH_PredicatePtr& filter,
148 SMDS_ElemIteratorPtr& elems,
151 vector< const SMDS_MeshElement*>& foundElems,
152 bool & foundElemsOK):
153 myPredicate( filter ),
156 myNbToFind( nbToFind ),
158 myTotalNb( totalNb ),
159 myFoundElems( foundElems ),
160 myFoundElemsOK( foundElemsOK )
162 myFoundElemsOK = false;
167 if ( !myFoundElemsOK )
168 clearVector( myFoundElems );
174 virtual const SMDS_MeshElement* next()
176 const SMDS_MeshElement* res = myNextElem;
177 myNbFound += bool( res );
179 if ( myNbFound < myNbToFind )
181 while ( myElemIt->more() && !myNextElem )
183 myNextElem = myElemIt->next();
184 if ( !myPredicate->IsSatisfy( myNextElem->GetID() ))
188 myFoundElems.push_back( myNextElem );
190 keepOrClearElemVec();
194 keepOrClearElemVec();
198 void keepOrClearElemVec()
200 if ( myNbFound == myTotalNb )
202 myFoundElemsOK = false; // all elems are OK, no need to keep them
206 // nb of bytes used for myFoundElems
207 size_t vecMemSize = myFoundElems.size() * sizeof( SMDS_MeshElement* ) / sizeof(char);
208 size_t aMB = 1024 * 1024;
209 if ( vecMemSize < aMB )
211 myFoundElemsOK = true; // < 1 MB - do not clear
215 int freeRamMB = SMDS_Mesh::CheckMemory( /*doNotRaise=*/true );
217 myFoundElemsOK = true; // hope it's OK
219 myFoundElemsOK = ( freeRamMB * aMB > 10 * vecMemSize );
222 if ( !myFoundElemsOK )
223 clearVector( myFoundElems );
227 struct TEmptyIterator : public SMDS_ElemIterator
229 virtual bool more() { return false; }
230 virtual const SMDS_MeshElement* next() { return 0; }
234 //================================================================================
236 * \brief Return iterator on all elements
238 //================================================================================
240 SMDS_ElemIteratorPtr SMESHDS_GroupOnFilter::GetElements() const
242 size_t nbToFind = std::numeric_limits<size_t>::max();
243 size_t totalNb = GetMesh()->GetMeshInfo().NbElements( GetType() );
245 SMDS_ElemIteratorPtr elemIt; // iterator on all elements to initialize TIterator
248 myPredicate->SetMesh( GetMesh() ); // hope myPredicate updates self here if necessary
253 elemIt = GetMesh()->elementsIterator( GetType() );
257 return SMDS_ElemIteratorPtr( new SMDS_ElementVectorIterator( myElements.begin(),
260 if ( nbToFind == totalNb )
261 return elemIt; // all elements are OK
262 for ( size_t i = 0; i < myNbElemToSkip; ++i )
263 elemIt->next(); // skip w/o check
268 elemIt = SMDS_ElemIteratorPtr( new TEmptyIterator );
271 // the iterator fills myElements if all elements are checked
272 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
273 return SMDS_ElemIteratorPtr
274 ( new TIterator( myPredicate, elemIt, nbToFind, totalNb, me->myElements, me->myElementsOK ));
277 //================================================================================
279 * \brief Return info on sub-types of elements
281 //================================================================================
283 std::vector< int > SMESHDS_GroupOnFilter::GetMeshInfo() const
289 //================================================================================
291 * \brief Fill ids of elements. And return their number.
292 * \a ids must be pre-allocated using nb of elements of type == GetType()
294 //================================================================================
296 int SMESHDS_GroupOnFilter::getElementIds( void* ids, size_t idSize ) const
298 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
303 char* curID = (char*) ids;
304 SMDS_ElemIteratorPtr elIt = GetElements();
309 for ( ; elIt->more(); curID += idSize )
310 (*(int*) curID) = elIt->next()->GetID();
314 // find out nb of elements to skip w/o check before the 1st OK element
315 const SMDS_MeshElement* firstOkElem = me->setNbElemToSkip( elIt );
317 me->myMeshInfo.assign( SMDSEntity_Last, 0 );
318 me->myMeshInfo[ firstOkElem->GetEntityType() ]++;
320 (*(int*) curID) = firstOkElem->GetID();
321 for ( curID += idSize; elIt->more(); curID += idSize )
323 const SMDS_MeshElement* e = elIt->next();
324 (*(int*) curID) = e->GetID();
325 me->myMeshInfo[ e->GetEntityType() ]++;
329 me->setChanged( false );
331 return ( curID - (char*)ids ) / idSize;
334 //================================================================================
336 * \brief Return a value allowing to find out if a group has changed or not
338 //================================================================================
340 int SMESHDS_GroupOnFilter::GetTic() const
342 return GetMesh()->GetMTime() * myPredicateTic;
345 //================================================================================
347 * \brief Return false if update() is needed
349 //================================================================================
351 bool SMESHDS_GroupOnFilter::IsUpToDate() const
353 return !( myMeshModifTime < GetMesh()->GetMTime() );
356 //================================================================================
358 * \brief Updates myElements if necessary
360 //================================================================================
362 void SMESHDS_GroupOnFilter::update() const
364 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
368 if ( !updateParallel() )
370 SMDS_ElemIteratorPtr elIt = GetElements();
371 if ( elIt->more() ) {
372 // find out nb of elements to skip w/o check before the 1st OK element
373 const SMDS_MeshElement* e = me->setNbElemToSkip( elIt );
374 ++me->myMeshInfo[ e->GetEntityType() ];
375 while ( elIt->more() )
376 ++me->myMeshInfo[ elIt->next()->GetEntityType() ];
379 me->setChanged( false );
383 //================================================================================
385 * \brief Updates myElements in parallel
387 //================================================================================
390 #include <tbb/parallel_for.h>
391 #include "tbb/enumerable_thread_specific.h"
393 // a predicate per a thread
394 typedef tbb::enumerable_thread_specific<SMESH_PredicatePtr> TLocalPredicat;
396 struct IsSatisfyParallel
398 vector< char >& myIsElemOK;
399 SMESH_PredicatePtr myPredicate;
400 TLocalPredicat& myLocalPredicates;
401 IsSatisfyParallel( SMESH_PredicatePtr mainPred, TLocalPredicat& locPred, vector< char >& isOk )
402 : myIsElemOK(isOk), myPredicate( mainPred ), myLocalPredicates( locPred )
404 void operator() ( const tbb::blocked_range<size_t>& r ) const
406 SMESH_PredicatePtr& pred = myLocalPredicates.local();
409 if ( r.begin() == 0 )
412 pred.reset( myPredicate->clone() );
414 for ( size_t i = r.begin(); i != r.end(); ++i )
415 myIsElemOK[ i ] = char( pred->IsSatisfy( i ));
419 bool SMESHDS_GroupOnFilter::updateParallel() const
421 // if ( !getenv("updateParallel"))
423 size_t nbElemsOfType = GetMesh()->GetMeshInfo().NbElements( GetType() );
424 if ( nbElemsOfType == 0 )
426 if ( nbElemsOfType < 1000000 )
427 return false; // no sense in parallel work
429 SMDS_ElemIteratorPtr elemIt = GetMesh()->elementsIterator( GetType() );
430 const int minID = elemIt->next()->GetID();
431 myPredicate->IsSatisfy( minID ); // make myPredicate fully initialized for clone()
432 SMESH_PredicatePtr clone( myPredicate->clone() );
436 TLocalPredicat threadPredicates;
437 threadPredicates.local() = clone;
439 int maxID = ( GetType() == SMDSAbs_Node ) ? GetMesh()->MaxNodeID() : GetMesh()->MaxElementID();
440 vector< char > isElemOK( 1 + maxID );
442 tbb::parallel_for ( tbb::blocked_range<size_t>( 0, isElemOK.size() ),
443 IsSatisfyParallel( myPredicate, threadPredicates, isElemOK ),
444 tbb::simple_partitioner());
446 SMESHDS_GroupOnFilter* me = const_cast<SMESHDS_GroupOnFilter*>( this );
449 for ( size_t i = minID; i < isElemOK.size(); ++i )
450 nbOkElems += ( isElemOK[ i ]);
451 me->myElements.resize( nbOkElems );
453 const SMDS_MeshElement* e;
455 if ( GetType() == SMDSAbs_Node )
457 for ( size_t i = minID; i < isElemOK.size(); ++i )
458 if (( isElemOK[ i ] ) &&
459 ( e = GetMesh()->FindNode( i )))
461 me->myElements[ iElem++ ] = e;
463 me->myMeshInfo[ SMDSEntity_Node ] = myElements.size();
467 for ( size_t i = minID; i < isElemOK.size(); ++i )
468 if (( isElemOK[ i ] ) &&
469 ( e = GetMesh()->FindElement( i )) &&
470 ( e->GetType() == GetType() ))
472 me->myElements[ iElem++ ] = e;
473 ++me->myMeshInfo[ e->GetEntityType() ];
476 me->myElementsOK = ( iElem < nbElemsOfType );
478 clearVector( me->myElements ); // all elements satisfy myPredicate
480 me->myElements.resize( iElem );
482 me->setChanged( false );
487 bool SMESHDS_GroupOnFilter::updateParallel() const
494 //================================================================================
496 * \brief Sets myMeshModifTime and clear fields according to modification state
498 //================================================================================
500 void SMESHDS_GroupOnFilter::setChanged(bool changed)
502 myMeshModifTime = GetMesh()->GetMTime();
503 if ( changed && myMeshModifTime != 0 )
506 clearVector( myElements );
507 myElementsOK = false;
509 myMeshInfo.assign( SMDSEntity_Last, 0 );
513 //================================================================================
515 * \brief Sets myNbElemToSkip
516 * \param okElemIt - iterator on OK elements
517 * \retval const SMDS_MeshElement* - the first OK element
519 //================================================================================
521 const SMDS_MeshElement*
522 SMESHDS_GroupOnFilter::setNbElemToSkip( SMDS_ElemIteratorPtr& okElemIt )
524 // find out nb of elements to skip w/o check before the 1st OK element
525 const SMDS_MeshElement* firstOkElem = okElemIt->next();
526 if ( myNbElemToSkip == 0 )
528 SMDS_ElemIteratorPtr elemIt = GetMesh()->elementsIterator( GetType() );
530 while ( elemIt->next() != firstOkElem )