OGS
PostUtils.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 "PostUtils.h"
5
8#include "MeshLib/Node.h"
11
12namespace ProcessLib
13{
14namespace LIE
15{
16namespace
17{
18bool includesNodeID(std::vector<MeshLib::Node*> const& vec_nodes,
19 std::size_t node_id)
20{
21 return std::any_of(vec_nodes.begin(), vec_nodes.end(),
22 [&](MeshLib::Node const* node)
23 { return node->getID() == node_id; });
24}
25
26std::vector<int> const& getMaterialIdsForNode(
27 std::vector<std::pair<std::size_t, std::vector<int>>> const&
28 vec_nodeID_matIDs,
29 std::size_t nodeID)
30{
31 auto itr =
32 std::find_if(vec_nodeID_matIDs.begin(), vec_nodeID_matIDs.end(),
33 [&](std::pair<std::size_t, std::vector<int>> const& entry)
34 { return entry.first == nodeID; });
35 assert(itr != vec_nodeID_matIDs.end());
36 return itr->second;
37};
38} // namespace
39
41 MeshLib::Mesh const& org_mesh,
42 std::vector<int> const& vec_fracture_mat_IDs,
43 std::vector<std::vector<MeshLib::Node*>> const& vec_vec_fracture_nodes,
44 std::vector<std::vector<MeshLib::Element*>> const&
45 vec_vec_fracture_matrix_elements,
46 std::vector<std::pair<std::size_t, std::vector<int>>> const&
47 vec_branch_nodeID_matIDs,
48 std::vector<std::pair<std::size_t, std::vector<int>>> const&
49 vec_junction_nodeID_matIDs)
50 : _org_mesh(org_mesh)
51{
52 if (!org_mesh.getProperties().hasPropertyVector("displacement") ||
53 !org_mesh.getProperties().hasPropertyVector("displacement_jump1") ||
54 !org_mesh.getProperties().hasPropertyVector("levelset1"))
55 {
56 OGS_FATAL("The given mesh does not have relevant properties");
57 }
58
59 // clone nodes and elements
60 std::vector<MeshLib::Node*> new_nodes(
62 std::vector<MeshLib::Element*> new_eles(
63 MeshLib::copyElementVector(org_mesh.getElements(), new_nodes));
64
65 // duplicate fracture nodes (two dup. nodes created at a branch)
66 for (auto const& vec_fracture_nodes : vec_vec_fracture_nodes)
67 {
68 for (auto const* org_node : vec_fracture_nodes)
69 {
70 auto duplicated_node =
71 new MeshLib::Node(org_node->data(), new_nodes.size());
72 new_nodes.push_back(duplicated_node);
73 _map_dup_newNodeIDs[org_node->getID()].push_back(
74 duplicated_node->getID());
75 }
76 }
77 // at a junction, generate one more duplicated node (total 4 nodes)
78 for (auto const& entry : vec_junction_nodeID_matIDs)
79 {
80 auto* org_node = org_mesh.getNode(entry.first);
81 auto duplicated_node =
82 new MeshLib::Node(org_node->data(), new_nodes.size());
83 new_nodes.push_back(duplicated_node);
84 _map_dup_newNodeIDs[org_node->getID()].push_back(
85 duplicated_node->getID());
86 }
87
88 // split elements using the new duplicated nodes
89 for (unsigned fracture_id = 0;
90 fracture_id < vec_vec_fracture_matrix_elements.size();
91 fracture_id++)
92 {
93 auto const frac_matid = vec_fracture_mat_IDs[fracture_id];
94 auto const& vec_fracture_matrix_elements =
95 vec_vec_fracture_matrix_elements[fracture_id];
96 auto const& vec_fracture_nodes = vec_vec_fracture_nodes[fracture_id];
97 auto prop_levelset = org_mesh.getProperties().getPropertyVector<double>(
98 "levelset" + std::to_string(fracture_id + 1));
99 for (auto const* org_e : vec_fracture_matrix_elements)
100 {
101 // only matrix elements
102 if (org_e->getDimension() != org_mesh.getDimension())
103 {
104 continue;
105 }
106
107 auto const eid = org_e->getID();
108 // keep original if the element has levelset<=0
109 if ((*prop_levelset)[eid] <= 0)
110 {
111 continue;
112 }
113
114 // replace fracture nodes with duplicated ones
115 MeshLib::Element* e = new_eles[eid];
116 for (unsigned i = 0; i < e->getNumberOfNodes(); i++)
117 {
118 const auto node_id = getNodeIndex(*e, i);
119 if (!includesNodeID(vec_fracture_nodes, node_id))
120 {
121 continue;
122 }
123
124 // list of duplicated node IDs
125 auto itr = _map_dup_newNodeIDs.find(node_id);
126 if (itr == _map_dup_newNodeIDs.end())
127 {
128 continue;
129 }
130 const auto& dup_newNodeIDs = itr->second;
131
132 // choose new node id
133 unsigned new_node_id = 0;
134 if (dup_newNodeIDs.size() == 1)
135 {
136 // non-intersected nodes
137 new_node_id = dup_newNodeIDs[0];
138 }
139 else if (dup_newNodeIDs.size() == 2)
140 {
141 // branch nodes
142 const auto& br_matids = getMaterialIdsForNode(
143 vec_branch_nodeID_matIDs, node_id);
144 auto const frac2_matid = BaseLib::findFirstNotEqualElement(
145 br_matids, frac_matid);
146 assert(frac2_matid);
147 auto const frac2_id =
148 BaseLib::findIndex(vec_fracture_mat_IDs, *frac2_matid);
149 assert(frac2_id != std::numeric_limits<std::size_t>::max());
150 auto prop_levelset2 =
151 org_mesh.getProperties().getPropertyVector<double>(
152 "levelset" + std::to_string(frac2_id + 1));
153 std::size_t pos = 0;
154 if ((*prop_levelset2)[eid] <= 0)
155 {
156 // index of this fracture
157 pos = BaseLib::findIndex(br_matids, frac_matid);
158 }
159 else
160 {
161 // index of the other fracture
162 pos = BaseLib::findIndex(br_matids, *frac2_matid);
163 }
164 assert(pos != std::numeric_limits<std::size_t>::max());
165 new_node_id = dup_newNodeIDs[pos];
166 }
167 else
168 {
169 // junction nodes
170 const auto& jct_matids = getMaterialIdsForNode(
171 vec_junction_nodeID_matIDs, node_id);
172 auto const frac2_matid = BaseLib::findFirstNotEqualElement(
173 jct_matids, frac_matid);
174 assert(frac2_matid);
175 auto const frac2_id =
176 BaseLib::findIndex(vec_fracture_mat_IDs, *frac2_matid);
177 assert(frac2_id != std::numeric_limits<std::size_t>::max());
178 auto prop_levelset2 =
179 org_mesh.getProperties().getPropertyVector<double>(
180 "levelset" + std::to_string(frac2_id + 1));
181
182 //
183 if ((*prop_levelset2)[eid] <= 0)
184 {
185 // index of this frac
186 auto const pos =
187 BaseLib::findIndex(jct_matids, frac_matid);
188 assert(pos != std::numeric_limits<std::size_t>::max());
189 new_node_id = dup_newNodeIDs[pos];
190 }
191 else
192 {
193 // set the last duplicated node
194 new_node_id = dup_newNodeIDs.back();
195 }
196 }
197
198 // replace node
199 e->setNode(i, new_nodes[new_node_id]);
200 }
201 }
202 }
203
204 // new mesh
205 _output_mesh = std::make_unique<MeshLib::Mesh>(org_mesh.getName(),
206 new_nodes, new_eles);
207
208 for (auto [name, property] : _org_mesh.getProperties())
209 {
210 if (auto const* p =
211 dynamic_cast<MeshLib::PropertyVector<double>*>(property))
212 {
214 }
215 else if (auto const* p =
216 dynamic_cast<MeshLib::PropertyVector<float>*>(property))
217 {
219 }
220 else if (auto const* p =
221 dynamic_cast<MeshLib::PropertyVector<int>*>(property))
222 {
224 }
225 else if (auto const* p =
226 dynamic_cast<MeshLib::PropertyVector<unsigned>*>(property))
227 {
229 }
230 else if (auto const* p =
231 dynamic_cast<MeshLib::PropertyVector<long>*>(property))
232 {
234 }
235 else if (auto const* p =
237 property))
238 {
240 }
241 else if (auto const* p =
243 property))
244 {
246 }
247 else if (auto const* p =
249 property))
250 {
252 }
253 else if (auto const* p =
255 property))
256 {
258 }
259 else if (auto const* p =
260 dynamic_cast<MeshLib::PropertyVector<char>*>(property))
261 {
263 }
264 else
265 {
266 OGS_FATAL(
267 "Mesh property '{:s}' of unhandled data type '{:s}'. Please "
268 "check the data type of the mesh properties. The available "
269 "data types are:"
270 "\n\t double,"
271 "\n\t float,"
272 "\n\t int,"
273 "\n\t unsigned,"
274 "\n\t long,"
275 "\n\t long long,"
276 "\n\t unsigned long,"
277 "\n\t unsigned long long,"
278 "\n\t char.",
279 property->getPropertyName(),
280 BaseLib::typeToString(*property));
281 }
282 }
283 calculateTotalDisplacement(vec_vec_fracture_nodes.size(),
284 vec_junction_nodeID_matIDs.size());
285}
286
287template <typename T>
289 MeshLib::PropertyVector<T> const& property)
290{
291 auto const item_type = property.getMeshItemType();
292 auto const n_src_comp = property.getNumberOfGlobalComponents();
293 // convert 2D vector to 3D. Otherwise Paraview Calculator filter does
294 // not recognize it as a vector
295 auto const n_dest_comp = (n_src_comp == 2) ? 3 : n_src_comp;
296
297 auto new_property = MeshLib::getOrCreateMeshProperty<T>(
298 *_output_mesh, property.getPropertyName(), item_type, n_dest_comp);
299
300 if (item_type == MeshLib::MeshItemType::Node)
301 {
302 assert(new_property->size() ==
303 _output_mesh->getNumberOfNodes() * n_dest_comp);
304 }
305 else if (item_type == MeshLib::MeshItemType::Cell)
306 {
307 assert(new_property->size() ==
308 _output_mesh->getNumberOfElements() * n_dest_comp);
309 }
310 else
311 {
312 WARN(
313 "Property '{:s}' cannot be created because its mesh item type "
314 "'{:s}' is not supported.",
315 property.getPropertyName(), toString(item_type));
316 _output_mesh->getProperties().removePropertyVector(
317 std::string(new_property->getPropertyName()));
318 return nullptr;
319 }
320 return new_property;
321}
322
323template <typename T>
325 MeshLib::PropertyVector<T> const& source_property,
326 MeshLib::PropertyVector<T>* const destination_property)
327{
328 if (destination_property == nullptr)
329 {
330 // skip the copy, because the destination wasn't created.
331 return;
332 }
333
334 auto const item_type = source_property.getMeshItemType();
335 if (item_type == MeshLib::MeshItemType::Node)
336 {
337 auto const n_src_comp = source_property.getNumberOfGlobalComponents();
338 auto const n_dest_comp =
339 destination_property->getNumberOfGlobalComponents();
340 // copy existing
341 for (unsigned i = 0; i < _org_mesh.getNumberOfNodes(); i++)
342 {
343 auto last = std::copy_n(&source_property[i * n_src_comp],
344 n_src_comp,
345 &(*destination_property)[i * n_dest_comp]);
346 // set zero for components not existing in the original
347 std::fill_n(last, n_dest_comp - n_src_comp, T{0});
348 }
349 // copy duplicated
350 for (auto itr : _map_dup_newNodeIDs)
351 {
352 for (unsigned k = 0; k < itr.second.size(); k++)
353 {
354 std::copy_n(
355 &(*destination_property)[itr.first * n_dest_comp],
356 n_dest_comp,
357 &(*destination_property)[itr.second[k] * n_dest_comp]);
358 }
359 }
360 }
361 else if (item_type == MeshLib::MeshItemType::Cell)
362 {
363 assert(source_property.size() == destination_property->size());
364 std::copy(source_property.begin(), source_property.end(),
365 destination_property->begin());
366 }
367 else
368 {
369 OGS_FATAL(
370 "Property '{:s}' values cannot be copied because its mesh item "
371 "type '{:s}' is not supported. Unexpected error, because the "
372 "destination property was created.",
373 source_property.getPropertyName(), toString(item_type));
374 }
375}
376
377void PostProcessTool::calculateTotalDisplacement(unsigned const n_fractures,
378 unsigned const n_junctions)
379{
380 auto const& u = *_output_mesh->getProperties().getPropertyVector<double>(
381 "displacement");
382 auto const n_u_comp = u.getNumberOfGlobalComponents();
383 assert(u.size() == _output_mesh->getNodes().size() * 3);
384 auto& total_u =
385 *_output_mesh->getProperties().createNewPropertyVector<double>(
386 "u", MeshLib::MeshItemType::Node, n_u_comp);
387 total_u.resize(u.size());
388 ranges::copy(u, total_u.begin());
389
390 for (unsigned enrich_id = 0; enrich_id < n_fractures + n_junctions;
391 enrich_id++)
392 {
393 // nodal value of levelset
394 std::vector<double> nodal_levelset(
395 _output_mesh->getNodes().size(),
396 std::numeric_limits<double>::quiet_NaN());
397
398 auto const& ele_levelset =
399 *_output_mesh->getProperties().getPropertyVector<double>(
400 "levelset" + std::to_string(enrich_id + 1));
401 for (MeshLib::Element const* e : _output_mesh->getElements())
402 {
403 if (e->getDimension() != _output_mesh->getDimension())
404 {
405 continue;
406 }
407 const double e_levelset = ele_levelset[e->getID()];
408
409 for (unsigned i = 0; i < e->getNumberOfNodes(); i++)
410 {
411 nodal_levelset[getNodeIndex(*e, i)] = e_levelset;
412 }
413 }
414
415 // update total displacements
416 auto const& g =
417 *_output_mesh->getProperties().getPropertyVector<double>(
418 "displacement_jump" + std::to_string(enrich_id + 1));
419 for (unsigned i = 0; i < _output_mesh->getNodes().size(); i++)
420 {
421 for (int j = 0; j < n_u_comp; j++)
422 {
423 total_u[i * n_u_comp + j] +=
424 nodal_levelset[i] * g[i * n_u_comp + j];
425 }
426 }
427 }
428}
429
430} // namespace LIE
431} // namespace ProcessLib
#define OGS_FATAL(...)
Definition Error.h:19
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
virtual unsigned getNumberOfNodes() const =0
virtual void setNode(unsigned idx, Node *node)=0
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
const Node * getNode(std::size_t idx) const
Get the node with the given index.
Definition Mesh.h:82
Properties & getProperties()
Definition Mesh.h:125
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:94
bool hasPropertyVector(std::string_view name) const
PropertyVector< T > const * getPropertyVector(std::string_view name) const
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()
void copyPropertyValues(MeshLib::PropertyVector< T > const &source_property, MeshLib::PropertyVector< T > *const destination_property)
MeshLib::Mesh const & _org_mesh
Definition PostUtils.h:51
std::map< std::size_t, std::vector< std::size_t > > _map_dup_newNodeIDs
Definition PostUtils.h:53
void calculateTotalDisplacement(unsigned const n_fractures, unsigned const n_junctions)
MeshLib::PropertyVector< T > * createProperty(MeshLib::PropertyVector< T > const &property)
std::unique_ptr< MeshLib::Mesh > _output_mesh
Definition PostUtils.h:52
PostProcessTool(MeshLib::Mesh const &org_mesh, std::vector< int > const &vec_fracture_mat_IDs, std::vector< std::vector< MeshLib::Node * > > const &vec_vec_fracture_nodes, std::vector< std::vector< MeshLib::Element * > > const &vec_vec_fracture_matrix_elements, std::vector< std::pair< std::size_t, std::vector< int > > > const &vec_branch_nodeID_matIDs, std::vector< std::pair< std::size_t, std::vector< int > > > const &vec_junction_nodeID_matIDs)
Definition PostUtils.cpp:40
std::size_t findIndex(Container const &container, typename Container::value_type const &element)
Definition Algorithm.h:236
std::string typeToString()
std::optional< typename Container::value_type > findFirstNotEqualElement(Container const &container, typename Container::value_type const &element)
Definition Algorithm.h:220
PropertyVector< T > * getOrCreateMeshProperty(Mesh &mesh, std::string const &property_name, MeshItemType const item_type, int const number_of_components)
std::vector< Node * > copyNodeVector(const std::vector< Node * > &nodes)
Creates a deep copy of a Node vector.
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)
bool includesNodeID(std::vector< MeshLib::Node * > const &vec_nodes, std::size_t node_id)
Definition PostUtils.cpp:18
std::vector< int > const & getMaterialIdsForNode(std::vector< std::pair< std::size_t, std::vector< int > > > const &vec_nodeID_matIDs, std::size_t nodeID)
Definition PostUtils.cpp:26