OGS
MeshToolsLib/MeshEditing/MergeMeshToBulkMesh.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 <Eigen/Dense>
7#include <algorithm>
8#include <cmath>
9#include <numeric>
10#include <range/v3/view/filter.hpp>
11#include <range/v3/view/zip.hpp>
12#include <tuple>
13#include <vector>
14
15#include "BaseLib/Logging.h"
16#include "GeoLib/AABB.h"
18#include "MeshLib/Mesh.h"
19#include "MeshLib/Node.h"
20#include "MeshLib/Properties.h"
25
26namespace MeshToolsLib
27{
28
29template <typename T>
30void setSigma0(int const pv_num_components,
31 MeshLib::PropertyVector<T> const* const pv_bulk_mesh,
32 std::unordered_map<std::string, double>& initial_value_dict,
34{
35 std::vector<double> sigma0(pv_num_components, 0.0);
36 sigma0[0] = initial_value_dict["sxx"];
37 sigma0[1] = initial_value_dict["syy"];
38 sigma0[2] = initial_value_dict["szz"];
39
40 std::transform(new_pv.begin() + pv_bulk_mesh->size(),
41 new_pv.end(),
42 new_pv.begin() + pv_bulk_mesh->size(),
43 [&, i = 0](T) mutable
44 { return static_cast<T>(sigma0[i++ % sigma0.size()]); });
45}
46
47template <typename T>
49 MeshLib::Mesh& merged_mesh, std::string const& pv_name,
50 int const pv_num_components,
51 MeshLib::PropertyVector<T> const* const pv_bulk_mesh,
52 std::unordered_map<std::string, double>& initial_value_dict)
53{
55 merged_mesh, pv_name, MeshLib::MeshItemType::Node, pv_num_components);
56 new_pv->resize(merged_mesh.getNumberOfNodes() * pv_num_components);
57
58 std::copy(pv_bulk_mesh->begin(), pv_bulk_mesh->end(), new_pv->begin());
59
60 if (pv_num_components > 1)
61 {
62 if (pv_name.find("sigma") != std::string::npos)
63 {
64 setSigma0(pv_num_components, pv_bulk_mesh, initial_value_dict,
65 *new_pv);
66 }
67 return true;
68 }
69
70 // Map possible pv_name values to their corresponding dictionary
71 // keys
72 const std::unordered_map<std::string, std::string> pv_to_dict_key = {
73 {"pressure", "p"},
74 {"p", "p"},
75 {"gas_pressure", "pg"},
76 {"pg", "pg"},
77 {"capillary_pressure", "pc"},
78 {"pc", "pc"},
79 {"temperature", "T"},
80 {"T", "T"}};
81
82 T value = static_cast<T>(0.0);
83 auto it = pv_to_dict_key.find(pv_name);
84 if (it != pv_to_dict_key.end() && initial_value_dict.contains(it->second))
85 {
86 value = static_cast<T>(initial_value_dict[it->second]);
87 }
88 std::fill(new_pv->begin() + pv_bulk_mesh->size(), new_pv->end(), value);
89 return true;
90}
91
92template <typename T>
94 MeshLib::Mesh& merged_mesh, std::string const& pv_name,
95 int const pv_num_components,
96 MeshLib::PropertyVector<T> const* const pv_bulk_mesh,
97 std::unordered_map<std::string, double>& initial_value_dict)
98{
100 merged_mesh, pv_name, MeshLib::MeshItemType::Cell, pv_num_components);
101 new_pv->resize(merged_mesh.getNumberOfElements() * pv_num_components);
102
103 std::copy(pv_bulk_mesh->begin(), pv_bulk_mesh->end(), new_pv->begin());
104
105 double const value =
106 (pv_name == "MaterialIDs") ? (initial_value_dict["mat_id"]) : 0.0;
107
108 std::fill(new_pv->begin() + pv_bulk_mesh->size(), new_pv->end(),
109 static_cast<T>(value));
110 return true;
111}
112
113template <typename T>
115 MeshLib::Mesh& merged_mesh, std::string const& pv_name,
116 int const pv_num_components,
117 MeshLib::PropertyVector<T> const* const pv_bulk_mesh,
118 std::unordered_map<std::string, double>& initial_value_dict,
119 std::optional<MeshLib::IntegrationPointMetaData> const&
120 integration_point_meta_data)
121{
123 merged_mesh, pv_name, MeshLib::MeshItemType::IntegrationPoint,
124 pv_num_components);
125
126 // Count the integration points
127 std::size_t counter = 0;
128 auto const ip_meta_data = MeshLib::getIntegrationPointMetaDataSingleField(
129 integration_point_meta_data, pv_name);
130
131 for (auto const element : merged_mesh.getElements())
132 {
133 int const number_of_integration_points =
135 *element);
136 counter += number_of_integration_points;
137 }
138 new_pv->resize(counter * pv_num_components);
139
140 std::copy(pv_bulk_mesh->begin(), pv_bulk_mesh->end(), new_pv->begin());
141
142 if (pv_name.find("sigma") != std::string::npos)
143 {
144 setSigma0(pv_num_components, pv_bulk_mesh, initial_value_dict, *new_pv);
145 }
146
147 return true;
148}
149
150template <typename T>
152 MeshLib::Mesh& merged_mesh,
153 std::unordered_map<std::string, double>& initial_value_dict,
154 MeshLib::PropertyVector<T> const* const pv_bulk_mesh,
155 std::optional<MeshLib::IntegrationPointMetaData> const&
156 integration_point_meta_data)
157{
158 if (pv_bulk_mesh == nullptr)
159 {
160 return false;
161 }
162
163 if (pv_bulk_mesh->getPropertyName() == "vtkGhostType")
164 {
165 // Do nothing
166 return true;
167 }
168
169 auto const item_type = pv_bulk_mesh->getMeshItemType();
170
171 auto const pv_name = pv_bulk_mesh->getPropertyName();
172
173 auto const pv_num_components = pv_bulk_mesh->getNumberOfGlobalComponents();
174
175 if (pv_name == "OGS_VERSION" || pv_name == "IntegrationPointMetaData")
176 {
178 merged_mesh, pv_name, item_type, pv_num_components);
179 new_pv->resize(pv_bulk_mesh->size());
180
181 std::copy(pv_bulk_mesh->begin(), pv_bulk_mesh->end(), new_pv->begin());
182 return true;
183 }
184
185 if (item_type == MeshLib::MeshItemType::Node)
186 {
187 return createNodeProperties(merged_mesh, pv_name, pv_num_components,
188 pv_bulk_mesh, initial_value_dict);
189 }
190
191 if (item_type == MeshLib::MeshItemType::Cell)
192 {
193 return createCellProperties(merged_mesh, pv_name, pv_num_components,
194 pv_bulk_mesh, initial_value_dict);
195 }
196
198 {
200 merged_mesh, pv_name, pv_num_components, pv_bulk_mesh,
201 initial_value_dict, integration_point_meta_data);
202 }
203
204 return false;
205}
206
207std::vector<MeshLib::Node*> findNodesInBoundedDomain(
208 std::vector<MeshLib::Node*> const& nodes, GeoLib::AABB const& aabb)
209{
210 return nodes |
211 ranges::views::filter(
212 [&](MeshLib::Node* n)
213 { return aabb.containsPoint(n->asEigenVector3d(), 1e-16); }) |
214 ranges::to<std::vector<MeshLib::Node*>>();
215}
216
217std::unique_ptr<MeshLib::Mesh> mergeMeshToBulkMesh(
218 MeshLib::Mesh const& bulk_mesh, MeshLib::Mesh const& other_mesh,
219 std::unordered_map<std::string, double>& initial_value_dict)
220{
221 auto const& other_mesh_nodes = other_mesh.getNodes();
222 GeoLib::AABB aabb(other_mesh_nodes.begin(), other_mesh_nodes.end());
223
224 auto const& bulk_mesh_nodes = bulk_mesh.getNodes();
225 auto const bulk_nodes_in_aabb =
226 findNodesInBoundedDomain(bulk_mesh_nodes, aabb);
227
228 // Find the interface nodes in the bulk nodes
229 auto const pn_bulk_mesh = partitionNodesByCoordinateMatch(
230 bulk_nodes_in_aabb, other_mesh_nodes, aabb,
231 false /*return_non_paired_nodes*/);
232 auto interface_nodes_of_bulk_mesh = pn_bulk_mesh.paired_nodes;
233
234 // Partitioned node vector of the other mesh
235 auto const pn_other_mesh = partitionNodesByCoordinateMatch(
236 other_mesh_nodes, bulk_nodes_in_aabb, aabb);
237 auto const interface_nodes_of_other_mesh = pn_other_mesh.paired_nodes;
238 auto const internal_nodes_of_other_mesh = *(pn_other_mesh.non_paired_nodes);
239
240 // Interface node id mapping: from the other mesh to the bulk mesh
241 auto cn_id_mapping_m2b = *(pn_other_mesh.id_mapping);
242
243 std::unordered_map<std::size_t, std::size_t> other_mesh_node_id_dict;
244
245 for (auto const&& [id_mapping, node] :
246 ranges::views::zip(cn_id_mapping_m2b, interface_nodes_of_other_mesh))
247 {
248 other_mesh_node_id_dict.insert({node->getID(), id_mapping});
249 }
250
251 // Create new mesh node vector
252 std::vector<MeshLib::Node*> new_node_vector;
253 new_node_vector.reserve(bulk_mesh_nodes.size() +
254 internal_nodes_of_other_mesh.size());
255 // First, copy the nodes from the bulk mesh
256 new_node_vector.insert(new_node_vector.end(), bulk_mesh_nodes.begin(),
257 bulk_mesh_nodes.end());
258 // Second, append the inside nodes of the merge mesh
259 std::size_t new_node_id = bulk_mesh_nodes.size();
260 for (auto node : internal_nodes_of_other_mesh)
261 {
262 other_mesh_node_id_dict.insert({node->getID(), new_node_id});
263 new_node_vector.push_back(node);
264 new_node_id++;
265 }
266
267 // Create new mesh element vector
268 auto const elements_bulk = bulk_mesh.getElements();
269 auto const elements_other_mesh = other_mesh.getElements();
270 std::vector<MeshLib::Element*> new_element_vector;
271 new_element_vector.reserve(elements_bulk.size() +
272 elements_other_mesh.size());
273 // First, copy the elements from the bulk mesh
274 new_element_vector.insert(new_element_vector.end(), elements_bulk.begin(),
275 elements_bulk.end());
276 // Append the elements of the mesh to be merged to the element vector of the
277 // bulk mesh:
278 for (auto element : elements_other_mesh)
279 {
280 auto const nn = element->getNumberOfNodes();
281 for (unsigned i = 0; i < nn; ++i)
282 {
283 // `node` cannot be declared as `const` because `element` is not
284 // `const`.
285 MeshLib::Node* node = element->getNode(i);
286 auto const new_id = other_mesh_node_id_dict[node->getID()];
287 element->setNode(i, new_node_vector[new_id]);
288 }
289 new_element_vector.push_back(element);
290 }
291
292 // Node IDs are reset in the constructor of MeshLib::Mesh according to their
293 // order of appearance (see MeshLib::Mesh::resetNodeIDs()). Since the order
294 // of nodes in the bulk mesh remains unchanged, the corresponding segments
295 // of property vectors of the original bulk mesh are also preserved.
296 auto merged_mesh = std::make_unique<MeshLib::Mesh>(
297 "merged_mesh", new_node_vector, new_element_vector);
298
299 MeshLib::Properties const& properties_bulk_mesh = bulk_mesh.getProperties();
300 auto const integration_point_meta_data =
301 MeshLib::getIntegrationPointMetaData(properties_bulk_mesh);
302
304 properties_bulk_mesh,
305 [&](auto type, auto const& property)
306 {
308 *merged_mesh, initial_value_dict,
309 dynamic_cast<MeshLib::PropertyVector<decltype(type)> const*>(
310 property),
311 integration_point_meta_data);
312 });
313
314 for (auto node : interface_nodes_of_other_mesh)
315 {
316 delete node;
317 }
318
319 return merged_mesh;
320}
321
322} // namespace MeshToolsLib
Class AABB is an axis aligned bounding box around a given set of geometric points of (template) type ...
Definition AABB.h:45
bool containsPoint(T const &pnt, double eps) const
Definition AABB.h:132
std::size_t getID() const
Eigen::Vector3d const & asEigenVector3d() const
Definition Point3d.h:55
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
Properties & getProperties()
Definition Mesh.h:125
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition Mesh.h:91
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:88
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
MeshItemType getMeshItemType() const
int getNumberOfGlobalComponents() const
std::string const & getPropertyName() const
constexpr PROP_VAL_TYPE * begin()
constexpr std::size_t size() const
constexpr PROP_VAL_TYPE * end()
PropertyVector< T > * getOrCreateMeshProperty(Mesh &mesh, std::string const &property_name, MeshItemType const item_type, int const number_of_components)
std::optional< IntegrationPointMetaData > getIntegrationPointMetaData(MeshLib::Properties const &properties)
void applyToPropertyVectors(Properties const &properties, Function f)
IntegrationPointMetaDataSingleField getIntegrationPointMetaDataSingleField(std::optional< IntegrationPointMetaData > const &ip_meta_data, std::string const &field_name)
NodesPartitionResult partitionNodesByCoordinateMatch(std::vector< MeshLib::Node * > const &node_vector, std::vector< MeshLib::Node * > const &tool_node_vector, GeoLib::AABB const &aabb, bool const return_non_paired_nodes)
bool createMergedPropertyVector(MeshLib::Mesh &merged_mesh, std::unordered_map< std::string, double > &initial_value_dict, MeshLib::PropertyVector< T > const *const pv_bulk_mesh, std::optional< MeshLib::IntegrationPointMetaData > const &integration_point_meta_data)
int getNumberOfElementIntegrationPoints(MeshLib::IntegrationPointMetaDataSingleField const &ip_meta_data, MeshLib::Element const &e)
bool createIntegrationPointProperties(MeshLib::Mesh &merged_mesh, std::string const &pv_name, int const pv_num_components, MeshLib::PropertyVector< T > const *const pv_bulk_mesh, std::unordered_map< std::string, double > &initial_value_dict, std::optional< MeshLib::IntegrationPointMetaData > const &integration_point_meta_data)
void setSigma0(int const pv_num_components, MeshLib::PropertyVector< T > const *const pv_bulk_mesh, std::unordered_map< std::string, double > &initial_value_dict, MeshLib::PropertyVector< T > &new_pv)
std::unique_ptr< MeshLib::Mesh > mergeMeshToBulkMesh(MeshLib::Mesh const &bulk_mesh, MeshLib::Mesh const &other_mesh, std::unordered_map< std::string, double > &initial_value_dict)
std::vector< MeshLib::Node * > findNodesInBoundedDomain(std::vector< MeshLib::Node * > const &nodes, GeoLib::AABB const &aabb)
bool createCellProperties(MeshLib::Mesh &merged_mesh, std::string const &pv_name, int const pv_num_components, MeshLib::PropertyVector< T > const *const pv_bulk_mesh, std::unordered_map< std::string, double > &initial_value_dict)
bool createNodeProperties(MeshLib::Mesh &merged_mesh, std::string const &pv_name, int const pv_num_components, MeshLib::PropertyVector< T > const *const pv_bulk_mesh, std::unordered_map< std::string, double > &initial_value_dict)