HyperHDG
plot.hxx
Go to the documentation of this file.
1 #pragma once // Ensure that file is included only once in a single compilation.
2 
4 #include <HyperHDG/dense_la.hxx>
6 #include <HyperHDG/hypercube.hxx>
7 
8 #include <filesystem>
9 #include <fstream>
10 #include <iomanip>
11 #include <iostream>
12 #include <tuple>
13 
14 /*!*************************************************************************************************
15  * \brief A class storing options for plotting.
16  *
17  * \authors Guido Kanschat, Heidelberg University, 2020.
18  * \authors Andreas Rupp, Heidelberg University, 2020.
19  **************************************************************************************************/
21 {
22  /*!***********************************************************************************************
23  * \brief Name of the directory to put the output into.
24  *
25  * This \c std::string describes the directory the output is created in. Default is "output".
26  ************************************************************************************************/
27  std::string outputDir = "output";
28  /*!***********************************************************************************************
29  * \brief Name of the file plotted.
30  *
31  * This \c std::string describes the name of the file for the output plot. Default is "example".
32  ************************************************************************************************/
33  std::string fileName = "example";
34  /*!***********************************************************************************************
35  * \brief Enum for possible file endings.
36  ************************************************************************************************/
37  enum fileType
38  {
40  };
41  /*!***********************************************************************************************
42  * \brief File ending and also way of plotting.
43  *
44  * This \c std::string describes the name of the file ending for the output plot. Thus, it also
45  * characterizes which applications can read the output files properly. Default and currently
46  * only option is "vtu" for Paraview.
47  ************************************************************************************************/
49  /*!***********************************************************************************************
50  * \brief Number of the plot file.
51  *
52  * This \c unsigned \c int describes the number of the plot file which is created. If a problem is
53  * solved repeatedly (e.g. parabolic problem, local refinement, ...) this number indicates the
54  * number of the file (e.g. time step, refinement step, ...). Default is 0.
55  ************************************************************************************************/
56  unsigned int fileNumber = 0;
57  /*!***********************************************************************************************
58  * \brief Decide whether \c fileNumber is part of the file name.
59  *
60  * This \c boolean discriminates whether the \c fileNumber should appear within the name of the
61  * file (true) or not (false). Default is true.
62  ************************************************************************************************/
63  bool printFileNumber = true;
64  /*!***********************************************************************************************
65  * \brief Decide whether \c fileNumber is incremented after plotting.
66  *
67  * This \c boolean discriminates whether the \c fileNumber should be incremented after a file has
68  * been written (true) or not (false). Default is true.
69  ************************************************************************************************/
70  bool incrementFileNumber = true;
71  /*!***********************************************************************************************
72  * \brief Include the edge boundaries with their function values into the plot.
73  *
74  * Defaults to false.
75  ************************************************************************************************/
76  bool plot_edge_boundaries = false;
77  /*!***********************************************************************************************
78  * \brief Include the hyperedges with their function values into the plot.
79  *
80  * Defaults to true.
81  ************************************************************************************************/
82  bool plot_edges = true;
83  /*!***********************************************************************************************
84  * \brief Number of subintervals for plotting.
85  *
86  * When plotting an interval, it is split into #n_subintervals intervals such that higher order
87  * polynomials and other functions can be displayed appropriately. When plotting higher
88  * dimensional objects, this subdivision is applied accordingly in each direction.
89  *
90  * This functionality is implemented such that higher order polynomials can be output as piecewise
91  * linear functions giving them sufficient meaning. It will increase the number of cells seen by
92  * the visualization tool, such that the cell boundaries there are not the actual cell boundaries
93  * anymore. You can still use the parameter #scale below to see the separate edges.
94  *
95  * Defaults to 1.
96  ************************************************************************************************/
97  unsigned int n_subintervals = 1;
98  /*!***********************************************************************************************
99  * \brief A factor for scaling each object of the plot locally.
100  *
101  * This factor defaults to 1 in order to produce a plot of a contiguous domain. If it is chosen
102  * less than 1, each edge or node is scaled by this factor around its center.
103  ************************************************************************************************/
104  float scale = 1.;
105  /*!***********************************************************************************************
106  * \brief A factor by which to separate two boundaries belonging to different edges.
107  *
108  * This factor defaults to 1 which results in boundaries of adjacent edges being drawn on top of
109  * each other, if scale is less than one a suitable choice would be (1+scale)/2 in order separate
110  * different boundaries. A smaller factor results in a wider gap.
111  ************************************************************************************************/
112  float boundary_scale = 1.;
113  /*!***********************************************************************************************
114  * \brief Output a cell data array with the number of each edge and/or each node.
115  ************************************************************************************************/
116  bool numbers = false;
117 }; // end of class PlotOptions
118 
119 /*!*************************************************************************************************
120  * \brief Set a plot option and return the new value of this option as std::string.
121  **************************************************************************************************/
122 std::string set_plot_option(PlotOptions& plot_options,
123  const std::string& option,
124  std::string value = "")
125 {
126  if (value == "")
127  ;
128  else if (option == "outputDir")
129  plot_options.outputDir = value;
130  else if (option == "fileName")
131  plot_options.fileName = value;
132  else if (option == "fileEnding")
133  {
134  if (value == "vtu")
135  plot_options.fileEnding = PlotOptions::vtu;
136  else
137  hy_assert(false, "You have chosen an invalid file type!");
138  }
139  else if (option == "fileNumber")
140  plot_options.fileNumber = stoi(value);
141  else if (option == "printFileNumber")
142  plot_options.printFileNumber = (value == "true" || value == "1");
143  else if (option == "incrementFileNumber")
144  plot_options.incrementFileNumber = (value == "true" || value == "1");
145  else if (option == "plotEdges")
146  plot_options.plot_edges = (value == "true" || value == "1");
147  else if (option == "plotEdgeBoundaries")
148  plot_options.plot_edge_boundaries = (value == "true" || value == "1");
149  else if (option == "boundaryScale")
150  plot_options.boundary_scale = std::stof(value);
151  else if (option == "scale")
152  plot_options.scale = stof(value);
153  else
154  hy_assert(false, "This plot option has not been defined (yet).");
155 
156  std::string return_value;
157  if (option == "outputDir")
158  return_value = plot_options.outputDir;
159  else if (option == "fileName")
160  return_value = plot_options.fileName;
161  else if (option == "fileEnding")
162  return_value = plot_options.fileEnding;
163  else if (option == "fileNumber")
164  return_value = std::to_string(plot_options.fileNumber);
165  else if (option == "printFileNumber")
166  return_value = std::to_string(plot_options.printFileNumber);
167  else if (option == "incrementFileNumber")
168  return_value = std::to_string(plot_options.incrementFileNumber);
169  else if (option == "plotEdges")
170  return_value = std::to_string(plot_options.plot_edges);
171  else if (option == "plotEdgeBoundaries")
172  return_value = std::to_string(plot_options.plot_edge_boundaries);
173  else if (option == "scale")
174  return_value = std::to_string(plot_options.scale);
175  else if (option == "boundaryScale")
176  return_value = std::to_string(plot_options.boundary_scale);
177  else
178  hy_assert(false, "This plot option has not been defined (yet).");
179 
180  return return_value;
181 }
182 /*!*************************************************************************************************
183  * \brief Function plotting the solution of an equation on a hypergraph in vtu format.
184  *
185  * Creates a file according to set plotting options in \c plot_options. This file contains the
186  * solution of the PDE defined in \c plotOpt having the representation \c lambda in terms of its
187  * skeleta degrees of freedom (related to skeletal variable lambda).
188  *
189  * \tparam HyperGraphT Template parameter describing the precise class of the \c HDGHyperGraph,
190  * i.e., it contains an \c HDGHyperGraph with chosen template parameters
191  * describing its topology, geometry, etc.
192  * \tparam LocalSolverT Template parameter describing the precise class of the local solver,
193  * i.e., it contains an local solver for a specific equation living on the
194  * hypergraph.
195  * \tparam LargeVecT The typename of the large vector.
196  * \tparam floatT The floating point type in wihch time is given of dof values.
197  * \param hyper_graph The hypergraph.
198  * \param local_solver The local solver.
199  * \param lambda Large vector containing the skeletal degrees of freedom encoding the
200  * representation of the unique solution.
201  * \param plot_options PlotOptions object containing plotting options.
202  * \param time The time stamp.
203  *
204  * \authors Guido Kanschat, Heidelberg University, 2020.
205  * \authors Andreas Rupp, Heidelberg University, 2020.
206  **************************************************************************************************/
207 template <typename HyperGraphT, typename LocalSolverT, typename LargeVecT, typename floatT = float>
208 void plot(HyperGraphT& hyper_graph,
209  const LocalSolverT& local_solver,
210  const LargeVecT& lambda,
211  PlotOptions& plot_options,
212  const floatT time = 0.);
213 
214 // -------------------------------------------------------------------------------------------------
215 // -------------------------------------------------------------------------------------------------
216 //
217 // IMPLEMENTATION OF AUXILIARY FUNCTIONS FOR plot()
218 //
219 // -------------------------------------------------------------------------------------------------
220 // -------------------------------------------------------------------------------------------------
221 
222 /*!*************************************************************************************************
223  * \brief Auxiliary functions for writing graphics files.
224  **************************************************************************************************/
225 namespace PlotFunctions
226 {
227 /*!*************************************************************************************************
228  * \brief Prepare struct to check for function to exist (cf. compile_time_tricks.hxx).
229  **************************************************************************************************/
230 HAS_MEMBER_FUNCTION(bulk_values, has_bulk_values);
231 /*!*************************************************************************************************
232  * \brief Turn fileType enum into string.
233  **************************************************************************************************/
235 {
236  switch (type)
237  {
238  case PlotOptions::fileType::vtu:
239  return "vtu";
240  }
241  hy_assert(false, "File type seems to be invalid.");
242  return "";
243 }
244 /*!*************************************************************************************************
245  * \brief Open stream to file.
246  **************************************************************************************************/
247 std::ofstream open_ofstream(const PlotOptions& plot_options, const bool append = false)
248 {
249  std::ofstream myfile;
250 
251  std::string filename = plot_options.outputDir + "/" + plot_options.fileName;
252  if (plot_options.printFileNumber)
253  filename += "." + std::to_string(plot_options.fileNumber);
254  filename += "." + fileType_to_string(plot_options.fileEnding);
255  if (std::filesystem::create_directory(plot_options.outputDir))
256  std::cout << "Directory \"" << plot_options.outputDir << "\" has been created." << std::endl;
257 
258  if (append)
259  myfile.open(filename, std::ios_base::app);
260  else
261  myfile.open(filename, std::ios_base::out);
262  hy_assert(myfile.is_open(),
263  "The file has not been created. Most likely, the filesystem could not"
264  << " create the output directory, since std::filesystem has not been available."
265  << std::endl
266  << "Please, try to create the output directoy manually and run the code again.");
267 
268  return myfile;
269 }
270 /*!*************************************************************************************************
271  * \brief Close stream to file.
272  **************************************************************************************************/
273 void close_ofstream(std::ofstream& myfile)
274 {
275  myfile.close();
276 }
277 
278 /*!*************************************************************************************************
279  * \brief Output of the cubes of the subdivision of an edge in lexicographic order.
280  *
281  * \tparam dim The dimension of the cube.
282  * \tparam pt_index_t The index type for global point numbers.
283  * \param output The output.
284  * \param n The number of subdivision points in each direction.
285  * \param offset The index of the first vertex
286  **************************************************************************************************/
287 template <unsigned int dim, typename pt_index_t>
288 void vtu_sub_cube_connectivity(std::ostream& output, unsigned int n, pt_index_t offset)
289 {
290  if constexpr (dim == 0)
291  for (unsigned int i = 0; i < n - 1; ++i)
292  output << offset + i << "\n";
293  else if constexpr (dim == 1)
294  for (unsigned int i = 0; i < n - 1; ++i)
295  output << offset + i << ' ' << offset + i + 1 << "\n";
296  else if constexpr (dim == 2)
297  for (unsigned int i = 0; i < n - 1; ++i)
298  for (unsigned int j = 0; j < n - 1; ++j)
299  output << offset + i * n + j << ' ' << offset + i * n + j + 1 << ' '
300  << offset + i * n + j + n << ' ' << offset + i * n + j + n + 1 << "\n";
301  else if constexpr (dim == 3)
302  {
303  const unsigned int nn = n * n;
304  for (unsigned int i = 0; i < n - 1; ++i)
305  for (unsigned int j = 0; j < n - 1; ++j)
306  for (unsigned int k = 0; k < n - 1; ++k)
307  output << offset + (i * n + j) * n + k << ' ' << offset + (i * n + j) * n + k + 1 << ' '
308  << offset + (i * n + j) * n + k + n << ' ' << offset + (i * n + j) * n + k + n + 1
309  << ' ' << offset + (i * n + j) * n + k + nn << ' '
310  << offset + (i * n + j) * n + k + nn + 1 << ' '
311  << offset + (i * n + j) * n + k + nn + n << ' '
312  << offset + (i * n + j) * n + k + nn + n + 1 << "\n";
313  }
314 } // end of vtu_sub_cube_connectivity
315 /*!*************************************************************************************************
316  * \brief Auxiliary function for writing geometry section VTU files.
317  *
318  * This function plots the geometry part of an unstructured mesh in* a VTU file.
319  * The typical file structure is
320  *
321  * < Preamble/>
322  * < UnstructuredGrid>
323  * < Geometry/>
324  * < Data/>
325  * < /UnstructuredGrid>
326  *
327  * This function writes the < Geometry> part of the structure.
328  **************************************************************************************************/
329 template <class HyperGraphT,
330  unsigned int n_subpoints,
331  typename hyEdge_index_t = unsigned int,
332  typename pt_index_t = unsigned int>
333 void plot_vtu_unstructured_geometry(std::ostream& output,
334  HyperGraphT& hyper_graph,
335  const SmallVec<n_subpoints, float>& sub_points,
336  const SmallVec<n_subpoints, float>& boundary_sub_points,
337  const PlotOptions& plot_options)
338 {
339  constexpr unsigned int edge_dim = HyperGraphT::hyEdge_dim();
340  constexpr unsigned int space_dim = HyperGraphT::space_dim();
341 
342  const hyEdge_index_t n_edges = hyper_graph.n_hyEdges();
343  // The number of cells which are actually plotted. This
344  // is the number of edges in the graph times the number of
345  // cells in an edge due to n_subdivisions
346  const pt_index_t n_plot_edges = n_edges * Hypercube<edge_dim>::pow(n_subpoints - 1);
347  const unsigned int points_per_edge = Hypercube<edge_dim>::pow(n_subpoints);
348 
349  const hyEdge_index_t n_boundaries_per_edge = 2 * edge_dim;
350  const hyEdge_index_t n_edge_boundaries = n_edges * n_boundaries_per_edge;
351  const unsigned int points_per_boundary = Hypercube<edge_dim - 1>::pow(n_subpoints);
352  const pt_index_t n_plot_boundaries =
353  n_edge_boundaries * Hypercube<edge_dim - 1>::pow(n_subpoints - 1);
354 
355  // The total number of points and cells (using VTK nomenclature)
356  // is the sum of the points for edges and the points for
357  // edge boundaries. Equally, the total number of cells is the sum of the
358  // cells of dimension edge_dim plus those of dimension node_dim.
359  const pt_index_t n_plot_points =
360  (plot_options.plot_edges ? (points_per_edge * n_edges) : 0) +
361  (plot_options.plot_edge_boundaries ? (points_per_boundary * n_edge_boundaries) : 0);
362  const pt_index_t n_plot_cells = (plot_options.plot_edges ? n_plot_edges : 0) +
363  (plot_options.plot_edge_boundaries ? n_plot_boundaries : 0);
364 
365  // The element id can be found in the VTK file format documentation.
366  static_assert(edge_dim <= 3);
367  unsigned int element_id;
368  if constexpr (edge_dim == 1)
369  element_id = 3;
370  else if constexpr (edge_dim == 2)
371  element_id = 8;
372  else if constexpr (edge_dim == 3)
373  element_id = 11;
374  unsigned int boundary_element_id = 0;
375  if constexpr (edge_dim == 1)
376  boundary_element_id = 1;
377  else if constexpr (edge_dim == 2)
378  boundary_element_id = 3;
379  else if constexpr (edge_dim == 3)
380  boundary_element_id = 8;
381 
382  output << " <Piece NumberOfPoints=\"" << n_plot_points << "\" NumberOfCells= \""
383  << n_plot_cells << "\">" << std::endl;
384  output << " <Points>" << std::endl;
385  output << " <DataArray type=\"Float32\" NumberOfComponents=\"3\" format=\"ascii\">"
386  << std::endl;
387  if (plot_options.plot_edges)
388  {
389  // For each edge, output the corners of the subdivided cells in lexicographic order.
390  for (hyEdge_index_t he_number = 0; he_number < n_edges; ++he_number)
391  {
392  auto edge = hyper_graph.hyEdge_geometry(he_number);
393 
394  for (unsigned int pt_number = 0; pt_number < points_per_edge; ++pt_number)
395  {
396  output << " ";
397  const Point<space_dim> point =
398  (Point<space_dim>)edge.template lexicographic<n_subpoints>(pt_number, sub_points);
399  for (unsigned int dim = 0; dim < space_dim; ++dim)
400  output << " " << std::fixed << std::scientific << std::setprecision(3) << point[dim];
401  for (unsigned int dim = space_dim; dim < 3; ++dim)
402  output << " 0.0";
403  output << std::endl;
404  }
405  }
406  }
407  if (plot_options.plot_edge_boundaries)
408  {
409  // For each edge accumulate edge boundary coordinates
410  for (hyEdge_index_t he_number = 0; he_number < n_edges; ++he_number)
411  {
412  auto edge = hyper_graph.hyEdge_geometry(he_number);
413  for (hyEdge_index_t boundary = 0; boundary < n_boundaries_per_edge; ++boundary)
414  {
415  for (unsigned int pt_number = 0; pt_number < points_per_boundary; ++pt_number)
416  {
417  output << " ";
418  const Point<space_dim> point =
419  (Point<space_dim>)edge.template boundary_lexicographic<n_subpoints>(
420  pt_number, boundary, plot_options.boundary_scale, boundary_sub_points);
421 
422  if (he_number == 0)
423  for (unsigned int dim = 0; dim < space_dim; ++dim)
424  {
425  output << " " << std::fixed << std::scientific << std::setprecision(3) << point[dim];
426  }
427  else
428  for (unsigned int dim = 0; dim < space_dim; ++dim)
429  {
430  output << " " << std::fixed << std::scientific << std::setprecision(3) << point[dim];
431  }
432  for (unsigned int dim = space_dim; dim < 3; ++dim)
433  output << " 0.0";
434  output << std::endl;
435  }
436  }
437  }
438  }
439 
440  output << " </DataArray>" << std::endl;
441  output << " </Points>" << std::endl;
442  output << " <Cells>" << std::endl;
443  output << " <DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">"
444  << std::endl;
445 
446  pt_index_t offset = 0;
447  if (plot_options.plot_edges)
448  for (hyEdge_index_t he_number = 0; he_number < n_edges; ++he_number)
449  {
450  vtu_sub_cube_connectivity<edge_dim>(output, n_subpoints, offset);
451  offset += points_per_edge;
452  }
453  if (plot_options.plot_edge_boundaries)
454  for (pt_index_t i = 0; i < n_edge_boundaries; ++i)
455  {
456  vtu_sub_cube_connectivity<edge_dim - 1>(output, n_subpoints, offset);
457  offset += points_per_boundary;
458  }
459 
460  hy_assert(offset == n_plot_points, "We did not write the right number of connectivity data");
461 
462  output << " </DataArray>" << std::endl;
463  output << " <DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">" << std::endl;
464  output << " ";
465  int start_number = 0;
466  if (plot_options.plot_edges)
467  {
468  for (hyEdge_index_t he_number = 1; he_number <= n_plot_edges; ++he_number)
469  {
470  output << " " << Hypercube<edge_dim>::n_vertices() * he_number;
471  start_number = Hypercube<edge_dim>::n_vertices() * he_number;
472  }
473  }
474  if (plot_options.plot_edge_boundaries)
475  {
476  for (hyEdge_index_t bdr_number = 1; bdr_number <= n_plot_boundaries; ++bdr_number)
477  output << " " << Hypercube<edge_dim - 1>::n_vertices() * bdr_number + start_number;
478  }
479  output << std::endl;
480 
481  output << " </DataArray>" << std::endl;
482  output << " <DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">" << std::endl;
483  output << " ";
484  if (plot_options.plot_edges)
485  {
486  for (hyEdge_index_t he_number = 0; he_number < n_plot_edges; ++he_number)
487  output << " " << element_id;
488  }
489  if (plot_options.plot_edge_boundaries)
490  {
491  for (hyEdge_index_t bdr_number = 1; bdr_number <= n_plot_boundaries; ++bdr_number)
492  output << " " << boundary_element_id;
493  }
494  output << std::endl;
495 
496  output << " </DataArray>" << std::endl;
497  output << " </Cells>" << std::endl;
498 } // end of void plot_vtu_unstructured_geometry
499 } // end of namespace PlotFunctions
500 
501 /*!*************************************************************************************************
502  * \brief Auxiliary function to get dof values of edge.
503  **************************************************************************************************/
504 template <unsigned int edge_dim, class HyperGraphT, typename hyEdge_index_t, typename LargeVecT>
505 std::array<std::array<typename LargeVecT::value_type, HyperGraphT::n_dofs_per_node()>, 2 * edge_dim>
506 get_edge_dof_values(HyperGraphT& hyper_graph, hyEdge_index_t edge_index, const LargeVecT& lambda)
507 {
508  std::array<std::array<typename LargeVecT::value_type, HyperGraphT::n_dofs_per_node()>,
509  2 * edge_dim>
510  hyEdge_dofs;
512  hyEdge_hyNodes = hyper_graph.hyEdge_topology(edge_index).get_hyNode_indices();
513  for (unsigned int hyNode = 0; hyNode < hyEdge_hyNodes.size(); ++hyNode)
514  {
515  hyEdge_dofs[hyNode] = hyper_graph.hyNode_factory().get_dof_values(hyEdge_hyNodes[hyNode],
516  lambda, hyEdge_dofs[hyNode]);
517  }
518  return hyEdge_dofs;
519 }
520 
521 /*!*************************************************************************************************
522  * \brief Auxiliary function to plot solution values on edge.
523  **************************************************************************************************/
524 template <class HyperGraphT,
525  class LocalSolverT,
526  typename LargeVecT,
527  typename floatT,
528  unsigned int n_subdivisions = 1,
529  typename hyEdge_index_t = unsigned int>
530 void plot_edge_values(HyperGraphT& hyper_graph,
531  const LocalSolverT& local_solver,
532  const LargeVecT& lambda,
533  std::ofstream& myfile,
535  const floatT time)
536 {
537  using dof_value_t = typename LargeVecT::value_type;
538  constexpr unsigned int edge_dim = HyperGraphT::hyEdge_dim();
539 
540  const hyEdge_index_t n_edges = hyper_graph.n_hyEdges();
541  std::array<std::array<dof_value_t, HyperGraphT::n_dofs_per_node()>, 2 * edge_dim> hyEdge_dofs;
542 
543  for (hyEdge_index_t he_number = 0; he_number < n_edges; ++he_number)
544  {
545  hyEdge_dofs = get_edge_dof_values<edge_dim, HyperGraphT, hyEdge_index_t, LargeVecT>(
546  hyper_graph, he_number, lambda);
547  std::array<
548  std::array<dof_value_t, Hypercube<HyperGraphT::hyEdge_dim()>::pow(n_subdivisions + 1)>,
549  LocalSolverT::system_dimension()>
550  local_values;
551  if constexpr (PlotFunctions::has_bulk_values<LocalSolverT,
552  decltype(local_values)(decltype(abscissas.data())&,
553  decltype(hyEdge_dofs)&,
554  decltype(time))>::value)
555  local_values = local_solver.bulk_values(abscissas.data(), hyEdge_dofs, time);
556  else if constexpr (PlotFunctions::has_bulk_values<
557  LocalSolverT, decltype(local_values)(
558  decltype(abscissas.data())&, decltype(hyEdge_dofs)&,
559  decltype(hyper_graph[he_number])&, decltype(time))>::value)
560  {
561  auto geometry = hyper_graph[he_number];
562  local_values = local_solver.bulk_values(abscissas.data(), hyEdge_dofs, geometry, time);
563  }
564  else
565  hy_assert(false, "Function seems not to be implemented!");
566 
567  myfile << " ";
568  for (unsigned int corner = 0; corner < Hypercube<edge_dim>::n_vertices(); ++corner)
569  {
570  myfile << " ";
571  for (unsigned int d = 0; d < LocalSolverT::system_dimension(); ++d)
572  myfile << " " << local_values[d][corner]; // AR: I switched d and corner!?
573  for (unsigned int d = LocalSolverT::system_dimension();
574  d < LocalSolverT::node_system_dimension(); ++d)
575  myfile << " " << 0; // AR: I switched d and corner!?
576  }
577  myfile << std::endl;
578  }
579 }
580 
581 /*!*************************************************************************************************
582  * \brief Auxiliary function to plot solution values on edge boundary.
583  **************************************************************************************************/
584 template <unsigned int index, typename functions>
585 static constexpr unsigned int first_dof()
586 {
587  static_assert(index <= std::tuple_size<functions>(), "Index is too large!");
588  if constexpr (index == 0)
589  return 0;
590  else
591  return std::tuple_element<index - 1, functions>::n_fun() + first_dof<index - 1>();
592 }
593 /*!*************************************************************************************************
594  * \brief Auxiliary function to plot solution values on edge boundary.
595  **************************************************************************************************/
596 template <unsigned int component,
597  typename LocalSolverT,
598  typename dof_value_t,
599  typename lv_t,
600  typename hd_t,
601  typename pt_t>
602 void fancy_recursion(__attribute__((unused)) lv_t& local_values,
603  __attribute__((unused)) const hd_t& hyEdge_dofs,
604  __attribute__((unused)) const pt_t& point,
605  __attribute__((unused)) const unsigned int k,
606  __attribute__((unused)) const unsigned int bdr_index)
607 {
608  if constexpr (component == LocalSolverT::node_system_dimension())
609  return;
610  else
611  {
612  std::array<
613  dof_value_t,
614  std::tuple_element<component, typename LocalSolverT::node_element::functions>::type::n_fun()>
615  helper_arr;
616  for (unsigned int k = 0; k < helper_arr.size(); ++k)
617  helper_arr[k] =
618  hyEdge_dofs[bdr_index]
619  [first_dof<component, typename LocalSolverT::node_element::functions>() + k];
620 
621  local_values[component][k] =
622  std::tuple_element<component, typename LocalSolverT::node_element::functions>::type::
623  template lin_comb_fct_val<float>(SmallVec<helper_arr.size(), dof_value_t>(helper_arr),
624  point);
625  fancy_recursion<component + 1, LocalSolverT, dof_value_t>(local_values, hyEdge_dofs, point, k,
626  bdr_index);
627  }
628 }
629 /*!*************************************************************************************************
630  * \brief Auxiliary function to plot solution values on edge boundary.
631  **************************************************************************************************/
632 template <class HyperGraphT,
633  class LocalSolverT,
634  typename LargeVecT,
635  unsigned int n_subdivisions = 1,
636  typename hyEdge_index_t = unsigned int>
637 void plot_boundary_values(HyperGraphT& hyper_graph,
638  const LargeVecT& lambda,
639  std::ofstream& myfile,
641 {
642  using dof_value_t = typename LargeVecT::value_type;
643  constexpr unsigned int hyEdge_dim = HyperGraphT::hyEdge_dim();
644 
645  const hyEdge_index_t n_edges = hyper_graph.n_hyEdges();
646  std::array<std::array<dof_value_t, HyperGraphT::n_dofs_per_node()>, 2 * hyEdge_dim> hyEdge_dofs;
647  std::array<
648  std::array<dof_value_t, Hypercube<HyperGraphT::hyEdge_dim() - 1>::pow(n_subdivisions + 1)>,
649  LocalSolverT::node_system_dimension()>
650  local_values;
651  for (unsigned int i = 0; i < local_values.size(); ++i)
652  local_values[i].fill(0.);
653 
654  for (hyEdge_index_t edge_index = 0; edge_index < n_edges; ++edge_index)
655  {
656  hyEdge_dofs = get_edge_dof_values<hyEdge_dim, HyperGraphT, hyEdge_index_t, LargeVecT>(
657  hyper_graph, edge_index, lambda);
658  for (unsigned int bdr_index = 0; bdr_index < hyEdge_dim * 2; ++bdr_index)
659  {
660  myfile << " ";
661 
662  for (unsigned int lval = 0; lval < local_values.size(); ++lval)
663  fancy_recursion<0, LocalSolverT, dof_value_t>(
664  local_values, hyEdge_dofs,
665  Hypercube<hyEdge_dim - 1>::template tensorial_pt<Point<hyEdge_dim - 1> >(lval, abscissas),
666  lval, bdr_index);
667  for (unsigned int corner = 0; corner < Hypercube<hyEdge_dim - 1>::n_vertices(); ++corner)
668  {
669  myfile << " ";
670  for (unsigned int d = 0; d < LocalSolverT::node_system_dimension(); ++d)
671  myfile << " " << local_values[d][corner]; // AR: I switched d and corner!?
672  }
673  for (unsigned int d = LocalSolverT::node_system_dimension();
674  d < LocalSolverT::system_dimension(); ++d)
675  myfile << " " << 0; // AR: I switched d and corner!?
676  myfile << std::endl;
677  }
678  }
679 }
680 
681 /*!*************************************************************************************************
682  * \brief Auxiliary function to plot solution values to vtu file.
683  **************************************************************************************************/
684 template <class HyperGraphT,
685  class LocalSolverT,
686  typename LargeVecT,
687  typename floatT,
688  unsigned int n_subdivisions = 1,
689  typename hyEdge_index_t = unsigned int>
690 void plot_vtu(HyperGraphT& hyper_graph,
691  const LocalSolverT& local_solver,
692  const LargeVecT& lambda,
693  const PlotOptions& plot_options,
694  const floatT time = 0.)
695 {
696  constexpr unsigned int edge_dim = HyperGraphT::hyEdge_dim();
697 
698  const hyEdge_index_t n_edges = hyper_graph.n_hyEdges();
699  const hyEdge_index_t n_edge_boundaries = n_edges * 2 * edge_dim;
700  // const unsigned int n_points_per_edge = 1 << edge_dim;
701 
702  SmallVec<n_subdivisions + 1, float> boundary_abscissas;
703  for (unsigned int i = 0; i <= n_subdivisions; ++i)
704  boundary_abscissas[i] =
705  plot_options.scale * plot_options.boundary_scale * (1. * i / n_subdivisions - 0.5) + 0.5;
707  for (unsigned int i = 0; i <= n_subdivisions; ++i)
708  abscissas[i] = plot_options.scale * (1. * i / n_subdivisions - 0.5) + 0.5;
709 
710  static_assert(edge_dim <= 3, "Plotting hyperedges with dimensions larger than 3 is hard.");
711 
712  std::ofstream myfile = PlotFunctions::open_ofstream(plot_options, false);
713 
714  myfile << "<?xml version=\"1.0\"?>" << std::endl;
715  myfile << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\" "
716  << "compressor=\"vtkZLibDataCompressor\">" << std::endl;
717  myfile << " <UnstructuredGrid>" << std::endl;
718 
719  PlotFunctions::plot_vtu_unstructured_geometry(myfile, hyper_graph, abscissas, boundary_abscissas,
720  plot_options);
721 
722  myfile << " <CellData>" << std::endl;
723  if (plot_options.numbers)
724  {
725  myfile << " <DataArray type=\"Int32\" Name=\"index\" NumberOfComponents=\"1\" "
726  << "format=\"ascii\">\n";
727  if (plot_options.plot_edges)
728  {
729  for (hyEdge_index_t he_number = 0; he_number < n_edges; ++he_number)
730  for (unsigned int i = 0; i < Hypercube<edge_dim>::pow(n_subdivisions); ++i)
731  myfile << ' ' << he_number;
732  }
733  if (plot_options.plot_edge_boundaries)
734  {
735  for (hyEdge_index_t bdr_number = 1; bdr_number <= n_edge_boundaries; ++bdr_number)
736  for (unsigned int i = 0; i < Hypercube<edge_dim>::pow(n_subdivisions); ++i)
737  myfile << " " << bdr_number;
738  }
739 
740  myfile << " </DataArray>";
741  }
742  myfile << " </CellData>" << std::endl;
743 
744  myfile << " <PointData>" << std::endl;
745  if (LocalSolverT::system_dimension() != 0)
746  {
747  myfile << " <DataArray type=\"Float32\" Name=\"values"
748  << "\" NumberOfComponents=\""
749  << std::max(LocalSolverT::system_dimension(), LocalSolverT::node_system_dimension())
750  << "\" format=\"ascii\">" << std::endl;
751  if (plot_options.plot_edges)
752  {
753  plot_edge_values<HyperGraphT, LocalSolverT, LargeVecT, floatT, n_subdivisions,
754  hyEdge_index_t>(hyper_graph, local_solver, lambda, myfile, abscissas, time);
755  }
756  if (plot_options.plot_edge_boundaries)
757  {
758  plot_boundary_values<HyperGraphT, LocalSolverT, LargeVecT, n_subdivisions, hyEdge_index_t>(
759  hyper_graph, lambda, myfile, boundary_abscissas);
760  }
761  myfile << " </DataArray>" << std::endl;
762  }
763  myfile << " </PointData>" << std::endl;
764  myfile << " </Piece>" << std::endl;
765  myfile << " </UnstructuredGrid>" << std::endl;
766  myfile << "</VTKFile>" << std::endl;
767  std::cout << plot_options.fileName;
768  if (plot_options.printFileNumber)
769  std::cout << "." << plot_options.fileNumber << " was written\n";
771 } // end of void plot_vtu
772 
773 // -------------------------------------------------------------------------------------------------
774 // plot()
775 // -------------------------------------------------------------------------------------------------
776 
777 template <typename HyperGraphT, typename LocalSolverT, typename LargeVecT, typename floatT>
778 void plot(HyperGraphT& hyper_graph,
779  const LocalSolverT& local_solver,
780  const LargeVecT& lambda,
781  PlotOptions& plot_options,
782  const floatT time)
783 {
784  hy_assert(plot_options.fileEnding == PlotOptions::vtu,
785  "Only file ending vtu is supported at the moment. Your choice has been "
786  << plot_options.fileEnding << ", which is invalid.");
787  hy_assert(!plot_options.fileName.empty(), "File name must not be empty!");
788  hy_assert(!plot_options.outputDir.empty(), "Ouput directory must not be empty!");
789  plot_vtu(hyper_graph, local_solver, lambda, plot_options, time);
790  if (plot_options.incrementFileNumber)
791  ++plot_options.fileNumber;
792 } // end of void plot
compile_time_tricks.hxx
first_dof
static constexpr unsigned int first_dof()
Auxiliary function to plot solution values on edge boundary.
Definition: plot.hxx:585
plot_edge_values
void plot_edge_values(HyperGraphT &hyper_graph, const LocalSolverT &local_solver, const LargeVecT &lambda, std::ofstream &myfile, SmallVec< n_subdivisions+1, float > abscissas, const floatT time)
Auxiliary function to plot solution values on edge.
Definition: plot.hxx:530
check_push_test.index
index
Definition: check_push_test.py:10
PlotOptions::fileName
std::string fileName
Name of the file plotted.
Definition: plot.hxx:33
PlotFunctions::open_ofstream
std::ofstream open_ofstream(const PlotOptions &plot_options, const bool append=false)
Open stream to file.
Definition: plot.hxx:247
PlotOptions
A class storing options for plotting.
Definition: plot.hxx:20
diffusion_uniform.geometry
geometry
Definition: diffusion_uniform.py:19
get_edge_dof_values
std::array< std::array< typename LargeVecT::value_type, HyperGraphT::n_dofs_per_node()>, 2 *edge_dim > get_edge_dof_values(HyperGraphT &hyper_graph, hyEdge_index_t edge_index, const LargeVecT &lambda)
Auxiliary function to get dof values of edge.
Definition: plot.hxx:506
PlotFunctions
Auxiliary functions for writing graphics files.
Definition: plot.hxx:225
PlotFunctions::close_ofstream
void close_ofstream(std::ofstream &myfile)
Close stream to file.
Definition: plot.hxx:273
PlotOptions::plot_edge_boundaries
bool plot_edge_boundaries
Include the edge boundaries with their function values into the plot.
Definition: plot.hxx:76
SmallMat::size
static constexpr unsigned int size()
Return size a SmallMat.
Definition: dense_la.hxx:54
PlotFunctions::HAS_MEMBER_FUNCTION
HAS_MEMBER_FUNCTION(bulk_values, has_bulk_values)
Prepare struct to check for function to exist (cf. compile_time_tricks.hxx).
diffusion_uniform.local_solver
local_solver
Definition: diffusion_uniform.py:17
PlotFunctions::fileType_to_string
std::string fileType_to_string(const PlotOptions::fileType &type)
Turn fileType enum into string.
Definition: plot.hxx:234
plot_boundary_values
void plot_boundary_values(HyperGraphT &hyper_graph, const LargeVecT &lambda, std::ofstream &myfile, SmallVec< n_subdivisions+1, float > abscissas)
Auxiliary function to plot solution values on edge boundary.
Definition: plot.hxx:637
PlotOptions::boundary_scale
float boundary_scale
A factor by which to separate two boundaries belonging to different edges.
Definition: plot.hxx:112
PlotOptions::vtu
@ vtu
Definition: plot.hxx:39
PlotOptions::scale
float scale
A factor for scaling each object of the plot locally.
Definition: plot.hxx:104
PlotFunctions::vtu_sub_cube_connectivity
void vtu_sub_cube_connectivity(std::ostream &output, unsigned int n, pt_index_t offset)
Output of the cubes of the subdivision of an edge in lexicographic order.
Definition: plot.hxx:288
PlotOptions::fileType
fileType
Enum for possible file endings.
Definition: plot.hxx:37
PlotOptions::fileEnding
fileType fileEnding
File ending and also way of plotting.
Definition: plot.hxx:48
SmallMat::data
std::array< mat_entry_t, size()> & data()
Return data array that allows to manipulate the SmallMat.
Definition: dense_la.hxx:190
Hypercube::n_vertices
static constexpr unsigned int n_vertices()
Number of vertices of the hypercube.
Definition: hypercube.hxx:21
hypercube.hxx
PlotOptions::fileNumber
unsigned int fileNumber
Number of the plot file.
Definition: plot.hxx:56
PlotOptions::numbers
bool numbers
Output a cell data array with the number of each edge and/or each node.
Definition: plot.hxx:116
Hypercube::pow
static constexpr unsigned int pow(unsigned int base)
Return n to the power dim.
Definition: hypercube.hxx:25
fancy_recursion
void fancy_recursion(__attribute__((unused)) lv_t &local_values, __attribute__((unused)) const hd_t &hyEdge_dofs, __attribute__((unused)) const pt_t &point, __attribute__((unused)) const unsigned int k, __attribute__((unused)) const unsigned int bdr_index)
Auxiliary function to plot solution values on edge boundary.
Definition: plot.hxx:602
PlotOptions::printFileNumber
bool printFileNumber
Decide whether fileNumber is part of the file name.
Definition: plot.hxx:63
plot
void plot(HyperGraphT &hyper_graph, const LocalSolverT &local_solver, const LargeVecT &lambda, PlotOptions &plot_options, const floatT time=0.)
Function plotting the solution of an equation on a hypergraph in vtu format.
Definition: plot.hxx:778
hy_assert
#define hy_assert(Expr, Msg)
The assertion to be used within HyperHDG — deactivate using -DNDEBUG compile flag.
Definition: hy_assert.hxx:38
dense_la.hxx
PlotOptions::incrementFileNumber
bool incrementFileNumber
Decide whether fileNumber is incremented after plotting.
Definition: plot.hxx:70
set_plot_option
std::string set_plot_option(PlotOptions &plot_options, const std::string &option, std::string value="")
Set a plot option and return the new value of this option as std::string.
Definition: plot.hxx:122
hdg_hypergraph.hxx
PlotFunctions::plot_vtu_unstructured_geometry
void plot_vtu_unstructured_geometry(std::ostream &output, HyperGraphT &hyper_graph, const SmallVec< n_subpoints, float > &sub_points, const SmallVec< n_subpoints, float > &boundary_sub_points, const PlotOptions &plot_options)
Auxiliary function for writing geometry section VTU files.
Definition: plot.hxx:333
PlotOptions::n_subintervals
unsigned int n_subintervals
Number of subintervals for plotting.
Definition: plot.hxx:97
PlotOptions::outputDir
std::string outputDir
Name of the directory to put the output into.
Definition: plot.hxx:27
PlotOptions::plot_edges
bool plot_edges
Include the hyperedges with their function values into the plot.
Definition: plot.hxx:82
plot_vtu
void plot_vtu(HyperGraphT &hyper_graph, const LocalSolverT &local_solver, const LargeVecT &lambda, const PlotOptions &plot_options, const floatT time=0.)
Auxiliary function to plot solution values to vtu file.
Definition: plot.hxx:690
SmallMat
This class implements a small/dense matrix.
Definition: dense_la.hxx:34
Hypercube
Helper class containing numbers and functions related to hypercubes.
Definition: hypercube.hxx:12