OGS
AddLayerToMesh.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 "AddLayerToMesh.h"
5
6#include <algorithm>
7#include <map>
8#include <memory>
9#include <numeric>
10#include <range/v3/algorithm/max_element.hpp>
11#include <range/v3/view/any_view.hpp>
12#include <range/v3/view/common.hpp>
13#include <range/v3/view/concat.hpp>
14#include <range/v3/view/iota.hpp>
15#include <range/v3/view/repeat_n.hpp>
16#include <vector>
17
18#include "BaseLib/Logging.h"
19#include "FlipElements.h"
21#include "MeshLib/Mesh.h"
22#include "MeshLib/Node.h"
25
26namespace MeshToolsLib
27{
42 std::vector<MeshLib::Node*> const& subsfc_nodes,
43 MeshLib::Element const& sfc_elem,
44 MeshLib::PropertyVector<std::size_t> const& sfc_to_subsfc_id_map,
45 std::map<std::size_t, std::size_t> const& subsfc_sfc_id_map)
46{
47 if (sfc_elem.getDimension() > 2)
48 {
49 return nullptr;
50 }
51
52 const unsigned nElemNodes(sfc_elem.getNumberOfBaseNodes());
53 auto new_nodes =
54 std::unique_ptr<MeshLib::Node*[]>{new MeshLib::Node*[2 * nElemNodes]};
55
56 for (unsigned j = 0; j < nElemNodes; ++j)
57 {
58 std::size_t const subsfc_id(
59 sfc_to_subsfc_id_map[sfc_elem.getNode(j)->getID()]);
60 new_nodes[j] = subsfc_nodes[subsfc_id];
61 std::size_t new_idx = (nElemNodes == 2) ? (3 - j) : (nElemNodes + j);
62 new_nodes[new_idx] = subsfc_nodes[subsfc_sfc_id_map.at(subsfc_id)];
63 }
64
66 {
67 return new MeshLib::Quad(new_nodes.release());
68 }
70 {
71 return new MeshLib::Prism(new_nodes.release());
72 }
74 {
75 return new MeshLib::Hex(new_nodes.release());
76 }
77
78 return nullptr;
79}
80
81MeshLib::Mesh* addLayerToMesh(MeshLib::Mesh const& mesh, double const thickness,
82 std::string const& name, bool const on_top,
83 bool const copy_material_ids,
84 std::optional<int> const layer_id)
85{
86 INFO("Extracting top surface of mesh '{:s}' ... ", mesh.getName());
87 double const flag = on_top ? -1.0 : 1.0;
88 Eigen::Vector3d const dir({0, 0, flag});
89 double const angle(90);
90 std::unique_ptr<MeshLib::Mesh> sfc_mesh(nullptr);
91
92 auto const prop_name =
94
95 if (mesh.getDimension() == 3)
96 {
98 mesh, dir, angle, prop_name));
99 }
100 else
101 {
102 sfc_mesh = (on_top) ? std::make_unique<MeshLib::Mesh>(mesh)
103 : std::unique_ptr<MeshLib::Mesh>(
105 // add property storing node ids
106 auto* const pv =
107 sfc_mesh->getProperties().createNewPropertyVector<std::size_t>(
109 sfc_mesh->getNumberOfNodes(), 1);
110 if (pv)
111 {
112 pv->assign(ranges::views::iota(0u, sfc_mesh->getNumberOfNodes()));
113 }
114 else
115 {
116 ERR("Could not create and initialize property '{}'.", prop_name);
117 return nullptr;
118 }
119 }
120 INFO("done.");
121
122 // *** add new surface nodes
123 std::vector<MeshLib::Node*> subsfc_nodes =
125 std::vector<MeshLib::Element*> subsfc_elements =
126 MeshLib::copyElementVector(mesh.getElements(), subsfc_nodes);
127
128 std::size_t const n_subsfc_nodes(subsfc_nodes.size());
129
130 std::vector<MeshLib::Node*> const& sfc_nodes(sfc_mesh->getNodes());
131 std::size_t const n_sfc_nodes(sfc_nodes.size());
132
133 if (!sfc_mesh->getProperties().existsPropertyVector<std::size_t>(prop_name))
134 {
135 ERR("Need subsurface node ids, but the property '{:s}' is not "
136 "available.",
137 prop_name);
138 return nullptr;
139 }
140 // fetch subsurface node ids PropertyVector
141 auto const* const node_id_pv =
142 sfc_mesh->getProperties().getPropertyVector<std::size_t>(prop_name);
143
144 // *** copy sfc nodes to subsfc mesh node
145 std::map<std::size_t, std::size_t> subsfc_sfc_id_map;
146 for (std::size_t k(0); k < n_sfc_nodes; ++k)
147 {
148 std::size_t const subsfc_id((*node_id_pv)[k]);
149 std::size_t const sfc_id(k + n_subsfc_nodes);
150 subsfc_sfc_id_map.insert(std::make_pair(subsfc_id, sfc_id));
151 MeshLib::Node const& node(*sfc_nodes[k]);
152 subsfc_nodes.push_back(new MeshLib::Node(
153 node[0], node[1], node[2] - (flag * thickness), sfc_id));
154 }
155
156 // *** insert new layer elements into subsfc_mesh
157 std::vector<MeshLib::Element*> const& sfc_elements(sfc_mesh->getElements());
158 std::size_t const n_sfc_elements(sfc_elements.size());
159 for (std::size_t k(0); k < n_sfc_elements; ++k)
160 {
161 subsfc_elements.push_back(extrudeElement(
162 subsfc_nodes, *sfc_elements[k], *node_id_pv, subsfc_sfc_id_map));
163 }
164
165 auto new_mesh = new MeshLib::Mesh(name, subsfc_nodes, subsfc_elements,
166 true /* compute_element_neighbors */);
167
168 if (!mesh.getProperties().existsPropertyVector<int>("MaterialIDs"))
169 {
170 ERR("Could not copy the property 'MaterialIDs' since the original mesh "
171 "does not contain such a property.");
172 return new_mesh;
173 }
174 auto const* const materials =
175 mesh.getProperties().getPropertyVector<int>("MaterialIDs");
176
177 auto* const new_materials =
178 new_mesh->getProperties().createNewPropertyVector<int>(
179 "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
180 if (!new_materials)
181 {
182 ERR("Can not set material properties for new layer");
183 return new_mesh;
184 }
185
186 int next_material_id = 0; // default, if materials are not available.
187
188 if (materials != nullptr)
189 {
190 next_material_id = *ranges::max_element(*materials) + 1;
191 }
192
193 auto initial_values =
194 materials ? ranges::any_view<int const>{*materials}
195 : ranges::views::repeat_n(layer_id.value_or(next_material_id),
196 mesh.getNumberOfElements());
197
198 auto additional_values = [&]() -> ranges::any_view<int const>
199 {
200 if (copy_material_ids &&
201 sfc_mesh->getProperties().existsPropertyVector<int>("MaterialIDs"))
202 {
203 return ranges::any_view<int const>{
204 *sfc_mesh->getProperties().getPropertyVector<int>(
205 "MaterialIDs")};
206 }
207 else
208 {
209 int const new_layer_id = layer_id.value_or(next_material_id);
210 auto const n_new_props =
211 subsfc_elements.size() - mesh.getNumberOfElements();
212 return ranges::views::repeat_n(new_layer_id, n_new_props);
213 }
214 }();
215
216 new_materials->assign(ranges::views::common(
217 ranges::views::concat(initial_values, additional_values)));
218 return new_mesh;
219}
220
221} // namespace MeshToolsLib
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::size_t getID() const
virtual MeshElemType getGeomType() const =0
virtual unsigned getNumberOfBaseNodes() const =0
virtual const Node * getNode(unsigned idx) const =0
virtual constexpr unsigned getDimension() const =0
Get dimension of the mesh element.
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
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition Mesh.h:79
Properties & getProperties()
Definition Mesh.h:125
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:94
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:88
bool existsPropertyVector(std::string_view name) const
PropertyVector< T > const * getPropertyVector(std::string_view name) const
static MeshLib::Mesh * getMeshSurface(const MeshLib::Mesh &subsfc_mesh, Eigen::Vector3d const &dir, double angle, std::string_view subsfc_node_id_prop_name="", std::string_view subsfc_element_id_prop_name="", std::string_view face_id_prop_name="")
std::vector< Node * > copyNodeVector(const std::vector< Node * > &nodes)
Creates a deep copy of a Node vector.
constexpr std::string_view getBulkIDString(MeshItemType mesh_item_type)
TemplateElement< MeshLib::QuadRule4 > Quad
Definition Quad.h:17
TemplateElement< MeshLib::PrismRule6 > Prism
Definition Prism.h:14
std::vector< Element * > copyElementVector(std::vector< Element * > const &elements, std::vector< Node * > const &new_nodes, std::vector< std::size_t > const *const node_id_map)
TemplateElement< MeshLib::HexRule8 > Hex
Definition Hex.h:14
std::unique_ptr< MeshLib::Mesh > createFlippedMesh(MeshLib::Mesh const &mesh)
MeshLib::Mesh * addLayerToMesh(MeshLib::Mesh const &mesh, double const thickness, std::string const &name, bool const on_top, bool const copy_material_ids, std::optional< int > const layer_id)
MeshLib::Element * extrudeElement(std::vector< MeshLib::Node * > const &subsfc_nodes, MeshLib::Element const &sfc_elem, MeshLib::PropertyVector< std::size_t > const &sfc_to_subsfc_id_map, std::map< std::size_t, std::size_t > const &subsfc_sfc_id_map)