OGS
GMSHInterface.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
5
6#include <fstream>
7#include <memory>
8#include <vector>
9
15#include "BaseLib/Algorithm.h"
16#include "BaseLib/FileTools.h"
17#include "BaseLib/Logging.h"
19#include "GeoLib/GEOObjects.h"
20#include "GeoLib/Polygon.h"
23#include "GeoLib/Station.h"
24#include "InfoLib/GitInfo.h"
25
26namespace FileIO
27{
28namespace GMSH
29{
30static std::ostream& operator<<(std::ostream& os,
31 std::vector<GMSHPoint*> const& points)
32{
33 for (auto const* const point : points)
34 {
35 if (point)
36 {
37 os << *point << "\n";
38 }
39 }
40 return os;
41}
42
44 GeoLib::GEOObjects& geo_objs, bool /*include_stations_as_constraints*/,
45 GMSH::MeshDensityAlgorithm const mesh_density_algorithm,
46 double const pnt_density, double const station_density,
47 std::size_t const max_pnts_per_leaf,
48 std::vector<std::string> const& selected_geometries, bool const rotate,
49 bool const keep_preprocessed_geometry)
50 : _n_lines(0),
51 _n_plane_sfc(0),
52 _geo_objs(geo_objs),
53 _selected_geometries(selected_geometries),
54 _rotate(rotate),
55 _keep_preprocessed_geometry(keep_preprocessed_geometry)
56{
57 switch (mesh_density_algorithm)
58 {
61 std::make_unique<GMSH::GMSHFixedMeshDensity>(pnt_density);
62 break;
65 std::make_unique<GMSH::GMSHAdaptiveMeshDensity>(
66 pnt_density, station_density, max_pnts_per_leaf);
67 break;
68 }
69}
70
72{
74 for (auto const* polygon_tree : _polygon_tree_list)
75 {
76 delete polygon_tree;
77 }
78}
79
81{
82 out << "// GMSH input file created by OpenGeoSys "
84 out << "\n\n";
85
86 return writeGMSHInputFile(out) <= 0;
87}
88
90{
91 DBUG("GMSHInterface::writeGMSHInputFile(): get data from GEOObjects.");
92
93 if (_selected_geometries.empty())
94 {
95 return 1;
96 }
97
98 // *** get and merge data from _geo_objs
99 if (_selected_geometries.size() > 1)
100 {
101 _gmsh_geo_name = "GMSHGeometry";
102 if (_geo_objs.mergeGeometries(_selected_geometries, _gmsh_geo_name))
103 {
104 return 2;
105 }
106 }
107 else
108 {
111 }
112
113 auto* merged_pnts(const_cast<std::vector<GeoLib::Point*>*>(
114 _geo_objs.getPointVec(_gmsh_geo_name)));
115 if (!merged_pnts)
116 {
117 ERR("GMSHInterface::writeGMSHInputFile(): Did not found any points.");
118 return 2;
119 }
120
121 if (_rotate)
122 {
123 // Rotate points to the x-y-plane.
125 // Compute inverse rotation matrix to reverse the rotation later on.
126 _inverse_rot_mat.transposeInPlace();
127 }
128 else
129 {
130 // project data on the x-y-plane
131 _inverse_rot_mat = Eigen::Matrix3d::Identity();
132 for (auto pnt : *merged_pnts)
133 {
134 (*pnt)[2] = 0.0;
135 }
136 }
137
138 std::vector<GeoLib::Polyline*> const* merged_plys(
139 _geo_objs.getPolylineVec(_gmsh_geo_name));
140 DBUG("GMSHInterface::writeGMSHInputFile(): Obtained data.");
141
142 if (!merged_plys)
143 {
144 ERR("GMSHInterface::writeGMSHInputFile(): Did not find any polylines.");
145 return 2;
146 }
147
148 // *** compute and insert all intersection points between polylines
149 GeoLib::PointVec& pnt_vec(*const_cast<GeoLib::PointVec*>(
150 _geo_objs.getPointVecObj(_gmsh_geo_name)));
152 pnt_vec, *(const_cast<std::vector<GeoLib::Polyline*>*>(merged_plys)));
153
154 std::vector<GeoLib::Polyline*> polygons;
155 // for each closed polyline add a PolygonWithSegmentMarker object into
156 // polygons
157 for (auto polyline : *merged_plys)
158 {
159 if (!polyline->isClosed())
160 {
161 continue;
162 }
163 polygons.push_back(new GeoLib::PolygonWithSegmentMarker(*polyline));
164 }
165 if (polygons.empty())
166 {
167 OGS_FATAL("GMSHInterface::writeGMSHInputFile(): no polygons found.");
168 }
169 // let the polygon memory management be done by GEOObjects
170 _geo_objs.appendPolylineVec(polygons, _gmsh_geo_name);
171 // create for each polygon a PolygonTree
172 std::transform(
173 polygons.begin(), polygons.end(),
174 std::back_inserter(_polygon_tree_list),
175 [this](auto const& polygon)
176 {
177 return new GMSH::GMSHPolygonTree(
178 dynamic_cast<GeoLib::PolygonWithSegmentMarker*>(polygon),
179 nullptr, _geo_objs, _gmsh_geo_name, *_mesh_density_strategy);
180 });
181 DBUG(
182 "GMSHInterface::writeGMSHInputFile(): Computed topological hierarchy - "
183 "detected {:d} polygons.",
184 _polygon_tree_list.size());
185 // compute topological hierarchy of polygons
187 DBUG(
188 "GMSHInterface::writeGMSHInputFile(): Computed topological hierarchy - "
189 "calculated {:d} polygon trees.",
190 _polygon_tree_list.size());
191
192 // *** Mark in each polygon tree the segments shared by two polygons.
193 for (auto* polygon_tree : _polygon_tree_list)
194 {
195 polygon_tree->markSharedSegments();
196 }
197
198 // *** insert stations and polylines (except polygons) in the appropriate
199 // object of
200 // class GMSHPolygonTree
201 // *** insert stations
202 std::vector<GeoLib::Point*> gmsh_stations{};
203 for (auto const& geometry_name : _selected_geometries)
204 {
205 auto const* stations(_geo_objs.getStationVec(geometry_name));
206 if (stations)
207 {
208 for (auto* station : *stations)
209 {
210 bool found(false);
211 for (auto it(_polygon_tree_list.begin());
212 it != _polygon_tree_list.end() && !found;
213 ++it)
214 {
215 gmsh_stations.emplace_back(new GeoLib::Station(
216 *static_cast<GeoLib::Station*>(station)));
217 if ((*it)->insertStation(gmsh_stations.back()))
218 {
219 found = true;
220 }
221 }
222 }
223 }
224 }
225 std::string gmsh_stations_name(_gmsh_geo_name + "-Stations");
226 if (!gmsh_stations.empty())
227 {
228 _geo_objs.addStationVec(std::move(gmsh_stations), gmsh_stations_name);
229 }
230
231 // *** insert polylines
232 for (auto polyline : *merged_plys)
233 {
234 if (!polyline->isClosed())
235 {
236 for (auto* polygon_tree : _polygon_tree_list)
237 {
238 auto polyline_with_segment_marker =
240 polygon_tree->insertPolyline(polyline_with_segment_marker);
241 }
242 }
243 }
244
245 // *** init mesh density strategies
246 for (auto& polygon_tree : _polygon_tree_list)
247 {
248 polygon_tree->initMeshDensityStrategy();
249 }
250
251 // *** create GMSH data structures
252 const std::size_t n_merged_pnts(merged_pnts->size());
253 _gmsh_pnts.resize(n_merged_pnts);
254 for (std::size_t k(0); k < n_merged_pnts; k++)
255 {
256 _gmsh_pnts[k] = nullptr;
257 }
258 for (auto& polygon_tree : _polygon_tree_list)
259 {
260 polygon_tree->createGMSHPoints(_gmsh_pnts);
261 }
262
263 std::stringstream error_messages;
264 error_messages.precision(std::numeric_limits<double>::max_digits10);
265 for (std::size_t k = 0; k < _gmsh_pnts.size(); ++k)
266 {
267 if (_gmsh_pnts[k] == nullptr)
268 {
269 error_messages
270 << "The point at (" << *(*merged_pnts)[k]
271 << ") is not part of a polyline, and won't be used in the "
272 "meshing as a constraint. If you want to include it in the "
273 "mesh please create a observation/measurement station for "
274 "the point and include it additional in the meshing "
275 "process.\n";
276 }
277 }
278 auto const error_message = error_messages.str();
279 if (!error_message.empty())
280 {
281 OGS_FATAL("{}", error_message);
282 }
283
284 // *** finally write data :-)
286 out << _gmsh_pnts;
287
288 std::size_t pnt_id_offset(_gmsh_pnts.size());
289 for (auto* polygon_tree : _polygon_tree_list)
290 {
291 polygon_tree->writeLineLoop(_n_lines, _n_plane_sfc, out,
293 polygon_tree->writeSubPolygonsAsLineConstraints(_n_lines,
294 _n_plane_sfc - 1, out);
295 polygon_tree->writeLineConstraints(_n_lines, _n_plane_sfc - 1, out);
296 polygon_tree->writeStations(pnt_id_offset, _n_plane_sfc - 1, out);
297 polygon_tree->writeAdditionalPointData(pnt_id_offset, _n_plane_sfc - 1,
298 out);
299 }
300
302 {
303 _geo_objs.removeSurfaceVec(_gmsh_geo_name);
304 _geo_objs.removePolylineVec(_gmsh_geo_name);
305 _geo_objs.removePointVec(_gmsh_geo_name);
306 _geo_objs.removeStationVec(gmsh_stations_name);
307 }
308
309 return 0;
310}
311
312} // end namespace GMSH
313} // end namespace FileIO
#define OGS_FATAL(...)
Definition Error.h:19
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
std::ostringstream out
The stream to write to.
Definition Writer.h:36
GMSHInterface(GeoLib::GEOObjects &geo_objs, bool include_stations_as_constraints, GMSH::MeshDensityAlgorithm mesh_density_algorithm, double pnt_density, double station_density, std::size_t max_pnts_per_leaf, std::vector< std::string > const &selected_geometries, bool rotate, bool keep_preprocessed_geometry)
std::unique_ptr< GMSH::GMSHMeshDensityStrategy > _mesh_density_strategy
Eigen::Matrix3d _inverse_rot_mat
std::vector< GMSH::GMSHPoint * > _gmsh_pnts
int writeGMSHInputFile(std::ostream &out)
std::vector< std::string > const & _selected_geometries
GeoLib::GEOObjects & _geo_objs
bool write() override
Writes the object to the internal stream. This method must be implemented by a subclass....
std::list< GMSH::GMSHPolygonTree * > _polygon_tree_list
Container class for geometric objects.
Definition GEOObjects.h:46
This class manages pointers to Points in a std::vector along with a name. It also handles the deletio...
Definition PointVec.h:25
A Station (observation site) is basically a Point with some additional information.
Definition Station.h:26
void cleanupVectorElements(std::vector< T * > &items)
Definition Algorithm.h:249
@ AdaptiveMeshDensity
computing the mesh density employing a QuadTree
@ FixedMeshDensity
set the parameter with a fixed value
static std::ostream & operator<<(std::ostream &os, std::vector< GMSHPoint * > const &points)
void createPolygonTrees(std::list< POLYGONTREETYPE * > &list_of_simple_polygon_hierarchies)
void computeAndInsertAllIntersectionPoints(GeoLib::PointVec &pnt_vec, std::vector< GeoLib::Polyline * > &plys)
void rotatePoints(Eigen::Matrix3d const &rot_mat, InputIterator pnts_begin, InputIterator pnts_end)
Eigen::Matrix3d rotatePointsToXY(InputIterator1 p_pnts_begin, InputIterator1 p_pnts_end, InputIterator2 r_pnts_begin, InputIterator2 r_pnts_end)
GITINFOLIB_EXPORT const std::string ogs_version