PRAgMaTIc  master
Swapping.h
Go to the documentation of this file.
1 /* Copyright (C) 2010 Imperial College London and others.
2  *
3  * Please see the AUTHORS file in the main source directory for a
4  * full list of copyright holders.
5  *
6  * Gerard Gorman
7  * Applied Modelling and Computation Group
8  * Department of Earth Science and Engineering
9  * Imperial College London
10  *
11  * g.gorman@imperial.ac.uk
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above
19  * copyright notice, this list of conditions and the following
20  * disclaimer in the documentation and/or other materials provided
21  * with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
28  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
30  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
32  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
34  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #ifndef SWAPPING_H
39 #define SWAPPING_H
40 
41 #include <algorithm>
42 #include <limits>
43 #include <list>
44 #include <set>
45 #include <vector>
46 
47 #include "Colour.h"
48 #include "DeferredOperations.h"
49 #include "Edge.h"
50 #include "ElementProperty.h"
51 #include "Mesh.h"
52 
56 template<typename real_t, int dim> class Swapping{
57  public:
60  _mesh = &mesh;
61 
62  size_t NElements = _mesh->get_number_elements();
63 
64  // Set the orientation of elements.
65  property = NULL;
66  for(size_t i=0;i<NElements;i++){
67  const int *n=_mesh->get_element(i);
68  if(n[0]<0)
69  continue;
70 
71  if(dim==2)
72  property = new ElementProperty<real_t>(_mesh->get_coords(n[0]),
73  _mesh->get_coords(n[1]),
74  _mesh->get_coords(n[2]));
75  else
76  property = new ElementProperty<real_t>(_mesh->get_coords(n[0]),
77  _mesh->get_coords(n[1]),
78  _mesh->get_coords(n[2]),
79  _mesh->get_coords(n[3]));
80  break;
81  }
82 
83  nnodes_reserve = 0;
84  nthreads = pragmatic_nthreads();
85 
86  if(dim==3){
87  newElements.resize(nthreads);
88  newBoundaries.resize(nthreads);
89  threadIdx.resize(nthreads);
90  splitCnt.resize(nthreads);
91  }
92 
93  for(int i=0; i<3; ++i){
94  worklist[i] = NULL;
95  }
96 
97  // We pre-allocate the maximum capacity that may be needed.
98  node_colour = NULL;
99 
100  for(int i=0; i<3; ++i)
101  ind_set_size[i].resize(max_colour, 0);
102  ind_sets.resize(nthreads, std::vector< std::vector<index_t> >(max_colour));
103  range_indexer.resize(nthreads, std::vector< std::pair<size_t,size_t> >(max_colour, std::pair<size_t,size_t>(0,0)));
104 
105  def_ops = new DeferredOperations<real_t>(_mesh, nthreads, defOp_scaling_factor);
106  }
107 
110  if(property!=NULL)
111  delete property;
112 
113  if(node_colour!=NULL)
114  delete[] node_colour;
115 
116  for(int i=0; i<3; ++i){
117  if(worklist[i] != NULL)
118  delete[] worklist[i];
119  }
120 
121  delete def_ops;
122  }
123 
124  void swap(real_t quality_tolerance){
125  if(dim==2)
126  swap2d(quality_tolerance);
127  else
128  swap3d(quality_tolerance);
129  }
130 
131 
132  private:
133 
134  void swap2d(real_t quality_tolerance){
135  size_t NNodes = _mesh->get_number_nodes();
136  size_t NElements = _mesh->get_number_elements();
137 
138  min_Q = quality_tolerance;
139 
140  if(nnodes_reserve<NNodes){
141  nnodes_reserve = NNodes;
142 
143  GlobalActiveSet.resize(NNodes);
144 
145  for(int i=0; i<3; ++i){
146  if(worklist[i] != NULL)
147  delete[] worklist[i];
148  worklist[i] = new index_t[NNodes];
149  }
150 
151  if(node_colour!=NULL)
152  delete[] node_colour;
153 
154  node_colour = new int[NNodes];
155 
156  quality.resize(NElements, 0.0);
157  marked_edges.resize(NNodes);
158  }
159 
160 #pragma omp parallel
161  {
162  const int tid = pragmatic_thread_id();
163 
164  // Thread-private array of forbidden colours
165  std::vector<index_t> forbiddenColours(max_colour, std::numeric_limits<index_t>::max());
166 
167 #pragma omp single nowait
168  memset(node_colour, 0, NNodes*sizeof(int));
169 
170 #pragma omp single nowait
171  {
172  for(int i=0; i<max_colour; ++i)
173  ind_set_size[0][i] = 0;
174  GlobalActiveSet_size[0] = 0;
175  }
176 
177  // Cache the element quality's. Really need to make this
178  // persistent within Mesh. Also, initialise marked_edges.
179 #pragma omp for schedule(guided)
180  for(size_t i=0; i<NElements; ++i){
181  const int *n=_mesh->get_element(i);
182  if(n[0]>=0){
183  const real_t *x0 = _mesh->get_coords(n[0]);
184  const real_t *x1 = _mesh->get_coords(n[1]);
185  const real_t *x2 = _mesh->get_coords(n[2]);
186 
187  quality[i] = property->lipnikov(x0, x1, x2,
188  _mesh->get_metric(n[0]),
189  _mesh->get_metric(n[1]),
190  _mesh->get_metric(n[2]));
191 
192  if(quality[i]<min_Q){
193  Edge<index_t> edge0(n[1], n[2]);
194  Edge<index_t> edge1(n[0], n[2]);
195  Edge<index_t> edge2(n[0], n[1]);
196  def_ops->propagate_swapping(edge0.edge.first, edge0.edge.second, tid);
197  def_ops->propagate_swapping(edge1.edge.first, edge1.edge.second, tid);
198  def_ops->propagate_swapping(edge2.edge.first, edge2.edge.second, tid);
199  }
200  }else{
201  quality[i] = 0.0;
202  }
203  }
204 
205 #pragma omp for schedule(guided)
206  for(int vtid=0; vtid<defOp_scaling_factor*nthreads; ++vtid){
207  for(int i=0; i<nthreads; ++i){
208  def_ops->commit_swapping_propagation(marked_edges, i, vtid);
209  }
210  }
211 
212  // Variable for accessing GlobalActiveSet_size[rnd] and ind_set_size[rnd]
213  int rnd = 2;
214 
215  do{
216  // Switch to the next round
217  rnd = (rnd+1)%3;
218 
219  // Prepare worklists for conflict resolution.
220  // Reset GlobalActiveSet_size and ind_set_size for next round.
221 #pragma omp single nowait
222  {
223  for(int i=0; i<3; ++i)
224  worklist_size[i] = 0;
225 
226  int next_rnd = (rnd+1)%3;
227  for(int i=0; i<max_colour; ++i)
228  ind_set_size[next_rnd][i] = 0;
229  GlobalActiveSet_size[next_rnd] = 0;
230  }
231 
232  // Colour the active sub-mesh
233  std::vector<index_t> local_coloured;
234 #pragma omp for schedule(guided) nowait
235  for(size_t i=0; i<NNodes; ++i){
236  if(marked_edges[i].size()>0){
237  /*
238  * Create subNNList for vertex i and also execute the first parallel
239  * loop of RokosGorman colouring. This way, two time-consuming barriers,
240  * the one at the end of the aforementioned loop and the one a few lines
241  * below this comment, are merged into one.
242  */
243  for(typename std::vector<index_t>::const_iterator jt=_mesh->NNList[i].begin(); jt!=_mesh->NNList[i].end(); ++jt){
244  if(marked_edges[*jt].size()>0){
245  forbiddenColours[node_colour[*jt]] = (index_t) i;
246  }
247 
248  for(size_t j=0; j<forbiddenColours.size(); ++j){
249  if(forbiddenColours[j] != (index_t) i){
250  node_colour[i] = (int) j;
251  break;
252  }
253  }
254  }
255 
256  local_coloured.push_back(i);
257  }
258  }
259 
260  if(local_coloured.size()>0){
261  size_t pos;
262  pos = pragmatic_omp_atomic_capture(&GlobalActiveSet_size[rnd], local_coloured.size());
263  memcpy(&GlobalActiveSet[pos], &local_coloured[0], local_coloured.size() * sizeof(index_t));
264  }
265 
266 #pragma omp barrier
267  if(GlobalActiveSet_size[rnd]>0){
268  // Continue colouring and swapping
269  for(int set_no=0; set_no<max_colour; ++set_no){
270  ind_sets[tid][set_no].clear();
271  range_indexer[tid][set_no].first = std::numeric_limits<size_t>::infinity();
272  range_indexer[tid][set_no].second = std::numeric_limits<size_t>::infinity();
273  }
274 
275  std::vector<index_t> conflicts;
276 
277 #pragma omp for schedule(guided) nowait
278  for(size_t i=0; i<GlobalActiveSet_size[rnd]; ++i){
279  bool defective = false;
280  index_t n = GlobalActiveSet[i];
281  for(typename std::vector<index_t>::const_iterator jt=_mesh->NNList[n].begin(); jt!=_mesh->NNList[n].end(); ++jt){
282  if(marked_edges[*jt].size()>0){
283  if(node_colour[n] == node_colour[*jt]){
284  // No need to mark both vertices as defectively coloured.
285  // Just mark the one with the lesser ID.
286  if(n < *jt){
287  defective = true;
288  break;
289  }
290  }
291  }
292  }
293 
294  if(defective){
295  conflicts.push_back(n);
296 
297  for(typename std::vector<index_t>::const_iterator jt=_mesh->NNList[n].begin(); jt!=_mesh->NNList[n].end(); ++jt){
298  if(marked_edges[*jt].size()>0){
299  int c = node_colour[*jt];
300  forbiddenColours[c] = n;
301  }
302  }
303 
304  for(size_t j=0; j<forbiddenColours.size(); j++){
305  if(forbiddenColours[j] != n){
306  node_colour[n] = (int) j;
307  break;
308  }
309  }
310  }else{
311  ind_sets[tid][node_colour[n]].push_back(n);
312  }
313  }
314 
315  size_t pos;
316  pos = pragmatic_omp_atomic_capture(&worklist_size[0], conflicts.size());
317 
318  memcpy(&worklist[0][pos], &conflicts[0], conflicts.size() * sizeof(index_t));
319 
320  conflicts.clear();
321 #pragma omp barrier
322 
323  int wl = 0;
324 
325  while(worklist_size[wl]){
326 #pragma omp for schedule(guided) nowait
327  for(size_t item=0; item<worklist_size[wl]; ++item){
328  index_t n = worklist[wl][item];
329  bool defective = false;
330  for(typename std::vector<index_t>::const_iterator jt=_mesh->NNList[n].begin(); jt!=_mesh->NNList[n].end(); ++jt){
331  if(marked_edges[*jt].size()>0){
332  if(node_colour[n] == node_colour[*jt]){
333  // No need to mark both vertices as defectively coloured.
334  // Just mark the one with the lesser ID.
335  if(n < *jt){
336  defective = true;
337  break;
338  }
339  }
340  }
341  }
342 
343  if(defective){
344  conflicts.push_back(n);
345 
346  for(typename std::vector<index_t>::const_iterator jt=_mesh->NNList[n].begin(); jt!=_mesh->NNList[n].end(); ++jt){
347  if(marked_edges[*jt].size()>0){
348  int c = node_colour[*jt];
349  forbiddenColours[c] = n;
350  }
351  }
352 
353  for(size_t j=0; j<forbiddenColours.size(); j++){
354  if(forbiddenColours[j] != n){
355  node_colour[n] = j;
356  break;
357  }
358  }
359  }else{
360  ind_sets[tid][node_colour[n]].push_back(n);
361  }
362  }
363 
364  // Switch worklist
365  wl = (wl+1)%3;
366 
367  size_t pos = pragmatic_omp_atomic_capture(&worklist_size[wl], conflicts.size());
368 
369  memcpy(&worklist[wl][pos], &conflicts[0], conflicts.size() * sizeof(index_t));
370 
371  conflicts.clear();
372 
373  // Clear the next worklist
374 #pragma omp single
375  {
376  worklist_size[(wl+1)%3] = 0;
377  }
378  }
379 
380  for(int set_no=0; set_no<max_colour; ++set_no){
381  if(ind_sets[tid][set_no].size()>0){
382  range_indexer[tid][set_no].first = pragmatic_omp_atomic_capture(&ind_set_size[rnd][set_no], ind_sets[tid][set_no].size());
383  range_indexer[tid][set_no].second = range_indexer[tid][set_no].first + ind_sets[tid][set_no].size();
384  }
385  }
386 
387 #pragma omp barrier
388 
389  for(int set_no=0; set_no<max_colour; ++set_no){
390  if(ind_set_size[rnd][set_no] == 0)
391  continue;
392 
393  // Sort range indexer
394  std::vector<range_element> range;
395  for(int t=0; t<nthreads; ++t){
396  if(range_indexer[t][set_no].first != range_indexer[t][set_no].second)
397  range.push_back(range_element(range_indexer[t][set_no], t));
398  }
399  std::sort(range.begin(), range.end(), pragmatic_range_element_comparator);
400 
401 #pragma omp for schedule(guided)
402  for(size_t idx=0; idx<ind_set_size[rnd][set_no]; ++idx){
403  // Find which vertex corresponds to idx.
404  index_t i = -1;
405  std::vector<range_element>::iterator ele = std::lower_bound(range.begin(), range.end(),
406  range_element(std::pair<size_t,size_t> (idx,idx), 0), pragmatic_range_element_finder);
407  assert(ele != range.end());
408  assert(idx >= range_indexer[ele->second][set_no].first && idx < range_indexer[ele->second][set_no].second);
409  i = ind_sets[ele->second][set_no][idx - range_indexer[ele->second][set_no].first];
410  assert(i>=0);
411 
412  // If the node has been un-coloured, skip it.
413  if(node_colour[i] != set_no)
414  continue;
415 
416  // Set of elements in this cavity which were modified since the last commit of deferred operations.
417  std::set<index_t> modified_elements;
418  std::set<index_t> marked_edges_new;
419 
420  for(typename std::set<index_t>::const_iterator vid=marked_edges[i].begin(); vid!=marked_edges[i].end(); ++vid){
421  index_t j = *vid;
422 
423  // If vertex j is adjacent to one of the modified elements, then its adjacency list is invalid.
424  bool skip = false;
425  for(typename std::set<index_t>::const_iterator it=modified_elements.begin(); it!=modified_elements.end(); ++it){
426  if(_mesh->NEList[j].find(*it) != _mesh->NEList[j].end()){
427  skip = true;
428  break;
429  }
430  }
431  if(skip){
432  marked_edges_new.insert(j);
433  continue;
434  }
435 
436  Edge<index_t> edge(i, j);
437  swap_kernel2d(edge, modified_elements, tid);
438 
439  // If edge was swapped
440  if(edge.edge.first != i){
441  index_t k = edge.edge.first;
442  index_t l = edge.edge.second;
443  // Uncolour one of the lateral vertices if their colours clash.
444  if((node_colour[k] == node_colour[l]) && (node_colour[k] >= 0))
445  def_ops->reset_colour(l, tid);
446 
447  Edge<index_t> lateralEdges[] = {
448  Edge<index_t>(i, k), Edge<index_t>(i, l), Edge<index_t>(j, k), Edge<index_t>(j, l)};
449 
450  // Propagate the operation
451  for(size_t ee=0; ee<4; ++ee)
452  def_ops->propagate_swapping(lateralEdges[ee].edge.first, lateralEdges[ee].edge.second, tid);
453  }
454  }
455 
456  marked_edges[i].swap(marked_edges_new);
457  }
458 
459  // Commit deferred operations
460 #pragma omp for schedule(guided)
461  for(int vtid=0; vtid<defOp_scaling_factor*nthreads; ++vtid){
462  for(int i=0; i<nthreads; ++i){
463  def_ops->commit_remNN(i, vtid);
464  def_ops->commit_addNN(i, vtid);
465  def_ops->commit_remNE(i, vtid);
466  def_ops->commit_addNE(i, vtid);
467  def_ops->commit_swapping_propagation(marked_edges, i, vtid);
468  def_ops->commit_colour_reset(node_colour, i, vtid);
469  }
470  }
471  }
472  }
473  }while(GlobalActiveSet_size[rnd]>0);
474  }
475  }
476 
477  void swap3d(real_t Q_min){
478  // Cache the element quality's.
479  size_t NElements = _mesh->get_number_elements();
480  std::vector<real_t> quality(NElements, -1);
481 #pragma omp parallel
482  {
483 #pragma omp for schedule(static)
484  for(int i=0;i<(int)NElements;i++){
485  const int *n=_mesh->get_element(i);
486  if(n[0]<0){
487  quality[i] = 0.0;
488  continue;
489  }
490 
491  const real_t *x0 = _mesh->get_coords(n[0]);
492  const real_t *x1 = _mesh->get_coords(n[1]);
493  const real_t *x2 = _mesh->get_coords(n[2]);
494  const real_t *x3 = _mesh->get_coords(n[3]);
495 
496  quality[i] = property->lipnikov(x0, x1, x2, x3,
497  _mesh->get_metric(n[0]),
498  _mesh->get_metric(n[1]),
499  _mesh->get_metric(n[2]),
500  _mesh->get_metric(n[3]));
501  }
502  }
503 
504  std::map<int, std::deque<int> > partialEEList;
505  for(size_t i=0;i<NElements;i++){
506  // Check this is not deleted.
507  const int *n=_mesh->get_element(i);
508  if(n[0]<0)
509  continue;
510 
511  // Only start storing information for poor elements.
512  if(quality[i]<Q_min){
513  bool is_halo = false;
514  for(int j=0; j<nloc; ++j){
515  if(_mesh->is_halo_node(n[j])){
516  is_halo = true;
517  break;
518  }
519  }
520  if(is_halo)
521  continue;
522 
523  partialEEList[i].resize(4);
524  std::fill(partialEEList[i].begin(), partialEEList[i].end(), -1);
525 
526  for(size_t j=0;j<4;j++){
527  std::set<index_t> intersection12;
528  set_intersection(_mesh->NEList[n[(j+1)%4]].begin(), _mesh->NEList[n[(j+1)%4]].end(),
529  _mesh->NEList[n[(j+2)%4]].begin(), _mesh->NEList[n[(j+2)%4]].end(),
530  inserter(intersection12, intersection12.begin()));
531 
532  std::set<index_t> EE;
533  set_intersection(intersection12.begin(),intersection12.end(),
534  _mesh->NEList[n[(j+3)%4]].begin(), _mesh->NEList[n[(j+3)%4]].end(),
535  inserter(EE, EE.begin()));
536 
537  for(typename std::set<index_t>::const_iterator it=EE.begin();it!=EE.end();++it){
538  if(*it != (index_t)i){
539  partialEEList[i][j] = *it;
540  break;
541  }
542  }
543  }
544  }
545  }
546 
547  if(partialEEList.empty())
548  return;
549 
550  // Colour the graph and choose the maximal independent set.
551  std::map<int , std::set<int> > graph;
552  for(std::map<int, std::deque<int> >::const_iterator it=partialEEList.begin();it!=partialEEList.end();++it){
553  for(std::deque<int>::const_iterator jt=it->second.begin();jt!=it->second.end();++jt){
554  graph[*jt].insert(it->first);
555  graph[it->first].insert(*jt);
556  }
557  }
558 
559  std::deque<int> renumber(graph.size());
560  std::map<int, int> irenumber;
561  // std::vector<size_t> nedges(graph.size());
562  size_t loc=0;
563  for(std::map<int , std::set<int> >::const_iterator it=graph.begin();it!=graph.end();++it){
564  // nedges[loc] = it->second.size();
565  renumber[loc] = it->first;
566  irenumber[it->first] = loc;
567  loc++;
568  }
569 
570  std::vector< std::vector<index_t> > NNList(graph.size());
571  for(std::map<int , std::set<int> >::const_iterator it=graph.begin();it!=graph.end();++it){
572  for(std::set<int>::const_iterator jt=it->second.begin();jt!=it->second.end();++jt){
573  NNList[irenumber[it->first]].push_back(irenumber[*jt]);
574  }
575  }
576  std::vector<char> colour(graph.size());
577  Colour::greedy(graph.size(), NNList, colour);
578 
579  // Assume colour 0 will be the maximal independent set.
580 
581  int max_colour=colour[0];
582  for(size_t i=1;i<graph.size();i++)
583  max_colour = std::max(max_colour, (int)colour[i]);
584 
585  // Process face-to-edge swap.
586  for(int c=0;c<max_colour;c++){
587  for(size_t i=0;i<graph.size();i++){
588  int eid0 = renumber[i];
589 
590  if(colour[i]==c && (partialEEList.count(eid0)>0)){
591 
592  // Check this is not deleted.
593  const int *n=_mesh->get_element(eid0);
594  if(n[0]<0)
595  continue;
596 
597  assert(partialEEList[eid0].size()==4);
598 
599  // Check adjacency is not toxic.
600  bool toxic = false;
601  for(int j=0;j<4;j++){
602  int eid1 = partialEEList[eid0][j];
603  if(eid1==-1)
604  continue;
605 
606  const int *m=_mesh->get_element(eid1);
607  if(m[0]<0){
608  toxic = true;
609  break;
610  }
611  }
612  if(toxic)
613  continue;
614 
615  // Create set of nodes for quick lookup.
616  std::set<int> ele0_set;
617  for(int j=0;j<4;j++)
618  ele0_set.insert(n[j]);
619 
620  for(int j=0;j<4;j++){
621  int eid1 = partialEEList[eid0][j];
622  if(eid1==-1)
623  continue;
624 
625  std::vector<int> hull(5, -1);
626  if(j==0){
627  hull[0] = n[1];
628  hull[1] = n[3];
629  hull[2] = n[2];
630  hull[3] = n[0];
631  }else if(j==1){
632  hull[0] = n[2];
633  hull[1] = n[3];
634  hull[2] = n[0];
635  hull[3] = n[1];
636  }else if(j==2){
637  hull[0] = n[0];
638  hull[1] = n[3];
639  hull[2] = n[1];
640  hull[3] = n[2];
641  }else if(j==3){
642  hull[0] = n[0];
643  hull[1] = n[1];
644  hull[2] = n[2];
645  hull[3] = n[3];
646  }
647 
648  const int *m=_mesh->get_element(eid1);
649  assert(m[0]>=0);
650 
651  for(int k=0;k<4;k++)
652  if(ele0_set.count(m[k])==0){
653  hull[4] = m[k];
654  break;
655  }
656  assert(hull[4]!=-1);
657 
658  // New element: 0143
659  real_t q0 = property->lipnikov(_mesh->get_coords(hull[0]),
660  _mesh->get_coords(hull[1]),
661  _mesh->get_coords(hull[4]),
662  _mesh->get_coords(hull[3]),
663  _mesh->get_metric(hull[0]),
664  _mesh->get_metric(hull[1]),
665  _mesh->get_metric(hull[4]),
666  _mesh->get_metric(hull[3]));
667 
668  // New element: 1243
669  real_t q1 = property->lipnikov(_mesh->get_coords(hull[1]),
670  _mesh->get_coords(hull[2]),
671  _mesh->get_coords(hull[4]),
672  _mesh->get_coords(hull[3]),
673  _mesh->get_metric(hull[1]),
674  _mesh->get_metric(hull[2]),
675  _mesh->get_metric(hull[4]),
676  _mesh->get_metric(hull[3]));
677 
678  // New element:2043
679  real_t q2 = property->lipnikov(_mesh->get_coords(hull[2]),
680  _mesh->get_coords(hull[0]),
681  _mesh->get_coords(hull[4]),
682  _mesh->get_coords(hull[3]),
683  _mesh->get_metric(hull[2]),
684  _mesh->get_metric(hull[0]),
685  _mesh->get_metric(hull[4]),
686  _mesh->get_metric(hull[3]));
687 
688  if(std::min(quality[eid0],quality[eid1]) < std::min(q0, std::min(q1, q2))){
689  // Cache boundary values
690  int eid0_b0, eid0_b1, eid0_b2, eid1_b0, eid1_b1, eid1_b2;
691  for(int face=0; face<nloc; ++face){
692  if(n[face] == hull[0])
693  eid0_b0 = _mesh->boundary[eid0*nloc+face];
694  else if(n[face] == hull[1])
695  eid0_b1 = _mesh->boundary[eid0*nloc+face];
696  else if(n[face] == hull[2])
697  eid0_b2 = _mesh->boundary[eid0*nloc+face];
698 
699  if(m[face] == hull[0])
700  eid1_b0 = _mesh->boundary[eid1*nloc+face];
701  else if(m[face] == hull[1])
702  eid1_b1 = _mesh->boundary[eid1*nloc+face];
703  else if(m[face] == hull[2])
704  eid1_b2 = _mesh->boundary[eid1*nloc+face];
705  }
706 
707  _mesh->erase_element(eid0);
708  _mesh->erase_element(eid1);
709 
710  int e0[] = {hull[0], hull[1], hull[4], hull[3]};
711  int b0[] = {0, 0, eid0_b2, eid1_b2};
712  int eid0 = _mesh->append_element(e0, b0);
713  quality.push_back(q0);
714 
715  int e1[] = {hull[1], hull[2], hull[4], hull[3]};
716  int b1[] = {0, 0, eid0_b0, eid1_b0};
717  int eid1 = _mesh->append_element(e1, b1);
718  quality.push_back(q1);
719 
720  int e2[] = {hull[2], hull[0], hull[4], hull[3]};
721  int b2[] = {0, 0, eid0_b1, eid1_b1};
722  int eid2 = _mesh->append_element(e2, b2);
723  quality.push_back(q2);
724 
725  _mesh->NNList[hull[3]].push_back(hull[4]);
726  _mesh->NNList[hull[4]].push_back(hull[3]);
727  _mesh->NEList[hull[0]].insert(eid0);
728  _mesh->NEList[hull[0]].insert(eid2);
729  _mesh->NEList[hull[1]].insert(eid0);
730  _mesh->NEList[hull[1]].insert(eid1);
731  _mesh->NEList[hull[2]].insert(eid1);
732  _mesh->NEList[hull[2]].insert(eid2);
733  _mesh->NEList[hull[3]].insert(eid0);
734  _mesh->NEList[hull[3]].insert(eid1);
735  _mesh->NEList[hull[3]].insert(eid2);
736  _mesh->NEList[hull[4]].insert(eid0);
737  _mesh->NEList[hull[4]].insert(eid1);
738  _mesh->NEList[hull[4]].insert(eid2);
739 
740  break;
741  }
742  }
743  }
744  }
745  }
746 
747  // Process edge-face swaps.
748  for(int c=0;c<max_colour;c++){
749  for(size_t i=0;i<graph.size();i++){
750  int eid0 = renumber[i];
751 
752  if(colour[i]==c && (partialEEList.count(eid0)>0)){
753 
754  // Check this is not deleted.
755  const int *n=_mesh->get_element(eid0);
756  if(n[0]<0)
757  continue;
758 
759  bool toxic=false, swapped=false;
760  for(int k=0;(k<3)&&(!toxic)&&(!swapped);k++){
761  for(int l=k+1;l<4;l++){
762  Edge<index_t> edge = Edge<index_t>(n[k], n[l]);
763 
764  std::set<index_t> neigh_elements;
765  set_intersection(_mesh->NEList[n[k]].begin(), _mesh->NEList[n[k]].end(),
766  _mesh->NEList[n[l]].begin(), _mesh->NEList[n[l]].end(),
767  inserter(neigh_elements, neigh_elements.begin()));
768 
769  double min_quality = quality[eid0];
770  std::vector<index_t> constrained_edges_unsorted;
771  std::map<int, std::map<index_t, int> > b;
772  std::vector<int> element_order, e_to_eid;
773 
774  for(typename std::set<index_t>::const_iterator it=neigh_elements.begin();it!=neigh_elements.end();++it){
775  min_quality = std::min(min_quality, quality[*it]);
776 
777  const int *m=_mesh->get_element(*it);
778  if(m[0]<0){
779  toxic=true;
780  break;
781  }
782 
783  e_to_eid.push_back(*it);
784 
785  for(int j=0;j<4;j++){
786  if((m[j]!=n[k])&&(m[j]!=n[l])){
787  constrained_edges_unsorted.push_back(m[j]);
788  }else if(m[j] == n[k]){
789  b[*it][n[k]] = _mesh->boundary[nloc*(*it)+j];
790  }else{ // if(m[j] == n[l])
791  b[*it][n[l]] = _mesh->boundary[nloc*(*it)+j];
792  }
793  }
794  }
795 
796  if(toxic)
797  break;
798 
799  size_t nelements = neigh_elements.size();
800  assert(nelements*2==constrained_edges_unsorted.size());
801  assert(b.size() == nelements);
802 
803  // Sort edges.
804  std::vector<index_t> constrained_edges;
805  std::vector<bool> sorted(nelements, false);
806  constrained_edges.push_back(constrained_edges_unsorted[0]);
807  constrained_edges.push_back(constrained_edges_unsorted[1]);
808  element_order.push_back(e_to_eid[0]);
809  for(size_t j=1;j<nelements;j++){
810  for(size_t e=1;e<nelements;e++){
811  if(sorted[e])
812  continue;
813  if(*constrained_edges.rbegin()==constrained_edges_unsorted[e*2]){
814  constrained_edges.push_back(constrained_edges_unsorted[e*2]);
815  constrained_edges.push_back(constrained_edges_unsorted[e*2+1]);
816  element_order.push_back(e_to_eid[e]);
817  sorted[e]=true;
818  break;
819  }else if(*constrained_edges.rbegin()==constrained_edges_unsorted[e*2+1]){
820  constrained_edges.push_back(constrained_edges_unsorted[e*2+1]);
821  constrained_edges.push_back(constrained_edges_unsorted[e*2]);
822  element_order.push_back(e_to_eid[e]);
823  sorted[e]=true;
824  break;
825  }
826  }
827  }
828 
829  if(*constrained_edges.begin() != *constrained_edges.rbegin()){
830  toxic = true;
831  break;
832  }
833  assert(element_order.size() == nelements);
834 
835  std::vector< std::vector<index_t> > new_elements;
836  std::vector< std::vector<int> > new_boundaries;
837  if(nelements==3){
838  // This is the 3-element to 2-element swap.
839  new_elements.resize(1);
840  new_boundaries.resize(1);
841 
842  new_elements[0].push_back(constrained_edges[0]);
843  new_elements[0].push_back(constrained_edges[2]);
844  new_elements[0].push_back(constrained_edges[4]);
845  new_elements[0].push_back(n[l]);
846  new_boundaries[0].push_back(b[element_order[1]][n[k]]);
847  new_boundaries[0].push_back(b[element_order[2]][n[k]]);
848  new_boundaries[0].push_back(b[element_order[0]][n[k]]);
849  new_boundaries[0].push_back(0);
850 
851  new_elements[0].push_back(constrained_edges[2]);
852  new_elements[0].push_back(constrained_edges[0]);
853  new_elements[0].push_back(constrained_edges[4]);
854  new_elements[0].push_back(n[k]);
855  new_boundaries[0].push_back(b[element_order[2]][n[l]]);
856  new_boundaries[0].push_back(b[element_order[1]][n[l]]);
857  new_boundaries[0].push_back(b[element_order[0]][n[l]]);
858  new_boundaries[0].push_back(0);
859  }else if(nelements==4){
860  // This is the 4-element to 4-element swap.
861  new_elements.resize(2);
862  new_boundaries.resize(2);
863 
864  // Option 1.
865  new_elements[0].push_back(constrained_edges[0]);
866  new_elements[0].push_back(constrained_edges[2]);
867  new_elements[0].push_back(constrained_edges[6]);
868  new_elements[0].push_back(n[l]);
869  new_boundaries[0].push_back(0);
870  new_boundaries[0].push_back(b[element_order[3]][n[k]]);
871  new_boundaries[0].push_back(b[element_order[0]][n[k]]);
872  new_boundaries[0].push_back(0);
873 
874  new_elements[0].push_back(constrained_edges[2]);
875  new_elements[0].push_back(constrained_edges[4]);
876  new_elements[0].push_back(constrained_edges[6]);
877  new_elements[0].push_back(n[l]);
878  new_boundaries[0].push_back(b[element_order[2]][n[k]]);
879  new_boundaries[0].push_back(0);
880  new_boundaries[0].push_back(b[element_order[1]][n[k]]);
881  new_boundaries[0].push_back(0);
882 
883  new_elements[0].push_back(constrained_edges[2]);
884  new_elements[0].push_back(constrained_edges[0]);
885  new_elements[0].push_back(constrained_edges[6]);
886  new_elements[0].push_back(n[k]);
887  new_boundaries[0].push_back(b[element_order[3]][n[l]]);
888  new_boundaries[0].push_back(0);
889  new_boundaries[0].push_back(b[element_order[0]][n[l]]);
890  new_boundaries[0].push_back(0);
891 
892  new_elements[0].push_back(constrained_edges[4]);
893  new_elements[0].push_back(constrained_edges[2]);
894  new_elements[0].push_back(constrained_edges[6]);
895  new_elements[0].push_back(n[k]);
896  new_boundaries[0].push_back(0);
897  new_boundaries[0].push_back(b[element_order[2]][n[l]]);
898  new_boundaries[0].push_back(b[element_order[1]][n[l]]);
899  new_boundaries[0].push_back(0);
900 
901  // Option 2
902  new_elements[1].push_back(constrained_edges[0]);
903  new_elements[1].push_back(constrained_edges[2]);
904  new_elements[1].push_back(constrained_edges[4]);
905  new_elements[1].push_back(n[l]);
906  new_boundaries[1].push_back(b[element_order[1]][n[k]]);
907  new_boundaries[1].push_back(0);
908  new_boundaries[1].push_back(b[element_order[0]][n[k]]);
909  new_boundaries[1].push_back(0);
910 
911  new_elements[1].push_back(constrained_edges[0]);
912  new_elements[1].push_back(constrained_edges[4]);
913  new_elements[1].push_back(constrained_edges[6]);
914  new_elements[1].push_back(n[l]);
915  new_boundaries[1].push_back(b[element_order[2]][n[k]]);
916  new_boundaries[1].push_back(b[element_order[3]][n[k]]);
917  new_boundaries[1].push_back(0);
918  new_boundaries[1].push_back(0);
919 
920  new_elements[1].push_back(constrained_edges[0]);
921  new_elements[1].push_back(constrained_edges[4]);
922  new_elements[1].push_back(constrained_edges[2]);
923  new_elements[1].push_back(n[k]);
924  new_boundaries[1].push_back(b[element_order[1]][n[l]]);
925  new_boundaries[1].push_back(b[element_order[0]][n[l]]);
926  new_boundaries[1].push_back(0);
927  new_boundaries[1].push_back(0);
928 
929  new_elements[1].push_back(constrained_edges[0]);
930  new_elements[1].push_back(constrained_edges[6]);
931  new_elements[1].push_back(constrained_edges[4]);
932  new_elements[1].push_back(n[k]);
933  new_boundaries[1].push_back(b[element_order[2]][n[l]]);
934  new_boundaries[1].push_back(0);
935  new_boundaries[1].push_back(b[element_order[3]][n[l]]);
936  new_boundaries[1].push_back(0);
937  }else if(nelements==5){
938  // This is the 5-element to 6-element swap.
939  new_elements.resize(5);
940  new_boundaries.resize(5);
941 
942  // Option 1
943  new_elements[0].push_back(constrained_edges[0]);
944  new_elements[0].push_back(constrained_edges[2]);
945  new_elements[0].push_back(constrained_edges[4]);
946  new_elements[0].push_back(n[l]);
947  new_boundaries[0].push_back(b[element_order[1]][n[k]]);
948  new_boundaries[0].push_back(0);
949  new_boundaries[0].push_back(b[element_order[0]][n[k]]);
950  new_boundaries[0].push_back(0);
951 
952  new_elements[0].push_back(constrained_edges[4]);
953  new_elements[0].push_back(constrained_edges[6]);
954  new_elements[0].push_back(constrained_edges[0]);
955  new_elements[0].push_back(n[l]);
956  new_boundaries[0].push_back(0);
957  new_boundaries[0].push_back(0);
958  new_boundaries[0].push_back(b[element_order[2]][n[k]]);
959  new_boundaries[0].push_back(0);
960 
961  new_elements[0].push_back(constrained_edges[6]);
962  new_elements[0].push_back(constrained_edges[8]);
963  new_elements[0].push_back(constrained_edges[0]);
964  new_elements[0].push_back(n[l]);
965  new_boundaries[0].push_back(b[element_order[4]][n[k]]);
966  new_boundaries[0].push_back(0);
967  new_boundaries[0].push_back(b[element_order[3]][n[k]]);
968  new_boundaries[0].push_back(0);
969 
970  new_elements[0].push_back(constrained_edges[2]);
971  new_elements[0].push_back(constrained_edges[0]);
972  new_elements[0].push_back(constrained_edges[4]);
973  new_elements[0].push_back(n[k]);
974  new_boundaries[0].push_back(0);
975  new_boundaries[0].push_back(b[element_order[1]][n[l]]);
976  new_boundaries[0].push_back(b[element_order[0]][n[l]]);
977  new_boundaries[0].push_back(0);
978 
979  new_elements[0].push_back(constrained_edges[6]);
980  new_elements[0].push_back(constrained_edges[4]);
981  new_elements[0].push_back(constrained_edges[0]);
982  new_elements[0].push_back(n[k]);
983  new_boundaries[0].push_back(0);
984  new_boundaries[0].push_back(0);
985  new_boundaries[0].push_back(b[element_order[2]][n[l]]);
986  new_boundaries[0].push_back(0);
987 
988  new_elements[0].push_back(constrained_edges[8]);
989  new_elements[0].push_back(constrained_edges[6]);
990  new_elements[0].push_back(constrained_edges[0]);
991  new_elements[0].push_back(n[k]);
992  new_boundaries[0].push_back(0);
993  new_boundaries[0].push_back(b[element_order[4]][n[l]]);
994  new_boundaries[0].push_back(b[element_order[3]][n[l]]);
995  new_boundaries[0].push_back(0);
996 
997  // Option 2
998  new_elements[1].push_back(constrained_edges[0]);
999  new_elements[1].push_back(constrained_edges[2]);
1000  new_elements[1].push_back(constrained_edges[8]);
1001  new_elements[1].push_back(n[l]);
1002  new_boundaries[1].push_back(0);
1003  new_boundaries[1].push_back(b[element_order[4]][n[k]]);
1004  new_boundaries[1].push_back(b[element_order[0]][n[k]]);
1005  new_boundaries[1].push_back(0);
1006 
1007  new_elements[1].push_back(constrained_edges[2]);
1008  new_elements[1].push_back(constrained_edges[6]);
1009  new_elements[1].push_back(constrained_edges[8]);
1010  new_elements[1].push_back(n[l]);
1011  new_boundaries[1].push_back(b[element_order[3]][n[k]]);
1012  new_boundaries[1].push_back(0);
1013  new_boundaries[1].push_back(0);
1014  new_boundaries[1].push_back(0);
1015 
1016  new_elements[1].push_back(constrained_edges[2]);
1017  new_elements[1].push_back(constrained_edges[4]);
1018  new_elements[1].push_back(constrained_edges[6]);
1019  new_elements[1].push_back(n[l]);
1020  new_boundaries[1].push_back(b[element_order[2]][n[k]]);
1021  new_boundaries[1].push_back(0);
1022  new_boundaries[1].push_back(b[element_order[1]][n[k]]);
1023  new_boundaries[1].push_back(0);
1024 
1025  new_elements[1].push_back(constrained_edges[0]);
1026  new_elements[1].push_back(constrained_edges[8]);
1027  new_elements[1].push_back(constrained_edges[2]);
1028  new_elements[1].push_back(n[k]);
1029  new_boundaries[1].push_back(0);
1030  new_boundaries[1].push_back(b[element_order[0]][n[l]]);
1031  new_boundaries[1].push_back(b[element_order[4]][n[l]]);
1032  new_boundaries[1].push_back(0);
1033 
1034  new_elements[1].push_back(constrained_edges[2]);
1035  new_elements[1].push_back(constrained_edges[8]);
1036  new_elements[1].push_back(constrained_edges[6]);
1037  new_elements[1].push_back(n[k]);
1038  new_boundaries[1].push_back(b[element_order[3]][n[l]]);
1039  new_boundaries[1].push_back(0);
1040  new_boundaries[1].push_back(0);
1041  new_boundaries[1].push_back(0);
1042 
1043  new_elements[1].push_back(constrained_edges[2]);
1044  new_elements[1].push_back(constrained_edges[6]);
1045  new_elements[1].push_back(constrained_edges[4]);
1046  new_elements[1].push_back(n[k]);
1047  new_boundaries[1].push_back(b[element_order[2]][n[l]]);
1048  new_boundaries[1].push_back(b[element_order[1]][n[l]]);
1049  new_boundaries[1].push_back(0);
1050  new_boundaries[1].push_back(0);
1051 
1052  // Option 3
1053  new_elements[2].push_back(constrained_edges[4]);
1054  new_elements[2].push_back(constrained_edges[0]);
1055  new_elements[2].push_back(constrained_edges[2]);
1056  new_elements[2].push_back(n[l]);
1057  new_boundaries[2].push_back(b[element_order[0]][n[k]]);
1058  new_boundaries[2].push_back(b[element_order[1]][n[k]]);
1059  new_boundaries[2].push_back(0);
1060  new_boundaries[2].push_back(0);
1061 
1062  new_elements[2].push_back(constrained_edges[4]);
1063  new_elements[2].push_back(constrained_edges[8]);
1064  new_elements[2].push_back(constrained_edges[0]);
1065  new_elements[2].push_back(n[l]);
1066  new_boundaries[2].push_back(b[element_order[4]][n[k]]);
1067  new_boundaries[2].push_back(0);
1068  new_boundaries[2].push_back(0);
1069  new_boundaries[2].push_back(0);
1070 
1071  new_elements[2].push_back(constrained_edges[4]);
1072  new_elements[2].push_back(constrained_edges[6]);
1073  new_elements[2].push_back(constrained_edges[8]);
1074  new_elements[2].push_back(n[l]);
1075  new_boundaries[2].push_back(b[element_order[3]][n[k]]);
1076  new_boundaries[2].push_back(0);
1077  new_boundaries[2].push_back(b[element_order[2]][n[k]]);
1078  new_boundaries[2].push_back(0);
1079 
1080  new_elements[2].push_back(constrained_edges[4]);
1081  new_elements[2].push_back(constrained_edges[2]);
1082  new_elements[2].push_back(constrained_edges[0]);
1083  new_elements[2].push_back(n[k]);
1084  new_boundaries[2].push_back(b[element_order[0]][n[l]]);
1085  new_boundaries[2].push_back(0);
1086  new_boundaries[2].push_back(b[element_order[1]][n[l]]);
1087  new_boundaries[2].push_back(0);
1088 
1089  new_elements[2].push_back(constrained_edges[4]);
1090  new_elements[2].push_back(constrained_edges[0]);
1091  new_elements[2].push_back(constrained_edges[8]);
1092  new_elements[2].push_back(n[k]);
1093  new_boundaries[2].push_back(b[element_order[4]][n[l]]);
1094  new_boundaries[2].push_back(0);
1095  new_boundaries[2].push_back(0);
1096  new_boundaries[2].push_back(0);
1097 
1098  new_elements[2].push_back(constrained_edges[4]);
1099  new_elements[2].push_back(constrained_edges[8]);
1100  new_elements[2].push_back(constrained_edges[6]);
1101  new_elements[2].push_back(n[k]);
1102  new_boundaries[2].push_back(b[element_order[3]][n[l]]);
1103  new_boundaries[2].push_back(b[element_order[2]][n[l]]);
1104  new_boundaries[2].push_back(0);
1105  new_boundaries[2].push_back(0);
1106 
1107  // Option 4
1108  new_elements[3].push_back(constrained_edges[6]);
1109  new_elements[3].push_back(constrained_edges[2]);
1110  new_elements[3].push_back(constrained_edges[4]);
1111  new_elements[3].push_back(n[l]);
1112  new_boundaries[3].push_back(b[element_order[1]][n[k]]);
1113  new_boundaries[3].push_back(b[element_order[2]][n[k]]);
1114  new_boundaries[3].push_back(0);
1115  new_boundaries[3].push_back(0);
1116 
1117  new_elements[3].push_back(constrained_edges[6]);
1118  new_elements[3].push_back(constrained_edges[0]);
1119  new_elements[3].push_back(constrained_edges[2]);
1120  new_elements[3].push_back(n[l]);
1121  new_boundaries[3].push_back(b[element_order[0]][n[k]]);
1122  new_boundaries[3].push_back(0);
1123  new_boundaries[3].push_back(0);
1124  new_boundaries[3].push_back(0);
1125 
1126  new_elements[3].push_back(constrained_edges[6]);
1127  new_elements[3].push_back(constrained_edges[8]);
1128  new_elements[3].push_back(constrained_edges[0]);
1129  new_elements[3].push_back(n[l]);
1130  new_boundaries[3].push_back(b[element_order[4]][n[k]]);
1131  new_boundaries[3].push_back(0);
1132  new_boundaries[3].push_back(b[element_order[3]][n[k]]);
1133  new_boundaries[3].push_back(0);
1134 
1135  new_elements[3].push_back(constrained_edges[6]);
1136  new_elements[3].push_back(constrained_edges[4]);
1137  new_elements[3].push_back(constrained_edges[2]);
1138  new_elements[3].push_back(n[k]);
1139  new_boundaries[3].push_back(b[element_order[1]][n[l]]);
1140  new_boundaries[3].push_back(0);
1141  new_boundaries[3].push_back(b[element_order[2]][n[l]]);
1142  new_boundaries[3].push_back(0);
1143 
1144  new_elements[3].push_back(constrained_edges[6]);
1145  new_elements[3].push_back(constrained_edges[2]);
1146  new_elements[3].push_back(constrained_edges[0]);
1147  new_elements[3].push_back(n[k]);
1148  new_boundaries[3].push_back(b[element_order[0]][n[l]]);
1149  new_boundaries[3].push_back(0);
1150  new_boundaries[3].push_back(0);
1151  new_boundaries[3].push_back(0);
1152 
1153  new_elements[3].push_back(constrained_edges[6]);
1154  new_elements[3].push_back(constrained_edges[0]);
1155  new_elements[3].push_back(constrained_edges[8]);
1156  new_elements[3].push_back(n[k]);
1157  new_boundaries[3].push_back(b[element_order[4]][n[l]]);
1158  new_boundaries[3].push_back(b[element_order[3]][n[l]]);
1159  new_boundaries[3].push_back(0);
1160  new_boundaries[3].push_back(0);
1161 
1162  // Option 5
1163  new_elements[4].push_back(constrained_edges[8]);
1164  new_elements[4].push_back(constrained_edges[0]);
1165  new_elements[4].push_back(constrained_edges[2]);
1166  new_elements[4].push_back(n[l]);
1167  new_boundaries[4].push_back(b[element_order[0]][n[k]]);
1168  new_boundaries[4].push_back(0);
1169  new_boundaries[4].push_back(b[element_order[4]][n[k]]);
1170  new_boundaries[4].push_back(0);
1171 
1172  new_elements[4].push_back(constrained_edges[8]);
1173  new_elements[4].push_back(constrained_edges[2]);
1174  new_elements[4].push_back(constrained_edges[4]);
1175  new_elements[4].push_back(n[l]);
1176  new_boundaries[4].push_back(b[element_order[1]][n[k]]);
1177  new_boundaries[4].push_back(0);
1178  new_boundaries[4].push_back(0);
1179  new_boundaries[4].push_back(0);
1180 
1181  new_elements[4].push_back(constrained_edges[8]);
1182  new_elements[4].push_back(constrained_edges[4]);
1183  new_elements[4].push_back(constrained_edges[6]);
1184  new_elements[4].push_back(n[l]);
1185  new_boundaries[4].push_back(b[element_order[2]][n[k]]);
1186  new_boundaries[4].push_back(b[element_order[3]][n[k]]);
1187  new_boundaries[4].push_back(0);
1188  new_boundaries[4].push_back(0);
1189 
1190  new_elements[4].push_back(constrained_edges[8]);
1191  new_elements[4].push_back(constrained_edges[2]);
1192  new_elements[4].push_back(constrained_edges[0]);
1193  new_elements[4].push_back(n[k]);
1194  new_boundaries[4].push_back(b[element_order[0]][n[l]]);
1195  new_boundaries[4].push_back(b[element_order[4]][n[l]]);
1196  new_boundaries[4].push_back(0);
1197  new_boundaries[4].push_back(0);
1198 
1199  new_elements[4].push_back(constrained_edges[8]);
1200  new_elements[4].push_back(constrained_edges[4]);
1201  new_elements[4].push_back(constrained_edges[2]);
1202  new_elements[4].push_back(n[k]);
1203  new_boundaries[4].push_back(b[element_order[1]][n[l]]);
1204  new_boundaries[4].push_back(0);
1205  new_boundaries[4].push_back(0);
1206  new_boundaries[4].push_back(0);
1207 
1208  new_elements[4].push_back(constrained_edges[8]);
1209  new_elements[4].push_back(constrained_edges[6]);
1210  new_elements[4].push_back(constrained_edges[4]);
1211  new_elements[4].push_back(n[k]);
1212  new_boundaries[4].push_back(b[element_order[2]][n[l]]);
1213  new_boundaries[4].push_back(0);
1214  new_boundaries[4].push_back(b[element_order[3]][n[l]]);
1215  new_boundaries[4].push_back(0);
1216  }else if(nelements==6){
1217  // This is the 6-element to 8-element swap.
1218  new_elements.resize(1);
1219  new_boundaries.resize(1);
1220 
1221  new_elements[0].push_back(constrained_edges[0]);
1222  new_elements[0].push_back(constrained_edges[2]);
1223  new_elements[0].push_back(constrained_edges[10]);
1224  new_elements[0].push_back(n[l]);
1225  new_boundaries[0].push_back(0);
1226  new_boundaries[0].push_back(b[element_order[5]][n[k]]);
1227  new_boundaries[0].push_back(b[element_order[0]][n[k]]);
1228  new_boundaries[0].push_back(0);
1229 
1230  new_elements[0].push_back(constrained_edges[4]);
1231  new_elements[0].push_back(constrained_edges[6]);
1232  new_elements[0].push_back(constrained_edges[8]);
1233  new_elements[0].push_back(n[l]);
1234  new_boundaries[0].push_back(b[element_order[3]][n[k]]);
1235  new_boundaries[0].push_back(0);
1236  new_boundaries[0].push_back(b[element_order[2]][n[k]]);
1237  new_boundaries[0].push_back(0);
1238 
1239  new_elements[0].push_back(constrained_edges[2]);
1240  new_elements[0].push_back(constrained_edges[4]);
1241  new_elements[0].push_back(constrained_edges[10]);
1242  new_elements[0].push_back(n[l]);
1243  new_boundaries[0].push_back(0);
1244  new_boundaries[0].push_back(0);
1245  new_boundaries[0].push_back(b[element_order[1]][n[k]]);
1246  new_boundaries[0].push_back(0);
1247 
1248  new_elements[0].push_back(constrained_edges[10]);
1249  new_elements[0].push_back(constrained_edges[4]);
1250  new_elements[0].push_back(constrained_edges[8]);
1251  new_elements[0].push_back(n[l]);
1252  new_boundaries[0].push_back(0);
1253  new_boundaries[0].push_back(b[element_order[4]][n[k]]);
1254  new_boundaries[0].push_back(0);
1255  new_boundaries[0].push_back(0);
1256 
1257  new_elements[0].push_back(constrained_edges[2]);
1258  new_elements[0].push_back(constrained_edges[0]);
1259  new_elements[0].push_back(constrained_edges[10]);
1260  new_elements[0].push_back(n[k]);
1261  new_boundaries[0].push_back(b[element_order[5]][n[l]]);
1262  new_boundaries[0].push_back(0);
1263  new_boundaries[0].push_back(b[element_order[0]][n[l]]);
1264  new_boundaries[0].push_back(0);
1265 
1266  new_elements[0].push_back(constrained_edges[6]);
1267  new_elements[0].push_back(constrained_edges[4]);
1268  new_elements[0].push_back(constrained_edges[8]);
1269  new_elements[0].push_back(n[k]);
1270  new_boundaries[0].push_back(0);
1271  new_boundaries[0].push_back(b[element_order[3]][n[l]]);
1272  new_boundaries[0].push_back(b[element_order[2]][n[l]]);
1273  new_boundaries[0].push_back(0);
1274 
1275  new_elements[0].push_back(constrained_edges[4]);
1276  new_elements[0].push_back(constrained_edges[2]);
1277  new_elements[0].push_back(constrained_edges[10]);
1278  new_elements[0].push_back(n[k]);
1279  new_boundaries[0].push_back(0);
1280  new_boundaries[0].push_back(0);
1281  new_boundaries[0].push_back(b[element_order[1]][n[l]]);
1282  new_boundaries[0].push_back(0);
1283 
1284  new_elements[0].push_back(constrained_edges[4]);
1285  new_elements[0].push_back(constrained_edges[10]);
1286  new_elements[0].push_back(constrained_edges[8]);
1287  new_elements[0].push_back(n[k]);
1288  new_boundaries[0].push_back(b[element_order[4]][n[l]]);
1289  new_boundaries[0].push_back(0);
1290  new_boundaries[0].push_back(0);
1291  new_boundaries[0].push_back(0);
1292  }else{
1293  continue;
1294  }
1295 
1296  nelements = new_elements[0].size()/4;
1297 
1298  // Check new minimum quality.
1299  std::vector<double> new_min_quality(new_elements.size());
1300  std::vector< std::vector<double> > newq(new_elements.size());
1301  int best_option;
1302  for(int invert=0;invert<2;invert++){
1303  best_option=0;
1304  for(size_t option=0;option<new_elements.size();option++){
1305  newq[option].resize(nelements);
1306  for(size_t j=0;j<nelements;j++){
1307  newq[option][j] = property->lipnikov(_mesh->get_coords(new_elements[option][j*4+0]),
1308  _mesh->get_coords(new_elements[option][j*4+1]),
1309  _mesh->get_coords(new_elements[option][j*4+2]),
1310  _mesh->get_coords(new_elements[option][j*4+3]),
1311  _mesh->get_metric(new_elements[option][j*4+0]),
1312  _mesh->get_metric(new_elements[option][j*4+1]),
1313  _mesh->get_metric(new_elements[option][j*4+2]),
1314  _mesh->get_metric(new_elements[option][j*4+3]));
1315  }
1316 
1317  new_min_quality[option] = newq[option][0];
1318  for(size_t j=0;j<nelements;j++)
1319  new_min_quality[option] = std::min(newq[option][j], new_min_quality[option]);
1320  }
1321 
1322 
1323  for(size_t option=1;option<new_elements.size();option++){
1324  if(new_min_quality[option]>new_min_quality[best_option]){
1325  best_option = option;
1326  }
1327  }
1328 
1329  if(new_min_quality[best_option] < 0.0){
1330  // Invert elements.
1331  std::vector< std::vector<index_t> >::iterator it, bit;
1332  for(it=new_elements.begin(), bit=new_boundaries.begin(); it!=new_elements.end(); ++it, ++bit){
1333  for(size_t j=0;j<nelements;j++){
1334  index_t stash_id = (*it)[j*4];
1335  (*it)[j*4] = (*it)[j*4+1];
1336  (*it)[j*4+1] = stash_id;
1337  int stash_b = (*bit)[j*4];
1338  (*bit)[j*4] = (*bit)[j*4+1];
1339  (*bit)[j*4+1] = stash_b;
1340  }
1341  }
1342 
1343  continue;
1344  }
1345  break;
1346  }
1347 
1348  if(new_min_quality[best_option] <= min_quality)
1349  continue;
1350 
1351  // Update NNList
1352  std::vector<index_t>::iterator vit = std::find(_mesh->NNList[n[k]].begin(), _mesh->NNList[n[k]].end(), n[l]);
1353  assert(vit != _mesh->NNList[n[k]].end());
1354  _mesh->NNList[n[k]].erase(vit);
1355  vit = std::find(_mesh->NNList[n[l]].begin(), _mesh->NNList[n[l]].end(), n[k]);
1356  assert(vit != _mesh->NNList[n[l]].end());
1357  _mesh->NNList[n[l]].erase(vit);
1358 
1359  // Remove old elements.
1360  for(typename std::set<index_t>::const_iterator it=neigh_elements.begin();it!=neigh_elements.end();++it)
1361  _mesh->erase_element(*it);
1362 
1363  // Add new elements.
1364  for(size_t j=0;j<nelements;j++){
1365  int eid = _mesh->append_element(&(new_elements[best_option][j*4]), &(new_boundaries[best_option][j*4]));
1366  quality.push_back(newq[best_option][j]);
1367 
1368  for(int p=0; p<nloc; ++p){
1369  index_t v1 = new_elements[best_option][j*4+p];
1370  _mesh->NEList[v1].insert(eid);
1371 
1372  for(int q=p+1; q<nloc; ++q){
1373  index_t v2 = new_elements[best_option][j*4+q];
1374  std::vector<index_t>::iterator vit = std::find(_mesh->NNList[v1].begin(), _mesh->NNList[v1].end(), v2);
1375  if(vit == _mesh->NNList[v1].end()){
1376  _mesh->NNList[v1].push_back(v2);
1377  _mesh->NNList[v2].push_back(v1);
1378  }
1379  }
1380  }
1381  }
1382 
1383  swapped = true;
1384  break;
1385  }
1386  }
1387  }
1388  }
1389  }
1390 
1391  return;
1392  }
1393 
1394  void swap_kernel2d(Edge<index_t>& edge, std::set<index_t>& modified_elements, size_t tid){
1395  index_t i = edge.edge.first;
1396  index_t j = edge.edge.second;
1397 
1398  if(_mesh->is_halo_node(i)&& _mesh->is_halo_node(j))
1399  return;
1400 
1401  // Find the two elements sharing this edge
1402  index_t intersection[2];
1403  {
1404  size_t loc = 0;
1405  std::set<index_t>::const_iterator it=_mesh->NEList[i].begin();
1406  while(loc<2 && it!=_mesh->NEList[i].end()){
1407  if(_mesh->NEList[j].find(*it)!=_mesh->NEList[j].end()){
1408  intersection[loc++] = *it;
1409  }
1410  ++it;
1411  }
1412 
1413  // If this is a surface edge, it cannot be swapped.
1414  if(loc!=2)
1415  return;
1416  }
1417 
1418  index_t eid0 = intersection[0];
1419  index_t eid1 = intersection[1];
1420 
1421  const index_t *n = _mesh->get_element(eid0);
1422  int n_off=-1;
1423  for(size_t k=0;k<3;k++){
1424  if((n[k]!=i) && (n[k]!=j)){
1425  n_off = k;
1426  break;
1427  }
1428  }
1429  assert(n[n_off]>=0);
1430 
1431  const index_t *m = _mesh->get_element(eid1);
1432  int m_off=-1;
1433  for(size_t k=0;k<3;k++){
1434  if((m[k]!=i) && (m[k]!=j)){
1435  m_off = k;
1436  break;
1437  }
1438  }
1439  assert(m[m_off]>=0);
1440 
1441  assert(n[(n_off+2)%3]==m[(m_off+1)%3] && n[(n_off+1)%3]==m[(m_off+2)%3]);
1442 
1443  index_t k = n[n_off];
1444  index_t l = m[m_off];
1445 
1446  if(_mesh->is_halo_node(k)&& _mesh->is_halo_node(l))
1447  return;
1448 
1449  int n_swap[] = {n[n_off], m[m_off], n[(n_off+2)%3]}; // new eid0
1450  int m_swap[] = {n[n_off], n[(n_off+1)%3], m[m_off]}; // new eid1
1451 
1452  real_t q0 = property->lipnikov(_mesh->get_coords(n_swap[0]),
1453  _mesh->get_coords(n_swap[1]),
1454  _mesh->get_coords(n_swap[2]),
1455  _mesh->get_metric(n_swap[0]),
1456  _mesh->get_metric(n_swap[1]),
1457  _mesh->get_metric(n_swap[2]));
1458  real_t q1 = property->lipnikov(_mesh->get_coords(m_swap[0]),
1459  _mesh->get_coords(m_swap[1]),
1460  _mesh->get_coords(m_swap[2]),
1461  _mesh->get_metric(m_swap[0]),
1462  _mesh->get_metric(m_swap[1]),
1463  _mesh->get_metric(m_swap[2]));
1464  real_t worst_q = std::min(quality[eid0], quality[eid1]);
1465  real_t new_worst_q = std::min(q0, q1);
1466 
1467  if(new_worst_q>worst_q){
1468  // Cache new quality measures.
1469  quality[eid0] = q0;
1470  quality[eid1] = q1;
1471 
1472  // Update NNList
1473  typename std::vector<index_t>::iterator it;
1474  it = std::find(_mesh->NNList[i].begin(), _mesh->NNList[i].end(), j);
1475  assert(it != _mesh->NNList[i].end());
1476  _mesh->NNList[i].erase(it);
1477  def_ops->remNN(j, i, tid);
1478  def_ops->addNN(k, l, tid);
1479  def_ops->addNN(l, k, tid);
1480 
1481  // Update node-element list.
1482  def_ops->remNE(n_swap[2], eid1, tid);
1483  def_ops->remNE(m_swap[1], eid0, tid);
1484  def_ops->addNE(n_swap[0], eid1, tid);
1485  def_ops->addNE(n_swap[1], eid0, tid);
1486 
1487  // Update element-node and boundary list for this element.
1488  const int *bn = &_mesh->boundary[eid0*nloc];
1489  const int *bm = &_mesh->boundary[eid1*nloc];
1490  const int bn_swap[] = {bm[(m_off+2)%3], bn[(n_off+1)%3], 0}; // boundary for n_swap
1491  const int bm_swap[] = {bm[(m_off+1)%3], 0, bn[(n_off+2)%3]}; // boundary for m_swap
1492 
1493  for(size_t cnt=0;cnt<nloc;cnt++){
1494  _mesh->_ENList[eid0*nloc+cnt] = n_swap[cnt];
1495  _mesh->_ENList[eid1*nloc+cnt] = m_swap[cnt];
1496  _mesh->boundary[eid0*nloc+cnt] = bn_swap[cnt];
1497  _mesh->boundary[eid1*nloc+cnt] = bm_swap[cnt];
1498  }
1499 
1500  edge.edge.first = std::min(k, l);
1501  edge.edge.second = std::max(k, l);
1502  modified_elements.insert(eid0);
1503  modified_elements.insert(eid1);
1504  }
1505 
1506  return;
1507  }
1508 
1509  inline void append_element(const index_t *elem, const int *boundary, const size_t tid){
1510  for(size_t i=0; i<nloc; ++i){
1511  newElements[tid].push_back(elem[i]);
1512  newBoundaries[tid].push_back(boundary[i]);
1513  }
1514  }
1515 
1516  inline void replace_element(const index_t eid, const index_t *n, const int *boundary){
1517  for(size_t i=0;i<nloc;i++){
1518  _mesh->_ENList[eid*nloc+i]=n[i];
1519  _mesh->boundary[eid*nloc+i]=boundary[i];
1520  }
1521  }
1522 
1523  Mesh<real_t> *_mesh;
1524  ElementProperty<real_t> *property;
1525 
1526  size_t nnodes_reserve;
1527 
1528  // Colouring
1529  int *node_colour;
1530  static const int max_colour = (dim==2?16:64);
1531  std::vector<index_t> GlobalActiveSet;
1532  size_t GlobalActiveSet_size[3];
1533  std::vector<size_t> ind_set_size[3];
1534  std::vector< std::vector< std::vector<index_t> > > ind_sets;
1535  std::vector< std::vector< std::pair<size_t,size_t> > > range_indexer;
1536 
1537  // Used for iterative colouring
1538  index_t* worklist[3];
1539  size_t worklist_size[3];
1540 
1541  static const size_t ndims=dim;
1542  static const size_t nloc=dim+1;
1543  static const size_t msize=(dim==2?3:6);
1544 
1545  DeferredOperations<real_t>* def_ops;
1546  static const int defOp_scaling_factor = 32;
1547 
1548  std::vector< std::vector<index_t> > newElements;
1549  std::vector< std::vector<int> > newBoundaries;
1550  std::vector<size_t> threadIdx, splitCnt;
1551 
1552  std::vector< std::set<index_t> > marked_edges;
1553  std::vector<real_t> quality;
1554  real_t min_Q;
1555 
1556  int nthreads;
1557 };
1558 
1559 #endif
Swapping(Mesh< real_t > &mesh)
Default constructor.
Definition: Swapping.h:59
int index_t
Calculates a number of element properties.
Performs edge/face swapping.
Definition: Swapping.h:56
Manages mesh data.
Definition: Mesh.h:70
bool pragmatic_range_element_comparator(range_element p1, range_element p2)
Mesh edge object.
Definition: Edge.h:43
int pragmatic_nthreads()
void swap(real_t quality_tolerance)
Definition: Swapping.h:124
~Swapping()
Default destructor.
Definition: Swapping.h:109
bool pragmatic_range_element_finder(range_element p1, range_element p2)
static void greedy(size_t NNodes, const std::vector< std::vector< index_t > > &NNList, std::vector< char > &colour)
Definition: Colour.h:59
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