OGS
PartitionMesh.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include <tclap/CmdLine.h>
5
6#include "BaseLib/CPUTime.h"
7#include "BaseLib/FileTools.h"
8#include "BaseLib/Logging.h"
9#include "BaseLib/MPI.h"
10#include "BaseLib/RunTime.h"
12#include "InfoLib/GitInfo.h"
14#include "Metis.h"
16
17using namespace ApplicationUtils;
18
20 MeshLib::MeshItemType const mesh_item_type,
21 std::size_t const number_of_items)
22{
23 if (!mesh_properties.existsPropertyVector<std::size_t>(
24 MeshLib::globalIDString(mesh_item_type), mesh_item_type, 1))
25 {
26 auto* global_ids = mesh_properties.createNewPropertyVector<std::size_t>(
27 MeshLib::globalIDString(mesh_item_type), mesh_item_type,
28 number_of_items, 1);
29 if (!global_ids)
30 {
31 OGS_FATAL("Could not create PropertyVector '{}'.",
32 MeshLib::globalIDString(mesh_item_type));
33 }
34 global_ids->assign(ranges::views::iota(0u, number_of_items));
35 }
36}
37
39{
40 auto& mesh_properties = mesh.getProperties();
41
43 mesh.getNumberOfNodes());
44 INFO("Property {} is added to mesh {}",
46
48 mesh.getNumberOfElements());
49 INFO("Property {} is added to mesh {}",
51}
52
53int main(int argc, char* argv[])
54{
55 TCLAP::CmdLine cmd(
56 "Partition a mesh for parallel computing."
57 "The tasks of this tool are in twofold:\n"
58 "1. Convert mesh file to the input file of the partitioning tool,\n"
59 "2. Partition a mesh using the partitioning tool,\n"
60 "\tcreate the mesh data of each partition,\n"
61 "\trenumber the node indices of each partition,\n"
62 "\tand output the results for parallel computing.\n"
63 "Note: If this tool is installed as a system command,\n"
64 "\tthe command must be run with its full path.\n\n"
65 "OpenGeoSys-6 software, version " +
67 ".\n"
68 "Copyright (c) 2012-2026, OpenGeoSys Community "
69 "(http://www.opengeosys.org)",
71 TCLAP::ValueArg<std::string> mesh_input(
72 "i", "mesh-input-file",
73 "Input (.vtu). The name of the file containing the input mesh", true,
74 "", "INPUT_FILE");
75 cmd.add(mesh_input);
76
77 TCLAP::ValueArg<std::string> metis_mesh_input(
78 "x", "metis-mesh-input-file",
79 "Input (.mesh). Base name (without .mesh extension) of the file "
80 "containing the metis input mesh",
81 false, "", "BASE_FILENAME_INPUT");
82 cmd.add(metis_mesh_input);
83
84 TCLAP::ValueArg<std::string> output_directory_arg(
85 "o", "output", "Output. Directory name for the output files", false, "",
86 "OUTPUT_PATH");
87 cmd.add(output_directory_arg);
88
89 TCLAP::ValueArg<int> nparts("n", "np",
90 "the number of partitions, "
91 "(min = 0)",
92 false, 2, "N_PARTS");
93 cmd.add(nparts);
94
95 TCLAP::SwitchArg ogs2metis_flag(
96 "s", "ogs2metis",
97 "Indicator to convert the ogs mesh file to METIS input file", cmd,
98 false);
99
100 TCLAP::SwitchArg exe_metis_flag(
101 "m", "exe_metis", "Call mpmetis inside the programme via system().",
102 false);
103 cmd.add(exe_metis_flag);
104
105 auto log_level_arg = BaseLib::makeLogLevelArg();
106 cmd.add(log_level_arg);
107
108 // All the remaining arguments are used as file names for boundary/subdomain
109 // meshes.
110 TCLAP::UnlabeledMultiArg<std::string> other_meshes_filenames_arg(
111 "other_meshes_filenames", "mesh file names.", false, "file");
112 cmd.add(other_meshes_filenames_arg);
113
114 cmd.parse(argc, argv);
115
116 BaseLib::MPI::Setup mpi_setup(argc, argv);
117 BaseLib::initOGSLogger(log_level_arg.getValue());
118
119 const auto output_directory = output_directory_arg.getValue();
120 BaseLib::createOutputDirectory(output_directory);
121
122 BaseLib::RunTime run_timer;
123 run_timer.start();
124 BaseLib::CPUTime CPU_timer;
125 CPU_timer.start();
126
127 const std::string input_file_name_wo_extension =
128 BaseLib::dropFileExtension(mesh_input.getValue());
129 std::unique_ptr<MeshLib::Mesh> mesh_ptr(
130 MeshLib::IO::readMeshFromFile(input_file_name_wo_extension + ".vtu"));
131 INFO("Mesh '{:s}' read: {:d} nodes, {:d} elements.",
132 mesh_ptr->getName(),
133 mesh_ptr->getNumberOfNodes(),
134 mesh_ptr->getNumberOfElements());
135
136 addGlobalIDsToMesh(*mesh_ptr);
137
138 std::string const output_file_name_wo_extension = BaseLib::joinPaths(
139 output_directory,
140 BaseLib::extractBaseNameWithoutExtension(mesh_input.getValue()));
141
142 if (ogs2metis_flag.getValue())
143 {
144 INFO("Write the mesh into METIS input file.");
145 ApplicationUtils::writeMETIS(mesh_ptr->getElements(),
146 output_file_name_wo_extension + ".mesh");
147 INFO("Total runtime: {:g} s.", run_timer.elapsed());
148 INFO("Total CPU time: {:g} s.", CPU_timer.elapsed());
149
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 return EXIT_FAILURE;
196 }
197 }
198 mesh_partitioner.resetPartitionIdsForNodes(
199 readMetisData(metis_mesh, num_partitions,
200 mesh_partitioner.mesh().getNumberOfNodes()));
201
202 // Remove metis partitioning files only if metis was run internally.
203 if (exe_metis_flag.getValue())
204 {
205 removeMetisPartitioningFiles(metis_mesh, num_partitions);
206 }
207
208 INFO("Partitioning the mesh in the node wise way ...");
209 mesh_partitioner.partitionByMETIS();
210
211 INFO("Partitioning other meshes according to the main mesh partitions.");
212 for (auto const& filename : other_meshes_filenames_arg.getValue())
213 {
214 std::unique_ptr<MeshLib::Mesh> mesh(
216 INFO("Mesh '{:s}' from file '{:s}' read: {:d} nodes, {:d} elements.",
217 mesh->getName(), filename, mesh->getNumberOfNodes(),
218 mesh->getNumberOfElements());
219
220 addGlobalIDsToMesh(*mesh);
221
222 std::string const other_mesh_output_file_name_wo_extension =
224 output_directory,
226 auto partitions = mesh_partitioner.partitionOtherMesh(*mesh);
227
228 auto partitioned_properties = partitionProperties(mesh, partitions);
229 mesh_partitioner.renumberBulkIdsProperty(partitions,
230 partitioned_properties);
231
232 mesh_partitioner.writeOtherMesh(
233 other_mesh_output_file_name_wo_extension, partitions,
234 partitioned_properties);
235 }
236
237 BaseLib::RunTime io_run_timer;
238 io_run_timer.start();
239 mesh_partitioner.write(output_file_name_wo_extension);
240 INFO("Writing the partitions data into binary files took {:g} s",
241 io_run_timer.elapsed());
242
243 INFO("Total runtime: {:g} s.", run_timer.elapsed());
244 INFO("Total CPU time: {:g} s.", CPU_timer.elapsed());
245
246 return EXIT_SUCCESS;
247}
#define OGS_FATAL(...)
Definition Error.h:19
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
int main(int argc, char *argv[])
void addGlobalIDsToMesh(MeshLib::Properties &mesh_properties, MeshLib::MeshItemType const mesh_item_type, std::size_t const number_of_items)
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:12
void start()
Start the timer.
Definition CPUTime.h:15
double elapsed() const
Get the elapsed time after started.
Definition CPUTime.h:18
Count the running time.
Definition RunTime.h:18
double elapsed() const
Get the elapsed time in seconds.
Definition RunTime.h:31
void start()
Start the timer.
Definition RunTime.h:21
Properties & getProperties()
Definition Mesh.h:125
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:94
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition Mesh.h:91
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:88
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
bool existsPropertyVector(std::string_view name) const
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)
constexpr void assign(R &&r)
void writeMETIS(std::vector< MeshLib::Element * > const &elements, const std::string &file_name)
Definition Metis.cpp:11
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:82
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:37
TCLAP::ValueArg< std::string > makeLogLevelArg()
void initOGSLogger(std::string const &log_level)
Definition Logging.cpp:56
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)
constexpr std::string_view globalIDString(MeshLib::MeshItemType const mesh_item_type)