OGS
removeMeshElements.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 <memory>
7
8#include "BaseLib/Logging.h"
9#include "BaseLib/MPI.h"
11#include "InfoLib/GitInfo.h"
15#include "MeshLib/Mesh.h"
16#include "MeshLib/MeshEnums.h"
18#include "MeshLib/Node.h"
21
22template <typename PROPERTY_TYPE>
23void searchByPropertyValue(std::string const& property_name,
24 std::vector<PROPERTY_TYPE> const& property_values,
25 MeshLib::ElementSearch& searcher)
26{
27 for (auto const& property_value : property_values)
28 {
29 std::size_t n_marked_elements = searcher.searchByPropertyValue<double>(
30 property_name, property_value);
31 if (n_marked_elements == 0)
32 {
33 n_marked_elements = searcher.searchByPropertyValue<int>(
34 property_name, property_value);
35 }
36
37 INFO("{:d} elements with property value {:s} found.", n_marked_elements,
38 std::to_string(property_value));
39 }
40}
41
42void searchByPropertyRange(std::string const& property_name,
43 double const& min_value, double const& max_value,
44 bool const& outside,
45 MeshLib::ElementSearch& searcher)
46{
47 std::size_t n_marked_elements = searcher.searchByPropertyValueRange<double>(
48 property_name, min_value, max_value, outside);
49
50 if (n_marked_elements == 0)
51 {
52 n_marked_elements = searcher.searchByPropertyValueRange<int>(
53 property_name, static_cast<int>(min_value),
54 static_cast<int>(max_value), outside);
55 }
56
57 // add checks for other data types here (if n_marked_elements remains 0)
58
59 INFO("{:d} elements in range [{:s}, {:s}] found.", n_marked_elements,
60 std::to_string(min_value), std::to_string(max_value));
61}
62
63void outputAABB(MeshLib::Mesh const& mesh)
64{
66 auto const [min, max] = aabb.getMinMaxPoints();
67
68 INFO(
69 "Bounding box of \"{:s}\" is\nx = [{:f},{:f}]\ny = [{:f},{:f}]\nz = "
70 "[{:f},{:f}]",
71 mesh.getName(), min.x(), max.x(), min.y(), max.y(), min.z(), max.z());
72}
73
74int main(int argc, char* argv[])
75{
76 TCLAP::CmdLine cmd(
77 "Removes mesh elements based on element type, element volume, scalar "
78 "arrays, or bounding box . The documentation is available at "
79 "https://docs.opengeosys.org/docs/tools/meshing/"
80 "remove-mesh-elements.\n\n"
81 "OpenGeoSys-6 software, version " +
83 ".\n"
84 "Copyright (c) 2012-2026, OpenGeoSys Community "
85 "(http://www.opengeosys.org)",
87
88 // Bounding box params
89 TCLAP::SwitchArg invert_bounding_box_arg(
90 "", "invert", "inverts the specified bounding box", false);
91 cmd.add(invert_bounding_box_arg);
92 TCLAP::ValueArg<double> zLargeArg(
93 "", "z-max", "largest allowed extent in z-dimension", false,
94 std::numeric_limits<double>::max(), "MAX_EXTENT_Z");
95 cmd.add(zLargeArg);
96 TCLAP::ValueArg<double> zSmallArg(
97 "", "z-min", "smallest allowed extent in z-dimension", false,
98 -1 * std::numeric_limits<double>::max(), "MIN_EXTENT_Z");
99 cmd.add(zSmallArg);
100 TCLAP::ValueArg<double> yLargeArg(
101 "", "y-max", "largest allowed extent in y-dimension", false,
102 std::numeric_limits<double>::max(), "MAX_EXTENT_Y");
103 cmd.add(yLargeArg);
104 TCLAP::ValueArg<double> ySmallArg(
105 "", "y-min", "smallest allowed extent in y-dimension", false,
106 -1 * std::numeric_limits<double>::max(), "MIN_EXTENT_Y");
107 cmd.add(ySmallArg);
108 TCLAP::ValueArg<double> xLargeArg(
109 "", "x-max", "largest allowed extent in x-dimension", false,
110 std::numeric_limits<double>::max(), "MAX_EXTENT_X");
111 cmd.add(xLargeArg);
112 TCLAP::ValueArg<double> xSmallArg(
113 "", "x-min", "smallest allowed extent in x-dimension", false,
114 -1 * std::numeric_limits<double>::max(), "MIN_EXTENT_X");
115 cmd.add(xSmallArg);
116
117 // Non-bounding-box params
118 TCLAP::SwitchArg zveArg("z", "zero-volume", "remove zero volume elements",
119 false);
120 cmd.add(zveArg);
121
122 std::vector<std::string> allowed_ele_types{
123 "point", "line", "tri", "quad", "hex", "prism", "tet", "pyramid"};
124 TCLAP::ValuesConstraint<std::string> allowedVals{allowed_ele_types};
125 TCLAP::MultiArg<std::string> eleTypeArg(
126 "t", "element-type", "element type to be removed", false, &allowedVals);
127 cmd.add(eleTypeArg);
128
129 // scalar array params
130 TCLAP::ValueArg<std::string> property_name_arg(
131 "n", "property-name", "name of property in the mesh", false,
132 "MaterialIDs", "PROPERTY_NAME");
133 cmd.add(property_name_arg);
134
135 TCLAP::MultiArg<int> property_arg(
136 "", "property-value", "value of selected property to be removed", false,
137 "PROPERTY_VALUE");
138 cmd.add(property_arg);
139
140 TCLAP::ValueArg<double> min_property_arg(
141 "", "min-value", "minimum value of range for selected property", false,
142 0, "MIN_RANGE");
143 cmd.add(min_property_arg);
144
145 TCLAP::ValueArg<double> max_property_arg(
146 "", "max-value", "maximum value of range for selected property", false,
147 0, "MAX_RANGE");
148 cmd.add(max_property_arg);
149
150 TCLAP::SwitchArg outside_property_arg(
151 "", "outside", "remove all elements outside the given property range");
152 cmd.add(outside_property_arg);
153
154 TCLAP::SwitchArg inside_property_arg(
155 "", "inside", "remove all elements inside the given property range");
156 cmd.add(inside_property_arg);
157
158 // I/O params
159 TCLAP::ValueArg<std::string> mesh_out(
160 "o", "mesh-output-file",
161 "Output (.vtu). The name of the file the mesh will be written to", true,
162 "", "OUTPUT_FILE");
163 cmd.add(mesh_out);
164 TCLAP::ValueArg<std::string> mesh_in(
165 "i", "mesh-input-file",
166 "Input (.vtu). The name of the file containing the input mesh", true,
167 "", "INPUT_FILE");
168 cmd.add(mesh_in);
169 auto log_level_arg = BaseLib::makeLogLevelArg();
170 cmd.add(log_level_arg);
171 cmd.parse(argc, argv);
172
173 BaseLib::MPI::Setup mpi_setup(argc, argv);
174 BaseLib::initOGSLogger(log_level_arg.getValue());
175
176 std::unique_ptr<MeshLib::Mesh const> mesh(
177 MeshLib::IO::readMeshFromFile(mesh_in.getValue()));
178 if (mesh == nullptr)
179 {
180 return EXIT_FAILURE;
181 }
182
183 INFO("Mesh read: {:d} nodes, {:d} elements.", mesh->getNumberOfNodes(),
184 mesh->getNumberOfElements());
185 MeshLib::ElementSearch searcher(*mesh);
186
187 // search elements IDs to be removed
188 if (zveArg.isSet())
189 {
190 INFO("{:d} zero volume elements found.", searcher.searchByContent());
191 }
192 if (eleTypeArg.isSet())
193 {
194 const std::vector<std::string> eleTypeNames = eleTypeArg.getValue();
195 for (const auto& typeName : eleTypeNames)
196 {
197 const MeshLib::MeshElemType type =
200 {
201 continue;
202 }
203 INFO("{:d} {:s} elements found.",
204 searcher.searchByElementType(type), typeName);
205 }
206 }
207
208 if (property_name_arg.isSet() || property_arg.isSet() ||
209 min_property_arg.isSet() || max_property_arg.isSet())
210 {
211 if ((property_arg.isSet() || min_property_arg.isSet() ||
212 max_property_arg.isSet()) &&
213 !property_name_arg.isSet())
214 {
215 ERR("Specify a property name for the value/range selected.");
216 return EXIT_FAILURE;
217 }
218
219 if (property_name_arg.isSet() &&
220 !((min_property_arg.isSet() && max_property_arg.isSet()) ||
221 property_arg.isSet()))
222 {
223 ERR("Specify a value or range ('-min-value' and '-max_value') for "
224 "the property selected.");
225 return EXIT_FAILURE;
226 }
227
228 // name + value
229 if (property_arg.isSet() && property_name_arg.isSet())
230 {
231 searchByPropertyValue(property_name_arg.getValue(),
232 property_arg.getValue(), searcher);
233 }
234
235 // name + range
236 if (property_name_arg.isSet() && min_property_arg.isSet() &&
237 max_property_arg.isSet())
238 {
239 if ((!outside_property_arg.isSet() &&
240 !inside_property_arg.isSet()) ||
241 (outside_property_arg.isSet() && inside_property_arg.isSet()))
242 {
243 ERR("Specify if the inside or the outside of the selected "
244 "range should be removed.");
245 return EXIT_FAILURE;
246 }
247
248 bool const outside = outside_property_arg.isSet();
250 property_name_arg.getValue(), min_property_arg.getValue(),
251 max_property_arg.getValue(), outside, searcher);
252 }
253 }
254
255 if (xSmallArg.isSet() || xLargeArg.isSet() || ySmallArg.isSet() ||
256 yLargeArg.isSet() || zSmallArg.isSet() || zLargeArg.isSet())
257 {
258 outputAABB(*mesh);
259 bool aabb_error(false);
260 if (xSmallArg.getValue() >= xLargeArg.getValue())
261 {
262 ERR("Minimum x-extent larger than maximum x-extent.");
263 aabb_error = true;
264 }
265 if (ySmallArg.getValue() >= yLargeArg.getValue())
266 {
267 ERR("Minimum y-extent larger than maximum y-extent.");
268 aabb_error = true;
269 }
270 if (zSmallArg.getValue() >= zLargeArg.getValue())
271 {
272 ERR("Minimum z-extent larger than maximum z-extent.");
273 aabb_error = true;
274 }
275 if (aabb_error)
276 {
277 return EXIT_FAILURE;
278 }
279
280 std::array<MathLib::Point3d, 2> extent(
281 {{MathLib::Point3d(std::array<double, 3>{{xSmallArg.getValue(),
282 ySmallArg.getValue(),
283 zSmallArg.getValue()}}),
284 MathLib::Point3d(std::array<double, 3>{
285 {xLargeArg.getValue(), yLargeArg.getValue(),
286 zLargeArg.getValue()}})}});
287 INFO("{:d} elements found.",
288 searcher.searchByBoundingBox(
289 GeoLib::AABB(extent.begin(), extent.end()),
290 invert_bounding_box_arg.getValue()));
291 }
292
293 // remove the elements and create a new mesh object.
294 std::unique_ptr<MeshLib::Mesh const> new_mesh(MeshToolsLib::removeElements(
295 *mesh, searcher.getSearchedElementIDs(), mesh->getName()));
296
297 if (new_mesh == nullptr)
298 {
299 return EXIT_FAILURE;
300 }
301
302 // write into a file
303 MeshLib::IO::writeMeshToFile(*new_mesh, mesh_out.getValue());
304
305 return EXIT_SUCCESS;
306}
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
Class AABB is an axis aligned bounding box around a given set of geometric points of (template) type ...
Definition AABB.h:45
Element search class.
std::size_t searchByBoundingBox(GeoLib::AABB const &aabb, bool const invert=false)
const std::vector< std::size_t > & getSearchedElementIDs() const
return marked elements
std::size_t searchByElementType(MeshElemType eleType)
Marks all elements of the given element type.
std::size_t searchByPropertyValueRange(std::string const &property_name, PROPERTY_TYPE const min_property_value, PROPERTY_TYPE const max_property_value, bool outside_of)
std::size_t searchByContent(double eps=std::numeric_limits< double >::epsilon())
Marks all elements with a volume smaller than eps.
std::size_t searchByPropertyValue(std::string const &property_name, PROPERTY_TYPE const property_value)
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:94
static GeoLib::AABB getBoundingBox(const MeshLib::Mesh &mesh)
Returns the bounding box of the mesh.
TCLAP::ValueArg< std::string > makeLogLevelArg()
void initOGSLogger(std::string const &log_level)
Definition Logging.cpp:56
GITINFOLIB_EXPORT const std::string ogs_version
MeshLib::Mesh * readMeshFromFile(const std::string &file_name, bool const compute_element_neighbors)
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 * removeElements(const MeshLib::Mesh &mesh, const std::vector< std::size_t > &removed_element_ids, const std::string &new_mesh_name)
int main(int argc, char *argv[])
void outputAABB(MeshLib::Mesh const &mesh)
void searchByPropertyValue(std::string const &property_name, std::vector< PROPERTY_TYPE > const &property_values, MeshLib::ElementSearch &searcher)
void searchByPropertyRange(std::string const &property_name, double const &min_value, double const &max_value, bool const &outside, MeshLib::ElementSearch &searcher)