OGS
GMSH2OGS.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 <algorithm>
7#include <string>
8
9#include "BaseLib/FileTools.h"
10#include "BaseLib/MPI.h"
11#include "BaseLib/RunTime.h"
13#include "InfoLib/GitInfo.h"
14#ifndef WIN32
15#include "BaseLib/MemWatch.h"
16#endif
17
19#include "BaseLib/Logging.h"
20#include "GeoLib/AABB.h"
24#include "MeshLib/Mesh.h"
29
30static std::unique_ptr<MeshLib::Mesh> createMeshFromElements(
31 MeshLib::Mesh const& mesh,
32 std::vector<MeshLib::Element*> const& selected_elements,
33 std::string mesh_name)
34{
35 // Create boundary mesh.
36 auto nodes = copyNodeVector(mesh.getNodes());
37 auto elements = copyElementVector(selected_elements, nodes);
38
39 // Cleanup unused nodes
41 MeshToolsLib::markUnusedNodes(elements, nodes), nodes);
42
43 return std::make_unique<MeshLib::Mesh>(std::move(mesh_name), nodes,
44 elements);
45}
46
47static std::vector<std::unique_ptr<MeshLib::Mesh>> extractBoundaryMeshes(
48 MeshLib::Mesh const& mesh, std::vector<std::size_t> selected_element_ids)
49{
50 auto const material_ids = materialIDs(mesh);
51 if (material_ids == nullptr)
52 {
54 "GMSH2OGS: Expected material ids to be present in the mesh to "
55 "extract boundary meshes.");
56 }
57
58 std::vector<std::unique_ptr<MeshLib::Mesh>> boundary_meshes;
59
60 auto const& elements = mesh.getElements();
61
62 while (!selected_element_ids.empty())
63 {
64 // Partition in two blocks, with elements for the material id at
65 // the end, s.t. one can erase them easily.
66 int const material_id = (*material_ids)[selected_element_ids.back()];
67 auto split = std::partition(
68 begin(selected_element_ids), end(selected_element_ids),
69 [&material_id, &material_ids](int const id)
70 { return (*material_ids)[id] != material_id; });
71
72 // Add elements with same material id to the mesh.
73 std::vector<MeshLib::Element*> single_material_elements;
74 single_material_elements.reserve(
75 std::distance(split, end(selected_element_ids)));
76 std::transform(split, end(selected_element_ids),
77 std::back_inserter(single_material_elements),
78 [&](int const id) { return elements[id]; });
79
80 // Remove already extracted elements.
81 selected_element_ids.erase(split, end(selected_element_ids));
82
83 // Create boundary mesh and identify the nodes/elements.
84 boundary_meshes.push_back(createMeshFromElements(
85 mesh, single_material_elements, std::to_string(material_id)));
86 }
87 return boundary_meshes;
88}
89
91 MeshLib::Mesh const& mesh,
92 std::string const& file_name,
93 std::vector<std::unique_ptr<MeshLib::Mesh>>& boundary_meshes)
94{
95 // Bulk mesh node searcher usef for boundary mesh identification.
96 auto const& mesh_node_searcher =
98 mesh,
99 std::make_unique<MeshGeoToolsLib::SearchLength>(
100 0)); // Exact match of nodes.
101
102 for (auto& boundary_mesh : boundary_meshes)
103 {
104 identifySubdomainMesh(*boundary_mesh, mesh, mesh_node_searcher);
105
106 // Save the boundary mesh.
107 auto boundary_mesh_file_name = BaseLib::dropFileExtension(file_name) +
108 '_' + boundary_mesh->getName() +
109 BaseLib::getFileExtension(file_name);
110
111 MeshLib::IO::writeMeshToFile(*boundary_mesh, boundary_mesh_file_name);
112 }
113}
114
115int main(int argc, char* argv[])
116{
117 TCLAP::CmdLine cmd(
118 "Converting meshes in gmsh file format (ASCII, version 2.2) to a vtk "
119 "unstructured grid file (new OGS file format) or to the old OGS file "
120 "format - see options.\n\n"
121 "OpenGeoSys-6 software, version " +
123 ".\n"
124 "Copyright (c) 2012-2026, OpenGeoSys Community "
125 "(http://www.opengeosys.org)",
127
128 TCLAP::ValueArg<std::string> ogs_mesh_arg(
129 "o",
130 "out",
131 "Output (.msh | .vtk). Filename for output mesh (if extension is .msh, "
132 "old OGS-5 file format "
133 "is written, if extension is .vtu, a vtk unstructure grid file is "
134 "written (OGS-6 mesh format))",
135 true,
136 "",
137 "OUTPUT_FILE");
138 cmd.add(ogs_mesh_arg);
139
140 TCLAP::ValueArg<std::string> gmsh_mesh_arg("i", "in", "Input (.msh) file",
141 true, "", "INPUT_FILE");
142 cmd.add(gmsh_mesh_arg);
143
144 TCLAP::SwitchArg valid_arg("v", "validation", "validate the mesh");
145 cmd.add(valid_arg);
146
147 TCLAP::SwitchArg create_boundary_meshes_arg(
148 "b", "boundaries", "if set, boundary meshes will be generated");
149 cmd.add(create_boundary_meshes_arg);
150
151 TCLAP::SwitchArg exclude_lines_arg(
152 "e", "exclude-lines",
153 "if set, lines will not be written to the ogs mesh");
154 cmd.add(exclude_lines_arg);
155
156 auto log_level_arg = BaseLib::makeLogLevelArg();
157 cmd.add(log_level_arg);
158
159 std::string const gmsh2_opt_message =
160 "if set, the mesh is generated with Gmsh version 2 and it is saved"
161 " (or exported) as \"Version 2 ASCII\" format";
162
163 TCLAP::SwitchArg gmsh2_arg("", "gmsh2_physical_id", gmsh2_opt_message);
164 cmd.add(gmsh2_arg);
165
166 cmd.parse(argc, argv);
167
168 BaseLib::MPI::Setup mpi_setup(argc, argv);
169 BaseLib::initOGSLogger(log_level_arg.getValue());
170
171 // *** read mesh
172 INFO("Reading {:s}.", gmsh_mesh_arg.getValue());
173#ifndef WIN32
174 BaseLib::MemWatch mem_watch;
175 unsigned long mem_without_mesh(mem_watch.getVirtMemUsage());
176#endif
177 BaseLib::RunTime run_time;
178 run_time.start();
179 MeshLib::Mesh* mesh(FileIO::GMSH::readGMSHMesh(gmsh_mesh_arg.getValue(),
180 gmsh2_arg.getValue()));
181
182 if (mesh == nullptr)
183 {
184 INFO("Could not read mesh from {:s}.", gmsh_mesh_arg.getValue());
185 return -1;
186 }
187#ifndef WIN32
188 INFO("Mem for mesh: {} MiB",
189 (mem_watch.getVirtMemUsage() - mem_without_mesh) / (1024 * 1024));
190#endif
191
192 INFO("Time for reading: {:f} seconds.", run_time.elapsed());
193 INFO("Read {:d} nodes and {:d} elements.", mesh->getNumberOfNodes(),
194 mesh->getNumberOfElements());
195
196 // Optionally remove line elements or create boundary meshes.
197 if (exclude_lines_arg.getValue() || create_boundary_meshes_arg.getValue())
198 {
199 auto ex = MeshLib::ElementSearch(*mesh);
200 ex.searchByElementType(MeshLib::MeshElemType::LINE);
201 auto const& selected_element_ids = ex.getSearchedElementIDs();
202
203 // First we extract the boundary meshes, then optionally remove the line
204 // elements, and only then run the node/element identification and write
205 // the meshes.
206
207 std::vector<std::unique_ptr<MeshLib::Mesh>> boundary_meshes;
208 if (create_boundary_meshes_arg.getValue())
209 {
210 boundary_meshes =
211 extractBoundaryMeshes(*mesh, selected_element_ids);
212 }
213
214 if (exclude_lines_arg.getValue())
215 {
217 *mesh, selected_element_ids, mesh->getName() + "-withoutLines");
218 if (m != nullptr)
219 {
220 INFO("Removed {:d} lines.",
221 mesh->getNumberOfElements() - m->getNumberOfElements());
222 std::swap(m, mesh);
223 delete m;
224 }
225 else
226 {
227 INFO("Mesh does not contain any lines.");
228 }
229 }
230
231 if (create_boundary_meshes_arg.getValue())
232 {
233 identifyAndWriteBoundaryMeshes(*mesh, ogs_mesh_arg.getValue(),
234 boundary_meshes);
235 }
236 }
237 // *** print meshinformation
238
239 INFO("Please check your mesh carefully!");
240 INFO(
241 "Degenerated or redundant mesh elements can cause OGS to stop or "
242 "misbehave.");
243 INFO("Use the -e option to delete redundant line elements.");
244
245 // Geometric information
246 const GeoLib::AABB aabb =
248 INFO("Axis aligned bounding box: {}", aabb);
249
250 auto const [min, max] = minMaxEdgeLength(mesh->getElements());
251 INFO("Edge length: [{:g}, {:g}]", min, max);
252
253 // Element information
255
257
258 if (valid_arg.isSet())
259 {
261 }
262
263 // *** write mesh in new format
264 MeshLib::IO::writeMeshToFile(*mesh, ogs_mesh_arg.getValue());
265
266 delete mesh;
267 return EXIT_SUCCESS;
268}
#define OGS_FATAL(...)
Definition Error.h:19
int main(int argc, char *argv[])
Definition GMSH2OGS.cpp:115
static std::unique_ptr< MeshLib::Mesh > createMeshFromElements(MeshLib::Mesh const &mesh, std::vector< MeshLib::Element * > const &selected_elements, std::string mesh_name)
Definition GMSH2OGS.cpp:30
static std::vector< std::unique_ptr< MeshLib::Mesh > > extractBoundaryMeshes(MeshLib::Mesh const &mesh, std::vector< std::size_t > selected_element_ids)
Definition GMSH2OGS.cpp:47
static void identifyAndWriteBoundaryMeshes(MeshLib::Mesh const &mesh, std::string const &file_name, std::vector< std::unique_ptr< MeshLib::Mesh > > &boundary_meshes)
Definition GMSH2OGS.cpp:90
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
unsigned long getVirtMemUsage()
Definition MemWatch.cpp:48
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
Class AABB is an axis aligned bounding box around a given set of geometric points of (template) type ...
Definition AABB.h:45
static OGS_NO_DANGLING MeshNodeSearcher const & getMeshNodeSearcher(MeshLib::Mesh const &mesh, std::unique_ptr< MeshGeoToolsLib::SearchLength > &&search_length_algorithm)
Element search class.
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition Mesh.h:97
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:100
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
static GeoLib::AABB getBoundingBox(const MeshLib::Mesh &mesh)
Returns the bounding box of the mesh.
static void writeMeshValidationResults(MeshLib::Mesh &mesh)
static void writeAllNumbersOfElementTypes(const MeshLib::Mesh &mesh)
writes all numbers of element types
static void writePropertyVectorInformation(const MeshLib::Mesh &mesh)
writes out property vector information
TCLAP::ValueArg< std::string > makeLogLevelArg()
void initOGSLogger(std::string const &log_level)
Definition Logging.cpp:56
std::string getFileExtension(const std::string &path)
std::string dropFileExtension(std::string const &filename)
MeshLib::Mesh * readGMSHMesh(std::string const &fname, bool const is_created_with_gmsh2)
GITINFOLIB_EXPORT const std::string ogs_version
int writeMeshToFile(const MeshLib::Mesh &mesh, std::filesystem::path const &file_path, std::set< std::string > variable_output_names)
std::vector< bool > markUnusedNodes(std::vector< MeshLib::Element * > const &elements, std::vector< MeshLib::Node * > const &nodes)
Marks nodes not used by any of the elements.
void removeMarkedNodes(std::vector< bool > const &nodes_to_delete, std::vector< MeshLib::Node * > &nodes)
Deallocates and removes nodes marked true.
MeshLib::Mesh * removeElements(const MeshLib::Mesh &mesh, const std::vector< std::size_t > &removed_element_ids, const std::string &new_mesh_name)