OGS
LIE/Common/MeshUtils.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 "MeshUtils.h"
5
6#include "BaseLib/Algorithm.h"
8#include "MeshLib/Mesh.h"
10#include "MeshLib/Node.h"
11
12namespace ProcessLib
13{
14namespace LIE
15{
16namespace
17{
18// A class to check whether a node is located on a crack tip with
19// the following conditions:
20// - the number of connected fracture elements is one
21// - the node is not located on a domain boundary
23{
24public:
25 explicit IsCrackTip(MeshLib::Mesh const& mesh)
26 : _mesh(mesh), _fracture_element_dim(_mesh.getDimension() - 1)
27 {
28 _is_internal_node.resize(_mesh.getNumberOfNodes(), true);
29
30 MeshLib::NodeSearch nodeSearch(mesh);
31 nodeSearch.searchBoundaryNodes();
32 for (auto i : nodeSearch.getSearchedNodeIDs())
33 {
34 _is_internal_node[i] = false;
35 }
36 }
37
38 bool operator()(MeshLib::Node const& node) const
39 {
40 if (!_is_internal_node[node.getID()] ||
41 !isBaseNode(node, _mesh.getElementsConnectedToNode(node)))
42 {
43 return false;
44 }
45
46 auto const elements_connected_to_node =
47 _mesh.getElementsConnectedToNode(node);
48 auto const n_connected_fracture_elements =
49 count_if(cbegin(elements_connected_to_node),
50 cend(elements_connected_to_node),
51 [&](auto* const e)
52 { return e->getDimension() == _fracture_element_dim; });
53 assert(n_connected_fracture_elements > 0);
54
55 return (n_connected_fracture_elements == 1);
56 }
57
58private:
60 unsigned const _fracture_element_dim;
61 std::vector<bool> _is_internal_node;
62};
63
65 MeshLib::Mesh const& mesh, std::vector<int> const& vec_fracture_mat_IDs,
66 std::vector<std::vector<MeshLib::Node*>> const& vec_fracture_nodes,
67 std::vector<std::vector<MeshLib::Element*>>& intersected_fracture_elements,
68 std::vector<std::pair<std::size_t, std::vector<int>>>&
69 vec_branch_nodeID_matIDs,
70 std::vector<std::pair<std::size_t, std::vector<int>>>&
71 vec_junction_nodeID_matIDs)
72{
73 auto const n_fractures = vec_fracture_mat_IDs.size();
74 std::map<unsigned, unsigned> matID_to_fid;
75 for (unsigned i = 0; i < n_fractures; i++)
76 {
77 matID_to_fid[vec_fracture_mat_IDs[i]] = i;
78 }
79
80 // make a vector all fracture nodes
81 std::vector<std::size_t> all_fracture_nodes;
82 for (auto& vec : vec_fracture_nodes)
83 {
84 transform(cbegin(vec), cend(vec), back_inserter(all_fracture_nodes),
85 [](auto* const n) { return n->getID(); });
86 }
87
88 // create a table of a node id and connected material IDs
89 std::map<std::size_t, std::vector<std::size_t>> frac_nodeID_to_matIDs;
90 for (unsigned i = 0; i < n_fractures; i++)
91 {
92 for (auto* node : vec_fracture_nodes[i])
93 {
94 frac_nodeID_to_matIDs[node->getID()].push_back(
95 vec_fracture_mat_IDs[i]);
96 }
97 }
98
99 auto const* const opt_material_ids = MeshLib::materialIDs(mesh);
100
101 // find branch/junction nodes which connect to multiple fractures
102 intersected_fracture_elements.resize(n_fractures);
103 for (auto frac_nodeID_to_matID : frac_nodeID_to_matIDs)
104 {
105 auto nodeID = frac_nodeID_to_matID.first;
106 auto const* node = mesh.getNode(frac_nodeID_to_matID.first);
107 auto const& matIDs = frac_nodeID_to_matID.second;
108 if (matIDs.size() < 2)
109 {
110 continue; // no intersection
111 }
112
113 auto const elements_connected_to_node =
114 mesh.getElementsConnectedToNode(*node);
115 std::vector<MeshLib::Element*> conn_fracture_elements;
116 {
117 for (auto const* e : elements_connected_to_node)
118 {
119 if (e->getDimension() == (mesh.getDimension() - 1))
120 {
121 conn_fracture_elements.push_back(
122 const_cast<MeshLib::Element*>(e));
123 }
124 }
125 }
126
127 std::map<int, int> vec_matID_counts;
128 {
129 for (auto matid : matIDs)
130 {
131 vec_matID_counts[matid] = 0;
132 }
133
134 for (auto const* e : conn_fracture_elements)
135 {
136 auto matid = (*opt_material_ids)[e->getID()];
137 vec_matID_counts[matid]++;
138 }
139 }
140
141 for (auto matid : matIDs)
142 {
143 auto fid = matID_to_fid[matid];
144 for (auto* e : conn_fracture_elements)
145 {
146 auto e_matid = (*opt_material_ids)[e->getID()];
147 if (matID_to_fid[e_matid] != fid)
148 { // only slave elements
149 intersected_fracture_elements[fid].push_back(e);
150 }
151 }
152 }
153
154 bool isBranch = false;
155 {
156 for (auto vec_matID_count : vec_matID_counts)
157 {
158 auto count = vec_matID_count.second;
159 if (count % 2 == 1)
160 {
161 isBranch = true;
162 break;
163 }
164 }
165 }
166
167 if (isBranch)
168 {
169 std::vector<int> branch_matIDs(2);
170 for (auto vec_matID_count : vec_matID_counts)
171 {
172 auto matid = vec_matID_count.first;
173 auto count = vec_matID_count.second;
174 if (count % 2 == 0)
175 {
176 branch_matIDs[0] = matid; // master
177 }
178 else
179 {
180 branch_matIDs[1] = matid; // slave
181 }
182 }
183 vec_branch_nodeID_matIDs.emplace_back(nodeID, branch_matIDs);
184 }
185 else
186 {
187 std::vector<int> junction_matIDs(2);
188 junction_matIDs[0] = std::min(vec_matID_counts.begin()->first,
189 vec_matID_counts.rbegin()->first);
190 junction_matIDs[1] = std::max(vec_matID_counts.begin()->first,
191 vec_matID_counts.rbegin()->first);
192 vec_junction_nodeID_matIDs.emplace_back(nodeID, junction_matIDs);
193 }
194 }
195
196 for (auto& elements : intersected_fracture_elements)
197 {
199 }
200
201 DBUG("-> found {:d} branches and {:d} junctions",
202 vec_branch_nodeID_matIDs.size(), vec_junction_nodeID_matIDs.size());
203}
204
205} // namespace
206
208 MeshLib::Mesh const& mesh,
209 std::vector<MeshLib::Element*>& vec_matrix_elements,
210 std::vector<int>& vec_fracture_mat_IDs,
211 std::vector<std::vector<MeshLib::Element*>>& vec_fracture_elements,
212 std::vector<std::vector<MeshLib::Element*>>& vec_fracture_matrix_elements,
213 std::vector<std::vector<MeshLib::Node*>>& vec_fracture_nodes,
214 std::vector<std::pair<std::size_t, std::vector<int>>>&
215 vec_branch_nodeID_matIDs,
216 std::vector<std::pair<std::size_t, std::vector<int>>>&
217 vec_junction_nodeID_matIDs)
218{
219 IsCrackTip isCrackTip(mesh);
220
221 // get vectors of matrix elements and fracture elements
222 vec_matrix_elements.reserve(mesh.getNumberOfElements());
223 std::vector<MeshLib::Element*> all_fracture_elements;
224 for (MeshLib::Element* e : mesh.getElements())
225 {
226 if (e->getDimension() == mesh.getDimension())
227 {
228 vec_matrix_elements.push_back(e);
229 }
230 else
231 {
232 all_fracture_elements.push_back(e);
233 }
234 }
235 DBUG("-> found total {:d} matrix elements and {:d} fracture elements",
236 vec_matrix_elements.size(), all_fracture_elements.size());
237
238 // get fracture material IDs
239 auto const material_ids = materialIDs(mesh);
240 if (!material_ids)
241 {
242 OGS_FATAL("Could not access MaterialIDs property from mesh.");
243 }
244 transform(cbegin(all_fracture_elements), cend(all_fracture_elements),
245 back_inserter(vec_fracture_mat_IDs),
246 [&material_ids](auto const* e)
247 { return (*material_ids)[e->getID()]; });
248
249 BaseLib::makeVectorUnique(vec_fracture_mat_IDs);
250 DBUG("-> found {:d} fracture material groups", vec_fracture_mat_IDs.size());
251
252 // create a vector of fracture elements for each material
253 vec_fracture_elements.resize(vec_fracture_mat_IDs.size());
254 for (unsigned frac_id = 0; frac_id < vec_fracture_mat_IDs.size(); frac_id++)
255 {
256 const auto frac_mat_id = vec_fracture_mat_IDs[frac_id];
257 std::vector<MeshLib::Element*>& vec_elements =
258 vec_fracture_elements[frac_id];
259 std::copy_if(all_fracture_elements.begin(), all_fracture_elements.end(),
260 std::back_inserter(vec_elements),
261 [&](MeshLib::Element const* const e)
262 { return (*material_ids)[e->getID()] == frac_mat_id; });
263 DBUG("-> found {:d} elements on the fracture {:d}", vec_elements.size(),
264 frac_id);
265 }
266
267 // get a vector of fracture nodes for each material
268 vec_fracture_nodes.resize(vec_fracture_mat_IDs.size());
269 for (unsigned frac_id = 0; frac_id < vec_fracture_mat_IDs.size(); frac_id++)
270 {
271 std::vector<MeshLib::Node*>& vec_nodes = vec_fracture_nodes[frac_id];
272 for (MeshLib::Element const* const e : vec_fracture_elements[frac_id])
273 {
274 for (unsigned i = 0; i < e->getNumberOfNodes(); i++)
275 {
276 if (isCrackTip(*e->getNode(i)))
277 {
278 continue;
279 }
280 vec_nodes.push_back(const_cast<MeshLib::Node*>(e->getNode(i)));
281 }
282 }
285 DBUG("-> found {:d} nodes on the fracture {:d}", vec_nodes.size(),
286 frac_id);
287 }
288
289 // find branch/junction nodes which connect to multiple fractures
290 std::vector<std::vector<MeshLib::Element*>> intersected_fracture_elements;
291 findFracutreIntersections(mesh, vec_fracture_mat_IDs, vec_fracture_nodes,
292 intersected_fracture_elements,
293 vec_branch_nodeID_matIDs,
294 vec_junction_nodeID_matIDs);
295
296 // create a vector fracture elements and connected matrix elements,
297 // which are passed to a DoF table
298 for (unsigned fid = 0; fid < vec_fracture_elements.size(); fid++)
299 {
300 auto const& fracture_elements = vec_fracture_elements[fid];
301 std::vector<MeshLib::Element*> vec_ele;
302 // first, collect matrix elements
303 for (MeshLib::Element const* const e : fracture_elements)
304 {
305 // it is sufficient to iterate over base nodes, because they are
306 // already connected to all neighbours
307 for (unsigned i = 0; i < e->getNumberOfBaseNodes(); i++)
308 {
309 MeshLib::Node const* node = e->getNode(i);
310 if (isCrackTip(*node))
311 {
312 continue;
313 }
314 auto const& elements_connected_to_node =
315 mesh.getElementsConnectedToNode(*node);
316 for (unsigned j = 0; j < elements_connected_to_node.size(); j++)
317 {
318 // only matrix elements
319 if (elements_connected_to_node[j]->getDimension() <
320 mesh.getDimension())
321 {
322 continue;
323 }
324 vec_ele.push_back(const_cast<MeshLib::Element*>(
325 elements_connected_to_node[j]));
326 }
327 }
328 }
331
332 // second, append fracture elements
333 std::copy(fracture_elements.begin(), fracture_elements.end(),
334 std::back_inserter(vec_ele));
335 // thirdly, append intersected fracture elements
336 std::copy(intersected_fracture_elements[fid].begin(),
337 intersected_fracture_elements[fid].end(),
338 std::back_inserter(vec_ele));
339
340 vec_fracture_matrix_elements.push_back(vec_ele);
341 }
342}
343
344} // namespace LIE
345} // namespace ProcessLib
#define OGS_FATAL(...)
Definition Error.h:19
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22
std::size_t getID() const
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
std::vector< Element const * > const & getElementsConnectedToNode(std::size_t node_id) const
Definition Mesh.cpp:246
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:88
Node search class.
Definition NodeSearch.h:18
std::size_t searchBoundaryNodes()
Marks all boundary nodes.
void makeVectorUnique(std::vector< T > &v)
Definition Algorithm.h:173
bool idsComparator(T const a, T const b)
Definition Mesh.h:197
PropertyVector< int > const * materialIDs(Mesh const &mesh)
Definition Mesh.cpp:258
void findFracutreIntersections(MeshLib::Mesh const &mesh, std::vector< int > const &vec_fracture_mat_IDs, std::vector< std::vector< MeshLib::Node * > > const &vec_fracture_nodes, std::vector< std::vector< MeshLib::Element * > > &intersected_fracture_elements, std::vector< std::pair< std::size_t, std::vector< int > > > &vec_branch_nodeID_matIDs, std::vector< std::pair< std::size_t, std::vector< int > > > &vec_junction_nodeID_matIDs)
void getFractureMatrixDataInMesh(MeshLib::Mesh const &mesh, std::vector< MeshLib::Element * > &vec_matrix_elements, std::vector< int > &vec_fracture_mat_IDs, std::vector< std::vector< MeshLib::Element * > > &vec_fracture_elements, std::vector< std::vector< MeshLib::Element * > > &vec_fracture_matrix_elements, std::vector< std::vector< MeshLib::Node * > > &vec_fracture_nodes, std::vector< std::pair< std::size_t, std::vector< int > > > &vec_branch_nodeID_matIDs, std::vector< std::pair< std::size_t, std::vector< int > > > &vec_junction_nodeID_matIDs)