diff --git a/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h b/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h index 0e5d3c9cb67..5ec5edcdfe1 100644 --- a/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h +++ b/Mesh_3/include/CGAL/Mesh_3/C3T3_helpers.h @@ -409,7 +409,7 @@ protected: return true; } - void unlock_all_elements() {} + void unlock_all_elements() const {} }; #ifdef CGAL_LINKED_WITH_TBB @@ -494,7 +494,7 @@ protected: return locked; } - void unlock_all_elements() + void unlock_all_elements() const { if (m_lock_ds) { @@ -615,7 +615,7 @@ public: * * Same as update_mesh, but with the precondition that * Th().no_topological_change(tr_, old_vertex, new_position, - * incident_cells) return false. + * incident_cells_) return false. */ template std::pair @@ -698,6 +698,23 @@ public: Outdated_cell_set& outdated_cells_set, Moving_vertices_set& moving_vertices, bool *p_could_lock_zone); + + /** + * Try to lock the incident cells and return them in \c cells + * Return value: + * - false: everything is unlocked and \c cells is empty + * - true: incident cells are locked and \c cells contains all of them + */ + bool + try_lock_and_get_incident_cells(const Vertex_handle& v, + Cell_vector &cells) const; + + /** + * Get the incident cells and return them in \c cells + */ + void + get_incident_cells_without_using_tds_data(const Vertex_handle& v, + Cell_vector &cells) const; /** * Outputs to out the sliver (wrt \c criterion and \c sliver_bound) incident @@ -1556,6 +1573,114 @@ private: } } } + + // Used by the parallel version + template + void update_facets(std::vector& outdated_cells_vector, FacetUpdater updater) + { +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_base_of::value) + { + tbb::parallel_for(tbb::blocked_range(0, outdated_cells_vector.size()), + [&]( const tbb::blocked_range& r ) // CJTODO: lambdas ok? + { + for( size_t i = r.begin() ; i != r.end() ; ++i) + { + const Cell_handle cell = outdated_cells_vector[i]; + Cell_handle null_cell; + bool inf = false; + for (int i=0 ; i<4 && (!inf) ; ++i ){ + if ( tr_.is_infinite(cell->vertex(i)) ){ + inf = true; + Cell_handle n = cell->neighbor(i); + if(n->next_intrusive() != null_cell){// the neighbor is also outdated + if(cell < n){ // otherwise n will report it later + Facet f(cell,i); + updater(f); + } + } else { // report it now or never + if(cell < n){ + Facet f(cell,i); + updater(f); + }else { + Facet f(n,n->index(cell)); + updater(f); + } + } + } + } + if(! inf){ + for ( int i=0 ; i<4 ; ++i ){ + Cell_handle n = cell->neighbor(i); + if(n->next_intrusive() != null_cell){// the neighbor is also outdated + if(cell < n){ // otherwise n will report it later + Facet f(cell,i); + updater(f); + } + } else { // report it now or never + if(cell < n){ + Facet f(cell,i); + updater(f); + }else { + Facet f(n,n->index(cell)); + updater(f); + } + } + } + } + } + }); + } + // Sequential + else +#endif // CGAL_LINKED_WITH_TBB + { + std::vector::iterator it; + for(it = outdated_cells_vector.begin(); + it != outdated_cells_vector.end(); + ++it) + { + Cell_handle cell = *it; + + int i=0; + bool inf = false; + for ( ; i<4 && (!inf) ; ++i ){ + if ( tr_.is_infinite(cell->vertex(i)) ){ + inf = true; + Cell_handle n = cell->neighbor(i); + if(n->next_intrusive() != Cell_handle()){// the neighbor is also outdated + if(cell < n){ // otherwise n will report it later + updater(Facet(cell,i)); + } + } else { // report it now or never + if(cell < n){ + updater(Facet(cell,i)); + }else { + updater(Facet(n,n->index(cell))); + } + } + } + } + if(! inf){ + for ( i=0 ; i<4 ; ++i ){ + Cell_handle n = cell->neighbor(i); + if(n->next_intrusive() != Cell_handle()){// the neighbor is also outdated + if(cell < n){ // otherwise n will report it later + updater(Facet(cell,i)); + } + } else { // report it now or never + if(cell < n){ + updater(Facet(cell,i)); + }else { + updater(Facet(n,n->index(cell))); + } + } + } + } + } + } + } #endif //CGAL_INTRUSIVE_LIST @@ -1740,13 +1865,13 @@ update_mesh(const Point_3& new_position, // << " " << (void*)(&*old_vertex) << "=" << old_vertex->point() // << ")\n"; - Cell_vector incident_cells; - incident_cells.reserve(64); - tr_.incident_cells(old_vertex, std::back_inserter(incident_cells)); - if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells) ) + Cell_vector incident_cells_; + incident_cells_.reserve(64); + tr_.incident_cells(old_vertex, std::back_inserter(incident_cells_)); + if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells_) ) { - BOOST_FOREACH(Cell_handle& ch, std::make_pair(incident_cells.begin(), - incident_cells.end())) + BOOST_FOREACH(Cell_handle& ch, std::make_pair(incident_cells_.begin(), + incident_cells_.end())) { ch->invalidate_circumcenter(); } @@ -1754,7 +1879,7 @@ update_mesh(const Point_3& new_position, old_vertex, criterion, modified_vertices, - incident_cells); + incident_cells_); } else { @@ -1947,16 +2072,53 @@ rebuild_restricted_delaunay(OutdatedCells& outdated_cells, // Updates cells // Note: ~58% of rebuild_restricted_delaunay time + + std::set vertex_to_proj; + #ifdef CGAL_LINKED_WITH_TBB // Parallel if (boost::is_base_of::value) { - tbb::parallel_do(first_cell, last_cell, + std::vector outdated_cells_vector; + outdated_cells_vector.reserve(outdated_cells.size()); + for ( ; first_cell != last_cell ; ++first_cell) + { + outdated_cells_vector.push_back(*first_cell); + } + + tbb::parallel_for(tbb::blocked_range(0, outdated_cells_vector.size()), + [&]( const tbb::blocked_range& r ) // CJTODO: lambdas ok? + { + for( size_t i = r.begin() ; i != r.end() ; ++i) + { + c3t3_.remove_from_complex(outdated_cells_vector[i]); + updater(outdated_cells_vector[i]); + } + }); + /*tbb::parallel_do(first_cell, last_cell, [&]( OutdatedCells::const_reference cell ) // CJTODO: lambdas ok? { c3t3_.remove_from_complex(cell); updater(cell); - }); + });*/ + + +#ifdef MESH_3_PROFILING + std::cerr << " done in " << t.elapsed() << " seconds (#cells from " + << num_cells << " to " << c3t3_.number_of_cells_in_complex() << ")." + << std::endl; + std::cerr << " Updating facets..."; + t.reset(); +#endif + + // Get facets (returns each canonical facet only once) + // Note: ~42% of rebuild_restricted_delaunay time + // Facet_vector facets; + Facet_updater facet_updater(c3t3_,vertex_to_proj, updater); + update_facets(outdated_cells_vector, facet_updater); + + // now we can clear + outdated_cells.clear(); } // Sequential else @@ -1968,25 +2130,25 @@ rebuild_restricted_delaunay(OutdatedCells& outdated_cells, c3t3_.remove_from_complex(cell); updater(cell); } - } - + #ifdef MESH_3_PROFILING - std::cerr << " done in " << t.elapsed() << " seconds (#cells from " - << num_cells << " to " << c3t3_.number_of_cells_in_complex() << ")." - << std::endl; - std::cerr << " Updating facets..."; - t.reset(); + std::cerr << " done in " << t.elapsed() << " seconds (#cells from " + << num_cells << " to " << c3t3_.number_of_cells_in_complex() << ")." + << std::endl; + std::cerr << " Updating facets..."; + t.reset(); #endif - // Get facets (returns each canonical facet only once) - // Note: ~42% of rebuild_restricted_delaunay time - // Facet_vector facets; - std::set vertex_to_proj; - Facet_updater facet_updater(c3t3_,vertex_to_proj, updater); - update_facets(outdated_cells, facet_updater); + // Get facets (returns each canonical facet only once) + // Note: ~42% of rebuild_restricted_delaunay time + // Facet_vector facets; + Facet_updater facet_updater(c3t3_,vertex_to_proj, updater); + update_facets(outdated_cells, facet_updater); + + // now we can clear + outdated_cells.clear(); + } - // now we can clear - outdated_cells.clear(); #ifdef MESH_3_PROFILING std::cerr << " done in " << t.elapsed() << " seconds (" @@ -2163,17 +2325,17 @@ move_point(const Vertex_handle& old_vertex, // std::cerr << "C3T3_helpers::move_point[v2](" // << (void*)(&*old_vertex) << " = " << old_vertex->point() // << " , " << new_position << ")\n"; - Cell_vector incident_cells; - incident_cells.reserve(64); - tr_.incident_cells(old_vertex, std::back_inserter(incident_cells)); - if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells) ) + Cell_vector incident_cells_; + incident_cells_.reserve(64); + tr_.incident_cells(old_vertex, std::back_inserter(incident_cells_)); + if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells_) ) { - BOOST_FOREACH(Cell_handle& ch, std::make_pair(incident_cells.begin(), - incident_cells.end())) + BOOST_FOREACH(Cell_handle& ch, std::make_pair(incident_cells_.begin(), + incident_cells_.end())) { ch->invalidate_circumcenter(); } - std::copy(incident_cells.begin(),incident_cells.end(), outdated_cells); + std::copy(incident_cells_.begin(),incident_cells_.end(), outdated_cells); return move_point_no_topo_change(old_vertex, new_position); } @@ -2195,17 +2357,17 @@ move_point(const Vertex_handle& old_vertex, Outdated_cell_set& outdated_cells_set, Moving_vertices_set& moving_vertices) { - Cell_vector incident_cells; - incident_cells.reserve(64); - tr_.incident_cells(old_vertex, std::back_inserter(incident_cells)); - if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells) ) + Cell_vector incident_cells_; + incident_cells_.reserve(64); + tr_.incident_cells(old_vertex, std::back_inserter(incident_cells_)); + if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells_) ) { - BOOST_FOREACH(Cell_handle& ch, std::make_pair(incident_cells.begin(), - incident_cells.end())) + BOOST_FOREACH(Cell_handle& ch, std::make_pair(incident_cells_.begin(), + incident_cells_.end())) { ch->invalidate_circumcenter(); } - std::copy(incident_cells.begin(),incident_cells.end(), + std::copy(incident_cells_.begin(),incident_cells_.end(), std::inserter(outdated_cells_set, outdated_cells_set.end())); return move_point_no_topo_change(old_vertex, new_position); } @@ -2236,8 +2398,8 @@ move_point(const Vertex_handle& old_vertex, CGAL_assertion(p_could_lock_zone != 0); *p_could_lock_zone = true; - Cell_vector incident_cells; - incident_cells.reserve(64); + Cell_vector incident_cells_; + incident_cells_.reserve(64); if (!try_lock_vertex(old_vertex)) // LOCK { *p_could_lock_zone = false; @@ -2246,54 +2408,11 @@ move_point(const Vertex_handle& old_vertex, } //======= Get incident cells ========== - //tr_.incident_cells(old_vertex, std::back_inserter(incident_cells)); - Cell_handle d = old_vertex->cell(); - if (!try_lock_element(d)) // LOCK + if (try_lock_and_get_incident_cells(old_vertex, incident_cells_) == false) { - BOOST_FOREACH(Cell_handle& ch, - std::make_pair(incident_cells.begin(), incident_cells.end())) - { - ch->tds_data().clear(); - } *p_could_lock_zone = false; - unlock_all_elements(); return Vertex_handle(); } - incident_cells.push_back(d); - d->tds_data().mark_in_conflict(); - int head=0; - int tail=1; - do { - Cell_handle c = incident_cells[head]; - - for (int i=0; i<4; ++i) { - if (c->vertex(i) == old_vertex) - continue; - Cell_handle next = c->neighbor(i); - if (!try_lock_element(next)) // LOCK - { - BOOST_FOREACH(Cell_handle& ch, - std::make_pair(incident_cells.begin(), incident_cells.end())) - { - ch->tds_data().clear(); - } - *p_could_lock_zone = false; - unlock_all_elements(); - return Vertex_handle(); - } - if (! next->tds_data().is_clear()) - continue; - incident_cells.push_back(next); - ++tail; - next->tds_data().mark_in_conflict(); - } - ++head; - } while(head != tail); - BOOST_FOREACH(Cell_handle& ch, - std::make_pair(incident_cells.begin(), incident_cells.end())) - { - ch->tds_data().clear(); - } //======= /Get incident cells ========== if (!try_lock_point(new_position)) // LOCK @@ -2302,16 +2421,16 @@ move_point(const Vertex_handle& old_vertex, unlock_all_elements(); return Vertex_handle(); } - if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells) ) + if ( Th().no_topological_change(tr_, old_vertex, new_position, incident_cells_) ) { - BOOST_FOREACH(Cell_handle& ch, std::make_pair(incident_cells.begin(), - incident_cells.end())) + BOOST_FOREACH(Cell_handle& ch, std::make_pair(incident_cells_.begin(), + incident_cells_.end())) { ch->invalidate_circumcenter(); } tbb::mutex::scoped_lock lock(mut_outdated_cells); // CJTODO LOCK - std::copy(incident_cells.begin(),incident_cells.end(), + std::copy(incident_cells_.begin(),incident_cells_.end(), std::inserter(outdated_cells_set, outdated_cells_set.end())); lock.release(); // CJTODO LOCK @@ -2759,10 +2878,10 @@ C3T3_helpers:: min_incident_value(const Vertex_handle& vh, const SliverCriterion& criterion) const { - Cell_vector incident_cells; - tr_.finite_incident_cells(vh,std::back_inserter(incident_cells)); + Cell_vector incident_cells_; + tr_.finite_incident_cells(vh,std::back_inserter(incident_cells_)); - return min_sliver_in_c3t3_value(incident_cells, criterion); + return min_sliver_in_c3t3_value(incident_cells_, criterion); } template @@ -2804,6 +2923,86 @@ struct Counter { }; +template +void +C3T3_helpers:: +get_incident_cells_without_using_tds_data(const Vertex_handle& v, + Cell_vector &cells) const +{ + std::set found_cells; + Cell_handle d = v->cell(); + + cells.push_back(d); + found_cells.insert(d); + int head=0; + int tail=1; + do { + Cell_handle c = cells[head]; + + for (int i=0; i<4; ++i) { + if (c->vertex(i) == v) + continue; + Cell_handle next = c->neighbor(i); + if (! found_cells.insert(next).second ) + continue; + cells.push_back(next); + ++tail; + } + ++head; + } while(head != tail); +} + + +template +bool +C3T3_helpers:: +try_lock_and_get_incident_cells(const Vertex_handle& v, + Cell_vector &cells) const +{ + Cell_handle d = v->cell(); + if (!try_lock_element(d)) // LOCK + { + unlock_all_elements(); + return false; + } + cells.push_back(d); + d->tds_data().mark_in_conflict(); + int head=0; + int tail=1; + do { + Cell_handle c = cells[head]; + + for (int i=0; i<4; ++i) { + if (c->vertex(i) == v) + continue; + Cell_handle next = c->neighbor(i); + if (!try_lock_element(next)) // LOCK + { + BOOST_FOREACH(Cell_handle& ch, + std::make_pair(cells.begin(), cells.end())) + { + ch->tds_data().clear(); + } + cells.clear(); + unlock_all_elements(); + return false; + } + if (! next->tds_data().is_clear()) + continue; + cells.push_back(next); + ++tail; + next->tds_data().mark_in_conflict(); + } + ++head; + } while(head != tail); + BOOST_FOREACH(Cell_handle& ch, std::make_pair(cells.begin(), cells.end())) + { + ch->tds_data().clear(); + } + return true; +} + + template template OutputIterator @@ -2815,11 +3014,11 @@ incident_slivers(const Vertex_handle& v, { typedef SliverCriterion Sc; - std::vector incident_cells; - tr_.incident_cells(v, std::back_inserter(incident_cells)); + std::vector incident_cells_; + tr_.incident_cells(v, std::back_inserter(incident_cells_)); - std::remove_copy_if(incident_cells.begin(), - incident_cells.end(), + std::remove_copy_if(incident_cells_.begin(), + incident_cells_.end(), out, std::not1(Is_sliver(c3t3_,criterion,sliver_bound))); @@ -2989,9 +3188,9 @@ get_conflict_zone_topo_change(const Vertex_handle& vertex, OutputIterator conflict_cells) const { // Get triangulation_vertex incident cells - Cell_vector incident_cells; - incident_cells.reserve(64); - tr_.incident_cells(vertex, std::back_inserter(incident_cells)); + Cell_vector incident_cells_; + incident_cells_.reserve(64); + tr_.incident_cells(vertex, std::back_inserter(incident_cells_)); // Get conflict_point conflict zone Cell_vector deleted_cells; @@ -3020,10 +3219,10 @@ get_conflict_zone_topo_change(const Vertex_handle& vertex, // Compute union of conflict_point conflict zone and triangulation_vertex // incident cells std::sort(deleted_cells.begin(),deleted_cells.end()); - std::sort(incident_cells.begin(),incident_cells.end()); + std::sort(incident_cells_.begin(),incident_cells_.end()); std::set_union(deleted_cells.begin(), deleted_cells.end(), - incident_cells.begin(), incident_cells.end(), + incident_cells_.begin(), incident_cells_.end(), conflict_cells); return conflict_cells; diff --git a/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h b/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h index c85ee86ccd0..acc8d3fee68 100644 --- a/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h +++ b/Mesh_3/include/CGAL/Mesh_3/Mesh_global_optimizer.h @@ -665,8 +665,18 @@ compute_move(const Vertex_handle& v) Gt().construct_translated_point_3_object(); Cell_vector incident_cells; - incident_cells.reserve(64); - tr_.incident_cells(v, std::back_inserter(incident_cells)); + incident_cells.reserve(64); +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_base_of::value) + { + helper_.get_incident_cells_without_using_tds_data(v, incident_cells); + } + else +#endif //CGAL_LINKED_WITH_TBB + { + tr_.incident_cells(v, std::back_inserter(incident_cells)); + } // Get move from move function Vector_3 move = move_function_(v, incident_cells, c3t3_, sizing_field_); @@ -839,14 +849,43 @@ Mesh_global_optimizer:: fill_sizing_field() { std::map value_map; - - // Fill map with local size - for(typename Tr::Finite_vertices_iterator vit = tr_.finite_vertices_begin(); - vit != tr_.finite_vertices_end(); - ++vit) + +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_base_of::value) { - value_map.insert(std::make_pair(vit->point(), - average_circumradius_length(vit))); + typedef tbb::enumerable_thread_specific< + std::vector< std::pair > > Local_list; + Local_list local_lists; + + tbb::parallel_do(tr_.finite_vertices_begin(), tr_.finite_vertices_end(), + [&]( Vertex& v ) // CJTODO: lambdas ok? + { + // CJTODO: should use Compact_container::s_iterator_to, + // but we don't know the exact Compact_container type here + Vertex_handle vh(&v); + local_lists.local().push_back( + std::make_pair(v.point(), average_circumradius_length(vh))); + }); + + for(typename Local_list::iterator it_list = local_lists.begin() ; + it_list != local_lists.end() ; + ++it_list ) + { + value_map.insert(it_list->begin(), it_list->end()); + } + } + else +#endif //CGAL_LINKED_WITH_TBB + { + // Fill map with local size + for(typename Tr::Finite_vertices_iterator vit = tr_.finite_vertices_begin(); + vit != tr_.finite_vertices_end(); + ++vit) + { + value_map.insert(std::make_pair(vit->point(), + average_circumradius_length(vit))); + } } // fill sizing field @@ -885,7 +924,17 @@ average_circumradius_length(const Vertex_handle& v) const { Cell_vector incident_cells; incident_cells.reserve(64); - tr_.incident_cells(v, std::back_inserter(incident_cells)); +#ifdef CGAL_LINKED_WITH_TBB + // Parallel + if (boost::is_base_of::value) + { + helper_.get_incident_cells_without_using_tds_data(v, incident_cells); + } + else +#endif //CGAL_LINKED_WITH_TBB + { + tr_.incident_cells(v, std::back_inserter(incident_cells)); + } FT sum_len (0); unsigned int nb = 0; diff --git a/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h b/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h index 146e78d21f4..6b68dfd153c 100644 --- a/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_ds_cell_base_3.h @@ -27,50 +27,10 @@ #include #include -#ifdef CGAL_LINKED_WITH_TBB -# include -#endif - namespace CGAL { - -/************************************************ -// Class Triangulation_ds_cell_base_3_base -// Two versions: sequential / parallel -************************************************/ - -// Sequential -template -class Triangulation_ds_cell_base_3_base -{ -public: - // TDS internal data access functions. - TDS_data& tds_data() { return _tds_data; } - const TDS_data& tds_data() const { return _tds_data; } - -protected: - TDS_data _tds_data; -}; - -#ifdef CGAL_LINKED_WITH_TBB -// Parallel -template -class Triangulation_ds_cell_base_3_base -{ -public: - // TDS internal data access functions. - TDS_data& tds_data() { return _tds_data.local(); } - const TDS_data& tds_data() const { return _tds_data.local(); } - -protected: - tbb::enumerable_thread_specific _tds_data; -}; -#endif // CGAL_LINKED_WITH_TBB - template < typename TDS = void > class Triangulation_ds_cell_base_3 - : public Triangulation_ds_cell_base_3_base { public: typedef TDS Triangulation_data_structure; @@ -238,10 +198,15 @@ public: void * for_compact_container() const { return N[0].for_compact_container(); } void * & for_compact_container() { return N[0].for_compact_container(); } + // TDS internal data access functions. + TDS_data& tds_data() { return _tds_data; } + const TDS_data& tds_data() const { return _tds_data; } + private: Cell_handle N[4]; Vertex_handle V[4]; + TDS_data _tds_data; }; template < class TDS > @@ -276,4 +241,4 @@ public: } //namespace CGAL -#endif // CGAL_TRIANGULATION_DS_CELL_BASE_3_H +#endif // CGAL_TRIANGULATION_DS_CELL_BASE_3_H \ No newline at end of file