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