PeriDEM 0.2.0
PeriDEM -- Peridynamics-based high-fidelity model for granular media
Loading...
Searching...
No Matches
testMeshPartitioningLib.cpp
Go to the documentation of this file.
1/*
2 * -------------------------------------------
3 * Copyright (c) 2021 - 2024 Prashant K. Jha
4 * -------------------------------------------
5 * PeriDEM https://github.com/prashjha/PeriDEM
6 *
7 * Distributed under the Boost Software License, Version 1.0. (See accompanying
8 * file LICENSE)
9 */
10
12#include "fe/mesh.h"
13#include "fe/meshPartitioning.h"
14#include "fe/meshUtil.h"
15#include "util/point.h"
16#include "util/methods.h" // declares std::chrono and defines timeDiff()
17#include "util/io.h"
18#include "rw/writer.h"
20
21#include <metis.h>
22#include <fmt/format.h>
23#include <algorithm>
24#include <fstream>
25#include <string>
26
27
28namespace {
29
30 // source - https://code.vt.edu/ARC/examples/-/blob/master/metis/metis_test.c?ref_type=heads
32 // The number of vertices.
33 idx_t nvtxs = 6;
34
35 // Number of balancing constraints, which must be at least 1.
36 idx_t ncon = 1;
37
38 // Pointers to initial entries in adjacency array. size of array is nvtxs + 1
39 idx_t xadj[7] = {0, 2, 5, 7, 9, 12, 14};
40
41 // Adjacent vertices in consecutive index order.
42 int nedges = 7;
43 idx_t adjncy[14] = {1, 3, 0, 4, 2, 1, 5, 0, 4, 3, 1, 5, 4, 2};
44
45 // The number of parts requested for the partition.
46 idx_t nParts = 3;
47
48 // On return, the edge cut volume of the partitioning solution.
49 idx_t objval;
50
51 // On return, the partition vector for the graph.
52 idx_t part[6];
53
54 printf("\n");
55 printf("partGraphRecursiveTest:\n");
56 printf(" METIS_PartGraphRecursive partitions a graph into K parts\n");
57 printf(" using multilevel recursive bisection.\n");
58
59 int ret = METIS_PartGraphRecursive(&nvtxs, &ncon, xadj, adjncy, NULL, NULL,
60 NULL, &nParts, NULL, NULL, NULL, &objval, part);
61
62 printf("\n");
63 printf(" Return code = %d\n", ret);
64 printf(" Edge cuts for partition = %d\n", (int) objval);
65
66 printf("\n");
67 printf(" Partition vector:\n");
68 printf("\n");
69 printf(" Node Part\n");
70 printf("\n");
71 for (unsigned part_i = 0; part_i < nvtxs; part_i++) {
72 printf(" %d %d\n", part_i, (int) part[part_i]);
73 }
74
75 }
76
77 // source - https://code.vt.edu/ARC/examples/-/blob/master/metis/metis_test.c?ref_type=heads
79
80 // The number of vertices.
81 idx_t nvtxs = 6;
82
83 // Number of balancing constraints, which must be at least 1.
84 idx_t ncon = 1;
85
86 // Pointers to initial entries in adjacency array.
87 idx_t xadj[7] = {0, 2, 5, 7, 9, 12, 14};
88
89 // Adjacent vertices in consecutive index order.
90 int nedges = 7;
91 idx_t adjncy[14] = {1, 3, 0, 4, 2, 1, 5, 0, 4, 3, 1, 5, 4, 2};
92
93 // The number of parts requested for the partition.
94 idx_t nParts = 3;
95
96 // On return, the edge cut volume of the partitioning solution.
97 idx_t objval;
98
99 // On return, the partition vector for the graph.
100 idx_t part[6];
101
102 printf("\n");
103 printf("partGraphKwayTest:\n");
104 printf(" METIS_PartGraphKway partitions a graph into K parts\n");
105 printf(" using multilevel K-way partition.\n");
106
107 int ret = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, NULL, NULL,
108 NULL, &nParts, NULL, NULL, NULL, &objval, part);
109
110 printf("\n");
111 printf(" Return code = %d\n", ret);
112 printf(" Edge cuts for partition = %d\n", (int) objval);
113
114 printf("\n");
115 printf(" Partition vector:\n");
116 printf("\n");
117 printf(" Node Part\n");
118 printf("\n");
119 for (unsigned part_i = 0; part_i < nvtxs; part_i++) {
120 printf(" %d %d\n", part_i, (int) part[part_i]);
121 }
122
123 }
124} // namespace
125
127
128 printf("\n");
129 printf("METIS_TEST\n");
130 printf(" Test the METIS library for graph partitioning (simple).\n");
131
132 // perform basic test that shows metis is linked correctly with the code
135}
136
137void test::testGraphPartitioning(size_t nPart, size_t nGrid, size_t mHorizon, size_t testOption, std::string meshFilename) {
138
139 std::cout << "\nMETIS_TEST\n";
140 std::cout << "\n Test the METIS library for graph partitioning for realistic mesh with nonlocal interaction.\n" ;
141 std::cout << fmt::format("\n Arguments: nPart = {}, nGrid = {}, mHorizon = {}\n", nPart, nGrid, mHorizon);
142
143 // create uniform mesh on domain [0, Lx]x[0, Ly]
144 auto t1 = steady_clock::now();
145
146 // empty mesh object
147 size_t dim(2);
148 auto mesh = fe::Mesh(dim);
149 mesh.d_spatialDiscretization = "finite_difference";
150
151 // create mesh
152 std::string outMeshFilename = "";
153 if (testOption == 1) {
154 // set geometry details
155 std::pair<std::vector<double>, std::vector<double>> box;
156 std::vector<size_t> nGridVec;
157 for (size_t i=0; i<dim; i++) {
158 box.first.push_back(0.);
159 box.second.push_back(1.);
160 nGridVec.push_back(nGrid);
161 }
162
163 // call utility function to create mesh
164 fe::createUniformMesh(&mesh, dim, box, nGridVec);
165
166 // filename for outputting
167 outMeshFilename = fmt::format("uniform_mesh_Lx_{}_Ly_{}_Nx_{}_Ny_{}",
168 box.second[0], box.second[1],
169 nGridVec[0], nGridVec[1]);
170 }
171 else if (testOption == 2) {
172 if (meshFilename.empty()) {
173 std::cerr << "testGraphPartitioning(): mesh filename is empty.\n";
174 exit(1);
175 }
176
177 // call in-built function of mesh to create data from file
178 mesh.createData(meshFilename);
179
180 // find the name of mesh file without path and without extension (i.e., remove .vtu/.msh/.csv extension)
181 auto f1 = util::io::getFilenameFromPath(meshFilename);
182 outMeshFilename = util::io::removeExtensionFromFile(f1);
183 }
184 else {
185 std::cerr << "testGraphPartitioning() accepts either 0 or 1 for testOption. The value "
186 << testOption << " is invalid.\n";
187 exit(1);
188 }
189
190 // set nonlocal lengthscale
191 double horizon = mHorizon*mesh.d_h;
192
193 // print mesh data and write mesh to a file
194 std::ostringstream msg;
195 msg << mesh.printStr();
196 std::cout << msg.str();
197
198 auto t2 = steady_clock::now();
199 auto setup_time = util::methods::timeDiff(t1, t2, "microseconds");
200 std::cout << fmt::format("Setup time (ms) = {}. \n", setup_time);
201
202 // create neighborhood of each node (to be used in metis partitioning of the graph)
203 std::vector<std::vector<size_t>> nodeNeighs(mesh.d_numNodes);
204 geometry::computeNonlocalNeighborhood(mesh.d_nodes, horizon, nodeNeighs);
205 auto t3 = steady_clock::now();
206 auto neigh_time = util::methods::timeDiff(t2, t3, "microseconds");
207 std::cout << fmt::format("Neighborhood calculation time (ms) = {}.\n", neigh_time);
208
209 // at this stage, we have mesh and nonlocal neighborhood
210 // we are ready to cast the nonlocal neighborhood into graph and call metis for partitioning of nodes
211 std::vector<size_t> nodePartitionRecursive(mesh.d_numNodes, 0);
212 std::vector<size_t> nodePartitionKWay(mesh.d_numNodes, 0);
213
214 // recursive method
215 auto t4 = steady_clock::now();
216 fe::metisGraphPartition("metis_recursive", nodeNeighs, nodePartitionRecursive, nPart);
217 auto t5 = steady_clock::now();
218
219 // K-way method
220 fe::metisGraphPartition("metis_kway", nodeNeighs, nodePartitionKWay, nPart);
221 auto t6 = steady_clock::now();
222
223 auto partition_recursive_time = util::methods::timeDiff(t4, t5, "microseconds");
224 auto partition_kway_time = util::methods::timeDiff(t5, t6, "microseconds");
225 std::cout << fmt::format("Partition (Recursive) calculation time (ms) = {}.\n", partition_recursive_time);
226 std::cout << fmt::format("Partition (KWay) calculation time (ms) = {}.\n", partition_kway_time);
227
228 // write data to file
229 outMeshFilename = outMeshFilename + fmt::format("_mHorizon_{}_nPart_{}", mHorizon, nPart);
230 std::cout << "out mesh filename = " << outMeshFilename << std::endl;
231 auto writer = rw::writer::Writer(outMeshFilename, "vtu");
232 writer.appendMesh(&mesh.d_nodes, mesh.d_eType, &mesh.d_enc);
233 writer.appendPointData("Nodal_Volume", &mesh.d_vol);
234 writer.appendPointData("Nodal_Partition_Metis_Recursive_Index", &nodePartitionRecursive);
235 writer.appendPointData("Nodal_Partition_Metis_KWay_Index", &nodePartitionKWay);
236 writer.close();
237}
A class for mesh data.
Definition mesh.h:51
A interface class writing data.
Definition writer.h:44
void createUniformMesh(fe::Mesh *mesh_p, size_t dim, std::pair< std::vector< double >, std::vector< double > > box, std::vector< size_t > nGrid)
Creates uniform mesh for rectangle/cuboid domain.
Definition meshUtil.cpp:23
void metisGraphPartition(std::string partitionMethod, const std::vector< std::vector< size_t > > &nodeNeighs, std::vector< size_t > &nodePartition, size_t nPartitions)
Partitions the nodes based on node neighborlist supplied. Function first creates a graph with nodes a...
void computeNonlocalNeighborhood(const std::vector< util::Point > &nodes, double horizon, std::vector< std::vector< size_t > > &nodeNeighs)
Partitions the nodes based on node neighborlist supplied. Function first creates a graph with nodes a...
void testGraphPartitioningSimple()
Tests metis partitioning of graph.
void testGraphPartitioning(size_t nPart=4, size_t nGrid=10, size_t mHorizon=3, size_t testOption=0, std::string meshFilename="")
Tests metis partitioning of graph from a 2-D mesh with nonlocal interaction.
std::string removeExtensionFromFile(std::string const &filename)
Remove extension from the filename Source - https://stackoverflow.com/a/24386991.
Definition io.h:416
std::string getFilenameFromPath(std::string const &path, std::string const &delims="/\\")
Get filename removing path from the string Source - https://stackoverflow.com/a/24386991.
Definition io.h:404
float timeDiff(std::chrono::steady_clock::time_point begin, std::chrono::steady_clock::time_point end, std::string unit="microseconds")
Returns difference between two times.
Definition methods.h:304