48 #ifdef HAVE_BOOST_UNORDERED_MAP_HPP
49 #include <boost/unordered_map.hpp>
70 template<
typename real_t>
class Mesh{
81 Mesh(
int NNodes,
int NElements,
const index_t *ENList,
const real_t *x,
const real_t *y){
83 _mpi_comm = MPI_COMM_WORLD;
85 _init(NNodes, NElements, ENList, x, y, NULL, NULL, NULL);
100 Mesh(
int NNodes,
int NElements,
const index_t *ENList,
101 const real_t *x,
const real_t *y,
const index_t *lnn2gnn,
102 const index_t *owner_range, MPI_Comm mpi_comm){
103 _mpi_comm = mpi_comm;
104 _init(NNodes, NElements, ENList, x, y, NULL, lnn2gnn, owner_range);
118 const real_t *x,
const real_t *y,
const real_t *z){
120 _mpi_comm = MPI_COMM_WORLD;
122 _init(NNodes, NElements, ENList, x, y, z, NULL, NULL);
138 Mesh(
int NNodes,
int NElements,
const index_t *ENList,
139 const real_t *x,
const real_t *y,
const real_t *z,
const index_t *lnn2gnn,
140 const index_t *owner_range, MPI_Comm mpi_comm){
141 _mpi_comm = mpi_comm;
142 _init(NNodes, NElements, ENList, x, y, z, lnn2gnn, owner_range);
153 for(
size_t i=0;i<ndims;i++)
154 _coords[ndims*NNodes+i] = x[i];
156 for(
size_t i=0;i<msize;i++)
157 metric[msize*NNodes+i] = m[i];
168 node_owner[nid] = rank;
174 if(_ENList.size() < (NElements+1)*nloc){
175 _ENList.resize(2*NElements*nloc);
176 boundary.resize(2*NElements*nloc);
179 for(
size_t i=0;i<nloc;i++)
180 _ENList[nloc*NElements+i] = n[i];
189 if(_ENList.size() < (NElements+1)*nloc){
190 _ENList.resize(2*NElements*nloc);
191 boundary.resize(2*NElements*nloc);
194 for(
size_t i=0;i<nloc;i++){
195 _ENList[nloc*NElements+i] = n[i];
196 boundary[nloc*NElements+i] = b[i];
205 assert(boundary.size()==0);
212 boundary.resize(NElements*3);
213 std::fill(boundary.begin(), boundary.end(), -2);
216 std::vector< std::set<int> > NEList(NNodes);
217 for(
size_t i=0;i<NElements;i++){
221 for(
size_t j=0;j<3;j++)
222 NEList[_ENList[i*3+j]].insert(i);
226 for(
size_t i=0;i<NElements;i++){
230 for(
int j=0;j<3;j++){
231 int n1 = _ENList[i*3+(j+1)%3];
232 int n2 = _ENList[i*3+(j+2)%3];
235 std::set<int> neighbours;
236 set_intersection(NEList[n1].begin(), NEList[n1].end(),
237 NEList[n2].begin(), NEList[n2].end(),
238 inserter(neighbours, neighbours.begin()));
240 if(neighbours.size()==2){
241 if(*neighbours.begin()==(int)i)
242 boundary[i*3+j] = *neighbours.rbegin();
244 boundary[i*3+j] = *neighbours.begin();
248 boundary[i*3+j] = -1;
254 boundary.resize(NElements*4);
255 std::fill(boundary.begin(), boundary.end(), -2);
258 std::vector< std::set<int> > NEList(NNodes);
259 for(
size_t i=0;i<NElements;i++){
263 for(
size_t j=0;j<4;j++)
264 NEList[_ENList[i*4+j]].insert(i);
268 for(
size_t i=0;i<NElements;i++){
272 for(
int j=0;j<4;j++){
273 int n1 = _ENList[i*4+(j+1)%4];
274 int n2 = _ENList[i*4+(j+2)%4];
275 int n3 = _ENList[i*4+(j+3)%4];
278 std::set<int> edge_neighbours;
279 set_intersection(NEList[n1].begin(), NEList[n1].end(),
280 NEList[n2].begin(), NEList[n2].end(),
281 inserter(edge_neighbours, edge_neighbours.begin()));
283 std::set<int> neighbours;
284 set_intersection(NEList[n3].begin(), NEList[n3].end(),
285 edge_neighbours.begin(), edge_neighbours.end(),
286 inserter(neighbours, neighbours.begin()));
288 if(neighbours.size()==2){
289 if(*neighbours.begin()==(int)i)
290 boundary[i*4+j] = *neighbours.rbegin();
292 boundary[i*4+j] = *neighbours.begin();
296 boundary[i*4+j] = -1;
301 for(std::vector<int>::iterator it=boundary.begin();it!=boundary.end();++it)
310 assert(boundary.size()==0);
314 std::map< std::set<int>,
int> facet2id;
315 for(
int i=0;i<nfacets;i++){
317 for(
int j=0;j<ndims;j++){
318 facet.insert(facets[i*ndims+j]);
320 assert(facet2id.find(facet)==facet2id.end());
321 facet2id[facet] = ids[i];
326 for(
int i=0;i<NElements;i++){
327 for(
int j=0;j<nloc;j++){
328 if(boundary[i*nloc+j]==1){
330 for(
int k=1;k<nloc;k++){
331 facet.insert(_ENList[i*nloc+(j+k)%nloc]);
333 assert(facet2id.find(facet)!=facet2id.end());
334 boundary[i*nloc+j] = facet2id[facet];
344 for(
size_t i=0; i<nloc; ++i)
345 NEList[n[i]].erase(eid);
347 _ENList[eid*nloc] = -1;
352 int tmp = _ENList[eid*nloc];
353 _ENList[eid*nloc] = _ENList[eid*nloc+1];
354 _ENList[eid*nloc+1] = tmp;
359 return &(_ENList[eid*nloc]);
364 for(
size_t i=0;i<nloc;i++)
365 ele[i] = _ENList[eid*nloc+i];
385 return &(_coords[nid*ndims]);
390 for(
size_t i=0;i<ndims;i++)
391 x[i] = _coords[nid*ndims+i];
397 assert(metric.size()>0);
398 return &(metric[nid*msize]);
403 assert(metric.size()>0);
404 for(
size_t i=0;i<msize;i++)
405 m[i] = metric[nid*msize+i];
411 return (node_owner[nid]!= rank || send_halo.count(nid)>0);
416 return node_owner[nid] == rank;
422 double total_length=0;
426 #pragma omp for schedule(static)
427 for(
int i=0;i<NNodes;i++){
429 for(
typename std::vector<index_t>::const_iterator it=NNList[i].begin();it!=NNList[i].end();++it){
433 total_length += length;
443 MPI_Allreduce(MPI_IN_PLACE, &total_length, 1, MPI_DOUBLE, MPI_SUM, _mpi_comm);
444 MPI_Allreduce(MPI_IN_PLACE, &nedges, 1, MPI_INT, MPI_SUM, _mpi_comm);
448 double mean = total_length/nedges;
457 long double total_length=0;
461 for(
int i=0;i<NElements;i++){
462 if(_ENList[i*nloc] < 0)
465 for(
int j=0;j<3;j++){
466 int n1 = _ENList[i*nloc+(j+1)%3];
467 int n2 = _ENList[i*nloc+(j+2)%3];
469 if(boundary[i*nloc+j]>0 && (std::min(node_owner[n1], node_owner[n2])==rank)){
470 long double dx = (_coords[n1*2 ]-_coords[n2*2 ]);
471 long double dy = (_coords[n1*2+1]-_coords[n2*2+1]);
473 total_length += sqrt(dx*dx+dy*dy);
478 MPI_Allreduce(MPI_IN_PLACE, &total_length, 1, MPI_LONG_DOUBLE, MPI_SUM, _mpi_comm);
481 for(
int i=0;i<NElements;i++){
482 if(_ENList[i*nloc] < 0)
485 for(
int j=0;j<3;j++){
486 if(boundary[i*nloc+j]>0){
487 int n1 = _ENList[i*nloc+(j+1)%3];
488 int n2 = _ENList[i*nloc+(j+2)%3];
490 long double dx = (_coords[n1*2 ]-_coords[n2*2 ]);
491 long double dy = (_coords[n1*2+1]-_coords[n2*2+1]);
493 total_length += sqrt(dx*dx+dy*dy);
501 std::cerr<<
"ERROR: calculate_perimeter() cannot be used for 3D. Use calculate_area() instead if you want the total surface area.\n";
510 long double total_area=0;
514 #pragma omp parallel for reduction(+:total_area)
515 for(
int i=0;i<NElements;i++){
521 if(std::min(node_owner[n[0]], std::min(node_owner[n[1]], node_owner[n[2]]))!=rank)
531 long double dx = (x1[0]-x2[0]);
532 long double dy = (x1[1]-x2[1]);
533 a = sqrt(dx*dx+dy*dy);
537 long double dx = (x1[0]-x3[0]);
538 long double dy = (x1[1]-x3[1]);
539 b = sqrt(dx*dx+dy*dy);
543 long double dx = (x2[0]-x3[0]);
544 long double dy = (x2[1]-x3[1]);
545 c = sqrt(dx*dx+dy*dy);
547 long double s = 0.5*(a+b+c);
549 total_area += sqrt(s*(s-a)*(s-b)*(s-c));
552 MPI_Allreduce(MPI_IN_PLACE, &total_area, 1, MPI_LONG_DOUBLE, MPI_SUM, _mpi_comm);
554 #pragma omp parallel for reduction(+:total_area)
555 for(
int i=0;i<NElements;i++){
567 long double dx = (x1[0]-x2[0]);
568 long double dy = (x1[1]-x2[1]);
569 a = sqrt(dx*dx+dy*dy);
573 long double dx = (x1[0]-x3[0]);
574 long double dy = (x1[1]-x3[1]);
575 b = sqrt(dx*dx+dy*dy);
579 long double dx = (x2[0]-x3[0]);
580 long double dy = (x2[1]-x3[1]);
581 c = sqrt(dx*dx+dy*dy);
583 long double s = 0.5*(a+b+c);
585 total_area += sqrt(s*(s-a)*(s-b)*(s-c));
590 #pragma omp parallel for reduction(+:total_area)
591 for(
int i=0;i<NElements;i++){
596 for(
int j=0;j<4;j++){
597 if(boundary[i*nloc+j]<=0)
605 if(std::min(node_owner[n1], std::min(node_owner[n2], node_owner[n3]))!=rank)
615 long double dx = (x1[0]-x2[0]);
616 long double dy = (x1[1]-x2[1]);
617 long double dz = (x1[2]-x2[2]);
618 a = sqrt(dx*dx+dy*dy+dz*dz);
622 long double dx = (x1[0]-x3[0]);
623 long double dy = (x1[1]-x3[1]);
624 long double dz = (x1[2]-x3[2]);
625 b = sqrt(dx*dx+dy*dy+dz*dz);
629 long double dx = (x2[0]-x3[0]);
630 long double dy = (x2[1]-x3[1]);
631 long double dz = (x2[2]-x3[2]);
632 c = sqrt(dx*dx+dy*dy+dz*dz);
634 long double s = 0.5*(a+b+c);
636 total_area += sqrt(s*(s-a)*(s-b)*(s-c));
640 MPI_Allreduce(MPI_IN_PLACE, &total_area, 1, MPI_LONG_DOUBLE, MPI_SUM, _mpi_comm);
642 #pragma omp parallel for reduction(+:total_area)
643 for(
int i=0;i<NElements;i++){
648 for(
int j=0;j<4;j++){
649 if(boundary[i*nloc+j]<=0)
663 long double dx = (x1[0]-x2[0]);
664 long double dy = (x1[1]-x2[1]);
665 long double dz = (x1[2]-x2[2]);
666 a = sqrt(dx*dx+dy*dy+dz*dz);
670 long double dx = (x1[0]-x3[0]);
671 long double dy = (x1[1]-x3[1]);
672 long double dz = (x1[2]-x3[2]);
673 b = sqrt(dx*dx+dy*dy+dz*dz);
677 long double dx = (x2[0]-x3[0]);
678 long double dy = (x2[1]-x3[1]);
679 long double dz = (x2[2]-x3[2]);
680 c = sqrt(dx*dx+dy*dy+dz*dz);
682 long double s = 0.5*(a+b+c);
684 total_area += sqrt(s*(s-a)*(s-b)*(s-c));
695 long double total_volume=0;
698 std::cerr<<
"ERROR: Cannot calculate volume in 2D\n";
701 #pragma omp parallel for reduction(+:total_volume)
702 for(
int i=0;i<NElements;i++){
708 if(std::min(std::min(node_owner[n[0]], node_owner[n[1]]), std::min(node_owner[n[2]], node_owner[n[3]]))!=rank)
716 long double x01 = (x0[0] - x1[0]);
717 long double x02 = (x0[0] - x2[0]);
718 long double x03 = (x0[0] - x3[0]);
720 long double y01 = (x0[1] - x1[1]);
721 long double y02 = (x0[1] - x2[1]);
722 long double y03 = (x0[1] - x3[1]);
724 long double z01 = (x0[2] - x1[2]);
725 long double z02 = (x0[2] - x2[2]);
726 long double z03 = (x0[2] - x3[2]);
728 total_volume += (-x03*(z02*y01 - z01*y02) + x02*(z03*y01 - z01*y03) - x01*(z03*y02 - z02*y03));
731 MPI_Allreduce(MPI_IN_PLACE, &total_volume, 1, MPI_LONG_DOUBLE, MPI_SUM, _mpi_comm);
733 #pragma omp parallel for reduction(+:total_volume)
734 for(
int i=0;i<NElements;i++){
744 long double x01 = (x0[0] - x1[0]);
745 long double x02 = (x0[0] - x2[0]);
746 long double x03 = (x0[0] - x3[0]);
748 long double y01 = (x0[1] - x1[1]);
749 long double y02 = (x0[1] - x2[1]);
750 long double y03 = (x0[1] - x3[1]);
752 long double z01 = (x0[2] - x1[2]);
753 long double z02 = (x0[2] - x2[2]);
754 long double z03 = (x0[2] - x3[2]);
756 total_volume += (-x03*(z02*y01 - z01*y02) + x02*(z03*y01 - z01*y03) - x01*(z03*y02 - z02*y03));
760 return total_volume/6;
768 #pragma omp parallel reduction(+:sum, nele)
770 #pragma omp for schedule(static)
771 for(
size_t i=0;i<NElements;i++){
791 MPI_Allreduce(MPI_IN_PLACE, &sum, 1, MPI_DOUBLE, MPI_SUM, _mpi_comm);
792 MPI_Allreduce(MPI_IN_PLACE, &nele, 1, MPI_INT, MPI_SUM, _mpi_comm);
795 double mean = sum/nele;
804 #pragma omp for schedule(static)
805 for(
size_t i=0;i<NElements;i++){
819 std::cout<<
"Quality[ele="<<i<<
"] = "<<q<<std::endl;
835 for(
size_t i=0;i<NElements;i++){
845 MPI_Allreduce(MPI_IN_PLACE, &qmin, 1, MPI_DOUBLE, MPI_MIN, _mpi_comm);
853 for(
size_t i=0;i<NElements;i++){
863 MPI_Allreduce(MPI_IN_PLACE, &qmin, 1, MPI_DOUBLE, MPI_MIN, _mpi_comm);
869 MPI_Comm get_mpi_comm()
const{
878 std::set<index_t> patch;
879 for(
typename std::vector<index_t>::const_iterator it=NNList[nid].begin();it!=NNList[nid].end();++it)
880 patch.insert(patch.end(), *it);
888 if(patch.size()<min_patch_size){
889 std::set<index_t> front = patch, new_front;
891 for(
typename std::set<index_t>::const_iterator it=front.begin();it!=front.end();it++){
892 for(
typename std::vector<index_t>::const_iterator jt=NNList[*it].begin();jt!=NNList[*it].end();jt++){
893 if(patch.find(*jt)==patch.end()){
894 new_front.insert(*jt);
900 if(patch.size()>=std::min(min_patch_size, NNodes))
903 front.swap(new_front);
915 m[0] = (metric[nid0*3 ]+metric[nid1*3 ])*0.5;
916 m[1] = (metric[nid0*3+1]+metric[nid1*3+1])*0.5;
917 m[2] = (metric[nid0*3+2]+metric[nid1*3+2])*0.5;
922 m[0] = (metric[nid0*msize ]+metric[nid1*msize ])*0.5;
923 m[1] = (metric[nid0*msize+1]+metric[nid1*msize+1])*0.5;
924 m[2] = (metric[nid0*msize+2]+metric[nid1*msize+2])*0.5;
926 m[3] = (metric[nid0*msize+3]+metric[nid1*msize+3])*0.5;
927 m[4] = (metric[nid0*msize+4]+metric[nid1*msize+4])*0.5;
929 m[5] = (metric[nid0*msize+5]+metric[nid1*msize+5])*0.5;
940 for(
typename std::vector<index_t>::const_iterator it=NNList[i].begin();it!=NNList[i].end();++it){
949 MPI_Allreduce(MPI_IN_PLACE, &L_max, 1, MPI_DOUBLE, MPI_MAX, _mpi_comm);
960 std::vector<index_t> active_vertex_map(NNodes);
962 #pragma omp parallel for schedule(static)
963 for(
size_t i=0;i<NNodes;i++){
964 active_vertex_map[i] = -1;
970 std::vector<index_t> active_element;
972 active_element.reserve(NElements);
974 std::map<index_t, std::set<int> > new_send_set, new_recv_set;
975 for(
size_t e=0;e<NElements;e++){
983 bool local=
false, halo_element=
false;
984 for(
size_t j=0;j<nloc;j++){
985 nid = _ENList[e*nloc+j];
986 if(recv_halo.count(nid)){
996 active_element.push_back(e);
999 for(
size_t j=0;j<nloc;j++){
1000 nid = _ENList[e*nloc+j];
1001 active_vertex_map[nid]=0;
1004 for(
int k=0;k<num_processes;k++){
1005 if(recv_map[k].count(lnn2gnn[nid])){
1006 new_recv_set[k].insert(nid);
1012 for(
size_t j=0;j<nloc;j++){
1013 nid = _ENList[e*nloc+j];
1014 for(std::set<int>::iterator kt=neigh.begin();kt!=neigh.end();++kt){
1015 if(send_map[*kt].count(lnn2gnn[nid]))
1016 new_send_set[*kt].insert(nid);
1023 for(
size_t i=0;i<NNodes;i++){
1024 if(active_vertex_map[i]<0)
1027 active_vertex_map[i] = cnt++;
1031 int active_nelements = active_element.size();
1032 std::map< std::set<index_t>,
index_t > ordered_elements;
1033 for(
int i=0;i<active_nelements;i++){
1034 index_t old_eid = active_element[i];
1035 std::set<index_t> sorted_element;
1036 for(
size_t j=0;j<nloc;j++){
1037 index_t new_nid = active_vertex_map[_ENList[old_eid*nloc+j]];
1038 sorted_element.insert(new_nid);
1040 if(ordered_elements.find(sorted_element)==ordered_elements.end()){
1041 ordered_elements[sorted_element] = old_eid;
1044 <<active_vertex_map[_ENList[old_eid*nloc]]<<
" "
1045 <<active_vertex_map[_ENList[old_eid*nloc+1]]<<
" "
1046 <<active_vertex_map[_ENList[old_eid*nloc+2]]<<std::endl;
1049 std::vector<index_t> element_renumber;
1050 element_renumber.reserve(ordered_elements.size());
1051 for(
typename std::map< std::set<index_t>,
index_t >::const_iterator it=ordered_elements.begin();it!=ordered_elements.end();++it){
1052 element_renumber.push_back(it->second);
1057 NElements = ordered_elements.size();
1059 std::vector<index_t> defrag_ENList(NElements*nloc);
1060 std::vector<real_t> defrag_coords(NNodes*ndims);
1061 std::vector<double> defrag_metric(NNodes*msize);
1062 std::vector<int> defrag_boundary(NElements*nloc);
1065 #pragma omp parallel
1067 #pragma omp for schedule(static)
1068 for(
int i=0;i<(int)NElements;i++){
1069 defrag_ENList[i*nloc] = 0;
1070 defrag_boundary[i*nloc] = 0;
1073 #pragma omp for schedule(static)
1074 for(
int i=0;i<(int)NNodes;i++){
1075 defrag_coords[i*ndims] = 0.0;
1076 defrag_metric[i*msize] = 0.0;
1081 for(
int i=0;i<NElements;i++){
1082 index_t old_eid = element_renumber[i];
1084 for(
size_t j=0;j<nloc;j++){
1085 index_t new_nid = active_vertex_map[_ENList[old_eid*nloc+j]];
1086 assert(new_nid<(
index_t)NNodes);
1087 defrag_ENList[new_eid*nloc+j] = new_nid;
1088 defrag_boundary[new_eid*nloc+j] = boundary[old_eid*nloc+j];
1093 for(
size_t old_nid=0;old_nid<active_vertex_map.size();++old_nid){
1094 index_t new_nid = active_vertex_map[old_nid];
1098 for(
size_t j=0;j<ndims;j++)
1099 defrag_coords[new_nid*ndims+j] = _coords[old_nid*ndims+j];
1100 for(
size_t j=0;j<msize;j++)
1101 defrag_metric[new_nid*msize+j] = metric[old_nid*msize+j];
1104 memcpy(&_ENList[0], &defrag_ENList[0], NElements*nloc*
sizeof(
index_t));
1105 memcpy(&boundary[0], &defrag_boundary[0], NElements*nloc*
sizeof(
int));
1106 memcpy(&_coords[0], &defrag_coords[0], NNodes*ndims*
sizeof(real_t));
1107 memcpy(&metric[0], &defrag_metric[0], NNodes*msize*
sizeof(
double));
1110 if(num_processes>1){
1111 std::vector<index_t> defrag_lnn2gnn(NNodes);
1112 std::vector<int> defrag_owner(NNodes);
1114 for(
size_t old_nid=0;old_nid<active_vertex_map.size();++old_nid){
1115 index_t new_nid = active_vertex_map[old_nid];
1119 defrag_lnn2gnn[new_nid] = lnn2gnn[old_nid];
1120 defrag_owner[new_nid] = node_owner[old_nid];
1123 lnn2gnn.swap(defrag_lnn2gnn);
1124 node_owner.swap(defrag_owner);
1126 for(
int k=0;k<num_processes;k++){
1127 std::vector<int> new_halo;
1128 send_map[k].clear();
1129 for(std::vector<int>::iterator jt=send[k].begin();jt!=send[k].end();++jt){
1130 if(new_send_set[k].count(*jt)){
1131 index_t new_lnn = active_vertex_map[*jt];
1132 new_halo.push_back(new_lnn);
1133 send_map[k][lnn2gnn[new_lnn]] = new_lnn;
1136 send[k].swap(new_halo);
1139 for(
int k=0;k<num_processes;k++){
1140 std::vector<int> new_halo;
1141 recv_map[k].clear();
1142 for(std::vector<int>::iterator jt=recv[k].begin();jt!=recv[k].end();++jt){
1143 if(new_recv_set[k].count(*jt)){
1144 index_t new_lnn = active_vertex_map[*jt];
1145 new_halo.push_back(new_lnn);
1146 recv_map[k][lnn2gnn[new_lnn]] = new_lnn;
1149 recv[k].swap(new_halo);
1154 for(
int k=0;k<num_processes;k++){
1155 for(std::vector<int>::iterator jt=send[k].begin();jt!=send[k].end();++jt){
1156 send_halo.insert(*jt);
1163 for(
int k=0;k<num_processes;k++){
1164 for(std::vector<int>::iterator jt=recv[k].begin();jt!=recv[k].end();++jt){
1165 recv_halo.insert(*jt);
1170 for(
size_t i=0; i<NNodes; ++i){
1176 #pragma omp parallel
1184 std::vector<int> mpi_node_owner(NNodes, rank);
1186 for(
int p=0;p<num_processes;p++)
1187 for(std::vector<int>::const_iterator it=recv[p].begin();it!=recv[p].end();++it){
1188 mpi_node_owner[*it] = p;
1190 std::vector<int> mpi_ele_owner(NElements, rank);
1192 for(
size_t i=0;i<NElements;i++){
1193 if(_ENList[i*nloc]<0)
1195 int owner = mpi_node_owner[_ENList[i*nloc]];
1196 for(
size_t j=1;j<nloc;j++)
1197 owner = std::min(owner, mpi_node_owner[_ENList[i*nloc+j]]);
1198 mpi_ele_owner[i] = owner;
1202 std::vector< std::set<index_t> > local_NEList(NNodes);
1203 std::vector< std::set<index_t> > local_NNList(NNodes);
1204 for(
size_t i=0; i<NElements; i++){
1205 if(_ENList[i*nloc]<0)
1208 for(
size_t j=0;j<nloc;j++){
1209 index_t nid_j = _ENList[i*nloc+j];
1211 local_NEList[nid_j].insert(i);
1212 for(
size_t k=j+1;k<nloc;k++){
1213 index_t nid_k = _ENList[i*nloc+k];
1214 local_NNList[nid_j].insert(nid_k);
1215 local_NNList[nid_k].insert(nid_j);
1220 if(rank==0) std::cout<<
"VERIFY: NNList..................";
1221 if(NNList.size()==0){
1222 if(rank==0) std::cout<<
"empty\n";
1224 bool valid_nnlist=
true;
1225 for(
size_t i=0;i<NNodes;i++){
1226 size_t active_cnt=0;
1227 for(
size_t j=0;j<NNList[i].size();j++){
1231 if(active_cnt!=local_NNList[i].size()){
1234 std::cerr<<std::endl<<
"active_cnt!=local_NNList[i].size() "<<active_cnt<<
", "<<local_NNList[i].size()<<std::endl;
1235 std::cerr<<
"NNList["
1240 if(ndims==3) std::cerr<<
get_coords(i)[2]<<
", ";
1241 std::cerr<<send_halo.count(i)<<
", "<<recv_halo.count(i)<<
")] = ";
1242 for(
size_t j=0;j<NNList[i].size();j++)
1243 std::cerr<<NNList[i][j]<<
"("<<NNList[NNList[i][j]].size()<<
", "
1244 <<send_halo.count(NNList[i][j])<<
", "
1245 <<recv_halo.count(NNList[i][j])<<
") ";
1246 std::cerr<<std::endl;
1247 std::cerr<<
"local_NNList["<<i<<
"] = ";
1248 for(
typename std::set<index_t>::iterator kt=local_NNList[i].begin();kt!=local_NNList[i].end();++kt)
1249 std::cerr<<*kt<<
" ";
1250 std::cerr<<std::endl;
1257 std::cout<<
"pass\n";
1260 std::cout<<
"warn\n";
1266 if(rank==0) std::cout<<
"VERIFY: NEList..................";
1267 std::string result=
"pass\n";
1268 if(NEList.size()==0){
1271 for(
size_t i=0;i<NNodes;i++){
1272 if(local_NEList[i].size()!=NEList[i].size()){
1273 result =
"fail (NEList[i].size()!=local_NEList[i].size())\n";
1277 if(local_NEList[i].size()==0)
1279 if(local_NEList[i]!=NEList[i]){
1280 result =
"fail (local_NEList[i]!=NEList[i])\n";
1286 if(rank==0) std::cout<<result;
1289 long double area=0, min_ele_area=0, max_ele_area=0;
1292 for(;i<NElements;i++){
1294 if((mpi_ele_owner[i]!=rank) || (n[0]<0))
1300 min_ele_area = area;
1301 max_ele_area = area;
1304 for(;i<NElements;i++){
1306 if((mpi_ele_owner[i]!=rank) || (n[0]<0))
1309 long double larea =
property->area(
get_coords(n[0]),
1313 std::cerr<<
"ERROR: Bad element "<<n[0]<<
", "<<n[1]<<
", "<<n[2]<<std::endl;
1317 min_ele_area = std::min(min_ele_area, larea);
1318 max_ele_area = std::max(max_ele_area, larea);
1322 MPI_Allreduce(MPI_IN_PLACE, &area, 1, MPI_LONG_DOUBLE, MPI_SUM, get_mpi_comm());
1323 MPI_Allreduce(MPI_IN_PLACE, &min_ele_area, 1, MPI_LONG_DOUBLE, MPI_MIN, get_mpi_comm());
1324 MPI_Allreduce(MPI_IN_PLACE, &max_ele_area, 1, MPI_LONG_DOUBLE, MPI_MAX, get_mpi_comm());
1328 std::cout<<
"VERIFY: total area ............"<<area<<std::endl;
1329 std::cout<<
"VERIFY: minimum element area...."<<min_ele_area<<std::endl;
1330 std::cout<<
"VERIFY: maximum element area...."<<max_ele_area<<std::endl;
1333 long double volume=0, min_ele_vol=0, max_ele_vol=0;
1335 for(;i<NElements;i++){
1337 if((mpi_ele_owner[i]!=rank) || (n[0]<0))
1344 min_ele_vol = volume;
1345 max_ele_vol = volume;
1348 for(;i<NElements;i++){
1350 if((mpi_ele_owner[i]!=rank) || (n[0]<0))
1353 long double lvolume =
property->volume(
get_coords(n[0]),
1358 min_ele_vol = std::min(min_ele_vol, lvolume);
1359 max_ele_vol = std::max(max_ele_vol, lvolume);
1363 MPI_Allreduce(MPI_IN_PLACE, &volume, 1, MPI_LONG_DOUBLE, MPI_SUM, get_mpi_comm());
1364 MPI_Allreduce(MPI_IN_PLACE, &min_ele_vol, 1, MPI_LONG_DOUBLE, MPI_MIN, get_mpi_comm());
1365 MPI_Allreduce(MPI_IN_PLACE, &max_ele_vol, 1, MPI_LONG_DOUBLE, MPI_MAX, get_mpi_comm());
1369 std::cout<<
"VERIFY: total volume.............."<<volume<<std::endl;
1370 std::cout<<
"VERIFY: minimum element volume...."<<min_ele_vol<<std::endl;
1371 std::cout<<
"VERIFY: maximum element volume...."<<max_ele_vol<<std::endl;
1377 std::cout<<
"VERIFY: mean quality...."<<qmean<<std::endl;
1378 std::cout<<
"VERIFY: min quality...."<<qmin<<std::endl;
1382 int false_cnt = state?0:1;
1383 if(num_processes>1){
1384 MPI_Allreduce(MPI_IN_PLACE, &false_cnt, 1, MPI_INT, MPI_SUM, _mpi_comm);
1386 state = (false_cnt == 0);
1393 std::vector< std::vector<index_t> > *recv_vec) {
1394 int ierr, recv_size, tag = 123456;
1395 std::vector<MPI_Status> status(num_processes);
1396 std::vector<MPI_Request> send_req(num_processes);
1397 std::vector<MPI_Request> recv_req(num_processes);
1399 for (
int proc=0; proc<num_processes; proc++) {
1400 if (proc == rank) {send_req[proc] = MPI_REQUEST_NULL;
continue;}
1402 ierr = MPI_Isend(send_vec[proc].data(), send_vec[proc].size(), MPI_INDEX_T,
1403 proc, tag, _mpi_comm, &send_req[proc]); assert(ierr==0);
1407 for (
int proc=0; proc<num_processes; proc++) {
1408 if (proc == rank) {recv_req[proc] = MPI_REQUEST_NULL;
continue;}
1410 ierr = MPI_Probe(proc, tag, _mpi_comm, &(status[proc])); assert(ierr==0);
1411 ierr = MPI_Get_count(&(status[proc]), MPI_INT, &recv_size); assert(ierr==0);
1412 (*recv_vec)[proc].resize(recv_size);
1413 MPI_Irecv((*recv_vec)[proc].data(), recv_size, MPI_INT, proc,
1414 tag, _mpi_comm, &recv_req[proc]); assert(ierr==0);
1417 MPI_Waitall(num_processes, &(send_req[0]), &(status[0]));
1418 MPI_Waitall(num_processes, &(recv_req[0]), &(status[0]));
1423 template<
typename _real_t,
int _dim>
friend class Smooth;
1424 template<
typename _real_t,
int _dim>
friend class Swapping;
1425 template<
typename _real_t,
int _dim>
friend class Coarsen;
1426 template<
typename _real_t,
int _dim>
friend class Refine;
1431 void _init(
int _NNodes,
int _NElements,
const index_t *globalENList,
1432 const real_t *x,
const real_t *y,
const real_t *z,
1437 NElements = _NElements;
1441 MPI_Comm_size(_mpi_comm, &num_processes);
1442 MPI_Comm_rank(_mpi_comm, &rank);
1446 MPI_INDEX_T = mpi_index_t_wrapper.
mpi_type;
1448 MPI_REAL_T = mpi_real_t_wrapper.
mpi_type;
1465 #ifdef HAVE_BOOST_UNORDERED_MAP_HPP
1466 boost::unordered_map<index_t, index_t> gnn2lnn;
1468 std::map<index_t, index_t> gnn2lnn;
1470 if(num_processes==1){
1471 ENList = globalENList;
1474 assert(lnn2gnn!=NULL);
1475 for(
size_t i=0;i<(size_t)NNodes;i++){
1476 gnn2lnn[lnn2gnn[i]] = i;
1479 std::vector< std::set<index_t> > recv_set(num_processes);
1481 for(
size_t i=0;i<(size_t)NElements*nloc;i++){
1482 index_t gnn = globalENList[i];
1483 for(
int j=0;j<num_processes;j++){
1484 if(gnn<owner_range[j+1]){
1486 recv_set[j].insert(gnn);
1490 localENList[i] = gnn2lnn[gnn];
1492 std::vector<int> recv_size(num_processes);
1493 recv.resize(num_processes);
1494 recv_map.resize(num_processes);
1495 for(
int j=0;j<num_processes;j++){
1496 for(
typename std::set<int>::const_iterator it=recv_set[j].begin();it!=recv_set[j].end();++it){
1497 recv[j].push_back(*it);
1499 recv_size[j] = recv[j].size();
1501 std::vector<int> send_size(num_processes);
1502 MPI_Alltoall(&(recv_size[0]), 1, MPI_INT,
1503 &(send_size[0]), 1, MPI_INT, _mpi_comm);
1506 send.resize(num_processes);
1507 send_map.resize(num_processes);
1508 std::vector<MPI_Request> request(num_processes*2);
1509 for(
int i=0;i<num_processes;i++){
1510 if((i==rank)||(send_size[i]==0)){
1511 request[i] = MPI_REQUEST_NULL;
1513 send[i].resize(send_size[i]);
1514 MPI_Irecv(&(send[i][0]), send_size[i], MPI_INDEX_T, i, 0, _mpi_comm, &(request[i]));
1519 for(
int i=0;i<num_processes;i++){
1520 if((i==rank)||(recv_size[i]==0)){
1521 request[num_processes+i] = MPI_REQUEST_NULL;
1523 MPI_Isend(&(recv[i][0]), recv_size[i], MPI_INDEX_T, i, 0, _mpi_comm, &(request[num_processes+i]));
1527 std::vector<MPI_Status> status(num_processes*2);
1528 MPI_Waitall(num_processes, &(request[0]), &(status[0]));
1529 MPI_Waitall(num_processes, &(request[num_processes]), &(status[num_processes]));
1531 for(
int j=0;j<num_processes;j++){
1532 for(
int k=0;k<recv_size[j];k++){
1535 recv_map[j][gnn] = lnn;
1539 for(
int k=0;k<send_size[j];k++){
1542 send_map[j][gnn] = lnn;
1547 ENList = localENList;
1551 _ENList.resize(NElements*nloc);
1552 _coords.resize(NNodes*ndims);
1553 metric.resize(NNodes*msize);
1554 NNList.resize(NNodes);
1555 NEList.resize(NNodes);
1556 node_owner.resize(NNodes);
1557 this->lnn2gnn.resize(NNodes);
1561 #pragma omp parallel
1563 #pragma omp for schedule(static)
1564 for(
int i=0;i<(int)NElements;i++){
1565 for(
size_t j=0;j<nloc;j++){
1566 _ENList[i*nloc+j] = ENList[i*nloc+j];
1570 #pragma omp for schedule(static)
1571 for(
int i=0;i<(int)NNodes;i++){
1572 _coords[i*2 ] = x[i];
1573 _coords[i*2+1] = y[i];
1576 #pragma omp for schedule(static)
1577 for(
int i=0;i<(int)NNodes;i++){
1578 _coords[i*3 ] = x[i];
1579 _coords[i*3+1] = y[i];
1580 _coords[i*3+2] = z[i];
1584 #pragma omp single nowait
1586 if(num_processes>1){
1588 for(
int j=0;j<num_processes;j++){
1589 for(
size_t k=0;k<recv[j].size();k++){
1590 recv_halo.insert(recv[j][k]);
1592 for(
size_t k=0;k<send[j].size();k++){
1593 send_halo.insert(send[j][k]);
1617 #pragma omp for schedule(static)
1618 for(
size_t i=1;i<(size_t)NElements;i++){
1622 double volarea =
property->area(
get_coords(n[0]),
1630 #pragma omp for schedule(static)
1631 for(
size_t i=1;i<(size_t)NElements;i++){
1635 double volarea =
property->volume(
get_coords(n[0]),
1649 create_global_node_numbering();
1653 void create_adjacency(){
1656 #pragma omp for schedule(static)
1657 for(
size_t i=0;i<NNodes;i++){
1662 for(
size_t i=0; i<NElements; i++){
1663 if(_ENList[i*nloc]<0)
1666 for(
size_t j=0;j<nloc;j++){
1667 index_t nid_j = _ENList[i*nloc+j];
1668 if((nid_j%nthreads)==tid){
1669 NEList[nid_j].insert(NEList[nid_j].end(), i);
1670 for(
size_t k=0;k<nloc;k++){
1672 index_t nid_k = _ENList[i*nloc+k];
1673 NNList[nid_j].push_back(nid_k);
1683 #pragma omp for schedule(static)
1684 for(
size_t i=0;i<NNodes;i++){
1685 if(NNList[i].empty())
1688 std::vector<index_t> *nnset =
new std::vector<index_t>();
1690 std::sort(NNList[i].begin(),NNList[i].end());
1691 std::unique_copy(NNList[i].begin(), NNList[i].end(), std::inserter(*nnset, nnset->begin()));
1693 NNList[i].swap(*nnset);
1699 std::set<index_t> recv_halo_temp, send_halo_temp;
1703 for(
int i=0;i<num_processes;i++){
1704 if(recv[i].size()==0)
1707 std::vector<index_t> recv_temp;
1708 #ifdef HAVE_BOOST_UNORDERED_MAP_HPP
1709 boost::unordered_map<index_t, index_t> recv_map_temp;
1711 std::map<index_t, index_t> recv_map_temp;
1714 for(
typename std::vector<index_t>::const_iterator vit = recv[i].begin(); vit != recv[i].end(); ++vit){
1717 std::set<index_t> NEList_copy = NEList[*vit];
1718 for(
typename std::set<index_t>::const_iterator eit = NEList_copy.begin(); eit != NEList_copy.end(); ++eit){
1720 std::vector<index_t> n(nloc);
1726 bool to_be_deleted =
true;
1727 for(
size_t j=0; j<nloc; ++j)
1729 to_be_deleted =
false;
1737 for(
size_t j=0; j<nloc; ++j){
1738 for(
size_t k=j+1; k<nloc; ++k){
1739 std::set<index_t> intersection;
1740 std::set_intersection(NEList[n[j]].begin(), NEList[n[j]].end(), NEList[n[k]].begin(), NEList[n[k]].end(),
1741 std::inserter(intersection, intersection.begin()));
1745 if(intersection.empty()){
1746 typename std::vector<index_t>::iterator it;
1747 it = std::find(NNList[n[j]].begin(), NNList[n[j]].end(), n[k]);
1748 NNList[n[j]].erase(it);
1749 it = std::find(NNList[n[k]].begin(), NNList[n[k]].end(), n[j]);
1750 NNList[n[k]].erase(it);
1758 if(NEList[*vit].empty()){
1760 for(
typename std::vector<index_t>::const_iterator neigh_it = NNList[*vit].begin(); neigh_it != NNList[*vit].end(); ++neigh_it){
1761 typename std::vector<index_t>::iterator it = std::find(NNList[*neigh_it].begin(), NNList[*neigh_it].end(), *vit);
1762 NNList[*neigh_it].erase(it);
1768 recv_temp.push_back(*vit);
1769 recv_map_temp[lnn2gnn[*vit]] = *vit;
1770 recv_halo_temp.insert(*vit);
1774 recv[i].swap(recv_temp);
1775 recv_map[i].swap(recv_map_temp);
1779 recv_halo.swap(recv_halo_temp);
1784 for(
int i=0;i<num_processes;i++){
1785 if(send[i].size()==0)
1788 std::vector<index_t> send_temp;
1789 #ifdef HAVE_BOOST_UNORDERED_MAP_HPP
1790 boost::unordered_map<index_t, index_t> send_map_temp;
1792 std::map<index_t, index_t> send_map_temp;
1795 for(
typename std::vector<index_t>::const_iterator vit = send[i].begin(); vit != send[i].end(); ++vit){
1796 bool to_be_deleted =
true;
1797 for(
typename std::vector<index_t>::const_iterator neigh_it = NNList[*vit].begin(); neigh_it != NNList[*vit].end(); ++neigh_it)
1798 if(node_owner[*neigh_it] == i){
1799 to_be_deleted =
false;
1804 send_temp.push_back(*vit);
1805 send_map_temp[lnn2gnn[*vit]] = *vit;
1806 send_halo_temp.insert(*vit);
1810 send[i].swap(send_temp);
1811 send_map[i].swap(send_map_temp);
1815 send_halo.swap(send_halo_temp);
1818 void create_global_node_numbering(){
1819 if(num_processes>1){
1823 int NPNodes = NNodes - recv_halo.size();
1824 MPI_Scan(&NPNodes, &gnn_offset, 1, MPI_INT, MPI_SUM, get_mpi_comm());
1825 gnn_offset-=NPNodes;
1829 if(recv_halo.count(i)){
1832 lnn2gnn[i] = gnn_offset++;
1833 node_owner[i] = rank;
1838 halo_update<int, 1>(_mpi_comm, send, recv, lnn2gnn);
1841 for(
int i=0;i<num_processes;i++){
1842 for(std::vector<int>::const_iterator it=recv[i].begin();it!=recv[i].end();++it){
1843 node_owner[*it] = i;
1848 memset(&node_owner[0], 0, NNodes*
sizeof(
int));
1854 void create_gappy_global_numbering(
size_t pNElements){
1858 index_t gnn_reserve = 5*pNElements;
1859 MPI_Scan(&gnn_reserve, &gnn_offset, 1, MPI_INDEX_T, MPI_SUM, _mpi_comm);
1860 gnn_offset -= gnn_reserve;
1862 for(
size_t i=0; i<NNodes; ++i){
1863 if(node_owner[i] == rank)
1864 lnn2gnn[i] = gnn_offset+i;
1869 halo_update<int, 1>(_mpi_comm, send, recv, lnn2gnn);
1871 for(
int i=0;i<num_processes;i++){
1872 send_map[i].clear();
1873 for(std::vector<int>::const_iterator it=send[i].begin();it!=send[i].end();++it){
1874 assert(node_owner[*it]==rank);
1875 send_map[i][lnn2gnn[*it]] = *it;
1878 recv_map[i].clear();
1879 for(std::vector<int>::const_iterator it=recv[i].begin();it!=recv[i].end();++it){
1880 node_owner[*it] = i;
1881 recv_map[i][lnn2gnn[*it]] = *it;
1887 void update_gappy_global_numbering(std::vector<size_t>& recv_cnt, std::vector<size_t>& send_cnt){
1890 std::vector<MPI_Request> request(num_processes*2);
1893 std::vector< std::vector<index_t> > recv_buff(num_processes);
1894 for(
int i=0;i<num_processes;i++){
1896 request[i] = MPI_REQUEST_NULL;
1898 recv_buff[i].resize(recv_cnt[i]);
1899 MPI_Irecv(&(recv_buff[i][0]), recv_buff[i].size(), MPI_INDEX_T, i, 0, _mpi_comm, &(request[i]));
1904 std::vector< std::vector<index_t> > send_buff(num_processes);
1905 for(
int i=0;i<num_processes;i++){
1907 request[num_processes+i] = MPI_REQUEST_NULL;
1909 for(
typename std::vector<index_t>::const_iterator it=send[i].end()-send_cnt[i];it!=send[i].end();++it)
1910 send_buff[i].push_back(lnn2gnn[*it]);
1912 MPI_Isend(&(send_buff[i][0]), send_buff[i].size(), MPI_INDEX_T, i, 0, _mpi_comm, &(request[num_processes+i]));
1916 std::vector<MPI_Status> status(num_processes*2);
1917 MPI_Waitall(num_processes, &(request[0]), &(status[0]));
1918 MPI_Waitall(num_processes, &(request[num_processes]), &(status[num_processes]));
1920 for(
int i=0;i<num_processes;i++){
1922 for(
typename std::vector<index_t>::const_iterator it=recv[i].end()-recv_cnt[i];it!=recv[i].end();++it, ++k)
1923 lnn2gnn[*it] = recv_buff[i][k];
1928 size_t ndims, nloc, msize;
1929 std::vector<index_t> _ENList;
1930 std::vector<real_t> _coords;
1932 size_t NNodes, NElements;
1938 std::vector< std::set<index_t> > NEList;
1939 std::vector< std::vector<index_t> > NNList;
1944 std::vector<double> metric;
1947 int rank, num_processes, nthreads;
1948 std::vector< std::vector<index_t> > send, recv;
1949 #ifdef HAVE_BOOST_UNORDERED_MAP_HPP
1950 std::vector< boost::unordered_map<index_t, index_t> > send_map, recv_map;
1952 std::vector< std::map<index_t, index_t> > send_map, recv_map;
1954 std::set<index_t> send_halo, recv_halo;
1955 std::vector<int> node_owner;
1956 std::vector<index_t> lnn2gnn;
1963 MPI_Datatype MPI_INDEX_T;
1964 MPI_Datatype MPI_REAL_T;
void get_coords(index_t nid, real_t *x) const
Return copy of the coordinate.
void get_element(size_t eid, index_t *ele) const
Return copy of element-node list.
void get_metric(index_t nid, double *m) const
Return copy of metric.
const real_t * get_coords(index_t nid) const
Return positions vector.
Performs 2D mesh coarsening.
~Mesh()
Default destructor.
static double length2d(const real_t x0[], const real_t x1[], const double m[])
double calculate_volume()
Calculate volume.
static double length3d(const real_t x0[], const real_t x1[], const double m[])
bool verify() const
This is used to verify that the mesh and its metadata is correct.
Calculates a number of element properties.
void invert_element(size_t eid)
Flip orientation of element.
double get_qmean() const
Get the element mean quality in metric space.
Performs edge/face swapping.
double get_qmin() const
Get the element minimum quality in metric space.
real_t calc_edge_length(index_t nid0, index_t nid1) const
Calculates the edge lengths in metric space.
double calculate_perimeter()
Calculate perimeter.
void erase_element(const index_t eid)
Erase an element.
Constructs metric tensor field which encodes anisotropic edge size information.
size_t get_number_elements() const
Return the number of elements in the mesh.
void print_quality() const
Print out the qualities. Useful if you want to plot a histogram of element qualities.
real_t maximal_edge_length() const
index_t append_vertex(const real_t *x, const double *m)
Add a new vertex.
double get_qmin_3d() const
double get_qmin_2d() const
double calculate_area()
Calculate area.
double get_lmean()
Get the mean edge length metric space.
const MPI_Datatype mpi_type
Mesh(int NNodes, int NElements, const index_t *ENList, const real_t *x, const real_t *y, const real_t *z)
const double * get_metric(index_t nid) const
Return metric at that vertex.
size_t get_number_dimensions() const
Return the number of spatial dimensions.
void erase_vertex(const index_t nid)
Erase a vertex.
Mesh(int NNodes, int NElements, const index_t *ENList, const real_t *x, const real_t *y)
std::set< index_t > get_node_patch(index_t nid) const
Return the node id's connected to the specified node_id.
size_t get_number_nodes() const
Return the number of nodes in the mesh.
Applies Laplacian smoothen in metric space.
std::set< index_t > get_node_patch(index_t nid, size_t min_patch_size)
Grow a node patch around node id's until it reaches a minimum size.
int pragmatic_thread_id()
void set_boundary(int nfacets, const int *facets, const int *ids)
index_t append_element(const index_t *n)
Add a new element.
bool is_halo_node(index_t nid) const
Returns true if the node is in any of the partitioned elements.
bool is_owned_node(index_t nid) const
Returns true if the node is assigned to the local partition.
void send_all_to_all(std::vector< std::vector< index_t > > send_vec, std::vector< std::vector< index_t > > *recv_vec)
const index_t * get_element(size_t eid) const
Return a pointer to the element-node list.
Performs 2D mesh refinement.
index_t append_element(const index_t *n, const int *b)
Add a new element and boundary.