OGS
generateStructuredMesh.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 <memory>
8#include <string>
9#include <vector>
10
11#include "BaseLib/Error.h"
12#include "BaseLib/Logging.h"
13#include "BaseLib/MPI.h"
14#include "BaseLib/Subdivision.h"
16#include "InfoLib/GitInfo.h"
17#include "MathLib/Point3d.h"
20#include "MeshLib/Mesh.h"
21#include "MeshLib/MeshEnums.h"
22#include "MeshLib/Node.h"
24
25namespace
26{
30{
31 switch (eleType)
32 {
34 return 1;
37 return 2;
42 return 3;
45 return 0;
46 }
47 return 0;
48}
49
50} // end namespace
51
52int main(int argc, char* argv[])
53{
54 TCLAP::CmdLine cmd(
55 "Structured mesh generator.\n"
56 "The documentation is available at "
57 "https://docs.opengeosys.org/docs/tools/meshing/"
58 "structured-mesh-generation.\n\n"
59 "OpenGeoSys-6 software, version " +
61 ".\n"
62 "Copyright (c) 2012-2026, OpenGeoSys Community "
63 "(http://www.opengeosys.org)",
65
66 std::vector<std::string> allowed_ele_types;
67 allowed_ele_types.emplace_back("line");
68 allowed_ele_types.emplace_back("tri");
69 allowed_ele_types.emplace_back("quad");
70 allowed_ele_types.emplace_back("hex");
71 allowed_ele_types.emplace_back("prism");
72 allowed_ele_types.emplace_back("tet");
73 allowed_ele_types.emplace_back("pyramid");
74 TCLAP::ValuesConstraint<std::string> allowedVals(allowed_ele_types);
75 TCLAP::ValueArg<std::string> eleTypeArg("e", "element-type",
76 "element type to be created", true,
77 "line", &allowedVals);
78 cmd.add(eleTypeArg);
79 TCLAP::ValueArg<std::string> mesh_out(
80 "o", "mesh-output-file",
81 "Output (.vtu). The name of the file the mesh will be written to", true,
82 "", "OUTPUT_FILE");
83 cmd.add(mesh_out);
84 TCLAP::ValueArg<double> lengthXArg("", "lx",
85 "length of a domain in x direction, "
86 "(min = 0)",
87 false, 10.0, "LENGTH_X");
88 cmd.add(lengthXArg);
89 TCLAP::ValueArg<double> lengthYArg("", "ly",
90 "length of a domain in y direction, "
91 "(min = 0)",
92 false, 10.0, "LENGTH_Y");
93 cmd.add(lengthYArg);
94 TCLAP::ValueArg<double> lengthZArg("", "lz",
95 "length of a domain in z direction, "
96 "(min = 0)",
97 false, 10.0, "LENGTH_Z");
98 cmd.add(lengthZArg);
99 TCLAP::ValueArg<unsigned> nsubdivXArg(
100 "", "nx",
101 "the number of subdivision in x direction, "
102 "(min = 0)",
103 false, 10, "SUBDIVISIONS_X");
104 cmd.add(nsubdivXArg);
105 TCLAP::ValueArg<unsigned> nsubdivYArg(
106 "", "ny",
107 "the number of subdivision in y direction, "
108 "(min = 0)",
109 false, 10, "SUBDIVISIONS_Y");
110 cmd.add(nsubdivYArg);
111 TCLAP::ValueArg<unsigned> nsubdivZArg(
112 "", "nz",
113 "the number of subdivision in z direction, "
114 "(min = 0)",
115 false, 10, "SUBDIVISIONS_Z");
116 cmd.add(nsubdivZArg);
117 // in case of gradual refinement
118 TCLAP::ValueArg<double> d0XArg("", "dx0",
119 "initial cell length in x direction, "
120 "(min = 0)",
121 false, 1, "INITIAL_X");
122 cmd.add(d0XArg);
123 TCLAP::ValueArg<double> d0YArg("", "dy0",
124 "initial cell length in y direction, "
125 "(min = 0)",
126 false, 1, "INITIAL_Y");
127 cmd.add(d0YArg);
128 TCLAP::ValueArg<double> d0ZArg("", "dz0",
129 "initial cell length in z direction, "
130 "(min = 0)",
131 false, 1, "INITIAL_Z");
132 cmd.add(d0ZArg);
133 TCLAP::ValueArg<double> dmaxXArg("", "dx-max",
134 "maximum cell length in x direction, "
135 "(min = 0)",
136 false, std::numeric_limits<double>::max(),
137 "MAX_X");
138 cmd.add(dmaxXArg);
139 TCLAP::ValueArg<double> dmaxYArg("", "dy-max",
140 "maximum cell length in y direction, "
141 "(min = 0)",
142 false, std::numeric_limits<double>::max(),
143 "MAX_Y");
144 cmd.add(dmaxYArg);
145 TCLAP::ValueArg<double> dmaxZArg("", "dz-max",
146 "maximum cell length in z direction, "
147 "(min = 0)",
148 false, std::numeric_limits<double>::max(),
149 "MAX_Z");
150 cmd.add(dmaxZArg);
151 TCLAP::ValueArg<double> multiXArg("", "mx", "multiplier in x direction",
152 false, 1, "MULTIPLIER_X");
153 cmd.add(multiXArg);
154 TCLAP::ValueArg<double> multiYArg("", "my", "multiplier in y direction",
155 false, 1, "MULTIPLIER_Y");
156 cmd.add(multiYArg);
157 TCLAP::ValueArg<double> multiZArg("", "mz", "multiplier in z direction",
158 false, 1, "MULTIPLIER_Z");
159 cmd.add(multiZArg);
160 TCLAP::ValueArg<double> originXArg(
161 "", "ox", "mesh origin (lower left corner) in x direction", false, 0,
162 "ORIGIN_X");
163 cmd.add(originXArg);
164 TCLAP::ValueArg<double> originYArg(
165 "", "oy", "mesh origin (lower left corner) in y direction", false, 0,
166 "ORIGIN_Y");
167 cmd.add(originYArg);
168 TCLAP::ValueArg<double> originZArg(
169 "", "oz", "mesh origin (lower left corner) in z direction", false, 0,
170 "ORIGIN_Z");
171 cmd.add(originZArg);
172
173 // parse arguments
174 auto log_level_arg = BaseLib::makeLogLevelArg();
175 cmd.add(log_level_arg);
176 cmd.parse(argc, argv);
177 BaseLib::MPI::Setup mpi_setup(argc, argv);
178 BaseLib::initOGSLogger(log_level_arg.getValue());
179
180 const std::string eleTypeName(eleTypeArg.getValue());
181 const MeshLib::MeshElemType eleType =
182 MeshLib::String2MeshElemType(eleTypeName);
183 const unsigned dim = getDimension(eleType);
184
185 bool dim_used[3] = {false};
186 for (unsigned i = 0; i < dim; i++)
187 {
188 dim_used[i] = true;
189 }
190
191 std::vector<TCLAP::ValueArg<double>*> vec_lengthArg = {
192 &lengthXArg, &lengthYArg, &lengthZArg};
193 std::vector<TCLAP::ValueArg<unsigned>*> vec_ndivArg = {
194 &nsubdivXArg, &nsubdivYArg, &nsubdivZArg};
195 std::vector<TCLAP::ValueArg<double>*> vec_d0Arg = {&d0XArg, &d0YArg,
196 &d0ZArg};
197 std::vector<TCLAP::ValueArg<double>*> vec_dMaxArg = {&dmaxXArg, &dmaxYArg,
198 &dmaxZArg};
199 std::vector<TCLAP::ValueArg<double>*> vec_multiArg = {
200 &multiXArg, &multiYArg, &multiZArg};
201 MathLib::Point3d const origin(
202 {originXArg.getValue(), originYArg.getValue(), originZArg.getValue()});
203
204 const bool isLengthSet =
205 std::any_of(vec_lengthArg.begin(), vec_lengthArg.end(),
206 [&](TCLAP::ValueArg<double>* arg) { return arg->isSet(); });
207 if (!isLengthSet)
208 {
209 ERR("Missing input: Length information is not provided at all.");
210 return EXIT_FAILURE;
211 }
212 for (unsigned i = 0; i < 3; i++)
213 {
214 if (dim_used[i] && !vec_lengthArg[i]->isSet())
215 {
216 ERR("Missing input: Length for dimension [{:d}] is required but "
217 "missing.",
218 i);
219 return EXIT_FAILURE;
220 }
221 }
222
223 std::vector<double> length(dim);
224 std::vector<unsigned> n_subdivision(dim);
225 std::vector<double> vec_dx(dim);
226 for (unsigned i = 0; i < dim; i++)
227 {
228 length[i] = vec_lengthArg[i]->getValue();
229 n_subdivision[i] = vec_ndivArg[i]->getValue();
230 vec_dx[i] = length[i] / n_subdivision[i];
231 }
232
233 std::vector<std::unique_ptr<BaseLib::ISubdivision>> vec_div;
234 vec_div.reserve(dim);
235 for (unsigned i = 0; i < dim; i++)
236 {
237 if (vec_multiArg[i]->isSet())
238 {
239 if (vec_ndivArg[i]->isSet())
240 {
241 // number of partitions in direction is specified
242 if (vec_d0Arg[i]->isSet())
243 {
244 OGS_FATAL(
245 "Specifying all of --m?, --d?0 and --n? for coordinate "
246 "'?' is not supported.");
247 }
248 vec_div.emplace_back(new BaseLib::GradualSubdivisionFixedNum(
249 length[i], vec_ndivArg[i]->getValue(),
250 vec_multiArg[i]->getValue()));
251 }
252 else
253 {
254 vec_div.emplace_back(new BaseLib::GradualSubdivision(
255 length[i], vec_d0Arg[i]->getValue(),
256 vec_dMaxArg[i]->getValue(), vec_multiArg[i]->getValue()));
257 }
258 }
259 else
260 {
261 vec_div.emplace_back(
262 new BaseLib::UniformSubdivision(length[i], n_subdivision[i]));
263 }
264 }
265
266 // generate a mesh
267 std::unique_ptr<MeshLib::Mesh> mesh;
268 switch (eleType)
269 {
272 *vec_div[0], origin));
273 break;
276 *vec_div[0], *vec_div[1], origin));
277 break;
280 *vec_div[0], *vec_div[1], origin));
281 break;
284 *vec_div[0], *vec_div[1], *vec_div[2], origin));
285 break;
288 length[0], length[1], length[2], n_subdivision[0],
289 n_subdivision[1], n_subdivision[2], origin));
290 break;
293 *vec_div[0], *vec_div[1], *vec_div[2], origin));
294 break;
297 *vec_div[0], *vec_div[1], *vec_div[2], origin));
298 break;
299 default:
300 ERR("Given element type is not supported.");
301 break;
302 }
303
304 if (mesh)
305 {
306 INFO("Mesh created: {:d} nodes, {:d} elements.",
307 mesh->getNumberOfNodes(), mesh->getNumberOfElements());
308
309 // write into a file
311 *(mesh.get()), std::filesystem::path(mesh_out.getValue()));
312 }
313
314 return EXIT_SUCCESS;
315}
#define OGS_FATAL(...)
Definition Error.h:19
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
std::string getValue(std::string const &line, std::string const &val_name, bool is_string)
int main(int argc, char *argv[])
TCLAP::ValueArg< std::string > makeLogLevelArg()
void initOGSLogger(std::string const &log_level)
Definition Logging.cpp:56
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)
MeshElemType String2MeshElemType(const std::string &s)
Given a string of the shortened name of the element type, this returns the corresponding MeshElemType...
Definition MeshEnums.cpp:84
MeshElemType
Types of mesh elements supported by OpenGeoSys. Values are from VTKCellType enum.
Definition MeshEnums.h:37
MeshLib::Mesh * generateLineMesh(const BaseLib::ISubdivision &div, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
MeshLib::Mesh * generateRegularPyramidMesh(const BaseLib::ISubdivision &div_x, const BaseLib::ISubdivision &div_y, const BaseLib::ISubdivision &div_z, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
MeshLib::Mesh * generateRegularTetMesh(const BaseLib::ISubdivision &div_x, const BaseLib::ISubdivision &div_y, const BaseLib::ISubdivision &div_z, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
MeshLib::Mesh * generateRegularQuadMesh(const BaseLib::ISubdivision &div_x, const BaseLib::ISubdivision &div_y, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
MeshLib::Mesh * generateRegularPrismMesh(const double x_length, const double y_length, const double z_length, const std::size_t x_subdivision, const std::size_t y_subdivision, const std::size_t z_subdivision, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
MeshLib::Mesh * generateRegularTriMesh(const BaseLib::ISubdivision &div_x, const BaseLib::ISubdivision &div_y, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
MeshLib::Mesh * generateRegularHexMesh(const BaseLib::ISubdivision &div_x, const BaseLib::ISubdivision &div_y, const BaseLib::ISubdivision &div_z, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
unsigned getDimension(MeshLib::MeshElemType eleType)