OGS
IdentifySubdomainMesh.cpp
Go to the documentation of this file.
1 
10 #include <map>
11 #include <vector>
12 
14 #include "MeshLib/Mesh.h"
15 #include "MeshLib/Node.h"
16 #include "MeshNodeSearcher.h"
17 
18 namespace
19 {
22 std::vector<std::size_t> identifySubdomainMeshNodes(
23  MeshLib::Mesh const& subdomain_mesh,
24  MeshGeoToolsLib::MeshNodeSearcher const& mesh_node_searcher)
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  {
36  OGS_FATAL(
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 }
45 
49 std::vector<std::size_t> findElementsInMesh(
50  MeshLib::Mesh const& mesh, std::vector<std::size_t> const& node_ids)
51 {
52  //
53  // Collect all element ids for all nodes.
54  //
55  std::vector<std::size_t> common_element_ids;
56  // Every node is connected to at least one element.
57  auto const nnodes = node_ids.size();
58  common_element_ids.reserve(nnodes);
59 
60  for (auto const node_id : node_ids)
61  {
62  auto const& connected_elements =
63  mesh.getElementsConnectedToNode(node_id);
64  std::transform(begin(connected_elements), end(connected_elements),
65  back_inserter(common_element_ids),
66  [](MeshLib::Element const* const e)
67  { return e->getID(); });
68  }
69 
70  //
71  // Count how often an element is shared by all nodes.
72  //
73  std::map<std::size_t, int> element_counts;
74  for (auto const element_id : common_element_ids)
75  {
76  element_counts[element_id]++;
77  }
78 
79  //
80  // Elements which are shared by as many nodes as the input nodes are the
81  // desired elements.
82  //
83  std::vector<std::size_t> element_ids;
84  for (auto const& pair : element_counts)
85  {
86  if (pair.second == static_cast<int>(nnodes))
87  {
88  element_ids.push_back(pair.first);
89  }
90  }
91 
92  return element_ids;
93 }
94 
98 std::vector<std::vector<std::size_t>> identifySubdomainMeshElements(
99  MeshLib::Mesh const& subdomain_mesh, MeshLib::Mesh const& bulk_mesh)
100 {
101  auto& properties = subdomain_mesh.getProperties();
102  auto const& bulk_node_ids = *properties.getPropertyVector<std::size_t>(
103  "bulk_node_ids", MeshLib::MeshItemType::Node, 1);
104 
105  // Allocate space for all elements for random insertion.
106  std::vector<std::vector<std::size_t>> bulk_element_ids_map(
107  subdomain_mesh.getNumberOfElements());
108 
109  for (auto* const e : subdomain_mesh.getElements())
110  {
111  std::vector<std::size_t> element_node_ids(e->getNumberOfBaseNodes());
112  for (unsigned n = 0; n < e->getNumberOfBaseNodes(); ++n)
113  {
114  element_node_ids[n] = MeshLib::getNodeIndex(*e, n);
115  }
116  std::vector<std::size_t> element_node_ids_bulk(
117  e->getNumberOfBaseNodes());
118  std::transform(begin(element_node_ids), end(element_node_ids),
119  begin(element_node_ids_bulk),
120  [&bulk_node_ids](std::size_t const id)
121  { return bulk_node_ids[id]; });
122  std::vector<std::size_t> bulk_element_ids =
123  findElementsInMesh(bulk_mesh, element_node_ids_bulk);
124 
125  if (bulk_element_ids.empty())
126  {
127  ERR("No element could be found for the subdomain element {:d}. "
128  "Corresponding bulk mesh node ids are:",
129  e->getID());
130  for (auto const i : element_node_ids_bulk)
131  {
132  ERR("\t{:d}", i);
133  }
134  OGS_FATAL(
135  "Expect at least one element to be found in the bulk mesh.");
136  }
137 
138  bulk_element_ids_map[e->getID()] = std::move(bulk_element_ids);
139  }
140 
141  return bulk_element_ids_map;
142 }
143 
146  MeshLib::Mesh& mesh, std::string const& property_name,
147  std::vector<std::size_t> const& values,
148  MeshLib::MeshItemType const mesh_item_type, bool const force_overwrite)
149 {
150  auto& properties = mesh.getProperties();
151  if (!properties.existsPropertyVector<std::size_t>(property_name))
152  {
153  addPropertyToMesh(mesh, property_name, mesh_item_type, 1, values);
154  return;
155  }
156 
157  //
158  // Check the existing property against new values.
159  //
160  auto& original_property =
161  *properties.getPropertyVector<std::size_t>(property_name);
162  if (std::equal(begin(original_property), end(original_property),
163  begin(values), end(values)))
164  {
165  INFO(
166  "There is already a '{:s}' property present in the subdomain mesh "
167  "'{:s}' and it is equal to the newly computed values.",
168  property_name, mesh.getName());
169  return;
170  }
171 
172  //
173  // Property differs. Notify and update if forced.
174  //
175  WARN(
176  "There is already a '{:s}' property present in the subdomain mesh "
177  "'{:s}' and it is not equal to the newly computed values.",
178  property_name,
179  mesh.getName());
180 
181  if (!force_overwrite)
182  {
183  OGS_FATAL("The force overwrite flag was not specified, exiting.");
184  }
185 
186  INFO("Overwriting '{:s}' property.", property_name);
187  original_property.resize(values.size());
188  std::copy(begin(values), end(values), begin(original_property));
189 }
190 } // namespace
191 
192 namespace MeshGeoToolsLib
193 {
195  MeshLib::Mesh const& bulk_mesh,
196  MeshNodeSearcher const& mesh_node_searcher,
197  bool const force_overwrite = false)
198 {
199  auto const& bulk_node_ids =
200  identifySubdomainMeshNodes(subdomain_mesh, mesh_node_searcher);
201 
203  subdomain_mesh, "bulk_node_ids", bulk_node_ids,
204  MeshLib::MeshItemType::Node, force_overwrite);
205 
206  auto const& bulk_element_ids =
207  identifySubdomainMeshElements(subdomain_mesh, bulk_mesh);
208 
209  // The bulk_element_ids could be of two types: one element per entry---this
210  // is the expected case for the boundary meshes; multiple elements per
211  // entry---this happens if the subdomain mesh lies inside the bulk mesh and
212  // has lower dimension.
213  // First find out the type, then add/check the CellData or FieldData.
214  if (all_of(begin(bulk_element_ids), end(bulk_element_ids),
215  [](std::vector<std::size_t> const& v) { return v.size() == 1; }))
216  {
217  // All vectors are of size 1, so the data can be flattened and
218  // stored in CellData or compared to existing CellData.
219  std::vector<std::size_t> unique_bulk_element_ids;
220  unique_bulk_element_ids.reserve(bulk_element_ids.size());
221  transform(begin(bulk_element_ids), end(bulk_element_ids),
222  back_inserter(unique_bulk_element_ids),
223  [](std::vector<std::size_t> const& v) { return v[0]; });
224 
226  subdomain_mesh, "bulk_element_ids", unique_bulk_element_ids,
227  MeshLib::MeshItemType::Cell, force_overwrite);
228  }
229  else
230  {
231  // Some of the boundary elements are connected to multiple bulk
232  // elements; Store the array in FieldData with additional CellData array
233  // for the number of elements, which also provides the offsets.
234  std::vector<std::size_t> flat_bulk_element_ids;
235  flat_bulk_element_ids.reserve(2 * bulk_element_ids.size()); // Guess.
236  std::vector<std::size_t> number_of_bulk_element_ids;
237  number_of_bulk_element_ids.reserve(bulk_element_ids.size());
238 
239  for (std::vector<std::size_t> const& v : bulk_element_ids)
240  {
241  number_of_bulk_element_ids.push_back(v.size());
242  flat_bulk_element_ids.insert(end(flat_bulk_element_ids), begin(v),
243  end(v));
244  }
245 
247  subdomain_mesh, "number_bulk_elements", number_of_bulk_element_ids,
248  MeshLib::MeshItemType::Cell, force_overwrite);
250  subdomain_mesh, "bulk_element_ids", flat_bulk_element_ids,
251  MeshLib::MeshItemType::IntegrationPoint, force_overwrite);
252  }
253 }
254 } // namespace MeshGeoToolsLib
Definition of the Element class.
#define OGS_FATAL(...)
Definition: Error.h:26
void INFO(char const *fmt, Args const &... args)
Definition: Logging.h:32
void ERR(char const *fmt, Args const &... args)
Definition: Logging.h:42
void WARN(char const *fmt, Args const &... args)
Definition: Logging.h:37
Definition of the Mesh class.
Definition of the Node class.
std::vector< std::size_t > getMeshNodeIDs(GeoLib::GeoObject const &geoObj) const
virtual std::size_t getID() const final
Returns the ID of the element.
Definition: Element.h:82
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition: Mesh.h:95
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition: Mesh.h:98
const std::string getName() const
Get name of the mesh.
Definition: Mesh.h:92
Properties & getProperties()
Definition: Mesh.h:123
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition: Mesh.h:89
std::vector< Element const * > const & getElementsConnectedToNode(std::size_t node_id) const
Definition: Mesh.cpp:232
std::size_t getNumberOfElements() const
Get the number of elements.
Definition: Mesh.h:86
PropertyVector< T > const * getPropertyVector(std::string const &name) const
void copy(PETScVector const &x, PETScVector &y)
Definition: LinAlg.cpp:37
void identifySubdomainMesh(MeshLib::Mesh &subdomain_mesh, MeshLib::Mesh const &bulk_mesh, MeshNodeSearcher const &mesh_node_searcher, bool const force_overwrite=false)
MeshItemType
Definition: Location.h:21
std::size_t getNodeIndex(Element const &element, unsigned const idx)
Definition: Element.cpp:225
void addPropertyToMesh(Mesh &mesh, std::string const &name, MeshItemType item_type, std::size_t number_of_components, std::vector< T > const &values)
Definition: Mesh.h:193
std::vector< std::size_t > identifySubdomainMeshNodes(MeshLib::Mesh const &subdomain_mesh, MeshGeoToolsLib::MeshNodeSearcher const &mesh_node_searcher)
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 const &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.
std::vector< std::size_t > findElementsInMesh(MeshLib::Mesh const &mesh, std::vector< std::size_t > const &node_ids)