OGS
AddProcessDataToMesh.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 <span>
7
8#include "InfoLib/GitInfo.h"
14#ifdef USE_PETSC
16#endif
18
21static void addOgsVersion(MeshLib::Mesh& mesh)
22{
23 auto& ogs_version_field = *MeshLib::getOrCreateMeshProperty<char>(
26
27 ogs_version_field.assign(GitInfoLib::GitInfo::ogs_version);
28}
29
31 NumLib::Time const& t,
32 std::vector<GlobalVector*> const& x,
33 std::vector<NumLib::LocalToGlobalIndexMap const*> const& dof_tables,
35 std::string const& output_name,
36 MeshLib::Mesh& mesh)
37{
38 DBUG(" secondary variable {:s}", output_name);
39
40 auto& nodal_values_mesh = *MeshLib::getOrCreateMeshProperty<double>(
41 mesh, output_name, MeshLib::MeshItemType::Node,
43 if (nodal_values_mesh.size() !=
45 {
47 "Nodal property `{:s}' does not have the right number of "
48 "components. Expected: {:d}, actual: {:d}",
49 output_name,
51 nodal_values_mesh.size());
52 }
53
54 std::unique_ptr<GlobalVector> result_cache;
55 auto const& nodal_values =
56 var.fcts.eval_field(t(), x, dof_tables, result_cache);
57
58#ifdef USE_PETSC
59 std::size_t const global_vector_size =
60 nodal_values.getLocalSize() + nodal_values.getGhostSize();
61#else
62 std::size_t const global_vector_size = nodal_values.size();
63#endif
64 if (nodal_values_mesh.size() != global_vector_size)
65 {
67 "Secondary variable `{:s}' did not evaluate to the right number of "
68 "components. Expected: {:d}, actual: {:d}.",
69 var.name, nodal_values_mesh.size(), global_vector_size);
70 }
71
72 // Copy result
73 nodal_values.copyValues(std::span{nodal_values_mesh});
74}
75
77 NumLib::Time const& t,
78 std::vector<GlobalVector*> const& x,
79 std::vector<NumLib::LocalToGlobalIndexMap const*> const& dof_table,
81 std::string const& output_name,
82 MeshLib::Mesh& mesh)
83{
84 if (!var.fcts.eval_residuals)
85 {
86 return;
87 }
88
89 DBUG(" secondary variable {:s} residual", output_name);
90 auto const& property_name_res = output_name + "_residual";
91
92 auto& residuals_mesh = *MeshLib::getOrCreateMeshProperty<double>(
93 mesh, property_name_res, MeshLib::MeshItemType::Cell,
95 if (residuals_mesh.size() !=
97 {
99 "Cell property `{:s}' does not have the right number of "
100 "components. Expected: {:d}, actual: {:d}",
101 property_name_res,
103 residuals_mesh.size());
104 }
105
106 std::unique_ptr<GlobalVector> result_cache;
107 auto const& residuals =
108 var.fcts.eval_residuals(t(), x, dof_table, result_cache);
109#ifdef USE_PETSC
110 std::size_t const global_vector_size =
111 residuals.getLocalSize() + residuals.getGhostSize();
112#else
113 std::size_t const global_vector_size = residuals.size();
114#endif
115 if (residuals_mesh.size() != global_vector_size)
116 {
117 OGS_FATAL(
118 "The residual of secondary variable `{:s}' did not evaluate to the "
119 "right number of components. Expected: {:d}, actual: {:d}.",
120 var.name, residuals_mesh.size(), global_vector_size);
121 }
122
123 // Copy result
124 residuals.copyValues(std::span{residuals_mesh});
125}
126
127static std::vector<double> copySolutionVector(GlobalVector const& x)
128{
129 std::vector<double> x_copy;
130 x.copyValues(x_copy);
131 return x_copy;
132}
133
135 [[maybe_unused]] MeshLib::Mesh const& mesh,
136 [[maybe_unused]] NumLib::LocalToGlobalIndexMap const& dof_table,
137 [[maybe_unused]] NumLib::LocalToGlobalIndexMap const& bulk_mesh_dof_table)
138{
139#ifdef USE_PETSC
140
141 if (&bulk_mesh_dof_table != &dof_table)
142 {
143 auto const bulk_id_string =
145 if (!mesh.getProperties().existsPropertyVector<std::size_t>(
146 bulk_id_string))
147 {
148 OGS_FATAL(
149 "The required bulk node ids map does not exist in "
150 "the boundary mesh '{:s}' or has the wrong data "
151 "type (should be equivalent to C++ data type "
152 "std::size_t which is an unsigned integer of size "
153 "{:d} or UInt64 in vtk terminology).",
154 mesh.getName(), sizeof(std::size_t));
155 }
156 return mesh.getProperties().getPropertyVector<std::size_t>(
157 bulk_id_string);
158 }
159#endif
160
161 return nullptr;
162}
163
165 std::size_t const mesh_id, std::size_t const node_id,
166 [[maybe_unused]] bool const is_ghost_node, int const global_component_id,
167 GlobalVector const& x, NumLib::LocalToGlobalIndexMap const& dof_table,
168 [[maybe_unused]] NumLib::LocalToGlobalIndexMap const& bulk_mesh_dof_table,
169 [[maybe_unused]] MeshLib::PropertyVector<std::size_t> const* const
170 bulk_node_id_map)
171{
172#ifdef USE_PETSC
173 if (is_ghost_node && &bulk_mesh_dof_table != &dof_table)
174 {
175 auto const bulk_node_id = (*bulk_node_id_map)[node_id];
176 std::size_t const bulk_mesh_id = 0;
177
178 MeshLib::Location const loc(bulk_mesh_id, MeshLib::MeshItemType::Node,
179 bulk_node_id);
180
181 // early return!
182 return bulk_mesh_dof_table.getLocalIndex(
183 loc, global_component_id, x.getRangeBegin(), x.getRangeEnd());
184 }
185#endif
186
187 MeshLib::Location const loc(mesh_id, MeshLib::MeshItemType::Node, node_id);
188
189 return dof_table.getLocalIndex(loc, global_component_id, x.getRangeBegin(),
190 x.getRangeEnd());
191}
192
193static bool isGhostNode([[maybe_unused]] MeshLib::Mesh const& mesh,
194 [[maybe_unused]] std::size_t const node_id)
195{
196#ifndef USE_PETSC
197 return false;
198#else
199 return static_cast<MeshLib::NodePartitionedMesh const&>(mesh).isGhostNode(
200 node_id);
201#endif
202}
203
233static std::set<std::string> addPrimaryVariablesToMesh(
234 MeshLib::Mesh& mesh,
235 GlobalVector const& x,
236 std::vector<std::reference_wrapper<ProcessLib::ProcessVariable>> const&
237 process_variables,
238 std::set<std::string> const& output_variables,
239 NumLib::LocalToGlobalIndexMap const& dof_table,
240 NumLib::LocalToGlobalIndexMap const& bulk_mesh_dof_table)
241{
242 if (dof_table.getNumberOfVariables() !=
243 bulk_mesh_dof_table.getNumberOfVariables() ||
244 dof_table.getNumberOfGlobalComponents() !=
245 bulk_mesh_dof_table.getNumberOfGlobalComponents())
246 {
247 OGS_FATAL(
248 "The d.o.f. table for the passed mesh must have the same number of "
249 "variables and global components as the d.o.f. table for the full "
250 "simulation domain. But the values differ: {} != {} (variables) or "
251 "{} != {} (global components).",
252 dof_table.getNumberOfVariables(),
253 bulk_mesh_dof_table.getNumberOfVariables(),
254 dof_table.getNumberOfGlobalComponents(),
255 bulk_mesh_dof_table.getNumberOfGlobalComponents());
256 }
257
258 auto const number_of_dof_variables = dof_table.getNumberOfVariables();
259
260 if (number_of_dof_variables != static_cast<int>(process_variables.size()))
261 {
262 OGS_FATAL(
263 "The number of variables in the d.o.f. table differs from the "
264 "number of primary variables of the process {} != {}.",
265 number_of_dof_variables, process_variables.size());
266 }
267
268 auto const x_copy = copySolutionVector(x);
269 std::set<std::string> names_of_already_output_variables;
270
271 int global_component_offset_next = 0;
272
273 auto const* const bulk_node_id_map = getBulkNodeIdMapForPetscIfNecessary(
274 mesh, dof_table, bulk_mesh_dof_table);
275
276 for (int variable_id = 0; variable_id < number_of_dof_variables;
277 ++variable_id)
278 {
279 auto const& pv = process_variables[variable_id].get();
280 auto const n_components = pv.getNumberOfGlobalComponents();
281
282 // increase global component offset even if we do not add anything in
283 // this iteration
284 int global_component_offset = global_component_offset_next;
285 global_component_offset_next += n_components;
286
287 if (!output_variables.empty() &&
288 !output_variables.contains(pv.getName()))
289 {
290 continue;
291 }
292
293 names_of_already_output_variables.insert(pv.getName());
294
295 DBUG(" process variable {:s}", pv.getName());
296
297 auto& output_data = *MeshLib::getOrCreateMeshProperty<double>(
298 mesh, pv.getName(), MeshLib::MeshItemType::Node, n_components);
299
300 // mesh subsets are the same for all components
301 int const dummy_component_id = 0;
302 auto const& mesh_subset =
303 dof_table.getMeshSubset(variable_id, dummy_component_id);
304 auto const mesh_id = mesh_subset.getMeshID();
305
306 for (auto const* node : mesh_subset.getNodes())
307 {
308 auto const node_id = node->getID();
309 auto const is_ghost_node = isGhostNode(mesh, node_id);
310
311 for (int component_id = 0; component_id < n_components;
312 ++component_id)
313 {
314 auto const global_component_id =
315 global_component_offset + component_id;
316
317 auto const in_index = getIndexForComponentInSolutionVector(
318 mesh_id, node_id, is_ghost_node, global_component_id, x,
319 dof_table, bulk_mesh_dof_table, bulk_node_id_map);
320
321 // per node ordering of components
322 auto const out_index = node_id * n_components + component_id;
323
324 // request for index of linear quantities at higher order nodes
325 // results in returning NumLib::MeshComponentMap::nop
326 if (in_index == NumLib::MeshComponentMap::nop)
327 {
328 output_data[out_index] = 0;
329 continue;
330 }
331
332 output_data[out_index] = x_copy[in_index];
333 }
334 }
335 }
336
337 return names_of_already_output_variables;
338}
339
341 ProcessLib::SecondaryVariableCollection const& secondary_variables,
342 std::set<std::string>& names_of_already_output_variables,
343 NumLib::Time const& t, std::vector<GlobalVector*> const& xs,
344 MeshLib::Mesh& mesh,
345 std::vector<NumLib::LocalToGlobalIndexMap const*> const& dof_tables,
346 bool const output_residuals)
347{
348 for (auto const& external_variable_name : secondary_variables)
349 {
350 auto const& name = external_variable_name.first;
351 if (!names_of_already_output_variables.insert(name).second)
352 {
353 // no insertion took place, output already done
354 continue;
355 }
356
357 addSecondaryVariableNodes(t, xs, dof_tables,
358 secondary_variables.get(name), name, mesh);
359
360 if (output_residuals)
361 {
363 t, xs, dof_tables, secondary_variables.get(name), name, mesh);
364 }
365 }
366}
367
368namespace ProcessLib
369{
371 std::vector<GlobalVector*> const& xs,
372 int const process_id,
373 ProcessOutputData const& process_output_data,
374 bool const output_secondary_variables,
375 OutputDataSpecification const& process_output)
376{
377 DBUG("Process output data.");
378
379 auto const& pod = process_output_data;
380 auto const& process_variables = pod.getProcessVariables(process_id);
381 auto const& secondary_variables = pod.getSecondaryVariables();
382 auto const* const integration_point_writers =
383 pod.getIntegrationPointWriters();
384 auto const& bulk_mesh_dof_table = pod.getBulkMeshDofTable(process_id);
385 auto const& output_mesh_dof_table = pod.getOutputMeshDofTable(process_id);
386 auto& output_mesh = pod.getOutputMesh();
387
388 auto const& output_variables = process_output.output_variables;
389
390 addOgsVersion(output_mesh);
391
392 auto names_of_already_output_variables = addPrimaryVariablesToMesh(
393 output_mesh, *xs[process_id], process_variables, output_variables,
394 output_mesh_dof_table, bulk_mesh_dof_table);
395
396 if (output_secondary_variables)
397 {
398 auto const& output_mesh_dof_tables =
399 pod.getOutputMeshDofTablesOfAllProcesses();
400
401 addSecondaryVariablesToMesh(secondary_variables,
402 names_of_already_output_variables, t, xs,
403 output_mesh, output_mesh_dof_tables,
404 process_output.output_residuals);
405 }
406
407 if (integration_point_writers)
408 {
409 addIntegrationPointDataToMesh(output_mesh, *integration_point_writers);
410 }
411}
412} // namespace ProcessLib
static void addSecondaryVariableNodes(NumLib::Time const &t, std::vector< GlobalVector * > const &x, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_tables, ProcessLib::SecondaryVariable const &var, std::string const &output_name, MeshLib::Mesh &mesh)
static std::vector< double > copySolutionVector(GlobalVector const &x)
static GlobalIndexType getIndexForComponentInSolutionVector(std::size_t const mesh_id, std::size_t const node_id, bool const is_ghost_node, int const global_component_id, GlobalVector const &x, NumLib::LocalToGlobalIndexMap const &dof_table, NumLib::LocalToGlobalIndexMap const &bulk_mesh_dof_table, MeshLib::PropertyVector< std::size_t > const *const bulk_node_id_map)
MeshLib::PropertyVector< std::size_t > const * getBulkNodeIdMapForPetscIfNecessary(MeshLib::Mesh const &mesh, NumLib::LocalToGlobalIndexMap const &dof_table, NumLib::LocalToGlobalIndexMap const &bulk_mesh_dof_table)
static std::set< std::string > addPrimaryVariablesToMesh(MeshLib::Mesh &mesh, GlobalVector const &x, std::vector< std::reference_wrapper< ProcessLib::ProcessVariable > > const &process_variables, std::set< std::string > const &output_variables, NumLib::LocalToGlobalIndexMap const &dof_table, NumLib::LocalToGlobalIndexMap const &bulk_mesh_dof_table)
static void addSecondaryVariablesToMesh(ProcessLib::SecondaryVariableCollection const &secondary_variables, std::set< std::string > &names_of_already_output_variables, NumLib::Time const &t, std::vector< GlobalVector * > const &xs, MeshLib::Mesh &mesh, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_tables, bool const output_residuals)
static void addSecondaryVariableResiduals(NumLib::Time const &t, std::vector< GlobalVector * > const &x, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_table, ProcessLib::SecondaryVariable const &var, std::string const &output_name, MeshLib::Mesh &mesh)
static bool isGhostNode(MeshLib::Mesh const &mesh, std::size_t const node_id)
static void addOgsVersion(MeshLib::Mesh &mesh)
#define OGS_FATAL(...)
Definition Error.h:19
MathLib::EigenVector GlobalVector
GlobalMatrix::IndexType GlobalIndexType
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22
IndexType getRangeEnd() const
return an end index of the active data range
Definition EigenVector.h:42
void copyValues(std::vector< double > &u) const
static constexpr IndexType getRangeBegin()
return a start index of the active data range
Definition EigenVector.h:39
std::size_t getMeshID() const
return this mesh ID
Definition MeshSubset.h:67
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:94
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition Mesh.h:91
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:88
MeshLib::MeshSubset const & getMeshSubset(int const variable_id, int const component_id) const
GlobalIndexType getLocalIndex(MeshLib::Location const &l, std::size_t const comp_id, std::size_t const range_begin, std::size_t const range_end) const
static constexpr NUMLIB_EXPORT GlobalIndexType const nop
Holds all data of a process that are needed for output.
std::vector< std::reference_wrapper< ProcessVariable > > const & getProcessVariables(int const process_id) const
Handles configuration of several secondary variables from the project file.
SecondaryVariable const & get(std::string const &external_name) const
Returns the secondary variable with the given external name.
const std::string OGS_VERSION
Definition GitInfo.cpp:11
GITINFOLIB_EXPORT const std::string ogs_version
PropertyVector< T > * getOrCreateMeshProperty(Mesh &mesh, std::string const &property_name, MeshItemType const item_type, int const number_of_components)
constexpr std::string_view getBulkIDString(MeshItemType mesh_item_type)
void addProcessDataToMesh(NumLib::Time const &t, std::vector< GlobalVector * > const &xs, int const process_id, ProcessOutputData const &process_output_data, bool const output_secondary_variables, OutputDataSpecification const &process_output)
Holds information about which variables to write to output files.
bool output_residuals
Tells if also to output extrapolation residuals.
std::set< std::string > output_variables
All variables that shall be output.
Function const eval_field
Computes the value of the field at every node of the underlying mesh.
const unsigned num_components
Number of components of the variable.
Stores information about a specific secondary variable.
SecondaryVariableFunctions fcts
Functions used for computing the secondary variable.
std::string const name
Name of the variable; used, e.g., for output.