690 assert(ELEMENT_DIM == 1);
695 EXCEPTION(
"There aren't enough nodes to make parallelisation worthwhile");
699 if (mPartitioning == DistributedTetrahedralMeshPartitionType::GEOMETRIC)
703 EXCEPTION(
"Space region not set for GEOMETRIC partition of DistributedTetrahedralMesh");
721 this->ConstructFromMeshReader(mesh_reader);
726 mPartitioning=DistributedTetrahedralMeshPartitionType::DUMB;
727 mTotalNumNodes=width+1;
728 mTotalNumBoundaryElements=2u;
729 mTotalNumElements=width;
732 assert(!this->mpDistributedVectorFactory);
734 if (this->mpDistributedVectorFactory->GetLocalOwnership() == 0)
745 bool am_top_most = (this->mpDistributedVectorFactory->GetHigh() == mTotalNumNodes);
747 unsigned lo_node=this->mpDistributedVectorFactory->GetLow();
748 unsigned hi_node=this->mpDistributedVectorFactory->GetHigh();
760 for (
unsigned node_index=lo_node; node_index<hi_node; node_index++)
764 if (node_index<this->mpDistributedVectorFactory->GetLow() ||
765 node_index==this->mpDistributedVectorFactory->GetHigh() )
768 RegisterHaloNode(node_index);
769 mHaloNodes.push_back(p_node);
773 RegisterNode(node_index);
774 this->mNodes.push_back(p_node);
780 this->mBoundaryNodes.push_back(p_node);
781 RegisterBoundaryElement(0);
784 if (node_index==width)
786 this->mBoundaryNodes.push_back(p_node);
787 RegisterBoundaryElement(1);
791 if (node_index>lo_node)
793 std::vector<Node<SPACE_DIM>*> nodes;
794 nodes.push_back(p_old_node);
795 nodes.push_back(p_node);
796 RegisterElement(node_index-1);
808 assert(SPACE_DIM == 2);
809 assert(ELEMENT_DIM == 2);
813 EXCEPTION(
"There aren't enough nodes to make parallelisation worthwhile");
817 if (mPartitioning == DistributedTetrahedralMeshPartitionType::GEOMETRIC)
821 EXCEPTION(
"Space region not set for GEOMETRIC partition of DistributedTetrahedralMesh");
839 this->ConstructFromMeshReader(mesh_reader);
844 mPartitioning=DistributedTetrahedralMeshPartitionType::DUMB;
846 mTotalNumNodes=(width+1)*(height+1);
847 mTotalNumBoundaryElements=(width+height)*2;
848 mTotalNumElements=width*height*2;
852 unsigned lo_y = y_partition.
GetLow();
853 unsigned hi_y = y_partition.
GetHigh();
855 assert(!this->mpDistributedVectorFactory);
857 if (this->mpDistributedVectorFactory->GetLocalOwnership() == 0)
868 bool am_top_most = (this->mpDistributedVectorFactory->GetHigh() == mTotalNumNodes);
883 for (
unsigned j=lo_y; j<hi_y; j++)
885 for (
unsigned i=0; i<width+1; i++)
887 bool is_boundary=
false;
888 if (i==0 || j==0 || i==width || j==height)
892 unsigned global_node_index=((width+1)*(j) + i);
897 RegisterHaloNode(global_node_index);
898 mHaloNodes.push_back(p_node);
902 RegisterNode(global_node_index);
903 this->mNodes.push_back(p_node);
907 this->mBoundaryNodes.push_back(p_node);
913 unsigned belem_index;
917 for (
unsigned i=0; i<width; i++)
919 std::vector<Node<SPACE_DIM>*> nodes;
920 nodes.push_back(GetNodeOrHaloNode( height*(width+1)+i+1 ));
921 nodes.push_back(GetNodeOrHaloNode( height*(width+1)+i ));
923 RegisterBoundaryElement(belem_index);
929 for (
unsigned j=lo_y+1; j<hi_y; j++)
931 std::vector<Node<SPACE_DIM>*> nodes;
932 nodes.push_back(GetNodeOrHaloNode( (width+1)*j-1 ));
933 nodes.push_back(GetNodeOrHaloNode( (width+1)*(j+1)-1 ));
934 belem_index=width+j-1;
935 RegisterBoundaryElement(belem_index);
942 for (
unsigned i=0; i<width; i++)
944 std::vector<Node<SPACE_DIM>*> nodes;
945 nodes.push_back(GetNodeOrHaloNode( i ));
946 nodes.push_back(GetNodeOrHaloNode( i+1 ));
947 belem_index=width+height+i;
948 RegisterBoundaryElement(belem_index);
954 for (
unsigned j=lo_y; j<hi_y-1; j++)
956 std::vector<Node<SPACE_DIM>*> nodes;
957 nodes.push_back(GetNodeOrHaloNode( (width+1)*(j+1) ));
958 nodes.push_back(GetNodeOrHaloNode( (width+1)*(j) ));
959 belem_index=2*width+height+j;
960 RegisterBoundaryElement(belem_index);
967 for (
unsigned j=lo_y; j<hi_y-1; j++)
969 for (
unsigned i=0; i<width; i++)
971 unsigned parity=(i+(height-j))%2;
972 unsigned nw=(j+1)*(width+1)+i;
973 unsigned sw=(j)*(width+1)+i;
974 std::vector<Node<SPACE_DIM>*> upper_nodes;
975 upper_nodes.push_back(GetNodeOrHaloNode( nw ));
976 upper_nodes.push_back(GetNodeOrHaloNode( nw+1 ));
977 if (stagger==
false || parity == 1)
979 upper_nodes.push_back(GetNodeOrHaloNode( sw+1 ));
983 upper_nodes.push_back(GetNodeOrHaloNode( sw ));
985 elem_index=2*(j*width+i);
986 RegisterElement(elem_index);
988 std::vector<Node<SPACE_DIM>*> lower_nodes;
989 lower_nodes.push_back(GetNodeOrHaloNode( sw+1 ));
990 lower_nodes.push_back(GetNodeOrHaloNode( sw ));
991 if (stagger==
false ||parity == 1)
993 lower_nodes.push_back(GetNodeOrHaloNode( nw ));
997 lower_nodes.push_back(GetNodeOrHaloNode( nw+1 ));
1000 RegisterElement(elem_index);
1013 assert(SPACE_DIM == 3);
1014 assert(ELEMENT_DIM == 3);
1018 EXCEPTION(
"There aren't enough nodes to make parallelisation worthwhile");
1022 if (mPartitioning == DistributedTetrahedralMeshPartitionType::GEOMETRIC)
1026 EXCEPTION(
"Space region not set for GEOMETRIC partition of DistributedTetrahedralMesh");
1044 this->ConstructFromMeshReader(mesh_reader);
1049 mPartitioning=DistributedTetrahedralMeshPartitionType::DUMB;
1051 mTotalNumNodes=(width+1)*(height+1)*(depth+1);
1052 mTotalNumBoundaryElements=((width*height)+(width*depth)+(height*depth))*4;
1053 mTotalNumElements=width*height*depth*6;
1057 unsigned lo_z = z_partition.
GetLow();
1058 unsigned hi_z = z_partition.
GetHigh();
1061 assert(!this->mpDistributedVectorFactory);
1063 if (this->mpDistributedVectorFactory->GetLocalOwnership() == 0)
1074 bool am_top_most = (this->mpDistributedVectorFactory->GetHigh() == mTotalNumNodes);
1088 unsigned global_node_index;
1089 for (
unsigned k=lo_z; k<hi_z; k++)
1091 for (
unsigned j=0; j<height+1; j++)
1093 for (
unsigned i=0; i<width+1; i++)
1095 bool is_boundary =
false;
1096 if (i==0 || j==0 || k==0 || i==width || j==height || k==depth)
1100 global_node_index = (k*(height+1)+j)*(width+1)+i;
1107 RegisterHaloNode(global_node_index);
1108 mHaloNodes.push_back(p_node);
1112 RegisterNode(global_node_index);
1113 this->mNodes.push_back(p_node);
1118 this->mBoundaryNodes.push_back(p_node);
1126 unsigned element_nodes[6][4] = {{0, 1, 5, 7}, {0, 1, 3, 7},
1127 {0, 2, 3, 7}, {0, 2, 6, 7},
1128 {0, 4, 6, 7}, {0, 4, 5, 7}};
1129 std::vector<Node<SPACE_DIM>*> tetrahedra_nodes;
1131 for (
unsigned k=lo_z; k<hi_z-1; k++)
1133 unsigned belem_index = 0;
1137 belem_index = 2*(height*width+k*2*(height+width));
1140 for (
unsigned j=0; j<height; j++)
1142 for (
unsigned i=0; i<width; i++)
1145 unsigned global_node_indices[8];
1146 unsigned local_node_index = 0;
1148 for (
unsigned z = 0; z < 2; z++)
1150 for (
unsigned y = 0; y < 2; y++)
1152 for (
unsigned x = 0; x < 2; x++)
1154 global_node_indices[local_node_index] = i+x+(width+1)*(j+y+(height+1)*(k+z));
1161 for (
unsigned m = 0; m < 6; m++)
1165 tetrahedra_nodes.clear();
1167 for (
unsigned n = 0; n < 4; n++)
1169 tetrahedra_nodes.push_back(GetNodeOrHaloNode( global_node_indices[element_nodes[m][n]] ));
1171 unsigned elem_index = 6 * ((k*height+j)*width+i)+m;
1172 RegisterElement(elem_index);
1177 std::vector<Node<SPACE_DIM>*> triangle_nodes;
1181 triangle_nodes.clear();
1182 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[0] ));
1183 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[2] ));
1184 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[6] ));
1185 RegisterBoundaryElement(belem_index);
1187 triangle_nodes.clear();
1188 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[0] ));
1189 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[6] ));
1190 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[4] ));
1191 RegisterBoundaryElement(belem_index);
1196 triangle_nodes.clear();
1197 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[1] ));
1198 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[5] ));
1199 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[7] ));
1200 RegisterBoundaryElement(belem_index);
1202 triangle_nodes.clear();
1203 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[1] ));
1204 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[7] ));
1205 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[3] ));
1206 RegisterBoundaryElement(belem_index);
1211 triangle_nodes.clear();
1212 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[0] ));
1213 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[5] ));
1214 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[1] ));
1215 RegisterBoundaryElement(belem_index);
1217 triangle_nodes.clear();
1218 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[0] ));
1219 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[4] ));
1220 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[5] ));
1221 RegisterBoundaryElement(belem_index);
1226 triangle_nodes.clear();
1227 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[2] ));
1228 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[3] ));
1229 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[7] ));
1230 RegisterBoundaryElement(belem_index);
1232 triangle_nodes.clear();
1233 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[2] ));
1234 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[7] ));
1235 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[6] ));
1236 RegisterBoundaryElement(belem_index);
1241 triangle_nodes.clear();
1242 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[0] ));
1243 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[3] ));
1244 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[2] ));
1245 RegisterBoundaryElement(belem_index);
1247 triangle_nodes.clear();
1248 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[0] ));
1249 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[1] ));
1250 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[3] ));
1251 RegisterBoundaryElement(belem_index);
1256 triangle_nodes.clear();
1257 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[4] ));
1258 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[7] ));
1259 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[5] ));
1260 RegisterBoundaryElement(belem_index);
1262 triangle_nodes.clear();
1263 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[4] ));
1264 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[6] ));
1265 triangle_nodes.push_back(GetNodeOrHaloNode( global_node_indices[7] ));
1266 RegisterBoundaryElement(belem_index);
1301 std::set<unsigned>& rElementsOwned,
1302 std::set<unsigned>& rNodesOwned,
1303 std::set<unsigned>& rHaloNodesOwned,
1304 std::vector<unsigned>& rProcessorsOffset)
1307 assert(ELEMENT_DIM==2 || ELEMENT_DIM==3);
1310 const unsigned num_nodes = rMeshReader.
GetNumNodes();
1317 boost::scoped_array<idx_t> element_distribution(
new idx_t[num_procs+1]);
1318 boost::scoped_array<int> element_counts(
new int[num_procs]);
1320 element_distribution[0] = 0;
1322 for (
unsigned proc_index=1; proc_index<num_procs; proc_index++)
1324 element_distribution[proc_index] = element_distribution[proc_index-1] + num_elements/num_procs;
1325 element_counts[proc_index-1] = element_distribution[proc_index] - element_distribution[proc_index-1];
1328 element_distribution[num_procs] = num_elements;
1329 element_counts[num_procs-1] = element_distribution[num_procs] - element_distribution[num_procs-1];
1334 idx_t first_local_element = element_distribution[local_proc_index];
1335 idx_t last_plus_one_element = element_distribution[local_proc_index+1];
1336 idx_t num_local_elements = last_plus_one_element - first_local_element;
1338 boost::scoped_array<idx_t> eind(
new idx_t[num_local_elements*(ELEMENT_DIM+1)]);
1339 boost::scoped_array<idx_t> eptr(
new idx_t[num_local_elements+1]);
1349 for (idx_t element_index = 0; element_index < first_local_element; element_index++)
1355#ifdef CHASTE_HOMEMADE_MESH_TO_DUAL
1358 Mat element_node_matrix;
1359 PetscTools::SetupMat(element_node_matrix, num_elements, num_nodes, ELEMENT_DIM+1, num_local_elements);
1362 unsigned counter = 0;
1363 for (idx_t element_index = 0; element_index < num_local_elements; element_index++)
1369 eptr[element_index] = counter;
1370 for (
unsigned i=0; i<ELEMENT_DIM+1; i++)
1372#ifdef CHASTE_HOMEMADE_MESH_TO_DUAL
1379 eptr[num_local_elements] = counter;
1381 rMeshReader.
Reset();
1384 MPI_Comm communicator = PETSC_COMM_WORLD;
1390#ifdef CHASTE_HOMEMADE_MESH_TO_DUAL
1392 std::vector<idx_t> my_xadj;
1393 std::vector<idx_t> my_adjncy;
1406 Mat node_element_matrix;
1407 MatTranspose(element_node_matrix, MAT_INITIAL_MATRIX, &node_element_matrix);
1408 Mat element_element_matrix;
1409 MatMatMult(element_node_matrix, node_element_matrix, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &element_element_matrix);
1410 my_xadj.push_back(0);
1413 const PetscScalar *vals;
1414 for (
PetscInt el_index=first_local_element; el_index<last_plus_one_element; el_index++)
1416 MatGetRow(element_element_matrix, el_index, &ncols, &cols, &vals);
1419 if (std::lround(vals[i])==ELEMENT_DIM)
1422 my_adjncy.push_back(cols[i]);
1425 MatRestoreRow(element_element_matrix, el_index, &ncols, &cols, NULL);
1427 my_xadj.push_back(my_adjncy.size());
1429 MatDestroy(&element_node_matrix);
1430 MatDestroy(&node_element_matrix);
1431 MatDestroy(&element_element_matrix);
1432 xadj = my_xadj.data();
1433 adjncy = my_adjncy.data();
1440 idx_t ncommonnodes = 3;
1441 if (ELEMENT_DIM == 2)
1445 ParMETIS_V3_Mesh2Dual(element_distribution.get(), eptr.get(), eind.get(),
1446 &numflag, &ncommonnodes, &xadj, &adjncy, &communicator);
1453 idx_t weight_flag = 0;
1454 idx_t n_constraints = 1;
1459 boost::scoped_array<real_t> tpwgts(
new real_t[n_subdomains]);
1460 real_t ubvec_value = (real_t)1.05;
1463 tpwgts[proc] = ((real_t)1.0)/n_subdomains;
1465 boost::scoped_array<idx_t> local_partition(
new idx_t[num_local_elements]);
1481 ParMETIS_V3_PartKway(element_distribution.get(), xadj, adjncy,
nullptr,
nullptr, &weight_flag, &numflag,
1482 &n_constraints, &n_subdomains, tpwgts.get(), &ubvec_value,
1483 options, &edgecut, local_partition.get(), &communicator);
1487 boost::scoped_array<idx_t> global_element_partition(
new idx_t[num_elements]);
1490 MPI_Datatype mpi_idx_t = MPI_LONG_LONG_INT;
1491 if (
sizeof(idx_t) ==
sizeof(
int))
1493 mpi_idx_t = MPI_INT;
1495 boost::scoped_array<int> int_element_distribution(
new int[num_procs+1]);
1496 for (
unsigned i=0; i<num_procs+1; ++i)
1498 int_element_distribution[i] = element_distribution[i];
1500 MPI_Allgatherv(local_partition.get(), num_local_elements, mpi_idx_t,
1501 global_element_partition.get(), element_counts.get(), int_element_distribution.get(), mpi_idx_t, PETSC_COMM_WORLD);
1503 local_partition.reset();
1505 for (
unsigned elem_index=0; elem_index<num_elements; elem_index++)
1507 if ((
unsigned) global_element_partition[elem_index] == local_proc_index)
1509 rElementsOwned.insert(elem_index);
1513 rMeshReader.
Reset();
1514#ifdef CHASTE_HOMEMADE_MESH_TO_DUAL
1524 std::vector<unsigned> global_node_partition(num_nodes, UNASSIGNED_NODE);
1526 assert(rProcessorsOffset.size() == 0);
1552 for (
unsigned element_number = 0; element_number < mTotalNumElements; element_number++)
1554 unsigned element_owner = global_element_partition[element_number];
1560 for (std::vector<unsigned>::const_iterator node_it = element_data.
NodeIndices.begin();
1568 if (global_node_partition[*node_it] == UNASSIGNED_NODE)
1570 if (element_owner == local_proc_index)
1572 rNodesOwned.insert(*node_it);
1575 global_node_partition[*node_it] = element_owner;
1582 rProcessorsOffset[proc]++;
1587 if (element_owner == local_proc_index)
1590 if (global_node_partition[*node_it] != local_proc_index)
1592 rHaloNodesOwned.insert(*node_it);
1612 rElementsOwned.clear();
1613 rMeshReader.
Reset();
1614 for (
unsigned element_number = 0; element_number < mTotalNumElements; element_number++)
1618 bool element_owned =
false;
1619 std::set<unsigned> temp_halo_nodes;
1621 for (std::vector<unsigned>::const_iterator node_it = element_data.
NodeIndices.begin();
1625 if (rNodesOwned.find(*node_it) != rNodesOwned.end())
1627 element_owned =
true;
1628 rElementsOwned.insert(element_number);
1632 temp_halo_nodes.insert(*node_it);
1638 rHaloNodesOwned.insert(temp_halo_nodes.begin(), temp_halo_nodes.end());
1642 rMeshReader.
Reset();
1649 this->mNodePermutation.resize(this->GetNumNodes());
1651 for (
unsigned node_index=0; node_index<this->GetNumNodes(); node_index++)
1653 unsigned partition = global_node_partition[node_index];
1654 assert(partition != UNASSIGNED_NODE);
1656 this->mNodePermutation[node_index] = rProcessorsOffset[partition] + local_index[partition];
1658 local_index[partition]++;