mirror of https://github.com/CGAL/cgal
The global optimizers are now parallel (needs some intense testing now)
This commit is contained in:
parent
f02e3c8872
commit
ab4d97c1e5
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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 >
|
||||
|
|
|
|||
|
|
@ -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 >
|
||||
|
|
|
|||
Loading…
Reference in New Issue