OGS
SubmeshResiduumOutputConfig.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
5
6#include <numeric>
7#include <unordered_set>
8
9#include "CreateOutput.h"
10#include "CreateOutputConfig.h"
11
12namespace
13{
14std::vector<std::reference_wrapper<MeshLib::Mesh>>
16 std::vector<std::unique_ptr<MeshLib::Mesh>> const& meshes,
17 std::vector<std::string> const& mesh_names_for_output)
18{
19 std::map<std::string, std::reference_wrapper<MeshLib::Mesh>>
20 map_mesh_name_to_mesh;
21 for (auto const& mesh : meshes)
22 {
23 auto const [it, inserted] =
24 map_mesh_name_to_mesh.emplace(mesh->getName(), *mesh);
25
26 if (!inserted)
27 {
28 OGS_FATAL("Duplicate mesh name '{}' detected.", mesh->getName());
29 }
30 }
31
32 std::vector<std::reference_wrapper<MeshLib::Mesh>> meshes_filtered;
33
34 for (auto const& mesh_name : mesh_names_for_output)
35 {
36 auto const& mesh = BaseLib::getOrError(
37 map_mesh_name_to_mesh, mesh_name,
38 "A mesh that has been requested for output is not known to OGS.");
39
40 meshes_filtered.push_back(mesh);
41 }
42
43 return meshes_filtered;
44}
45
46bool areElementsUnique(std::vector<std::string> const& strings)
47{
48 std::unordered_set<std::string_view> const strings_set(strings.begin(),
49 strings.end());
50
51 return strings_set.size() == strings.size();
52}
53
55{
56 auto const& properties = mesh.getProperties();
57
58 if (!properties.existsPropertyVector<std::size_t>(
61 {
63 "The required nodal property '{}' is missing in mesh '{}' or has "
64 "the wrong data type or the wrong number of components",
66 mesh.getName());
67 }
68
69 if (!properties.existsPropertyVector<std::size_t>(
72 {
74 "The required cell property '{}' is missing in mesh '{}' or has "
75 "the wrong data type or the wrong number of components",
77 mesh.getName());
78 }
79}
80
82 MeshLib::Mesh const& bulk_mesh,
83 std::vector<std::reference_wrapper<MeshLib::Mesh>> const& submesh_refs)
84{
85 auto const n_elements_bulk = bulk_mesh.getNumberOfElements();
86 auto const sum_elements_submeshes = [&submesh_refs]()
87 {
88 std::size_t n = 0;
89 for (auto const& submesh_ref : submesh_refs)
90 {
91 n += submesh_ref.get().getNumberOfElements();
92 }
93 return n;
94 }();
95
96 if (n_elements_bulk != sum_elements_submeshes)
97 {
99 "The number of bulk mesh elements does not match the sum of all "
100 "submesh elements: {} != {}. Hence, the set of all submeshes "
101 "cannot be a non-overlapping cover of the bulk mesh.",
102 n_elements_bulk, sum_elements_submeshes);
103 }
104}
105
107 MeshLib::Mesh const& bulk_mesh,
108 std::vector<std::reference_wrapper<MeshLib::Mesh>> const& submesh_refs)
109{
110 auto const n_elements_bulk = bulk_mesh.getNumberOfElements();
111
112 std::vector<bool> bulk_element_covered(n_elements_bulk);
113
114 for (auto const& submesh_ref : submesh_refs)
115 {
116 auto const& submesh = submesh_ref.get();
117 auto const& bulk_element_ids = bulkElementIDs(submesh);
118 if (bulk_element_ids == nullptr)
119 {
120 OGS_FATAL(
121 "The 'bulk_element_ids' property does not exist on the submesh "
122 "{:s}.",
123 submesh.getName());
124 }
125
126 if (bulk_element_ids->size() != submesh.getNumberOfElements())
127 {
128 OGS_FATAL(
129 "There is something terribly wrong with the mesh '{}'. The "
130 "size of 'bulk_element_ids' does not equal the number of "
131 "elements in the mesh: {} != {}",
132 submesh.getName(), bulk_element_ids->size(),
133 submesh.getNumberOfElements());
134 }
135
136 for (auto const bulk_element_id : *bulk_element_ids)
137 {
138 // meshes are provided as user input, so we better check the bounds
139 // of the contained data
140 [[unlikely]] if (bulk_element_id >= n_elements_bulk)
141 {
142 OGS_FATAL(
143 "Saw bulk element id {} in submesh '{}', but the bulk mesh "
144 "('{}') has only {} elements, i.e., the maximum allowed "
145 "bulk element id is {}.",
146 bulk_element_id, submesh.getName(), bulk_mesh.getName(),
147 n_elements_bulk, n_elements_bulk - 1);
148 }
149
150 [[unlikely]] if (bulk_element_covered[bulk_element_id])
151 {
152 OGS_FATAL(
153 "The bulk element id {} has already been covered by "
154 "another submesh. The second submesh covering this bulk "
155 "element is '{}'.",
156 bulk_element_id, submesh.getName());
157 }
158
159 bulk_element_covered[bulk_element_id] = true;
160 }
161 }
162
163 return bulk_element_covered;
164}
165
167 MeshLib::Mesh const& bulk_mesh,
168 std::vector<std::reference_wrapper<MeshLib::Mesh>> const& submesh_refs)
169{
170 checkMatchingElementCounts(bulk_mesh, submesh_refs);
171
172 auto const n_elements_bulk = bulk_mesh.getNumberOfElements();
173
174 std::vector<bool> const bulk_element_covered =
175 computeNonOverlappingBulkMeshCoverBySubmeshes(bulk_mesh, submesh_refs);
176
177 auto const n_elements_covered =
178 std::accumulate(bulk_element_covered.begin(),
179 bulk_element_covered.end(), std::size_t{0});
180
181 if (n_elements_covered == n_elements_bulk)
182 {
183 return;
184 }
185
186 // search first bulk element that has not been covered
187 auto const non_covered_it = std::find(bulk_element_covered.begin(),
188 bulk_element_covered.end(), false);
189 auto const non_covered_index =
190 std::distance(bulk_element_covered.begin(), non_covered_it);
191
192 OGS_FATAL(
193 "The bulk mesh ('{}') is not covered completely by the given "
194 "submeshes. Only {} out of {} elements are covered. The first element "
195 "that is not covered is #{}.",
196 bulk_mesh.getName(), n_elements_covered, n_elements_bulk,
197 non_covered_index);
198}
199} // namespace
200
201namespace ProcessLib
202{
204 BaseLib::ConfigTree const& config, std::string const& output_directory,
205 std::vector<std::unique_ptr<MeshLib::Mesh>>& meshes)
206{
207 auto oc = createOutputConfig(config, meshes);
208
209 if (oc.mesh_names_for_output.empty())
210 {
211 OGS_FATAL(
212 "You did not specify any meshes for submesh residuum output.");
213 }
214
215 if (!areElementsUnique(oc.mesh_names_for_output))
216 {
217 OGS_FATAL("The mesh names for submesh residuum output are not unique.");
218 }
219
220 auto const meshes_filtered =
221 filterMeshesForResiduumOutput(meshes, oc.mesh_names_for_output);
222
223 for (auto const& mesh : meshes_filtered)
224 {
225 checkBulkIDMappingsPresent(mesh.get());
226 }
227
228 auto const& bulk_mesh =
229 *meshes.front(); // convention: the first mesh is the bulk mesh
230 checkNonOverlappingCover(bulk_mesh, meshes_filtered);
231
232 return {createOutput(std::move(oc), output_directory, meshes),
233 std::move(meshes_filtered)};
234}
235} // namespace ProcessLib
#define OGS_FATAL(...)
Definition Error.h:19
Properties & getProperties()
Definition Mesh.h:125
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:94
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:88
OGS_NO_DANGLING Map::mapped_type & getOrError(Map &map, Key const &key, std::string const &error_message)
Definition Algorithm.h:111
constexpr std::string_view getBulkIDString(MeshItemType mesh_item_type)
OutputConfig createOutputConfig(const BaseLib::ConfigTree &config, std::vector< std::unique_ptr< MeshLib::Mesh > > &meshes)
SubmeshResiduumOutputConfig createSubmeshResiduumOutputConfig(BaseLib::ConfigTree const &config, std::string const &output_directory, std::vector< std::unique_ptr< MeshLib::Mesh > > &meshes)
Output createOutput(OutputConfig &&oc, std::string const &output_directory, std::vector< std::unique_ptr< MeshLib::Mesh > > const &meshes)
bool areElementsUnique(std::vector< std::string > const &strings)
std::vector< std::reference_wrapper< MeshLib::Mesh > > filterMeshesForResiduumOutput(std::vector< std::unique_ptr< MeshLib::Mesh > > const &meshes, std::vector< std::string > const &mesh_names_for_output)
void checkMatchingElementCounts(MeshLib::Mesh const &bulk_mesh, std::vector< std::reference_wrapper< MeshLib::Mesh > > const &submesh_refs)
std::vector< bool > computeNonOverlappingBulkMeshCoverBySubmeshes(MeshLib::Mesh const &bulk_mesh, std::vector< std::reference_wrapper< MeshLib::Mesh > > const &submesh_refs)
void checkNonOverlappingCover(MeshLib::Mesh const &bulk_mesh, std::vector< std::reference_wrapper< MeshLib::Mesh > > const &submesh_refs)