OGS
MeshToolsLib::MeshLayerMapper Class Referencefinal

Detailed Description

Manipulating and adding prism element layers to an existing 2D mesh.

Definition at line 25 of file MeshLayerMapper.h.

#include <MeshLayerMapper.h>

Inheritance diagram for MeshToolsLib::MeshLayerMapper:
[legend]
Collaboration diagram for MeshToolsLib::MeshLayerMapper:
[legend]

Public Member Functions

 ~MeshLayerMapper () override=default
 
bool createRasterLayers (MeshLib::Mesh const &mesh, std::vector< GeoLib::Raster const * > const &rasters, double minimum_thickness, double noDataReplacementValue=0.0) override
 
- Public Member Functions inherited from LayeredMeshGenerator
virtual bool createLayers (MeshLib::Mesh const &mesh, std::vector< GeoLib::Raster const * > const &rasters, double minimum_thickness, double noDataReplacementValue=0.0) final
 
std::unique_ptr< MeshLib::MeshgetMesh (std::string const &mesh_name) const
 Returns a mesh of the subsurface representation.
 

Static Public Member Functions

static MeshLib::MeshcreateStaticLayers (MeshLib::Mesh const &mesh, std::vector< float > const &layer_thickness_vector, std::string const &mesh_name="SubsurfaceMesh")
 
static bool layerMapping (MeshLib::Mesh const &mesh, const GeoLib::Raster &raster, double nodata_replacement=0.0, bool const ignore_nodata=false)
 
static bool mapToStaticValue (MeshLib::Mesh const &mesh, double value)
 Maps the elevation of all mesh nodes to the specified static value.
 

Private Member Functions

void addLayerToMesh (const MeshLib::Mesh &dem_mesh, unsigned layer_id, GeoLib::Raster const &raster) override
 Adds another layer to a subsurface mesh.
 

Additional Inherited Members

- Protected Member Functions inherited from LayeredMeshGenerator
 LayeredMeshGenerator ()=default
 
virtual ~LayeredMeshGenerator ()=default
 
MeshLib::NodegetNewLayerNode (MeshLib::Node const &dem_node, MeshLib::Node const &last_layer_node, GeoLib::Raster const &raster, std::size_t new_node_id) const
 
- Static Protected Member Functions inherited from LayeredMeshGenerator
static double calcEpsilon (GeoLib::Raster const &low, GeoLib::Raster const &high)
 Calculates a data-dependent epsilon value.
 
- Protected Attributes inherited from LayeredMeshGenerator
double _elevation_epsilon {0.0001}
 
double _minimum_thickness {std::numeric_limits<float>::epsilon()}
 
std::vector< int > _materials
 
std::vector< MeshLib::Node * > _nodes
 
std::vector< MeshLib::Element * > _elements
 

Constructor & Destructor Documentation

◆ ~MeshLayerMapper()

MeshToolsLib::MeshLayerMapper::~MeshLayerMapper ( )
overridedefault

Member Function Documentation

◆ addLayerToMesh()

void MeshToolsLib::MeshLayerMapper::addLayerToMesh ( const MeshLib::Mesh & dem_mesh,
unsigned layer_id,
GeoLib::Raster const & raster )
overrideprivatevirtual

Adds another layer to a subsurface mesh.

Implements LayeredMeshGenerator.

Definition at line 199 of file MeshLayerMapper.cpp.

202{
203 const unsigned pyramid_base[3][4] = {
204 {1, 3, 4, 2}, // Point 4 missing
205 {2, 4, 3, 0}, // Point 5 missing
206 {0, 3, 4, 1}, // Point 6 missing
207 };
208
209 std::size_t const nNodes = dem_mesh.getNumberOfNodes();
210 std::vector<MeshLib::Node*> const& top_nodes = dem_mesh.getNodes();
211 int const last_layer_node_offset = layer_id * nNodes;
212
213 // add nodes for new layer
214 for (std::size_t i = 0; i < nNodes; ++i)
215 {
216 _nodes.push_back(getNewLayerNode(*top_nodes[i],
217 *_nodes[last_layer_node_offset + i],
218 raster, _nodes.size()));
219 }
220
221 std::vector<MeshLib::Element*> const& elems = dem_mesh.getElements();
222 std::size_t const nElems(dem_mesh.getNumberOfElements());
223
224 for (std::size_t i = 0; i < nElems; ++i)
225 {
226 MeshLib::Element* elem(elems[i]);
227 if (elem->getGeomType() != MeshLib::MeshElemType::TRIANGLE)
228 {
229 continue;
230 }
231 unsigned node_counter(3);
232 unsigned missing_idx(0);
233 std::array<MeshLib::Node*, 6> new_elem_nodes{};
234 for (unsigned j = 0; j < 3; ++j)
235 {
236 new_elem_nodes[j] =
237 _nodes[_nodes[last_layer_node_offset + getNodeIndex(*elem, j)]
238 ->getID()];
239 new_elem_nodes[node_counter] =
240 (_nodes[last_layer_node_offset + getNodeIndex(*elem, j) +
241 nNodes]);
242 if (new_elem_nodes[j]->getID() !=
243 new_elem_nodes[node_counter]->getID())
244 {
245 node_counter++;
246 }
247 else
248 {
249 missing_idx = j;
250 }
251 }
252
253 switch (node_counter)
254 {
255 case 6:
256 _elements.push_back(new MeshLib::Prism(new_elem_nodes));
257 _materials.push_back(layer_id);
258 break;
259 case 5:
260 {
261 std::array<MeshLib::Node*, 5> pyramid_nodes{};
262 pyramid_nodes[0] = new_elem_nodes[pyramid_base[missing_idx][0]];
263 pyramid_nodes[1] = new_elem_nodes[pyramid_base[missing_idx][1]];
264 pyramid_nodes[2] = new_elem_nodes[pyramid_base[missing_idx][2]];
265 pyramid_nodes[3] = new_elem_nodes[pyramid_base[missing_idx][3]];
266 pyramid_nodes[4] = new_elem_nodes[missing_idx];
267 _elements.push_back(new MeshLib::Pyramid(pyramid_nodes));
268 _materials.push_back(layer_id);
269 break;
270 }
271 case 4:
272 {
273 std::array<MeshLib::Node*, 4> tet_nodes{};
274 std::copy(new_elem_nodes.begin(),
275 new_elem_nodes.begin() + node_counter,
276 tet_nodes.begin());
277 _elements.push_back(new MeshLib::Tet(tet_nodes));
278 _materials.push_back(layer_id);
279 break;
280 }
281 default:
282 continue;
283 }
284 }
285}
std::vector< int > _materials
MeshLib::Node * getNewLayerNode(MeshLib::Node const &dem_node, MeshLib::Node const &last_layer_node, GeoLib::Raster const &raster, std::size_t new_node_id) const
std::vector< MeshLib::Node * > _nodes
std::vector< MeshLib::Element * > _elements
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition Mesh.h:106
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:109
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition Mesh.h:100
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:97
std::size_t getNodeIndex(Element const &element, unsigned const idx)
Definition Element.cpp:219

References LayeredMeshGenerator::_elements, LayeredMeshGenerator::_materials, LayeredMeshGenerator::_nodes, MeshLib::Mesh::getElements(), MeshLib::Element::getGeomType(), LayeredMeshGenerator::getNewLayerNode(), MeshLib::Mesh::getNodes(), MeshLib::Mesh::getNumberOfElements(), MeshLib::Mesh::getNumberOfNodes(), and MeshLib::TRIANGLE.

Referenced by createRasterLayers().

◆ createRasterLayers()

bool MeshToolsLib::MeshLayerMapper::createRasterLayers ( MeshLib::Mesh const & mesh,
std::vector< GeoLib::Raster const * > const & rasters,
double minimum_thickness,
double noDataReplacementValue = 0.0 )
overridevirtual

Based on a 2D triangle mesh this method creates a 3D mesh with a given number of prism-layers. Note: While this method would technically also work with quad meshes, this is discouraged as quad elements will most likely not be coplanar after the mapping process which result in invaled mesh elements.

Parameters
meshThe 2D triangle mesh that is the basis for the new 3D prism mesh
rastersContaining all the raster-data for the subsurface layers from bottom to top (starting with the bottom of the oldest layer and ending with the DEM)
minimum_thicknessMinimum thickness of each of the newly created layers (i.e. nodes with a vertical distance smaller than this will be collapsed)
noDataReplacementValueDefault z-coordinate if there are mesh nodes not located on the DEM raster (i.e. raster_paths[0])
Returns
A mesh with the requested number of layers of prism elements (also including Tet- & Pyramid-elements in case of degenerated prisms)

Implements LayeredMeshGenerator.

Definition at line 147 of file MeshLayerMapper.cpp.

152{
153 const std::size_t nLayers(rasters.size());
154 if (nLayers < 2 || mesh.getDimension() != 2)
155 {
156 ERR("MeshLayerMapper::createRasterLayers(): A 2D mesh and at least two "
157 "rasters required as input.");
158 return false;
159 }
160
161 auto top = std::make_unique<MeshLib::Mesh>(mesh);
162 if (!layerMapping(*top, *rasters.back(), noDataReplacementValue))
163 {
164 return false;
165 }
166
167 auto bottom = std::make_unique<MeshLib::Mesh>(mesh);
168 if (!layerMapping(*bottom, *rasters[0], 0))
169 {
170 return false;
171 }
172
173 this->_minimum_thickness = minimum_thickness;
174 std::size_t const nNodes = mesh.getNumberOfNodes();
175 _nodes.reserve(nLayers * nNodes);
176
177 // number of triangles in the original mesh
178 std::size_t const nElems(std::count_if(
179 mesh.getElements().begin(), mesh.getElements().end(),
180 [](MeshLib::Element const* elem)
181 { return (elem->getGeomType() == MeshLib::MeshElemType::TRIANGLE); }));
182 _elements.reserve(nElems * (nLayers - 1));
183 _materials.reserve(nElems * (nLayers - 1));
184
185 // add bottom layer
186 std::vector<MeshLib::Node*> const& nodes = bottom->getNodes();
187 std::transform(nodes.begin(), nodes.end(), std::back_inserter(_nodes),
188 [](auto const* node) { return new MeshLib::Node(*node); });
189
190 // add the other layers
191 for (std::size_t i = 0; i < nLayers - 1; ++i)
192 {
193 addLayerToMesh(*top, i, *rasters[i + 1]);
194 }
195
196 return true;
197}
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:45
void addLayerToMesh(const MeshLib::Mesh &dem_mesh, unsigned layer_id, GeoLib::Raster const &raster) override
Adds another layer to a subsurface mesh.
static bool layerMapping(MeshLib::Mesh const &mesh, const GeoLib::Raster &raster, double nodata_replacement=0.0, bool const ignore_nodata=false)

References LayeredMeshGenerator::_elements, LayeredMeshGenerator::_materials, LayeredMeshGenerator::_minimum_thickness, LayeredMeshGenerator::_nodes, addLayerToMesh(), ERR(), MeshLib::Mesh::getDimension(), MeshLib::Mesh::getElements(), MeshLib::Mesh::getNumberOfNodes(), and layerMapping().

◆ createStaticLayers()

MeshLib::Mesh * MeshToolsLib::MeshLayerMapper::createStaticLayers ( MeshLib::Mesh const & mesh,
std::vector< float > const & layer_thickness_vector,
std::string const & mesh_name = "SubsurfaceMesh" )
static

Based on a 2D triangle-or quad mesh this method creates a 3D mesh with a given number of prism- or hex-layers

Parameters
meshThe triangle/quad mesh that is the basis for the new prism/hex mesh
layer_thickness_vectorThe size of the vector equals the number of layers of prism/hex elements that will be extruded from the triangle/quad elements of the original mesh. The thickness of the \(i\)-th layer corresponds to the \(i\) entry of the vector.
mesh_nameThe name of the newly created mesh
Returns
A mesh with the requested number of layers of prism/hex elements

Definition at line 31 of file MeshLayerMapper.cpp.

34{
35 std::vector<float> thickness;
36 for (std::size_t i = 0; i < layer_thickness_vector.size(); ++i)
37 {
38 if (layer_thickness_vector[i] > std::numeric_limits<float>::epsilon())
39 {
40 thickness.push_back(layer_thickness_vector[i]);
41 }
42 else
43 {
44 WARN("Ignoring layer {:d} with thickness {:f}.", i,
45 layer_thickness_vector[i]);
46 }
47 }
48
49 const std::size_t nLayers(thickness.size());
50 if (nLayers < 1 || mesh.getDimension() != 2)
51 {
52 ERR("MeshLayerMapper::createStaticLayers(): A 2D mesh with nLayers > 0 "
53 "is required as input.");
54 return nullptr;
55 }
56
57 const std::size_t nNodes = mesh.getNumberOfNodes();
58 // count number of 2d elements in the original mesh
59 const std::size_t nElems(
60 std::count_if(mesh.getElements().begin(), mesh.getElements().end(),
61 [](MeshLib::Element const* elem)
62 { return (elem->getDimension() == 2); }));
63
64 const std::size_t nOrgElems(mesh.getNumberOfElements());
65 const std::vector<MeshLib::Node*>& nodes = mesh.getNodes();
66 const std::vector<MeshLib::Element*>& elems = mesh.getElements();
67 std::vector<MeshLib::Node*> new_nodes(nNodes + (nLayers * nNodes));
68 std::vector<MeshLib::Element*> new_elems;
69 new_elems.reserve(nElems * nLayers);
70 MeshLib::Properties properties;
71 auto* const materials = properties.createNewPropertyVector<int>(
72 "MaterialIDs", MeshLib::MeshItemType::Cell);
73 if (!materials)
74 {
75 ERR("Could not create PropertyVector object 'MaterialIDs'.");
76 return nullptr;
77 }
78
79 materials->reserve(nElems * nLayers);
80 double z_offset(0.0);
81
82 for (unsigned layer_id = 0; layer_id <= nLayers; ++layer_id)
83 {
84 // add nodes for new layer
85 unsigned node_offset(nNodes * layer_id);
86 if (layer_id > 0)
87 {
88 z_offset += thickness[layer_id - 1];
89 }
90
91 std::transform(nodes.cbegin(), nodes.cend(),
92 new_nodes.begin() + node_offset,
93 [&z_offset](MeshLib::Node* node) {
94 return new MeshLib::Node((*node)[0], (*node)[1],
95 (*node)[2] - z_offset);
96 });
97
98 // starting with 2nd layer create prism or hex elements connecting the
99 // last layer with the current one
100 if (layer_id == 0)
101 {
102 continue;
103 }
104
105 node_offset -= nNodes;
106 const unsigned mat_id(nLayers - layer_id);
107
108 for (unsigned i = 0; i < nOrgElems; ++i)
109 {
110 const MeshLib::Element* sfc_elem(elems[i]);
111 if (sfc_elem->getDimension() < 2)
112 { // ignore line-elements
113 continue;
114 }
115
116 const unsigned nElemNodes(sfc_elem->getNumberOfBaseNodes());
117 auto** e_nodes = new MeshLib::Node*[2 * nElemNodes];
118
119 for (unsigned j = 0; j < nElemNodes; ++j)
120 {
121 const unsigned node_id =
122 sfc_elem->getNode(j)->getID() + node_offset;
123 e_nodes[j] = new_nodes[node_id + nNodes];
124 e_nodes[j + nElemNodes] = new_nodes[node_id];
125 }
126 if (sfc_elem->getGeomType() == MeshLib::MeshElemType::TRIANGLE)
127 {
128 // extrude triangles to prism
129 new_elems.push_back(new MeshLib::Prism(e_nodes));
130 }
131 else if (sfc_elem->getGeomType() == MeshLib::MeshElemType::QUAD)
132 {
133 // extrude quads to hexes
134 new_elems.push_back(new MeshLib::Hex(e_nodes));
135 }
136 else
137 {
138 OGS_FATAL("MeshLayerMapper: Unknown element type to extrude.");
139 }
140 materials->push_back(mat_id);
141 }
142 }
143 return new MeshLib::Mesh(mesh_name, new_nodes, new_elems,
144 true /* compute_element_neighbors */, properties);
145}
#define OGS_FATAL(...)
Definition Error.h:26
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
std::size_t getID() const
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
Definition Properties.h:36
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)

References MeshLib::Cell, MeshLib::Properties::createNewPropertyVector(), ERR(), MeshLib::Element::getDimension(), MeshLib::Mesh::getDimension(), MeshLib::Mesh::getElements(), MeshLib::Element::getGeomType(), MathLib::Point3dWithID::getID(), MeshLib::Element::getNode(), MeshLib::Mesh::getNodes(), MeshLib::Element::getNumberOfBaseNodes(), MeshLib::Mesh::getNumberOfElements(), MeshLib::Mesh::getNumberOfNodes(), OGS_FATAL, MeshLib::QUAD, MeshLib::TRIANGLE, and WARN().

Referenced by MeshLayerEditDialog::createPrismMesh(), and MeshLayerEditDialog::createTetMesh().

◆ layerMapping()

bool MeshToolsLib::MeshLayerMapper::layerMapping ( MeshLib::Mesh const & mesh,
const GeoLib::Raster & raster,
double nodata_replacement = 0.0,
bool const ignore_nodata = false )
static

Maps the elevation of nodes of a given 2D mesh according to the raster. At locations where no information is given, node elevation is set to noDataReplacementValue.

Definition at line 287 of file MeshLayerMapper.cpp.

291{
292 if (mesh.getDimension() != 2)
293 {
294 ERR("MshLayerMapper::layerMapping() - requires 2D mesh");
295 return false;
296 }
297
298 GeoLib::RasterHeader const& header(raster.getHeader());
299 const double x0(header.origin[0]);
300 const double y0(header.origin[1]);
301 const double delta(header.cell_size);
302
303 const std::pair<double, double> xDim(
304 x0, x0 + header.n_cols * delta); // extension in x-dimension
305 const std::pair<double, double> yDim(
306 y0, y0 + header.n_rows * delta); // extension in y-dimension
307
308 const std::size_t nNodes(mesh.getNumberOfNodes());
309 const std::vector<MeshLib::Node*>& nodes = mesh.getNodes();
310 for (unsigned i = 0; i < nNodes; ++i)
311 {
312 if (!ignore_nodata && !raster.isPntOnRaster(*nodes[i]))
313 {
314 // use either default value or elevation from layer above
315 (*nodes[i])[2] = nodata_replacement;
316 continue;
317 }
318
319 double elevation(raster.getValueAtPoint(*nodes[i]));
320 constexpr double eps = std::numeric_limits<double>::epsilon();
321 if (std::abs(elevation - header.no_data) < eps)
322 {
323 if (ignore_nodata)
324 {
325 continue;
326 }
327 elevation = nodata_replacement;
328 }
329 else
330 {
331 elevation = raster.interpolateValueAtPoint(*nodes[i]);
332 }
333 (*nodes[i])[2] = elevation;
334 }
335
336 return true;
337}
double getValueAtPoint(const MathLib::Point3d &pnt) const
Definition Raster.cpp:56
bool isPntOnRaster(MathLib::Point3d const &pnt) const
Definition Raster.cpp:151
double interpolateValueAtPoint(const MathLib::Point3d &pnt) const
Definition Raster.cpp:85
RasterHeader const & getHeader() const
Returns the complete header information.
Definition Raster.h:85
Contains the relevant information when storing a geoscientific raster data.
Definition Raster.h:28

References GeoLib::RasterHeader::cell_size, ERR(), MeshLib::Mesh::getDimension(), GeoLib::Raster::getHeader(), MeshLib::Mesh::getNodes(), MeshLib::Mesh::getNumberOfNodes(), GeoLib::Raster::getValueAtPoint(), GeoLib::Raster::interpolateValueAtPoint(), GeoLib::Raster::isPntOnRaster(), GeoLib::RasterHeader::n_cols, GeoLib::RasterHeader::n_rows, GeoLib::RasterHeader::no_data, and GeoLib::RasterHeader::origin.

Referenced by LayeredVolume::createRasterLayers(), createRasterLayers(), main(), and MeshView::openMap2dMeshDialog().

◆ mapToStaticValue()

bool MeshToolsLib::MeshLayerMapper::mapToStaticValue ( MeshLib::Mesh const & mesh,
double value )
static

Maps the elevation of all mesh nodes to the specified static value.

Definition at line 339 of file MeshLayerMapper.cpp.

341{
342 if (mesh.getDimension() != 2)
343 {
344 ERR("MshLayerMapper::mapToStaticValue() - requires 2D mesh");
345 return false;
346 }
347
348 std::vector<MeshLib::Node*> const& nodes(mesh.getNodes());
349 for (MeshLib::Node* node : nodes)
350 {
351 (*node)[2] = value;
352 }
353 return true;
354}

References ERR(), MeshLib::Mesh::getDimension(), and MeshLib::Mesh::getNodes().

Referenced by main(), and MeshView::openMap2dMeshDialog().


The documentation for this class was generated from the following files: