OGS
anonymous_namespace{IdentifySubdomainMesh.cpp} Namespace Reference

Functions

std::vector< std::size_t > identifySubdomainMeshNodes (MeshLib::Mesh const &subdomain_mesh, MeshGeoToolsLib::MeshNodeSearcher const &mesh_node_searcher)
std::vector< std::size_t > findElementsInMesh (std::vector< std::size_t > const &node_ids, std::vector< std::vector< std::size_t > > const &connected_element_ids_per_node)
std::vector< std::vector< std::size_t > > identifySubdomainMeshElements (MeshLib::Mesh const &subdomain_mesh, MeshLib::Mesh const &bulk_mesh)
void updateOrCheckExistingSubdomainProperty (MeshLib::Mesh &mesh, std::string_view property_name, std::vector< std::size_t > const &values, MeshLib::MeshItemType const mesh_item_type, bool const force_overwrite)
 Updates or checks the existing mesh's property with the given values.

Function Documentation

◆ findElementsInMesh()

std::vector< std::size_t > anonymous_namespace{IdentifySubdomainMesh.cpp}::findElementsInMesh ( std::vector< std::size_t > const & node_ids,
std::vector< std::vector< std::size_t > > const & connected_element_ids_per_node )

Find all elements which consist of all of the given node ids.

Note
It is recommended to include only base nodes of elements into the search node_ids.

Definition at line 49 of file IdentifySubdomainMesh.cpp.

52{
53 if (node_ids.empty())
54 {
55 return {};
56 }
57
58 // An element belongs to the subdomain element when it is connected to all
59 // of the given nodes. Use the node with the fewest connected elements as
60 // the candidate set and keep only those candidates that are connected to
61 // every other node. This avoids any allocation that scales with the bulk
62 // mesh size, so the work per call stays cheap inside the parallel loop
63 // over subdomain elements. Only local state is used, hence thread-safe.
64 auto const& smallest_elements =
65 connected_element_ids_per_node[*std::min_element(
66 begin(node_ids), end(node_ids),
67 [&connected_element_ids_per_node](std::size_t const a,
68 std::size_t const b)
69 {
70 return connected_element_ids_per_node[a].size() <
71 connected_element_ids_per_node[b].size();
72 })];
73
74 std::vector<std::size_t> element_ids;
75 for (auto const element_id : smallest_elements)
76 {
77 bool const shared_by_all = std::all_of(
78 begin(node_ids), end(node_ids),
79 [&connected_element_ids_per_node,
80 element_id](std::size_t const node_id)
81 {
82 auto const& elements = connected_element_ids_per_node[node_id];
83 return std::find(begin(elements), end(elements), element_id) !=
84 end(elements);
85 });
86 if (shared_by_all)
87 {
88 element_ids.push_back(element_id);
89 }
90 }
91
92 // Sort descending so the result is deterministic across compilers and
93 // parallel execution ordering.
94 std::sort(element_ids.begin(), element_ids.end(),
95 std::greater<std::size_t>());
96
97 return element_ids;
98}

Referenced by identifySubdomainMeshElements().

◆ identifySubdomainMeshElements()

std::vector< std::vector< std::size_t > > anonymous_namespace{IdentifySubdomainMesh.cpp}::identifySubdomainMeshElements ( MeshLib::Mesh const & subdomain_mesh,
MeshLib::Mesh const & bulk_mesh )

Tries to find all elements' ids in the bulk mesh. The subdomain elements' nodes are mapped to the bulk mesh and are then used to identify the bulk mesh elements.

Definition at line 103 of file IdentifySubdomainMesh.cpp.

105{
106 auto const& bulk_node_ids = *MeshLib::bulkNodeIDs(subdomain_mesh);
107
108 // Allocate space for all elements for random insertion.
109 std::vector<std::vector<std::size_t>> bulk_element_ids_map(
110 subdomain_mesh.getNumberOfElements());
111
112 // For each node a vector of connected element ids of that node.
113 std::vector<std::vector<std::size_t>> connected_element_ids_per_node(
114 bulk_mesh.getNumberOfNodes());
115 for (auto const node_id : bulk_mesh.getNodes() | MeshLib::views::ids)
116 {
117 connected_element_ids_per_node[node_id] =
118 bulk_mesh.getElementsConnectedToNode(node_id) |
119 MeshLib::views::ids | ranges::to<std::vector>;
120 }
121
122 auto const& elements = subdomain_mesh.getElements();
123#pragma omp parallel for
124 for (std::ptrdiff_t j = 0; j < std::ssize(elements); ++j)
125 {
126 auto* const e = elements[j];
127 std::vector<std::size_t> element_node_ids(e->getNumberOfBaseNodes());
128 for (unsigned n = 0; n < e->getNumberOfBaseNodes(); ++n)
129 {
130 element_node_ids[n] = MeshLib::getNodeIndex(*e, n);
131 }
132 std::vector<std::size_t> element_node_ids_bulk(
133 e->getNumberOfBaseNodes());
134 std::transform(begin(element_node_ids), end(element_node_ids),
135 begin(element_node_ids_bulk),
136 [&bulk_node_ids](std::size_t const id)
137 { return bulk_node_ids[id]; });
138
139 std::vector<std::size_t> bulk_element_ids = findElementsInMesh(
140 element_node_ids_bulk, connected_element_ids_per_node);
141
142 if (bulk_element_ids.empty())
143 {
144 ERR("No element could be found for the subdomain element {:d}. "
145 "Corresponding bulk mesh node ids are:",
146 e->getID());
147 for (auto const i : element_node_ids_bulk)
148 {
149 ERR("\t{:d}", i);
150 }
151 OGS_FATAL(
152 "Expect at least one element to be found in the bulk mesh.");
153 }
154
155 bulk_element_ids_map[e->getID()] = std::move(bulk_element_ids);
156 }
157
158 return bulk_element_ids_map;
159}
#define OGS_FATAL(...)
Definition Error.h:10
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
Definition Mesh.h:223
std::size_t getNodeIndex(Element const &element, unsigned const idx)
Definition Element.cpp:226
PropertyVector< std::size_t > const * bulkNodeIDs(Mesh const &mesh)
Definition Mesh.cpp:284
std::vector< std::size_t > findElementsInMesh(std::vector< std::size_t > const &node_ids, std::vector< std::vector< std::size_t > > const &connected_element_ids_per_node)

References MeshLib::bulkNodeIDs(), ERR(), findElementsInMesh(), MeshLib::Mesh::getElements(), MeshLib::Mesh::getElementsConnectedToNode(), MeshLib::getNodeIndex(), MeshLib::Mesh::getNodes(), MeshLib::Mesh::getNumberOfElements(), MeshLib::Mesh::getNumberOfNodes(), MeshLib::views::ids, and OGS_FATAL.

◆ identifySubdomainMeshNodes()

std::vector< std::size_t > anonymous_namespace{IdentifySubdomainMesh.cpp}::identifySubdomainMeshNodes ( MeshLib::Mesh const & subdomain_mesh,
MeshGeoToolsLib::MeshNodeSearcher const & mesh_node_searcher )

Find one-to-one mapping of subdomain nodes to the bulk mesh nodes and returns the map of ids.

Definition at line 22 of file IdentifySubdomainMesh.cpp.

25{
26 // Convert nodes pointers needed for the mesh_node_searcher algorithm.
27 auto const& nodes = subdomain_mesh.getNodes();
28 std::vector<MathLib::Point3dWithID*> subdomain_points{begin(nodes),
29 end(nodes)};
30
31 auto const& bulk_node_ids =
32 mesh_node_searcher.getMeshNodeIDs(subdomain_points);
33
34 if (bulk_node_ids.size() != subdomain_mesh.getNumberOfNodes())
35 {
37 "Expected to find exactly one node in the bulk mesh for each node "
38 "of the subdomain; Found {:d} nodes in the bulk mesh out of {:d} "
39 "nodes in the subdomain.",
40 bulk_node_ids.size(), subdomain_mesh.getNumberOfNodes());
41 }
42
43 return bulk_node_ids;
44}

References MeshGeoToolsLib::MeshNodeSearcher::getMeshNodeIDs(), MeshLib::Mesh::getNodes(), MeshLib::Mesh::getNumberOfNodes(), and OGS_FATAL.

◆ updateOrCheckExistingSubdomainProperty()

void anonymous_namespace{IdentifySubdomainMesh.cpp}::updateOrCheckExistingSubdomainProperty ( MeshLib::Mesh & mesh,
std::string_view property_name,
std::vector< std::size_t > const & values,
MeshLib::MeshItemType const mesh_item_type,
bool const force_overwrite )

Updates or checks the existing mesh's property with the given values.

Definition at line 162 of file IdentifySubdomainMesh.cpp.

166{
167 auto& properties = mesh.getProperties();
168 const bool property_name_exists =
169 properties.hasPropertyVector(property_name);
170 if (!properties.existsPropertyVector<std::size_t>(property_name,
171 mesh_item_type, 1))
172 {
173 if (property_name_exists)
174 {
175 if (!force_overwrite)
176 {
177 OGS_FATAL(
178 "A property named '{:s}' already exists on mesh '{:s}', "
179 "but it has a different mesh item type or number of "
180 "components. Use force overwrite to replace it.",
181 property_name, mesh.getName());
182 }
183
184 WARN(
185 "A property named '{:s}' exists on mesh '{:s}' with a "
186 "different mesh item type or number of components. "
187 "Overwriting it.",
188 property_name, mesh.getName());
189 properties.removePropertyVector(property_name);
190 }
191
192 addPropertyToMesh<std::size_t>(mesh, property_name, mesh_item_type, 1,
193 {values});
194 return;
195 }
196
197 //
198 // Check the existing property against new values.
199 //
200 auto& original_property =
201 *properties.getPropertyVector<std::size_t>(property_name);
202 if (ranges::equal(original_property, values))
203 {
204 INFO(
205 "There is already a '{:s}' property present in the subdomain mesh "
206 "'{:s}' and it is equal to the newly computed values.",
207 property_name, mesh.getName());
208 return;
209 }
210
211 //
212 // Property differs. Notify and update if forced.
213 //
214 WARN(
215 "There is already a '{:s}' property present in the subdomain mesh "
216 "'{:s}' and it is not equal to the newly computed values.",
217 property_name,
218 mesh.getName());
219
220 if (!force_overwrite)
221 {
222 OGS_FATAL("The force overwrite flag was not specified, exiting.");
223 }
224
225 INFO("Overwriting '{:s}' property.", property_name);
226 original_property.assign(values);
227}
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:28
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
Properties & getProperties()
Definition Mesh.h:127
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:95
bool hasPropertyVector(std::string_view name) const

References MeshLib::Mesh::getName(), MeshLib::Mesh::getProperties(), MeshLib::Properties::hasPropertyVector(), INFO(), OGS_FATAL, and WARN().