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