47 #ifdef HAVE_BOOST_UNORDERED_MAP_HPP
48 #include <boost/unordered_map.hpp>
59 template<
typename real_t,
int dim>
class Coarsen{
66 size_t NElements = _mesh->get_number_elements();
67 for(
size_t i=0;i<NElements;i++){
68 const int *n=_mesh->get_element(i);
74 _mesh->get_coords(n[1]),
75 _mesh->get_coords(n[2]));
78 _mesh->get_coords(n[1]),
79 _mesh->get_coords(n[2]),
80 _mesh->get_coords(n[3]));
88 dynamic_vertex = NULL;
90 for(
int i=0; i<3; ++i){
96 for(
int i=0; i<3; ++i)
97 ind_set_size[i].resize(max_colour, 0);
98 ind_sets.resize(nthreads, std::vector< std::vector<index_t> >(max_colour));
99 range_indexer.resize(nthreads, std::vector< std::pair<size_t,size_t> >(max_colour, std::pair<size_t,size_t>(0,0)));
109 if(dynamic_vertex!=NULL)
110 delete[] dynamic_vertex;
112 if(node_colour!=NULL)
113 delete[] node_colour;
115 for(
int i=0; i<3; ++i){
116 if(worklist[i] != NULL)
117 delete[] worklist[i];
126 void coarsen(real_t L_low, real_t L_max,
bool enable_sliver_deletion=
false){
127 size_t NNodes = _mesh->get_number_nodes();
131 delete_slivers = enable_sliver_deletion;
133 if(nnodes_reserve<NNodes){
134 nnodes_reserve = NNodes;
136 if(dynamic_vertex!=NULL)
137 delete [] dynamic_vertex;
139 dynamic_vertex =
new index_t[NNodes];
141 GlobalActiveSet.resize(NNodes);
143 for(
int i=0; i<3; ++i){
144 if(worklist[i] != NULL)
145 delete[] worklist[i];
146 worklist[i] =
new index_t[NNodes];
149 if(node_colour!=NULL)
150 delete[] node_colour;
152 node_colour =
new int[NNodes];
160 std::vector<index_t> forbiddenColours(max_colour, std::numeric_limits<index_t>::max());
167 #pragma omp single nowait
168 memset(node_colour, 0, NNodes *
sizeof(
int));
170 #pragma omp single nowait
172 for(
int i=0; i<max_colour; ++i)
173 ind_set_size[0][i] = 0;
174 GlobalActiveSet_size[0] = 0;
178 #pragma omp for schedule(guided)
179 for(
size_t i=0; i<NNodes; ++i){
180 dynamic_vertex[i] = coarsen_identify_kernel(i, L_low, L_max);
186 bool first_time =
true;
193 #pragma omp single nowait
195 for(
int i=0; i<3; ++i)
196 worklist_size[i] = 0;
198 int next_rnd = (rnd+1)%3;
199 for(
int i=0; i<max_colour; ++i)
200 ind_set_size[next_rnd][i] = 0;
201 GlobalActiveSet_size[next_rnd] = 0;
205 #pragma omp for schedule(guided)
206 for(
size_t i=0; i<NNodes; ++i){
207 if(dynamic_vertex[i] == -2){
208 dynamic_vertex[i] = coarsen_identify_kernel(i, L_low, L_max);
217 std::vector<index_t> local_coloured;
218 #pragma omp for schedule(guided)
219 for(
size_t i=0; i<NNodes; ++i){
220 if(dynamic_vertex[i]>=0){
227 for(
typename std::vector<index_t>::const_iterator jt=_mesh->NNList[i].begin(); jt!=_mesh->NNList[i].end(); ++jt){
228 if(dynamic_vertex[*jt]>=0){
229 forbiddenColours[node_colour[*jt]] = (
index_t) i;
232 for(
size_t j=0; j<forbiddenColours.size(); ++j){
233 if(forbiddenColours[j] != (
index_t) i){
234 node_colour[i] = (int) j;
240 local_coloured.push_back(i);
244 if(local_coloured.size()>0){
247 memcpy(&GlobalActiveSet[pos], &local_coloured[0], local_coloured.size() *
sizeof(
index_t));
251 if(GlobalActiveSet_size[rnd]>0){
252 for(
int set_no=0; set_no<max_colour; ++set_no){
253 ind_sets[tid][set_no].clear();
254 range_indexer[tid][set_no].first = std::numeric_limits<size_t>::infinity();
255 range_indexer[tid][set_no].second = std::numeric_limits<size_t>::infinity();
259 std::vector<index_t> conflicts;
261 #pragma omp for schedule(guided)
262 for(
size_t i=0; i<GlobalActiveSet_size[rnd]; ++i){
263 bool defective =
false;
264 index_t n = GlobalActiveSet[i];
265 for(
typename std::vector<index_t>::const_iterator jt=_mesh->NNList[n].begin(); jt!=_mesh->NNList[n].end(); ++jt){
266 if(dynamic_vertex[*jt]>=0){
267 if(node_colour[n] == node_colour[*jt]){
279 conflicts.push_back(n);
281 for(
typename std::vector<index_t>::const_iterator jt=_mesh->NNList[n].begin(); jt!=_mesh->NNList[n].end(); ++jt){
282 if(dynamic_vertex[*jt]>=0){
283 int c = node_colour[*jt];
284 forbiddenColours[c] = n;
288 for(
size_t j=0; j<forbiddenColours.size(); j++){
289 if(forbiddenColours[j] != n){
290 node_colour[n] = (int) j;
295 ind_sets[tid][node_colour[n]].push_back(n);
302 memcpy(&worklist[0][pos], &conflicts[0], conflicts.size() *
sizeof(
index_t));
309 while(worklist_size[wl]){
310 #pragma omp for schedule(guided)
311 for(
size_t item=0; item<worklist_size[wl]; ++item){
312 index_t n = worklist[wl][item];
313 bool defective =
false;
314 for(
typename std::vector<index_t>::const_iterator jt=_mesh->NNList[n].begin(); jt!=_mesh->NNList[n].end(); ++jt){
315 if(dynamic_vertex[*jt]>=0){
316 if(node_colour[n] == node_colour[*jt]){
328 conflicts.push_back(n);
330 for(
typename std::vector<index_t>::const_iterator jt=_mesh->NNList[n].begin(); jt!=_mesh->NNList[n].end(); ++jt){
331 if(dynamic_vertex[*jt]>=0){
332 int c = node_colour[*jt];
333 forbiddenColours[c] = n;
337 for(
size_t j=0; j<forbiddenColours.size(); j++){
338 if(forbiddenColours[j] != n){
344 ind_sets[tid][node_colour[n]].push_back(n);
353 memcpy(&worklist[wl][pos], &conflicts[0], conflicts.size() *
sizeof(
index_t));
360 worklist_size[(wl+1)%3] = 0;
364 for(
int set_no=0; set_no<max_colour; ++set_no){
365 if(ind_sets[tid][set_no].size()>0){
367 range_indexer[tid][set_no].second = range_indexer[tid][set_no].first + ind_sets[tid][set_no].size();
386 for(
int set_no=0; set_no<max_colour; ++set_no){
387 if(ind_set_size[rnd][set_no] == 0)
391 std::vector<range_element> range;
392 for(
int t=0; t<nthreads; ++t){
393 if(range_indexer[t][set_no].first != range_indexer[t][set_no].second)
398 #pragma omp for schedule(guided)
399 for(
size_t idx=0; idx<ind_set_size[rnd][set_no]; ++idx){
402 std::vector<range_element>::iterator ele = std::lower_bound(range.begin(), range.end(),
404 assert(ele != range.end());
405 assert(idx >= range_indexer[ele->second][set_no].first && idx < range_indexer[ele->second][set_no].second);
406 rm_vertex = ind_sets[ele->second][set_no][idx - range_indexer[ele->second][set_no].first];
407 assert(rm_vertex>=0);
410 if(node_colour[rm_vertex] != set_no)
419 if(dynamic_vertex[rm_vertex] == -2)
420 dynamic_vertex[rm_vertex] = coarsen_identify_kernel(rm_vertex, L_low, L_max);
422 if(dynamic_vertex[rm_vertex] < 0)
425 index_t target_vertex = dynamic_vertex[rm_vertex];
428 for(
typename std::vector<index_t>::const_iterator jt=_mesh->NNList[rm_vertex].begin();jt!=_mesh->NNList[rm_vertex].end();++jt)
429 def_ops->propagate_coarsening(*jt, tid);
432 if(node_colour[target_vertex] >= 0){
433 for(
typename std::vector<index_t>::const_iterator jt=_mesh->NNList[rm_vertex].begin();jt!=_mesh->NNList[rm_vertex].end();++jt){
434 if(*jt != target_vertex){
435 if(node_colour[*jt] == node_colour[target_vertex]){
436 def_ops->reset_colour(target_vertex, tid);
444 dynamic_vertex[rm_vertex] = -1;
447 coarsen_kernel(rm_vertex, target_vertex, tid);
450 #pragma omp for schedule(guided)
451 for(
size_t vtid=0; vtid<defOp_scaling_factor*nthreads; ++vtid){
452 for(
int i=0; i<nthreads; ++i){
453 def_ops->commit_remNN(i, vtid);
454 def_ops->commit_addNN(i, vtid);
455 def_ops->commit_remNE(i, vtid);
456 def_ops->commit_addNE(i, vtid);
457 def_ops->commit_repEN(i, vtid);
458 def_ops->commit_coarsening_propagation(dynamic_vertex, i, vtid);
459 def_ops->commit_colour_reset(node_colour, i, vtid);
464 }
while(GlobalActiveSet_size[rnd]>0);
474 int coarsen_identify_kernel(
index_t rm_vertex, real_t L_low, real_t L_max)
const{
476 if(_mesh->NNList[rm_vertex].empty())
480 if(!_mesh->is_owned_node(rm_vertex))
484 if(_mesh->is_halo_node(rm_vertex))
488 bool delete_with_extreme_prejudice =
false;
490 if(delete_slivers && dim==3){
491 std::set<index_t>::iterator ee=_mesh->NEList[rm_vertex].begin();
492 const int *n=_mesh->get_element(*ee);
494 q_linf =
property->lipnikov(_mesh->get_coords(n[0]),
495 _mesh->get_coords(n[1]),
496 _mesh->get_coords(n[2]),
497 _mesh->get_coords(n[3]),
498 _mesh->get_metric(n[0]),
499 _mesh->get_metric(n[1]),
500 _mesh->get_metric(n[2]),
501 _mesh->get_metric(n[3]));
503 for(;ee!=_mesh->NEList[rm_vertex].end();++ee){
504 n=_mesh->get_element(*ee);
506 q_linf = std::min(q_linf, property->lipnikov(_mesh->get_coords(n[0]),
507 _mesh->get_coords(n[1]),
508 _mesh->get_coords(n[2]),
509 _mesh->get_coords(n[3]),
510 _mesh->get_metric(n[0]),
511 _mesh->get_metric(n[1]),
512 _mesh->get_metric(n[2]),
513 _mesh->get_metric(n[3])));
517 delete_with_extreme_prejudice =
true;
524 std::multimap<real_t, index_t> short_edges;
525 for(
typename std::vector<index_t>::const_iterator nn=_mesh->NNList[rm_vertex].begin();nn!=_mesh->NNList[rm_vertex].end();++nn){
526 double length = _mesh->calc_edge_length(rm_vertex, *nn);
527 if(length<L_low || delete_with_extreme_prejudice)
528 short_edges.insert(std::pair<real_t, index_t>(length, *nn));
531 bool reject_collapse =
false;
533 while(short_edges.size()){
535 target_vertex = short_edges.begin()->second;
536 short_edges.erase(short_edges.begin());
539 reject_collapse=
false;
545 long double total_old_av=0;
546 long double total_new_av=0;
548 for(
typename std::set<index_t>::iterator ee=_mesh->NEList[rm_vertex].begin();ee!=_mesh->NEList[rm_vertex].end();++ee){
549 const int *old_n=_mesh->get_element(*ee);
553 old_av =
property->area(_mesh->get_coords(old_n[0]),
554 _mesh->get_coords(old_n[1]),
555 _mesh->get_coords(old_n[2]));
557 old_av =
property->volume(_mesh->get_coords(old_n[0]),
558 _mesh->get_coords(old_n[1]),
559 _mesh->get_coords(old_n[2]),
560 _mesh->get_coords(old_n[3]));
562 total_old_av+=old_av;
565 if(_mesh->NEList[target_vertex].find(*ee)!=_mesh->NEList[target_vertex].end())
569 std::vector<int> n(nloc);
570 for(
size_t i=0;i<nloc;i++){
573 n[i] = target_vertex;
581 new_av =
property->area(_mesh->get_coords(n[0]),
582 _mesh->get_coords(n[1]),
583 _mesh->get_coords(n[2]));
585 new_av =
property->volume(_mesh->get_coords(n[0]),
586 _mesh->get_coords(n[1]),
587 _mesh->get_coords(n[2]),
588 _mesh->get_coords(n[3]));
589 double new_q =
property->lipnikov(_mesh->get_coords(n[0]),
590 _mesh->get_coords(n[1]),
591 _mesh->get_coords(n[2]),
592 _mesh->get_coords(n[3]),
593 _mesh->get_metric(n[0]),
594 _mesh->get_metric(n[1]),
595 _mesh->get_metric(n[2]),
596 _mesh->get_metric(n[3]));
600 total_new_av+=new_av;
603 if(new_av<DBL_EPSILON){
604 reject_collapse=
true;
610 if(!reject_collapse && fabs(total_new_av-total_old_av)>DBL_EPSILON){
611 reject_collapse=
true;
629 reject_collapse=
true;
640 if(delete_with_extreme_prejudice)
643 return target_vertex;
649 void coarsen_kernel(
index_t rm_vertex,
index_t target_vertex,
int tid){
650 std::set<index_t> deleted_elements;
651 std::set_intersection(_mesh->NEList[rm_vertex].begin(), _mesh->NEList[rm_vertex].end(),
652 _mesh->NEList[target_vertex].begin(), _mesh->NEList[target_vertex].end(),
653 std::inserter(deleted_elements, deleted_elements.begin()));
656 std::set<index_t> common_patch;
659 for(
typename std::set<index_t>::const_iterator de=deleted_elements.begin(); de!=deleted_elements.end();++de){
663 _mesh->NEList[rm_vertex].erase(eid);
667 std::vector<index_t> other_vertex;
668 for(
size_t i=0; i<nloc; ++i){
669 index_t vid = _mesh->_ENList[eid*nloc+i];
673 def_ops->remNE(vid, eid, tid);
676 if(vid != target_vertex){
677 other_vertex.push_back(vid);
678 common_patch.insert(vid);
684 if(_mesh->boundary[eid*nloc+lrm_vertex]>0){
686 std::set<index_t> otherNE;
688 assert(other_vertex.size()==1);
689 otherNE = _mesh->NEList[other_vertex[0]];
691 assert(other_vertex.size()==2);
692 std::set_intersection(_mesh->NEList[other_vertex[0]].begin(), _mesh->NEList[other_vertex[0]].end(),
693 _mesh->NEList[other_vertex[1]].begin(), _mesh->NEList[other_vertex[1]].end(),
694 std::inserter(otherNE, otherNE.begin()));
696 std::set<index_t> new_boundary_eid;
697 std::set_intersection(_mesh->NEList[rm_vertex].begin(), _mesh->NEList[rm_vertex].end(),
698 otherNE.begin(), otherNE.end(), std::inserter(new_boundary_eid, new_boundary_eid.begin()));
700 if(!new_boundary_eid.empty()){
703 assert(new_boundary_eid.size()==1);
704 index_t target_eid = *new_boundary_eid.begin();
705 for(
int i=0;i<nloc;i++){
706 int nid=_mesh->_ENList[target_eid*nloc+i];
708 if(nid!=rm_vertex && nid!=other_vertex[0]){
709 _mesh->boundary[target_eid*nloc+i] = _mesh->boundary[eid*nloc+lrm_vertex];
713 if(nid!=rm_vertex && nid!=other_vertex[0] && nid!=other_vertex[1]){
714 _mesh->boundary[target_eid*nloc+i] = _mesh->boundary[eid*nloc+lrm_vertex];
723 _mesh->_ENList[eid*nloc] = -1;
726 assert((dim==2 && common_patch.size() == deleted_elements.size()) || (dim==3));
729 for(
typename std::set<index_t>::iterator ee=_mesh->NEList[rm_vertex].begin();ee!=_mesh->NEList[rm_vertex].end();++ee){
730 for(
size_t i=0;i<nloc;i++){
731 if(_mesh->_ENList[nloc*(*ee)+i]==rm_vertex){
732 def_ops->repEN(nloc*(*ee)+i, target_vertex, tid);
738 def_ops->addNE(target_vertex, *ee, tid);
742 common_patch.insert(target_vertex);
743 for(
typename std::vector<index_t>::const_iterator nn=_mesh->NNList[rm_vertex].begin();nn!=_mesh->NNList[rm_vertex].end();++nn){
744 def_ops->remNN(*nn, rm_vertex, tid);
747 if(common_patch.count(*nn)==0){
748 def_ops->addNN(*nn, target_vertex, tid);
749 def_ops->addNN(target_vertex, *nn, tid);
753 _mesh->erase_vertex(rm_vertex);
759 size_t nnodes_reserve;
764 static const int max_colour = (dim==2?16:64);
765 std::vector<index_t> GlobalActiveSet;
766 size_t GlobalActiveSet_size[3];
767 std::vector<size_t> ind_set_size[3];
768 std::vector< std::vector< std::vector<index_t> > > ind_sets;
769 std::vector< std::vector< std::pair<size_t,size_t> > > range_indexer;
773 size_t worklist_size[3];
776 static const int defOp_scaling_factor = 4;
778 real_t _L_low, _L_max;
781 const static size_t ndims=dim;
782 const static size_t nloc=dim+1;
783 const static size_t msize=(dim==2?3:6);
Performs 2D mesh coarsening.
Calculates a number of element properties.
bool pragmatic_range_element_comparator(range_element p1, range_element p2)
void coarsen(real_t L_low, real_t L_max, bool enable_sliver_deletion=false)
~Coarsen()
Default destructor.
bool pragmatic_range_element_finder(range_element p1, range_element p2)
Coarsen(Mesh< real_t > &mesh)
Default constructor.
int pragmatic_thread_id()
size_t pragmatic_omp_atomic_capture(size_t *shared, size_t inc)
std::pair< std::pair< size_t, size_t >, int > range_element