OGS
PartitionMesh.cpp
Go to the documentation of this file.
1
15#include <spdlog/spdlog.h>
16#include <tclap/CmdLine.h>
17
18#ifdef USE_PETSC
19#include <mpi.h>
20#endif
21
22#include "BaseLib/CPUTime.h"
23#include "BaseLib/FileTools.h"
24#include "BaseLib/RunTime.h"
25#include "InfoLib/GitInfo.h"
27#include "Metis.h"
29
30using namespace ApplicationUtils;
31
32int main(int argc, char* argv[])
33{
34 TCLAP::CmdLine cmd(
35 "Partition a mesh for parallel computing."
36 "The tasks of this tool are in twofold:\n"
37 "1. Convert mesh file to the input file of the partitioning tool,\n"
38 "2. Partition a mesh using the partitioning tool,\n"
39 "\tcreate the mesh data of each partition,\n"
40 "\trenumber the node indices of each partition,\n"
41 "\tand output the results for parallel computing.\n"
42 "Note: If this tool is installed as a system command,\n"
43 "\tthe command must be run with its full path.\n\n"
44 "OpenGeoSys-6 software, version " +
46 ".\n"
47 "Copyright (c) 2012-2024, OpenGeoSys Community "
48 "(http://www.opengeosys.org)",
50 TCLAP::ValueArg<std::string> mesh_input(
51 "i", "mesh-input-file",
52 "the name of the file containing the input mesh", true, "",
53 "file name of input mesh");
54 cmd.add(mesh_input);
55
56 TCLAP::ValueArg<std::string> metis_mesh_input(
57 "x", "metis-mesh-input-file",
58 "base name (without .mesh extension) of the file containing the metis "
59 "input mesh",
60 false, "",
61 "base name (without .mesh extension) of the file containing the metis "
62 "input mesh");
63 cmd.add(metis_mesh_input);
64
65 TCLAP::ValueArg<std::string> output_directory_arg(
66 "o", "output", "directory name for the output files", false, "",
67 "directory");
68 cmd.add(output_directory_arg);
69
70 TCLAP::ValueArg<int> nparts("n", "np", "the number of partitions", false, 2,
71 "integer");
72 cmd.add(nparts);
73
74 TCLAP::SwitchArg ogs2metis_flag(
75 "s", "ogs2metis",
76 "Indicator to convert the ogs mesh file to METIS input file", cmd,
77 false);
78
79 TCLAP::SwitchArg exe_metis_flag(
80 "m", "exe_metis", "Call mpmetis inside the programme via system().",
81 false);
82 cmd.add(exe_metis_flag);
83
84 TCLAP::ValueArg<std::string> log_level_arg(
85 "l", "log-level",
86 "the verbosity of logging messages: none, error, warn, info, debug, "
87 "all",
88 false,
89#ifdef NDEBUG
90 "info",
91#else
92 "all",
93#endif
94 "LOG_LEVEL");
95 cmd.add(log_level_arg);
96
97 // All the remaining arguments are used as file names for boundary/subdomain
98 // meshes.
99 TCLAP::UnlabeledMultiArg<std::string> other_meshes_filenames_arg(
100 "other_meshes_filenames", "mesh file names.", false, "file");
101 cmd.add(other_meshes_filenames_arg);
102
103 cmd.parse(argc, argv);
104
105#ifdef USE_PETSC
106 MPI_Init(&argc, &argv);
107#endif
108
109 BaseLib::setConsoleLogLevel(log_level_arg.getValue());
110 spdlog::set_pattern("%^%l:%$ %v");
111 spdlog::set_error_handler(
112 [](const std::string& msg)
113 {
114 std::cerr << "spdlog error: " << msg << std::endl;
115 OGS_FATAL("spdlog logger error occurred.");
116 });
117
118 const auto output_directory = output_directory_arg.getValue();
119 BaseLib::createOutputDirectory(output_directory);
120
121 BaseLib::RunTime run_timer;
122 run_timer.start();
123 BaseLib::CPUTime CPU_timer;
124 CPU_timer.start();
125
126 const std::string input_file_name_wo_extension =
127 BaseLib::dropFileExtension(mesh_input.getValue());
128 std::unique_ptr<MeshLib::Mesh> mesh_ptr(
129 MeshLib::IO::readMeshFromFile(input_file_name_wo_extension + ".vtu"));
130 INFO("Mesh '{:s}' read: {:d} nodes, {:d} elements.",
131 mesh_ptr->getName(),
132 mesh_ptr->getNumberOfNodes(),
133 mesh_ptr->getNumberOfElements());
134
135 std::string const output_file_name_wo_extension = BaseLib::joinPaths(
136 output_directory,
137 BaseLib::extractBaseNameWithoutExtension(mesh_input.getValue()));
138
139 if (ogs2metis_flag.getValue())
140 {
141 INFO("Write the mesh into METIS input file.");
142 ApplicationUtils::writeMETIS(mesh_ptr->getElements(),
143 output_file_name_wo_extension + ".mesh");
144 INFO("Total runtime: {:g} s.", run_timer.elapsed());
145 INFO("Total CPU time: {:g} s.", CPU_timer.elapsed());
146
147#ifdef USE_PETSC
148 MPI_Finalize();
149#endif
150 return EXIT_SUCCESS;
151 }
152
154 nparts.getValue(), std::move(mesh_ptr));
155
156 const int num_partitions = nparts.getValue();
157
158 if (num_partitions < 1)
159 {
160 OGS_FATAL("Number of partitions must be positive.");
161 }
162
163 if (num_partitions == 1)
164 {
165 OGS_FATAL(
166 "Partitioning the mesh into one domain is unnecessary because OGS "
167 "reads vtu mesh data directly when called with 'mpirun bin/ogs "
168 "-np=1'.");
169 }
170
171 auto metis_mesh = output_file_name_wo_extension;
172 if (metis_mesh_input.getValue() != "")
173 {
174 metis_mesh = metis_mesh_input.getValue();
175 }
176
177 // Execute mpmetis via system(...)
178 if (exe_metis_flag.getValue())
179 {
180 INFO("METIS is running ...");
181 const std::string exe_name = argv[0];
182 const std::string exe_path = BaseLib::extractPath(exe_name);
183 INFO("Path to mpmetis is: \n\t{:s}", exe_path);
184
185 const std::string mpmetis_com =
186 BaseLib::joinPaths(exe_path, "mpmetis") + " -gtype=nodal " + "\"" +
187 metis_mesh + ".mesh" + "\" " + std::to_string(nparts.getValue());
188
189 INFO("Running: {:s}", mpmetis_com);
190 const int status = system(mpmetis_com.c_str());
191 if (status != 0)
192 {
193 INFO("Failed in system calling.");
194 INFO("Return value of system call {:d} ", status);
195#ifdef USE_PETSC
196 MPI_Finalize();
197#endif
198 return EXIT_FAILURE;
199 }
200 }
201 mesh_partitioner.resetPartitionIdsForNodes(
202 readMetisData(metis_mesh, num_partitions,
203 mesh_partitioner.mesh().getNumberOfNodes()));
204
205 // Remove metis partitioning files only if metis was run internally.
206 if (exe_metis_flag.getValue())
207 {
208 removeMetisPartitioningFiles(metis_mesh, num_partitions);
209 }
210
211 INFO("Partitioning the mesh in the node wise way ...");
212 mesh_partitioner.partitionByMETIS();
213
214 INFO("Partitioning other meshes according to the main mesh partitions.");
215 for (auto const& filename : other_meshes_filenames_arg.getValue())
216 {
217 std::unique_ptr<MeshLib::Mesh> mesh(
219 INFO("Mesh '{:s}' from file '{:s}' read: {:d} nodes, {:d} elements.",
220 mesh->getName(), filename, mesh->getNumberOfNodes(),
221 mesh->getNumberOfElements());
222
223 std::string const other_mesh_output_file_name_wo_extension =
225 output_directory,
227 auto partitions = mesh_partitioner.partitionOtherMesh(*mesh);
228
229 auto partitioned_properties = partitionProperties(mesh, partitions);
230 mesh_partitioner.renumberBulkIdsProperty(partitions,
231 partitioned_properties);
232
233 mesh_partitioner.writeOtherMesh(
234 other_mesh_output_file_name_wo_extension, partitions,
235 partitioned_properties);
236 }
237
238 BaseLib::RunTime io_run_timer;
239 io_run_timer.start();
240 mesh_partitioner.write(output_file_name_wo_extension);
241 INFO("Writing the partitions data into binary files took {:g} s",
242 io_run_timer.elapsed());
243
244 INFO("Total runtime: {:g} s.", run_timer.elapsed());
245 INFO("Total CPU time: {:g} s.", CPU_timer.elapsed());
246
247#ifdef USE_PETSC
248 MPI_Finalize();
249#endif
250 return EXIT_SUCCESS;
251}
Definition of the CPUTime class.
#define OGS_FATAL(...)
Definition Error.h:26
Filename manipulation routines.
Git information.
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:35
Declare a class to perform node wise mesh partitioning.
int main(int argc, char *argv[])
Definition of the RunTime class.
std::vector< Partition > partitionOtherMesh(MeshLib::Mesh const &mesh) const
void write(const std::string &file_name_base)
void renumberBulkIdsProperty(std::vector< Partition > const &partitions, MeshLib::Properties &partitioned_properties)
void resetPartitionIdsForNodes(std::vector< std::size_t > &&node_partition_ids)
void writeOtherMesh(std::string const &output_filename_base, std::vector< Partition > const &partitions, MeshLib::Properties const &partitioned_properties) const
Count CPU time.
Definition CPUTime.h:23
void start()
Start the timer.
Definition CPUTime.h:26
double elapsed() const
Get the elapsed time after started.
Definition CPUTime.h:29
Count the running time.
Definition RunTime.h:29
double elapsed() const
Get the elapsed time in seconds.
Definition RunTime.h:42
void start()
Start the timer.
Definition RunTime.h:32
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition Mesh.h:100
void writeMETIS(std::vector< MeshLib::Element * > const &elements, const std::string &file_name)
Definition Metis.cpp:19
MeshLib::Properties partitionProperties(std::unique_ptr< MeshLib::Mesh > const &mesh, std::vector< Partition > &partitions)
Partition existing properties and add vtkGhostType cell data array property.
void removeMetisPartitioningFiles(std::string const &file_name_base, long const number_of_partitions)
Definition Metis.cpp:90
std::vector< std::size_t > readMetisData(const std::string &file_name_base, long const number_of_partitions, std::size_t const number_of_nodes)
Definition Metis.cpp:45
void setConsoleLogLevel(std::string const &level_string)
Definition Logging.cpp:37
std::string extractPath(std::string const &pathname)
std::string extractBaseNameWithoutExtension(std::string const &pathname)
std::string dropFileExtension(std::string const &filename)
std::string joinPaths(std::string const &pathA, std::string const &pathB)
bool createOutputDirectory(std::string const &dir)
GITINFOLIB_EXPORT const std::string ogs_version
MeshLib::Mesh * readMeshFromFile(const std::string &file_name, bool const compute_element_neighbors)
Definition of readMeshFromFile function.