52 #include <Eigen/Dense>
66 template<
typename real_t,
int dim>
76 MPI_Comm_size(_mesh->get_mpi_comm(), &mpi_nparts);
77 MPI_Comm_rank(_mesh->get_mpi_comm(), &rank);
80 epsilon_q = DBL_EPSILON;
84 int NElements = _mesh->get_number_elements();
85 for(
int i=0;i<NElements;i++){
86 const int *n=_mesh->get_element(i);
92 _mesh->get_coords(n[1]),
93 _mesh->get_coords(n[2]));
96 _mesh->get_coords(n[1]),
97 _mesh->get_coords(n[2]),
98 _mesh->get_coords(n[3]));
113 int NElements = _mesh->get_number_elements();
114 quality.resize(NElements);
119 #pragma omp for schedule(guided) reduction(+:qsum)
120 for(
int i=0;i<NElements;i++){
121 const int *n=_mesh->get_element(i);
131 good_q = qsum/NElements;
134 good_q = quality_tol;
138 std::vector<int> halo_elements;
140 for(
int i=0;i<NElements;i++){
141 const int *n=_mesh->get_element(i);
145 for(
size_t j=0;j<nloc;j++){
146 if(!_mesh->is_owned_node(n[j])){
147 halo_elements.push_back(i);
155 int NNodes = _mesh->get_number_nodes();
156 std::vector<int> active_vertices(NNodes, 0);
160 if(!colour_sets.empty())
161 max_colour = colour_sets.rbegin()->first;
164 MPI_Allreduce(MPI_IN_PLACE, &max_colour, 1, MPI_INT, MPI_MAX, _mesh->get_mpi_comm());
172 for(
int ic=0;ic<=max_colour;ic++){
173 if(colour_sets.count(ic)){
174 int node_set_size = colour_sets[ic].size();
175 #pragma omp for schedule(guided)
176 for(
int cn=0;cn<node_set_size;cn++){
177 index_t node = colour_sets[ic][cn];
178 active_vertices[node] = 0;
180 if(smart_laplacian_kernel(node)){
181 active_vertices[node] = 1;
183 for(
typename std::vector<index_t>::const_iterator it=_mesh->NNList[node].begin();it!=_mesh->NNList[node].end();++it){
184 active_vertices[*it] = 1;
193 halo_update<real_t, dim, dim==2?3:6>(_mesh->get_mpi_comm(), _mesh->send, _mesh->recv, _mesh->_coords, _mesh->metric);
195 for(std::vector<int>::const_iterator ie=halo_elements.begin();ie!=halo_elements.end();++ie)
201 for(
int iter=1;iter<max_iterations;iter++){
202 for(
int ic=0;ic<=max_colour;ic++){
203 if(colour_sets.count(ic)){
204 int node_set_size = colour_sets[ic].size();
205 #pragma omp for schedule(guided)
206 for(
int cn=0;cn<node_set_size;cn++){
207 index_t node = colour_sets[ic][cn];
210 if(active_vertices[node]){
211 active_vertices[node] = 0;
213 if(smart_laplacian_kernel(node)){
214 active_vertices[node] = 1;
216 for(
typename std::vector<index_t>::const_iterator it=_mesh->NNList[node].begin();it!=_mesh->NNList[node].end();++it){
217 active_vertices[*it] = 1;
226 halo_update<real_t, dim, dim==2?3:6>(_mesh->get_mpi_comm(), _mesh->send, _mesh->recv, _mesh->_coords, _mesh->metric);
228 for(std::vector<int>::const_iterator ie=halo_elements.begin();ie!=halo_elements.end();++ie)
242 int NElements = _mesh->get_number_elements();
243 quality.resize(NElements);
248 #pragma omp for schedule(guided) reduction(+:qsum)
249 for(
int i=0;i<NElements;i++){
250 const int *n=_mesh->get_element(i);
260 good_q = qsum/NElements;
263 good_q = quality_tol;
267 std::vector<int> halo_elements;
269 for(
int i=0;i<NElements;i++){
270 const int *n=_mesh->get_element(i);
274 for(
size_t j=0;j<nloc;j++){
275 if(!_mesh->is_owned_node(n[j])){
276 halo_elements.push_back(i);
284 int NNodes = _mesh->get_number_nodes();
285 std::vector<int> active_vertices(NNodes, 0);
290 if(!colour_sets.empty())
291 max_colour = colour_sets.rbegin()->first;
294 MPI_Allreduce(MPI_IN_PLACE, &max_colour, 1, MPI_INT, MPI_MAX, _mesh->get_mpi_comm());
300 for(
int ic=1;ic<=max_colour;ic++){
301 if(colour_sets.count(ic)){
302 int node_set_size = colour_sets[ic].size();
303 #pragma omp for schedule(guided)
304 for(
int cn=0;cn<node_set_size;cn++){
305 index_t node = colour_sets[ic][cn];
306 active_vertices[node] = 0;
308 if(optimisation_linf_kernel(node)){
309 active_vertices[node] = 1;
311 for(
typename std::vector<index_t>::const_iterator it=_mesh->NNList[node].begin();it!=_mesh->NNList[node].end();++it){
312 active_vertices[*it] = 1;
321 halo_update<real_t, dim, dim==2?3:6>(_mesh->get_mpi_comm(), _mesh->send, _mesh->recv, _mesh->_coords, _mesh->metric);
323 for(std::vector<int>::const_iterator ie=halo_elements.begin();ie!=halo_elements.end();++ie)
329 for(
int iter=1;iter<max_iterations;iter++){
330 for(
int ic=1;ic<=max_colour;ic++){
331 if(colour_sets.count(ic)){
332 int node_set_size = colour_sets[ic].size();
333 #pragma omp for schedule(guided)
334 for(
int cn=0;cn<node_set_size;cn++){
335 index_t node = colour_sets[ic][cn];
338 if(active_vertices[node]){
339 active_vertices[node] = 0;
341 if(optimisation_linf_kernel(node)){
342 active_vertices[node] = 1;
344 for(
typename std::vector<index_t>::const_iterator it=_mesh->NNList[node].begin();it!=_mesh->NNList[node].end();++it){
345 active_vertices[*it] = 1;
354 halo_update<real_t, dim, dim==2?3:6>(_mesh->get_mpi_comm(), _mesh->send, _mesh->recv, _mesh->_coords, _mesh->metric);
356 for(std::vector<int>::const_iterator ie=halo_elements.begin();ie!=halo_elements.end();++ie)
371 std::vector<int> halo_elements;
372 int NElements = _mesh->get_number_elements();
374 for(
int i=0;i<NElements;i++){
375 const int *n=_mesh->get_element(i);
379 for(
size_t j=0;j<nloc;j++){
380 if(!_mesh->is_owned_node(n[j])){
381 halo_elements.push_back(i);
390 if(!colour_sets.empty())
391 max_colour = colour_sets.rbegin()->first;
394 MPI_Allreduce(MPI_IN_PLACE, &max_colour, 1, MPI_INT, MPI_MAX, _mesh->get_mpi_comm());
400 for(
int iter=1;iter<max_iterations;iter++){
401 for(
int ic=1;ic<=max_colour;ic++){
402 if(colour_sets.count(ic)){
403 int node_set_size = colour_sets[ic].size();
404 #pragma omp for schedule(guided)
405 for(
int cn=0;cn<node_set_size;cn++){
406 index_t node = colour_sets[ic][cn];
408 laplacian_kernel(node);
414 halo_update<real_t, dim, dim==2?3:6>(_mesh->get_mpi_comm(), _mesh->send, _mesh->recv, _mesh->_coords, _mesh->metric);
427 inline bool laplacian_kernel(
index_t node){
430 update = laplacian_2d_kernel(node);
432 update = laplacian_3d_kernel(node);
437 inline bool laplacian_2d_kernel(
index_t node){
439 laplacian_2d_kernel(node, p);
442 bool valid = generate_location_2d(node, p, mp);
445 for(
size_t j=0;j<2;j++)
446 p[j] = 0.5*(p[j] + _mesh->_coords[node*2+j]);
448 valid = generate_location_2d(node, p, mp);
455 for(
size_t j=0;j<2;j++)
456 _mesh->_coords[node*2+j] = p[j];
458 for(
size_t j=0;j<3;j++)
459 _mesh->metric[node*3+j] = mp[j];
464 inline bool laplacian_3d_kernel(
index_t node){
466 laplacian_3d_kernel(node, p);
469 bool valid = generate_location_3d(node, p, mp);
472 for(
size_t j=0;j<3;j++)
473 p[j] = 0.5*(p[j] + _mesh->_coords[node*3+j]);
475 valid = generate_location_3d(node, p, mp);
480 for(
size_t j=0;j<3;j++)
481 _mesh->_coords[node*3+j] = p[j];
483 for(
size_t j=0;j<6;j++)
484 _mesh->metric[node*6+j] = mp[j];
489 inline void laplacian_2d_kernel(
index_t node, real_t *p){
490 std::set<index_t> patch(_mesh->get_node_patch(node));
492 real_t x0 = get_x(node);
493 real_t y0 = get_y(node);
495 Eigen::Matrix<real_t, Eigen::Dynamic, Eigen::Dynamic>
A = Eigen::Matrix<real_t, Eigen::Dynamic, Eigen::Dynamic>::Zero(2, 2);
496 Eigen::Matrix<real_t, Eigen::Dynamic, 1> q = Eigen::Matrix<real_t, Eigen::Dynamic, 1>::Zero(2);
498 const real_t *m0 = _mesh->get_metric(node);
499 for(
typename std::set<index_t>::const_iterator il=patch.begin();il!=patch.end();++il){
500 real_t x = get_x(*il)-x0;
501 real_t y = get_y(*il)-y0;
503 const real_t *m1 = _mesh->get_metric(*il);
504 double m[] = {0.5*(m0[0]+m1[0]), 0.5*(m0[1]+m1[1]), 0.5*(m0[2]+m1[2])};
506 q[0] += (m[0]*x + m[1]*y);
507 q[1] += (m[1]*x + m[2]*y);
509 A[0] += m[0]; A[1] += m[1];
515 Eigen::Matrix<real_t, Eigen::Dynamic, 1>
b = Eigen::Matrix<real_t, Eigen::Dynamic, 1>::Zero(2);
516 A.svd().solve(q, &b);
518 for(
size_t i=0;i<2;i++)
527 inline void laplacian_3d_kernel(
index_t node, real_t *p){
528 std::set<index_t> patch(_mesh->get_node_patch(node));
530 real_t x0 = get_x(node);
531 real_t y0 = get_y(node);
532 real_t z0 = get_z(node);
534 Eigen::Matrix<real_t, Eigen::Dynamic, Eigen::Dynamic> A = Eigen::Matrix<real_t, Eigen::Dynamic, Eigen::Dynamic>::Zero(3, 3);
535 Eigen::Matrix<real_t, Eigen::Dynamic, 1> q = Eigen::Matrix<real_t, Eigen::Dynamic, 1>::Zero(3);
537 const real_t *m0 = _mesh->get_metric(node);
538 for(
typename std::set<index_t>::const_iterator il=patch.begin();il!=patch.end();++il){
539 real_t x = get_x(*il)-x0;
540 real_t y = get_y(*il)-y0;
541 real_t z = get_z(*il)-z0;
543 const real_t *m1 = _mesh->get_metric(*il);
544 double m[] = {0.5*(m0[0]+m1[0]), 0.5*(m0[1]+m1[1]), 0.5*(m0[2]+m1[2]),
545 0.5*(m0[3]+m1[3]), 0.5*(m0[4]+m1[4]),
548 q[0] += m[0]*x + m[1]*y + m[2]*z;
549 q[1] += m[1]*x + m[3]*y + m[4]*z;
550 q[2] += m[2]*x + m[4]*y + m[5]*z;
552 A[0] += m[0]; A[1] += m[1]; A[2] += m[2];
553 A[4] += m[3]; A[5] += m[4];
561 Eigen::Matrix<real_t, Eigen::Dynamic, 1> b = Eigen::Matrix<real_t, Eigen::Dynamic, 1>::Zero(3);
562 A.svd().solve(q, &b);
575 inline bool smart_laplacian_kernel(
index_t node){
578 update = smart_laplacian_2d_kernel(node);
580 update = smart_laplacian_3d_kernel(node);
585 bool smart_laplacian_2d_kernel(
index_t node){
587 laplacian_2d_kernel(node, p);
590 bool valid = generate_location_2d(node, p, mp);
593 for(
size_t j=0;j<2;j++)
594 p[j] = 0.5*(p[j] + _mesh->_coords[node*2+j]);
596 valid = generate_location_2d(node, p, mp);
603 real_t functional = functional_Linf(node, p, mp);
604 real_t functional_orig = functional_Linf(node);
606 if(functional-functional_orig<epsilon_q)
609 for(
size_t j=0;j<2;j++)
610 _mesh->_coords[node*2+j] = p[j];
612 for(
size_t j=0;j<3;j++)
613 _mesh->metric[node*3+j] = mp[j];
618 inline bool smart_laplacian_3d_kernel(
index_t node){
620 laplacian_3d_kernel(node, p);
623 bool valid = generate_location_3d(node, p, mp);
626 for(
size_t j=0;j<3;j++)
627 p[j] = 0.5*(p[j] + _mesh->_coords[node*2+j]);
629 valid = generate_location_3d(node, p, mp);
636 real_t functional = functional_Linf(node, p, mp);
637 real_t functional_orig = functional_Linf(node);
639 if(functional-functional_orig<epsilon_q)
642 for(
size_t j=0;j<3;j++)
643 _mesh->_coords[node*3+j] = p[j];
645 for(
size_t j=0;j<6;j++)
646 _mesh->metric[node*6+j] = mp[j];
652 inline bool optimisation_linf_kernel(
index_t node){
655 update = optimisation_linf_2d_kernel(node);
657 update = optimisation_linf_3d_kernel(node);
663 inline bool optimisation_linf_2d_kernel(
index_t n0){
664 const double *m0 = _mesh->get_metric(n0);
665 const double *x0 = _mesh->get_coords(n0);
668 std::pair<double, index_t> worst_element(DBL_MAX, -1);
669 for(
typename std::set<index_t>::const_iterator it=_mesh->NEList[n0].begin();it!=_mesh->NEList[n0].end();++it){
670 if(quality[*it]<worst_element.first)
671 worst_element = std::pair<double, index_t>(quality[*it], *it);
673 assert(worst_element.second!=-1);
676 if(worst_element.first>good_q)
680 double search[2], grad_w[2];
682 const index_t *n=_mesh->get_element(worst_element.second);
688 int n1 = n[(loc+1)%3];
689 int n2 = n[(loc+2)%3];
691 const double *
x1 = _mesh->get_coords(n1);
692 const double *
x2 = _mesh->get_coords(n2);
694 property->lipnikov_grad(loc, x0, x1, x2, m0, grad_w);
696 double mag = sqrt(grad_w[0]*grad_w[0]+grad_w[1]*grad_w[1]);
700 search[i] = grad_w[i]/mag;
708 double bbox[] = {DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX};
709 for(
typename std::vector<index_t>::const_iterator it=_mesh->NNList[n0].begin();it!=_mesh->NNList[n0].end();++it){
710 const double *x1 = _mesh->get_coords(*it);
712 bbox[0] = std::min(bbox[0], x1[0]);
713 bbox[1] = std::max(bbox[1], x1[0]);
715 bbox[2] = std::min(bbox[2], x1[1]);
716 bbox[3] = std::max(bbox[3], x1[1]);
718 alpha = (bbox[1]-bbox[0] + bbox[3]-bbox[2])/2.0;
721 for(
typename std::set<index_t>::const_iterator it=_mesh->NEList[n0].begin();it!=_mesh->NEList[n0].end();++it){
722 if(*it==worst_element.second)
725 const index_t *n=_mesh->get_element(*it);
731 int n1 = n[(loc+1)%3];
732 int n2 = n[(loc+2)%3];
734 const double *x1 = _mesh->get_coords(n1);
735 const double *x2 = _mesh->get_coords(n2);
738 property->lipnikov_grad(loc, x0, x1, x2, m0, grad);
741 (quality[*it]-worst_element.first)/
742 ((search[0]*grad_w[0]+search[1]*grad_w[1])-
743 (search[0]*grad[0]+search[1]*grad[1]));
746 alpha = std::min(alpha, new_alpha);
750 for(
int isearch=0;isearch<10;isearch++){
757 for(
int i=0;i<2;i++){
758 new_x0[i] = x0[i] + alpha*search[i];
759 if(!std::isnormal(new_x0[i]))
764 bool valid = generate_location_2d(n0, new_x0, new_m0);
771 std::vector<double> new_quality;
772 for(
typename std::set<index_t>::const_iterator it=_mesh->NEList[n0].begin();it!=_mesh->NEList[n0].end();++it){
773 const index_t *n=_mesh->get_element(*it);
779 int n1 = n[(loc+1)%3];
780 int n2 = n[(loc+2)%3];
782 const double *x1 = _mesh->get_coords(n1);
783 const double *x2 = _mesh->get_coords(n2);
785 const double *m1 = _mesh->get_metric(n1);
786 const double *m2 = _mesh->get_metric(n2);
788 double new_q =
property->lipnikov(new_x0, x1, x2, new_m0, m1, m2);
789 new_quality.push_back(new_q);
791 if(!std::isnormal(new_q) || new_quality.back()<worst_element.first){
802 assert(_mesh->NEList[n0].size()==new_quality.size());
803 for(
typename std::set<index_t>::const_reverse_iterator it=_mesh->NEList[n0].rbegin();it!=_mesh->NEList[n0].rend();++it){
804 quality[*it] = new_quality.back();
805 new_quality.pop_back();
807 assert(new_quality.empty());
809 for(
size_t i=0;i<dim;i++)
810 _mesh->_coords[n0*dim+i] = new_x0[i];
812 for(
size_t i=0;i<msize;i++)
813 _mesh->metric[n0*msize+i] = new_m0[i];
821 inline bool optimisation_linf_3d_kernel(
index_t n0){
822 const double *m0 = _mesh->get_metric(n0);
823 const double *x0 = _mesh->get_coords(n0);
826 std::pair<double, index_t> worst_element(DBL_MAX, -1);
827 for(
typename std::set<index_t>::const_iterator it=_mesh->NEList[n0].begin();it!=_mesh->NEList[n0].end();++it){
828 if(quality[*it]<worst_element.first)
829 worst_element = std::pair<double, index_t>(quality[*it], *it);
831 assert(worst_element.second!=-1);
834 if(worst_element.first>good_q)
838 double grad_w[3], search[3];
840 const index_t *n=_mesh->get_element(worst_element.second);
870 const double *x1 = _mesh->get_coords(n1);
871 const double *x2 = _mesh->get_coords(n2);
872 const double *
x3 = _mesh->get_coords(n3);
874 property->lipnikov_grad(loc, x0, x1, x2, x3, m0, grad_w);
876 double mag = sqrt(grad_w[0]*grad_w[0] + grad_w[1]*grad_w[1] + grad_w[2]*grad_w[2]);
877 if(!std::isnormal(mag)){
878 std::cout<<
"mag issues "<<mag<<
", "<<grad_w[0]<<
", "<<grad_w[1]<<
", "<<grad_w[2]<<std::endl;
879 std::cout<<
"This usually means that the metric field is rubbish\n";
881 assert(std::isnormal(mag));
884 search[i] = grad_w[i]/mag;
892 double bbox[] = {DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX, DBL_MAX, -DBL_MAX};
893 for(
typename std::vector<index_t>::const_iterator it=_mesh->NNList[n0].begin();it!=_mesh->NNList[n0].end();++it){
894 const double *x1 = _mesh->get_coords(*it);
896 bbox[0] = std::min(bbox[0], x1[0]);
897 bbox[1] = std::max(bbox[1], x1[0]);
899 bbox[2] = std::min(bbox[2], x1[1]);
900 bbox[3] = std::max(bbox[3], x1[1]);
902 bbox[4] = std::min(bbox[4], x1[2]);
903 bbox[5] = std::max(bbox[5], x1[2]);
905 alpha = (bbox[1]-bbox[0] + bbox[3]-bbox[2] + bbox[5]-bbox[4])/6.0;
907 for(
typename std::set<index_t>::const_iterator it=_mesh->NEList[n0].begin();it!=_mesh->NEList[n0].end();++it){
908 if(*it==worst_element.second)
911 const index_t *n=_mesh->get_element(*it);
941 const double *x1 = _mesh->get_coords(n1);
942 const double *x2 = _mesh->get_coords(n2);
943 const double *x3 = _mesh->get_coords(n3);
946 property->lipnikov_grad(loc, x0, x1, x2, x3, m0, grad);
949 (quality[*it]-worst_element.first)/
950 ((search[0]*grad_w[0]+search[1]*grad_w[1]+search[2]*grad_w[2])-
951 (search[0]*grad[0]+search[1]*grad[1]+search[2]*grad[2]));
954 alpha = std::min(alpha, new_alpha);
958 for(
int isearch=0;isearch<10;isearch++){
965 for(
int i=0;i<3;i++){
966 new_x0[i] = x0[i] + alpha*search[i];
970 bool valid = generate_location_3d(n0, new_x0, new_m0);
977 std::vector<double> new_quality;
978 for(
typename std::set<index_t>::const_iterator it=_mesh->NEList[n0].begin();it!=_mesh->NEList[n0].end();++it){
979 const index_t *n=_mesh->get_element(*it);
1009 const double *x1 = _mesh->get_coords(n1);
1010 const double *x2 = _mesh->get_coords(n2);
1011 const double *x3 = _mesh->get_coords(n3);
1014 const double *m1 = _mesh->get_metric(n1);
1015 const double *m2 = _mesh->get_metric(n2);
1016 const double *m3 = _mesh->get_metric(n3);
1018 double new_q =
property->lipnikov(new_x0, x1, x2, x3, new_m0, m1, m2, m3);
1020 if(new_q>worst_element.first){
1021 new_quality.push_back(new_q);
1024 linf_update =
false;
1034 assert(_mesh->NEList[n0].size()==new_quality.size());
1035 for(
typename std::set<index_t>::const_reverse_iterator it=_mesh->NEList[n0].rbegin();it!=_mesh->NEList[n0].rend();++it){
1036 quality[*it] = new_quality.back();
1037 new_quality.pop_back();
1039 assert(new_quality.empty());
1041 for(
size_t i=0;i<dim;i++)
1042 _mesh->_coords[n0*dim+i] = new_x0[i];
1044 for(
size_t i=0;i<msize;i++)
1045 _mesh->metric[n0*msize+i] = new_m0[i];
1054 colour_sets.clear();
1056 int NNodes = _mesh->get_number_nodes();
1057 std::vector<char> colour(NNodes);
1059 Colour::GebremedhinManne(MPI_COMM_WORLD, NNodes, _mesh->NNList, _mesh->send, _mesh->recv, _mesh->node_owner, colour);
1061 int NElements = _mesh->get_number_elements();
1062 std::vector<bool> is_boundary(NNodes,
false);
1063 for(
int i=0;i<NElements;i++){
1064 const int *n=_mesh->get_element(i);
1068 for(
size_t j=0;j<nloc;j++){
1069 if(_mesh->boundary[i*nloc+j]>0){
1070 for(
size_t k=1;k<nloc;k++){
1071 is_boundary[n[(j+k)%nloc]] =
true;
1077 for(
int i=0;i<NNodes;i++){
1078 if((colour[i]<0)||(!_mesh->is_owned_node(i))||(_mesh->NNList[i].empty())||is_boundary[i])
1081 colour_sets[colour[i]].push_back(i);
1087 inline real_t get_x(
index_t nid){
1088 return _mesh->_coords[nid*dim];
1091 inline real_t get_y(
index_t nid){
1092 return _mesh->_coords[nid*dim+1];
1095 inline real_t get_z(
index_t nid){
1097 return _mesh->_coords[nid*dim+2];
1099 std::cerr<<
"ERROR: inline real_t get_z(index_t nid) should not get called for 2D";
1104 inline real_t functional_Linf(
index_t node){
1105 double patch_quality = std::numeric_limits<double>::max();
1107 for(
typename std::set<index_t>::const_iterator ie=_mesh->NEList[node].begin();ie!=_mesh->NEList[node].end();++ie){
1108 patch_quality = std::min(patch_quality, quality[*ie]);
1111 return patch_quality;
1114 inline real_t functional_Linf(
index_t n0,
const real_t *p,
const real_t *mp)
const{
1117 f = functional_Linf_2d(n0, p, mp);
1119 f = functional_Linf_3d(n0, p, mp);
1124 inline real_t functional_Linf_2d(
index_t n0,
const real_t *p,
const real_t *mp)
const{
1125 real_t functional = DBL_MAX;
1126 for(
typename std::set<index_t>::iterator ie=_mesh->NEList[n0].begin();ie!=_mesh->NEList[n0].end();++ie){
1127 const index_t *n=_mesh->get_element(*ie);
1131 while(n[iloc]!=(
int)n0){
1134 int loc1 = (iloc+1)%3;
1135 int loc2 = (iloc+2)%3;
1137 const real_t *x1 = _mesh->get_coords(n[loc1]);
1138 const real_t *x2 = _mesh->get_coords(n[loc2]);
1140 const double *m1 = _mesh->get_metric(n[loc1]);
1141 const double *m2 = _mesh->get_metric(n[loc2]);
1143 real_t fnl =
property->lipnikov(p, x1, x2,
1145 functional = std::min(functional, fnl);
1151 inline real_t functional_Linf_3d(
index_t n0,
const real_t *p,
const real_t *mp)
const{
1152 real_t functional = DBL_MAX;
1153 for(
typename std::set<index_t>::iterator ie=_mesh->NEList[n0].begin();ie!=_mesh->NEList[n0].end();++ie){
1154 const index_t *n=_mesh->get_element(*ie);
1184 const double *x1 = _mesh->get_coords(n1);
1185 const double *x2 = _mesh->get_coords(n2);
1186 const double *x3 = _mesh->get_coords(n3);
1188 const double *m1 = _mesh->get_metric(n1);
1189 const double *m2 = _mesh->get_metric(n2);
1190 const double *m3 = _mesh->get_metric(n3);
1192 real_t fnl =
property->lipnikov(p, x1, x2, x3,
1195 functional = std::min(functional, fnl);
1200 bool generate_location_2d(
index_t node,
const real_t *p,
double *mp){
1202 real_t l[]={-1, -1, -1};
1206 for(
typename std::set<index_t>::const_iterator ie=_mesh->NEList[node].begin();ie!=_mesh->NEList[node].end();++ie){
1207 const index_t *n=_mesh->get_element(*ie);
1210 const real_t *x0 = _mesh->get_coords(n[0]);
1211 const real_t *x1 = _mesh->get_coords(n[1]);
1212 const real_t *x2 = _mesh->get_coords(n[2]);
1218 area =
property->area(p, x1, x2);
1219 }
else if(n[1]==node){
1220 area =
property->area(x0, p, x2);
1222 area =
property->area(x0, x1, p);
1227 real_t
L =
property->area(x0, x1, x2);
1230 ll[0] =
property->area(p, x1, x2)/
L;
1231 ll[1] =
property->area(x0, p, x2)/
L;
1232 ll[2] =
property->area(x0, x1, p )/
L;
1234 real_t min_l = std::min(ll[0], std::min(ll[1], ll[2]));
1238 for(
size_t i=0;i<nloc;i++)
1244 for(
size_t i=0;i<nloc;i++)
1250 assert(tol>-DBL_EPSILON);
1252 const index_t *n=_mesh->get_element(best_e);
1255 for(
size_t i=0;i<msize;i++)
1257 l[0]*_mesh->metric[n[0]*msize+i]+
1258 l[1]*_mesh->metric[n[1]*msize+i]+
1259 l[2]*_mesh->metric[n[2]*msize+i];
1264 bool generate_location_3d(
index_t node,
const real_t *p,
double *mp){
1266 real_t l[]={-1, -1, -1, -1};
1270 for(
typename std::set<index_t>::const_iterator ie=_mesh->NEList[node].begin();ie!=_mesh->NEList[node].end();++ie){
1271 const index_t *n=_mesh->get_element(*ie);
1274 const real_t *x0 = _mesh->get_coords(n[0]);
1275 const real_t *x1 = _mesh->get_coords(n[1]);
1276 const real_t *x2 = _mesh->get_coords(n[2]);
1277 const real_t *x3 = _mesh->get_coords(n[3]);
1283 volume =
property->volume(p, x1, x2, x3);
1284 }
else if(n[1]==node){
1285 volume =
property->volume(x0, p, x2, x3);
1286 }
else if(n[2]==node){
1287 volume =
property->volume(x0, x1, p, x3);
1289 volume =
property->volume(x0, x1, x2, p);
1294 real_t L =
property->volume(x0, x1, x2, x3);
1297 ll[0] =
property->volume(p, x1, x2, x3)/
L;
1298 ll[1] =
property->volume(x0, p, x2, x3)/
L;
1299 ll[2] =
property->volume(x0, x1, p, x3)/
L;
1300 ll[3] =
property->volume(x0, x1, x2, p )/
L;
1302 real_t min_l = std::min(std::min(ll[0], ll[1]), std::min(ll[2], ll[3]));
1306 for(
size_t i=0;i<nloc;i++)
1312 for(
size_t i=0;i<nloc;i++)
1318 assert(tol>-10*DBL_EPSILON);
1320 const index_t *n=_mesh->get_element(best_e);
1323 for(
size_t i=0;i<msize;i++)
1325 l[0]*_mesh->metric[n[0]*msize+i]+
1326 l[1]*_mesh->metric[n[1]*msize+i]+
1327 l[2]*_mesh->metric[n[2]*msize+i]+
1328 l[3]*_mesh->metric[n[3]*msize+i];
1333 inline void update_quality(
index_t element){
1335 update_quality_2d(element);
1337 update_quality_3d(element);
1340 inline void update_quality_2d(
index_t element){
1341 const index_t *n=_mesh->get_element(element);
1343 const double *x0 = _mesh->get_coords(n[0]);
1344 const double *x1 = _mesh->get_coords(n[1]);
1345 const double *x2 = _mesh->get_coords(n[2]);
1347 const double *m0 = _mesh->get_metric(n[0]);
1348 const double *m1 = _mesh->get_metric(n[1]);
1349 const double *m2 = _mesh->get_metric(n[2]);
1351 quality[element] =
property->lipnikov(x0, x1, x2,
1356 inline void update_quality_3d(
index_t element){
1357 const index_t *n=_mesh->get_element(element);
1359 const double *x0 = _mesh->get_coords(n[0]);
1360 const double *x1 = _mesh->get_coords(n[1]);
1361 const double *x2 = _mesh->get_coords(n[2]);
1362 const double *x3 = _mesh->get_coords(n[3]);
1364 const double *m0 = _mesh->get_metric(n[0]);
1365 const double *m1 = _mesh->get_metric(n[1]);
1366 const double *m2 = _mesh->get_metric(n[2]);
1367 const double *m3 = _mesh->get_metric(n[3]);
1369 quality[element] =
property->lipnikov(x0, x1, x2, x3,
1377 const size_t nloc, msize;
1379 int mpi_nparts, rank;
1380 real_t good_q, epsilon_q;
1381 std::vector<real_t> quality;
1382 std::map<int, std::vector<index_t> > colour_sets;
void smart_laplacian(int max_iterations=10, double quality_tol=-1.0)
Calculates a number of element properties.
void laplacian(int max_iterations=10)
static void GebremedhinManne(size_t NNodes, const std::vector< std::vector< index_t > > &NNList, std::vector< char > &colour)
~Smooth()
Default destructor.
Smooth(Mesh< real_t > &mesh)
Default constructor.
Applies Laplacian smoothen in metric space.
void optimisation_linf(int max_iterations=10, double quality_tol=-1.0)