The global optimizers are now parallel (needs some intense testing now)

This commit is contained in:
Clement Jamin 2012-11-21 16:16:47 +01:00
parent f02e3c8872
commit ab4d97c1e5
9 changed files with 1030 additions and 190 deletions

View File

@ -33,6 +33,10 @@
#include <CGAL/tuple.h>
#include <CGAL/iterator.h>
#ifdef MESH_3_PROFILING
#include <CGAL/Mesh_3/Profiling_tools.h>
#endif
#include <boost/foreach.hpp>
#include <boost/optional.hpp>
#include <boost/iterator/transform_iterator.hpp>
@ -41,13 +45,18 @@
#include <boost/lambda/bind.hpp>
#include <boost/type_traits/is_same.hpp>
#ifdef CGAL_LINKED_WITH_TBB
# include <tbb/parallel_do.h>
#endif
#include <functional>
#include <vector>
#include <set>
namespace CGAL {
namespace Mesh_3 {
static tbb::mutex mut_outdated_cells, mut_moving_vertices, mut_vertex_to_proj; // CJTODO LOCK
#ifdef CGAL_INTRUSIVE_LIST
template <typename Type>
@ -356,12 +365,169 @@ private:
};
#endif // #ifdef CGAL_INTRUSIVE_LIST
template <typename C3T3, typename MeshDomain>
/************************************************
// Class C3T3_helpers_base
// Two versions: sequential / parallel
************************************************/
// Sequential
template <typename Tr, typename Concurrency_tag>
class C3T3_helpers_base
{
protected:
typedef typename Tr::Geom_traits Gt;
typedef typename Gt::Point_3 Point_3;
typedef typename Tr::Vertex_handle Vertex_handle;
typedef typename Tr::Cell_handle Cell_handle;
typedef typename Tr::Facet Facet;
C3T3_helpers_base(LockDataStructureType *) {}
LockDataStructureType *get_lock_data_structure() const
{
return 0;
}
bool try_lock_point(const Point_3 &p, int lock_radius = 0) const
{
return true;
}
bool try_lock_vertex(Vertex_handle vh, int lock_radius = 0) const
{
return true;
}
bool try_lock_element(Cell_handle cell_handle, int lock_radius = 0) const
{
return true;
}
bool try_lock_element(const Facet &facet, int lock_radius = 0) const
{
return true;
}
void unlock_all_elements() {}
};
#ifdef CGAL_LINKED_WITH_TBB
// Parallel
template <typename Tr>
class C3T3_helpers_base<Tr, Parallel_tag>
{
protected:
typedef typename Tr::Geom_traits Gt;
typedef typename Gt::Point_3 Point_3;
typedef typename Tr::Vertex_handle Vertex_handle;
typedef typename Tr::Cell_handle Cell_handle;
typedef typename Tr::Facet Facet;
C3T3_helpers_base(LockDataStructureType *p_lock_ds)
: m_lock_ds(p_lock_ds) {}
// LOCKS (CONCURRENCY)
/*Mesh_3::LockDataStructureType *get_lock_data_structure() const
{
return m_lock_ds;
}*/
bool try_lock_point(const Point_3 &p, int lock_radius = 0) const
{
if (m_lock_ds)
{
return m_lock_ds->try_lock(p, lock_radius).first;
}
return true;
}
bool try_lock_vertex(Vertex_handle vh, int lock_radius = 0) const
{
if (m_lock_ds)
{
return m_lock_ds->try_lock(vh->point(), lock_radius).first;
}
return true;
}
bool try_lock_element(Cell_handle cell_handle, int lock_radius = 0) const
{
bool success = true;
// Lock the element area on the grid
for (int iVertex = 0 ; success && iVertex < 4 ; ++iVertex)
{
Vertex_handle vh = cell_handle->vertex(iVertex);
success = try_lock_vertex(vh, lock_radius);
}
return success;
}
bool try_lock_element(const Facet &facet, int lock_radius = 0) const
{
bool success = true;
// Lock the element area on the grid
Cell_handle cell = facet.first;
for (int iVertex = (facet.second+1)&3 ;
success && iVertex != facet.second ; iVertex = (iVertex+1)&3)
{
Vertex_handle vh = cell->vertex(iVertex);
success = try_lock_vertex(vh, lock_radius);
}
return success;
}
bool is_element_locked_by_this_thread(Cell_handle cell_handle) const
{
bool locked = true;
for (int iVertex = 0 ; locked && iVertex < 4 ; ++iVertex)
{
Vertex_handle vh = cell_handle->vertex(iVertex);
locked = m_lock_ds->is_locked_by_this_thread(vh->point());
}
return locked;
}
void unlock_all_elements()
{
if (m_lock_ds)
{
m_lock_ds->unlock_all_tls_locked_cells();
}
}
protected:
Mesh_3::LockDataStructureType *m_lock_ds;
};
#endif // CGAL_LINKED_WITH_TBB
/************************************************
*
* C3T3_helpers class
*
************************************************/
template <typename C3T3,
typename MeshDomain>
class C3T3_helpers
: public C3T3_helpers_base<typename C3T3::Triangulation,
typename C3T3::Concurrency_tag>
{
// -----------------------------------
// Private types
// -----------------------------------
typedef C3T3_helpers<C3T3, MeshDomain> Self;
typedef C3T3_helpers_base<typename C3T3::Triangulation,
typename C3T3::Concurrency_tag> Base;
typedef typename C3T3::Concurrency_tag Concurrency_tag;
typedef typename C3T3::Triangulation Tr;
typedef Tr Triangulation;
typedef typename Tr::Geom_traits Gt;
@ -417,8 +583,10 @@ public:
/**
* Constructor
*/
C3T3_helpers(C3T3& c3t3, const MeshDomain& domain)
: c3t3_(c3t3)
C3T3_helpers(C3T3& c3t3, const MeshDomain& domain,
LockDataStructureType *p_lock_ds = 0)
: Base(p_lock_ds)
, c3t3_(c3t3)
, tr_(c3t3.triangulation())
, domain_(domain) { }
@ -519,11 +687,17 @@ public:
* Moves \c old_vertex to \c new_position
* Stores the cells which have to be updated in \c outdated_cells
* Updates the Vertex_handle old_vertex to its new value in \c moving_vertices
* The second one (with the p_could_lock_zone param) is for the parallel version
*/
Vertex_handle move_point(const Vertex_handle& old_vertex,
const Point_3& new_position,
Outdated_cell_set& outdated_cells_set,
Moving_vertices_set& moving_vertices);
Vertex_handle move_point(const Vertex_handle& old_vertex,
const Point_3& new_position,
Outdated_cell_set& outdated_cells_set,
Moving_vertices_set& moving_vertices,
bool *p_could_lock_zone);
/**
* Outputs to out the sliver (wrt \c criterion and \c sliver_bound) incident
@ -896,7 +1070,8 @@ private:
{
const Vertex_handle& v = f.first->vertex((k+i)&3);
if ( c3t3_.in_dimension(v) > 2 )
{
{
tbb::mutex::scoped_lock lock(mut_vertex_to_proj);
vertex_to_proj.insert(v);
}
}
@ -1018,7 +1193,8 @@ private:
Vertex_handle
move_point_topo_change(const Vertex_handle& old_vertex,
const Point_3& new_position,
Outdated_cell_set& outdated_cells_set);
Outdated_cell_set& outdated_cells_set,
bool *p_could_lock_zone = 0);
template < typename OutdatedCellsOutputIterator,
typename DeletedCellsOutputIterator >
@ -1132,7 +1308,8 @@ private:
const Point_3& conflict_point,
CellsOutputIterator insertion_conflict_cells,
FacetsOutputIterator insertion_conflict_boundary,
CellsOutputIterator removal_conflict_cells) const;
CellsOutputIterator removal_conflict_cells,
bool *p_could_lock_zone = 0) const;
template < typename ConflictCellsInputIterator,
@ -1280,44 +1457,99 @@ private:
template <typename FacetUpdater>
void update_facets(Intrusive_list<Cell_handle>& outdated_cells, FacetUpdater updater)
{
typename Intrusive_list<Cell_handle>::iterator it;
for(it = outdated_cells.begin();
it != outdated_cells.end();
++it)
#ifdef CGAL_LINKED_WITH_TBB
// Parallel
if (boost::is_base_of<Parallel_tag, Concurrency_tag>::value)
{
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)));
tbb::parallel_do(outdated_cells.begin(), outdated_cells.end(),
[&]( const Cell_handle& cell ) // CJTODO: lambdas ok?
{
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 ( 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));
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);
}
}
} else { // report it now or never
if(cell < n){
updater(Facet(cell,i));
}else {
updater(Facet(n,n->index(cell)));
}
}
});
}
// Sequential
else
#endif // CGAL_LINKED_WITH_TBB
{
typename Intrusive_list<Cell_handle>::iterator it;
for(it = outdated_cells.begin();
it != outdated_cells.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)));
}
}
}
}
@ -1492,7 +1724,7 @@ private:
C3T3& c3t3_;
Tr& tr_;
const MeshDomain& domain_;
};
}; // class C3T3_helpers
template <typename C3T3, typename MD>
@ -1706,16 +1938,48 @@ rebuild_restricted_delaunay(OutdatedCells& outdated_cells,
typename OutdatedCells::iterator first_cell = outdated_cells.begin();
typename OutdatedCells::iterator last_cell = outdated_cells.end();
Update_c3t3 updater(domain_,c3t3_);
#ifdef MESH_3_PROFILING
std::cerr << std::endl << " Updating cells...";
WallClockTimer t;
size_t num_cells = c3t3_.number_of_cells_in_complex();
#endif
// Updates cells
while ( first_cell != last_cell )
// Note: ~58% of rebuild_restricted_delaunay time
#ifdef CGAL_LINKED_WITH_TBB
// Parallel
if (boost::is_base_of<Parallel_tag, Concurrency_tag>::value)
{
const Cell_handle& cell = *first_cell++;
c3t3_.remove_from_complex(cell);
updater(cell);
tbb::parallel_do(first_cell, last_cell,
[&]( OutdatedCells::const_reference cell ) // CJTODO: lambdas ok?
{
c3t3_.remove_from_complex(cell);
updater(cell);
});
}
// Sequential
else
#endif // CGAL_LINKED_WITH_TBB
{
while ( first_cell != last_cell )
{
const Cell_handle& cell = *first_cell++;
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;
std::set<Vertex_handle> vertex_to_proj;
Facet_updater facet_updater(c3t3_,vertex_to_proj, updater);
@ -1723,9 +1987,17 @@ rebuild_restricted_delaunay(OutdatedCells& outdated_cells,
// now we can clear
outdated_cells.clear();
#ifdef MESH_3_PROFILING
std::cerr << " done in " << t.elapsed() << " seconds ("
<< vertex_to_proj.size() << " vertices to project)." << std::endl;
std::cerr << " Projecting interior vertices...";
t.reset();
#endif
CGAL_HISTOGRAM_PROFILER("|vertex_to_proj|=", vertex_to_proj.size());
// Project interior vertices
// Note: ~0% of rebuild_restricted_delaunay time
// TODO : iterate to be sure no interior vertice become on the surface
// because of move ?
for ( typename std::set<Vertex_handle>::iterator it = vertex_to_proj.begin() ;
@ -1746,6 +2018,10 @@ rebuild_restricted_delaunay(OutdatedCells& outdated_cells,
moving_vertices.insert(new_vertex);
}
}
#ifdef MESH_3_PROFILING
std::cerr << " done in " << t.elapsed() << " seconds." << std::endl;
#endif
}
#endif //CGAL_INTRUSIVE_LIST
@ -1763,35 +2039,87 @@ rebuild_restricted_delaunay(ForwardIterator first_cell,
Facet_vector facets = get_facets(first_cell, last_cell);
// Updates cells
while ( first_cell != last_cell )
// Note: ~58% of rebuild_restricted_delaunay time
#ifdef CGAL_LINKED_WITH_TBB
// Parallel
if (boost::is_base_of<Parallel_tag, Concurrency_tag>::value)
{
const Cell_handle& cell = *first_cell++;
c3t3_.remove_from_complex(cell);
updater(cell);
tbb::parallel_do(first_cell, last_cell,
[&]( ForwardIterator::reference cell ) // CJTODO: lambdas ok?
{
c3t3_.remove_from_complex(cell);
updater(cell);
});
}
// Sequential
else
#endif // CGAL_LINKED_WITH_TBB
{
while ( first_cell != last_cell )
{
const Cell_handle& cell = *first_cell++;
c3t3_.remove_from_complex(cell);
updater(cell);
}
}
// Updates facets
std::set<std::pair<Vertex_handle, Surface_patch_index> > vertex_to_proj;
for ( typename Facet_vector::iterator fit = facets.begin() ;
fit != facets.end() ;
++fit )
#ifdef CGAL_LINKED_WITH_TBB
// Parallel
if (boost::is_base_of<Parallel_tag, Concurrency_tag>::value)
{
// Update facet
c3t3_.remove_from_complex(*fit);
updater(*fit);
// Update vertex_to_proj
if ( c3t3_.is_in_complex(*fit) )
tbb::parallel_do(facets.begin(), facets.end(),
[&]( const Facet& facet ) // CJTODO: lambdas ok?
{
// Iterate on vertices
int k = fit->second;
for ( int i=1 ; i<4 ; ++i )
// Update facet
c3t3_.remove_from_complex(facet);
updater(facet);
// Update vertex_to_proj
if ( c3t3_.is_in_complex(facet) )
{
const Vertex_handle& v = fit->first->vertex((k+i)&3);
if ( c3t3_.in_dimension(v) > 2 )
{
vertex_to_proj.insert
(std::make_pair(v, c3t3_.surface_patch_index(*fit)));
// Iterate on vertices
int k = facet.second;
for ( int i=1 ; i<4 ; ++i )
{
const Vertex_handle& v = facet.first->vertex((k+i)&3);
if ( c3t3_.in_dimension(v) > 2 )
{
std::pair<Vertex_handle, Surface_patch_index> p
= std::make_pair(v, c3t3_.surface_patch_index(facet));
tbb::mutex::scoped_lock lock(mut_vertex_to_proj);
vertex_to_proj.insert(p);
}
}
}
});
}
// Sequential
else
#endif // CGAL_LINKED_WITH_TBB
{
for ( typename Facet_vector::iterator fit = facets.begin() ;
fit != facets.end() ;
++fit )
{
// Update facet
c3t3_.remove_from_complex(*fit);
updater(*fit);
// Update vertex_to_proj
if ( c3t3_.is_in_complex(*fit) )
{
// Iterate on vertices
int k = fit->second;
for ( int i=1 ; i<4 ; ++i )
{
const Vertex_handle& v = fit->first->vertex((k+i)&3);
if ( c3t3_.in_dimension(v) > 2 )
{
vertex_to_proj.insert
(std::make_pair(v, c3t3_.surface_patch_index(*fit)));
}
}
}
}
@ -1858,6 +2186,7 @@ move_point(const Vertex_handle& old_vertex,
}
}
// Sequential
template <typename C3T3, typename MD>
typename C3T3_helpers<C3T3,MD>::Vertex_handle
C3T3_helpers<C3T3,MD>::
@ -1891,12 +2220,138 @@ move_point(const Vertex_handle& old_vertex,
}
}
// Parallel
// In case of success (could_lock_zone = true), the zone is locked after the call
// ==> the caller needs to call "unlock_all_elements" by itself
// In case of failure (could_lock_zone = false), the zone is unlocked by this function
template <typename C3T3, typename MD>
typename C3T3_helpers<C3T3,MD>::Vertex_handle
C3T3_helpers<C3T3,MD>::
move_point(const Vertex_handle& old_vertex,
const Point_3& new_position,
Outdated_cell_set& outdated_cells_set,
Moving_vertices_set& moving_vertices,
bool *p_could_lock_zone)
{
CGAL_assertion(p_could_lock_zone != 0);
*p_could_lock_zone = true;
Cell_vector incident_cells;
incident_cells.reserve(64);
if (!try_lock_vertex(old_vertex)) // LOCK
{
*p_could_lock_zone = false;
unlock_all_elements();
return Vertex_handle();
}
//======= 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
{
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
{
*p_could_lock_zone = false;
unlock_all_elements();
return Vertex_handle();
}
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()))
{
ch->invalidate_circumcenter();
}
tbb::mutex::scoped_lock lock(mut_outdated_cells); // CJTODO LOCK
std::copy(incident_cells.begin(),incident_cells.end(),
std::inserter(outdated_cells_set, outdated_cells_set.end()));
lock.release(); // CJTODO LOCK
Vertex_handle new_vertex = move_point_no_topo_change(old_vertex, new_position);
// Don't "unlock_all_elements" here, the caller may need it to do it himself
return new_vertex;
}
else
{
//moving_vertices.erase(old_vertex); MOVED BELOW
Vertex_handle new_vertex =
move_point_topo_change(old_vertex, new_position, outdated_cells_set,
p_could_lock_zone);
if (*p_could_lock_zone == false)
{
unlock_all_elements();
return Vertex_handle();
}
tbb::mutex::scoped_lock lock(mut_moving_vertices); // CJTODO LOCK
moving_vertices.erase(old_vertex);
moving_vertices.insert(new_vertex);
lock.release();
// Don't "unlock_all_elements" here, the caller may need it to do it itself
return new_vertex;
}
}
template <typename C3T3, typename MD>
typename C3T3_helpers<C3T3,MD>::Vertex_handle
C3T3_helpers<C3T3,MD>::
move_point_topo_change(const Vertex_handle& old_vertex,
const Point_3& new_position,
Outdated_cell_set& outdated_cells_set)
Outdated_cell_set& outdated_cells_set,
bool *p_could_lock_zone)
{
Cell_set insertion_conflict_cells;
Cell_set removal_conflict_cells;
@ -1906,14 +2361,20 @@ move_point_topo_change(const Vertex_handle& old_vertex,
get_conflict_zone_topo_change(old_vertex, new_position,
std::inserter(insertion_conflict_cells,insertion_conflict_cells.end()),
std::back_inserter(insertion_conflict_boundary),
std::inserter(removal_conflict_cells, removal_conflict_cells.end()));
std::inserter(removal_conflict_cells, removal_conflict_cells.end()),
p_could_lock_zone);
if (p_could_lock_zone && *p_could_lock_zone == false)
return Vertex_handle();
tbb::mutex::scoped_lock lock(mut_outdated_cells); // CJTODO LOCK
for(typename Cell_set::iterator it = insertion_conflict_cells.begin();
it != insertion_conflict_cells.end(); ++it)
outdated_cells_set.erase(*it);
for(typename Cell_set::iterator it = removal_conflict_cells.begin();
it != removal_conflict_cells.end(); ++it)
outdated_cells_set.erase(*it);
lock.release();
Cell_vector outdated_cells;
Vertex_handle nv = move_point_topo_change_conflict_zone_known(old_vertex, new_position,
@ -1924,10 +2385,12 @@ move_point_topo_change(const Vertex_handle& old_vertex,
removal_conflict_cells.end(),
std::back_inserter(outdated_cells),
CGAL::Emptyset_iterator()); // deleted_cells
lock.acquire(mut_outdated_cells);
for(typename Cell_vector::iterator it = outdated_cells.begin();
it != outdated_cells.end(); ++it)
outdated_cells_set.insert(*it);
lock.release();
return nv;
}
@ -1960,6 +2423,7 @@ move_point_topo_change(const Vertex_handle& old_vertex,
removal_conflict_cells.end(),
outdated_cells,
deleted_cells);
return nv;
}
@ -1996,10 +2460,6 @@ move_point_topo_change_conflict_zone_known(
int dimension = c3t3_.in_dimension(old_vertex);
Index vertex_index = c3t3_.index(old_vertex);
FT meshing_info = old_vertex->meshing_info();
#ifdef CGAL_INTRUSIVE_LIST
Vertex_handle next = old_vertex->next_intrusive();
Vertex_handle prev = old_vertex->previous_intrusive();
#endif
// insert new point
Vertex_handle new_vertex = tr_.insert_in_hole(new_position,
@ -2020,10 +2480,6 @@ move_point_topo_change_conflict_zone_known(
c3t3_.set_dimension(new_vertex,dimension);
c3t3_.set_index(new_vertex,vertex_index);
new_vertex->set_meshing_info(meshing_info);
#ifdef CGAL_INTRUSIVE_LIST
new_vertex->next_intrusive() = next;
new_vertex->previous_intrusive() = prev;
#endif
// End Move point
//// Fill outdated_cells
@ -2119,10 +2575,6 @@ move_point_topo_change(const Vertex_handle& old_vertex,
c3t3_.set_dimension(new_vertex,dimension);
c3t3_.set_index(new_vertex,vertex_index);
new_vertex->set_meshing_info(meshing_info);
#ifdef CGAL_INTRUSIVE_LIST
new_vertex->next_intrusive() = next;
new_vertex->previous_intrusive() = prev;
#endif
return new_vertex;
}
@ -2136,7 +2588,11 @@ move_point_no_topo_change(const Vertex_handle& old_vertex,
const Point_3& new_position,
OutdatedCellsOutputIterator outdated_cells)
{
tbb::mutex::scoped_lock lock(mut_outdated_cells); // CJTODO LOCK
get_conflict_zone_no_topo_change(old_vertex, outdated_cells);
lock.release(); // CJTODO LOCK
return move_point_no_topo_change(old_vertex, new_position);
}
@ -2496,16 +2952,22 @@ get_conflict_zone_topo_change(const Vertex_handle& v,
const Point_3& conflict_point,
CellsOutputIterator insertion_conflict_cells,
FacetsOutputIterator insertion_conflict_boundary,
CellsOutputIterator removal_conflict_cells) const
CellsOutputIterator removal_conflict_cells,
bool *p_could_lock_zone) const
{
// Get triangulation_vertex incident cells : removal conflict zone
// CJTODO: hasn't it already been computed in "move_point"?
tr_.incident_cells(v, removal_conflict_cells);
// Get conflict_point conflict zone
int li=0;
int lj=0;
typename Tr::Locate_type lt;
Cell_handle cell = tr_.locate(conflict_point, lt, li, lj, v->cell());
Cell_handle cell = tr_.locate(
conflict_point, lt, li, lj, v->cell(), p_could_lock_zone);
if (p_could_lock_zone && *p_could_lock_zone == false)
return;
if ( lt == Tr::VERTEX ) // Vertex removal is forbidden
return;
@ -2514,7 +2976,8 @@ get_conflict_zone_topo_change(const Vertex_handle& v,
tr_.find_conflicts(conflict_point,
cell,
insertion_conflict_boundary,
insertion_conflict_cells);
insertion_conflict_cells,
p_could_lock_zone);
}
template <typename C3T3, typename MD>

View File

@ -102,7 +102,8 @@ public:
return CGAL::NULL_VECTOR;
}
#ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE
#if defined(CGAL_MESH_3_OPTIMIZER_VERBOSE) \
|| defined (CGAL_MESH_3_EXPORT_PERFORMANCE_DATA)
static std::string name() { return std::string("Lloyd"); }
#endif

View File

@ -33,25 +33,189 @@
#include <CGAL/Mesh_optimization_return_code.h>
#include <CGAL/Mesh_3/Null_global_optimizer_visitor.h>
#include <CGAL/Prevent_deref.h>
#include <CGAL/tuple.h>
#include <CGAL/Mesh_3/Concurrent_mesher_config.h>
#include <CGAL/Mesh_3/Locking_data_structures.h>
#ifdef MESH_3_PROFILING
#include <CGAL/Mesh_3/Profiling_tools.h>
#endif
#include <vector>
#include <list>
#include <limits>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#ifdef CGAL_LINKED_WITH_TBB
# include <tbb/atomic.h>
# include <tbb/parallel_do.h>
# include <tbb/concurrent_vector.h>
#endif
namespace CGAL {
namespace Mesh_3 {
/************************************************
// Class Mesh_global_optimizer_base
// Two versions: sequential / parallel
************************************************/
// Sequential
template <typename Tr, typename Concurrency_tag>
class Mesh_global_optimizer_base
{
protected:
typedef typename Tr::Geom_traits Gt;
typedef typename Gt::FT FT;
typedef std::vector<cpp11::tuple<
typename Tr::Vertex_handle, typename Tr::Point, FT> > Moves_vector;
typedef unsigned int Nb_frozen_points_type ;
Mesh_global_optimizer_base(const Bbox_3 &, int)
: big_moves_size_(0) {}
void update_big_moves(const FT& new_sq_move)
{
if (big_moves_.size() < big_moves_size_ )
big_moves_.insert(new_sq_move);
else
{
FT smallest = *(big_moves_.begin());
if( new_sq_move > smallest )
{
big_moves_.erase(big_moves_.begin());
big_moves_.insert(new_sq_move);
}
}
}
void clear_big_moves()
{
big_moves_.clear();
}
LockDataStructureType *get_lock_data_structure() { return 0; }
void unlock_all_elements() {}
protected:
std::size_t big_moves_size_;
std::multiset<FT> big_moves_;
};
#ifdef CGAL_LINKED_WITH_TBB
// Parallel
template <typename Tr>
class Mesh_global_optimizer_base<Tr, Parallel_tag>
{
protected:
typedef typename Tr::Geom_traits Gt;
typedef typename Gt::FT FT;
typedef tbb::concurrent_vector<cpp11::tuple<
typename Tr::Vertex_handle, typename Tr::Point, FT> > Moves_vector;
typedef tbb::atomic<unsigned int> Nb_frozen_points_type ;
Mesh_global_optimizer_base(const Bbox_3 &bbox, int num_grid_cells_per_axis)
: big_moves_size_(0)
, m_lock_ds(bbox, num_grid_cells_per_axis)
{
big_moves_current_size_ = 0;
big_moves_smallest_ = std::numeric_limits<FT>::max();
}
void update_big_moves(const FT& new_sq_move)
{
static tbb::mutex mut;
if (++big_moves_current_size_ <= big_moves_size_ )
{
tbb::mutex::scoped_lock lock(mut);
std::multiset<FT>::const_iterator it = big_moves_.insert(new_sq_move);
// New smallest move of all big moves?
if (it == big_moves_.begin())
big_moves_smallest_ = new_sq_move;
}
else
{
--big_moves_current_size_;
if( new_sq_move > big_moves_smallest_ )
{
tbb::mutex::scoped_lock lock(mut);
// Test it again since it may have been modified by another
// thread in the meantime
if( new_sq_move > big_moves_smallest_ )
{
big_moves_.erase(big_moves_.begin());
std::multiset<FT>::const_iterator it = big_moves_.insert(new_sq_move);
// New smallest move of all big moves?
if (it == big_moves_.begin())
big_moves_smallest_ = new_sq_move;
}
}
}
}
void clear_big_moves()
{
big_moves_current_size_ = 0;
big_moves_smallest_ = std::numeric_limits<FT>::max();
big_moves_.clear();
}
LockDataStructureType *get_lock_data_structure()
{
return &m_lock_ds;
}
void unlock_all_elements()
{
m_lock_ds.unlock_all_tls_locked_cells();
}
public:
protected:
tbb::atomic<std::size_t> big_moves_current_size_;
tbb::atomic<FT> big_moves_smallest_;
std::size_t big_moves_size_;
std::multiset<FT> big_moves_;
/// Lock data structure
LockDataStructureType m_lock_ds;
};
#endif // CGAL_LINKED_WITH_TBB
/************************************************
// Class Mesh_global_optimizer
************************************************/
template <typename C3T3,
typename MeshDomain,
typename MoveFunction,
typename Visitor_ = Null_global_optimizer_visitor<C3T3> >
class Mesh_global_optimizer
{
: public Mesh_global_optimizer_base<typename C3T3::Triangulation, typename C3T3::Concurrency_tag>
{
// Types
typedef typename C3T3::Concurrency_tag Concurrency_tag;
typedef Mesh_global_optimizer<C3T3, MeshDomain, MoveFunction, Visitor_> Self;
typedef Mesh_global_optimizer_base<
typename C3T3::Triangulation, typename C3T3::Concurrency_tag> Base;
using Base::get_lock_data_structure;
typedef typename C3T3::Triangulation Tr;
typedef typename Tr::Geom_traits Gt;
@ -67,7 +231,6 @@ class Mesh_global_optimizer
typedef typename std::vector<Cell_handle> Cell_vector;
typedef typename std::vector<Vertex_handle> Vertex_vector;
typedef typename std::set<Vertex_handle> Vertex_set;
typedef std::vector<std::pair<Vertex_handle, Point_3> > Moves_vector;
#ifdef CGAL_INTRUSIVE_LIST
typedef Intrusive_list<Cell_handle> Outdated_cell_set;
@ -135,11 +298,6 @@ private:
*/
Vector_3 compute_move(const Vertex_handle& v);
/**
* update big_moves_ vector with new_sq_move value
*/
void update_big_moves(const FT& new_sq_move);
/**
* Updates mesh using moves of \c moves vector. Updates moving_vertices with
* the new set of moving vertices after the move.
@ -197,11 +355,8 @@ private:
double time_limit_;
CGAL::Timer running_time_;
std::size_t big_moves_size_;
std::set<FT> big_moves_;
bool do_freeze_;
mutable unsigned int nb_frozen_points_;
mutable Nb_frozen_points_type nb_frozen_points_;
#ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE
mutable FT sum_moves_;
@ -217,27 +372,30 @@ Mesh_global_optimizer(C3T3& c3t3,
const bool do_freeze,
const FT& convergence_ratio,
const Mf move_function)
: c3t3_(c3t3)
: Base(c3t3.bbox(),
Concurrent_mesher_config::get().locking_grid_num_cells_per_axis)
, c3t3_(c3t3)
, tr_(c3t3_.triangulation())
, domain_(domain)
, sq_freeze_ratio_(freeze_ratio*freeze_ratio)
, convergence_ratio_(convergence_ratio)
, helper_(c3t3_,domain_)
, helper_(c3t3_,domain_, get_lock_data_structure())
, move_function_(move_function)
, sizing_field_(c3t3.triangulation())
, time_limit_(-1)
, running_time_()
, big_moves_size_(0)
, big_moves_()
, do_freeze_(do_freeze)
, nb_frozen_points_(0)
#ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE
, sum_moves_(0)
#endif // CGAL_MESH_3_OPTIMIZER_VERBOSE
{
nb_frozen_points_ = 0; // We put it here in case it's an "atomic"
// If we're multi-thread
tr_.set_lock_data_structure(get_lock_data_structure());
#ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE
std::cerr << "Fill sizing field...";
CGAL::Timer timer;
@ -280,7 +438,7 @@ operator()(int nb_iterations, Visitor visitor)
#endif //CGAL_MESH_3_OPTIMIZER_VERBOSE
// Initialize big moves (stores the largest moves)
big_moves_.clear();
clear_big_moves();
big_moves_size_ =
(std::max)(std::size_t(1), std::size_t(moving_vertices.size()/500));
@ -321,7 +479,7 @@ operator()(int nb_iterations, Visitor visitor)
visitor.end_of_iteration(i);
#ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE
unsigned int moving_vertices_size = moving_vertices.size();
size_t moving_vertices_size = moving_vertices.size();
std::cerr << boost::format("\r \r"
"end iter.%1%, %2% / %3%, last step:%4$.2fs, step avg:%5$.2fs, avg big moves:%6$.3f ")
% (i+1)
@ -358,6 +516,10 @@ operator()(int nb_iterations, Visitor visitor)
<< "s" << std::endl << std::endl;
#endif
#ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA
CGAL_MESH_3_SET_PERFORMANCE_DATA(std::string(Mf::name()) + "_optim_time", running_time_.time());
#endif
if ( do_freeze_ && nb_frozen_points_ == initial_vertices_nb )
return ALL_VERTICES_FROZEN;
@ -396,37 +558,98 @@ compute_moves(Moving_vertices_set& moving_vertices)
moves.reserve(moving_vertices.size());
// reset worst_move list
big_moves_.clear();
clear_big_moves();
// Get move for each moving vertex
typename Moving_vertices_set::iterator vit = moving_vertices.begin();
for ( ; vit != moving_vertices.end() ; )
{
Vertex_handle oldv = *vit;
Vector_3 move = compute_move(oldv);
++vit;
if ( CGAL::NULL_VECTOR != move )
{
Point_3 new_position = translate(oldv->point(),move);
moves.push_back(std::make_pair(oldv,new_position));
}
else // CGAL::NULL_VECTOR == move
{
if(do_freeze_)
moving_vertices.erase(oldv);
}
#ifdef MESH_3_PROFILING
std::cerr << "Computing moves...";
WallClockTimer t;
#endif
// Stop if time_limit_ is reached
if ( is_time_limit_reached() )
break;
}
#ifdef CGAL_LINKED_WITH_TBB
// Parallel
if (boost::is_base_of<Parallel_tag, Concurrency_tag>::value)
{
tbb::concurrent_vector<Vertex_handle> vertices_not_moving_any_more;
// Get move for each moving vertex
tbb::parallel_do(moving_vertices.begin(), moving_vertices.end(),
[&]( const Vertex_handle& oldv ) // CJTODO: lambdas ok?
{
Vector_3 move = compute_move(oldv);
if ( CGAL::NULL_VECTOR != move )
{
Point_3 new_position = translate(oldv->point(),move);
FT size = (Mesh_global_optimizer<C3T3,Md,Mf,V_>::Sizing_field::is_vertex_update_needed ?
sizing_field_(new_position, oldv) : 0);
moves.push_back(std::make_tuple(oldv,new_position,size));
}
else // CGAL::NULL_VECTOR == move
{
if(this->do_freeze_)
{
vertices_not_moving_any_more.push_back(oldv);
}
}
// CJTODO TEMP : à remettre (comment ?)
// Stop if time_limit_ is reached
//if ( is_time_limit_reached() )
// break;
});
tbb::concurrent_vector<Vertex_handle>::const_iterator it
= vertices_not_moving_any_more.begin();
tbb::concurrent_vector<Vertex_handle>::const_iterator it_end
= vertices_not_moving_any_more.end();
for ( ; it != it_end ; ++it)
{
moving_vertices.erase(*it);
}
}
// Sequential
else
#endif // CGAL_LINKED_WITH_TBB
{
// Get move for each moving vertex
typename Moving_vertices_set::iterator vit = moving_vertices.begin();
for ( ; vit != moving_vertices.end() ; )
{
Vertex_handle oldv = *vit;
++vit;
Vector_3 move = compute_move(oldv);
if ( CGAL::NULL_VECTOR != move )
{
Point_3 new_position = translate(oldv->point(),move);
FT size = (Sizing_field::is_vertex_update_needed ?
sizing_field_(new_position, oldv) : 0);
moves.push_back(std::make_tuple(oldv,new_position,size));
}
else // CGAL::NULL_VECTOR == move
{
if(do_freeze_)
moving_vertices.erase(oldv); // CJTODO: si non-intrusive,
//on peut optimiser en passant l'itérateur,
// et il faut faire "vit = mv.erase(vit)" au lieu de ++vit
}
// Stop if time_limit_ is reached
if ( is_time_limit_reached() )
break;
}
}
#ifdef MESH_3_PROFILING
std::cerr << "done in " << t.elapsed() << " seconds." << std::endl;
#endif
return moves;
}
template <typename C3T3, typename Md, typename Mf, typename V_>
typename Mesh_global_optimizer<C3T3,Md,Mf,V_>::Vector_3
Mesh_global_optimizer<C3T3,Md,Mf,V_>::
@ -467,33 +690,14 @@ compute_move(const Vertex_handle& v)
nb_frozen_points_++;
return CGAL::NULL_VECTOR;
}
// Update big moves
update_big_moves(local_move_sq_ratio);
return move;
}
template <typename C3T3, typename Md, typename Mf, typename V_>
void
Mesh_global_optimizer<C3T3,Md,Mf,V_>::
update_big_moves(const FT& new_sq_move)
{
if (big_moves_.size() < big_moves_size_ )
big_moves_.insert(new_sq_move);
else
{
FT smallest = *(big_moves_.begin());
if( new_sq_move > smallest )
{
big_moves_.erase(big_moves_.begin());
big_moves_.insert(new_sq_move);
}
}
}
template <typename C3T3, typename Md, typename Mf, typename V_>
void
Mesh_global_optimizer<C3T3,Md,Mf,V_>::
@ -504,36 +708,109 @@ update_mesh(const Moves_vector& moves,
// Cells which have to be updated
Outdated_cell_set outdated_cells;
// Apply moves in triangulation
for ( typename Moves_vector::const_iterator it = moves.begin() ;
it != moves.end() ;
++it )
#ifdef MESH_3_PROFILING
std::cerr << "Moving vertices...";
WallClockTimer t;
#endif
#ifdef CGAL_LINKED_WITH_TBB
// Parallel
if (boost::is_base_of<Parallel_tag, Concurrency_tag>::value)
{
const Vertex_handle& v = it->first;
const Point_3& new_position = it->second;
// Get size at new position
if ( Sizing_field::is_vertex_update_needed )
// Apply moves in triangulation
tbb::parallel_for(tbb::blocked_range<size_t>(0, moves.size()),
[&]( const tbb::blocked_range<size_t>& r ) // CJTODO: lambdas ok?
{
FT size = sizing_field_(new_position,v);
// Move point
Vertex_handle new_v = helper_.move_point(v, new_position, outdated_cells, moving_vertices);
for( size_t i = r.begin() ; i != r.end() ; ++i)
{
const Vertex_handle& v = cpp11::get<0>(moves[i]);
const Point_3& new_position = cpp11::get<1>(moves[i]);
// Get size at new position
if ( Self::Sizing_field::is_vertex_update_needed )
{
//FT size = sizing_field_(new_position,v);
FT size = cpp11::get<2>(moves[i]);
// Restore size in meshing_info data
new_v->set_meshing_info(size);
}
else // Move point
{
helper_.move_point(v, new_position, outdated_cells, moving_vertices);
}
// Move point
bool could_lock_zone;
Vertex_handle new_v = helper_.move_point(
v, new_position, outdated_cells, moving_vertices, &could_lock_zone);
while (could_lock_zone == false)
{
new_v = helper_.move_point(
v, new_position, outdated_cells, moving_vertices, &could_lock_zone);
}
// Restore size in meshing_info data
new_v->set_meshing_info(size);
}
else // Move point
{
bool could_lock_zone;
do {
helper_.move_point(
v, new_position, outdated_cells, moving_vertices, &could_lock_zone);
} while (!could_lock_zone);
}
unlock_all_elements();
// Stop if time_limit_ is reached, here we can't return without rebuilding
// restricted delaunay
if ( is_time_limit_reached() )
break;
// CJTODO : à remettre (comment ?)
// Stop if time_limit_ is reached, here we can't return without rebuilding
// restricted delaunay
/*if ( is_time_limit_reached() )
break;*/
}
});
}
// Sequential
else
#endif // CGAL_LINKED_WITH_TBB
{
// Apply moves in triangulation
for ( typename Moves_vector::const_iterator it = moves.begin() ;
it != moves.end() ;
++it )
{
const Vertex_handle& v = cpp11::get<0>(*it);
const Point_3& new_position = cpp11::get<1>(*it);
// Get size at new position
if ( Sizing_field::is_vertex_update_needed )
{
//FT size = sizing_field_(new_position,v);
FT size = cpp11::get<2>(*it);
// Move point
Vertex_handle new_v = helper_.move_point(v, new_position, outdated_cells, moving_vertices);
// Restore size in meshing_info data
new_v->set_meshing_info(size);
}
else // Move point
{
helper_.move_point(v, new_position, outdated_cells, moving_vertices);
}
// Stop if time_limit_ is reached, here we can't return without rebuilding
// restricted delaunay
if ( is_time_limit_reached() )
break;
}
}
visitor.after_move_points();
#ifdef MESH_3_PROFILING
std::cerr << "done in " << t.elapsed() << " seconds." << std::endl;
#endif
#ifdef MESH_3_PROFILING
std::cerr << "Updating C3T3 (rebuilding restricted Delaunay)...";
t.reset();
#endif
// Update c3t3
#ifdef CGAL_INTRUSIVE_LIST
// AF: rebuild_restricted_delaunay does more cell insertion/removal
@ -548,6 +825,11 @@ update_mesh(const Moves_vector& moves,
#endif
visitor.after_rebuild_restricted_delaunay();
#ifdef MESH_3_PROFILING
std::cerr << "Updating C3T3 done in " << t.elapsed() << " seconds." << std::endl;
#endif
}
@ -580,7 +862,7 @@ check_convergence() const
namespace bl = boost::lambda;
FT sum(0);
for( typename std::set<FT>::const_iterator
for( typename std::multiset<FT>::const_iterator
it = big_moves_.begin(), end = big_moves_.end() ; it != end ; ++it )
{
sum += CGAL::sqrt(*it);

View File

@ -26,16 +26,68 @@
#ifndef CGAL_MESH_3_MESH_SIZING_FIELD_H
#define CGAL_MESH_3_MESH_SIZING_FIELD_H
#ifdef CGAL_LINKED_WITH_TBB
# include <tbb/enumerable_thread_specific.h>
#endif
namespace CGAL {
namespace Mesh_3
{
/**
* @class Mesh_sizing_field_base
*/
// Sequential
template <typename Cell_handle, bool used_by_parallel_mesh_3>
class Mesh_sizing_field_base
{
protected:
Cell_handle get_last_cell() const
{
return last_cell_;
}
void set_last_cell(Cell_handle c) const
{
last_cell_ = c;
}
/// A cell that is used to accelerate location queries
mutable Cell_handle last_cell_;
};
#ifdef CGAL_LINKED_WITH_TBB
/**
* @class Mesh_sizing_field_base specialization
*/
// Parallel
template <typename Cell_handle>
class Mesh_sizing_field_base<Cell_handle, true>
{
protected:
Cell_handle get_last_cell() const
{
return last_cell_.local();
}
void set_last_cell(Cell_handle c) const
{
last_cell_.local() = c;
}
/// A cell that is used to accelerate location queries
mutable tbb::enumerable_thread_specific<Cell_handle> last_cell_;
};
#endif // CGAL_LINKED_WITH_TBB
/**
* @class Mesh_sizing_field
*/
template <typename Tr, bool Need_vertex_update = true>
class Mesh_sizing_field
: public Mesh_sizing_field_base<typename Tr::Cell_handle,
Tr::Is_for_parallel_mesh_3>
{
// Types
typedef typename Tr::Geom_traits Gt;
@ -64,7 +116,7 @@ public:
* Returns size at point \c p.
*/
FT operator()(const Point_3& p) const
{ return this->operator()(p,last_cell_); }
{ return this->operator()(p, get_last_cell()); }
/**
* Returns size at point \c p, using \c v to accelerate \c p location
@ -96,12 +148,10 @@ private:
*/
FT interpolate_on_facet_vertices(const Point_3& p,
const Cell_handle& cell) const;
private:
/// The triangulation
Tr& tr_;
/// A cell that is used to accelerate location queries
mutable Cell_handle last_cell_;
};
@ -110,7 +160,6 @@ template <typename Tr, bool B>
Mesh_sizing_field<Tr,B>::
Mesh_sizing_field(Tr& tr)
: tr_(tr)
, last_cell_()
{
}
@ -164,7 +213,7 @@ operator()(const Point_3& p, const Cell_handle& c) const
#else
const Cell_handle cell = tr_.locate(p,c);
#endif
last_cell_ = cell;
set_last_cell(cell);
if ( !tr_.is_infinite(cell) )
return interpolate_on_cell_vertices(p,cell);

View File

@ -113,8 +113,8 @@ public:
return CGAL::NULL_VECTOR;
}
#ifdef CGAL_MESH_3_OPTIMIZER_VERBOSE
#if defined(CGAL_MESH_3_OPTIMIZER_VERBOSE) \
|| defined (CGAL_MESH_3_EXPORT_PERFORMANCE_DATA)
static std::string name() { return std::string("Odt"); }
#endif

View File

@ -433,6 +433,10 @@ operator()(const FT& sliver_bound, const FT& delta, Visitor visitor)
std::cerr << std::endl << "Perturbation statistics:" << std::endl;
print_final_perturbations_statistics();
#endif
#ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA
CGAL_MESH_3_SET_PERFORMANCE_DATA("Perturber_optim_time", running_time_.time());
#endif
if ( is_time_limit_reached() ) {
#ifdef CGAL_MESH_3_PERTURBER_VERBOSE

View File

@ -627,6 +627,10 @@ pump_vertices(double sliver_criterion_limit,
std::cerr << std::endl;
#endif // CGAL_MESH_3_EXUDER_VERBOSE
#ifdef CGAL_MESH_3_EXPORT_PERFORMANCE_DATA
CGAL_MESH_3_SET_PERFORMANCE_DATA("Exuder_optim_time", running_time_.time());
#endif
if ( is_time_limit_reached() ) {
#ifdef CGAL_MESH_3_EXUDER_VERBOSE
std::cerr << "Exuding return code: TIME_LIMIT_REACHED\n\n";

View File

@ -79,6 +79,8 @@ class Triangulation_data_structure_3
typedef Triangulation_data_structure_3<Vb,Cb,used_by_parallel_mesh_3> Tds;
public:
static const bool Is_for_parallel_mesh_3 = used_by_parallel_mesh_3;
// Tools to change the Vertex and Cell types of the TDS.
template < typename Vb2 >

View File

@ -27,10 +27,50 @@
#include <CGAL/triangulation_assertions.h>
#include <CGAL/internal/Dummy_tds_3.h>
#ifdef CGAL_LINKED_WITH_TBB
# include <tbb/enumerable_thread_specific.h>
#endif
namespace CGAL {
/************************************************
// Class Triangulation_ds_cell_base_3_base
// Two versions: sequential / parallel
************************************************/
// Sequential
template <typename TDS_data, bool used_by_parallel_mesh_3>
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 <typename TDS_data>
class Triangulation_ds_cell_base_3_base<TDS_data, true>
{
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> _tds_data;
};
#endif // CGAL_LINKED_WITH_TBB
template < typename TDS = void >
class Triangulation_ds_cell_base_3
: public Triangulation_ds_cell_base_3_base<typename TDS::Cell_data,
TDS::Is_for_parallel_mesh_3>
{
public:
typedef TDS Triangulation_data_structure;
@ -198,15 +238,10 @@ 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 >