OGS
ProcessOutput.cpp
Go to the documentation of this file.
1 
11 #include "ProcessOutput.h"
12 
13 #ifndef _WIN32
14 #ifndef __APPLE__
15 #include <cfenv>
16 #endif // __APPLE__
17 #endif // _WIN32
18 
19 #include "InfoLib/GitInfo.h"
20 #include "IntegrationPointWriter.h"
21 #ifdef USE_PETSC
23 #endif
26 
29 static void addOgsVersion(MeshLib::Mesh& mesh)
30 {
31  auto& ogs_version_field = *MeshLib::getOrCreateMeshProperty<char>(
34 
35  ogs_version_field.assign(GitInfoLib::GitInfo::ogs_version.begin(),
37 }
38 
40  double const t,
41  std::vector<GlobalVector*> const& x,
42  std::vector<NumLib::LocalToGlobalIndexMap const*> const& dof_table,
44  std::string const& output_name,
45  MeshLib::Mesh& mesh)
46 {
47  DBUG(" secondary variable {:s}", output_name);
48 
49  auto& nodal_values_mesh = *MeshLib::getOrCreateMeshProperty<double>(
50  mesh, output_name, MeshLib::MeshItemType::Node,
51  var.fcts.num_components);
52  if (nodal_values_mesh.size() !=
54  {
55  OGS_FATAL(
56  "Nodal property `{:s}' does not have the right number of "
57  "components. Expected: {:d}, actual: {:d}",
58  output_name,
60  nodal_values_mesh.size());
61  }
62 
63  std::unique_ptr<GlobalVector> result_cache;
64  auto const& nodal_values =
65  var.fcts.eval_field(t, x, dof_table, result_cache);
66 #ifdef USE_PETSC
67  std::size_t const global_vector_size =
68  nodal_values.getLocalSize() + nodal_values.getGhostSize();
69 #else
70  std::size_t const global_vector_size = nodal_values.size();
71 #endif
72  if (nodal_values_mesh.size() != global_vector_size)
73  {
74  OGS_FATAL(
75  "Secondary variable `{:s}' did not evaluate to the right number of "
76  "components. Expected: {:d}, actual: {:d}.",
77  var.name, nodal_values_mesh.size(), global_vector_size);
78  }
79 
80  // Copy result
81  nodal_values.copyValues(nodal_values_mesh);
82 }
83 
85  double const t,
86  std::vector<GlobalVector*> const& x,
87  std::vector<NumLib::LocalToGlobalIndexMap const*> const& dof_table,
89  std::string const& output_name,
90  MeshLib::Mesh& mesh)
91 {
92  if (!var.fcts.eval_residuals)
93  {
94  return;
95  }
96 
97  DBUG(" secondary variable {:s} residual", output_name);
98  auto const& property_name_res = output_name + "_residual";
99 
100  auto& residuals_mesh = *MeshLib::getOrCreateMeshProperty<double>(
101  mesh, property_name_res, MeshLib::MeshItemType::Cell,
102  var.fcts.num_components);
103  if (residuals_mesh.size() !=
105  {
106  OGS_FATAL(
107  "Cell property `{:s}' does not have the right number of "
108  "components. Expected: {:d}, actual: {:d}",
109  property_name_res,
111  residuals_mesh.size());
112  }
113 
114  std::unique_ptr<GlobalVector> result_cache;
115  auto const& residuals =
116  var.fcts.eval_residuals(t, x, dof_table, result_cache);
117 #ifdef USE_PETSC
118  std::size_t const global_vector_size =
119  residuals.getLocalSize() + residuals.getGhostSize();
120 #else
121  std::size_t const global_vector_size = residuals.size();
122 #endif
123  if (residuals_mesh.size() != global_vector_size)
124  {
125  OGS_FATAL(
126  "The residual of secondary variable `{:s}' did not evaluate to the "
127  "right number of components. Expected: {:d}, actual: {:d}.",
128  var.name, residuals_mesh.size(), global_vector_size);
129  }
130 
131  // Copy result
132  residuals.copyValues(residuals_mesh);
133 }
134 
135 namespace ProcessLib
136 {
138  const double t, std::vector<GlobalVector*> const& x, int const process_id,
139  MeshLib::Mesh& mesh,
140  [[maybe_unused]] std::vector<NumLib::LocalToGlobalIndexMap const*> const&
141  bulk_dof_tables,
142  std::vector<NumLib::LocalToGlobalIndexMap const*> const& dof_table,
143  std::vector<std::reference_wrapper<ProcessVariable>> const&
144  process_variables,
145  SecondaryVariableCollection const& secondary_variables,
146  bool const output_secondary_variable,
147  std::vector<std::unique_ptr<IntegrationPointWriter>> const* const
148  integration_point_writer,
149  OutputDataSpecification const& process_output)
150 {
151  DBUG("Process output data.");
152 
153  addOgsVersion(mesh);
154 
155  // Copy result
156 #ifdef USE_PETSC
157  // TODO It is also possible directly to copy the data for single process
158  // variable to a mesh property. It needs a vector of global indices and
159  // some PETSc magic to do so.
160  std::vector<double> x_copy(x[process_id]->getLocalSize() +
161  x[process_id]->getGhostSize());
162 #else
163  std::vector<double> x_copy(x[process_id]->size());
164 #endif
165  x[process_id]->copyValues(x_copy);
166 
167  auto const& output_variables = process_output.output_variables;
168  std::set<std::string> already_output;
169 
170  int global_component_offset = 0;
171  int global_component_offset_next = 0;
172 
173  const auto number_of_dof_variables =
174  dof_table[process_id]->getNumberOfVariables();
175  // primary variables
176  for (int variable_id = 0;
177  variable_id < static_cast<int>(process_variables.size());
178  ++variable_id)
179  {
180  ProcessVariable& pv = process_variables[variable_id];
181  int const n_components = pv.getNumberOfGlobalComponents();
182  // If (number_of_dof_variables==1), the case is either the staggered
183  // scheme being applied or a single PDE being solved.
184  const int sub_meshset_id =
185  (number_of_dof_variables == 1) ? 0 : variable_id;
186 
187  if (number_of_dof_variables > 1)
188  {
189  global_component_offset = global_component_offset_next;
190  global_component_offset_next += n_components;
191  }
192 
193  if (output_variables.find(pv.getName()) == output_variables.cend())
194  {
195  continue;
196  }
197 
198  already_output.insert(pv.getName());
199 
200  DBUG(" process variable {:s}", pv.getName());
201 
202  auto const num_comp = pv.getNumberOfGlobalComponents();
203  auto& output_data = *MeshLib::getOrCreateMeshProperty<double>(
204  mesh, pv.getName(), MeshLib::MeshItemType::Node, num_comp);
205 
206  for (int component_id = 0; component_id < num_comp; ++component_id)
207  {
208  auto const& mesh_subset = dof_table[process_id]->getMeshSubset(
209  sub_meshset_id, component_id);
210  auto const mesh_id = mesh_subset.getMeshID();
211  for (auto const* node : mesh_subset.getNodes())
212  {
213 #ifdef USE_PETSC
214  if (bulk_dof_tables[process_id] != dof_table[process_id])
215  {
216  if (!mesh.getProperties().existsPropertyVector<std::size_t>(
217  "bulk_node_ids"))
218  {
219  OGS_FATAL(
220  "The required bulk node ids map does not exist in "
221  "the boundary mesh '{:s}' or has the wrong data "
222  "type (should be equivalent to C++ data type "
223  "std::size_t which is an unsigned integer of size "
224  "{:d} or UInt64 in vtk terminology).",
225  mesh.getName(), sizeof(std::size_t));
226  }
227  auto const bulk_node_id_map =
228  *mesh.getProperties().getPropertyVector<std::size_t>(
229  "bulk_node_ids");
230 
231  if (static_cast<MeshLib::NodePartitionedMesh const&>(mesh)
232  .isGhostNode(node->getID()))
233  {
234  auto const bulk_node_id =
235  bulk_node_id_map[node->getID()];
236  // use bulk_dof_tables to find information
237  std::size_t const bulk_mesh_id = 0;
238  MeshLib::Location const l(bulk_mesh_id,
240  bulk_node_id);
241  auto const global_component_id =
242  global_component_offset + component_id;
243  auto const index =
244  bulk_dof_tables[process_id]->getLocalIndex(
245  l, global_component_id,
246  x[process_id]->getRangeBegin(),
247  x[process_id]->getRangeEnd());
248 
249  output_data[node->getID() * n_components +
250  component_id] = x_copy[index];
251  continue;
252  }
253  }
254 #endif
256  node->getID());
257 
258  auto const global_component_id =
259  global_component_offset + component_id;
260  auto const index = dof_table[process_id]->getLocalIndex(
261  l, global_component_id, x[process_id]->getRangeBegin(),
262  x[process_id]->getRangeEnd());
263 
264  output_data[node->getID() * n_components + component_id] =
265  x_copy[index];
266  }
267  }
268  }
269 
270  if (output_secondary_variable)
271  {
272  for (auto const& external_variable_name : secondary_variables)
273  {
274  auto const& name = external_variable_name.first;
275  if (!already_output.insert(name).second)
276  {
277  // no insertion took place, output already done
278  continue;
279  }
280 
282  t, x, dof_table, secondary_variables.get(name), name, mesh);
283 
284  if (process_output.output_residuals)
285  {
287  t, x, dof_table, secondary_variables.get(name), name, mesh);
288  }
289  }
290  }
291 
292  if (integration_point_writer != nullptr)
293  {
294  addIntegrationPointWriter(mesh, *integration_point_writer);
295  }
296 }
297 
298 void makeOutput(std::string const& file_name, MeshLib::Mesh const& mesh,
299  bool const compress_output, int const data_mode)
300 {
301  // Write output file
302  DBUG("Writing output to '{:s}'.", file_name);
303 
304  // Store floating-point exception handling. Output of NaN's triggers
305  // floating point exceptions. Because we are not debugging VTK (or other
306  // libraries) at this point, the possibly set exceptions are temporary
307  // disabled and restored before end of the function.
308 #ifndef _WIN32
309 #ifndef __APPLE__
310  fenv_t fe_env;
311  fegetenv(&fe_env);
312  fesetenv(FE_DFL_ENV); // Set default environment effectively disabling
313  // exceptions.
314 #endif //_WIN32
315 #endif //__APPLE__
316 
317  MeshLib::IO::VtuInterface vtu_interface(&mesh, data_mode, compress_output);
318  vtu_interface.writeToFile(file_name);
319 
320  // Restore floating-point exception handling.
321 #ifndef _WIN32
322 #ifndef __APPLE__
323  fesetenv(&fe_env);
324 #endif //_WIN32
325 #endif //__APPLE__
326 }
327 } // namespace ProcessLib
#define OGS_FATAL(...)
Definition: Error.h:26
Git information.
void DBUG(char const *fmt, Args const &... args)
Definition: Logging.h:27
Definition of mesh class for partitioned mesh (by node) for parallel computing within the framework o...
static void addSecondaryVariableNodes(double 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 void addSecondaryVariableResiduals(double 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 void addOgsVersion(MeshLib::Mesh &mesh)
Implementation of the VtuInterface class.
Reads and writes VtkXMLUnstructuredGrid-files (vtu) to and from OGS data structures....
Definition: VtuInterface.h:38
bool writeToFile(std::filesystem::path const &file_path)
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::size_t getNumberOfElements() const
Get the number of elements.
Definition: Mesh.h:86
bool isGhostNode(const std::size_t node_id) const
Check whether a node with ID of node_id is a ghost node.
PropertyVector< T > const * getPropertyVector(std::string const &name) const
bool existsPropertyVector(std::string const &name) const
std::string const & getName() const
int getNumberOfGlobalComponents() const
Returns the number of components of the process variable.
Handles configuration of several secondary variables from the project file.
const std::string OGS_VERSION
Definition: GitInfo.cpp:20
GITINFOLIB_EXPORT const std::string ogs_version
void addProcessDataToMesh(const double t, std::vector< GlobalVector * > const &x, int const process_id, MeshLib::Mesh &mesh, [[maybe_unused]] std::vector< NumLib::LocalToGlobalIndexMap const * > const &bulk_dof_tables, std::vector< NumLib::LocalToGlobalIndexMap const * > const &dof_table, std::vector< std::reference_wrapper< ProcessVariable >> const &process_variables, SecondaryVariableCollection const &secondary_variables, bool const output_secondary_variable, std::vector< std::unique_ptr< IntegrationPointWriter >> const *const integration_point_writer, OutputDataSpecification const &process_output)
void addIntegrationPointWriter(MeshLib::Mesh &mesh, std::vector< std::unique_ptr< IntegrationPointWriter >> const &integration_point_writer)
void makeOutput(std::string const &file_name, MeshLib::Mesh const &mesh, bool const compress_output, int const data_mode)
Holds information about which variables to write to output files.
Definition: ProcessOutput.h:23
bool const output_residuals
Tells if also to output extrapolation residuals.
Definition: ProcessOutput.h:28
std::set< std::string > output_variables
All variables that shall be output.
Definition: ProcessOutput.h:25
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.