Reference documentation for deal.II version 9.3.2
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
data_out_base.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 1999 - 2021 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 
17 // TODO: Do neighbors for dx and povray smooth triangles
18 
20 // Remarks on the implementations
21 //
22 // Variable names: in most functions, variable names have been
23 // standardized in the following way:
24 //
25 // n1, n2, ni Number of points in coordinate direction 1, 2, i
26 // will be 1 if i>=dim
27 //
28 // i1, i2, ii Loop variable running up to ni
29 //
30 // d1, d2, di Multiplicators for ii to find positions in the
31 // array of nodes.
33 
36 #include <deal.II/base/mpi.h>
39 #include <deal.II/base/utilities.h>
40 
42 
43 #include <algorithm>
44 #include <cmath>
45 #include <cstring>
46 #include <ctime>
47 #include <fstream>
48 #include <iomanip>
49 #include <memory>
50 #include <set>
51 #include <sstream>
52 
53 // we use uint32_t and uint8_t below, which are declared here:
54 #include <cstdint>
55 #include <vector>
56 
57 #ifdef DEAL_II_WITH_ZLIB
58 # include <zlib.h>
59 #endif
60 
61 #ifdef DEAL_II_WITH_HDF5
62 # include <hdf5.h>
63 #endif
64 
66 
67 
68 // we need the following exception from a global function, so can't declare it
69 // in the usual way inside a class
70 namespace
71 {
72  DeclException2(ExcUnexpectedInput,
73  std::string,
74  std::string,
75  << "Unexpected input: expected line\n <" << arg1
76  << ">\nbut got\n <" << arg2 << ">");
77 }
78 
79 
80 namespace
81 {
82 #ifdef DEAL_II_WITH_ZLIB
87  int
88  get_zlib_compression_level(
90  {
91  switch (level)
92  {
94  return Z_NO_COMPRESSION;
96  return Z_BEST_SPEED;
98  return Z_BEST_COMPRESSION;
100  return Z_DEFAULT_COMPRESSION;
101  default:
102  Assert(false, ExcNotImplemented());
103  return Z_NO_COMPRESSION;
104  }
105  }
106 
111  template <typename T>
112  void
113  write_compressed_block(const std::vector<T> & data,
114  const DataOutBase::VtkFlags &flags,
115  std::ostream & output_stream)
116  {
117  if (data.size() != 0)
118  {
119  // allocate a buffer for compressing data and do so
120  auto compressed_data_length = compressBound(data.size() * sizeof(T));
121  std::vector<unsigned char> compressed_data(compressed_data_length);
122 
123  int err =
124  compress2(&compressed_data[0],
125  &compressed_data_length,
126  reinterpret_cast<const Bytef *>(data.data()),
127  data.size() * sizeof(T),
128  get_zlib_compression_level(flags.compression_level));
129  (void)err;
130  Assert(err == Z_OK, ExcInternalError());
131 
132  // Discard the unnecessary bytes
133  compressed_data.resize(compressed_data_length);
134 
135  // now encode the compression header
136  const uint32_t compression_header[4] = {
137  1, /* number of blocks */
138  static_cast<uint32_t>(data.size() * sizeof(T)), /* size of block */
139  static_cast<uint32_t>(data.size() *
140  sizeof(T)), /* size of last block */
141  static_cast<uint32_t>(
142  compressed_data_length)}; /* list of compressed sizes of blocks */
143 
144  const auto header_start =
145  reinterpret_cast<const unsigned char *>(&compression_header[0]);
146 
147  output_stream << Utilities::encode_base64(
148  {header_start, header_start + 4 * sizeof(uint32_t)})
149  << Utilities::encode_base64(compressed_data);
150  }
151  }
152 #endif
153 } // namespace
154 
155 
156 // some declarations of functions and locally used classes
157 namespace DataOutBase
158 {
159  namespace
160  {
166  class SvgCell
167  {
168  public:
169  // Center of the cell (three-dimensional)
171 
176 
181  float depth;
182 
187 
188  // Center of the cell (projected, two-dimensional)
190 
194  bool
195  operator<(const SvgCell &) const;
196  };
197 
198  bool
199  SvgCell::operator<(const SvgCell &e) const
200  {
201  // note the "wrong" order in which we sort the elements
202  return depth > e.depth;
203  }
204 
205 
206 
212  class EpsCell2d
213  {
214  public:
218  Point<2> vertices[4];
219 
224  float color_value;
225 
230  float depth;
231 
235  bool
236  operator<(const EpsCell2d &) const;
237  };
238 
239  bool
240  EpsCell2d::operator<(const EpsCell2d &e) const
241  {
242  // note the "wrong" order in which we sort the elements
243  return depth > e.depth;
244  }
245 
246 
247 
258  template <int dim, int spacedim, typename Number = double>
259  void
260  write_gmv_reorder_data_vectors(
261  const std::vector<Patch<dim, spacedim>> &patches,
262  Table<2, Number> & data_vectors)
263  {
264  // If there is nothing to write, just return
265  if (patches.size() == 0)
266  return;
267 
268  // unlike in the main function, we don't have here the data_names field,
269  // so we initialize it with the number of data sets in the first patch.
270  // the equivalence of these two definitions is checked in the main
271  // function.
272 
273  // we have to take care, however, whether the points are appended to the
274  // end of the patch.data table
275  const unsigned int n_data_sets = patches[0].points_are_available ?
276  (patches[0].data.n_rows() - spacedim) :
277  patches[0].data.n_rows();
278 
279  Assert(data_vectors.size()[0] == n_data_sets, ExcInternalError());
280 
281  // loop over all patches
282  unsigned int next_value = 0;
283  for (const auto &patch : patches)
284  {
285  const unsigned int n_subdivisions = patch.n_subdivisions;
286  (void)n_subdivisions;
287 
288  Assert((patch.data.n_rows() == n_data_sets &&
289  !patch.points_are_available) ||
290  (patch.data.n_rows() == n_data_sets + spacedim &&
291  patch.points_are_available),
292  ExcDimensionMismatch(patch.points_are_available ?
293  (n_data_sets + spacedim) :
294  n_data_sets,
295  patch.data.n_rows()));
296  Assert(patch.reference_cell != ReferenceCells::get_hypercube<dim>() ||
297  (n_data_sets == 0) ||
298  (patch.data.n_cols() ==
299  Utilities::fixed_power<dim>(n_subdivisions + 1)),
300  ExcInvalidDatasetSize(patch.data.n_cols(),
301  n_subdivisions + 1));
302 
303  for (unsigned int i = 0; i < patch.data.n_cols(); ++i, ++next_value)
304  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
305  data_vectors[data_set][next_value] = patch.data(data_set, i);
306  }
307 
308  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
309  Assert(data_vectors[data_set].size() == next_value, ExcInternalError());
310  }
311  } // namespace
312 
313 
314 
316  : flags(false, true)
317  , node_dim(numbers::invalid_unsigned_int)
318  , num_cells(numbers::invalid_unsigned_int)
319  {}
320 
321 
322 
324  : flags(flags)
325  , node_dim(numbers::invalid_unsigned_int)
326  , num_cells(numbers::invalid_unsigned_int)
327  {}
328 
329 
330 
331  template <int dim>
332  void
333  DataOutFilter::write_point(const unsigned int index, const Point<dim> &p)
334  {
335  node_dim = dim;
336 
337  Point<3> int_pt;
338  for (unsigned int d = 0; d < dim; ++d)
339  int_pt(d) = p(d);
340 
341  const Map3DPoint::const_iterator it = existing_points.find(int_pt);
342  unsigned int internal_ind;
343 
344  // If the point isn't in the set, or we're not filtering duplicate points,
345  // add it
346  if (it == existing_points.end() || !flags.filter_duplicate_vertices)
347  {
348  internal_ind = existing_points.size();
349  existing_points.insert(std::make_pair(int_pt, internal_ind));
350  }
351  else
352  {
353  internal_ind = it->second;
354  }
355  // Now add the index to the list of filtered points
356  filtered_points[index] = internal_ind;
357  }
358 
359 
360 
361  void
363  const unsigned int pt_index)
364  {
366 
367  // (Re)-initialize counter at any first call to this method.
368  if (cell_index == 0)
369  num_cells = 1;
370  }
371 
372 
373 
374  void
375  DataOutFilter::fill_node_data(std::vector<double> &node_data) const
376  {
377  node_data.resize(existing_points.size() * node_dim);
378 
379  for (const auto &existing_point : existing_points)
380  {
381  for (unsigned int d = 0; d < node_dim; ++d)
382  node_data[node_dim * existing_point.second + d] =
383  existing_point.first(d);
384  }
385  }
386 
387 
388 
389  void
390  DataOutFilter::fill_cell_data(const unsigned int local_node_offset,
391  std::vector<unsigned int> &cell_data) const
392  {
393  cell_data.resize(filtered_cells.size());
394 
395  for (const auto &filtered_cell : filtered_cells)
396  {
397  cell_data[filtered_cell.first] =
398  filtered_cell.second + local_node_offset;
399  }
400  }
401 
402 
403 
404  std::string
405  DataOutFilter::get_data_set_name(const unsigned int set_num) const
406  {
407  return data_set_names.at(set_num);
408  }
409 
410 
411 
412  unsigned int
413  DataOutFilter::get_data_set_dim(const unsigned int set_num) const
414  {
415  return data_set_dims.at(set_num);
416  }
417 
418 
419 
420  const double *
421  DataOutFilter::get_data_set(const unsigned int set_num) const
422  {
423  return data_sets[set_num].data();
424  }
425 
426 
427 
428  unsigned int
430  {
431  return existing_points.size();
432  }
433 
434 
435 
436  unsigned int
438  {
439  return num_cells;
440  }
441 
442 
443 
444  unsigned int
446  {
447  return data_set_names.size();
448  }
449 
450 
451 
452  void
454  {}
455 
456 
457 
458  void
460  {}
461 
462 
463 
464  template <int dim>
465  void
466  DataOutFilter::write_cell(const unsigned int index,
467  const unsigned int start,
468  const unsigned int d1,
469  const unsigned int d2,
470  const unsigned int d3)
471  {
472  ++num_cells;
473 
474  const unsigned int base_entry =
476 
477  internal_add_cell(base_entry + 0, start);
478  if (dim >= 1)
479  {
480  internal_add_cell(base_entry + 1, start + d1);
481  if (dim >= 2)
482  {
483  internal_add_cell(base_entry + 2, start + d2 + d1);
484  internal_add_cell(base_entry + 3, start + d2);
485  if (dim >= 3)
486  {
487  internal_add_cell(base_entry + 4, start + d3);
488  internal_add_cell(base_entry + 5, start + d3 + d1);
489  internal_add_cell(base_entry + 6, start + d3 + d2 + d1);
490  internal_add_cell(base_entry + 7, start + d3 + d2);
491  }
492  }
493  }
494  }
495 
496 
497 
498  void
499  DataOutFilter::write_cell_single(const unsigned int index,
500  const unsigned int start,
501  const unsigned int n_points)
502  {
503  ++num_cells;
504 
505  const unsigned int base_entry = index * n_points;
506 
507  for (unsigned int i = 0; i < n_points; ++i)
508  {
509  internal_add_cell(base_entry + i, start + i);
510  }
511  }
512 
513 
514 
515  void
516  DataOutFilter::write_data_set(const std::string & name,
517  const unsigned int dimension,
518  const unsigned int set_num,
519  const Table<2, double> &data_vectors)
520  {
521  unsigned int new_dim;
522 
523  // HDF5/XDMF output only supports 1D or 3D output, so force rearrangement if
524  // needed
525  if (flags.xdmf_hdf5_output && dimension != 1)
526  new_dim = 3;
527  else
528  new_dim = dimension;
529 
530  // Record the data set name, dimension, and allocate space for it
531  data_set_names.push_back(name);
532  data_set_dims.push_back(new_dim);
533  data_sets.emplace_back(new_dim * existing_points.size());
534 
535  // TODO: averaging, min/max, etc for merged vertices
536  for (unsigned int i = 0; i < filtered_points.size(); ++i)
537  {
538  const unsigned int r = filtered_points[i];
539 
540  for (unsigned int d = 0; d < new_dim; ++d)
541  {
542  if (d < dimension)
543  data_sets.back()[r * new_dim + d] = data_vectors(set_num + d, i);
544  else
545  data_sets.back()[r * new_dim + d] = 0;
546  }
547  }
548  }
549 } // namespace DataOutBase
550 
551 
552 
553 //----------------------------------------------------------------------//
554 // Auxiliary data
555 //----------------------------------------------------------------------//
556 
557 namespace
558 {
559  const char *gmv_cell_type[4] = {"", "line 2", "quad 4", "hex 8"};
560 
561  const char *ucd_cell_type[4] = {"pt", "line", "quad", "hex"};
562 
563  const char *tecplot_cell_type[4] = {"", "lineseg", "quadrilateral", "brick"};
564 
565 #ifdef DEAL_II_HAVE_TECPLOT
566  const unsigned int tecplot_binary_cell_type[4] = {0, 0, 1, 3};
567 #endif
568 
569  // Define cell id using VTK nomenclature for linear, quadratic and
570  // high-order Lagrange cells
571  enum vtk_linear_cell_type
572  {
573  VTK_VERTEX = 1,
574  VTK_LINE = 3,
575  VTK_TRIANGLE = 5,
576  VTK_QUAD = 9,
577  VTK_TETRA = 10,
578  VTK_HEXAHEDRON = 12,
579  VTK_WEDGE = 13,
580  VTK_PYRAMID = 14
581  };
582 
583  enum vtk_quadratic_cell_type
584  {
585  VTK_QUADRATIC_EDGE = 21,
586  VTK_QUADRATIC_TRIANGLE = 22,
587  VTK_QUADRATIC_QUAD = 23,
588  VTK_QUADRATIC_TETRA = 24,
589  VTK_QUADRATIC_HEXAHEDRON = 25,
590  VTK_QUADRATIC_WEDGE = 26,
591  VTK_QUADRATIC_PYRAMID = 27
592  };
593 
594  enum vtk_lagrange_cell_type
595  {
596  VTK_LAGRANGE_CURVE = 68,
597  VTK_LAGRANGE_TRIANGLE = 69,
598  VTK_LAGRANGE_QUADRILATERAL = 70,
599  VTK_LAGRANGE_TETRAHEDRON = 71,
600  VTK_LAGRANGE_HEXAHEDRON = 72,
601  VTK_LAGRANGE_WEDGE = 73,
602  VTK_LAGRANGE_PYRAMID = 74
603  };
604 
609  template <int dim, int spacedim>
610  std::array<unsigned int, 3>
611  extract_vtk_patch_info(const DataOutBase::Patch<dim, spacedim> &patch,
612  const bool write_higher_order_cells)
613  {
614  std::array<unsigned int, 3> vtk_cell_id{};
615 
616  if (write_higher_order_cells)
617  {
618  if (patch.reference_cell == ReferenceCells::get_hypercube<dim>())
619  {
620  const std::array<unsigned int, 4> cell_type_by_dim{
621  {VTK_VERTEX,
622  VTK_LAGRANGE_CURVE,
623  VTK_LAGRANGE_QUADRILATERAL,
624  VTK_LAGRANGE_HEXAHEDRON}};
625  vtk_cell_id[0] = cell_type_by_dim[dim];
626  vtk_cell_id[1] = 1;
627  }
628  else if (patch.reference_cell == ReferenceCells::Triangle)
629  {
630  vtk_cell_id[0] = VTK_LAGRANGE_TRIANGLE;
631  vtk_cell_id[1] = 1;
632  }
633  else
634  {
635  Assert(false, ExcNotImplemented());
636  }
637  }
638  else if (patch.reference_cell == ReferenceCells::Triangle &&
639  patch.data.n_cols() == 3)
640  {
641  vtk_cell_id[0] = VTK_TRIANGLE;
642  vtk_cell_id[1] = 1;
643  }
644  else if (patch.reference_cell == ReferenceCells::Triangle &&
645  patch.data.n_cols() == 6)
646  {
647  vtk_cell_id[0] = VTK_QUADRATIC_TRIANGLE;
648  vtk_cell_id[1] = 1;
649  }
650  else if (patch.reference_cell == ReferenceCells::Tetrahedron &&
651  patch.data.n_cols() == 4)
652  {
653  vtk_cell_id[0] = VTK_TETRA;
654  vtk_cell_id[1] = 1;
655  }
656  else if (patch.reference_cell == ReferenceCells::Tetrahedron &&
657  patch.data.n_cols() == 10)
658  {
659  vtk_cell_id[0] = VTK_QUADRATIC_TETRA;
660  vtk_cell_id[1] = 1;
661  }
662  else if (patch.reference_cell == ReferenceCells::Wedge &&
663  patch.data.n_cols() == 6)
664  {
665  vtk_cell_id[0] = VTK_WEDGE;
666  vtk_cell_id[1] = 1;
667  }
668  else if (patch.reference_cell == ReferenceCells::Pyramid &&
669  patch.data.n_cols() == 5)
670  {
671  vtk_cell_id[0] = VTK_PYRAMID;
672  vtk_cell_id[1] = 1;
673  }
674  else if (patch.reference_cell == ReferenceCells::get_hypercube<dim>())
675  {
676  const std::array<unsigned int, 4> cell_type_by_dim{
677  {VTK_VERTEX, VTK_LINE, VTK_QUAD, VTK_HEXAHEDRON}};
678  vtk_cell_id[0] = cell_type_by_dim[dim];
679  vtk_cell_id[1] = Utilities::pow(patch.n_subdivisions, dim);
680  }
681  else
682  {
683  Assert(false, ExcNotImplemented());
684  }
685 
686  if (patch.reference_cell != ReferenceCells::get_hypercube<dim>() ||
687  write_higher_order_cells)
688  vtk_cell_id[2] = patch.data.n_cols();
689  else
690  vtk_cell_id[2] = GeometryInfo<dim>::vertices_per_cell;
691 
692  return vtk_cell_id;
693  }
694 
695  //----------------------------------------------------------------------//
696  // Auxiliary functions
697  //----------------------------------------------------------------------//
698  // For a given patch, compute the node interpolating the corner nodes linearly
699  // at the point (xstep, ystep, zstep)*1./n_subdivisions. If the points are
700  // saved in the patch.data member, return the saved point instead.
701  template <int dim, int spacedim>
702  inline Point<spacedim>
703  compute_hypercube_node(const DataOutBase::Patch<dim, spacedim> &patch,
704  const unsigned int xstep,
705  const unsigned int ystep,
706  const unsigned int zstep,
707  const unsigned int n_subdivisions)
708  {
709  Point<spacedim> node;
710  if (patch.points_are_available)
711  {
712  unsigned int point_no = 0;
713  switch (dim)
714  {
715  case 3:
716  AssertIndexRange(zstep, n_subdivisions + 1);
717  point_no += (n_subdivisions + 1) * (n_subdivisions + 1) * zstep;
719  case 2:
720  AssertIndexRange(ystep, n_subdivisions + 1);
721  point_no += (n_subdivisions + 1) * ystep;
723  case 1:
724  AssertIndexRange(xstep, n_subdivisions + 1);
725  point_no += xstep;
727  case 0:
728  // break here for dim<=3
729  break;
730 
731  default:
732  Assert(false, ExcNotImplemented());
733  }
734  for (unsigned int d = 0; d < spacedim; ++d)
735  node[d] = patch.data(patch.data.size(0) - spacedim + d, point_no);
736  }
737  else
738  {
739  if (dim == 0)
740  node = patch.vertices[0];
741  else
742  {
743  // perform a dim-linear interpolation
744  const double stepsize = 1. / n_subdivisions,
745  xfrac = xstep * stepsize;
746 
747  node =
748  (patch.vertices[1] * xfrac) + (patch.vertices[0] * (1 - xfrac));
749  if (dim > 1)
750  {
751  const double yfrac = ystep * stepsize;
752  node *= 1 - yfrac;
753  node += ((patch.vertices[3] * xfrac) +
754  (patch.vertices[2] * (1 - xfrac))) *
755  yfrac;
756  if (dim > 2)
757  {
758  const double zfrac = zstep * stepsize;
759  node *= (1 - zfrac);
760  node += (((patch.vertices[5] * xfrac) +
761  (patch.vertices[4] * (1 - xfrac))) *
762  (1 - yfrac) +
763  ((patch.vertices[7] * xfrac) +
764  (patch.vertices[6] * (1 - xfrac))) *
765  yfrac) *
766  zfrac;
767  }
768  }
769  }
770  }
771  return node;
772  }
773 
774  // For a given patch, compute the nodes for arbitrary (non-hypercube) cells.
775  // If the points are saved in the patch.data member, return the saved point
776  // instead.
777  template <int dim, int spacedim>
778  inline Point<spacedim>
779  compute_arbitrary_node(const DataOutBase::Patch<dim, spacedim> &patch,
780  const unsigned int point_no)
781  {
782  Point<spacedim> node;
783 
784  if (patch.points_are_available)
785  {
786  for (unsigned int d = 0; d < spacedim; ++d)
787  node[d] = patch.data(patch.data.size(0) - spacedim + d, point_no);
788  return node;
789  }
790  else
791  {
793  Assert(
795  ExcMessage(
796  "Pyramids need different ordering of the vertices, which is not implemented yet here."));
797 
798  node = patch.vertices[point_no];
799  }
800 
801  return node;
802  }
803 
811  int
812  vtk_point_index_from_ijk(const unsigned i,
813  const unsigned j,
814  const unsigned,
815  const std::array<unsigned, 2> &order)
816  {
817  const bool ibdy = (i == 0 || i == order[0]);
818  const bool jbdy = (j == 0 || j == order[1]);
819  // How many boundaries do we lie on at once?
820  const int nbdy = (ibdy ? 1 : 0) + (jbdy ? 1 : 0);
821 
822  if (nbdy == 2) // Vertex DOF
823  { // ijk is a corner node. Return the proper index (somewhere in [0,3]):
824  return (i ? (j ? 2 : 1) : (j ? 3 : 0));
825  }
826 
827  int offset = 4;
828  if (nbdy == 1) // Edge DOF
829  {
830  if (!ibdy)
831  { // On i axis
832  return (i - 1) + (j ? order[0] - 1 + order[1] - 1 : 0) + offset;
833  }
834 
835  if (!jbdy)
836  { // On j axis
837  return (j - 1) +
838  (i ? order[0] - 1 : 2 * (order[0] - 1) + order[1] - 1) +
839  offset;
840  }
841  }
842 
843  offset += 2 * (order[0] - 1 + order[1] - 1);
844  // nbdy == 0: Face DOF
845  return offset + (i - 1) + (order[0] - 1) * ((j - 1));
846  }
847 
855  int
856  vtk_point_index_from_ijk(const unsigned i,
857  const unsigned j,
858  const unsigned k,
859  const std::array<unsigned, 3> &order)
860  {
861  const bool ibdy = (i == 0 || i == order[0]);
862  const bool jbdy = (j == 0 || j == order[1]);
863  const bool kbdy = (k == 0 || k == order[2]);
864  // How many boundaries do we lie on at once?
865  const int nbdy = (ibdy ? 1 : 0) + (jbdy ? 1 : 0) + (kbdy ? 1 : 0);
866 
867  if (nbdy == 3) // Vertex DOF
868  { // ijk is a corner node. Return the proper index (somewhere in [0,7]):
869  return (i ? (j ? 2 : 1) : (j ? 3 : 0)) + (k ? 4 : 0);
870  }
871 
872  int offset = 8;
873  if (nbdy == 2) // Edge DOF
874  {
875  if (!ibdy)
876  { // On i axis
877  return (i - 1) + (j ? order[0] - 1 + order[1] - 1 : 0) +
878  (k ? 2 * (order[0] - 1 + order[1] - 1) : 0) + offset;
879  }
880  if (!jbdy)
881  { // On j axis
882  return (j - 1) +
883  (i ? order[0] - 1 : 2 * (order[0] - 1) + order[1] - 1) +
884  (k ? 2 * (order[0] - 1 + order[1] - 1) : 0) + offset;
885  }
886  // !kbdy, On k axis
887  offset += 4 * (order[0] - 1) + 4 * (order[1] - 1);
888  return (k - 1) + (order[2] - 1) * (i ? (j ? 3 : 1) : (j ? 2 : 0)) +
889  offset;
890  }
891 
892  offset += 4 * (order[0] - 1 + order[1] - 1 + order[2] - 1);
893  if (nbdy == 1) // Face DOF
894  {
895  if (ibdy) // On i-normal face
896  {
897  return (j - 1) + ((order[1] - 1) * (k - 1)) +
898  (i ? (order[1] - 1) * (order[2] - 1) : 0) + offset;
899  }
900  offset += 2 * (order[1] - 1) * (order[2] - 1);
901  if (jbdy) // On j-normal face
902  {
903  return (i - 1) + ((order[0] - 1) * (k - 1)) +
904  (j ? (order[2] - 1) * (order[0] - 1) : 0) + offset;
905  }
906  offset += 2 * (order[2] - 1) * (order[0] - 1);
907  // kbdy, On k-normal face
908  return (i - 1) + ((order[0] - 1) * (j - 1)) +
909  (k ? (order[0] - 1) * (order[1] - 1) : 0) + offset;
910  }
911 
912  // nbdy == 0: Body DOF
913  offset +=
914  2 * ((order[1] - 1) * (order[2] - 1) + (order[2] - 1) * (order[0] - 1) +
915  (order[0] - 1) * (order[1] - 1));
916  return offset + (i - 1) +
917  (order[0] - 1) * ((j - 1) + (order[1] - 1) * ((k - 1)));
918  }
919 
920  int
921  vtk_point_index_from_ijk(const unsigned,
922  const unsigned,
923  const unsigned,
924  const std::array<unsigned, 0> &)
925  {
926  Assert(false, ExcNotImplemented());
927  return 0;
928  }
929 
930  int
931  vtk_point_index_from_ijk(const unsigned,
932  const unsigned,
933  const unsigned,
934  const std::array<unsigned, 1> &)
935  {
936  Assert(false, ExcNotImplemented());
937  return 0;
938  }
939 
940 
941  template <int dim, int spacedim>
942  static void
943  compute_sizes(const std::vector<DataOutBase::Patch<dim, spacedim>> &patches,
944  unsigned int & n_nodes,
945  unsigned int & n_cells)
946  {
947  n_nodes = 0;
948  n_cells = 0;
949  for (const auto &patch : patches)
950  {
951  // The following formula doesn't hold for non-tensor products.
952  if (patch.reference_cell == ReferenceCells::get_hypercube<dim>())
953  {
954  n_nodes += Utilities::fixed_power<dim>(patch.n_subdivisions + 1);
955  n_cells += Utilities::fixed_power<dim>(patch.n_subdivisions);
956  }
957  else
958  {
959  Assert(patch.n_subdivisions == 1, ExcNotImplemented());
960  n_nodes += patch.reference_cell.n_vertices();
961  n_cells += 1;
962  }
963  }
964  }
965 
966  template <int dim, int spacedim>
967  static void
968  compute_sizes(const std::vector<DataOutBase::Patch<dim, spacedim>> &patches,
969  const bool write_higher_order_cells,
970  unsigned int &n_nodes,
971  unsigned int &n_cells,
972  unsigned int &n_points_and_n_cells)
973  {
974  n_nodes = 0;
975  n_cells = 0;
976  n_points_and_n_cells = 0;
977 
978  for (const auto &patch : patches)
979  {
980  // The following formulas don't hold for non-tensor products.
981  if (patch.reference_cell == ReferenceCells::get_hypercube<dim>())
982  {
983  n_nodes += Utilities::fixed_power<dim>(patch.n_subdivisions + 1);
984 
985  if (write_higher_order_cells)
986  {
987  n_cells += 1;
988  n_points_and_n_cells +=
989  1 + Utilities::fixed_power<dim>(patch.n_subdivisions + 1);
990  }
991  else
992  {
993  n_cells += Utilities::fixed_power<dim>(patch.n_subdivisions);
994  n_points_and_n_cells +=
995  Utilities::fixed_power<dim>(patch.n_subdivisions) *
997  }
998  }
999  else
1000  {
1001  n_nodes += patch.data.n_cols();
1002  n_cells += 1;
1003  n_points_and_n_cells += patch.data.n_cols() + 1;
1004  }
1005  }
1006  }
1007 
1013  template <typename FlagsType>
1014  class StreamBase
1015  {
1016  public:
1017  /*
1018  * Constructor. Stores a reference to the output stream for immediate use.
1019  */
1020  StreamBase(std::ostream &stream, const FlagsType &flags)
1021  : selected_component(numbers::invalid_unsigned_int)
1022  , stream(stream)
1023  , flags(flags)
1024  {}
1025 
1030  template <int dim>
1031  void
1032  write_point(const unsigned int, const Point<dim> &)
1033  {
1034  Assert(false,
1035  ExcMessage("The derived class you are using needs to "
1036  "reimplement this function if you want to call "
1037  "it."));
1038  }
1039 
1045  void
1046  flush_points()
1047  {}
1048 
1054  template <int dim>
1055  void
1056  write_cell(const unsigned int /*index*/,
1057  const unsigned int /*start*/,
1058  const unsigned int /*x_offset*/,
1059  const unsigned int /*y_offset*/,
1060  const unsigned int /*z_offset*/)
1061  {
1062  Assert(false,
1063  ExcMessage("The derived class you are using needs to "
1064  "reimplement this function if you want to call "
1065  "it."));
1066  }
1067 
1074  void
1075  write_cell_single(const unsigned int index,
1076  const unsigned int start,
1077  const unsigned int n_points)
1078  {
1079  (void)index;
1080  (void)start;
1081  (void)n_points;
1082 
1083  Assert(false,
1084  ExcMessage("The derived class you are using needs to "
1085  "reimplement this function if you want to call "
1086  "it."));
1087  }
1088 
1095  void
1096  flush_cells()
1097  {}
1098 
1103  template <typename T>
1104  std::ostream &
1105  operator<<(const T &t)
1106  {
1107  stream << t;
1108  return stream;
1109  }
1110 
1117  unsigned int selected_component;
1118 
1119  protected:
1124  std::ostream &stream;
1125 
1129  const FlagsType flags;
1130  };
1131 
1135  class DXStream : public StreamBase<DataOutBase::DXFlags>
1136  {
1137  public:
1138  DXStream(std::ostream &stream, const DataOutBase::DXFlags &flags);
1139 
1140  template <int dim>
1141  void
1142  write_point(const unsigned int index, const Point<dim> &);
1143 
1152  template <int dim>
1153  void
1154  write_cell(const unsigned int index,
1155  const unsigned int start,
1156  const unsigned int x_offset,
1157  const unsigned int y_offset,
1158  const unsigned int z_offset);
1159 
1166  template <typename data>
1167  void
1168  write_dataset(const unsigned int index, const std::vector<data> &values);
1169  };
1170 
1174  class GmvStream : public StreamBase<DataOutBase::GmvFlags>
1175  {
1176  public:
1177  GmvStream(std::ostream &stream, const DataOutBase::GmvFlags &flags);
1178 
1179  template <int dim>
1180  void
1181  write_point(const unsigned int index, const Point<dim> &);
1182 
1191  template <int dim>
1192  void
1193  write_cell(const unsigned int index,
1194  const unsigned int start,
1195  const unsigned int x_offset,
1196  const unsigned int y_offset,
1197  const unsigned int z_offset);
1198  };
1199 
1203  class TecplotStream : public StreamBase<DataOutBase::TecplotFlags>
1204  {
1205  public:
1206  TecplotStream(std::ostream &stream, const DataOutBase::TecplotFlags &flags);
1207 
1208  template <int dim>
1209  void
1210  write_point(const unsigned int index, const Point<dim> &);
1211 
1220  template <int dim>
1221  void
1222  write_cell(const unsigned int index,
1223  const unsigned int start,
1224  const unsigned int x_offset,
1225  const unsigned int y_offset,
1226  const unsigned int z_offset);
1227  };
1228 
1232  class UcdStream : public StreamBase<DataOutBase::UcdFlags>
1233  {
1234  public:
1235  UcdStream(std::ostream &stream, const DataOutBase::UcdFlags &flags);
1236 
1237  template <int dim>
1238  void
1239  write_point(const unsigned int index, const Point<dim> &);
1240 
1251  template <int dim>
1252  void
1253  write_cell(const unsigned int index,
1254  const unsigned int start,
1255  const unsigned int x_offset,
1256  const unsigned int y_offset,
1257  const unsigned int z_offset);
1258 
1265  template <typename data>
1266  void
1267  write_dataset(const unsigned int index, const std::vector<data> &values);
1268  };
1269 
1273  class VtkStream : public StreamBase<DataOutBase::VtkFlags>
1274  {
1275  public:
1276  VtkStream(std::ostream &stream, const DataOutBase::VtkFlags &flags);
1277 
1278  template <int dim>
1279  void
1280  write_point(const unsigned int index, const Point<dim> &);
1281 
1290  template <int dim>
1291  void
1292  write_cell(const unsigned int index,
1293  const unsigned int start,
1294  const unsigned int x_offset,
1295  const unsigned int y_offset,
1296  const unsigned int z_offset);
1297 
1301  void
1302  write_cell_single(const unsigned int index,
1303  const unsigned int start,
1304  const unsigned int n_points);
1305 
1313  template <int dim>
1314  void
1315  write_high_order_cell(const unsigned int index,
1316  const unsigned int start,
1317  const std::vector<unsigned> &connectivity);
1318  };
1319 
1320 
1321  class VtuStream : public StreamBase<DataOutBase::VtkFlags>
1322  {
1323  public:
1324  VtuStream(std::ostream &stream, const DataOutBase::VtkFlags &flags);
1325 
1326  template <int dim>
1327  void
1328  write_point(const unsigned int index, const Point<dim> &);
1329 
1330  void
1331  flush_points();
1332 
1341  template <int dim>
1342  void
1343  write_cell(const unsigned int index,
1344  const unsigned int start,
1345  const unsigned int x_offset,
1346  const unsigned int y_offset,
1347  const unsigned int z_offset);
1348 
1352  void
1353  write_cell_single(const unsigned int index,
1354  const unsigned int start,
1355  const unsigned int n_points);
1356 
1364  template <int dim>
1365  void
1366  write_high_order_cell(const unsigned int index,
1367  const unsigned int start,
1368  const std::vector<unsigned> &connectivity);
1369 
1370  void
1371  flush_cells();
1372 
1373  template <typename T>
1374  std::ostream &
1375  operator<<(const T &);
1376 
1384  template <typename T>
1385  std::ostream &
1386  operator<<(const std::vector<T> &);
1387 
1388  private:
1397  std::vector<float> vertices;
1398  std::vector<int32_t> cells;
1399  };
1400 
1401 
1402  //----------------------------------------------------------------------//
1403 
1404  DXStream::DXStream(std::ostream &out, const DataOutBase::DXFlags &f)
1405  : StreamBase<DataOutBase::DXFlags>(out, f)
1406  {}
1407 
1408 
1409  template <int dim>
1410  void
1411  DXStream::write_point(const unsigned int, const Point<dim> &p)
1412  {
1413  if (flags.coordinates_binary)
1414  {
1415  float data[dim];
1416  for (unsigned int d = 0; d < dim; ++d)
1417  data[d] = p(d);
1418  stream.write(reinterpret_cast<const char *>(data), dim * sizeof(*data));
1419  }
1420  else
1421  {
1422  for (unsigned int d = 0; d < dim; ++d)
1423  stream << p(d) << '\t';
1424  stream << '\n';
1425  }
1426  }
1427 
1428 
1429 
1430  // Separate these out to avoid an internal compiler error with intel 17
1432  {
1437  template <int dim>
1438  std::array<unsigned int, GeometryInfo<dim>::vertices_per_cell>
1439  set_node_numbers(const unsigned int /*start*/,
1440  const unsigned int /*d1*/,
1441  const unsigned int /*d2*/,
1442  const unsigned int /*d3*/)
1443  {
1444  Assert(false, ExcInternalError());
1445  return {};
1446  }
1447 
1448 
1449 
1450  template <>
1451  std::array<unsigned int, GeometryInfo<1>::vertices_per_cell>
1452  set_node_numbers<1>(const unsigned int start,
1453  const unsigned int d1,
1454  const unsigned int /*d2*/,
1455  const unsigned int /*d3*/)
1456 
1457  {
1458  std::array<unsigned int, GeometryInfo<1>::vertices_per_cell> nodes;
1459  nodes[0] = start;
1460  nodes[1] = start + d1;
1461  return nodes;
1462  }
1463 
1464 
1465 
1466  template <>
1467  std::array<unsigned int, GeometryInfo<2>::vertices_per_cell>
1468  set_node_numbers<2>(const unsigned int start,
1469  const unsigned int d1,
1470  const unsigned int d2,
1471  const unsigned int /*d3*/)
1472 
1473  {
1474  std::array<unsigned int, GeometryInfo<2>::vertices_per_cell> nodes;
1475  nodes[0] = start;
1476  nodes[1] = start + d1;
1477  nodes[2] = start + d2;
1478  nodes[3] = start + d2 + d1;
1479  return nodes;
1480  }
1481 
1482 
1483 
1484  template <>
1485  std::array<unsigned int, GeometryInfo<3>::vertices_per_cell>
1486  set_node_numbers<3>(const unsigned int start,
1487  const unsigned int d1,
1488  const unsigned int d2,
1489  const unsigned int d3)
1490  {
1491  std::array<unsigned int, GeometryInfo<3>::vertices_per_cell> nodes;
1492  nodes[0] = start;
1493  nodes[1] = start + d1;
1494  nodes[2] = start + d2;
1495  nodes[3] = start + d2 + d1;
1496  nodes[4] = start + d3;
1497  nodes[5] = start + d3 + d1;
1498  nodes[6] = start + d3 + d2;
1499  nodes[7] = start + d3 + d2 + d1;
1500  return nodes;
1501  }
1502  } // namespace DataOutBaseImplementation
1503 
1504 
1505 
1506  template <int dim>
1507  void
1508  DXStream::write_cell(unsigned int,
1509  unsigned int start,
1510  unsigned int d1,
1511  unsigned int d2,
1512  unsigned int d3)
1513  {
1514  const auto nodes =
1515  DataOutBaseImplementation::set_node_numbers<dim>(start, d1, d2, d3);
1516 
1517  if (flags.int_binary)
1518  {
1519  std::array<unsigned int, GeometryInfo<dim>::vertices_per_cell> temp;
1520  for (unsigned int i = 0; i < nodes.size(); ++i)
1521  temp[i] = nodes[GeometryInfo<dim>::dx_to_deal[i]];
1522  stream.write(reinterpret_cast<const char *>(temp.data()),
1523  temp.size() * sizeof(temp[0]));
1524  }
1525  else
1526  {
1527  for (unsigned int i = 0; i < nodes.size() - 1; ++i)
1528  stream << nodes[GeometryInfo<dim>::dx_to_deal[i]] << '\t';
1529  stream << nodes[GeometryInfo<dim>::dx_to_deal[nodes.size() - 1]]
1530  << '\n';
1531  }
1532  }
1533 
1534 
1535 
1536  template <typename data>
1537  inline void
1538  DXStream::write_dataset(const unsigned int, const std::vector<data> &values)
1539  {
1540  if (flags.data_binary)
1541  {
1542  stream.write(reinterpret_cast<const char *>(values.data()),
1543  values.size() * sizeof(data));
1544  }
1545  else
1546  {
1547  for (unsigned int i = 0; i < values.size(); ++i)
1548  stream << '\t' << values[i];
1549  stream << '\n';
1550  }
1551  }
1552 
1553 
1554 
1555  //----------------------------------------------------------------------//
1556 
1557  GmvStream::GmvStream(std::ostream &out, const DataOutBase::GmvFlags &f)
1558  : StreamBase<DataOutBase::GmvFlags>(out, f)
1559  {}
1560 
1561 
1562  template <int dim>
1563  void
1564  GmvStream::write_point(const unsigned int, const Point<dim> &p)
1565  {
1566  Assert(selected_component != numbers::invalid_unsigned_int,
1567  ExcNotInitialized());
1568  stream << p(selected_component) << ' ';
1569  }
1570 
1571 
1572 
1573  template <int dim>
1574  void
1575  GmvStream::write_cell(unsigned int,
1576  unsigned int s,
1577  unsigned int d1,
1578  unsigned int d2,
1579  unsigned int d3)
1580  {
1581  // Vertices are numbered starting with one.
1582  const unsigned int start = s + 1;
1583  stream << gmv_cell_type[dim] << '\n';
1584 
1585  stream << start;
1586  if (dim >= 1)
1587  {
1588  stream << '\t' << start + d1;
1589  if (dim >= 2)
1590  {
1591  stream << '\t' << start + d2 + d1 << '\t' << start + d2;
1592  if (dim >= 3)
1593  {
1594  stream << '\t' << start + d3 << '\t' << start + d3 + d1 << '\t'
1595  << start + d3 + d2 + d1 << '\t' << start + d3 + d2;
1596  }
1597  }
1598  }
1599  stream << '\n';
1600  }
1601 
1602 
1603 
1604  TecplotStream::TecplotStream(std::ostream & out,
1605  const DataOutBase::TecplotFlags &f)
1606  : StreamBase<DataOutBase::TecplotFlags>(out, f)
1607  {}
1608 
1609 
1610  template <int dim>
1611  void
1612  TecplotStream::write_point(const unsigned int, const Point<dim> &p)
1613  {
1614  Assert(selected_component != numbers::invalid_unsigned_int,
1615  ExcNotInitialized());
1616  stream << p(selected_component) << '\n';
1617  }
1618 
1619 
1620 
1621  template <int dim>
1622  void
1623  TecplotStream::write_cell(unsigned int,
1624  unsigned int s,
1625  unsigned int d1,
1626  unsigned int d2,
1627  unsigned int d3)
1628  {
1629  const unsigned int start = s + 1;
1630 
1631  stream << start;
1632  if (dim >= 1)
1633  {
1634  stream << '\t' << start + d1;
1635  if (dim >= 2)
1636  {
1637  stream << '\t' << start + d2 + d1 << '\t' << start + d2;
1638  if (dim >= 3)
1639  {
1640  stream << '\t' << start + d3 << '\t' << start + d3 + d1 << '\t'
1641  << start + d3 + d2 + d1 << '\t' << start + d3 + d2;
1642  }
1643  }
1644  }
1645  stream << '\n';
1646  }
1647 
1648 
1649 
1650  UcdStream::UcdStream(std::ostream &out, const DataOutBase::UcdFlags &f)
1651  : StreamBase<DataOutBase::UcdFlags>(out, f)
1652  {}
1653 
1654 
1655  template <int dim>
1656  void
1657  UcdStream::write_point(const unsigned int index, const Point<dim> &p)
1658  {
1659  stream << index + 1 << " ";
1660  // write out coordinates
1661  for (unsigned int i = 0; i < dim; ++i)
1662  stream << p(i) << ' ';
1663  // fill with zeroes
1664  for (unsigned int i = dim; i < 3; ++i)
1665  stream << "0 ";
1666  stream << '\n';
1667  }
1668 
1669 
1670 
1671  template <int dim>
1672  void
1673  UcdStream::write_cell(unsigned int index,
1674  unsigned int start,
1675  unsigned int d1,
1676  unsigned int d2,
1677  unsigned int d3)
1678  {
1679  const auto nodes =
1680  DataOutBaseImplementation::set_node_numbers<dim>(start, d1, d2, d3);
1681 
1682  // Write out all cells and remember that all indices must be shifted by one.
1683  stream << index + 1 << "\t0 " << ucd_cell_type[dim];
1684  for (unsigned int i = 0; i < nodes.size(); ++i)
1685  stream << '\t' << nodes[GeometryInfo<dim>::ucd_to_deal[i]] + 1;
1686  stream << '\n';
1687  }
1688 
1689 
1690 
1691  template <typename data>
1692  inline void
1693  UcdStream::write_dataset(const unsigned int index,
1694  const std::vector<data> &values)
1695  {
1696  stream << index + 1;
1697  for (unsigned int i = 0; i < values.size(); ++i)
1698  stream << '\t' << values[i];
1699  stream << '\n';
1700  }
1701 
1702 
1703 
1704  //----------------------------------------------------------------------//
1705 
1706  VtkStream::VtkStream(std::ostream &out, const DataOutBase::VtkFlags &f)
1707  : StreamBase<DataOutBase::VtkFlags>(out, f)
1708  {}
1709 
1710 
1711  template <int dim>
1712  void
1713  VtkStream::write_point(const unsigned int, const Point<dim> &p)
1714  {
1715  // write out coordinates
1716  stream << p;
1717  // fill with zeroes
1718  for (unsigned int i = dim; i < 3; ++i)
1719  stream << " 0";
1720  stream << '\n';
1721  }
1722 
1723 
1724 
1725  template <int dim>
1726  void
1727  VtkStream::write_cell(unsigned int,
1728  unsigned int start,
1729  unsigned int d1,
1730  unsigned int d2,
1731  unsigned int d3)
1732  {
1733  stream << GeometryInfo<dim>::vertices_per_cell << '\t' << start;
1734 
1735  if (dim >= 1)
1736  stream << '\t' << start + d1;
1737  {
1738  if (dim >= 2)
1739  {
1740  stream << '\t' << start + d2 + d1 << '\t' << start + d2;
1741  if (dim >= 3)
1742  {
1743  stream << '\t' << start + d3 << '\t' << start + d3 + d1 << '\t'
1744  << start + d3 + d2 + d1 << '\t' << start + d3 + d2;
1745  }
1746  }
1747  }
1748  stream << '\n';
1749  }
1750 
1751  void
1752  VtkStream::write_cell_single(const unsigned int index,
1753  const unsigned int start,
1754  const unsigned int n_points)
1755  {
1756  (void)index;
1757 
1758  stream << '\t' << n_points;
1759  for (unsigned int i = 0; i < n_points; ++i)
1760  stream << '\t' << start + i;
1761  stream << '\n';
1762  }
1763 
1764  template <int dim>
1765  void
1766  VtkStream::write_high_order_cell(const unsigned int,
1767  const unsigned int start,
1768  const std::vector<unsigned> &connectivity)
1769  {
1770  stream << connectivity.size();
1771  for (const auto &c : connectivity)
1772  stream << '\t' << start + c;
1773  stream << '\n';
1774  }
1775 
1776  VtuStream::VtuStream(std::ostream &out, const DataOutBase::VtkFlags &f)
1777  : StreamBase<DataOutBase::VtkFlags>(out, f)
1778  {}
1779 
1780 
1781  template <int dim>
1782  void
1783  VtuStream::write_point(const unsigned int, const Point<dim> &p)
1784  {
1785 #if !defined(DEAL_II_WITH_ZLIB)
1786  // write out coordinates
1787  stream << p;
1788  // fill with zeroes
1789  for (unsigned int i = dim; i < 3; ++i)
1790  stream << " 0";
1791  stream << '\n';
1792 #else
1793  // if we want to compress, then first collect all the data in an array
1794  for (unsigned int i = 0; i < dim; ++i)
1795  vertices.push_back(p[i]);
1796  for (unsigned int i = dim; i < 3; ++i)
1797  vertices.push_back(0);
1798 #endif
1799  }
1800 
1801 
1802  void
1803  VtuStream::flush_points()
1804  {
1805 #ifdef DEAL_II_WITH_ZLIB
1806  // compress the data we have in memory and write them to the stream. then
1807  // release the data
1808  *this << vertices << '\n';
1809  vertices.clear();
1810 #endif
1811  }
1812 
1813 
1814  template <int dim>
1815  void
1816  VtuStream::write_cell(unsigned int,
1817  unsigned int start,
1818  unsigned int d1,
1819  unsigned int d2,
1820  unsigned int d3)
1821  {
1822 #if !defined(DEAL_II_WITH_ZLIB)
1823  stream << start;
1824  if (dim >= 1)
1825  {
1826  stream << '\t' << start + d1;
1827  if (dim >= 2)
1828  {
1829  stream << '\t' << start + d2 + d1 << '\t' << start + d2;
1830  if (dim >= 3)
1831  {
1832  stream << '\t' << start + d3 << '\t' << start + d3 + d1 << '\t'
1833  << start + d3 + d2 + d1 << '\t' << start + d3 + d2;
1834  }
1835  }
1836  }
1837  stream << '\n';
1838 #else
1839  cells.push_back(start);
1840  if (dim >= 1)
1841  {
1842  cells.push_back(start + d1);
1843  if (dim >= 2)
1844  {
1845  cells.push_back(start + d2 + d1);
1846  cells.push_back(start + d2);
1847  if (dim >= 3)
1848  {
1849  cells.push_back(start + d3);
1850  cells.push_back(start + d3 + d1);
1851  cells.push_back(start + d3 + d2 + d1);
1852  cells.push_back(start + d3 + d2);
1853  }
1854  }
1855  }
1856 #endif
1857  }
1858 
1859  void
1860  VtuStream::write_cell_single(const unsigned int index,
1861  const unsigned int start,
1862  const unsigned int n_points)
1863  {
1864  (void)index;
1865 
1866 #if !defined(DEAL_II_WITH_ZLIB)
1867  for (unsigned int i = 0; i < n_points; ++i)
1868  stream << '\t' << start + i;
1869  stream << '\n';
1870 #else
1871  for (unsigned int i = 0; i < n_points; ++i)
1872  cells.push_back(start + i);
1873 #endif
1874  }
1875 
1876  template <int dim>
1877  void
1878  VtuStream::write_high_order_cell(const unsigned int,
1879  const unsigned int start,
1880  const std::vector<unsigned> &connectivity)
1881  {
1882 #if !defined(DEAL_II_WITH_ZLIB)
1883  for (const auto &c : connectivity)
1884  stream << '\t' << start + c;
1885  stream << '\n';
1886 #else
1887  for (const auto &c : connectivity)
1888  cells.push_back(start + c);
1889 #endif
1890  }
1891 
1892  void
1893  VtuStream::flush_cells()
1894  {
1895 #ifdef DEAL_II_WITH_ZLIB
1896  // compress the data we have in memory and write them to the stream. then
1897  // release the data
1898  *this << cells << '\n';
1899  cells.clear();
1900 #endif
1901  }
1902 
1903 
1904  template <typename T>
1905  std::ostream &
1906  VtuStream::operator<<(const std::vector<T> &data)
1907  {
1908 #ifdef DEAL_II_WITH_ZLIB
1909  // compress the data we have in memory and write them to the stream. then
1910  // release the data
1911  write_compressed_block(data, flags, stream);
1912 #else
1913  for (unsigned int i = 0; i < data.size(); ++i)
1914  stream << data[i] << ' ';
1915 #endif
1916 
1917  return stream;
1918  }
1919 } // namespace
1920 
1921 
1922 
1923 namespace DataOutBase
1924 {
1925  const unsigned int Deal_II_IntermediateFlags::format_version = 3;
1926 
1927 
1928  template <int dim, int spacedim>
1929  const unsigned int Patch<dim, spacedim>::space_dim;
1930 
1931 
1932  template <int dim, int spacedim>
1933  const unsigned int Patch<dim, spacedim>::no_neighbor;
1934 
1935 
1936  template <int dim, int spacedim>
1938  : patch_index(no_neighbor)
1939  , n_subdivisions(1)
1940  , points_are_available(false)
1942  // all the other data has a constructor of its own, except for the "neighbors"
1943  // field, which we set to invalid values.
1944  {
1945  for (unsigned int i : GeometryInfo<dim>::face_indices())
1946  neighbors[i] = no_neighbor;
1947 
1948  AssertIndexRange(dim, spacedim + 1);
1949  Assert(spacedim <= 3, ExcNotImplemented());
1950  }
1951 
1952 
1953 
1954  template <int dim, int spacedim>
1955  bool
1957  {
1958  // TODO: make tolerance relative
1959  const double epsilon = 3e-16;
1960  for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
1961  if (vertices[i].distance(patch.vertices[i]) > epsilon)
1962  return false;
1963 
1964  for (unsigned int i : GeometryInfo<dim>::face_indices())
1965  if (neighbors[i] != patch.neighbors[i])
1966  return false;
1967 
1968  if (patch_index != patch.patch_index)
1969  return false;
1970 
1971  if (n_subdivisions != patch.n_subdivisions)
1972  return false;
1973 
1974  if (points_are_available != patch.points_are_available)
1975  return false;
1976 
1977  if (data.n_rows() != patch.data.n_rows())
1978  return false;
1979 
1980  if (data.n_cols() != patch.data.n_cols())
1981  return false;
1982 
1983  for (unsigned int i = 0; i < data.n_rows(); ++i)
1984  for (unsigned int j = 0; j < data.n_cols(); ++j)
1985  if (data[i][j] != patch.data[i][j])
1986  return false;
1987 
1988  return true;
1989  }
1990 
1991 
1992 
1993  template <int dim, int spacedim>
1994  std::size_t
1996  {
1997  return (sizeof(vertices) / sizeof(vertices[0]) *
1999  sizeof(neighbors) / sizeof(neighbors[0]) *
2002  MemoryConsumption::memory_consumption(n_subdivisions) +
2004  MemoryConsumption::memory_consumption(points_are_available));
2005  }
2006 
2007 
2008 
2009  template <int dim, int spacedim>
2010  void
2012  {
2013  std::swap(vertices, other_patch.vertices);
2014  std::swap(neighbors, other_patch.neighbors);
2015  std::swap(patch_index, other_patch.patch_index);
2016  std::swap(n_subdivisions, other_patch.n_subdivisions);
2017  data.swap(other_patch.data);
2018  std::swap(points_are_available, other_patch.points_are_available);
2019  std::swap(reference_cell, other_patch.reference_cell);
2020  }
2021 
2022 
2023 
2024  template <int spacedim>
2025  const unsigned int Patch<0, spacedim>::space_dim;
2026 
2027 
2028  template <int spacedim>
2029  const unsigned int Patch<0, spacedim>::no_neighbor;
2030 
2031 
2032  template <int spacedim>
2033  unsigned int Patch<0, spacedim>::neighbors[1] = {
2035 
2036  template <int spacedim>
2037  unsigned int Patch<0, spacedim>::n_subdivisions = 1;
2038 
2039  template <int spacedim>
2041  : patch_index(no_neighbor)
2042  , points_are_available(false)
2044  {
2045  Assert(spacedim <= 3, ExcNotImplemented());
2046  }
2047 
2048 
2049 
2050  template <int spacedim>
2051  bool
2053  {
2054  const unsigned int dim = 0;
2055 
2056  // TODO: make tolerance relative
2057  const double epsilon = 3e-16;
2058  for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
2059  if (vertices[i].distance(patch.vertices[i]) > epsilon)
2060  return false;
2061 
2062  if (patch_index != patch.patch_index)
2063  return false;
2064 
2066  return false;
2067 
2068  if (data.n_rows() != patch.data.n_rows())
2069  return false;
2070 
2071  if (data.n_cols() != patch.data.n_cols())
2072  return false;
2073 
2074  for (unsigned int i = 0; i < data.n_rows(); ++i)
2075  for (unsigned int j = 0; j < data.n_cols(); ++j)
2076  if (data[i][j] != patch.data[i][j])
2077  return false;
2078 
2079  return true;
2080  }
2081 
2082 
2083 
2084  template <int spacedim>
2085  std::size_t
2087  {
2088  return (sizeof(vertices) / sizeof(vertices[0]) *
2092  }
2093 
2094 
2095 
2096  template <int spacedim>
2098  {
2099  std::swap(vertices, other_patch.vertices);
2100  std::swap(patch_index, other_patch.patch_index);
2101  data.swap(other_patch.data);
2103  }
2104 
2105 
2106 
2107  UcdFlags::UcdFlags(const bool write_preamble)
2108  : write_preamble(write_preamble)
2109  {}
2110 
2111 
2112 
2114  {
2115  space_dimension_labels.emplace_back("x");
2116  space_dimension_labels.emplace_back("y");
2117  space_dimension_labels.emplace_back("z");
2118  }
2119 
2120 
2121 
2122  GnuplotFlags::GnuplotFlags(const std::vector<std::string> &labels)
2123  : space_dimension_labels(labels)
2124  {}
2125 
2126 
2127 
2128  std::size_t
2130  {
2132  }
2133 
2134 
2135 
2136  PovrayFlags::PovrayFlags(const bool smooth,
2137  const bool bicubic_patch,
2138  const bool external_data)
2139  : smooth(smooth)
2140  , bicubic_patch(bicubic_patch)
2141  , external_data(external_data)
2142  {}
2143 
2144 
2145  DataOutFilterFlags::DataOutFilterFlags(const bool filter_duplicate_vertices,
2146  const bool xdmf_hdf5_output)
2147  : filter_duplicate_vertices(filter_duplicate_vertices)
2148  , xdmf_hdf5_output(xdmf_hdf5_output)
2149  {}
2150 
2151 
2152  void
2154  {
2155  prm.declare_entry(
2156  "Filter duplicate vertices",
2157  "false",
2158  Patterns::Bool(),
2159  "Whether to remove duplicate vertex values. deal.II duplicates "
2160  "vertices once for each adjacent cell so that it can output "
2161  "discontinuous quantities for which there may be more than one "
2162  "value for each vertex position. Setting this flag to "
2163  "'true' will merge all of these values by selecting a "
2164  "random one and outputting this as 'the' value for the vertex. "
2165  "As long as the data to be output corresponds to continuous "
2166  "fields, merging vertices has no effect. On the other hand, "
2167  "if the data to be output corresponds to discontinuous fields "
2168  "(either because you are using a discontinuous finite element, "
2169  "or because you are using a DataPostprocessor that yields "
2170  "discontinuous data, or because the data to be output has been "
2171  "produced by entirely different means), then the data in the "
2172  "output file no longer faithfully represents the underlying data "
2173  "because the discontinuous field has been replaced by a "
2174  "continuous one. Note also that the filtering can not occur "
2175  "on processor boundaries. Thus, a filtered discontinuous field "
2176  "looks like a continuous field inside of a subdomain, "
2177  "but like a discontinuous field at the subdomain boundary."
2178  "\n\n"
2179  "In any case, filtering results in drastically smaller output "
2180  "files (smaller by about a factor of 2^dim).");
2181  prm.declare_entry(
2182  "XDMF HDF5 output",
2183  "false",
2184  Patterns::Bool(),
2185  "Whether the data will be used in an XDMF/HDF5 combination.");
2186  }
2187 
2188 
2189 
2190  void
2192  {
2193  filter_duplicate_vertices = prm.get_bool("Filter duplicate vertices");
2194  xdmf_hdf5_output = prm.get_bool("XDMF HDF5 output");
2195  }
2196 
2197 
2198 
2199  DXFlags::DXFlags(const bool write_neighbors,
2200  const bool int_binary,
2201  const bool coordinates_binary,
2202  const bool data_binary)
2203  : write_neighbors(write_neighbors)
2204  , int_binary(int_binary)
2205  , coordinates_binary(coordinates_binary)
2206  , data_binary(data_binary)
2207  , data_double(false)
2208  {}
2209 
2210 
2211  void
2213  {
2214  prm.declare_entry("Write neighbors",
2215  "true",
2216  Patterns::Bool(),
2217  "A boolean field indicating whether neighborship "
2218  "information between cells is to be written to the "
2219  "OpenDX output file");
2220  prm.declare_entry("Integer format",
2221  "ascii",
2222  Patterns::Selection("ascii|32|64"),
2223  "Output format of integer numbers, which is "
2224  "either a text representation (ascii) or binary integer "
2225  "values of 32 or 64 bits length");
2226  prm.declare_entry("Coordinates format",
2227  "ascii",
2228  Patterns::Selection("ascii|32|64"),
2229  "Output format of vertex coordinates, which is "
2230  "either a text representation (ascii) or binary "
2231  "floating point values of 32 or 64 bits length");
2232  prm.declare_entry("Data format",
2233  "ascii",
2234  Patterns::Selection("ascii|32|64"),
2235  "Output format of data values, which is "
2236  "either a text representation (ascii) or binary "
2237  "floating point values of 32 or 64 bits length");
2238  }
2239 
2240 
2241 
2242  void
2244  {
2245  write_neighbors = prm.get_bool("Write neighbors");
2246  // TODO:[GK] Read the new parameters
2247  }
2248 
2249 
2250 
2251  void
2253  {
2254  prm.declare_entry("Write preamble",
2255  "true",
2256  Patterns::Bool(),
2257  "A flag indicating whether a comment should be "
2258  "written to the beginning of the output file "
2259  "indicating date and time of creation as well "
2260  "as the creating program");
2261  }
2262 
2263 
2264 
2265  void
2267  {
2268  write_preamble = prm.get_bool("Write preamble");
2269  }
2270 
2271 
2272 
2273  SvgFlags::SvgFlags(const unsigned int height_vector,
2274  const int azimuth_angle,
2275  const int polar_angle,
2276  const unsigned int line_thickness,
2277  const bool margin,
2278  const bool draw_colorbar)
2279  : height(4000)
2280  , width(0)
2281  , height_vector(height_vector)
2282  , azimuth_angle(azimuth_angle)
2283  , polar_angle(polar_angle)
2284  , line_thickness(line_thickness)
2285  , margin(margin)
2286  , draw_colorbar(draw_colorbar)
2287  {}
2288 
2289 
2290 
2291  void
2293  {
2294  prm.declare_entry("Use smooth triangles",
2295  "false",
2296  Patterns::Bool(),
2297  "A flag indicating whether POVRAY should use smoothed "
2298  "triangles instead of the usual ones");
2299  prm.declare_entry("Use bicubic patches",
2300  "false",
2301  Patterns::Bool(),
2302  "Whether POVRAY should use bicubic patches");
2303  prm.declare_entry("Include external file",
2304  "true",
2305  Patterns::Bool(),
2306  "Whether camera and lighting information should "
2307  "be put into an external file \"data.inc\" or into "
2308  "the POVRAY input file");
2309  }
2310 
2311 
2312 
2313  void
2315  {
2316  smooth = prm.get_bool("Use smooth triangles");
2317  bicubic_patch = prm.get_bool("Use bicubic patches");
2318  external_data = prm.get_bool("Include external file");
2319  }
2320 
2321 
2322 
2323  EpsFlags::EpsFlags(const unsigned int height_vector,
2324  const unsigned int color_vector,
2325  const SizeType size_type,
2326  const unsigned int size,
2327  const double line_width,
2328  const double azimut_angle,
2329  const double turn_angle,
2330  const double z_scaling,
2331  const bool draw_mesh,
2332  const bool draw_cells,
2333  const bool shade_cells,
2334  const ColorFunction color_function)
2335  : height_vector(height_vector)
2336  , color_vector(color_vector)
2337  , size_type(size_type)
2338  , size(size)
2339  , line_width(line_width)
2340  , azimut_angle(azimut_angle)
2341  , turn_angle(turn_angle)
2342  , z_scaling(z_scaling)
2343  , draw_mesh(draw_mesh)
2344  , draw_cells(draw_cells)
2345  , shade_cells(shade_cells)
2346  , color_function(color_function)
2347  {}
2348 
2349 
2350 
2353  const double xmin,
2354  const double xmax)
2355  {
2356  RgbValues rgb_values = {0, 0, 0};
2357 
2358  // A difficult color scale:
2359  // xmin = black (1)
2360  // 3/4*xmin+1/4*xmax = blue (2)
2361  // 1/2*xmin+1/2*xmax = green (3)
2362  // 1/4*xmin+3/4*xmax = red (4)
2363  // xmax = white (5)
2364  // Makes the following color functions:
2365  //
2366  // red green blue
2367  // __
2368  // / /\ / /\ /
2369  // ____/ __/ \/ / \__/
2370 
2371  // { 0 (1) - (3)
2372  // r = { ( 4*x-2*xmin+2*xmax)/(xmax-xmin) (3) - (4)
2373  // { 1 (4) - (5)
2374  //
2375  // { 0 (1) - (2)
2376  // g = { ( 4*x-3*xmin- xmax)/(xmax-xmin) (2) - (3)
2377  // { (-4*x+ xmin+3*xmax)/(xmax-xmin) (3) - (4)
2378  // { ( 4*x- xmin-3*xmax)/(xmax-xmin) (4) - (5)
2379  //
2380  // { ( 4*x-4*xmin )/(xmax-xmin) (1) - (2)
2381  // b = { (-4*x+2*xmin+2*xmax)/(xmax-xmin) (2) - (3)
2382  // { 0 (3) - (4)
2383  // { ( 4*x- xmin-3*xmax)/(xmax-xmin) (4) - (5)
2384 
2385  double sum = xmax + xmin;
2386  double sum13 = xmin + 3 * xmax;
2387  double sum22 = 2 * xmin + 2 * xmax;
2388  double sum31 = 3 * xmin + xmax;
2389  double dif = xmax - xmin;
2390  double rezdif = 1.0 / dif;
2391 
2392  int where;
2393 
2394  if (x < (sum31) / 4)
2395  where = 0;
2396  else if (x < (sum22) / 4)
2397  where = 1;
2398  else if (x < (sum13) / 4)
2399  where = 2;
2400  else
2401  where = 3;
2402 
2403  if (dif != 0)
2404  {
2405  switch (where)
2406  {
2407  case 0:
2408  rgb_values.red = 0;
2409  rgb_values.green = 0;
2410  rgb_values.blue = (x - xmin) * 4. * rezdif;
2411  break;
2412  case 1:
2413  rgb_values.red = 0;
2414  rgb_values.green = (4 * x - 3 * xmin - xmax) * rezdif;
2415  rgb_values.blue = (sum22 - 4. * x) * rezdif;
2416  break;
2417  case 2:
2418  rgb_values.red = (4 * x - 2 * sum) * rezdif;
2419  rgb_values.green = (xmin + 3 * xmax - 4 * x) * rezdif;
2420  rgb_values.blue = 0;
2421  break;
2422  case 3:
2423  rgb_values.red = 1;
2424  rgb_values.green = (4 * x - xmin - 3 * xmax) * rezdif;
2425  rgb_values.blue = (4. * x - sum13) * rezdif;
2426  break;
2427  default:
2428  break;
2429  }
2430  }
2431  else // White
2432  rgb_values.red = rgb_values.green = rgb_values.blue = 1;
2433 
2434  return rgb_values;
2435  }
2436 
2437 
2438 
2441  const double xmin,
2442  const double xmax)
2443  {
2444  EpsFlags::RgbValues rgb_values;
2445  rgb_values.red = rgb_values.blue = rgb_values.green =
2446  (x - xmin) / (xmax - xmin);
2447  return rgb_values;
2448  }
2449 
2450 
2451 
2454  const double xmin,
2455  const double xmax)
2456  {
2457  EpsFlags::RgbValues rgb_values;
2458  rgb_values.red = rgb_values.blue = rgb_values.green =
2459  1 - (x - xmin) / (xmax - xmin);
2460  return rgb_values;
2461  }
2462 
2463 
2464 
2465  void
2467  {
2468  prm.declare_entry("Index of vector for height",
2469  "0",
2471  "Number of the input vector that is to be used to "
2472  "generate height information");
2473  prm.declare_entry("Index of vector for color",
2474  "0",
2476  "Number of the input vector that is to be used to "
2477  "generate color information");
2478  prm.declare_entry("Scale to width or height",
2479  "width",
2480  Patterns::Selection("width|height"),
2481  "Whether width or height should be scaled to match "
2482  "the given size");
2483  prm.declare_entry("Size (width or height) in eps units",
2484  "300",
2486  "The size (width or height) to which the eps output "
2487  "file is to be scaled");
2488  prm.declare_entry("Line widths in eps units",
2489  "0.5",
2490  Patterns::Double(),
2491  "The width in which the postscript renderer is to "
2492  "plot lines");
2493  prm.declare_entry("Azimut angle",
2494  "60",
2495  Patterns::Double(0, 180),
2496  "Angle of the viewing position against the vertical "
2497  "axis");
2498  prm.declare_entry("Turn angle",
2499  "30",
2500  Patterns::Double(0, 360),
2501  "Angle of the viewing direction against the y-axis");
2502  prm.declare_entry("Scaling for z-axis",
2503  "1",
2504  Patterns::Double(),
2505  "Scaling for the z-direction relative to the scaling "
2506  "used in x- and y-directions");
2507  prm.declare_entry("Draw mesh lines",
2508  "true",
2509  Patterns::Bool(),
2510  "Whether the mesh lines, or only the surface should be "
2511  "drawn");
2512  prm.declare_entry("Fill interior of cells",
2513  "true",
2514  Patterns::Bool(),
2515  "Whether only the mesh lines, or also the interior of "
2516  "cells should be plotted. If this flag is false, then "
2517  "one can see through the mesh");
2518  prm.declare_entry("Color shading of interior of cells",
2519  "true",
2520  Patterns::Bool(),
2521  "Whether the interior of cells shall be shaded");
2522  prm.declare_entry("Color function",
2523  "default",
2525  "default|grey scale|reverse grey scale"),
2526  "Name of a color function used to colorize mesh lines "
2527  "and/or cell interiors");
2528  }
2529 
2530 
2531 
2532  void
2534  {
2535  height_vector = prm.get_integer("Index of vector for height");
2536  color_vector = prm.get_integer("Index of vector for color");
2537  if (prm.get("Scale to width or height") == "width")
2538  size_type = width;
2539  else
2540  size_type = height;
2541  size = prm.get_integer("Size (width or height) in eps units");
2542  line_width = prm.get_double("Line widths in eps units");
2543  azimut_angle = prm.get_double("Azimut angle");
2544  turn_angle = prm.get_double("Turn angle");
2545  z_scaling = prm.get_double("Scaling for z-axis");
2546  draw_mesh = prm.get_bool("Draw mesh lines");
2547  draw_cells = prm.get_bool("Fill interior of cells");
2548  shade_cells = prm.get_bool("Color shading of interior of cells");
2549  if (prm.get("Color function") == "default")
2551  else if (prm.get("Color function") == "grey scale")
2553  else if (prm.get("Color function") == "reverse grey scale")
2555  else
2556  // we shouldn't get here, since the parameter object should already have
2557  // checked that the given value is valid
2558  Assert(false, ExcInternalError());
2559  }
2560 
2561 
2562 
2563  TecplotFlags::TecplotFlags(const char *zone_name, const double solution_time)
2564  : zone_name(zone_name)
2565  , solution_time(solution_time)
2566  {}
2567 
2568 
2569 
2570  std::size_t
2572  {
2573  return sizeof(*this) + MemoryConsumption::memory_consumption(zone_name);
2574  }
2575 
2577 
2578  VtkFlags::VtkFlags(const double time,
2579  const unsigned int cycle,
2580  const bool print_date_and_time,
2581  const VtkFlags::ZlibCompressionLevel compression_level,
2582  const bool write_higher_order_cells)
2583  : time(time)
2584  , cycle(cycle)
2585  , print_date_and_time(print_date_and_time)
2586  , compression_level(compression_level)
2587  , write_higher_order_cells(write_higher_order_cells)
2588  {}
2589 
2591 
2592  OutputFormat
2593  parse_output_format(const std::string &format_name)
2594  {
2595  if (format_name == "none")
2596  return none;
2598  if (format_name == "dx")
2599  return dx;
2600 
2601  if (format_name == "ucd")
2602  return ucd;
2603 
2604  if (format_name == "gnuplot")
2605  return gnuplot;
2606 
2607  if (format_name == "povray")
2608  return povray;
2609 
2610  if (format_name == "eps")
2611  return eps;
2612 
2613  if (format_name == "gmv")
2614  return gmv;
2615 
2616  if (format_name == "tecplot")
2617  return tecplot;
2619  if (format_name == "tecplot_binary")
2620  return tecplot_binary;
2621 
2622  if (format_name == "vtk")
2623  return vtk;
2624 
2625  if (format_name == "vtu")
2626  return vtu;
2627 
2628  if (format_name == "deal.II intermediate")
2629  return deal_II_intermediate;
2630 
2631  if (format_name == "hdf5")
2632  return hdf5;
2633 
2634  AssertThrow(false,
2635  ExcMessage("The given file format name is not recognized: <" +
2636  format_name + ">"));
2637 
2638  // return something invalid
2639  return OutputFormat(-1);
2640  }
2641 
2642 
2643 
2644  std::string
2646  {
2647  return "none|dx|ucd|gnuplot|povray|eps|gmv|tecplot|tecplot_binary|vtk|vtu|hdf5|svg|deal.II intermediate";
2648  }
2650 
2651 
2652  std::string
2653  default_suffix(const OutputFormat output_format)
2654  {
2655  switch (output_format)
2656  {
2657  case none:
2658  return "";
2659  case dx:
2660  return ".dx";
2661  case ucd:
2662  return ".inp";
2663  case gnuplot:
2664  return ".gnuplot";
2665  case povray:
2666  return ".pov";
2667  case eps:
2668  return ".eps";
2669  case gmv:
2670  return ".gmv";
2671  case tecplot:
2672  return ".dat";
2673  case tecplot_binary:
2674  return ".plt";
2675  case vtk:
2676  return ".vtk";
2677  case vtu:
2678  return ".vtu";
2679  case deal_II_intermediate:
2680  return ".d2";
2681  case hdf5:
2682  return ".h5";
2683  case svg:
2684  return ".svg";
2685  default:
2686  Assert(false, ExcNotImplemented());
2687  return "";
2688  }
2689  }
2690 
2691 
2692  //----------------------------------------------------------------------//
2693 
2694  template <int dim, int spacedim, typename StreamType>
2695  void
2696  write_nodes(const std::vector<Patch<dim, spacedim>> &patches, StreamType &out)
2697  {
2698  Assert(dim <= 3, ExcNotImplemented());
2699  unsigned int count = 0;
2700 
2701  for (const auto &patch : patches)
2702  {
2703  // special treatment of non-hypercube cells
2704  if (patch.reference_cell != ReferenceCells::get_hypercube<dim>())
2705  {
2706  for (unsigned int point_no = 0; point_no < patch.data.n_cols();
2707  ++point_no)
2708  out.write_point(count++, compute_arbitrary_node(patch, point_no));
2709  }
2710  else
2711  {
2712  const unsigned int n_subdivisions = patch.n_subdivisions;
2713  const unsigned int n = n_subdivisions + 1;
2714  // Length of loops in all dimensions. If a dimension is not used, a
2715  // loop of length one will do the job.
2716  const unsigned int n1 = (dim > 0) ? n : 1;
2717  const unsigned int n2 = (dim > 1) ? n : 1;
2718  const unsigned int n3 = (dim > 2) ? n : 1;
2719 
2720  for (unsigned int i3 = 0; i3 < n3; ++i3)
2721  for (unsigned int i2 = 0; i2 < n2; ++i2)
2722  for (unsigned int i1 = 0; i1 < n1; ++i1)
2723  out.write_point(
2724  count++,
2725  compute_hypercube_node(patch, i1, i2, i3, n_subdivisions));
2726  }
2727  }
2728  out.flush_points();
2729  }
2730 
2731  template <int dim, int spacedim, typename StreamType>
2732  void
2733  write_cells(const std::vector<Patch<dim, spacedim>> &patches, StreamType &out)
2734  {
2735  Assert(dim <= 3, ExcNotImplemented());
2736  unsigned int count = 0;
2737  unsigned int first_vertex_of_patch = 0;
2738  for (const auto &patch : patches)
2739  {
2740  // special treatment of simplices since they are not subdivided
2741  if (patch.reference_cell != ReferenceCells::get_hypercube<dim>())
2742  {
2743  out.write_cell_single(count++,
2744  first_vertex_of_patch,
2745  patch.data.n_cols());
2746  first_vertex_of_patch += patch.data.n_cols();
2747  }
2748  else
2749  {
2750  const unsigned int n_subdivisions = patch.n_subdivisions;
2751  const unsigned int n = n_subdivisions + 1;
2752  // Length of loops in all dimensions
2753  const unsigned int n1 = (dim > 0) ? n_subdivisions : 1;
2754  const unsigned int n2 = (dim > 1) ? n_subdivisions : 1;
2755  const unsigned int n3 = (dim > 2) ? n_subdivisions : 1;
2756  // Offsets of outer loops
2757  const unsigned int d1 = 1;
2758  const unsigned int d2 = n;
2759  const unsigned int d3 = n * n;
2760  for (unsigned int i3 = 0; i3 < n3; ++i3)
2761  for (unsigned int i2 = 0; i2 < n2; ++i2)
2762  for (unsigned int i1 = 0; i1 < n1; ++i1)
2763  {
2764  const unsigned int offset =
2765  first_vertex_of_patch + i3 * d3 + i2 * d2 + i1 * d1;
2766  // First write line in x direction
2767  out.template write_cell<dim>(count++, offset, d1, d2, d3);
2768  }
2769  // finally update the number of the first vertex of this patch
2770  first_vertex_of_patch +=
2771  Utilities::fixed_power<dim>(n_subdivisions + 1);
2772  }
2773  }
2774 
2775  out.flush_cells();
2776  }
2777 
2778  template <int dim, int spacedim, typename StreamType>
2779  void
2780  write_high_order_cells(const std::vector<Patch<dim, spacedim>> &patches,
2781  StreamType & out)
2782  {
2783  Assert(dim <= 3 && dim > 1, ExcNotImplemented());
2784  unsigned int first_vertex_of_patch = 0;
2785  unsigned int count = 0;
2786  // Array to hold all the node numbers of a cell
2787  std::vector<unsigned> connectivity;
2788  // Array to hold cell order in each dimension
2789  std::array<unsigned, dim> cell_order;
2790 
2791  for (const auto &patch : patches)
2792  {
2793  if (patch.reference_cell != ReferenceCells::get_hypercube<dim>())
2794  {
2795  connectivity.resize(patch.data.n_cols());
2796 
2797  for (unsigned int i = 0; i < patch.data.n_cols(); ++i)
2798  connectivity[i] = i;
2799 
2800  out.template write_high_order_cell<dim>(count++,
2801  first_vertex_of_patch,
2802  connectivity);
2803 
2804  first_vertex_of_patch += patch.data.n_cols();
2805  }
2806  else
2807  {
2808  const unsigned int n_subdivisions = patch.n_subdivisions;
2809  const unsigned int n = n_subdivisions + 1;
2810 
2811  cell_order.fill(n_subdivisions);
2812  connectivity.resize(Utilities::fixed_power<dim>(n));
2813 
2814  // Length of loops in all dimensons
2815  const unsigned int n1 = (dim > 0) ? n_subdivisions : 0;
2816  const unsigned int n2 = (dim > 1) ? n_subdivisions : 0;
2817  const unsigned int n3 = (dim > 2) ? n_subdivisions : 0;
2818  // Offsets of outer loops
2819  const unsigned int d1 = 1;
2820  const unsigned int d2 = n;
2821  const unsigned int d3 = n * n;
2822  for (unsigned int i3 = 0; i3 <= n3; ++i3)
2823  for (unsigned int i2 = 0; i2 <= n2; ++i2)
2824  for (unsigned int i1 = 0; i1 <= n1; ++i1)
2825  {
2826  const unsigned int local_index =
2827  i3 * d3 + i2 * d2 + i1 * d1;
2828  const unsigned int connectivity_index =
2829  vtk_point_index_from_ijk(i1, i2, i3, cell_order);
2830  connectivity[connectivity_index] = local_index;
2831  }
2832 
2833  out.template write_high_order_cell<dim>(count++,
2834  first_vertex_of_patch,
2835  connectivity);
2836 
2837  // finally update the number of the first vertex of this patch
2838  first_vertex_of_patch += Utilities::fixed_power<dim>(n);
2839  }
2840  }
2841 
2842  out.flush_cells();
2843  }
2844 
2845 
2846  template <int dim, int spacedim, class StreamType>
2847  void
2848  write_data(const std::vector<Patch<dim, spacedim>> &patches,
2849  unsigned int n_data_sets,
2850  const bool double_precision,
2851  StreamType & out)
2852  {
2853  Assert(dim <= 3, ExcNotImplemented());
2854  unsigned int count = 0;
2855 
2856  for (const auto &patch : patches)
2857  {
2858  const unsigned int n_subdivisions = patch.n_subdivisions;
2859  const unsigned int n = n_subdivisions + 1;
2860  // Length of loops in all dimensions
2861  Assert((patch.data.n_rows() == n_data_sets &&
2862  !patch.points_are_available) ||
2863  (patch.data.n_rows() == n_data_sets + spacedim &&
2864  patch.points_are_available),
2866  (n_data_sets + spacedim) :
2867  n_data_sets,
2868  patch.data.n_rows()));
2869  Assert(patch.data.n_cols() == Utilities::fixed_power<dim>(n),
2870  ExcInvalidDatasetSize(patch.data.n_cols(), n));
2871 
2872  std::vector<float> floats(n_data_sets);
2873  std::vector<double> doubles(n_data_sets);
2874 
2875  // Data is already in lexicographic ordering
2876  for (unsigned int i = 0; i < Utilities::fixed_power<dim>(n);
2877  ++i, ++count)
2878  if (double_precision)
2879  {
2880  for (unsigned int data_set = 0; data_set < n_data_sets;
2881  ++data_set)
2882  doubles[data_set] = patch.data(data_set, i);
2883  out.write_dataset(count, doubles);
2884  }
2885  else
2886  {
2887  for (unsigned int data_set = 0; data_set < n_data_sets;
2888  ++data_set)
2889  floats[data_set] = patch.data(data_set, i);
2890  out.write_dataset(count, floats);
2891  }
2892  }
2893  }
2894 
2895 
2896 
2897  namespace
2898  {
2907  Point<2> svg_project_point(Point<3> point,
2908  Point<3> camera_position,
2909  Point<3> camera_direction,
2910  Point<3> camera_horizontal,
2911  float camera_focus)
2912  {
2913  Point<3> camera_vertical;
2914  camera_vertical[0] = camera_horizontal[1] * camera_direction[2] -
2915  camera_horizontal[2] * camera_direction[1];
2916  camera_vertical[1] = camera_horizontal[2] * camera_direction[0] -
2917  camera_horizontal[0] * camera_direction[2];
2918  camera_vertical[2] = camera_horizontal[0] * camera_direction[1] -
2919  camera_horizontal[1] * camera_direction[0];
2921  float phi;
2922  phi = camera_focus;
2923  phi /= (point[0] - camera_position[0]) * camera_direction[0] +
2924  (point[1] - camera_position[1]) * camera_direction[1] +
2925  (point[2] - camera_position[2]) * camera_direction[2];
2926 
2927  Point<3> projection;
2928  projection[0] =
2929  camera_position[0] + phi * (point[0] - camera_position[0]);
2930  projection[1] =
2931  camera_position[1] + phi * (point[1] - camera_position[1]);
2932  projection[2] =
2933  camera_position[2] + phi * (point[2] - camera_position[2]);
2934 
2935  Point<2> projection_decomposition;
2936  projection_decomposition[0] = (projection[0] - camera_position[0] -
2937  camera_focus * camera_direction[0]) *
2938  camera_horizontal[0];
2939  projection_decomposition[0] += (projection[1] - camera_position[1] -
2940  camera_focus * camera_direction[1]) *
2941  camera_horizontal[1];
2942  projection_decomposition[0] += (projection[2] - camera_position[2] -
2943  camera_focus * camera_direction[2]) *
2944  camera_horizontal[2];
2945 
2946  projection_decomposition[1] = (projection[0] - camera_position[0] -
2947  camera_focus * camera_direction[0]) *
2948  camera_vertical[0];
2949  projection_decomposition[1] += (projection[1] - camera_position[1] -
2950  camera_focus * camera_direction[1]) *
2951  camera_vertical[1];
2952  projection_decomposition[1] += (projection[2] - camera_position[2] -
2953  camera_focus * camera_direction[2]) *
2954  camera_vertical[2];
2955 
2956  return projection_decomposition;
2957  }
2958 
2959 
2964  Point<6> svg_get_gradient_parameters(Point<3> points[])
2965  {
2966  Point<3> v_min, v_max, v_inter;
2967 
2968  // Use the Bubblesort algorithm to sort the points with respect to the
2969  // third coordinate
2970  for (int i = 0; i < 2; ++i)
2971  {
2972  for (int j = 0; j < 2 - i; ++j)
2973  {
2974  if (points[j][2] > points[j + 1][2])
2975  {
2976  Point<3> temp = points[j];
2977  points[j] = points[j + 1];
2978  points[j + 1] = temp;
2979  }
2980  }
2981  }
2982 
2983  // save the related three-dimensional vectors v_min, v_inter, and v_max
2984  v_min = points[0];
2985  v_inter = points[1];
2986  v_max = points[2];
2987 
2988  Point<2> A[2];
2989  Point<2> b, gradient;
2990 
2991  // determine the plane offset c
2992  A[0][0] = v_max[0] - v_min[0];
2993  A[0][1] = v_inter[0] - v_min[0];
2994  A[1][0] = v_max[1] - v_min[1];
2995  A[1][1] = v_inter[1] - v_min[1];
2996 
2997  b[0] = -v_min[0];
2998  b[1] = -v_min[1];
3000  double x, sum;
3001  bool col_change = false;
3002 
3003  if (A[0][0] == 0)
3004  {
3005  col_change = true;
3006 
3007  A[0][0] = A[0][1];
3008  A[0][1] = 0;
3009 
3010  double temp = A[1][0];
3011  A[1][0] = A[1][1];
3012  A[1][1] = temp;
3013  }
3014 
3015  for (unsigned int k = 0; k < 1; k++)
3016  {
3017  for (unsigned int i = k + 1; i < 2; i++)
3018  {
3019  x = A[i][k] / A[k][k];
3020 
3021  for (unsigned int j = k + 1; j < 2; j++)
3022  A[i][j] = A[i][j] - A[k][j] * x;
3023 
3024  b[i] = b[i] - b[k] * x;
3025  }
3026  }
3027 
3028  b[1] = b[1] / A[1][1];
3029 
3030  for (int i = 0; i >= 0; i--)
3031  {
3032  sum = b[i];
3033 
3034  for (unsigned int j = i + 1; j < 2; j++)
3035  sum = sum - A[i][j] * b[j];
3036 
3037  b[i] = sum / A[i][i];
3038  }
3039 
3040  if (col_change)
3041  {
3042  double temp = b[0];
3043  b[0] = b[1];
3044  b[1] = temp;
3045  }
3046 
3047  double c = b[0] * (v_max[2] - v_min[2]) + b[1] * (v_inter[2] - v_min[2]) +
3048  v_min[2];
3049 
3050  // Determine the first entry of the gradient (phi, cf. documentation)
3051  A[0][0] = v_max[0] - v_min[0];
3052  A[0][1] = v_inter[0] - v_min[0];
3053  A[1][0] = v_max[1] - v_min[1];
3054  A[1][1] = v_inter[1] - v_min[1];
3055 
3056  b[0] = 1.0 - v_min[0];
3057  b[1] = -v_min[1];
3058 
3059  col_change = false;
3060 
3061  if (A[0][0] == 0)
3062  {
3063  col_change = true;
3064 
3065  A[0][0] = A[0][1];
3066  A[0][1] = 0;
3067 
3068  double temp = A[1][0];
3069  A[1][0] = A[1][1];
3070  A[1][1] = temp;
3071  }
3072 
3073  for (unsigned int k = 0; k < 1; k++)
3074  {
3075  for (unsigned int i = k + 1; i < 2; i++)
3076  {
3077  x = A[i][k] / A[k][k];
3078 
3079  for (unsigned int j = k + 1; j < 2; j++)
3080  A[i][j] = A[i][j] - A[k][j] * x;
3081 
3082  b[i] = b[i] - b[k] * x;
3083  }
3084  }
3085 
3086  b[1] = b[1] / A[1][1];
3087 
3088  for (int i = 0; i >= 0; i--)
3089  {
3090  sum = b[i];
3091 
3092  for (unsigned int j = i + 1; j < 2; j++)
3093  sum = sum - A[i][j] * b[j];
3094 
3095  b[i] = sum / A[i][i];
3096  }
3097 
3098  if (col_change)
3099  {
3100  double temp = b[0];
3101  b[0] = b[1];
3102  b[1] = temp;
3103  }
3104 
3105  gradient[0] = b[0] * (v_max[2] - v_min[2]) +
3106  b[1] * (v_inter[2] - v_min[2]) - c + v_min[2];
3107 
3108  // determine the second entry of the gradient
3109  A[0][0] = v_max[0] - v_min[0];
3110  A[0][1] = v_inter[0] - v_min[0];
3111  A[1][0] = v_max[1] - v_min[1];
3112  A[1][1] = v_inter[1] - v_min[1];
3113 
3114  b[0] = -v_min[0];
3115  b[1] = 1.0 - v_min[1];
3116 
3117  col_change = false;
3118 
3119  if (A[0][0] == 0)
3120  {
3121  col_change = true;
3122 
3123  A[0][0] = A[0][1];
3124  A[0][1] = 0;
3125 
3126  double temp = A[1][0];
3127  A[1][0] = A[1][1];
3128  A[1][1] = temp;
3129  }
3130 
3131  for (unsigned int k = 0; k < 1; k++)
3132  {
3133  for (unsigned int i = k + 1; i < 2; i++)
3134  {
3135  x = A[i][k] / A[k][k];
3136 
3137  for (unsigned int j = k + 1; j < 2; j++)
3138  A[i][j] = A[i][j] - A[k][j] * x;
3139 
3140  b[i] = b[i] - b[k] * x;
3141  }
3142  }
3143 
3144  b[1] = b[1] / A[1][1];
3145 
3146  for (int i = 0; i >= 0; i--)
3147  {
3148  sum = b[i];
3149 
3150  for (unsigned int j = i + 1; j < 2; j++)
3151  sum = sum - A[i][j] * b[j];
3152 
3153  b[i] = sum / A[i][i];
3154  }
3155 
3156  if (col_change)
3157  {
3158  double temp = b[0];
3159  b[0] = b[1];
3160  b[1] = temp;
3161  }
3162 
3163  gradient[1] = b[0] * (v_max[2] - v_min[2]) +
3164  b[1] * (v_inter[2] - v_min[2]) - c + v_min[2];
3165 
3166  // normalize the gradient
3167  double gradient_norm =
3168  std::sqrt(std::pow(gradient[0], 2.0) + std::pow(gradient[1], 2.0));
3169  gradient[0] /= gradient_norm;
3170  gradient[1] /= gradient_norm;
3171 
3172  double lambda = -gradient[0] * (v_min[0] - v_max[0]) -
3173  gradient[1] * (v_min[1] - v_max[1]);
3174 
3175  Point<6> gradient_parameters;
3176 
3177  gradient_parameters[0] = v_min[0];
3178  gradient_parameters[1] = v_min[1];
3179 
3180  gradient_parameters[2] = v_min[0] + lambda * gradient[0];
3181  gradient_parameters[3] = v_min[1] + lambda * gradient[1];
3182 
3183  gradient_parameters[4] = v_min[2];
3184  gradient_parameters[5] = v_max[2];
3185 
3186  return gradient_parameters;
3187  }
3188  } // namespace
3189 
3190 
3191 
3192  template <int dim, int spacedim>
3193  void
3195  const std::vector<Patch<dim, spacedim>> &patches,
3196  const std::vector<std::string> & data_names,
3197  const std::vector<
3198  std::tuple<unsigned int,
3199  unsigned int,
3200  std::string,
3202  const UcdFlags &flags,
3203  std::ostream & out)
3204  {
3205  // Note that while in theory dim==0 should be implemented, this is not
3206  // tested, therefore currently not allowed.
3207  AssertThrow(dim > 0, ExcNotImplemented());
3208 
3209  AssertThrow(out, ExcIO());
3210 
3211 #ifndef DEAL_II_WITH_MPI
3212  // verify that there are indeed patches to be written out. most of the
3213  // times, people just forget to call build_patches when there are no
3214  // patches, so a warning is in order. that said, the assertion is disabled
3215  // if we support MPI since then it can happen that on the coarsest mesh, a
3216  // processor simply has no cells it actually owns, and in that case it is
3217  // legit if there are no patches
3218  Assert(patches.size() > 0, ExcNoPatches());
3219 #else
3220  if (patches.size() == 0)
3221  return;
3222 #endif
3223 
3224  const unsigned int n_data_sets = data_names.size();
3225 
3226  UcdStream ucd_out(out, flags);
3227 
3228  // first count the number of cells and cells for later use
3229  unsigned int n_nodes;
3230  unsigned int n_cells;
3231  compute_sizes<dim, spacedim>(patches, n_nodes, n_cells);
3233  // preamble
3234  if (flags.write_preamble)
3235  {
3236  out
3237  << "# This file was generated by the deal.II library." << '\n'
3238  << "# Date = " << Utilities::System::get_date() << "\n"
3239  << "# Time = " << Utilities::System::get_time() << "\n"
3240  << "#" << '\n'
3241  << "# For a description of the UCD format see the AVS Developer's guide."
3242  << '\n'
3243  << "#" << '\n';
3244  }
3245 
3246  // start with ucd data
3247  out << n_nodes << ' ' << n_cells << ' ' << n_data_sets << ' ' << 0
3248  << ' ' // no cell data at present
3249  << 0 // no model data
3250  << '\n';
3251 
3252  write_nodes(patches, ucd_out);
3253  out << '\n';
3254 
3255  write_cells(patches, ucd_out);
3256  out << '\n';
3257 
3259  // now write data
3260  if (n_data_sets != 0)
3261  {
3262  out << n_data_sets << " "; // number of vectors
3263  for (unsigned int i = 0; i < n_data_sets; ++i)
3264  out << 1 << ' '; // number of components;
3265  // only 1 supported presently
3266  out << '\n';
3267 
3268  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
3269  out << data_names[data_set]
3270  << ",dimensionless" // no units supported at present
3271  << '\n';
3272 
3273  write_data(patches, n_data_sets, true, ucd_out);
3274  }
3275  // make sure everything now gets to disk
3276  out.flush();
3277 
3278  // assert the stream is still ok
3279  AssertThrow(out, ExcIO());
3280  }
3281 
3282 
3283  template <int dim, int spacedim>
3284  void
3286  const std::vector<Patch<dim, spacedim>> &patches,
3287  const std::vector<std::string> & data_names,
3288  const std::vector<
3289  std::tuple<unsigned int,
3290  unsigned int,
3291  std::string,
3293  const DXFlags &flags,
3294  std::ostream & out)
3295  {
3296  // Point output is currently not implemented.
3297  AssertThrow(dim > 0, ExcNotImplemented());
3298 
3299  AssertThrow(out, ExcIO());
3300 
3301 #ifndef DEAL_II_WITH_MPI
3302  // verify that there are indeed patches to be written out. most of the
3303  // times, people just forget to call build_patches when there are no
3304  // patches, so a warning is in order. that said, the assertion is disabled
3305  // if we support MPI since then it can happen that on the coarsest mesh, a
3306  // processor simply has no cells it actually owns, and in that case it is
3307  // legit if there are no patches
3308  Assert(patches.size() > 0, ExcNoPatches());
3309 #else
3310  if (patches.size() == 0)
3311  return;
3312 #endif
3313  // Stream with special features for dx output
3314  DXStream dx_out(out, flags);
3315 
3316  // Variable counting the offset of binary data.
3317  unsigned int offset = 0;
3318 
3319  const unsigned int n_data_sets = data_names.size();
3320 
3321  // first count the number of cells and cells for later use
3322  unsigned int n_nodes;
3323  unsigned int n_cells;
3324  compute_sizes<dim, spacedim>(patches, n_nodes, n_cells);
3325  // start with vertices order is lexicographical, x varying fastest
3326  out << "object \"vertices\" class array type float rank 1 shape "
3327  << spacedim << " items " << n_nodes;
3328 
3329  if (flags.coordinates_binary)
3330  {
3331  out << " lsb ieee data 0" << '\n';
3332  offset += n_nodes * spacedim * sizeof(float);
3333  }
3334  else
3335  {
3336  out << " data follows" << '\n';
3337  write_nodes(patches, dx_out);
3338  }
3339 
3341  // first write the coordinates of all vertices
3342 
3344  // write cells
3345  out << "object \"cells\" class array type int rank 1 shape "
3346  << GeometryInfo<dim>::vertices_per_cell << " items " << n_cells;
3347 
3348  if (flags.int_binary)
3349  {
3350  out << " lsb binary data " << offset << '\n';
3351  offset += n_cells * sizeof(int);
3352  }
3353  else
3354  {
3355  out << " data follows" << '\n';
3356  write_cells(patches, dx_out);
3357  out << '\n';
3358  }
3359 
3360 
3361  out << "attribute \"element type\" string \"";
3362  if (dim == 1)
3363  out << "lines";
3364  if (dim == 2)
3365  out << "quads";
3366  if (dim == 3)
3367  out << "cubes";
3368  out << "\"" << '\n' << "attribute \"ref\" string \"positions\"" << '\n';
3369 
3370  // TODO:[GK] Patches must be of same size!
3372  // write neighbor information
3373  if (flags.write_neighbors)
3374  {
3375  out << "object \"neighbors\" class array type int rank 1 shape "
3376  << GeometryInfo<dim>::faces_per_cell << " items " << n_cells
3377  << " data follows";
3378 
3379  for (const auto &patch : patches)
3380  {
3381  const unsigned int n = patch.n_subdivisions;
3382  const unsigned int n1 = (dim > 0) ? n : 1;
3383  const unsigned int n2 = (dim > 1) ? n : 1;
3384  const unsigned int n3 = (dim > 2) ? n : 1;
3385  unsigned int cells_per_patch = Utilities::fixed_power<dim>(n);
3386  unsigned int dx = 1;
3387  unsigned int dy = n;
3388  unsigned int dz = n * n;
3389 
3390  const unsigned int patch_start =
3391  patch.patch_index * cells_per_patch;
3392 
3393  for (unsigned int i3 = 0; i3 < n3; ++i3)
3394  for (unsigned int i2 = 0; i2 < n2; ++i2)
3395  for (unsigned int i1 = 0; i1 < n1; ++i1)
3396  {
3397  const unsigned int nx = i1 * dx;
3398  const unsigned int ny = i2 * dy;
3399  const unsigned int nz = i3 * dz;
3400 
3401  // There are no neighbors for dim==0. Note that this case is
3402  // caught by the AssertThrow at the beginning of this
3403  // function anyway. This condition avoids compiler warnings.
3404  if (dim < 1)
3405  continue;
3406 
3407  out << '\n';
3408  // Direction -x Last cell in row of other patch
3409  if (i1 == 0)
3410  {
3411  const unsigned int nn = patch.neighbors[0];
3412  out << '\t';
3413  if (nn != patch.no_neighbor)
3414  out
3415  << (nn * cells_per_patch + ny + nz + dx * (n - 1));
3416  else
3417  out << "-1";
3418  }
3419  else
3420  {
3421  out << '\t' << patch_start + nx - dx + ny + nz;
3422  }
3423  // Direction +x First cell in row of other patch
3424  if (i1 == n - 1)
3425  {
3426  const unsigned int nn = patch.neighbors[1];
3427  out << '\t';
3428  if (nn != patch.no_neighbor)
3429  out << (nn * cells_per_patch + ny + nz);
3430  else
3431  out << "-1";
3432  }
3433  else
3434  {
3435  out << '\t' << patch_start + nx + dx + ny + nz;
3436  }
3437  if (dim < 2)
3438  continue;
3439  // Direction -y
3440  if (i2 == 0)
3441  {
3442  const unsigned int nn = patch.neighbors[2];
3443  out << '\t';
3444  if (nn != patch.no_neighbor)
3445  out
3446  << (nn * cells_per_patch + nx + nz + dy * (n - 1));
3447  else
3448  out << "-1";
3449  }
3450  else
3451  {
3452  out << '\t' << patch_start + nx + ny - dy + nz;
3453  }
3454  // Direction +y
3455  if (i2 == n - 1)
3456  {
3457  const unsigned int nn = patch.neighbors[3];
3458  out << '\t';
3459  if (nn != patch.no_neighbor)
3460  out << (nn * cells_per_patch + nx + nz);
3461  else
3462  out << "-1";
3463  }
3464  else
3465  {
3466  out << '\t' << patch_start + nx + ny + dy + nz;
3467  }
3468  if (dim < 3)
3469  continue;
3470 
3471  // Direction -z
3472  if (i3 == 0)
3473  {
3474  const unsigned int nn = patch.neighbors[4];
3475  out << '\t';
3476  if (nn != patch.no_neighbor)
3477  out
3478  << (nn * cells_per_patch + nx + ny + dz * (n - 1));
3479  else
3480  out << "-1";
3481  }
3482  else
3483  {
3484  out << '\t' << patch_start + nx + ny + nz - dz;
3485  }
3486  // Direction +z
3487  if (i3 == n - 1)
3488  {
3489  const unsigned int nn = patch.neighbors[5];
3490  out << '\t';
3491  if (nn != patch.no_neighbor)
3492  out << (nn * cells_per_patch + nx + ny);
3493  else
3494  out << "-1";
3495  }
3496  else
3497  {
3498  out << '\t' << patch_start + nx + ny + nz + dz;
3499  }
3500  }
3501  out << '\n';
3502  }
3503  }
3505  // now write data
3506  if (n_data_sets != 0)
3507  {
3508  out << "object \"data\" class array type float rank 1 shape "
3509  << n_data_sets << " items " << n_nodes;
3510 
3511  if (flags.data_binary)
3512  {
3513  out << " lsb ieee data " << offset << '\n';
3514  offset += n_data_sets * n_nodes *
3515  ((flags.data_double) ? sizeof(double) : sizeof(float));
3516  }
3517  else
3518  {
3519  out << " data follows" << '\n';
3520  write_data(patches, n_data_sets, flags.data_double, dx_out);
3521  }
3522 
3523  // loop over all patches
3524  out << "attribute \"dep\" string \"positions\"" << '\n';
3525  }
3526  else
3527  {
3528  out << "object \"data\" class constantarray type float rank 0 items "
3529  << n_nodes << " data follows" << '\n'
3530  << '0' << '\n';
3531  }
3532 
3533  // no model data
3534 
3535  out << "object \"deal data\" class field" << '\n'
3536  << "component \"positions\" value \"vertices\"" << '\n'
3537  << "component \"connections\" value \"cells\"" << '\n'
3538  << "component \"data\" value \"data\"" << '\n';
3539 
3540  if (flags.write_neighbors)
3541  out << "component \"neighbors\" value \"neighbors\"" << '\n';
3542 
3543  {
3544  out << "attribute \"created\" string \"" << Utilities::System::get_date()
3545  << ' ' << Utilities::System::get_time() << '"' << '\n';
3546  }
3547 
3548  out << "end" << '\n';
3549  // Write all binary data now
3550  if (flags.coordinates_binary)
3551  write_nodes(patches, dx_out);
3552  if (flags.int_binary)
3553  write_cells(patches, dx_out);
3554  if (flags.data_binary)
3555  write_data(patches, n_data_sets, flags.data_double, dx_out);
3556 
3557  // make sure everything now gets to disk
3558  out.flush();
3559 
3560  // assert the stream is still ok
3561  AssertThrow(out, ExcIO());
3562  }
3563 
3564 
3565 
3566  template <int dim, int spacedim>
3567  void
3569  const std::vector<Patch<dim, spacedim>> &patches,
3570  const std::vector<std::string> & data_names,
3571  const std::vector<
3572  std::tuple<unsigned int,
3573  unsigned int,
3574  std::string,
3576  const GnuplotFlags &flags,
3577  std::ostream & out)
3578  {
3579  AssertThrow(out, ExcIO());
3580 
3581 #ifndef DEAL_II_WITH_MPI
3582  // verify that there are indeed patches to be written out. most
3583  // of the times, people just forget to call build_patches when there
3584  // are no patches, so a warning is in order. that said, the
3585  // assertion is disabled if we support MPI since then it can
3586  // happen that on the coarsest mesh, a processor simply has no
3587  // cells it actually owns, and in that case it is legit if there
3588  // are no patches
3589  Assert(patches.size() > 0, ExcNoPatches());
3590 #else
3591  if (patches.size() == 0)
3592  return;
3593 #endif
3594 
3595  const unsigned int n_data_sets = data_names.size();
3596 
3597  // write preamble
3598  {
3599  out << "# This file was generated by the deal.II library." << '\n'
3600  << "# Date = " << Utilities::System::get_date() << '\n'
3601  << "# Time = " << Utilities::System::get_time() << '\n'
3602  << "#" << '\n'
3603  << "# For a description of the GNUPLOT format see the GNUPLOT manual."
3604  << '\n'
3605  << "#" << '\n'
3606  << "# ";
3607 
3608  AssertThrow(spacedim <= flags.space_dimension_labels.size(),
3609  GnuplotFlags::ExcNotEnoughSpaceDimensionLabels());
3610  for (unsigned int spacedim_n = 0; spacedim_n < spacedim; ++spacedim_n)
3611  {
3612  out << '<' << flags.space_dimension_labels.at(spacedim_n) << "> ";
3613  }
3614 
3615  for (const auto &data_name : data_names)
3616  out << '<' << data_name << "> ";
3617  out << '\n';
3618  }
3619 
3620 
3621  // loop over all patches
3622  for (const auto &patch : patches)
3623  {
3624  const unsigned int n_subdivisions = patch.n_subdivisions;
3625  const unsigned int n = n_subdivisions + 1;
3626  // Length of loops in all dimensions
3627  const unsigned int n1 = (dim > 0) ? n : 1;
3628  const unsigned int n2 = (dim > 1) ? n : 1;
3629  const unsigned int n3 = (dim > 2) ? n : 1;
3630  unsigned int d1 = 1;
3631  unsigned int d2 = n;
3632  unsigned int d3 = n * n;
3633 
3634  Assert((patch.data.n_rows() == n_data_sets &&
3635  !patch.points_are_available) ||
3636  (patch.data.n_rows() == n_data_sets + spacedim &&
3637  patch.points_are_available),
3639  (n_data_sets + spacedim) :
3640  n_data_sets,
3641  patch.data.n_rows()));
3642  Assert(patch.data.n_cols() == Utilities::fixed_power<dim>(n),
3643  ExcInvalidDatasetSize(patch.data.n_cols(), n_subdivisions + 1));
3644 
3645  Point<spacedim> this_point;
3646  if (dim < 3)
3647  {
3648  for (unsigned int i2 = 0; i2 < n2; ++i2)
3649  {
3650  for (unsigned int i1 = 0; i1 < n1; ++i1)
3651  {
3652  // compute coordinates for this patch point
3653  out << compute_hypercube_node(
3654  patch, i1, i2, 0, n_subdivisions)
3655  << ' ';
3656 
3657  for (unsigned int data_set = 0; data_set < n_data_sets;
3658  ++data_set)
3659  out << patch.data(data_set, i1 * d1 + i2 * d2) << ' ';
3660  out << '\n';
3661  }
3662  // end of row in patch
3663  if (dim > 1)
3664  out << '\n';
3665  }
3666  // end of patch
3667  if (dim == 1)
3668  out << '\n';
3669  out << '\n';
3670  }
3671  else if (dim == 3)
3672  {
3673  // for all grid points: draw lines into all positive coordinate
3674  // directions if there is another grid point there
3675  for (unsigned int i3 = 0; i3 < n3; ++i3)
3676  for (unsigned int i2 = 0; i2 < n2; ++i2)
3677  for (unsigned int i1 = 0; i1 < n1; ++i1)
3678  {
3679  // compute coordinates for this patch point
3680  this_point =
3681  compute_hypercube_node(patch, i1, i2, i3, n_subdivisions);
3682  // line into positive x-direction if possible
3683  if (i1 < n_subdivisions)
3684  {
3685  // write point here and its data
3686  out << this_point;
3687  for (unsigned int data_set = 0; data_set < n_data_sets;
3688  ++data_set)
3689  out << ' '
3690  << patch.data(data_set,
3691  i1 * d1 + i2 * d2 + i3 * d3);
3692  out << '\n';
3693 
3694  // write point there and its data
3695  out << compute_hypercube_node(
3696  patch, i1 + 1, i2, i3, n_subdivisions);
3697 
3698  for (unsigned int data_set = 0; data_set < n_data_sets;
3699  ++data_set)
3700  out << ' '
3701  << patch.data(data_set,
3702  (i1 + 1) * d1 + i2 * d2 + i3 * d3);
3703  out << '\n';
3704 
3705  // end of line
3706  out << '\n' << '\n';
3707  }
3708 
3709  // line into positive y-direction if possible
3710  if (i2 < n_subdivisions)
3711  {
3712  // write point here and its data
3713  out << this_point;
3714  for (unsigned int data_set = 0; data_set < n_data_sets;
3715  ++data_set)
3716  out << ' '
3717  << patch.data(data_set,
3718  i1 * d1 + i2 * d2 + i3 * d3);
3719  out << '\n';
3720 
3721  // write point there and its data
3722  out << compute_hypercube_node(
3723  patch, i1, i2 + 1, i3, n_subdivisions);
3724 
3725  for (unsigned int data_set = 0; data_set < n_data_sets;
3726  ++data_set)
3727  out << ' '
3728  << patch.data(data_set,
3729  i1 * d1 + (i2 + 1) * d2 + i3 * d3);
3730  out << '\n';
3731 
3732  // end of line
3733  out << '\n' << '\n';
3734  }
3735 
3736  // line into positive z-direction if possible
3737  if (i3 < n_subdivisions)
3738  {
3739  // write point here and its data
3740  out << this_point;
3741  for (unsigned int data_set = 0; data_set < n_data_sets;
3742  ++data_set)
3743  out << ' '
3744  << patch.data(data_set,
3745  i1 * d1 + i2 * d2 + i3 * d3);
3746  out << '\n';
3747 
3748  // write point there and its data
3749  out << compute_hypercube_node(
3750  patch, i1, i2, i3 + 1, n_subdivisions);
3751 
3752  for (unsigned int data_set = 0; data_set < n_data_sets;
3753  ++data_set)
3754  out << ' '
3755  << patch.data(data_set,
3756  i1 * d1 + i2 * d2 + (i3 + 1) * d3);
3757  out << '\n';
3758  // end of line
3759  out << '\n' << '\n';
3760  }
3761  }
3762  }
3763  else
3764  Assert(false, ExcNotImplemented());
3765  }
3766  // make sure everything now gets to disk
3767  out.flush();
3768 
3769  AssertThrow(out, ExcIO());
3770  }
3771 
3772 
3773 
3774  template <int dim, int spacedim>
3775  void
3777  const std::vector<Patch<dim, spacedim>> &patches,
3778  const std::vector<std::string> & data_names,
3779  const std::vector<
3780  std::tuple<unsigned int,
3781  unsigned int,
3782  std::string,
3784  const PovrayFlags &flags,
3785  std::ostream & out)
3786  {
3787  AssertThrow(out, ExcIO());
3788 
3789 #ifndef DEAL_II_WITH_MPI
3790  // verify that there are indeed patches to be written out. most
3791  // of the times, people just forget to call build_patches when there
3792  // are no patches, so a warning is in order. that said, the
3793  // assertion is disabled if we support MPI since then it can
3794  // happen that on the coarsest mesh, a processor simply has no cells it
3795  // actually owns, and in that case it is legit if there are no patches
3796  Assert(patches.size() > 0, ExcNoPatches());
3797 #else
3798  if (patches.size() == 0)
3799  return;
3800 #endif
3801  Assert(dim == 2,
3802  ExcNotImplemented()); // only for 2-D surfaces on a 2-D plane
3803  Assert(spacedim == 2, ExcNotImplemented());
3804 
3805  const unsigned int n_data_sets = data_names.size();
3806  (void)n_data_sets;
3807 
3808  // write preamble
3809  {
3810  out << "/* This file was generated by the deal.II library." << '\n'
3811  << " Date = " << Utilities::System::get_date() << '\n'
3812  << " Time = " << Utilities::System::get_time() << '\n'
3813  << '\n'
3814  << " For a description of the POVRAY format see the POVRAY manual."
3815  << '\n'
3816  << "*/ " << '\n';
3817 
3818  // include files
3819  out << "#include \"colors.inc\" " << '\n'
3820  << "#include \"textures.inc\" " << '\n';
3821 
3822 
3823  // use external include file for textures, camera and light
3824  if (flags.external_data)
3825  out << "#include \"data.inc\" " << '\n';
3826  else // all definitions in data file
3827  {
3828  // camera
3829  out << '\n'
3830  << '\n'
3831  << "camera {" << '\n'
3832  << " location <1,4,-7>" << '\n'
3833  << " look_at <0,0,0>" << '\n'
3834  << " angle 30" << '\n'
3835  << "}" << '\n';
3836 
3837  // light
3838  out << '\n'
3839  << "light_source {" << '\n'
3840  << " <1,4,-7>" << '\n'
3841  << " color Grey" << '\n'
3842  << "}" << '\n';
3843  out << '\n'
3844  << "light_source {" << '\n'
3845  << " <0,20,0>" << '\n'
3846  << " color White" << '\n'
3847  << "}" << '\n';
3848  }
3849  }
3850 
3851  // max. and min. height of solution
3852  Assert(patches.size() > 0, ExcNoPatches());
3853  double hmin = patches[0].data(0, 0);
3854  double hmax = patches[0].data(0, 0);
3855 
3856  for (const auto &patch : patches)
3857  {
3858  const unsigned int n_subdivisions = patch.n_subdivisions;
3859 
3860  Assert((patch.data.n_rows() == n_data_sets &&
3861  !patch.points_are_available) ||
3862  (patch.data.n_rows() == n_data_sets + spacedim &&
3863  patch.points_are_available),
3865  (n_data_sets + spacedim) :
3866  n_data_sets,
3867  patch.data.n_rows()));
3868  Assert(patch.data.n_cols() ==
3869  Utilities::fixed_power<dim>(n_subdivisions + 1),
3870  ExcInvalidDatasetSize(patch.data.n_cols(), n_subdivisions + 1));
3871 
3872  for (unsigned int i = 0; i < n_subdivisions + 1; ++i)
3873  for (unsigned int j = 0; j < n_subdivisions + 1; ++j)
3874  {
3875  const int dl = i * (n_subdivisions + 1) + j;
3876  if (patch.data(0, dl) < hmin)
3877  hmin = patch.data(0, dl);
3878  if (patch.data(0, dl) > hmax)
3879  hmax = patch.data(0, dl);
3880  }
3881  }
3882 
3883  out << "#declare HMIN=" << hmin << ";" << '\n'
3884  << "#declare HMAX=" << hmax << ";" << '\n'
3885  << '\n';
3886 
3887  if (!flags.external_data)
3888  {
3889  // texture with scaled niveau lines 10 lines in the surface
3890  out << "#declare Tex=texture{" << '\n'
3891  << " pigment {" << '\n'
3892  << " gradient y" << '\n'
3893  << " scale y*(HMAX-HMIN)*" << 0.1 << '\n'
3894  << " color_map {" << '\n'
3895  << " [0.00 color Light_Purple] " << '\n'
3896  << " [0.95 color Light_Purple] " << '\n'
3897  << " [1.00 color White] " << '\n'
3898  << "} } }" << '\n'
3899  << '\n';
3900  }
3901 
3902  if (!flags.bicubic_patch)
3903  {
3904  // start of mesh header
3905  out << '\n' << "mesh {" << '\n';
3906  }
3907 
3908  // loop over all patches
3909  for (const auto &patch : patches)
3910  {
3911  const unsigned int n_subdivisions = patch.n_subdivisions;
3912  const unsigned int n = n_subdivisions + 1;
3913  const unsigned int d1 = 1;
3914  const unsigned int d2 = n;
3915 
3916  Assert((patch.data.n_rows() == n_data_sets &&
3917  !patch.points_are_available) ||
3918  (patch.data.n_rows() == n_data_sets + spacedim &&
3919  patch.points_are_available),
3921  (n_data_sets + spacedim) :
3922  n_data_sets,
3923  patch.data.n_rows()));
3924  Assert(patch.data.n_cols() == Utilities::fixed_power<dim>(n),
3925  ExcInvalidDatasetSize(patch.data.n_cols(), n_subdivisions + 1));
3926 
3927 
3928  std::vector<Point<spacedim>> ver(n * n);
3929 
3930  for (unsigned int i2 = 0; i2 < n; ++i2)
3931  for (unsigned int i1 = 0; i1 < n; ++i1)
3932  {
3933  // compute coordinates for this patch point, storing in ver
3934  ver[i1 * d1 + i2 * d2] =
3935  compute_hypercube_node(patch, i1, i2, 0, n_subdivisions);
3936  }
3937 
3938 
3939  if (!flags.bicubic_patch)
3940  {
3941  // approximate normal vectors in patch
3942  std::vector<Point<3>> nrml;
3943  // only if smooth triangles are used
3944  if (flags.smooth)
3945  {
3946  nrml.resize(n * n);
3947  // These are difference quotients of the surface
3948  // mapping. We take them symmetric inside the
3949  // patch and one-sided at the edges
3950  Point<3> h1, h2;
3951  // Now compute normals in every point
3952  for (unsigned int i = 0; i < n; ++i)
3953  for (unsigned int j = 0; j < n; ++j)
3954  {
3955  const unsigned int il = (i == 0) ? i : (i - 1);
3956  const unsigned int ir =
3957  (i == n_subdivisions) ? i : (i + 1);
3958  const unsigned int jl = (j == 0) ? j : (j - 1);
3959  const unsigned int jr =
3960  (j == n_subdivisions) ? j : (j + 1);
3961 
3962  h1(0) =
3963  ver[ir * d1 + j * d2](0) - ver[il * d1 + j * d2](0);
3964  h1(1) = patch.data(0, ir * d1 + j * d2) -
3965  patch.data(0, il * d1 + j * d2);
3966  h1(2) =
3967  ver[ir * d1 + j * d2](1) - ver[il * d1 + j * d2](1);
3968 
3969  h2(0) =
3970  ver[i * d1 + jr * d2](0) - ver[i * d1 + jl * d2](0);
3971  h2(1) = patch.data(0, i * d1 + jr * d2) -
3972  patch.data(0, i * d1 + jl * d2);
3973  h2(2) =
3974  ver[i * d1 + jr * d2](1) - ver[i * d1 + jl * d2](1);
3975 
3976  nrml[i * d1 + j * d2](0) = h1(1) * h2(2) - h1(2) * h2(1);
3977  nrml[i * d1 + j * d2](1) = h1(2) * h2(0) - h1(0) * h2(2);
3978  nrml[i * d1 + j * d2](2) = h1(0) * h2(1) - h1(1) * h2(0);
3979 
3980  // normalize Vector
3981  double norm =
3982  std::sqrt(std::pow(nrml[i * d1 + j * d2](0), 2.) +
3983  std::pow(nrml[i * d1 + j * d2](1), 2.) +
3984  std::pow(nrml[i * d1 + j * d2](2), 2.));
3985 
3986  if (nrml[i * d1 + j * d2](1) < 0)
3987  norm *= -1.;
3988 
3989  for (unsigned int k = 0; k < 3; ++k)
3990  nrml[i * d1 + j * d2](k) /= norm;
3991  }
3992  }
3993 
3994  // setting up triangles
3995  for (unsigned int i = 0; i < n_subdivisions; ++i)
3996  for (unsigned int j = 0; j < n_subdivisions; ++j)
3997  {
3998  // down/left vertex of triangle
3999  const int dl = i * d1 + j * d2;
4000  if (flags.smooth)
4001  {
4002  // writing smooth_triangles
4003 
4004  // down/right triangle
4005  out << "smooth_triangle {" << '\n'
4006  << "\t<" << ver[dl](0) << "," << patch.data(0, dl)
4007  << "," << ver[dl](1) << ">, <" << nrml[dl](0) << ", "
4008  << nrml[dl](1) << ", " << nrml[dl](2) << ">," << '\n';
4009  out << " \t<" << ver[dl + d1](0) << ","
4010  << patch.data(0, dl + d1) << "," << ver[dl + d1](1)
4011  << ">, <" << nrml[dl + d1](0) << ", "
4012  << nrml[dl + d1](1) << ", " << nrml[dl + d1](2)
4013  << ">," << '\n';
4014  out << "\t<" << ver[dl + d1 + d2](0) << ","
4015  << patch.data(0, dl + d1 + d2) << ","
4016  << ver[dl + d1 + d2](1) << ">, <"
4017  << nrml[dl + d1 + d2](0) << ", "
4018  << nrml[dl + d1 + d2](1) << ", "
4019  << nrml[dl + d1 + d2](2) << ">}" << '\n';
4020 
4021  // upper/left triangle
4022  out << "smooth_triangle {" << '\n'
4023  << "\t<" << ver[dl](0) << "," << patch.data(0, dl)
4024  << "," << ver[dl](1) << ">, <" << nrml[dl](0) << ", "
4025  << nrml[dl](1) << ", " << nrml[dl](2) << ">," << '\n';
4026  out << "\t<" << ver[dl + d1 + d2](0) << ","
4027  << patch.data(0, dl + d1 + d2) << ","
4028  << ver[dl + d1 + d2](1) << ">, <"
4029  << nrml[dl + d1 + d2](0) << ", "
4030  << nrml[dl + d1 + d2](1) << ", "
4031  << nrml[dl + d1 + d2](2) << ">," << '\n';
4032  out << "\t<" << ver[dl + d2](0) << ","
4033  << patch.data(0, dl + d2) << "," << ver[dl + d2](1)
4034  << ">, <" << nrml[dl + d2](0) << ", "
4035  << nrml[dl + d2](1) << ", " << nrml[dl + d2](2)
4036  << ">}" << '\n';
4037  }
4038  else
4039  {
4040  // writing standard triangles down/right triangle
4041  out << "triangle {" << '\n'
4042  << "\t<" << ver[dl](0) << "," << patch.data(0, dl)
4043  << "," << ver[dl](1) << ">," << '\n';
4044  out << "\t<" << ver[dl + d1](0) << ","
4045  << patch.data(0, dl + d1) << "," << ver[dl + d1](1)
4046  << ">," << '\n';
4047  out << "\t<" << ver[dl + d1 + d2](0) << ","
4048  << patch.data(0, dl + d1 + d2) << ","
4049  << ver[dl + d1 + d2](1) << ">}" << '\n';
4050 
4051  // upper/left triangle
4052  out << "triangle {" << '\n'
4053  << "\t<" << ver[dl](0) << "," << patch.data(0, dl)
4054  << "," << ver[dl](1) << ">," << '\n';
4055  out << "\t<" << ver[dl + d1 + d2](0) << ","
4056  << patch.data(0, dl + d1 + d2) << ","
4057  << ver[dl + d1 + d2](1) << ">," << '\n';
4058  out << "\t<" << ver[dl + d2](0) << ","
4059  << patch.data(0, dl + d2) << "," << ver[dl + d2](1)
4060  << ">}" << '\n';
4061  }
4062  }
4063  }
4064  else
4065  {
4066  // writing bicubic_patch
4067  Assert(n_subdivisions == 3,
4068  ExcDimensionMismatch(n_subdivisions, 3));
4069  out << '\n'
4070  << "bicubic_patch {" << '\n'
4071  << " type 0" << '\n'
4072  << " flatness 0" << '\n'
4073  << " u_steps 0" << '\n'
4074  << " v_steps 0" << '\n';
4075  for (int i = 0; i < 16; ++i)
4076  {
4077  out << "\t<" << ver[i](0) << "," << patch.data(0, i) << ","
4078  << ver[i](1) << ">";
4079  if (i != 15)
4080  out << ",";
4081  out << '\n';
4082  }
4083  out << " texture {Tex}" << '\n' << "}" << '\n';
4084  }
4085  }
4086 
4087  if (!flags.bicubic_patch)
4088  {
4089  // the end of the mesh
4090  out << " texture {Tex}" << '\n' << "}" << '\n' << '\n';
4091  }
4092 
4093  // make sure everything now gets to disk
4094  out.flush();
4095 
4096  AssertThrow(out, ExcIO());
4097  }
4098 
4099 
4100 
4101  template <int dim, int spacedim>
4102  void
4104  const std::vector<Patch<dim, spacedim>> & /*patches*/,
4105  const std::vector<std::string> & /*data_names*/,
4106  const std::vector<
4107  std::tuple<unsigned int,
4108  unsigned int,
4109  std::string,
4111  const EpsFlags & /*flags*/,
4112  std::ostream & /*out*/)
4113  {
4114  // not implemented, see the documentation of the function
4115  AssertThrow(dim == 2, ExcNotImplemented());
4116  }
4117 
4118 
4119  template <int spacedim>
4120  void
4122  const std::vector<Patch<2, spacedim>> &patches,
4123  const std::vector<std::string> & /*data_names*/,
4124  const std::vector<
4125  std::tuple<unsigned int,
4126  unsigned int,
4127  std::string,
4129  const EpsFlags &flags,
4130  std::ostream & out)
4131  {
4132  AssertThrow(out, ExcIO());
4133 
4134 #ifndef DEAL_II_WITH_MPI
4135  // verify that there are indeed patches to be written out. most of the
4136  // times, people just forget to call build_patches when there are no
4137  // patches, so a warning is in order. that said, the assertion is disabled
4138  // if we support MPI since then it can happen that on the coarsest mesh, a
4139  // processor simply has no cells it actually owns, and in that case it is
4140  // legit if there are no patches
4141  Assert(patches.size() > 0, ExcNoPatches());
4142 #else
4143  if (patches.size() == 0)
4144  return;
4145 #endif
4146 
4147  // set up an array of cells to be written later. this array holds the cells
4148  // of all the patches as projected to the plane perpendicular to the line of
4149  // sight.
4150  //
4151  // note that they are kept sorted by the set, where we chose the value of
4152  // the center point of the cell along the line of sight as value for sorting
4153  std::multiset<EpsCell2d> cells;
4154 
4155  // two variables in which we will store the minimum and maximum values of
4156  // the field to be used for colorization
4157  float min_color_value = std::numeric_limits<float>::max();
4158  float max_color_value = std::numeric_limits<float>::min();
4159 
4160  // Array for z-coordinates of points. The elevation determined by a function
4161  // if spacedim=2 or the z-cooridate of the grid point if spacedim=3
4162  double heights[4] = {0, 0, 0, 0};
4163 
4164  // compute the cells for output and enter them into the set above note that
4165  // since dim==2, we have exactly four vertices per patch and per cell
4166  for (const auto &patch : patches)
4167  {
4168  const unsigned int n_subdivisions = patch.n_subdivisions;
4169  const unsigned int n = n_subdivisions + 1;
4170  const unsigned int d1 = 1;
4171  const unsigned int d2 = n;
4172 
4173  for (unsigned int i2 = 0; i2 < n_subdivisions; ++i2)
4174  for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1)
4175  {
4176  Point<spacedim> points[4];
4177  points[0] =
4178  compute_hypercube_node(patch, i1, i2, 0, n_subdivisions);
4179  points[1] =
4180  compute_hypercube_node(patch, i1 + 1, i2, 0, n_subdivisions);
4181  points[2] =
4182  compute_hypercube_node(patch, i1, i2 + 1, 0, n_subdivisions);
4183  points[3] = compute_hypercube_node(
4184  patch, i1 + 1, i2 + 1, 0, n_subdivisions);
4185 
4186  switch (spacedim)
4187  {
4188  case 2:
4189  Assert((flags.height_vector < patch.data.n_rows()) ||
4190  patch.data.n_rows() == 0,
4192  0,
4193  patch.data.n_rows()));
4194  heights[0] =
4195  patch.data.n_rows() != 0 ?
4196  patch.data(flags.height_vector, i1 * d1 + i2 * d2) *
4197  flags.z_scaling :
4198  0;
4199  heights[1] = patch.data.n_rows() != 0 ?
4200  patch.data(flags.height_vector,
4201  (i1 + 1) * d1 + i2 * d2) *
4202  flags.z_scaling :
4203  0;
4204  heights[2] = patch.data.n_rows() != 0 ?
4205  patch.data(flags.height_vector,
4206  i1 * d1 + (i2 + 1) * d2) *
4207  flags.z_scaling :
4208  0;
4209  heights[3] = patch.data.n_rows() != 0 ?
4210  patch.data(flags.height_vector,
4211  (i1 + 1) * d1 + (i2 + 1) * d2) *
4212  flags.z_scaling :
4213  0;
4214 
4215  break;
4216  case 3:
4217  // Copy z-coordinates into the height vector
4218  for (unsigned int i = 0; i < 4; ++i)
4219  heights[i] = points[i](2);
4220  break;
4221  default:
4222  Assert(false, ExcNotImplemented());
4223  }
4224 
4225 
4226  // now compute the projection of the bilinear cell given by the
4227  // four vertices and their heights and write them to a proper cell
4228  // object. note that we only need the first two components of the
4229  // projected position for output, but we need the value along the
4230  // line of sight for sorting the cells for back-to- front-output
4231  //
4232  // this computation was first written by Stefan Nauber. please
4233  // no-one ask me why it works that way (or may be not), especially
4234  // not about the angles and the sign of the height field, I don't
4235  // know it.
4236  EpsCell2d eps_cell;
4237  const double pi = numbers::PI;
4238  const double cx =
4239  -std::cos(pi - flags.azimut_angle * 2 * pi / 360.),
4240  cz = -std::cos(flags.turn_angle * 2 * pi / 360.),
4241  sx =
4242  std::sin(pi - flags.azimut_angle * 2 * pi / 360.),
4243  sz = std::sin(flags.turn_angle * 2 * pi / 360.);
4244  for (unsigned int vertex = 0; vertex < 4; ++vertex)
4245  {
4246  const double x = points[vertex](0), y = points[vertex](1),
4247  z = -heights[vertex];
4248 
4249  eps_cell.vertices[vertex](0) = -cz * x + sz * y;
4250  eps_cell.vertices[vertex](1) =
4251  -cx * sz * x - cx * cz * y - sx * z;
4252 
4253  // ( 1 0 0 )
4254  // D1 = ( 0 cx -sx )
4255  // ( 0 sx cx )
4256 
4257  // ( cy 0 sy )
4258  // Dy = ( 0 1 0 )
4259  // (-sy 0 cy )
4260 
4261  // ( cz -sz 0 )
4262  // Dz = ( sz cz 0 )
4263  // ( 0 0 1 )
4264 
4265  // ( cz -sz 0 )( 1 0 0 )(x) (
4266  // cz*x-sz*(cx*y-sx*z)+0*(sx*y+cx*z) )
4267  // Dxz = ( sz cz 0 )( 0 cx -sx )(y) = (
4268  // sz*x+cz*(cx*y-sx*z)+0*(sx*y+cx*z) )
4269  // ( 0 0 1 )( 0 sx cx )(z) ( 0*x+
4270  // *(cx*y-sx*z)+1*(sx*y+cx*z) )
4271  }
4272 
4273  // compute coordinates of center of cell
4274  const Point<spacedim> center_point =
4275  (points[0] + points[1] + points[2] + points[3]) / 4;
4276  const double center_height =
4277  -(heights[0] + heights[1] + heights[2] + heights[3]) / 4;
4278 
4279  // compute the depth into the picture
4280  eps_cell.depth = -sx * sz * center_point(0) -
4281  sx * cz * center_point(1) + cx * center_height;
4282 
4283  if (flags.draw_cells && flags.shade_cells)
4284  {
4285  Assert((flags.color_vector < patch.data.n_rows()) ||
4286  patch.data.n_rows() == 0,
4288  0,
4289  patch.data.n_rows()));
4290  const double color_values[4] = {
4291  patch.data.n_rows() != 0 ?
4292  patch.data(flags.color_vector, i1 * d1 + i2 * d2) :
4293  1,
4294 
4295  patch.data.n_rows() != 0 ?
4296  patch.data(flags.color_vector, (i1 + 1) * d1 + i2 * d2) :
4297  1,
4298 
4299  patch.data.n_rows() != 0 ?
4300  patch.data(flags.color_vector, i1 * d1 + (i2 + 1) * d2) :
4301  1,
4302 
4303  patch.data.n_rows() != 0 ?
4304  patch.data(flags.color_vector,
4305  (i1 + 1) * d1 + (i2 + 1) * d2) :
4306  1};
4307 
4308  // set color value to average of the value at the vertices
4309  eps_cell.color_value = (color_values[0] + color_values[1] +
4310  color_values[3] + color_values[2]) /
4311  4;
4312 
4313  // update bounds of color field
4314  min_color_value =
4315  std::min(min_color_value, eps_cell.color_value);
4316  max_color_value =
4317  std::max(max_color_value, eps_cell.color_value);
4318  }
4319 
4320  // finally add this cell
4321  cells.insert(eps_cell);
4322  }
4323  }
4324 
4325  // find out minimum and maximum x and y coordinates to compute offsets and
4326  // scaling factors
4327  double x_min = cells.begin()->vertices[0](0);
4328  double x_max = x_min;
4329  double y_min = cells.begin()->vertices[0](1);
4330  double y_max = y_min;
4331 
4332  for (const auto &cell : cells)
4333  for (const auto &vertex : cell.vertices)
4334  {
4335  x_min = std::min(x_min, vertex(0));
4336  x_max = std::max(x_max, vertex(0));
4337  y_min = std::min(y_min, vertex(1));
4338  y_max = std::max(y_max, vertex(1));
4339  }
4340 
4341  // scale in x-direction such that in the output 0 <= x <= 300. don't scale
4342  // in y-direction to preserve the shape of the triangulation
4343  const double scale =
4344  (flags.size /
4345  (flags.size_type == EpsFlags::width ? x_max - x_min : y_min - y_max));
4346 
4347  const Point<2> offset(x_min, y_min);
4348 
4349 
4350  // now write preamble
4351  {
4352  out << "%!PS-Adobe-2.0 EPSF-1.2" << '\n'
4353  << "%%Title: deal.II Output" << '\n'
4354  << "%%Creator: the deal.II library" << '\n'
4355  << "%%Creation Date: " << Utilities::System::get_date() << " - "
4356  << Utilities::System::get_time() << '\n'
4357  << "%%BoundingBox: "
4358  // lower left corner
4359  << "0 0 "
4360  // upper right corner
4361  << static_cast<unsigned int>((x_max - x_min) * scale + 0.5) << ' '
4362  << static_cast<unsigned int>((y_max - y_min) * scale + 0.5) << '\n';
4363 
4364  // define some abbreviations to keep the output small:
4365  // m=move turtle to
4366  // l=define a line
4367  // s=set rgb color
4368  // sg=set gray value
4369  // lx=close the line and plot the line
4370  // lf=close the line and fill the interior
4371  out << "/m {moveto} bind def" << '\n'
4372  << "/l {lineto} bind def" << '\n'
4373  << "/s {setrgbcolor} bind def" << '\n'
4374  << "/sg {setgray} bind def" << '\n'
4375  << "/lx {lineto closepath stroke} bind def" << '\n'
4376  << "/lf {lineto closepath fill} bind def" << '\n';
4377 
4378  out << "%%EndProlog" << '\n' << '\n';
4379  // set fine lines
4380  out << flags.line_width << " setlinewidth" << '\n';
4381  }
4382 
4383  // check if min and max values for the color are actually different. If
4384  // that is not the case (such things happen, for example, in the very first
4385  // time step of a time dependent problem, if the initial values are zero),
4386  // all values are equal, and then we can draw everything in an arbitrary
4387  // color. Thus, change one of the two values arbitrarily
4388  if (max_color_value == min_color_value)
4389  max_color_value = min_color_value + 1;
4390 
4391  // now we've got all the information we need. write the cells. note: due to
4392  // the ordering, we traverse the list of cells back-to-front
4393  for (const auto &cell : cells)
4394  {
4395  if (flags.draw_cells)
4396  {
4397  if (flags.shade_cells)
4398  {
4399  const EpsFlags::RgbValues rgb_values =
4400  (*flags.color_function)(cell.color_value,
4401  min_color_value,
4402  max_color_value);
4403 
4404  // write out color
4405  if (rgb_values.is_grey())
4406  out << rgb_values.red << " sg ";
4407  else
4408  out << rgb_values.red << ' ' << rgb_values.green << ' '
4409  << rgb_values.blue << " s ";
4410  }
4411  else
4412  out << "1 sg ";
4413 
4414  out << (cell.vertices[0] - offset) * scale << " m "
4415  << (cell.vertices[1] - offset) * scale << " l "
4416  << (cell.vertices[3] - offset) * scale << " l "
4417  << (cell.vertices[2] - offset) * scale << " lf" << '\n';
4418  }
4419 
4420  if (flags.draw_mesh)
4421  out << "0 sg " // draw lines in black
4422  << (cell.vertices[0] - offset) * scale << " m "
4423  << (cell.vertices[1] - offset) * scale << " l "
4424  << (cell.vertices[3] - offset) * scale << " l "
4425  << (cell.vertices[2] - offset) * scale << " lx" << '\n';
4426  }
4427  out << "showpage" << '\n';
4428 
4429  out.flush();
4430 
4431  AssertThrow(out, ExcIO());
4432  }
4433 
4434 
4435 
4436  template <int dim, int spacedim>
4437  void
4439  const std::vector<Patch<dim, spacedim>> &patches,
4440  const std::vector<std::string> & data_names,
4441  const std::vector<
4442  std::tuple<unsigned int,
4443  unsigned int,
4444  std::string,
4446  const GmvFlags &flags,
4447  std::ostream & out)
4448  {
4449  // The gmv format does not support cells that only consist of a single
4450  // point. It does support the output of point data using the keyword
4451  // 'tracers' instead of 'nodes' and 'cells', but this output format is
4452  // currently not implemented.
4453  AssertThrow(dim > 0, ExcNotImplemented());
4454 
4455  Assert(dim <= 3, ExcNotImplemented());
4456  AssertThrow(out, ExcIO());
4457 
4458 #ifndef DEAL_II_WITH_MPI
4459  // verify that there are indeed patches to be written out. most of the
4460  // times, people just forget to call build_patches when there are no
4461  // patches, so a warning is in order. that said, the assertion is disabled
4462  // if we support MPI since then it can happen that on the coarsest mesh, a
4463  // processor simply has no cells it actually owns, and in that case it is
4464  // legit if there are no patches
4465  Assert(patches.size() > 0, ExcNoPatches());
4466 #else
4467  if (patches.size() == 0)
4468  return;
4469 #endif
4470 
4471  GmvStream gmv_out(out, flags);
4472  const unsigned int n_data_sets = data_names.size();
4473  // check against # of data sets in first patch. checks against all other
4474  // patches are made in write_gmv_reorder_data_vectors
4475  Assert((patches[0].data.n_rows() == n_data_sets &&
4476  !patches[0].points_are_available) ||
4477  (patches[0].data.n_rows() == n_data_sets + spacedim &&
4478  patches[0].points_are_available),
4479  ExcDimensionMismatch(patches[0].points_are_available ?
4480  (n_data_sets + spacedim) :
4481  n_data_sets,
4482  patches[0].data.n_rows()));
4483 
4485  // preamble
4486  out << "gmvinput ascii" << '\n' << '\n';
4487 
4488  // first count the number of cells and cells for later use
4489  unsigned int n_nodes;
4490  unsigned int n_cells;
4491  compute_sizes<dim, spacedim>(patches, n_nodes, n_cells);
4492 
4493  // in gmv format the vertex coordinates and the data have an order that is a
4494  // bit unpleasant (first all x coordinates, then all y coordinate, ...;
4495  // first all data of variable 1, then variable 2, etc), so we have to copy
4496  // the data vectors a bit around
4497  //
4498  // note that we copy vectors when looping over the patches since we have to
4499  // write them one variable at a time and don't want to use more than one
4500  // loop
4501  //
4502  // this copying of data vectors can be done while we already output the
4503  // vertices, so do this on a separate task and when wanting to write out the
4504  // data, we wait for that task to finish
4505  Table<2, double> data_vectors(n_data_sets, n_nodes);
4506  void (*fun_ptr)(const std::vector<Patch<dim, spacedim>> &,
4507  Table<2, double> &) =
4508  &write_gmv_reorder_data_vectors<dim, spacedim>;
4509  Threads::Task<> reorder_task =
4510  Threads::new_task(fun_ptr, patches, data_vectors);
4511 
4513  // first make up a list of used vertices along with their coordinates
4514  //
4515  // note that we have to print 3 dimensions
4516  out << "nodes " << n_nodes << '\n';
4517  for (unsigned int d = 0; d < spacedim; ++d)
4518  {
4519  gmv_out.selected_component = d;
4520  write_nodes(patches, gmv_out);
4521  out << '\n';
4522  }
4523  gmv_out.selected_component = numbers::invalid_unsigned_int;
4524 
4525  for (unsigned int d = spacedim; d < 3; ++d)
4526  {
4527  for (unsigned int i = 0; i < n_nodes; ++i)
4528  out << "0 ";
4529  out << '\n';
4530  }
4531 
4533  // now for the cells. note that vertices are counted from 1 onwards
4534  out << "cells " << n_cells << '\n';
4535  write_cells(patches, gmv_out);
4536 
4538  // data output.
4539  out << "variable" << '\n';
4540 
4541  // now write the data vectors to @p{out} first make sure that all data is in
4542  // place
4543  reorder_task.join();
4544 
4545  // then write data. the '1' means: node data (as opposed to cell data, which
4546  // we do not support explicitly here)
4547  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
4548  {
4549  out << data_names[data_set] << " 1" << '\n';
4550  std::copy(data_vectors[data_set].begin(),
4551  data_vectors[data_set].end(),
4552  std::ostream_iterator<double>(out, " "));
4553  out << '\n' << '\n';
4554  }
4555 
4556 
4557 
4558  // end of variable section
4559  out << "endvars" << '\n';
4560 
4561  // end of output
4562  out << "endgmv" << '\n';
4563 
4564  // make sure everything now gets to disk
4565  out.flush();
4566 
4567  // assert the stream is still ok
4568  AssertThrow(out, ExcIO());
4569  }
4570 
4571 
4572 
4573  template <int dim, int spacedim>
4574  void
4576  const std::vector<Patch<dim, spacedim>> &patches,
4577  const std::vector<std::string> & data_names,
4578  const std::vector<
4579  std::tuple<unsigned int,
4580  unsigned int,
4581  std::string,
4583  const TecplotFlags &flags,
4584  std::ostream & out)
4585  {
4586  AssertThrow(out, ExcIO());
4587 
4588  // The FEBLOCK or FEPOINT formats of tecplot only allows full elements (e.g.
4589  // triangles), not single points. Other tecplot format allow point output,
4590  // but they are currently not implemented.
4591  AssertThrow(dim > 0, ExcNotImplemented());
4592 
4593 #ifndef DEAL_II_WITH_MPI
4594  // verify that there are indeed patches to be written out. most of the
4595  // times, people just forget to call build_patches when there are no
4596  // patches, so a warning is in order. that said, the assertion is disabled
4597  // if we support MPI since then it can happen that on the coarsest mesh, a
4598  // processor simply has no cells it actually owns, and in that case it is
4599  // legit if there are no patches
4600  Assert(patches.size() > 0, ExcNoPatches());
4601 #else
4602  if (patches.size() == 0)
4603  return;
4604 #endif
4605 
4606  TecplotStream tecplot_out(out, flags);
4607 
4608  const unsigned int n_data_sets = data_names.size();
4609  // check against # of data sets in first patch. checks against all other
4610  // patches are made in write_gmv_reorder_data_vectors
4611  Assert((patches[0].data.n_rows() == n_data_sets &&
4612  !patches[0].points_are_available) ||
4613  (patches[0].data.n_rows() == n_data_sets + spacedim &&
4614  patches[0].points_are_available),
4615  ExcDimensionMismatch(patches[0].points_are_available ?
4616  (n_data_sets + spacedim) :
4617  n_data_sets,
4618  patches[0].data.n_rows()));
4619 
4620  // first count the number of cells and cells for later use
4621  unsigned int n_nodes;
4622  unsigned int n_cells;
4623  compute_sizes<dim, spacedim>(patches, n_nodes, n_cells);
4624 
4626  // preamble
4627  {
4628  out
4629  << "# This file was generated by the deal.II library." << '\n'
4630  << "# Date = " << Utilities::System::get_date() << '\n'
4631  << "# Time = " << Utilities::System::get_time() << '\n'
4632  << "#" << '\n'
4633  << "# For a description of the Tecplot format see the Tecplot documentation."
4634  << '\n'
4635  << "#" << '\n';
4636 
4637 
4638  out << "Variables=";
4639 
4640  switch (spacedim)
4641  {
4642  case 1:
4643  out << "\"x\"";
4644  break;
4645  case 2:
4646  out << "\"x\", \"y\"";
4647  break;
4648  case 3:
4649  out << "\"x\", \"y\", \"z\"";
4650  break;
4651  default:
4652  Assert(false, ExcNotImplemented());
4653  }
4654 
4655  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
4656  out << ", \"" << data_names[data_set] << "\"";
4657 
4658  out << '\n';
4659 
4660  out << "zone ";
4661  if (flags.zone_name)
4662  out << "t=\"" << flags.zone_name << "\" ";
4663 
4664  if (flags.solution_time >= 0.0)
4665  out << "strandid=1, solutiontime=" << flags.solution_time << ", ";
4666 
4667  out << "f=feblock, n=" << n_nodes << ", e=" << n_cells
4668  << ", et=" << tecplot_cell_type[dim] << '\n';
4669  }
4670 
4671 
4672  // in Tecplot FEBLOCK format the vertex coordinates and the data have an
4673  // order that is a bit unpleasant (first all x coordinates, then all y
4674  // coordinate, ...; first all data of variable 1, then variable 2, etc), so
4675  // we have to copy the data vectors a bit around
4676  //
4677  // note that we copy vectors when looping over the patches since we have to
4678  // write them one variable at a time and don't want to use more than one
4679  // loop
4680  //
4681  // this copying of data vectors can be done while we already output the
4682  // vertices, so do this on a separate task and when wanting to write out the
4683  // data, we wait for that task to finish
4684 
4685  Table<2, double> data_vectors(n_data_sets, n_nodes);
4686 
4687  void (*fun_ptr)(const std::vector<Patch<dim, spacedim>> &,
4688  Table<2, double> &) =
4689  &write_gmv_reorder_data_vectors<dim, spacedim>;
4690  Threads::Task<> reorder_task =
4691  Threads::new_task(fun_ptr, patches, data_vectors);
4692 
4694  // first make up a list of used vertices along with their coordinates
4695 
4696 
4697  for (unsigned int d = 0; d < spacedim; ++d)
4698  {
4699  tecplot_out.selected_component = d;
4700  write_nodes(patches, tecplot_out);
4701  out << '\n';
4702  }
4703 
4704 
4706  // data output.
4707  //
4708  // now write the data vectors to @p{out} first make sure that all data is in
4709  // place
4710  reorder_task.join();
4711 
4712  // then write data.
4713  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
4714  {
4715  std::copy(data_vectors[data_set].begin(),
4716  data_vectors[data_set].end(),
4717  std::ostream_iterator<double>(out, "\n"));
4718  out << '\n';
4719  }
4720 
4721  write_cells(patches, tecplot_out);
4722 
4723  // make sure everything now gets to disk
4724  out.flush();
4725 
4726  // assert the stream is still ok
4727  AssertThrow(out, ExcIO());
4728  }
4729 
4730 
4731 
4732  //---------------------------------------------------------------------------
4733  // Macros for handling Tecplot API data
4734 
4735 #ifdef DEAL_II_HAVE_TECPLOT
4736 
4737  namespace
4738  {
4739  class TecplotMacros
4740  {
4741  public:
4742  TecplotMacros(const unsigned int n_nodes = 0,
4743  const unsigned int n_vars = 0,
4744  const unsigned int n_cells = 0,
4745  const unsigned int n_vert = 0);
4746  ~TecplotMacros();
4747  float &
4748  nd(const unsigned int i, const unsigned int j);
4749  int &
4750  cd(const unsigned int i, const unsigned int j);
4751  std::vector<float> nodalData;
4752  std::vector<int> connData;
4753 
4754  private:
4755  unsigned int n_nodes;
4756  unsigned int n_vars;
4757  unsigned int n_cells;
4758  unsigned int n_vert;
4759  };
4760 
4761 
4762  inline TecplotMacros::TecplotMacros(const unsigned int n_nodes,
4763  const unsigned int n_vars,
4764  const unsigned int n_cells,
4765  const unsigned int n_vert)
4766  : n_nodes(n_nodes)
4767  , n_vars(n_vars)
4768  , n_cells(n_cells)
4769  , n_vert(n_vert)
4770  {
4771  nodalData.resize(n_nodes * n_vars);
4772  connData.resize(n_cells * n_vert);
4773  }
4774 
4775 
4776 
4777  inline TecplotMacros::~TecplotMacros()
4778  {}
4779 
4780 
4781 
4782  inline float &
4783  TecplotMacros::nd(const unsigned int i, const unsigned int j)
4784  {
4785  return nodalData[i * n_nodes + j];
4786  }
4787 
4788 
4789 
4790  inline int &
4791  TecplotMacros::cd(const unsigned int i, const unsigned int j)
4792  {
4793  return connData[i + j * n_vert];
4794  }
4795 
4796  } // namespace
4797 
4798 
4799 #endif
4800  //---------------------------------------------------------------------------
4801 
4802 
4803 
4804  template <int dim, int spacedim>
4805  void
4807  const std::vector<Patch<dim, spacedim>> &patches,
4808  const std::vector<std::string> & data_names,
4809  const std::vector<
4810  std::tuple<unsigned int,
4811  unsigned int,
4812  std::string,
4814  & nonscalar_data_ranges,
4815  const TecplotFlags &flags,
4816  std::ostream & out)
4817  {
4818  // The FEBLOCK or FEPOINT formats of tecplot only allows full elements (e.g.
4819  // triangles), not single points. Other tecplot format allow point output,
4820  // but they are currently not implemented.
4821  AssertThrow(dim > 0, ExcNotImplemented());
4822 
4823 #ifndef DEAL_II_HAVE_TECPLOT
4824 
4825  // simply call the ASCII output function if the Tecplot API isn't present
4826  write_tecplot(patches, data_names, nonscalar_data_ranges, flags, out);
4827  return;
4828 
4829 #else
4830 
4831  // Tecplot binary output only good for 2D & 3D
4832  if (dim == 1)
4833  {
4834  write_tecplot(patches, data_names, nonscalar_data_ranges, flags, out);
4835  return;
4836  }
4837 
4838  // if the user hasn't specified a file name we should call the ASCII
4839  // function and use the ostream @p{out} instead of doing something silly
4840  // later
4841  char *file_name = (char *)flags.tecplot_binary_file_name;
4842 
4843  if (file_name == nullptr)
4844  {
4845  // At least in debug mode we should tell users why they don't get
4846  // tecplot binary output
4847  Assert(false,
4848  ExcMessage("Specify the name of the tecplot_binary"
4849  " file through the TecplotFlags interface."));
4850  write_tecplot(patches, data_names, nonscalar_data_ranges, flags, out);
4851  return;
4852  }
4853 
4854 
4855  AssertThrow(out, ExcIO());
4856 
4857 # ifndef DEAL_II_WITH_MPI
4858  // verify that there are indeed patches to be written out. most of the
4859  // times, people just forget to call build_patches when there are no
4860  // patches, so a warning is in order. that said, the assertion is disabled
4861  // if we support MPI since then it can happen that on the coarsest mesh, a
4862  // processor simply has no cells it actually owns, and in that case it is
4863  // legit if there are no patches
4864  Assert(patches.size() > 0, ExcNoPatches());
4865 # else
4866  if (patches.size() == 0)
4867  return;
4868 # endif
4869 
4870  const unsigned int n_data_sets = data_names.size();
4871  // check against # of data sets in first patch. checks against all other
4872  // patches are made in write_gmv_reorder_data_vectors
4873  Assert((patches[0].data.n_rows() == n_data_sets &&
4874  !patches[0].points_are_available) ||
4875  (patches[0].data.n_rows() == n_data_sets + spacedim &&
4876  patches[0].points_are_available),
4877  ExcDimensionMismatch(patches[0].points_are_available ?
4878  (n_data_sets + spacedim) :
4879  n_data_sets,
4880  patches[0].data.n_rows()));
4881 
4882  // first count the number of cells and cells for later use
4883  unsigned int n_nodes;
4884  unsigned int n_cells;
4885  compute_sizes<dim, spacedim>(patches, n_nodes, n_cells);
4886  // local variables only needed to write Tecplot binary output files
4887  const unsigned int vars_per_node = (spacedim + n_data_sets),
4888  nodes_per_cell = GeometryInfo<dim>::vertices_per_cell;
4889 
4890  TecplotMacros tm(n_nodes, vars_per_node, n_cells, nodes_per_cell);
4891 
4892  int is_double = 0, tec_debug = 0, cell_type = tecplot_binary_cell_type[dim];
4893 
4894  std::string tec_var_names;
4895  switch (spacedim)
4896  {
4897  case 2:
4898  tec_var_names = "x y";
4899  break;
4900  case 3:
4901  tec_var_names = "x y z";
4902  break;
4903  default:
4904  Assert(false, ExcNotImplemented());
4905  }
4906 
4907  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
4908  {
4909  tec_var_names += " ";
4910  tec_var_names += data_names[data_set];
4911  }
4912  // in Tecplot FEBLOCK format the vertex coordinates and the data have an
4913  // order that is a bit unpleasant (first all x coordinates, then all y
4914  // coordinate, ...; first all data of variable 1, then variable 2, etc), so
4915  // we have to copy the data vectors a bit around
4916  //
4917  // note that we copy vectors when looping over the patches since we have to
4918  // write them one variable at a time and don't want to use more than one
4919  // loop
4920  //
4921  // this copying of data vectors can be done while we already output the
4922  // vertices, so do this on a separate task and when wanting to write out the
4923  // data, we wait for that task to finish
4924  Table<2, double> data_vectors(n_data_sets, n_nodes);
4925 
4926  void (*fun_ptr)(const std::vector<Patch<dim, spacedim>> &,
4927  Table<2, double> &) =
4928  &write_gmv_reorder_data_vectors<dim, spacedim>;
4929  Threads::Task<> reorder_task =
4930  Threads::new_task(fun_ptr, patches, data_vectors);
4931 
4933  // first make up a list of used vertices along with their coordinates
4934  for (unsigned int d = 1; d <= spacedim; ++d)
4935  {
4936  unsigned int entry = 0;
4937 
4938  for (const auto &patch : patches)
4939  {
4940  const unsigned int n_subdivisions = patch.n_subdivisions;
4941 
4942  switch (dim)
4943  {
4944  case 2:
4945  {
4946  for (unsigned int j = 0; j < n_subdivisions + 1; ++j)
4947  for (unsigned int i = 0; i < n_subdivisions + 1; ++i)
4948  {
4949  const double x_frac = i * 1. / n_subdivisions,
4950  y_frac = j * 1. / n_subdivisions;
4951 
4952  tm.nd((d - 1), entry) = static_cast<float>(
4953  (((patch.vertices[1](d - 1) * x_frac) +
4954  (patch.vertices[0](d - 1) * (1 - x_frac))) *
4955  (1 - y_frac) +
4956  ((patch.vertices[3](d - 1) * x_frac) +
4957  (patch.vertices[2](d - 1) * (1 - x_frac))) *
4958  y_frac));
4959  entry++;
4960  }
4961  break;
4962  }
4963 
4964  case 3:
4965  {
4966  for (unsigned int j = 0; j < n_subdivisions + 1; ++j)
4967  for (unsigned int k = 0; k < n_subdivisions + 1; ++k)
4968  for (unsigned int i = 0; i < n_subdivisions + 1; ++i)
4969  {
4970  const double x_frac = i * 1. / n_subdivisions,
4971  y_frac = k * 1. / n_subdivisions,
4972  z_frac = j * 1. / n_subdivisions;
4973 
4974  // compute coordinates for this patch point
4975  tm.nd((d - 1), entry) = static_cast<float>(
4976  ((((patch.vertices[1](d - 1) * x_frac) +
4977  (patch.vertices[0](d - 1) * (1 - x_frac))) *
4978  (1 - y_frac) +
4979  ((patch.vertices[3](d - 1) * x_frac) +
4980  (patch.vertices[2](d - 1) * (1 - x_frac))) *
4981  y_frac) *
4982  (1 - z_frac) +
4983  (((patch.vertices[5](d - 1) * x_frac) +
4984  (patch.vertices[4](d - 1) * (1 - x_frac))) *
4985  (1 - y_frac) +
4986  ((patch.vertices[7](d - 1) * x_frac) +
4987  (patch.vertices[6](d - 1) * (1 - x_frac))) *
4988  y_frac) *
4989  z_frac));
4990  entry++;
4991  }
4992  break;
4993  }
4994 
4995  default:
4996  Assert(false, ExcNotImplemented());
4997  }
4998  }
4999  }
5000 
5001 
5003  // data output.
5004  //
5005  reorder_task.join();
5006 
5007  // then write data.
5008  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
5009  for (unsigned int entry = 0; entry < data_vectors[data_set].size();
5010  entry++)
5011  tm.nd((spacedim + data_set), entry) =
5012  static_cast<float>(data_vectors[data_set][entry]);
5013 
5014 
5015 
5017  // now for the cells. note that vertices are counted from 1 onwards
5018  unsigned int first_vertex_of_patch = 0;
5019  unsigned int elem = 0;
5020 
5021  for (const auto &patch : patches)
5022  {
5023  const unsigned int n_subdivisions = patch.n_subdivisions;
5024  const unsigned int n = n_subdivisions + 1;
5025  const unsigned int d1 = 1;
5026  const unsigned int d2 = n;
5027  const unsigned int d3 = n * n;
5028  // write out the cells making up this patch
5029  switch (dim)
5030  {
5031  case 2:
5032  {
5033  for (unsigned int i2 = 0; i2 < n_subdivisions; ++i2)
5034  for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1)
5035  {
5036  tm.cd(0, elem) =
5037  first_vertex_of_patch + (i1)*d1 + (i2)*d2 + 1;
5038  tm.cd(1, elem) =
5039  first_vertex_of_patch + (i1 + 1) * d1 + (i2)*d2 + 1;
5040  tm.cd(2, elem) = first_vertex_of_patch + (i1 + 1) * d1 +
5041  (i2 + 1) * d2 + 1;
5042  tm.cd(3, elem) =
5043  first_vertex_of_patch + (i1)*d1 + (i2 + 1) * d2 + 1;
5044 
5045  elem++;
5046  }
5047  break;
5048  }
5049 
5050  case 3:
5051  {
5052  for (unsigned int i3 = 0; i3 < n_subdivisions; ++i3)
5053  for (unsigned int i2 = 0; i2 < n_subdivisions; ++i2)
5054  for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1)
5055  {
5056  // note: vertex indices start with 1!
5057 
5058 
5059  tm.cd(0, elem) = first_vertex_of_patch + (i1)*d1 +
5060  (i2)*d2 + (i3)*d3 + 1;
5061  tm.cd(1, elem) = first_vertex_of_patch + (i1 + 1) * d1 +
5062  (i2)*d2 + (i3)*d3 + 1;
5063  tm.cd(2, elem) = first_vertex_of_patch + (i1 + 1) * d1 +
5064  (i2 + 1) * d2 + (i3)*d3 + 1;
5065  tm.cd(3, elem) = first_vertex_of_patch + (i1)*d1 +
5066  (i2 + 1) * d2 + (i3)*d3 + 1;
5067  tm.cd(4, elem) = first_vertex_of_patch + (i1)*d1 +
5068  (i2)*d2 + (i3 + 1) * d3 + 1;
5069  tm.cd(5, elem) = first_vertex_of_patch + (i1 + 1) * d1 +
5070  (i2)*d2 + (i3 + 1) * d3 + 1;
5071  tm.cd(6, elem) = first_vertex_of_patch + (i1 + 1) * d1 +
5072  (i2 + 1) * d2 + (i3 + 1) * d3 + 1;
5073  tm.cd(7, elem) = first_vertex_of_patch + (i1)*d1 +
5074  (i2 + 1) * d2 + (i3 + 1) * d3 + 1;
5075 
5076  elem++;
5077  }
5078  break;
5079  }
5080 
5081  default:
5082  Assert(false, ExcNotImplemented());
5083  }
5084 
5085 
5086  // finally update the number of the first vertex of this patch
5087  first_vertex_of_patch += Utilities::fixed_power<dim>(n);
5088  }
5089 
5090 
5091  {
5092  int ierr = 0, num_nodes = static_cast<int>(n_nodes),
5093  num_cells = static_cast<int>(n_cells);
5094 
5095  char dot[2] = {'.', 0};
5096  // Unfortunately, TECINI takes a char *, but c_str() gives a const char *.
5097  // As we don't do anything else with tec_var_names following const_cast is
5098  // ok
5099  char *var_names = const_cast<char *>(tec_var_names.c_str());
5100  ierr = TECINI(nullptr, var_names, file_name, dot, &tec_debug, &is_double);
5101 
5102  Assert(ierr == 0, ExcErrorOpeningTecplotFile(file_name));
5103 
5104  char FEBLOCK[] = {'F', 'E', 'B', 'L', 'O', 'C', 'K', 0};
5105  ierr =
5106  TECZNE(nullptr, &num_nodes, &num_cells, &cell_type, FEBLOCK, nullptr);
5107 
5108  Assert(ierr == 0, ExcTecplotAPIError());
5109 
5110  int total = (vars_per_node * num_nodes);
5111 
5112  ierr = TECDAT(&total, tm.nodalData.data(), &is_double);
5113 
5114  Assert(ierr == 0, ExcTecplotAPIError());
5115 
5116  ierr = TECNOD(tm.connData.data());
5117 
5118  Assert(ierr == 0, ExcTecplotAPIError());
5119 
5120  ierr = TECEND();
5121 
5122  Assert(ierr == 0, ExcTecplotAPIError());
5123  }
5124 #endif
5125  }
5126 
5127 
5128 
5129  template <int dim, int spacedim>
5130  void
5132  const std::vector<Patch<dim, spacedim>> &patches,
5133  const std::vector<std::string> & data_names,
5134  const std::vector<
5135  std::tuple<unsigned int,
5136  unsigned int,
5137  std::string,
5139  & nonscalar_data_ranges,
5140  const VtkFlags &flags,
5141  std::ostream & out)
5142  {
5143  AssertThrow(out, ExcIO());
5144 
5145 #ifndef DEAL_II_WITH_MPI
5146  // verify that there are indeed patches to be written out. most of the
5147  // times, people just forget to call build_patches when there are no
5148  // patches, so a warning is in order. that said, the assertion is disabled
5149  // if we support MPI since then it can happen that on the coarsest mesh, a
5150  // processor simply has no cells it actually owns, and in that case it is
5151  // legit if there are no patches
5152  Assert(patches.size() > 0, ExcNoPatches());
5153 #else
5154  if (patches.size() == 0)
5155  return;
5156 #endif
5157 
5158  VtkStream vtk_out(out, flags);
5159 
5160  const unsigned int n_data_sets = data_names.size();
5161  // check against # of data sets in first patch.
5162  if (patches[0].points_are_available)
5163  {
5164  AssertDimension(n_data_sets + spacedim, patches[0].data.n_rows())
5165  }
5166  else
5167  {
5168  AssertDimension(n_data_sets, patches[0].data.n_rows())
5169  }
5170 
5172  // preamble
5173  {
5174  out << "# vtk DataFile Version 3.0" << '\n'
5175  << "#This file was generated by the deal.II library";
5176  if (flags.print_date_and_time)
5177  {
5178  out << " on " << Utilities::System::get_date() << " at "
5180  }
5181  else
5182  out << ".";
5183  out << '\n' << "ASCII" << '\n';
5184  // now output the data header
5185  out << "DATASET UNSTRUCTURED_GRID\n" << '\n';
5186  }
5187 
5188  // if desired, output time and cycle of the simulation, following the
5189  // instructions at
5190  // http://www.visitusers.org/index.php?title=Time_and_Cycle_in_VTK_files
5191  {
5192  const unsigned int n_metadata =
5193  ((flags.cycle != std::numeric_limits<unsigned int>::min() ? 1 : 0) +
5194  (flags.time != std::numeric_limits<double>::min() ? 1 : 0));
5195  if (n_metadata > 0)
5196  {
5197  out << "FIELD FieldData " << n_metadata << "\n";
5198 
5200  {
5201  out << "CYCLE 1 1 int\n" << flags.cycle << "\n";
5202  }
5203  if (flags.time != std::numeric_limits<double>::min())
5204  {
5205  out << "TIME 1 1 double\n" << flags.time << "\n";
5206  }
5207  }
5208  }
5209 
5210  // first count the number of cells and cells for later use
5211  unsigned int n_nodes, n_cells, n_points_and_n_cells;
5212  compute_sizes(patches,
5214  n_nodes,
5215  n_cells,
5216  n_points_and_n_cells);
5217 
5218  // in gmv format the vertex coordinates and the data have an order that is a
5219  // bit unpleasant (first all x coordinates, then all y coordinate, ...;
5220  // first all data of variable 1, then variable 2, etc), so we have to copy
5221  // the data vectors a bit around
5222  //
5223  // note that we copy vectors when looping over the patches since we have to
5224  // write them one variable at a time and don't want to use more than one
5225  // loop
5226  //
5227  // this copying of data vectors can be done while we already output the
5228  // vertices, so do this on a separate task and when wanting to write out the
5229  // data, we wait for that task to finish
5230  Table<2, double> data_vectors(n_data_sets, n_nodes);
5231 
5232  void (*fun_ptr)(const std::vector<Patch<dim, spacedim>> &,
5233  Table<2, double> &) =
5234  &write_gmv_reorder_data_vectors<dim, spacedim>;
5235  Threads::Task<> reorder_task =
5236  Threads::new_task(fun_ptr, patches, data_vectors);
5237 
5239  // first make up a list of used vertices along with their coordinates
5240  //
5241  // note that we have to print d=1..3 dimensions
5242  out << "POINTS " << n_nodes << " double" << '\n';
5243  write_nodes(patches, vtk_out);
5244  out << '\n';
5246  // now for the cells
5247  out << "CELLS " << n_cells << ' ' << n_points_and_n_cells << '\n';
5248  if (flags.write_higher_order_cells)
5249  write_high_order_cells(patches, vtk_out);
5250  else
5251  write_cells(patches, vtk_out);
5252  out << '\n';
5253  // next output the types of the cells. since all cells are the same, this is
5254  // simple
5255  out << "CELL_TYPES " << n_cells << '\n';
5256 
5257  // need to distinguish between linear cells, simplex cells (linear or
5258  // quadratic), and high order cells
5259  for (const auto &patch : patches)
5260  {
5261  const auto vtk_cell_id =
5262  extract_vtk_patch_info(patch, flags.write_higher_order_cells);
5263 
5264  for (unsigned int i = 0; i < vtk_cell_id[1]; ++i)
5265  out << ' ' << vtk_cell_id[0];
5266  }
5267 
5268  out << '\n';
5270  // data output.
5271 
5272  // now write the data vectors to @p{out} first make sure that all data is in
5273  // place
5274  reorder_task.join();
5275 
5276  // then write data. the 'POINT_DATA' means: node data (as opposed to cell
5277  // data, which we do not support explicitly here). all following data sets
5278  // are point data
5279  out << "POINT_DATA " << n_nodes << '\n';
5280 
5281  // when writing, first write out all vector data, then handle the scalar
5282  // data sets that have been left over
5283  std::vector<bool> data_set_written(n_data_sets, false);
5284  for (const auto &nonscalar_data_range : nonscalar_data_ranges)
5285  {
5286  AssertThrow(std::get<3>(nonscalar_data_range) !=
5288  ExcNotImplemented());
5289 
5290  AssertThrow(std::get<1>(nonscalar_data_range) >=
5291  std::get<0>(nonscalar_data_range),
5292  ExcLowerRange(std::get<1>(nonscalar_data_range),
5293  std::get<0>(nonscalar_data_range)));
5294  AssertThrow(std::get<1>(nonscalar_data_range) < n_data_sets,
5295  ExcIndexRange(std::get<1>(nonscalar_data_range),
5296  0,
5297  n_data_sets));
5298  AssertThrow(std::get<1>(nonscalar_data_range) + 1 -
5299  std::get<0>(nonscalar_data_range) <=
5300  3,
5301  ExcMessage(
5302  "Can't declare a vector with more than 3 components "
5303  "in VTK"));
5304 
5305  // mark these components as already written:
5306  for (unsigned int i = std::get<0>(nonscalar_data_range);
5307  i <= std::get<1>(nonscalar_data_range);
5308  ++i)
5309  data_set_written[i] = true;
5310 
5311  // write the header. concatenate all the component names with double
5312  // underscores unless a vector name has been specified
5313  out << "VECTORS ";
5314 
5315  if (!std::get<2>(nonscalar_data_range).empty())
5316  out << std::get<2>(nonscalar_data_range);
5317  else
5318  {
5319  for (unsigned int i = std::get<0>(nonscalar_data_range);
5320  i < std::get<1>(nonscalar_data_range);
5321  ++i)
5322  out << data_names[i] << "__";
5323  out << data_names[std::get<1>(nonscalar_data_range)];
5324  }
5325 
5326  out << " double" << '\n';
5327 
5328  // now write data. pad all vectors to have three components
5329  for (unsigned int n = 0; n < n_nodes; ++n)
5330  {
5331  switch (std::get<1>(nonscalar_data_range) -
5332  std::get<0>(nonscalar_data_range))
5333  {
5334  case 0:
5335  out << data_vectors(std::get<0>(nonscalar_data_range), n)
5336  << " 0 0" << '\n';
5337  break;
5338 
5339  case 1:
5340  out << data_vectors(std::get<0>(nonscalar_data_range), n)
5341  << ' '
5342  << data_vectors(std::get<0>(nonscalar_data_range) + 1, n)
5343  << " 0" << '\n';
5344  break;
5345  case 2:
5346  out << data_vectors(std::get<0>(nonscalar_data_range), n)
5347  << ' '
5348  << data_vectors(std::get<0>(nonscalar_data_range) + 1, n)
5349  << ' '
5350  << data_vectors(std::get<0>(nonscalar_data_range) + 2, n)
5351  << '\n';
5352  break;
5353 
5354  default:
5355  // VTK doesn't support anything else than vectors with 1, 2,
5356  // or 3 components
5357  Assert(false, ExcInternalError());
5358  }
5359  }
5360  }
5361 
5362  // now do the left over scalar data sets
5363  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
5364  if (data_set_written[data_set] == false)
5365  {
5366  out << "SCALARS " << data_names[data_set] << " double 1" << '\n'
5367  << "LOOKUP_TABLE default" << '\n';
5368  std::copy(data_vectors[data_set].begin(),
5369  data_vectors[data_set].end(),
5370  std::ostream_iterator<double>(out, " "));
5371  out << '\n';
5372  }
5373 
5374  // make sure everything now gets to disk
5375  out.flush();
5376 
5377  // assert the stream is still ok
5378  AssertThrow(out, ExcIO());
5379  }
5380 
5381 
5382  void
5383  write_vtu_header(std::ostream &out, const VtkFlags &flags)
5384  {
5385  AssertThrow(out, ExcIO());
5386  out << "<?xml version=\"1.0\" ?> \n";
5387  out << "<!-- \n";
5388  out << "# vtk DataFile Version 3.0" << '\n'
5389  << "#This file was generated by the deal.II library";
5390  if (flags.print_date_and_time)
5391  {
5392  out << " on " << Utilities::System::get_time() << " at "
5394  }
5395  else
5396  out << ".";
5397  out << "\n-->\n";
5398  out << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\"";
5399 #ifdef DEAL_II_WITH_ZLIB
5400  out << " compressor=\"vtkZLibDataCompressor\"";
5401 #endif
5402 #ifdef DEAL_II_WORDS_BIGENDIAN
5403  out << " byte_order=\"BigEndian\"";
5404 #else
5405  out << " byte_order=\"LittleEndian\"";
5406 #endif
5407  out << ">";
5408  out << '\n';
5409  out << "<UnstructuredGrid>";
5410  out << '\n';
5411  }
5412 
5413 
5414 
5415  void
5416  write_vtu_footer(std::ostream &out)
5417  {
5418  AssertThrow(out, ExcIO());
5419  out << " </UnstructuredGrid>\n";
5420  out << "</VTKFile>\n";
5421  }
5422 
5423 
5424 
5425  template <int dim, int spacedim>
5426  void
5428  const std::vector<Patch<dim, spacedim>> &patches,
5429  const std::vector<std::string> & data_names,
5430  const std::vector<
5431  std::tuple<unsigned int,
5432  unsigned int,
5433  std::string,
5435  & nonscalar_data_ranges,
5436  const VtkFlags &flags,
5437  std::ostream & out)
5438  {
5439  write_vtu_header(out, flags);
5440  write_vtu_main(patches, data_names, nonscalar_data_ranges, flags, out);
5441  write_vtu_footer(out);
5442 
5443  out << std::flush;
5444  }
5445 
5446 
5447  template <int dim, int spacedim>
5448  void
5450  const std::vector<Patch<dim, spacedim>> &patches,
5451  const std::vector<std::string> & data_names,
5452  const std::vector<
5453  std::tuple<unsigned int,
5454  unsigned int,
5455  std::string,
5457  & nonscalar_data_ranges,
5458  const VtkFlags &flags,
5459  std::ostream & out)
5460  {
5461  AssertThrow(out, ExcIO());
5462 
5463 #ifndef DEAL_II_WITH_MPI
5464  // verify that there are indeed patches to be written out. most of the
5465  // times, people just forget to call build_patches when there are no
5466  // patches, so a warning is in order. that said, the assertion is disabled
5467  // if we support MPI since then it can happen that on the coarsest mesh, a
5468  // processor simply has no cells it actually owns, and in that case it is
5469  // legit if there are no patches
5470  Assert(patches.size() > 0, ExcNoPatches());
5471 #else
5472  if (patches.size() == 0)
5473  {
5474  // we still need to output a valid vtu file, because other CPUs might
5475  // output data. This is the minimal file that is accepted by paraview
5476  // and visit. if we remove the field definitions, visit is complaining.
5477  out << "<Piece NumberOfPoints=\"0\" NumberOfCells=\"0\" >\n"
5478  << "<Cells>\n"
5479  << "<DataArray type=\"UInt8\" Name=\"types\"></DataArray>\n"
5480  << "</Cells>\n"
5481  << " <PointData Scalars=\"scalars\">\n";
5482  std::vector<bool> data_set_written(data_names.size(), false);
5483  for (const auto &nonscalar_data_range : nonscalar_data_ranges)
5484  {
5485  // mark these components as already written:
5486  for (unsigned int i = std::get<0>(nonscalar_data_range);
5487  i <= std::get<1>(nonscalar_data_range);
5488  ++i)
5489  data_set_written[i] = true;
5490 
5491  // write the header. concatenate all the component names with double
5492  // underscores unless a vector name has been specified
5493  out << " <DataArray type=\"Float32\" Name=\"";
5494 
5495  if (!std::get<2>(nonscalar_data_range).empty())
5496  out << std::get<2>(nonscalar_data_range);
5497  else
5498  {
5499  for (unsigned int i = std::get<0>(nonscalar_data_range);
5500  i < std::get<1>(nonscalar_data_range);
5501  ++i)
5502  out << data_names[i] << "__";
5503  out << data_names[std::get<1>(nonscalar_data_range)];
5504  }
5505 
5506  out << "\" NumberOfComponents=\"3\"></DataArray>\n";
5507  }
5508 
5509  for (unsigned int data_set = 0; data_set < data_names.size();
5510  ++data_set)
5511  if (data_set_written[data_set] == false)
5512  {
5513  out << " <DataArray type=\"Float32\" Name=\""
5514  << data_names[data_set] << "\"></DataArray>\n";
5515  }
5516 
5517  out << " </PointData>\n";
5518  out << "</Piece>\n";
5519 
5520  out << std::flush;
5521 
5522  return;
5523  }
5524 #endif
5525 
5526  // first up: metadata
5527  //
5528  // if desired, output time and cycle of the simulation, following the
5529  // instructions at
5530  // http://www.visitusers.org/index.php?title=Time_and_Cycle_in_VTK_files
5531  {
5532  const unsigned int n_metadata =
5533  ((flags.cycle != std::numeric_limits<unsigned int>::min() ? 1 : 0) +
5534  (flags.time != std::numeric_limits<double>::min() ? 1 : 0));
5535  if (n_metadata > 0)
5536  out << "<FieldData>\n";
5537 
5539  {
5540  out
5541  << "<DataArray type=\"Float32\" Name=\"CYCLE\" NumberOfTuples=\"1\" format=\"ascii\">"
5542  << flags.cycle << "</DataArray>\n";
5543  }
5544  if (flags.time != std::numeric_limits<double>::min())
5545  {
5546  out
5547  << "<DataArray type=\"Float32\" Name=\"TIME\" NumberOfTuples=\"1\" format=\"ascii\">"
5548  << flags.time << "</DataArray>\n";
5549  }
5550 
5551  if (n_metadata > 0)
5552  out << "</FieldData>\n";
5553  }
5554 
5555 
5556  VtuStream vtu_out(out, flags);
5557 
5558  const unsigned int n_data_sets = data_names.size();
5559  // check against # of data sets in first patch. checks against all other
5560  // patches are made in write_gmv_reorder_data_vectors
5561  if (patches[0].points_are_available)
5562  {
5563  AssertDimension(n_data_sets + spacedim, patches[0].data.n_rows())
5564  }
5565  else
5566  {
5567  AssertDimension(n_data_sets, patches[0].data.n_rows())
5568  }
5569 
5570 #ifdef DEAL_II_WITH_ZLIB
5571  const char *ascii_or_binary = "binary";
5572 #else
5573  const char * ascii_or_binary = "ascii";
5574 #endif
5575 
5576 
5577  // first count the number of cells and cells for later use
5578  unsigned int n_nodes, n_cells, n_points_and_n_cells;
5579  compute_sizes(patches,
5581  n_nodes,
5582  n_cells,
5583  n_points_and_n_cells);
5584 
5585  // in gmv format the vertex coordinates and the data have an order that is a
5586  // bit unpleasant (first all x coordinates, then all y coordinate, ...;
5587  // first all data of variable 1, then variable 2, etc), so we have to copy
5588  // the data vectors a bit around
5589  //
5590  // note that we copy vectors when looping over the patches since we have to
5591  // write them one variable at a time and don't want to use more than one
5592  // loop
5593  //
5594  // this copying of data vectors can be done while we already output the
5595  // vertices, so do this on a separate task and when wanting to write out the
5596  // data, we wait for that task to finish
5597  Table<2, float> data_vectors(n_data_sets, n_nodes);
5598 
5599  void (*fun_ptr)(const std::vector<Patch<dim, spacedim>> &,
5600  Table<2, float> &) =
5601  &write_gmv_reorder_data_vectors<dim, spacedim, float>;
5602  Threads::Task<> reorder_task =
5603  Threads::new_task(fun_ptr, patches, data_vectors);
5604 
5606  // first make up a list of used vertices along with their coordinates
5607  //
5608  // note that according to the standard, we have to print d=1..3 dimensions,
5609  // even if we are in reality in 2d, for example
5610  out << "<Piece NumberOfPoints=\"" << n_nodes << "\" NumberOfCells=\""
5611  << n_cells << "\" >\n";
5612  out << " <Points>\n";
5613  out << " <DataArray type=\"Float32\" NumberOfComponents=\"3\" format=\""
5614  << ascii_or_binary << "\">\n";
5615  write_nodes(patches, vtu_out);
5616  out << " </DataArray>\n";
5617  out << " </Points>\n\n";
5619  // now for the cells
5620  out << " <Cells>\n";
5621  out << " <DataArray type=\"Int32\" Name=\"connectivity\" format=\""
5622  << ascii_or_binary << "\">\n";
5623  if (flags.write_higher_order_cells)
5624  write_high_order_cells(patches, vtu_out);
5625  else
5626  write_cells(patches, vtu_out);
5627  out << " </DataArray>\n";
5628 
5629  // XML VTU format uses offsets; this is different than the VTK format, which
5630  // puts the number of nodes per cell in front of the connectivity list.
5631  out << " <DataArray type=\"Int32\" Name=\"offsets\" format=\""
5632  << ascii_or_binary << "\">\n";
5633 
5634  std::vector<int32_t> offsets;
5635  offsets.reserve(n_cells);
5636 
5637  // uint8_t might be an alias to unsigned char which is then not printed
5638  // as ascii integers
5639 #ifdef DEAL_II_WITH_ZLIB
5640  std::vector<uint8_t> cell_types;
5641 #else
5642  std::vector<unsigned int> cell_types;
5643 #endif
5644  cell_types.reserve(n_cells);
5645 
5646  unsigned int first_vertex_of_patch = 0;
5647 
5648  for (const auto &patch : patches)
5649  {
5650  const auto vtk_cell_id =
5651  extract_vtk_patch_info(patch, flags.write_higher_order_cells);
5652 
5653  for (unsigned int i = 0; i < vtk_cell_id[1]; ++i)
5654  {
5655  cell_types.push_back(vtk_cell_id[0]);
5656  first_vertex_of_patch += vtk_cell_id[2];
5657  offsets.push_back(first_vertex_of_patch);
5658  }
5659  }
5660 
5661  vtu_out << offsets;
5662  out << "\n";
5663  out << " </DataArray>\n";
5664 
5665  // next output the types of the cells. since all cells are the same, this is
5666  // simple
5667  out << " <DataArray type=\"UInt8\" Name=\"types\" format=\""
5668  << ascii_or_binary << "\">\n";
5669 
5670  // this should compress well :-)
5671  vtu_out << cell_types;
5672  out << "\n";
5673  out << " </DataArray>\n";
5674  out << " </Cells>\n";
5675 
5676 
5678  // data output.
5679 
5680  // now write the data vectors to @p{out} first make sure that all data is in
5681  // place
5682  reorder_task.join();
5683 
5684  // then write data. the 'POINT_DATA' means: node data (as opposed to cell
5685  // data, which we do not support explicitly here). all following data sets
5686  // are point data
5687  out << " <PointData Scalars=\"scalars\">\n";
5688 
5689  // when writing, first write out all vector data, then handle the scalar
5690  // data sets that have been left over
5691  std::vector<bool> data_set_written(n_data_sets, false);
5692  for (const auto &range : nonscalar_data_ranges)
5693  {
5694  const auto first_component = std::get<0>(range);
5695  const auto last_component = std::get<1>(range);
5696  const auto &name = std::get<2>(range);
5697  const bool is_tensor =
5698  (std::get<3>(range) ==
5700  const unsigned int n_components = (is_tensor ? 9 : 3);
5701  AssertThrow(last_component >= first_component,
5702  ExcLowerRange(last_component, first_component));
5703  AssertThrow(last_component < n_data_sets,
5704  ExcIndexRange(last_component, 0, n_data_sets));
5705  if (is_tensor)
5706  {
5707  AssertThrow((last_component + 1 - first_component <= 9),
5708  ExcMessage(
5709  "Can't declare a tensor with more than 9 components "
5710  "in VTK"));
5711  }
5712  else
5713  {
5714  AssertThrow((last_component + 1 - first_component <= 3),
5715  ExcMessage(
5716  "Can't declare a vector with more than 3 components "
5717  "in VTK"));
5718  }
5719 
5720  // mark these components as already written:
5721  for (unsigned int i = first_component; i <= last_component; ++i)
5722  data_set_written[i] = true;
5723 
5724  // write the header. concatenate all the component names with double
5725  // underscores unless a vector name has been specified
5726  out << " <DataArray type=\"Float32\" Name=\"";
5727 
5728  if (!name.empty())
5729  out << name;
5730  else
5731  {
5732  for (unsigned int i = first_component; i < last_component; ++i)
5733  out << data_names[i] << "__";
5734  out << data_names[last_component];
5735  }
5736 
5737  out << "\" NumberOfComponents=\"" << n_components << "\" format=\""
5738  << ascii_or_binary << "\">\n";
5739 
5740  // now write data. pad all vectors to have three components
5741  std::vector<float> data;
5742  data.reserve(n_nodes * n_components);
5743 
5744  for (unsigned int n = 0; n < n_nodes; ++n)
5745  {
5746  if (!is_tensor)
5747  {
5748  switch (last_component - first_component)
5749  {
5750  case 0:
5751  data.push_back(data_vectors(first_component, n));
5752  data.push_back(0);
5753  data.push_back(0);
5754  break;
5755 
5756  case 1:
5757  data.push_back(data_vectors(first_component, n));
5758  data.push_back(data_vectors(first_component + 1, n));
5759  data.push_back(0);
5760  break;
5761 
5762  case 2:
5763  data.push_back(data_vectors(first_component, n));
5764  data.push_back(data_vectors(first_component + 1, n));
5765  data.push_back(data_vectors(first_component + 2, n));
5766  break;
5767 
5768  default:
5769  // Anything else is not yet implemented
5770  Assert(false, ExcInternalError());
5771  }
5772  }
5773  else
5774  {
5775  Tensor<2, 3> vtk_data;
5776  vtk_data = 0.;
5777 
5778  const unsigned int size = last_component - first_component + 1;
5779  if (size == 1)
5780  // 1D, 1 element
5781  {
5782  vtk_data[0][0] = data_vectors(first_component, n);
5783  }
5784  else if (size == 4)
5785  // 2D, 4 elements
5786  {
5787  for (unsigned int c = 0; c < size; ++c)
5788  {
5789  const auto ind =
5791  vtk_data[ind[0]][ind[1]] =
5792  data_vectors(first_component + c, n);
5793  }
5794  }
5795  else if (size == 9)
5796  // 3D 9 elements
5797  {
5798  for (unsigned int c = 0; c < size; ++c)
5799  {
5800  const auto ind =
5802  vtk_data[ind[0]][ind[1]] =
5803  data_vectors(first_component + c, n);
5804  }
5805  }
5806  else
5807  {
5808  Assert(false, ExcInternalError());
5809  }
5810 
5811  // now put the tensor into data
5812  // note we padd with zeros because VTK format always wants to
5813  // see a 3x3 tensor, regardless of dimension
5814  for (unsigned int i = 0; i < 3; ++i)
5815  for (unsigned int j = 0; j < 3; ++j)
5816  data.push_back(vtk_data[i][j]);
5817  }
5818  } // loop over nodes
5819 
5820  vtu_out << data;
5821  out << " </DataArray>\n";
5822 
5823  } // loop over ranges
5824 
5825  // now do the left over scalar data sets
5826  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
5827  if (data_set_written[data_set] == false)
5828  {
5829  out << " <DataArray type=\"Float32\" Name=\""
5830  << data_names[data_set] << "\" format=\"" << ascii_or_binary
5831  << "\">\n";
5832 
5833  std::vector<float> data(data_vectors[data_set].begin(),
5834  data_vectors[data_set].end());
5835  vtu_out << data;
5836  out << " </DataArray>\n";
5837  }
5838 
5839  out << " </PointData>\n";
5840 
5841  // Finish up writing a valid XML file
5842  out << " </Piece>\n";
5843 
5844  // make sure everything now gets to disk
5845  out.flush();
5846 
5847  // assert the stream is still ok
5848  AssertThrow(out, ExcIO());
5849  }
5850 
5851 
5852 
5853  void
5855  std::ostream & out,
5856  const std::vector<std::string> &piece_names,
5857  const std::vector<std::string> &data_names,
5858  const std::vector<
5859  std::tuple<unsigned int,
5860  unsigned int,
5861  std::string,
5863  &nonscalar_data_ranges)
5864  {
5865  AssertThrow(out, ExcIO());
5866 
5867  const unsigned int n_data_sets = data_names.size();
5868 
5869  out << "<?xml version=\"1.0\"?>\n";
5870 
5871  out << "<!--\n";
5872  out << "#This file was generated by the deal.II library"
5873  << " on " << Utilities::System::get_date() << " at "
5874  << Utilities::System::get_time() << "\n-->\n";
5875 
5876  out
5877  << "<VTKFile type=\"PUnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n";
5878  out << " <PUnstructuredGrid GhostLevel=\"0\">\n";
5879  out << " <PPointData Scalars=\"scalars\">\n";
5880 
5881  // We need to output in the same order as the write_vtu function does:
5882  std::vector<bool> data_set_written(n_data_sets, false);
5883  for (const auto &nonscalar_data_range : nonscalar_data_ranges)
5884  {
5885  const auto first_component = std::get<0>(nonscalar_data_range);
5886  const auto last_component = std::get<1>(nonscalar_data_range);
5887  const bool is_tensor =
5888  (std::get<3>(nonscalar_data_range) ==
5890  const unsigned int n_components = (is_tensor ? 9 : 3);
5891  AssertThrow(last_component >= first_component,
5892  ExcLowerRange(last_component, first_component));
5893  AssertThrow(last_component < n_data_sets,
5894  ExcIndexRange(last_component, 0, n_data_sets));
5895  if (is_tensor)
5896  {
5897  AssertThrow((last_component + 1 - first_component <= 9),
5898  ExcMessage(
5899  "Can't declare a tensor with more than 9 components "
5900  "in VTK"));
5901  }
5902  else
5903  {
5904  Assert((last_component + 1 - first_component <= 3),
5905  ExcMessage(
5906  "Can't declare a vector with more than 3 components "
5907  "in VTK"));
5908  }
5909 
5910  // mark these components as already written:
5911  for (unsigned int i = std::get<0>(nonscalar_data_range);
5912  i <= std::get<1>(nonscalar_data_range);
5913  ++i)
5914  data_set_written[i] = true;
5915 
5916  // write the header. concatenate all the component names with double
5917  // underscores unless a vector name has been specified
5918  out << " <PDataArray type=\"Float32\" Name=\"";
5919 
5920  if (!std::get<2>(nonscalar_data_range).empty())
5921  out << std::get<2>(nonscalar_data_range);
5922  else
5923  {
5924  for (unsigned int i = std::get<0>(nonscalar_data_range);
5925  i < std::get<1>(nonscalar_data_range);
5926  ++i)
5927  out << data_names[i] << "__";
5928  out << data_names[std::get<1>(nonscalar_data_range)];
5929  }
5930 
5931  out << "\" NumberOfComponents=\"" << n_components
5932  << "\" format=\"ascii\"/>\n";
5933  }
5934 
5935  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
5936  if (data_set_written[data_set] == false)
5937  {
5938  out << " <PDataArray type=\"Float32\" Name=\""
5939  << data_names[data_set] << "\" format=\"ascii\"/>\n";
5940  }
5941 
5942  out << " </PPointData>\n";
5943 
5944  out << " <PPoints>\n";
5945  out << " <PDataArray type=\"Float32\" NumberOfComponents=\"3\"/>\n";
5946  out << " </PPoints>\n";
5947 
5948  for (const auto &piece_name : piece_names)
5949  out << " <Piece Source=\"" << piece_name << "\"/>\n";
5950 
5951  out << " </PUnstructuredGrid>\n";
5952  out << "</VTKFile>\n";
5953 
5954  out.flush();
5955 
5956  // assert the stream is still ok
5957  AssertThrow(out, ExcIO());
5958  }
5959 
5960 
5961 
5962  void
5964  std::ostream & out,
5965  const std::vector<std::pair<double, std::string>> &times_and_names)
5966  {
5967  AssertThrow(out, ExcIO());
5968 
5969  out << "<?xml version=\"1.0\"?>\n";
5970 
5971  out << "<!--\n";
5972  out << "#This file was generated by the deal.II library"
5973  << " on " << Utilities::System::get_date() << " at "
5974  << Utilities::System::get_time() << "\n-->\n";
5975 
5976  out
5977  << "<VTKFile type=\"Collection\" version=\"0.1\" ByteOrder=\"LittleEndian\">\n";
5978  out << " <Collection>\n";
5979 
5980  std::streamsize ss = out.precision();
5981  out.precision(12);
5982 
5983  for (const auto &time_and_name : times_and_names)
5984  out << " <DataSet timestep=\"" << time_and_name.first
5985  << "\" group=\"\" part=\"0\" file=\"" << time_and_name.second
5986  << "\"/>\n";
5987 
5988  out << " </Collection>\n";
5989  out << "</VTKFile>\n";
5990 
5991  out.flush();
5992  out.precision(ss);
5993 
5994  AssertThrow(out, ExcIO());
5995  }
5996 
5997 
5998 
5999  void
6000  write_visit_record(std::ostream & out,
6001  const std::vector<std::string> &piece_names)
6002  {
6003  out << "!NBLOCKS " << piece_names.size() << '\n';
6004  for (const auto &piece_name : piece_names)
6005  out << piece_name << '\n';
6006 
6007  out << std::flush;
6008  }
6009 
6010 
6011 
6012  void
6013  write_visit_record(std::ostream & out,
6014  const std::vector<std::vector<std::string>> &piece_names)
6015  {
6016  AssertThrow(out, ExcIO());
6017 
6018  if (piece_names.size() == 0)
6019  return;
6020 
6021  const double nblocks = piece_names[0].size();
6022  Assert(nblocks > 0,
6023  ExcMessage("piece_names should be a vector of nonempty vectors."));
6024 
6025  out << "!NBLOCKS " << nblocks << '\n';
6026  for (const auto &domain : piece_names)
6027  {
6028  Assert(domain.size() == nblocks,
6029  ExcMessage(
6030  "piece_names should be a vector of equal sized vectors."));
6031  for (const auto &subdomain : domain)
6032  out << subdomain << '\n';
6033  }
6034 
6035  out << std::flush;
6036  }
6037 
6038 
6039 
6040  void
6042  std::ostream &out,
6043  const std::vector<std::pair<double, std::vector<std::string>>>
6044  &times_and_piece_names)
6045  {
6046  AssertThrow(out, ExcIO());
6047 
6048  if (times_and_piece_names.size() == 0)
6049  return;
6050 
6051  const double nblocks = times_and_piece_names[0].second.size();
6052  Assert(
6053  nblocks > 0,
6054  ExcMessage(
6055  "time_and_piece_names should contain nonempty vectors of filenames for every timestep."));
6056 
6057  for (const auto &domain : times_and_piece_names)
6058  out << "!TIME " << domain.first << '\n';
6059 
6060  out << "!NBLOCKS " << nblocks << '\n';
6061  for (const auto &domain : times_and_piece_names)
6062  {
6063  Assert(domain.second.size() == nblocks,
6064  ExcMessage(
6065  "piece_names should be a vector of equal sized vectors."));
6066  for (const auto &subdomain : domain.second)
6067  out << subdomain << '\n';
6068  }
6069 
6070  out << std::flush;
6071  }
6072 
6073 
6074 
6075  template <int dim, int spacedim>
6076  void
6078  const std::vector<Patch<dim, spacedim>> &,
6079  const std::vector<std::string> &,
6080  const std::vector<
6081  std::tuple<unsigned int,
6082  unsigned int,
6083  std::string,
6085  const SvgFlags &,
6086  std::ostream &)
6087  {
6088  Assert(false, ExcNotImplemented());
6089  }
6090 
6091  template <int spacedim>
6092  void
6094  const std::vector<Patch<2, spacedim>> &patches,
6095  const std::vector<std::string> & /*data_names*/,
6096  const std::vector<
6097  std::tuple<unsigned int,
6098  unsigned int,
6099  std::string,
6101  & /*nonscalar_data_ranges*/,
6102  const SvgFlags &flags,
6103  std::ostream & out)
6104  {
6105  const unsigned int height = flags.height;
6106  unsigned int width = flags.width;
6107 
6108  // margin around the plotted area
6109  unsigned int margin_in_percent = 0;
6110  if (flags.margin)
6111  margin_in_percent = 5;
6112 
6113 
6114  // determine the bounding box in the model space
6115  double x_dimension, y_dimension, z_dimension;
6116 
6117  const auto &first_patch = patches[0];
6118 
6119  unsigned int n_subdivisions = first_patch.n_subdivisions;
6120  unsigned int n = n_subdivisions + 1;
6121  const unsigned int d1 = 1;
6122  const unsigned int d2 = n;
6123 
6124  Point<spacedim> projected_point;
6125  std::array<Point<spacedim>, 4> projected_points;
6126 
6127  Point<2> projection_decomposition;
6128  std::array<Point<2>, 4> projection_decompositions;
6129 
6130  projected_point =
6131  compute_hypercube_node(first_patch, 0, 0, 0, n_subdivisions);
6132 
6133  if (first_patch.data.n_rows() != 0)
6134  {
6135  AssertIndexRange(flags.height_vector, first_patch.data.n_rows());
6136  }
6137 
6138  double x_min = projected_point[0];
6139  double x_max = x_min;
6140  double y_min = projected_point[1];
6141  double y_max = y_min;
6142  double z_min = first_patch.data.n_rows() != 0 ?
6143  first_patch.data(flags.height_vector, 0) :
6144  0;
6145  double z_max = z_min;
6146 
6147  // iterate over the patches
6148  for (const auto &patch : patches)
6149  {
6150  n_subdivisions = patch.n_subdivisions;
6151  n = n_subdivisions + 1;
6152 
6153  for (unsigned int i2 = 0; i2 < n_subdivisions; ++i2)
6154  {
6155  for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1)
6156  {
6157  projected_points[0] =
6158  compute_hypercube_node(patch, i1, i2, 0, n_subdivisions);
6159  projected_points[1] =
6160  compute_hypercube_node(patch, i1 + 1, i2, 0, n_subdivisions);
6161  projected_points[2] =
6162  compute_hypercube_node(patch, i1, i2 + 1, 0, n_subdivisions);
6163  projected_points[3] = compute_hypercube_node(
6164  patch, i1 + 1, i2 + 1, 0, n_subdivisions);
6165 
6166  x_min = std::min(x_min, projected_points[0][0]);
6167  x_min = std::min(x_min, projected_points[1][0]);
6168  x_min = std::min(x_min, projected_points[2][0]);
6169  x_min = std::min(x_min, projected_points[3][0]);
6170 
6171  x_max = std::max(x_max, projected_points[0][0]);
6172  x_max = std::max(x_max, projected_points[1][0]);
6173  x_max = std::max(x_max, projected_points[2][0]);
6174  x_max = std::max(x_max, projected_points[3][0]);
6175 
6176  y_min = std::min(y_min, projected_points[0][1]);
6177  y_min = std::min(y_min, projected_points[1][1]);
6178  y_min = std::min(y_min, projected_points[2][1]);
6179  y_min = std::min(y_min, projected_points[3][1]);
6180 
6181  y_max = std::max(y_max, projected_points[0][1]);
6182  y_max = std::max(y_max, projected_points[1][1]);
6183  y_max = std::max(y_max, projected_points[2][1]);
6184  y_max = std::max(y_max, projected_points[3][1]);
6185 
6186  Assert((flags.height_vector < patch.data.n_rows()) ||
6187  patch.data.n_rows() == 0,
6189  0,
6190  patch.data.n_rows()));
6191 
6192  z_min = std::min<double>(z_min,
6193  patch.data(flags.height_vector,
6194  i1 * d1 + i2 * d2));
6195  z_min = std::min<double>(z_min,
6196  patch.data(flags.height_vector,
6197  (i1 + 1) * d1 + i2 * d2));
6198  z_min = std::min<double>(z_min,
6199  patch.data(flags.height_vector,
6200  i1 * d1 + (i2 + 1) * d2));
6201  z_min =
6202  std::min<double>(z_min,
6203  patch.data(flags.height_vector,
6204  (i1 + 1) * d1 + (i2 + 1) * d2));
6205 
6206  z_max = std::max<double>(z_max,
6207  patch.data(flags.height_vector,
6208  i1 * d1 + i2 * d2));
6209  z_max = std::max<double>(z_max,
6210  patch.data(flags.height_vector,
6211  (i1 + 1) * d1 + i2 * d2));
6212  z_max = std::max<double>(z_max,
6213  patch.data(flags.height_vector,
6214  i1 * d1 + (i2 + 1) * d2));
6215  z_max =
6216  std::max<double>(z_max,
6217  patch.data(flags.height_vector,
6218  (i1 + 1) * d1 + (i2 + 1) * d2));
6219  }
6220  }
6221  }
6222 
6223  x_dimension = x_max - x_min;
6224  y_dimension = y_max - y_min;
6225  z_dimension = z_max - z_min;
6226 
6227 
6228  // set initial camera position
6229  Point<3> camera_position;
6230  Point<3> camera_direction;
6231  Point<3> camera_horizontal;
6232  float camera_focus = 0;
6233 
6234  // translate camera from the origin to the initial position
6235  camera_position[0] = 0.;
6236  camera_position[1] = 0.;
6237  camera_position[2] = z_min + 2. * z_dimension;
6238 
6239  camera_direction[0] = 0.;
6240  camera_direction[1] = 0.;
6241  camera_direction[2] = -1.;
6242 
6243  camera_horizontal[0] = 1.;
6244  camera_horizontal[1] = 0.;
6245  camera_horizontal[2] = 0.;
6246 
6247  camera_focus = .5 * z_dimension;
6248 
6249  Point<3> camera_position_temp;
6250  Point<3> camera_direction_temp;
6251  Point<3> camera_horizontal_temp;
6252 
6253  const float angle_factor = 3.14159265f / 180.f;
6254 
6255  // (I) rotate the camera to the chosen polar angle
6256  camera_position_temp[1] =
6257  std::cos(angle_factor * flags.polar_angle) * camera_position[1] -
6258  std::sin(angle_factor * flags.polar_angle) * camera_position[2];
6259  camera_position_temp[2] =
6260  std::sin(angle_factor * flags.polar_angle) * camera_position[1] +
6261  std::cos(angle_factor * flags.polar_angle) * camera_position[2];
6262 
6263  camera_direction_temp[1] =
6264  std::cos(angle_factor * flags.polar_angle) * camera_direction[1] -
6265  std::sin(angle_factor * flags.polar_angle) * camera_direction[2];
6266  camera_direction_temp[2] =
6267  std::sin(angle_factor * flags.polar_angle) * camera_direction[1] +
6268  std::cos(angle_factor * flags.polar_angle) * camera_direction[2];
6269 
6270  camera_horizontal_temp[1] =
6271  std::cos(angle_factor * flags.polar_angle) * camera_horizontal[1] -
6272  std::sin(angle_factor * flags.polar_angle) * camera_horizontal[2];
6273  camera_horizontal_temp[2] =
6274  std::sin(angle_factor * flags.polar_angle) * camera_horizontal[1] +
6275  std::cos(angle_factor * flags.polar_angle) * camera_horizontal[2];
6276 
6277  camera_position[1] = camera_position_temp[1];
6278  camera_position[2] = camera_position_temp[2];
6279 
6280  camera_direction[1] = camera_direction_temp[1];
6281  camera_direction[2] = camera_direction_temp[2];
6282 
6283  camera_horizontal[1] = camera_horizontal_temp[1];
6284  camera_horizontal[2] = camera_horizontal_temp[2];
6285 
6286  // (II) rotate the camera to the chosen azimuth angle
6287  camera_position_temp[0] =
6288  std::cos(angle_factor * flags.azimuth_angle) * camera_position[0] -
6289  std::sin(angle_factor * flags.azimuth_angle) * camera_position[1];
6290  camera_position_temp[1] =
6291  std::sin(angle_factor * flags.azimuth_angle) * camera_position[0] +
6292  std::cos(angle_factor * flags.azimuth_angle) * camera_position[1];
6293 
6294  camera_direction_temp[0] =
6295  std::cos(angle_factor * flags.azimuth_angle) * camera_direction[0] -
6296  std::sin(angle_factor * flags.azimuth_angle) * camera_direction[1];
6297  camera_direction_temp[1] =
6298  std::sin(angle_factor * flags.azimuth_angle) * camera_direction[0] +
6299  std::cos(angle_factor * flags.azimuth_angle) * camera_direction[1];
6300 
6301  camera_horizontal_temp[0] =
6302  std::cos(angle_factor * flags.azimuth_angle) * camera_horizontal[0] -
6303  std::sin(angle_factor * flags.azimuth_angle) * camera_horizontal[1];
6304  camera_horizontal_temp[1] =
6305  std::sin(angle_factor * flags.azimuth_angle) * camera_horizontal[0] +
6306  std::cos(angle_factor * flags.azimuth_angle) * camera_horizontal[1];
6307 
6308  camera_position[0] = camera_position_temp[0];
6309  camera_position[1] = camera_position_temp[1];
6310 
6311  camera_direction[0] = camera_direction_temp[0];
6312  camera_direction[1] = camera_direction_temp[1];
6313 
6314  camera_horizontal[0] = camera_horizontal_temp[0];
6315  camera_horizontal[1] = camera_horizontal_temp[1];
6316 
6317  // (III) translate the camera
6318  camera_position[0] = x_min + .5 * x_dimension;
6319  camera_position[1] = y_min + .5 * y_dimension;
6320 
6321  camera_position[0] += (z_min + 2. * z_dimension) *
6322  std::sin(angle_factor * flags.polar_angle) *
6323  std::sin(angle_factor * flags.azimuth_angle);
6324  camera_position[1] -= (z_min + 2. * z_dimension) *
6325  std::sin(angle_factor * flags.polar_angle) *
6326  std::cos(angle_factor * flags.azimuth_angle);
6327 
6328 
6329  // determine the bounding box on the projection plane
6330  double x_min_perspective, y_min_perspective;
6331  double x_max_perspective, y_max_perspective;
6332  double x_dimension_perspective, y_dimension_perspective;
6333 
6334  n_subdivisions = first_patch.n_subdivisions;
6335  n = n_subdivisions + 1;
6336 
6337  Point<3> point;
6338 
6339  projected_point =
6340  compute_hypercube_node(first_patch, 0, 0, 0, n_subdivisions);
6341 
6342  if (first_patch.data.n_rows() != 0)
6343  {
6344  AssertIndexRange(flags.height_vector, first_patch.data.n_rows());
6345  }
6346 
6347  point[0] = projected_point[0];
6348  point[1] = projected_point[1];
6349  point[2] = first_patch.data.n_rows() != 0 ?
6350  first_patch.data(flags.height_vector, 0) :
6351  0;
6352 
6353  projection_decomposition = svg_project_point(point,
6354  camera_position,
6355  camera_direction,
6356  camera_horizontal,
6357  camera_focus);
6358 
6359  x_min_perspective = projection_decomposition[0];
6360  x_max_perspective = projection_decomposition[0];
6361  y_min_perspective = projection_decomposition[1];
6362  y_max_perspective = projection_decomposition[1];
6363 
6364  // iterate over the patches
6365  for (const auto &patch : patches)
6366  {
6367  n_subdivisions = patch.n_subdivisions;
6368  for (unsigned int i2 = 0; i2 < n_subdivisions; ++i2)
6369  {
6370  for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1)
6371  {
6372  const std::array<Point<spacedim>, 4> projected_vertices{
6373  {compute_hypercube_node(patch, i1, i2, 0, n_subdivisions),
6374  compute_hypercube_node(patch, i1 + 1, i2, 0, n_subdivisions),
6375  compute_hypercube_node(patch, i1, i2 + 1, 0, n_subdivisions),
6376  compute_hypercube_node(
6377  patch, i1 + 1, i2 + 1, 0, n_subdivisions)}};
6378 
6379  Assert((flags.height_vector < patch.data.n_rows()) ||
6380  patch.data.n_rows() == 0,
6382  0,
6383  patch.data.n_rows()));
6384 
6385  const std::array<Point<3>, 4> vertices = {
6387  projected_vertices[0][1],
6388  patch.data.n_rows() != 0 ?
6389  patch.data(0, i1 * d1 + i2 * d2) :
6390  0},
6392  projected_vertices[1][1],
6393  patch.data.n_rows() != 0 ?
6394  patch.data(0, (i1 + 1) * d1 + i2 * d2) :
6395  0},
6397  projected_vertices[2][1],
6398  patch.data.n_rows() != 0 ?
6399  patch.data(0, i1 * d1 + (i2 + 1) * d2) :
6400  0},
6402  projected_vertices[3][1],
6403  patch.data.n_rows() != 0 ?
6404  patch.data(0, (i1 + 1) * d1 + (i2 + 1) * d2) :
6405  0}}};
6406 
6407  projection_decompositions = {
6408  {svg_project_point(vertices[0],
6409  camera_position,
6410  camera_direction,
6411  camera_horizontal,
6412  camera_focus),
6413  svg_project_point(vertices[1],
6414  camera_position,
6415  camera_direction,
6416  camera_horizontal,
6417  camera_focus),
6418  svg_project_point(vertices[2],
6419  camera_position,
6420  camera_direction,
6421  camera_horizontal,
6422  camera_focus),
6423  svg_project_point(vertices[3],
6424  camera_position,
6425  camera_direction,
6426  camera_horizontal,
6427  camera_focus)}};
6428 
6429  x_min_perspective =
6430  std::min(x_min_perspective,
6431  static_cast<double>(
6432  projection_decompositions[0][0]));
6433  x_min_perspective =
6434  std::min(x_min_perspective,
6435  static_cast<double>(
6436  projection_decompositions[1][0]));
6437  x_min_perspective =
6438  std::min(x_min_perspective,
6439  static_cast<double>(
6440  projection_decompositions[2][0]));
6441  x_min_perspective =
6442  std::min(x_min_perspective,
6443  static_cast<double>(
6444  projection_decompositions[3][0]));
6445 
6446  x_max_perspective =
6447  std::max(x_max_perspective,
6448  static_cast<double>(
6449  projection_decompositions[0][0]));
6450  x_max_perspective =
6451  std::max(x_max_perspective,
6452  static_cast<double>(
6453  projection_decompositions[1][0]));
6454  x_max_perspective =
6455  std::max(x_max_perspective,
6456  static_cast<double>(
6457  projection_decompositions[2][0]));
6458  x_max_perspective =
6459  std::max(x_max_perspective,
6460  static_cast<double>(
6461  projection_decompositions[3][0]));
6462 
6463  y_min_perspective =
6464  std::min(y_min_perspective,
6465  static_cast<double>(
6466  projection_decompositions[0][1]));
6467  y_min_perspective =
6468  std::min(y_min_perspective,
6469  static_cast<double>(
6470  projection_decompositions[1][1]));
6471  y_min_perspective =
6472  std::min(y_min_perspective,
6473  static_cast<double>(
6474  projection_decompositions[2][1]));
6475  y_min_perspective =
6476  std::min(y_min_perspective,
6477  static_cast<double>(
6478  projection_decompositions[3][1]));
6479 
6480  y_max_perspective =
6481  std::max(y_max_perspective,
6482  static_cast<double>(
6483  projection_decompositions[0][1]));
6484  y_max_perspective =
6485  std::max(y_max_perspective,
6486  static_cast<double>(
6487  projection_decompositions[1][1]));
6488  y_max_perspective =
6489  std::max(y_max_perspective,
6490  static_cast<double>(
6491  projection_decompositions[2][1]));
6492  y_max_perspective =
6493  std::max(y_max_perspective,
6494  static_cast<double>(
6495  projection_decompositions[3][1]));
6496  }
6497  }
6498  }
6499 
6500  x_dimension_perspective = x_max_perspective - x_min_perspective;
6501  y_dimension_perspective = y_max_perspective - y_min_perspective;
6502 
6503  std::multiset<SvgCell> cells;
6504 
6505  // iterate over the patches
6506  for (const auto &patch : patches)
6507  {
6508  n_subdivisions = patch.n_subdivisions;
6509 
6510  for (unsigned int i2 = 0; i2 < n_subdivisions; ++i2)
6511  {
6512  for (unsigned int i1 = 0; i1 < n_subdivisions; ++i1)
6513  {
6514  const std::array<Point<spacedim>, 4> projected_vertices = {
6515  {compute_hypercube_node(patch, i1, i2, 0, n_subdivisions),
6516  compute_hypercube_node(patch, i1 + 1, i2, 0, n_subdivisions),
6517  compute_hypercube_node(patch, i1, i2 + 1, 0, n_subdivisions),
6518  compute_hypercube_node(
6519  patch, i1 + 1, i2 + 1, 0, n_subdivisions)}};
6520 
6521  Assert((flags.height_vector < patch.data.n_rows()) ||
6522  patch.data.n_rows() == 0,
6524  0,
6525  patch.data.n_rows()));
6526 
6527  SvgCell cell;
6528 
6529  cell.vertices[0][0] = projected_vertices[0][0];
6530  cell.vertices[0][1] = projected_vertices[0][1];
6531  cell.vertices[0][2] = patch.data.n_rows() != 0 ?
6532  patch.data(0, i1 * d1 + i2 * d2) :
6533  0;
6534 
6535  cell.vertices[1][0] = projected_vertices[1][0];
6536  cell.vertices[1][1] = projected_vertices[1][1];
6537  cell.vertices[1][2] = patch.data.n_rows() != 0 ?
6538  patch.data(0, (i1 + 1) * d1 + i2 * d2) :
6539  0;
6540 
6541  cell.vertices[2][0] = projected_vertices[2][0];
6542  cell.vertices[2][1] = projected_vertices[2][1];
6543  cell.vertices[2][2] = patch.data.n_rows() != 0 ?
6544  patch.data(0, i1 * d1 + (i2 + 1) * d2) :
6545  0;
6546 
6547  cell.vertices[3][0] = projected_vertices[3][0];
6548  cell.vertices[3][1] = projected_vertices[3][1];
6549  cell.vertices[3][2] =
6550  patch.data.n_rows() != 0 ?
6551  patch.data(0, (i1 + 1) * d1 + (i2 + 1) * d2) :
6552  0;
6553 
6554  cell.projected_vertices[0] =
6555  svg_project_point(cell.vertices[0],
6556  camera_position,
6557  camera_direction,
6558  camera_horizontal,
6559  camera_focus);
6560  cell.projected_vertices[1] =
6561  svg_project_point(cell.vertices[1],
6562  camera_position,
6563  camera_direction,
6564  camera_horizontal,
6565  camera_focus);
6566  cell.projected_vertices[2] =
6567  svg_project_point(cell.vertices[2],
6568  camera_position,
6569  camera_direction,
6570  camera_horizontal,
6571  camera_focus);
6572  cell.projected_vertices[3] =
6573  svg_project_point(cell.vertices[3],
6574  camera_position,
6575  camera_direction,
6576  camera_horizontal,
6577  camera_focus);
6578 
6579  cell.center = .25 * (cell.vertices[0] + cell.vertices[1] +
6580  cell.vertices[2] + cell.vertices[3]);
6581  cell.projected_center = svg_project_point(cell.center,
6582  camera_position,
6583  camera_direction,
6584  camera_horizontal,
6585  camera_focus);
6586 
6587  cell.depth = cell.center.distance(camera_position);
6588 
6589  cells.insert(cell);
6590  }
6591  }
6592  }
6593 
6594 
6595  // write the svg file
6596  if (width == 0)
6597  width = static_cast<unsigned int>(
6598  .5 + height * (x_dimension_perspective / y_dimension_perspective));
6599  unsigned int additional_width = 0;
6600 
6601  if (flags.draw_colorbar)
6602  additional_width = static_cast<unsigned int>(
6603  .5 + height * .3); // additional width for colorbar
6604 
6605  // basic svg header and background rectangle
6606  out << "<svg width=\"" << width + additional_width << "\" height=\""
6607  << height << "\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">"
6608  << '\n'
6609  << " <rect width=\"" << width + additional_width << "\" height=\""
6610  << height << "\" style=\"fill:white\"/>" << '\n'
6611  << '\n';
6612 
6613  unsigned int triangle_counter = 0;
6614 
6615  // write the cells in the correct order
6616  for (const auto &cell : cells)
6617  {
6618  Point<3> points3d_triangle[3];
6619 
6620  for (unsigned int triangle_index = 0; triangle_index < 4;
6621  triangle_index++)
6622  {
6623  switch (triangle_index)
6624  {
6625  case 0:
6626  points3d_triangle[0] = cell.vertices[0],
6627  points3d_triangle[1] = cell.vertices[1],
6628  points3d_triangle[2] = cell.center;
6629  break;
6630  case 1:
6631  points3d_triangle[0] = cell.vertices[1],
6632  points3d_triangle[1] = cell.vertices[3],
6633  points3d_triangle[2] = cell.center;
6634  break;
6635  case 2:
6636  points3d_triangle[0] = cell.vertices[3],
6637  points3d_triangle[1] = cell.vertices[2],
6638  points3d_triangle[2] = cell.center;
6639  break;
6640  case 3:
6641  points3d_triangle[0] = cell.vertices[2],
6642  points3d_triangle[1] = cell.vertices[0],
6643  points3d_triangle[2] = cell.center;
6644  break;
6645  default:
6646  break;
6647  }
6648 
6649  Point<6> gradient_param =
6650  svg_get_gradient_parameters(points3d_triangle);
6651 
6652  double start_h =
6653  .667 - ((gradient_param[4] - z_min) / z_dimension) * .667;
6654  double stop_h =
6655  .667 - ((gradient_param[5] - z_min) / z_dimension) * .667;
6656 
6657  unsigned int start_r = 0;
6658  unsigned int start_g = 0;
6659  unsigned int start_b = 0;
6660 
6661  unsigned int stop_r = 0;
6662  unsigned int stop_g = 0;
6663  unsigned int stop_b = 0;
6664 
6665  unsigned int start_i = static_cast<unsigned int>(start_h * 6.);
6666  unsigned int stop_i = static_cast<unsigned int>(stop_h * 6.);
6667 
6668  double start_f = start_h * 6. - start_i;
6669  double start_q = 1. - start_f;
6670 
6671  double stop_f = stop_h * 6. - stop_i;
6672  double stop_q = 1. - stop_f;
6673 
6674  switch (start_i % 6)
6675  {
6676  case 0:
6677  start_r = 255,
6678  start_g = static_cast<unsigned int>(.5 + 255. * start_f);
6679  break;
6680  case 1:
6681  start_r = static_cast<unsigned int>(.5 + 255. * start_q),
6682  start_g = 255;
6683  break;
6684  case 2:
6685  start_g = 255,
6686  start_b = static_cast<unsigned int>(.5 + 255. * start_f);
6687  break;
6688  case 3:
6689  start_g = static_cast<unsigned int>(.5 + 255. * start_q),
6690  start_b = 255;
6691  break;
6692  case 4:
6693  start_r = static_cast<unsigned int>(.5 + 255. * start_f),
6694  start_b = 255;
6695  break;
6696  case 5:
6697  start_r = 255,
6698  start_b = static_cast<unsigned int>(.5 + 255. * start_q);
6699  break;
6700  default:
6701  break;
6702  }
6703 
6704  switch (stop_i % 6)
6705  {
6706  case 0:
6707  stop_r = 255,
6708  stop_g = static_cast<unsigned int>(.5 + 255. * stop_f);
6709  break;
6710  case 1:
6711  stop_r = static_cast<unsigned int>(.5 + 255. * stop_q),
6712  stop_g = 255;
6713  break;
6714  case 2:
6715  stop_g = 255,
6716  stop_b = static_cast<unsigned int>(.5 + 255. * stop_f);
6717  break;
6718  case 3:
6719  stop_g = static_cast<unsigned int>(.5 + 255. * stop_q),
6720  stop_b = 255;
6721  break;
6722  case 4:
6723  stop_r = static_cast<unsigned int>(.5 + 255. * stop_f),
6724  stop_b = 255;
6725  break;
6726  case 5:
6727  stop_r = 255,
6728  stop_b = static_cast<unsigned int>(.5 + 255. * stop_q);
6729  break;
6730  default:
6731  break;
6732  }
6733 
6734  Point<3> gradient_start_point_3d, gradient_stop_point_3d;
6735 
6736  gradient_start_point_3d[0] = gradient_param[0];
6737  gradient_start_point_3d[1] = gradient_param[1];
6738  gradient_start_point_3d[2] = gradient_param[4];
6739 
6740  gradient_stop_point_3d[0] = gradient_param[2];
6741  gradient_stop_point_3d[1] = gradient_param[3];
6742  gradient_stop_point_3d[2] = gradient_param[5];
6743 
6744  Point<2> gradient_start_point =
6745  svg_project_point(gradient_start_point_3d,
6746  camera_position,
6747  camera_direction,
6748  camera_horizontal,
6749  camera_focus);
6750  Point<2> gradient_stop_point =
6751  svg_project_point(gradient_stop_point_3d,
6752  camera_position,
6753  camera_direction,
6754  camera_horizontal,
6755  camera_focus);
6756 
6757  // define linear gradient
6758  out << " <linearGradient id=\"" << triangle_counter
6759  << "\" gradientUnits=\"userSpaceOnUse\" "
6760  << "x1=\""
6761  << static_cast<unsigned int>(
6762  .5 +
6763  ((gradient_start_point[0] - x_min_perspective) /
6764  x_dimension_perspective) *
6765  (width - (width / 100.) * 2. * margin_in_percent) +
6766  ((width / 100.) * margin_in_percent))
6767  << "\" "
6768  << "y1=\""
6769  << static_cast<unsigned int>(
6770  .5 + height - (height / 100.) * margin_in_percent -
6771  ((gradient_start_point[1] - y_min_perspective) /
6772  y_dimension_perspective) *
6773  (height - (height / 100.) * 2. * margin_in_percent))
6774  << "\" "
6775  << "x2=\""
6776  << static_cast<unsigned int>(
6777  .5 +
6778  ((gradient_stop_point[0] - x_min_perspective) /
6779  x_dimension_perspective) *
6780  (width - (width / 100.) * 2. * margin_in_percent) +
6781  ((width / 100.) * margin_in_percent))
6782  << "\" "
6783  << "y2=\""
6784  << static_cast<unsigned int>(
6785  .5 + height - (height / 100.) * margin_in_percent -
6786  ((gradient_stop_point[1] - y_min_perspective) /
6787  y_dimension_perspective) *
6788  (height - (height / 100.) * 2. * margin_in_percent))
6789  << "\""
6790  << ">" << '\n'
6791  << " <stop offset=\"0\" style=\"stop-color:rgb(" << start_r
6792  << "," << start_g << "," << start_b << ")\"/>" << '\n'
6793  << " <stop offset=\"1\" style=\"stop-color:rgb(" << stop_r
6794  << "," << stop_g << "," << stop_b << ")\"/>" << '\n'
6795  << " </linearGradient>" << '\n';
6796 
6797  // draw current triangle
6798  double x1 = 0, y1 = 0, x2 = 0, y2 = 0;
6799  double x3 = cell.projected_center[0];
6800  double y3 = cell.projected_center[1];
6801 
6802  switch (triangle_index)
6803  {
6804  case 0:
6805  x1 = cell.projected_vertices[0][0],
6806  y1 = cell.projected_vertices[0][1],
6807  x2 = cell.projected_vertices[1][0],
6808  y2 = cell.projected_vertices[1][1];
6809  break;
6810  case 1:
6811  x1 = cell.projected_vertices[1][0],
6812  y1 = cell.projected_vertices[1][1],
6813  x2 = cell.projected_vertices[3][0],
6814  y2 = cell.projected_vertices[3][1];
6815  break;
6816  case 2:
6817  x1 = cell.projected_vertices[3][0],
6818  y1 = cell.projected_vertices[3][1],
6819  x2 = cell.projected_vertices[2][0],
6820  y2 = cell.projected_vertices[2][1];
6821  break;
6822  case 3:
6823  x1 = cell.projected_vertices[2][0],
6824  y1 = cell.projected_vertices[2][1],
6825  x2 = cell.projected_vertices[0][0],
6826  y2 = cell.projected_vertices[0][1];
6827  break;
6828  default:
6829  break;
6830  }
6831 
6832  out << " <path d=\"M "
6833  << static_cast<unsigned int>(
6834  .5 +
6835  ((x1 - x_min_perspective) / x_dimension_perspective) *
6836  (width - (width / 100.) * 2. * margin_in_percent) +
6837  ((width / 100.) * margin_in_percent))
6838  << ' '
6839  << static_cast<unsigned int>(
6840  .5 + height - (height / 100.) * margin_in_percent -
6841  ((y1 - y_min_perspective) / y_dimension_perspective) *
6842  (height - (height / 100.) * 2. * margin_in_percent))
6843  << " L "
6844  << static_cast<unsigned int>(
6845  .5 +
6846  ((x2 - x_min_perspective) / x_dimension_perspective) *
6847  (width - (width / 100.) * 2. * margin_in_percent) +
6848  ((width / 100.) * margin_in_percent))
6849  << ' '
6850  << static_cast<unsigned int>(
6851  .5 + height - (height / 100.) * margin_in_percent -
6852  ((y2 - y_min_perspective) / y_dimension_perspective) *
6853  (height - (height / 100.) * 2. * margin_in_percent))
6854  << " L "
6855  << static_cast<unsigned int>(
6856  .5 +
6857  ((x3 - x_min_perspective) / x_dimension_perspective) *
6858  (width - (width / 100.) * 2. * margin_in_percent) +
6859  ((width / 100.) * margin_in_percent))
6860  << ' '
6861  << static_cast<unsigned int>(
6862  .5 + height - (height / 100.) * margin_in_percent -
6863  ((y3 - y_min_perspective) / y_dimension_perspective) *
6864  (height - (height / 100.) * 2. * margin_in_percent))
6865  << " L "
6866  << static_cast<unsigned int>(
6867  .5 +
6868  ((x1 - x_min_perspective) / x_dimension_perspective) *
6869  (width - (width / 100.) * 2. * margin_in_percent) +
6870  ((width / 100.) * margin_in_percent))
6871  << ' '
6872  << static_cast<unsigned int>(
6873  .5 + height - (height / 100.) * margin_in_percent -
6874  ((y1 - y_min_perspective) / y_dimension_perspective) *
6875  (height - (height / 100.) * 2. * margin_in_percent))
6876  << "\" style=\"stroke:black; fill:url(#" << triangle_counter
6877  << "); stroke-width:" << flags.line_thickness << "\"/>" << '\n';
6878 
6879  triangle_counter++;
6880  }
6881  }
6882 
6883 
6884  // draw the colorbar
6885  if (flags.draw_colorbar)
6886  {
6887  out << '\n' << " <!-- colorbar -->" << '\n';
6888 
6889  unsigned int element_height = static_cast<unsigned int>(
6890  ((height / 100.) * (71. - 2. * margin_in_percent)) / 4);
6891  unsigned int element_width =
6892  static_cast<unsigned int>(.5 + (height / 100.) * 2.5);
6893 
6894  additional_width = 0;
6895  if (!flags.margin)
6896  additional_width =
6897  static_cast<unsigned int>(.5 + (height / 100.) * 2.5);
6898 
6899  for (unsigned int index = 0; index < 4; index++)
6900  {
6901  double start_h = .667 - ((index + 1) / 4.) * .667;
6902  double stop_h = .667 - (index / 4.) * .667;
6903 
6904  unsigned int start_r = 0;
6905  unsigned int start_g = 0;
6906  unsigned int start_b = 0;
6907 
6908  unsigned int stop_r = 0;
6909  unsigned int stop_g = 0;
6910  unsigned int stop_b = 0;
6911 
6912  unsigned int start_i = static_cast<unsigned int>(start_h * 6.);
6913  unsigned int stop_i = static_cast<unsigned int>(stop_h * 6.);
6914 
6915  double start_f = start_h * 6. - start_i;
6916  double start_q = 1. - start_f;
6917 
6918  double stop_f = stop_h * 6. - stop_i;
6919  double stop_q = 1. - stop_f;
6920 
6921  switch (start_i % 6)
6922  {
6923  case 0:
6924  start_r = 255,
6925  start_g = static_cast<unsigned int>(.5 + 255. * start_f);
6926  break;
6927  case 1:
6928  start_r = static_cast<unsigned int>(.5 + 255. * start_q),
6929  start_g = 255;
6930  break;
6931  case 2:
6932  start_g = 255,
6933  start_b = static_cast<unsigned int>(.5 + 255. * start_f);
6934  break;
6935  case 3:
6936  start_g = static_cast<unsigned int>(.5 + 255. * start_q),
6937  start_b = 255;
6938  break;
6939  case 4:
6940  start_r = static_cast<unsigned int>(.5 + 255. * start_f),
6941  start_b = 255;
6942  break;
6943  case 5:
6944  start_r = 255,
6945  start_b = static_cast<unsigned int>(.5 + 255. * start_q);
6946  break;
6947  default:
6948  break;
6949  }
6950 
6951  switch (stop_i % 6)
6952  {
6953  case 0:
6954  stop_r = 255,
6955  stop_g = static_cast<unsigned int>(.5 + 255. * stop_f);
6956  break;
6957  case 1:
6958  stop_r = static_cast<unsigned int>(.5 + 255. * stop_q),
6959  stop_g = 255;
6960  break;
6961  case 2:
6962  stop_g = 255,
6963  stop_b = static_cast<unsigned int>(.5 + 255. * stop_f);
6964  break;
6965  case 3:
6966  stop_g = static_cast<unsigned int>(.5 + 255. * stop_q),
6967  stop_b = 255;
6968  break;
6969  case 4:
6970  stop_r = static_cast<unsigned int>(.5 + 255. * stop_f),
6971  stop_b = 255;
6972  break;
6973  case 5:
6974  stop_r = 255,
6975  stop_b = static_cast<unsigned int>(.5 + 255. * stop_q);
6976  break;
6977  default:
6978  break;
6979  }
6980 
6981  // define gradient
6982  out << " <linearGradient id=\"colorbar_" << index
6983  << "\" gradientUnits=\"userSpaceOnUse\" "
6984  << "x1=\"" << width + additional_width << "\" "
6985  << "y1=\""
6986  << static_cast<unsigned int>(.5 + (height / 100.) *
6987  (margin_in_percent + 29)) +
6988  (3 - index) * element_height
6989  << "\" "
6990  << "x2=\"" << width + additional_width << "\" "
6991  << "y2=\""
6992  << static_cast<unsigned int>(.5 + (height / 100.) *
6993  (margin_in_percent + 29)) +
6994  (4 - index) * element_height
6995  << "\""
6996  << ">" << '\n'
6997  << " <stop offset=\"0\" style=\"stop-color:rgb(" << start_r
6998  << "," << start_g << "," << start_b << ")\"/>" << '\n'
6999  << " <stop offset=\"1\" style=\"stop-color:rgb(" << stop_r
7000  << "," << stop_g << "," << stop_b << ")\"/>" << '\n'
7001  << " </linearGradient>" << '\n';
7002 
7003  // draw box corresponding to the gradient above
7004  out
7005  << " <rect"
7006  << " x=\"" << width + additional_width << "\" y=\""
7007  << static_cast<unsigned int>(.5 + (height / 100.) *
7008  (margin_in_percent + 29)) +
7009  (3 - index) * element_height
7010  << "\" width=\"" << element_width << "\" height=\""
7011  << element_height
7012  << "\" style=\"stroke:black; stroke-width:2; fill:url(#colorbar_"
7013  << index << ")\"/>" << '\n';
7014  }
7015 
7016  for (unsigned int index = 0; index < 5; index++)
7017  {
7018  out
7019  << " <text x=\""
7020  << width + additional_width +
7021  static_cast<unsigned int>(1.5 * element_width)
7022  << "\" y=\""
7023  << static_cast<unsigned int>(
7024  .5 + (height / 100.) * (margin_in_percent + 29) +
7025  (4. - index) * element_height + 30.)
7026  << "\""
7027  << " style=\"text-anchor:start; font-size:80; font-family:Helvetica";
7028 
7029  if (index == 0 || index == 4)
7030  out << "; font-weight:bold";
7031 
7032  out << "\">"
7033  << static_cast<float>(
7034  (static_cast<int>((z_min + index * (z_dimension / 4.)) *
7035  10000)) /
7036  10000.);
7037 
7038  if (index == 4)
7039  out << " max";
7040  if (index == 0)
7041  out << " min";
7042 
7043  out << "</text>" << '\n';
7044  }
7045  }
7046 
7047  // finalize the svg file
7048  out << '\n' << "</svg>";
7049  out.flush();
7050  }
7051 
7052 
7053 
7054  template <int dim, int spacedim>
7055  void
7057  const std::vector<Patch<dim, spacedim>> &patches,
7058  const std::vector<std::string> & data_names,
7059  const std::vector<
7060  std::tuple<unsigned int,
7061  unsigned int,
7062  std::string,
7064  &nonscalar_data_ranges,
7065  const Deal_II_IntermediateFlags & /*flags*/,
7066  std::ostream &out)
7067  {
7068  AssertThrow(out, ExcIO());
7069 
7070  // first write tokens indicating the template parameters. we need this in
7071  // here because we may want to read in data again even if we don't know in
7072  // advance the template parameters:
7073  out << dim << ' ' << spacedim << '\n';
7074 
7075  // then write a header
7076  out << "[deal.II intermediate format graphics data]" << '\n'
7077  << "[written by " << DEAL_II_PACKAGE_NAME << " "
7078  << DEAL_II_PACKAGE_VERSION << "]" << '\n'
7079  << "[Version: " << Deal_II_IntermediateFlags::format_version << "]"
7080  << '\n';
7081 
7082  out << data_names.size() << '\n';
7083  for (const auto &data_name : data_names)
7084  out << data_name << '\n';
7085 
7086  out << patches.size() << '\n';
7087  for (unsigned int i = 0; i < patches.size(); ++i)
7088  out << patches[i] << '\n';
7089 
7090  out << nonscalar_data_ranges.size() << '\n';
7091  for (const auto &nonscalar_data_range : nonscalar_data_ranges)
7092  out << std::get<0>(nonscalar_data_range) << ' '
7093  << std::get<1>(nonscalar_data_range) << '\n'
7094  << std::get<2>(nonscalar_data_range) << '\n';
7095 
7096  out << '\n';
7097  // make sure everything now gets to disk
7098  out.flush();
7099  }
7100 
7101 
7102 
7103  std::pair<unsigned int, unsigned int>
7105  {
7106  AssertThrow(input, ExcIO());
7107 
7108  unsigned int dim, spacedim;
7109  input >> dim >> spacedim;
7110 
7111  return std::make_pair(dim, spacedim);
7112  }
7113 } // namespace DataOutBase
7114 
7115 
7116 
7117 /* --------------------------- class DataOutInterface ---------------------- */
7118 
7119 
7120 template <int dim, int spacedim>
7122  : default_subdivisions(1)
7123  , default_fmt(DataOutBase::default_format)
7124 {}
7125 
7126 
7127 
7128 template <int dim, int spacedim>
7129 void
7131 {
7132  DataOutBase::write_dx(get_patches(),
7133  get_dataset_names(),
7134  get_nonscalar_data_ranges(),
7135  dx_flags,
7136  out);
7137 }
7138 
7139 
7140 
7141 template <int dim, int spacedim>
7142 void
7144 {
7145  DataOutBase::write_ucd(get_patches(),
7146  get_dataset_names(),
7147  get_nonscalar_data_ranges(),
7148  ucd_flags,
7149  out);
7150 }
7151 
7152 
7153 
7154 template <int dim, int spacedim>
7155 void
7157 {
7158  DataOutBase::write_gnuplot(get_patches(),
7159  get_dataset_names(),
7160  get_nonscalar_data_ranges(),
7161  gnuplot_flags,
7162  out);
7163 }
7164 
7165 
7166 
7167 template <int dim, int spacedim>
7168 void
7170 {
7171  DataOutBase::write_povray(get_patches(),
7172  get_dataset_names(),
7173  get_nonscalar_data_ranges(),
7174  povray_flags,
7175  out);
7176 }
7177 
7178 
7179 
7180 template <int dim, int spacedim>
7181 void
7183 {
7184  DataOutBase::write_eps(get_patches(),
7185  get_dataset_names(),
7186  get_nonscalar_data_ranges(),
7187  eps_flags,
7188  out);
7189 }
7190 
7191 
7192 
7193 template <int dim, int spacedim>
7194 void
7196 {
7197  DataOutBase::write_gmv(get_patches(),
7198  get_dataset_names(),
7199  get_nonscalar_data_ranges(),
7200  gmv_flags,
7201  out);
7202 }
7203 
7204 
7205 
7206 template <int dim, int spacedim>
7207 void
7209 {
7210  DataOutBase::write_tecplot(get_patches(),
7211  get_dataset_names(),
7212  get_nonscalar_data_ranges(),
7213  tecplot_flags,
7214  out);
7215 }
7216 
7217 
7218 
7219 template <int dim, int spacedim>
7220 void
7222 {
7223  DataOutBase::write_vtk(get_patches(),
7224  get_dataset_names(),
7225  get_nonscalar_data_ranges(),
7226  vtk_flags,
7227  out);
7228 }
7229 
7230 template <int dim, int spacedim>
7231 void
7233 {
7234  DataOutBase::write_vtu(get_patches(),
7235  get_dataset_names(),
7236  get_nonscalar_data_ranges(),
7237  vtk_flags,
7238  out);
7239 }
7240 
7241 template <int dim, int spacedim>
7242 void
7244 {
7245  DataOutBase::write_svg(get_patches(),
7246  get_dataset_names(),
7247  get_nonscalar_data_ranges(),
7248  svg_flags,
7249  out);
7250 }
7251 
7252 template <int dim, int spacedim>
7253 void
7255  const std::string &filename,
7256  const MPI_Comm & comm) const
7257 {
7258 #ifndef DEAL_II_WITH_MPI
7259  // without MPI fall back to the normal way to write a vtu file :
7260  (void)comm;
7261 
7262  std::ofstream f(filename);
7263  AssertThrow(f, ExcFileNotOpen(filename));
7264  write_vtu(f);
7265 #else
7266 
7267  const int myrank = Utilities::MPI::this_mpi_process(comm);
7268 
7269  MPI_Info info;
7270  int ierr = MPI_Info_create(&info);
7271  AssertThrowMPI(ierr);
7272  MPI_File fh;
7273  ierr = MPI_File_open(comm,
7274  DEAL_II_MPI_CONST_CAST(filename.c_str()),
7275  MPI_MODE_CREATE | MPI_MODE_WRONLY,
7276  info,
7277  &fh);
7278  AssertThrow(ierr == MPI_SUCCESS, ExcFileNotOpen(filename));
7279 
7280  ierr = MPI_File_set_size(fh, 0); // delete the file contents
7281  AssertThrowMPI(ierr);
7282  // this barrier is necessary, because otherwise others might already write
7283  // while one core is still setting the size to zero.
7284  ierr = MPI_Barrier(comm);
7285  AssertThrowMPI(ierr);
7286  ierr = MPI_Info_free(&info);
7287  AssertThrowMPI(ierr);
7288 
7289  unsigned int header_size;
7290 
7291  // write header
7292  if (myrank == 0)
7293  {
7294  std::stringstream ss;
7295  DataOutBase::write_vtu_header(ss, vtk_flags);
7296  header_size = ss.str().size();
7297  ierr = MPI_File_write(fh,
7298  DEAL_II_MPI_CONST_CAST(ss.str().c_str()),
7299  header_size,
7300  MPI_CHAR,
7301  MPI_STATUS_IGNORE);
7302  AssertThrowMPI(ierr);
7303  }
7304 
7305  ierr = MPI_Bcast(&header_size, 1, MPI_UNSIGNED, 0, comm);
7306  AssertThrowMPI(ierr);
7307 
7308  ierr = MPI_File_seek_shared(fh, header_size, MPI_SEEK_SET);
7309  AssertThrowMPI(ierr);
7310  {
7311  const auto &patches = get_patches();
7312  const types::global_dof_index my_n_patches = patches.size();
7313  const types::global_dof_index global_n_patches =
7314  Utilities::MPI::sum(my_n_patches, comm);
7315 
7316  // Do not write pieces with 0 cells as this will crash paraview if this is
7317  // the first piece written. But if nobody has any pieces to write (file is
7318  // empty), let processor 0 write their empty data, otherwise the vtk file is
7319  // invalid.
7320  std::stringstream ss;
7321  if (my_n_patches > 0 || (global_n_patches == 0 && myrank == 0))
7323  get_dataset_names(),
7324  get_nonscalar_data_ranges(),
7325  vtk_flags,
7326  ss);
7327 
7328  ierr = MPI_File_write_ordered(fh,
7329  DEAL_II_MPI_CONST_CAST(ss.str().c_str()),
7330  ss.str().size(),
7331  MPI_CHAR,
7332  MPI_STATUS_IGNORE);
7333  AssertThrowMPI(ierr);
7334  }
7335 
7336  // write footer
7337  if (myrank == 0)
7338  {
7339  std::stringstream ss;
7341  unsigned int footer_size = ss.str().size();
7342  ierr = MPI_File_write_shared(fh,
7343  DEAL_II_MPI_CONST_CAST(ss.str().c_str()),
7344  footer_size,
7345  MPI_CHAR,
7346  MPI_STATUS_IGNORE);
7347  AssertThrowMPI(ierr);
7348  }
7349  ierr = MPI_File_close(&fh);
7350  AssertThrowMPI(ierr);
7351 #endif
7352 }
7353 
7354 
7355 template <int dim, int spacedim>
7356 void
7358  std::ostream & out,
7359  const std::vector<std::string> &piece_names) const
7360 {
7362  piece_names,
7363  get_dataset_names(),
7364  get_nonscalar_data_ranges());
7365 }
7366 
7367 
7368 template <int dim, int spacedim>
7369 std::string
7371  const std::string &directory,
7372  const std::string &filename_without_extension,
7373  const unsigned int counter,
7374  const MPI_Comm & mpi_communicator,
7375  const unsigned int n_digits_for_counter,
7376  const unsigned int n_groups) const
7377 {
7378  const unsigned int rank = Utilities::MPI::this_mpi_process(mpi_communicator);
7379  const unsigned int n_ranks =
7380  Utilities::MPI::n_mpi_processes(mpi_communicator);
7381  const unsigned int n_files_written =
7382  (n_groups == 0 || n_groups > n_ranks) ? n_ranks : n_groups;
7383 
7384  Assert(n_files_written >= 1, ExcInternalError());
7385  // the "-1" is needed since we use C++ style counting starting with 0, so
7386  // writing 10 files means the filename runs from 0 to 9
7387  const unsigned int n_digits =
7388  Utilities::needed_digits(std::max(0, int(n_files_written) - 1));
7389 
7390  const unsigned int color = rank % n_files_written;
7391  const std::string filename =
7392  directory + filename_without_extension + "_" +
7393  Utilities::int_to_string(counter, n_digits_for_counter) + "." +
7394  Utilities::int_to_string(color, n_digits) + ".vtu";
7395 
7396  if (n_groups == 0 || n_groups > n_ranks)
7397  {
7398  // every processor writes one file
7399  std::ofstream output(filename.c_str());
7400  AssertThrow(output, ExcFileNotOpen(filename));
7401  this->write_vtu(output);
7402  }
7403  else if (n_groups == 1)
7404  {
7405  // write only a single data file in parallel
7406  this->write_vtu_in_parallel(filename.c_str(), mpi_communicator);
7407  }
7408  else
7409  {
7410 #ifdef DEAL_II_WITH_MPI
7411  // write n_groups data files
7412  MPI_Comm comm_group;
7413  int ierr = MPI_Comm_split(mpi_communicator, color, rank, &comm_group);
7414  AssertThrowMPI(ierr);
7415  this->write_vtu_in_parallel(filename.c_str(), comm_group);
7416  ierr = MPI_Comm_free(&comm_group);
7417  AssertThrowMPI(ierr);
7418 #else
7419  AssertThrow(false, ExcMessage("Logical error. Should not arrive here."));
7420 #endif
7421  }
7422 
7423  // write pvtu record
7424  const std::string pvtu_filename =
7425  filename_without_extension + "_" +
7426  Utilities::int_to_string(counter, n_digits_for_counter) + ".pvtu";
7427 
7428  if (rank == 0)
7429  {
7430  std::vector<std::string> filename_vector;
7431  for (unsigned int i = 0; i < n_files_written; ++i)
7432  {
7433  const std::string filename =
7434  filename_without_extension + "_" +
7435  Utilities::int_to_string(counter, n_digits_for_counter) + "." +
7436  Utilities::int_to_string(i, n_digits) + ".vtu";
7437 
7438  filename_vector.emplace_back(filename);
7439  }
7440 
7441  std::ofstream pvtu_output((directory + pvtu_filename).c_str());
7442  this->write_pvtu_record(pvtu_output, filename_vector);
7443  }
7444 
7445  return pvtu_filename;
7446 }
7447 
7448 
7449 
7450 template <int dim, int spacedim>
7451 void
7453  std::ostream &out) const
7454 {
7456  get_dataset_names(),
7457  get_nonscalar_data_ranges(),
7458  deal_II_intermediate_flags,
7459  out);
7460 }
7461 
7462 
7463 template <int dim, int spacedim>
7464 XDMFEntry
7466  const DataOutBase::DataOutFilter &data_filter,
7467  const std::string & h5_filename,
7468  const double cur_time,
7469  const MPI_Comm & comm) const
7470 {
7471  return create_xdmf_entry(
7472  data_filter, h5_filename, h5_filename, cur_time, comm);
7473 }
7474 
7475 
7476 
7477 template <int dim, int spacedim>
7478 XDMFEntry
7480  const DataOutBase::DataOutFilter &data_filter,
7481  const std::string & h5_mesh_filename,
7482  const std::string & h5_solution_filename,
7483  const double cur_time,
7484  const MPI_Comm & comm) const
7485 {
7486  unsigned int local_node_cell_count[2], global_node_cell_count[2];
7487 
7488 #ifndef DEAL_II_WITH_HDF5
7489  // throw an exception, but first make sure the compiler does not warn about
7490  // the now unused function arguments
7491  (void)data_filter;
7492  (void)h5_mesh_filename;
7493  (void)h5_solution_filename;
7494  (void)cur_time;
7495  (void)comm;
7496  AssertThrow(false, ExcMessage("XDMF support requires HDF5 to be turned on."));
7497 #endif
7498  AssertThrow(spacedim == 2 || spacedim == 3,
7499  ExcMessage("XDMF only supports 2 or 3 space dimensions."));
7500 
7501  local_node_cell_count[0] = data_filter.n_nodes();
7502  local_node_cell_count[1] = data_filter.n_cells();
7503 
7504  // And compute the global total
7505 #ifdef DEAL_II_WITH_MPI
7506  const int myrank = Utilities::MPI::this_mpi_process(comm);
7507  int ierr = MPI_Allreduce(local_node_cell_count,
7508  global_node_cell_count,
7509  2,
7510  MPI_UNSIGNED,
7511  MPI_SUM,
7512  comm);
7513  AssertThrowMPI(ierr);
7514 #else
7515  (void)comm;
7516  const int myrank = 0;
7517  global_node_cell_count[0] = local_node_cell_count[0];
7518  global_node_cell_count[1] = local_node_cell_count[1];
7519 #endif
7520 
7521  // Output the XDMF file only on the root process
7522  if (myrank == 0)
7523  {
7524  XDMFEntry entry(h5_mesh_filename,
7525  h5_solution_filename,
7526  cur_time,
7527  global_node_cell_count[0],
7528  global_node_cell_count[1],
7529  dim,
7530  spacedim);
7531  unsigned int n_data_sets = data_filter.n_data_sets();
7532 
7533  // The vector names generated here must match those generated in the HDF5
7534  // file
7535  unsigned int i;
7536  for (i = 0; i < n_data_sets; ++i)
7537  {
7538  entry.add_attribute(data_filter.get_data_set_name(i),
7539  data_filter.get_data_set_dim(i));
7540  }
7541 
7542  return entry;
7543  }
7544  else
7545  {
7546  return {};
7547  }
7548 }
7549 
7550 template <int dim, int spacedim>
7551 void
7553  const std::vector<XDMFEntry> &entries,
7554  const std::string & filename,
7555  const MPI_Comm & comm) const
7556 {
7557 #ifdef DEAL_II_WITH_MPI
7558  const int myrank = Utilities::MPI::this_mpi_process(comm);
7559 #else
7560  (void)comm;
7561  const int myrank = 0;
7562 #endif
7563 
7564  // Only rank 0 process writes the XDMF file
7565  if (myrank == 0)
7566  {
7567  std::ofstream xdmf_file(filename.c_str());
7568  std::vector<XDMFEntry>::const_iterator it;
7569 
7570  xdmf_file << "<?xml version=\"1.0\" ?>\n";
7571  xdmf_file << "<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\" []>\n";
7572  xdmf_file << "<Xdmf Version=\"2.0\">\n";
7573  xdmf_file << " <Domain>\n";
7574  xdmf_file
7575  << " <Grid Name=\"CellTime\" GridType=\"Collection\" CollectionType=\"Temporal\">\n";
7576 
7577  // Write out all the entries indented
7578  const auto &patches = get_patches();
7579  Assert(patches.size() > 0, DataOutBase::ExcNoPatches());
7580 
7581  for (it = entries.begin(); it != entries.end(); ++it)
7582  {
7583  xdmf_file << it->get_xdmf_content(3, patches[0].reference_cell);
7584  }
7585 
7586  xdmf_file << " </Grid>\n";
7587  xdmf_file << " </Domain>\n";
7588  xdmf_file << "</Xdmf>\n";
7589 
7590  xdmf_file.close();
7591  }
7592 }
7593 
7594 
7595 
7596 /*
7597  * Write the data in this DataOutInterface to a DataOutFilter object. Filtering
7598  * is performed based on the DataOutFilter flags.
7599  */
7600 template <int dim, int spacedim>
7601 void
7603  DataOutBase::DataOutFilter &filtered_data) const
7604 {
7605  DataOutBase::write_filtered_data(get_patches(),
7606  get_dataset_names(),
7607  get_nonscalar_data_ranges(),
7608  filtered_data);
7609 }
7610 
7611 
7612 
7613 template <int dim, int spacedim>
7614 void
7616  const std::vector<Patch<dim, spacedim>> &patches,
7617  const std::vector<std::string> & data_names,
7618  const std::vector<
7619  std::tuple<unsigned int,
7620  unsigned int,
7621  std::string,
7623  & nonscalar_data_ranges,
7624  DataOutBase::DataOutFilter &filtered_data)
7625 {
7626  const unsigned int n_data_sets = data_names.size();
7627  unsigned int n_node, n_cell;
7628  Table<2, double> data_vectors;
7629  Threads::Task<> reorder_task;
7630 
7631 #ifndef DEAL_II_WITH_MPI
7632  // verify that there are indeed patches to be written out. most of the times,
7633  // people just forget to call build_patches when there are no patches, so a
7634  // warning is in order. that said, the assertion is disabled if we support MPI
7635  // since then it can happen that on the coarsest mesh, a processor simply has
7636  // no cells it actually owns, and in that case it is legit if there are no
7637  // patches
7638  Assert(patches.size() > 0, ExcNoPatches());
7639 #else
7640  if (patches.size() == 0)
7641  return;
7642 #endif
7643 
7644  compute_sizes<dim, spacedim>(patches, n_node, n_cell);
7645 
7646  data_vectors = Table<2, double>(n_data_sets, n_node);
7647  void (*fun_ptr)(const std::vector<Patch<dim, spacedim>> &,
7648  Table<2, double> &) =
7649  &DataOutBase::template write_gmv_reorder_data_vectors<dim, spacedim>;
7650  reorder_task = Threads::new_task(fun_ptr, patches, data_vectors);
7651 
7652  // Write the nodes/cells to the DataOutFilter object.
7653  write_nodes(patches, filtered_data);
7654  write_cells(patches, filtered_data);
7655 
7656  // Ensure reordering is done before we output data set values
7657  reorder_task.join();
7658 
7659  // when writing, first write out all vector data, then handle the scalar data
7660  // sets that have been left over
7661  unsigned int i, n_th_vector, data_set, pt_data_vector_dim;
7662  std::string vector_name;
7663  for (n_th_vector = 0, data_set = 0; data_set < n_data_sets;)
7664  {
7665  // Advance n_th_vector to at least the current data set we are on
7666  while (n_th_vector < nonscalar_data_ranges.size() &&
7667  std::get<0>(nonscalar_data_ranges[n_th_vector]) < data_set)
7668  n_th_vector++;
7669 
7670  // Determine the dimension of this data
7671  if (n_th_vector < nonscalar_data_ranges.size() &&
7672  std::get<0>(nonscalar_data_ranges[n_th_vector]) == data_set)
7673  {
7674  // Multiple dimensions
7675  pt_data_vector_dim = std::get<1>(nonscalar_data_ranges[n_th_vector]) -
7676  std::get<0>(nonscalar_data_ranges[n_th_vector]) +
7677  1;
7678 
7679  // Ensure the dimensionality of the data is correct
7680  AssertThrow(
7681  std::get<1>(nonscalar_data_ranges[n_th_vector]) >=
7682  std::get<0>(nonscalar_data_ranges[n_th_vector]),
7683  ExcLowerRange(std::get<1>(nonscalar_data_ranges[n_th_vector]),
7684  std::get<0>(nonscalar_data_ranges[n_th_vector])));
7685  AssertThrow(
7686  std::get<1>(nonscalar_data_ranges[n_th_vector]) < n_data_sets,
7687  ExcIndexRange(std::get<1>(nonscalar_data_ranges[n_th_vector]),
7688  0,
7689  n_data_sets));
7690 
7691  // Determine the vector name. Concatenate all the component names with
7692  // double underscores unless a vector name has been specified
7693  if (!std::get<2>(nonscalar_data_ranges[n_th_vector]).empty())
7694  {
7695  vector_name = std::get<2>(nonscalar_data_ranges[n_th_vector]);
7696  }
7697  else
7698  {
7699  vector_name = "";
7700  for (i = std::get<0>(nonscalar_data_ranges[n_th_vector]);
7701  i < std::get<1>(nonscalar_data_ranges[n_th_vector]);
7702  ++i)
7703  vector_name += data_names[i] + "__";
7704  vector_name +=
7705  data_names[std::get<1>(nonscalar_data_ranges[n_th_vector])];
7706  }
7707  }
7708  else
7709  {
7710  // One dimension
7711  pt_data_vector_dim = 1;
7712  vector_name = data_names[data_set];
7713  }
7714 
7715  // Write data to the filter object
7716  filtered_data.write_data_set(vector_name,
7717  pt_data_vector_dim,
7718  data_set,
7719  data_vectors);
7720 
7721  // Advance the current data set
7722  data_set += pt_data_vector_dim;
7723  }
7724 }
7725 
7726 
7727 
7728 template <int dim, int spacedim>
7729 void
7731  const DataOutBase::DataOutFilter &data_filter,
7732  const std::string & filename,
7733  const MPI_Comm & comm) const
7734 {
7735  DataOutBase::write_hdf5_parallel(get_patches(), data_filter, filename, comm);
7736 }
7737 
7738 
7739 
7740 template <int dim, int spacedim>
7741 void
7743  const DataOutBase::DataOutFilter &data_filter,
7744  const bool write_mesh_file,
7745  const std::string & mesh_filename,
7746  const std::string & solution_filename,
7747  const MPI_Comm & comm) const
7748 {
7749  DataOutBase::write_hdf5_parallel(get_patches(),
7750  data_filter,
7751  write_mesh_file,
7752  mesh_filename,
7753  solution_filename,
7754  comm);
7755 }
7756 
7757 
7758 
7759 template <int dim, int spacedim>
7760 void
7762  const std::vector<Patch<dim, spacedim>> &patches,
7763  const DataOutBase::DataOutFilter & data_filter,
7764  const std::string & filename,
7765  const MPI_Comm & comm)
7766 {
7767  write_hdf5_parallel(patches, data_filter, true, filename, filename, comm);
7768 }
7769 
7770 
7771 
7772 template <int dim, int spacedim>
7773 void
7775  const std::vector<Patch<dim, spacedim>> &patches,
7776  const DataOutBase::DataOutFilter & data_filter,
7777  const bool write_mesh_file,
7778  const std::string & mesh_filename,
7779  const std::string & solution_filename,
7780  const MPI_Comm & comm)
7781 {
7782  AssertThrow(
7783  spacedim >= 2,
7784  ExcMessage(
7785  "DataOutBase was asked to write HDF5 output for a space dimension of 1. "
7786  "HDF5 only supports datasets that live in 2 or 3 dimensions."));
7787 
7788  int ierr = 0;
7789  (void)ierr;
7790 #ifndef DEAL_II_WITH_HDF5
7791  // throw an exception, but first make sure the compiler does not warn about
7792  // the now unused function arguments
7793  (void)patches;
7794  (void)data_filter;
7795  (void)write_mesh_file;
7796  (void)mesh_filename;
7797  (void)solution_filename;
7798  (void)comm;
7799  AssertThrow(false, ExcMessage("HDF5 support is disabled."));
7800 #else
7801 # ifndef DEAL_II_WITH_MPI
7802  (void)comm;
7803 # endif
7804 
7805  // verify that there are indeed patches to be written out. most of the times,
7806  // people just forget to call build_patches when there are no patches, so a
7807  // warning is in order. that said, the assertion is disabled if we support MPI
7808  // since then it can happen that on the coarsest mesh, a processor simply has
7809  // no cells it actually owns, and in that case it is legit if there are no
7810  // patches
7811  Assert(patches.size() > 0, ExcNoPatches());
7812 
7813  hid_t h5_mesh_file_id = -1, h5_solution_file_id, file_plist_id, plist_id;
7814  hid_t node_dataspace, node_dataset, node_file_dataspace,
7815  node_memory_dataspace;
7816  hid_t cell_dataspace, cell_dataset, cell_file_dataspace,
7817  cell_memory_dataspace;
7818  hid_t pt_data_dataspace, pt_data_dataset, pt_data_file_dataspace,
7819  pt_data_memory_dataspace;
7820  herr_t status;
7821  unsigned int local_node_cell_count[2];
7822  hsize_t count[2], offset[2], node_ds_dim[2], cell_ds_dim[2];
7823  std::vector<double> node_data_vec;
7824  std::vector<unsigned int> cell_data_vec;
7825 
7826  // If HDF5 is not parallel and we're using multiple processes, abort
7827 # ifndef H5_HAVE_PARALLEL
7828 # ifdef DEAL_II_WITH_MPI
7829  int world_size = Utilities::MPI::n_mpi_processes(comm);
7830  AssertThrow(
7831  world_size <= 1,
7832  ExcMessage(
7833  "Serial HDF5 output on multiple processes is not yet supported."));
7834 # endif
7835 # endif
7836 
7837  local_node_cell_count[0] = data_filter.n_nodes();
7838  local_node_cell_count[1] = data_filter.n_cells();
7839 
7840  // Create file access properties
7841  file_plist_id = H5Pcreate(H5P_FILE_ACCESS);
7842  AssertThrow(file_plist_id != -1, ExcIO());
7843  // If MPI is enabled *and* HDF5 is parallel, we can do parallel output
7844 # ifdef DEAL_II_WITH_MPI
7845 # ifdef H5_HAVE_PARALLEL
7846  // Set the access to use the specified MPI_Comm object
7847  status = H5Pset_fapl_mpio(file_plist_id, comm, MPI_INFO_NULL);
7848  AssertThrow(status >= 0, ExcIO());
7849 # endif
7850 # endif
7851 
7852  // Compute the global total number of nodes/cells and determine the offset of
7853  // the data for this process
7854 
7855  unsigned int global_node_cell_count[2] = {0, 0};
7856  unsigned int global_node_cell_offsets[2] = {0, 0};
7857 
7858 # ifdef DEAL_II_WITH_MPI
7859  ierr = MPI_Allreduce(local_node_cell_count,
7860  global_node_cell_count,
7861  2,
7862  MPI_UNSIGNED,
7863  MPI_SUM,
7864  comm);
7865  AssertThrowMPI(ierr);
7866  ierr = MPI_Exscan(local_node_cell_count,
7867  global_node_cell_offsets,
7868  2,
7869  MPI_UNSIGNED,
7870  MPI_SUM,
7871  comm);
7872  AssertThrowMPI(ierr);
7873 # else
7874  global_node_cell_count[0] = local_node_cell_count[0];
7875  global_node_cell_count[1] = local_node_cell_count[1];
7876  global_node_cell_offsets[0] = global_node_cell_offsets[1] = 0;
7877 # endif
7878 
7879  // Create the property list for a collective write
7880  plist_id = H5Pcreate(H5P_DATASET_XFER);
7881  AssertThrow(plist_id >= 0, ExcIO());
7882 # ifdef DEAL_II_WITH_MPI
7883 # ifdef H5_HAVE_PARALLEL
7884  status = H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE);
7885  AssertThrow(status >= 0, ExcIO());
7886 # endif
7887 # endif
7888 
7889  if (write_mesh_file)
7890  {
7891  // Overwrite any existing files (change this to an option?)
7892  h5_mesh_file_id = H5Fcreate(mesh_filename.c_str(),
7893  H5F_ACC_TRUNC,
7894  H5P_DEFAULT,
7895  file_plist_id);
7896  AssertThrow(h5_mesh_file_id >= 0, ExcIO());
7897 
7898  // Create the dataspace for the nodes and cells. HDF5 only supports 2- or
7899  // 3-dimensional coordinates
7900  node_ds_dim[0] = global_node_cell_count[0];
7901  node_ds_dim[1] = (spacedim < 2) ? 2 : spacedim;
7902  node_dataspace = H5Screate_simple(2, node_ds_dim, nullptr);
7903  AssertThrow(node_dataspace >= 0, ExcIO());
7904 
7905  cell_ds_dim[0] = global_node_cell_count[1];
7906  cell_ds_dim[1] = patches[0].reference_cell.n_vertices();
7907  cell_dataspace = H5Screate_simple(2, cell_ds_dim, nullptr);
7908  AssertThrow(cell_dataspace >= 0, ExcIO());
7909 
7910  // Create the dataset for the nodes and cells
7911 # if H5Gcreate_vers == 1
7912  node_dataset = H5Dcreate(h5_mesh_file_id,
7913  "nodes",
7914  H5T_NATIVE_DOUBLE,
7915  node_dataspace,
7916  H5P_DEFAULT);
7917 # else
7918  node_dataset = H5Dcreate(h5_mesh_file_id,
7919  "nodes",
7920  H5T_NATIVE_DOUBLE,
7921  node_dataspace,
7922  H5P_DEFAULT,
7923  H5P_DEFAULT,
7924  H5P_DEFAULT);
7925 # endif
7926  AssertThrow(node_dataset >= 0, ExcIO());
7927 # if H5Gcreate_vers == 1
7928  cell_dataset = H5Dcreate(
7929  h5_mesh_file_id, "cells", H5T_NATIVE_UINT, cell_dataspace, H5P_DEFAULT);
7930 # else
7931  cell_dataset = H5Dcreate(h5_mesh_file_id,
7932  "cells",
7933  H5T_NATIVE_UINT,
7934  cell_dataspace,
7935  H5P_DEFAULT,
7936  H5P_DEFAULT,
7937  H5P_DEFAULT);
7938 # endif
7939  AssertThrow(cell_dataset >= 0, ExcIO());
7940 
7941  // Close the node and cell dataspaces since we're done with them
7942  status = H5Sclose(node_dataspace);
7943  AssertThrow(status >= 0, ExcIO());
7944  status = H5Sclose(cell_dataspace);
7945  AssertThrow(status >= 0, ExcIO());
7946 
7947  // Create the data subset we'll use to read from memory. HDF5 only
7948  // supports 2- or 3-dimensional coordinates
7949  count[0] = local_node_cell_count[0];
7950  count[1] = (spacedim < 2) ? 2 : spacedim;
7951 
7952  offset[0] = global_node_cell_offsets[0];
7953  offset[1] = 0;
7954 
7955  node_memory_dataspace = H5Screate_simple(2, count, nullptr);
7956  AssertThrow(node_memory_dataspace >= 0, ExcIO());
7957 
7958  // Select the hyperslab in the file
7959  node_file_dataspace = H5Dget_space(node_dataset);
7960  AssertThrow(node_file_dataspace >= 0, ExcIO());
7961  status = H5Sselect_hyperslab(
7962  node_file_dataspace, H5S_SELECT_SET, offset, nullptr, count, nullptr);
7963  AssertThrow(status >= 0, ExcIO());
7964 
7965  // And repeat for cells
7966  count[0] = local_node_cell_count[1];
7967  count[1] = patches[0].reference_cell.n_vertices();
7968  offset[0] = global_node_cell_offsets[1];
7969  offset[1] = 0;
7970  cell_memory_dataspace = H5Screate_simple(2, count, nullptr);
7971  AssertThrow(cell_memory_dataspace >= 0, ExcIO());
7972 
7973  cell_file_dataspace = H5Dget_space(cell_dataset);
7974  AssertThrow(cell_file_dataspace >= 0, ExcIO());
7975  status = H5Sselect_hyperslab(
7976  cell_file_dataspace, H5S_SELECT_SET, offset, nullptr, count, nullptr);
7977  AssertThrow(status >= 0, ExcIO());
7978 
7979  // And finally, write the node data
7980  data_filter.fill_node_data(node_data_vec);
7981  status = H5Dwrite(node_dataset,
7982  H5T_NATIVE_DOUBLE,
7983  node_memory_dataspace,
7984  node_file_dataspace,
7985  plist_id,
7986  node_data_vec.data());
7987  AssertThrow(status >= 0, ExcIO());
7988  node_data_vec.clear();
7989 
7990  // And the cell data
7991  data_filter.fill_cell_data(global_node_cell_offsets[0], cell_data_vec);
7992  status = H5Dwrite(cell_dataset,
7993  H5T_NATIVE_UINT,
7994  cell_memory_dataspace,
7995  cell_file_dataspace,
7996  plist_id,
7997  cell_data_vec.data());
7998  AssertThrow(status >= 0, ExcIO());
7999  cell_data_vec.clear();
8000 
8001  // Close the file dataspaces
8002  status = H5Sclose(node_file_dataspace);
8003  AssertThrow(status >= 0, ExcIO());
8004  status = H5Sclose(cell_file_dataspace);
8005  AssertThrow(status >= 0, ExcIO());
8006 
8007  // Close the memory dataspaces
8008  status = H5Sclose(node_memory_dataspace);
8009  AssertThrow(status >= 0, ExcIO());
8010  status = H5Sclose(cell_memory_dataspace);
8011  AssertThrow(status >= 0, ExcIO());
8012 
8013  // Close the datasets
8014  status = H5Dclose(node_dataset);
8015  AssertThrow(status >= 0, ExcIO());
8016  status = H5Dclose(cell_dataset);
8017  AssertThrow(status >= 0, ExcIO());
8018 
8019  // If the filenames are different, we need to close the mesh file
8020  if (mesh_filename != solution_filename)
8021  {
8022  status = H5Fclose(h5_mesh_file_id);
8023  AssertThrow(status >= 0, ExcIO());
8024  }
8025  }
8026 
8027  // If the filenames are identical, continue with the same file
8028  if (mesh_filename == solution_filename && write_mesh_file)
8029  {
8030  h5_solution_file_id = h5_mesh_file_id;
8031  }
8032  else
8033  {
8034  // Otherwise we need to open a new file
8035  h5_solution_file_id = H5Fcreate(solution_filename.c_str(),
8036  H5F_ACC_TRUNC,
8037  H5P_DEFAULT,
8038  file_plist_id);
8039  AssertThrow(h5_solution_file_id >= 0, ExcIO());
8040  }
8041 
8042  // when writing, first write out all vector data, then handle the scalar data
8043  // sets that have been left over
8044  unsigned int i;
8045  std::string vector_name;
8046  for (i = 0; i < data_filter.n_data_sets(); ++i)
8047  {
8048  // Allocate space for the point data
8049  // Must be either 1D or 3D
8050  const unsigned int pt_data_vector_dim = data_filter.get_data_set_dim(i);
8051  vector_name = data_filter.get_data_set_name(i);
8052 
8053  // Create the dataspace for the point data
8054  node_ds_dim[0] = global_node_cell_count[0];
8055  node_ds_dim[1] = pt_data_vector_dim;
8056  pt_data_dataspace = H5Screate_simple(2, node_ds_dim, nullptr);
8057  AssertThrow(pt_data_dataspace >= 0, ExcIO());
8058 
8059 # if H5Gcreate_vers == 1
8060  pt_data_dataset = H5Dcreate(h5_solution_file_id,
8061  vector_name.c_str(),
8062  H5T_NATIVE_DOUBLE,
8063  pt_data_dataspace,
8064  H5P_DEFAULT);
8065 # else
8066  pt_data_dataset = H5Dcreate(h5_solution_file_id,
8067  vector_name.c_str(),
8068  H5T_NATIVE_DOUBLE,
8069  pt_data_dataspace,
8070  H5P_DEFAULT,
8071  H5P_DEFAULT,
8072  H5P_DEFAULT);
8073 # endif
8074  AssertThrow(pt_data_dataset >= 0, ExcIO());
8075 
8076  // Create the data subset we'll use to read from memory
8077  count[0] = local_node_cell_count[0];
8078  count[1] = pt_data_vector_dim;
8079  offset[0] = global_node_cell_offsets[0];
8080  offset[1] = 0;
8081  pt_data_memory_dataspace = H5Screate_simple(2, count, nullptr);
8082  AssertThrow(pt_data_memory_dataspace >= 0, ExcIO());
8083 
8084  // Select the hyperslab in the file
8085  pt_data_file_dataspace = H5Dget_space(pt_data_dataset);
8086  AssertThrow(pt_data_file_dataspace >= 0, ExcIO());
8087  status = H5Sselect_hyperslab(pt_data_file_dataspace,
8088  H5S_SELECT_SET,
8089  offset,
8090  nullptr,
8091  count,
8092  nullptr);
8093  AssertThrow(status >= 0, ExcIO());
8094 
8095  // And finally, write the data
8096  status = H5Dwrite(pt_data_dataset,
8097  H5T_NATIVE_DOUBLE,
8098  pt_data_memory_dataspace,
8099  pt_data_file_dataspace,
8100  plist_id,
8101  data_filter.get_data_set(i));
8102  AssertThrow(status >= 0, ExcIO());
8103 
8104  // Close the dataspaces
8105  status = H5Sclose(pt_data_dataspace);
8106  AssertThrow(status >= 0, ExcIO());
8107  status = H5Sclose(pt_data_memory_dataspace);
8108  AssertThrow(status >= 0, ExcIO());
8109  status = H5Sclose(pt_data_file_dataspace);
8110  AssertThrow(status >= 0, ExcIO());
8111  // Close the dataset
8112  status = H5Dclose(pt_data_dataset);
8113  AssertThrow(status >= 0, ExcIO());
8114  }
8115 
8116  // Close the file property list
8117  status = H5Pclose(file_plist_id);
8118  AssertThrow(status >= 0, ExcIO());
8119 
8120  // Close the parallel access
8121  status = H5Pclose(plist_id);
8122  AssertThrow(status >= 0, ExcIO());
8123 
8124  // Close the file
8125  status = H5Fclose(h5_solution_file_id);
8126  AssertThrow(status >= 0, ExcIO());
8127 #endif
8128 }
8129 
8130 
8131 
8132 template <int dim, int spacedim>
8133 void
8135  std::ostream & out,
8136  const DataOutBase::OutputFormat output_format_) const
8137 {
8138  DataOutBase::OutputFormat output_format = output_format_;
8139  if (output_format == DataOutBase::default_format)
8140  output_format = default_fmt;
8141 
8142  switch (output_format)
8143  {
8144  case DataOutBase::none:
8145  break;
8146 
8147  case DataOutBase::dx:
8148  write_dx(out);
8149  break;
8150 
8151  case DataOutBase::ucd:
8152  write_ucd(out);
8153  break;
8154 
8155  case DataOutBase::gnuplot:
8156  write_gnuplot(out);
8157  break;
8158 
8159  case DataOutBase::povray:
8160  write_povray(out);
8161  break;
8162 
8163  case DataOutBase::eps:
8164  write_eps(out);
8165  break;
8166 
8167  case DataOutBase::gmv:
8168  write_gmv(out);
8169  break;
8170 
8171  case DataOutBase::tecplot:
8172  write_tecplot(out);
8173  break;
8174 
8175  case DataOutBase::vtk:
8176  write_vtk(out);
8177  break;
8178 
8179  case DataOutBase::vtu:
8180  write_vtu(out);
8181  break;
8182 
8183  case DataOutBase::svg:
8184  write_svg(out);
8185  break;
8186 
8189  break;
8190 
8191  default:
8192  Assert(false, ExcNotImplemented());
8193  }
8194 }
8195 
8196 
8197 
8198 template <int dim, int spacedim>
8199 void
8201  const DataOutBase::OutputFormat fmt)
8202 {
8204  default_fmt = fmt;
8205 }
8206 
8207 template <int dim, int spacedim>
8208 template <typename FlagType>
8209 void
8211 {
8212  // The price for not writing ten duplicates of this function is some loss in
8213  // type safety.
8214  if (typeid(flags) == typeid(dx_flags))
8215  dx_flags = *reinterpret_cast<const DataOutBase::DXFlags *>(&flags);
8216  else if (typeid(flags) == typeid(ucd_flags))
8217  ucd_flags = *reinterpret_cast<const DataOutBase::UcdFlags *>(&flags);
8218  else if (typeid(flags) == typeid(povray_flags))
8219  povray_flags = *reinterpret_cast<const DataOutBase::PovrayFlags *>(&flags);
8220  else if (typeid(flags) == typeid(eps_flags))
8221  eps_flags = *reinterpret_cast<const DataOutBase::EpsFlags *>(&flags);
8222  else if (typeid(flags) == typeid(gmv_flags))
8223  gmv_flags = *reinterpret_cast<const DataOutBase::GmvFlags *>(&flags);
8224  else if (typeid(flags) == typeid(tecplot_flags))
8225  tecplot_flags =
8226  *reinterpret_cast<const DataOutBase::TecplotFlags *>(&flags);
8227  else if (typeid(flags) == typeid(vtk_flags))
8228  vtk_flags = *reinterpret_cast<const DataOutBase::VtkFlags *>(&flags);
8229  else if (typeid(flags) == typeid(svg_flags))
8230  svg_flags = *reinterpret_cast<const DataOutBase::SvgFlags *>(&flags);
8231  else if (typeid(flags) == typeid(gnuplot_flags))
8232  gnuplot_flags =
8233  *reinterpret_cast<const DataOutBase::GnuplotFlags *>(&flags);
8234  else if (typeid(flags) == typeid(deal_II_intermediate_flags))
8235  deal_II_intermediate_flags =
8236  *reinterpret_cast<const DataOutBase::Deal_II_IntermediateFlags *>(&flags);
8237  else
8238  Assert(false, ExcNotImplemented());
8239 }
8240 
8241 
8242 
8243 template <int dim, int spacedim>
8244 std::string
8246  const DataOutBase::OutputFormat output_format) const
8247 {
8248  if (output_format == DataOutBase::default_format)
8249  return DataOutBase::default_suffix(default_fmt);
8250  else
8251  return DataOutBase::default_suffix(output_format);
8252 }
8253 
8254 
8255 
8256 template <int dim, int spacedim>
8257 void
8259 {
8260  prm.declare_entry("Output format",
8261  "gnuplot",
8263  "A name for the output format to be used");
8264  prm.declare_entry("Subdivisions",
8265  "1",
8267  "Number of subdivisions of each mesh cell");
8268 
8269  prm.enter_subsection("DX output parameters");
8271  prm.leave_subsection();
8272 
8273  prm.enter_subsection("UCD output parameters");
8275  prm.leave_subsection();
8276 
8277  prm.enter_subsection("Gnuplot output parameters");
8279  prm.leave_subsection();
8280 
8281  prm.enter_subsection("Povray output parameters");
8283  prm.leave_subsection();
8284 
8285  prm.enter_subsection("Eps output parameters");
8287  prm.leave_subsection();
8288 
8289  prm.enter_subsection("Gmv output parameters");
8291  prm.leave_subsection();
8292 
8293  prm.enter_subsection("Tecplot output parameters");
8295  prm.leave_subsection();
8296 
8297  prm.enter_subsection("Vtk output parameters");
8299  prm.leave_subsection();
8300 
8301 
8302  prm.enter_subsection("deal.II intermediate output parameters");
8304  prm.leave_subsection();
8305 }
8306 
8307 
8308 
8309 template <int dim, int spacedim>
8310 void
8312 {
8313  const std::string &output_name = prm.get("Output format");
8314  default_fmt = DataOutBase::parse_output_format(output_name);
8315  default_subdivisions = prm.get_integer("Subdivisions");
8316 
8317  prm.enter_subsection("DX output parameters");
8318  dx_flags.parse_parameters(prm);
8319  prm.leave_subsection();
8320 
8321  prm.enter_subsection("UCD output parameters");
8322  ucd_flags.parse_parameters(prm);
8323  prm.leave_subsection();
8324 
8325  prm.enter_subsection("Gnuplot output parameters");
8326  gnuplot_flags.parse_parameters(prm);
8327  prm.leave_subsection();
8328 
8329  prm.enter_subsection("Povray output parameters");
8330  povray_flags.parse_parameters(prm);
8331  prm.leave_subsection();
8332 
8333  prm.enter_subsection("Eps output parameters");
8334  eps_flags.parse_parameters(prm);
8335  prm.leave_subsection();
8336 
8337  prm.enter_subsection("Gmv output parameters");
8338  gmv_flags.parse_parameters(prm);
8339  prm.leave_subsection();
8340 
8341  prm.enter_subsection("Tecplot output parameters");
8342  tecplot_flags.parse_parameters(prm);
8343  prm.leave_subsection();
8344 
8345  prm.enter_subsection("Vtk output parameters");
8346  vtk_flags.parse_parameters(prm);
8347  prm.leave_subsection();
8348 
8349  prm.enter_subsection("deal.II intermediate output parameters");
8350  deal_II_intermediate_flags.parse_parameters(prm);
8351  prm.leave_subsection();
8352 }
8353 
8354 
8355 
8356 template <int dim, int spacedim>
8357 std::size_t
8359 {
8360  return (sizeof(default_fmt) +
8363  MemoryConsumption::memory_consumption(gnuplot_flags) +
8367  MemoryConsumption::memory_consumption(tecplot_flags) +
8370  MemoryConsumption::memory_consumption(deal_II_intermediate_flags));
8371 }
8372 
8373 
8374 
8375 template <int dim, int spacedim>
8376 std::vector<
8377  std::tuple<unsigned int,
8378  unsigned int,
8379  std::string,
8382 {
8383  return std::vector<
8384  std::tuple<unsigned int,
8385  unsigned int,
8386  std::string,
8388 }
8389 
8390 
8391 template <int dim, int spacedim>
8392 void
8394 {
8395 #ifdef DEBUG
8396  {
8397  // Check that names for datasets are only used once. This is somewhat
8398  // complicated, because vector ranges might have a name or not.
8399  std::set<std::string> all_names;
8400 
8401  const std::vector<
8402  std::tuple<unsigned int,
8403  unsigned int,
8404  std::string,
8406  ranges = this->get_nonscalar_data_ranges();
8407  const std::vector<std::string> data_names = this->get_dataset_names();
8408  const unsigned int n_data_sets = data_names.size();
8409  std::vector<bool> data_set_written(n_data_sets, false);
8410 
8411  for (const auto &range : ranges)
8412  {
8413  const std::string &name = std::get<2>(range);
8414  if (!name.empty())
8415  {
8416  Assert(all_names.find(name) == all_names.end(),
8417  ExcMessage(
8418  "Error: names of fields in DataOut need to be unique, "
8419  "but '" +
8420  name + "' is used more than once."));
8421  all_names.insert(name);
8422  for (unsigned int i = std::get<0>(range); i <= std::get<1>(range);
8423  ++i)
8424  data_set_written[i] = true;
8425  }
8426  }
8427 
8428  for (unsigned int data_set = 0; data_set < n_data_sets; ++data_set)
8429  if (data_set_written[data_set] == false)
8430  {
8431  const std::string &name = data_names[data_set];
8432  Assert(all_names.find(name) == all_names.end(),
8433  ExcMessage(
8434  "Error: names of fields in DataOut need to be unique, "
8435  "but '" +
8436  name + "' is used more than once."));
8437  all_names.insert(name);
8438  }
8439  }
8440 #endif
8441 }
8442 
8443 
8444 
8445 // ---------------------------------------------- DataOutReader ----------
8446 
8447 template <int dim, int spacedim>
8448 void
8450 {
8451  AssertThrow(in, ExcIO());
8452 
8453  // first empty previous content
8454  {
8455  std::vector<typename ::DataOutBase::Patch<dim, spacedim>> tmp;
8456  tmp.swap(patches);
8457  }
8458  {
8459  std::vector<std::string> tmp;
8460  tmp.swap(dataset_names);
8461  }
8462  {
8463  std::vector<
8464  std::tuple<unsigned int,
8465  unsigned int,
8466  std::string,
8468  tmp;
8469  tmp.swap(nonscalar_data_ranges);
8470  }
8471 
8472  // then check that we have the correct header of this file. both the first and
8473  // second real lines have to match, as well as the dimension information
8474  // written before that and the Version information written in the third line
8475  {
8476  std::pair<unsigned int, unsigned int> dimension_info =
8478  AssertThrow((dimension_info.first == dim) &&
8479  (dimension_info.second == spacedim),
8480  ExcIncompatibleDimensions(
8481  dimension_info.first, dim, dimension_info.second, spacedim));
8482 
8483  // read to the end of the line
8484  std::string tmp;
8485  getline(in, tmp);
8486  }
8487 
8488  {
8489  std::string header;
8490  getline(in, header);
8491 
8492  std::ostringstream s;
8493  s << "[deal.II intermediate format graphics data]";
8494 
8495  Assert(header == s.str(), ExcUnexpectedInput(s.str(), header));
8496  }
8497  {
8498  std::string header;
8499  getline(in, header);
8500 
8501  std::ostringstream s;
8502  s << "[written by " << DEAL_II_PACKAGE_NAME << " "
8503  << DEAL_II_PACKAGE_VERSION << "]";
8504 
8505  Assert(header == s.str(), ExcUnexpectedInput(s.str(), header));
8506  }
8507  {
8508  std::string header;
8509  getline(in, header);
8510 
8511  std::ostringstream s;
8512  s << "[Version: "
8514 
8515  Assert(header == s.str(),
8516  ExcMessage(
8517  "Invalid or incompatible file format. Intermediate format "
8518  "files can only be read by the same deal.II version as they "
8519  "are written by."));
8520  }
8521 
8522  // then read the rest of the data
8523  unsigned int n_datasets;
8524  in >> n_datasets;
8525  dataset_names.resize(n_datasets);
8526  for (unsigned int i = 0; i < n_datasets; ++i)
8527  in >> dataset_names[i];
8528 
8529  unsigned int n_patches;
8530  in >> n_patches;
8531  patches.resize(n_patches);
8532  for (unsigned int i = 0; i < n_patches; ++i)
8533  in >> patches[i];
8534 
8535  unsigned int n_nonscalar_data_ranges;
8536  in >> n_nonscalar_data_ranges;
8537  nonscalar_data_ranges.resize(n_nonscalar_data_ranges);
8538  for (unsigned int i = 0; i < n_nonscalar_data_ranges; ++i)
8539  {
8540  in >> std::get<0>(nonscalar_data_ranges[i]) >>
8541  std::get<1>(nonscalar_data_ranges[i]);
8542 
8543  // read in the name of that vector range. because it is on a separate
8544  // line, we first need to read to the end of the previous line (nothing
8545  // should be there any more after we've read the previous two integers)
8546  // and then read the entire next line for the name
8547  std::string name;
8548  getline(in, name);
8549  getline(in, name);
8550  std::get<2>(nonscalar_data_ranges[i]) = name;
8551  }
8552 
8553  AssertThrow(in, ExcIO());
8554 }
8555 
8556 
8557 
8558 template <int dim, int spacedim>
8559 void
8561 {
8562  using Patch = typename ::DataOutBase::Patch<dim, spacedim>;
8563 
8564 
8565  const std::vector<Patch> &source_patches = source.get_patches();
8566  Assert(patches.size() != 0, DataOutBase::ExcNoPatches());
8567  Assert(source_patches.size() != 0, DataOutBase::ExcNoPatches());
8568  // check equality of component names
8569  Assert(get_dataset_names() == source.get_dataset_names(),
8571 
8572  // check equality of the vector data specifications
8573  Assert(get_nonscalar_data_ranges().size() ==
8574  source.get_nonscalar_data_ranges().size(),
8575  ExcMessage("Both sources need to declare the same components "
8576  "as vectors."));
8577  for (unsigned int i = 0; i < get_nonscalar_data_ranges().size(); ++i)
8578  {
8579  Assert(std::get<0>(get_nonscalar_data_ranges()[i]) ==
8580  std::get<0>(source.get_nonscalar_data_ranges()[i]),
8581  ExcMessage("Both sources need to declare the same components "
8582  "as vectors."));
8583  Assert(std::get<1>(get_nonscalar_data_ranges()[i]) ==
8584  std::get<1>(source.get_nonscalar_data_ranges()[i]),
8585  ExcMessage("Both sources need to declare the same components "
8586  "as vectors."));
8587  Assert(std::get<2>(get_nonscalar_data_ranges()[i]) ==
8588  std::get<2>(source.get_nonscalar_data_ranges()[i]),
8589  ExcMessage("Both sources need to declare the same components "
8590  "as vectors."));
8591  }
8592 
8593  // make sure patches are compatible
8594  Assert(patches[0].n_subdivisions == source_patches[0].n_subdivisions,
8596  Assert(patches[0].data.n_rows() == source_patches[0].data.n_rows(),
8598  Assert(patches[0].data.n_cols() == source_patches[0].data.n_cols(),
8600 
8601  // merge patches. store old number of elements, since we need to adjust patch
8602  // numbers, etc afterwards
8603  const unsigned int old_n_patches = patches.size();
8604  patches.insert(patches.end(), source_patches.begin(), source_patches.end());
8605 
8606  // adjust patch numbers
8607  for (unsigned int i = old_n_patches; i < patches.size(); ++i)
8608  patches[i].patch_index += old_n_patches;
8609 
8610  // adjust patch neighbors
8611  for (unsigned int i = old_n_patches; i < patches.size(); ++i)
8612  for (unsigned int n : GeometryInfo<dim>::face_indices())
8613  if (patches[i].neighbors[n] !=
8615  patches[i].neighbors[n] += old_n_patches;
8616 }
8617 
8618 
8619 
8620 template <int dim, int spacedim>
8621 const std::vector<typename ::DataOutBase::Patch<dim, spacedim>> &
8623 {
8624  return patches;
8625 }
8626 
8627 
8628 
8629 template <int dim, int spacedim>
8630 std::vector<std::string>
8632 {
8633  return dataset_names;
8634 }
8635 
8636 
8637 
8638 template <int dim, int spacedim>
8639 std::vector<
8640  std::tuple<unsigned int,
8641  unsigned int,
8642  std::string,
8645 {
8646  return nonscalar_data_ranges;
8647 }
8648 
8649 
8650 
8651 // ---------------------------------------------- XDMFEntry ----------
8652 
8654  : valid(false)
8655  , h5_sol_filename("")
8656  , h5_mesh_filename("")
8657  , entry_time(0.0)
8658  , num_nodes(numbers::invalid_unsigned_int)
8659  , num_cells(numbers::invalid_unsigned_int)
8660  , dimension(numbers::invalid_unsigned_int)
8661  , space_dimension(numbers::invalid_unsigned_int)
8662 {}
8663 
8664 
8665 
8666 XDMFEntry::XDMFEntry(const std::string &filename,
8667  const double time,
8668  const unsigned int nodes,
8669  const unsigned int cells,
8670  const unsigned int dim)
8671  : XDMFEntry(filename, filename, time, nodes, cells, dim, dim)
8672 {}
8673 
8674 
8675 
8676 XDMFEntry::XDMFEntry(const std::string &mesh_filename,
8677  const std::string &solution_filename,
8678  const double time,
8679  const unsigned int nodes,
8680  const unsigned int cells,
8681  const unsigned int dim)
8682  : XDMFEntry(mesh_filename, solution_filename, time, nodes, cells, dim, dim)
8683 {}
8684 
8685 
8686 
8687 XDMFEntry::XDMFEntry(const std::string &mesh_filename,
8688  const std::string &solution_filename,
8689  const double time,
8690  const unsigned int nodes,
8691  const unsigned int cells,
8692  const unsigned int dim,
8693  const unsigned int spacedim)
8694  : valid(true)
8695  , h5_sol_filename(solution_filename)
8696  , h5_mesh_filename(mesh_filename)
8697  , entry_time(time)
8698  , num_nodes(nodes)
8699  , num_cells(cells)
8700  , dimension(dim)
8701  , space_dimension(spacedim)
8702 {}
8703 
8704 
8705 
8706 void
8707 XDMFEntry::add_attribute(const std::string &attr_name,
8708  const unsigned int dimension)
8709 {
8710  attribute_dims[attr_name] = dimension;
8711 }
8712 
8713 
8714 
8715 namespace
8716 {
8720  std::string
8721  indent(const unsigned int indent_level)
8722  {
8723  std::string res = "";
8724  for (unsigned int i = 0; i < indent_level; ++i)
8725  res += " ";
8726  return res;
8727  }
8728 } // namespace
8729 
8730 
8731 
8732 std::string
8733 XDMFEntry::get_xdmf_content(const unsigned int indent_level) const
8734 {
8735  switch (dimension)
8736  {
8737  case 0:
8738  return get_xdmf_content(indent_level,
8739  ReferenceCells::get_hypercube<0>());
8740  case 1:
8741  return get_xdmf_content(indent_level,
8742  ReferenceCells::get_hypercube<1>());
8743  case 2:
8744  return get_xdmf_content(indent_level,
8745  ReferenceCells::get_hypercube<2>());
8746  case 3:
8747  return get_xdmf_content(indent_level,
8748  ReferenceCells::get_hypercube<3>());
8749  default:
8750  Assert(false, ExcNotImplemented());
8751  }
8752 
8753  return "";
8754 }
8755 
8756 
8757 
8758 std::string
8759 XDMFEntry::get_xdmf_content(const unsigned int indent_level,
8760  const ReferenceCell &reference_cell) const
8761 {
8762  if (!valid)
8763  return "";
8764 
8765  std::stringstream ss;
8766  ss << indent(indent_level + 0)
8767  << "<Grid Name=\"mesh\" GridType=\"Uniform\">\n";
8768  ss << indent(indent_level + 1) << "<Time Value=\"" << entry_time << "\"/>\n";
8769  ss << indent(indent_level + 1) << "<Geometry GeometryType=\""
8770  << (space_dimension <= 2 ? "XY" : "XYZ") << "\">\n";
8771  ss << indent(indent_level + 2) << "<DataItem Dimensions=\"" << num_nodes
8772  << " " << (space_dimension <= 2 ? 2 : space_dimension)
8773  << "\" NumberType=\"Float\" Precision=\"8\" Format=\"HDF\">\n";
8774  ss << indent(indent_level + 3) << h5_mesh_filename << ":/nodes\n";
8775  ss << indent(indent_level + 2) << "</DataItem>\n";
8776  ss << indent(indent_level + 1) << "</Geometry>\n";
8777 
8778  // If we have cells defined, use the topology corresponding to the dimension
8779  if (num_cells > 0)
8780  {
8781  ss << indent(indent_level + 1) << "<Topology TopologyType=\"";
8782 
8783  if (dimension == 0)
8784  {
8785  ss << "Polyvertex";
8786  }
8787  else if (dimension == 1)
8788  {
8789  ss << "Polyline";
8790  }
8791  else if (dimension == 2)
8792  {
8795  ExcNotImplemented());
8796 
8798  {
8799  ss << "Quadrilateral";
8800  }
8801  else // if (reference_cell == ReferenceCells::Triangle)
8802  {
8803  ss << "Triangle";
8804  }
8805  }
8806  else if (dimension == 3)
8807  {
8810  ExcNotImplemented());
8811 
8813  {
8814  ss << "Hexahedron";
8815  }
8816  else // if (reference_cell == ReferenceCells::Tetrahedron)
8817  {
8818  ss << "Tetrahedron";
8819  }
8820  }
8821 
8822  ss << "\" NumberOfElements=\"" << num_cells;
8823  if (dimension == 0)
8824  ss << "\" NodesPerElement=\"1\">\n";
8825  else if (dimension == 1)
8826  ss << "\" NodesPerElement=\"2\">\n";
8827  else
8828  // no "NodesPerElement" for dimension 2 and higher
8829  ss << "\">\n";
8830 
8831  ss << indent(indent_level + 2) << "<DataItem Dimensions=\"" << num_cells
8832  << " " << reference_cell.n_vertices()
8833  << "\" NumberType=\"UInt\" Format=\"HDF\">\n";
8834 
8835  ss << indent(indent_level + 3) << h5_mesh_filename << ":/cells\n";
8836  ss << indent(indent_level + 2) << "</DataItem>\n";
8837  ss << indent(indent_level + 1) << "</Topology>\n";
8838  }
8839  // Otherwise, we assume the points are isolated in space and use a Polyvertex
8840  // topology
8841  else
8842  {
8843  ss << indent(indent_level + 1)
8844  << "<Topology TopologyType=\"Polyvertex\" NumberOfElements=\""
8845  << num_nodes << "\">\n";
8846  ss << indent(indent_level + 1) << "</Topology>\n";
8847  }
8848 
8849  for (const auto &attribute_dim : attribute_dims)
8850  {
8851  ss << indent(indent_level + 1) << "<Attribute Name=\""
8852  << attribute_dim.first << "\" AttributeType=\""
8853  << (attribute_dim.second > 1 ? "Vector" : "Scalar")
8854  << "\" Center=\"Node\">\n";
8855  // Vectors must have 3 elements even for 2D models
8856  ss << indent(indent_level + 2) << "<DataItem Dimensions=\"" << num_nodes
8857  << " " << (attribute_dim.second > 1 ? 3 : 1)
8858  << "\" NumberType=\"Float\" Precision=\"8\" Format=\"HDF\">\n";
8859  ss << indent(indent_level + 3) << h5_sol_filename << ":/"
8860  << attribute_dim.first << "\n";
8861  ss << indent(indent_level + 2) << "</DataItem>\n";
8862  ss << indent(indent_level + 1) << "</Attribute>\n";
8863  }
8864 
8865  ss << indent(indent_level + 0) << "</Grid>\n";
8866 
8867  return ss.str();
8868 }
8869 
8870 
8871 
8872 namespace DataOutBase
8873 {
8874  template <int dim, int spacedim>
8875  std::ostream &
8876  operator<<(std::ostream &out, const Patch<dim, spacedim> &patch)
8877  {
8878  // write a header line
8879  out << "[deal.II intermediate Patch<" << dim << ',' << spacedim << ">]"
8880  << '\n';
8881 
8882  // then write all the data that is in this patch
8883  for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
8884  out << patch.vertices[GeometryInfo<dim>::ucd_to_deal[i]] << ' ';
8885  out << '\n';
8886 
8887  for (unsigned int i : GeometryInfo<dim>::face_indices())
8888  out << patch.neighbors[i] << ' ';
8889  out << '\n';
8890 
8891  out << patch.patch_index << ' ' << patch.n_subdivisions << '\n';
8892 
8893  out << patch.points_are_available << '\n';
8894 
8895  out << patch.data.n_rows() << ' ' << patch.data.n_cols() << '\n';
8896  for (unsigned int i = 0; i < patch.data.n_rows(); ++i)
8897  for (unsigned int j = 0; j < patch.data.n_cols(); ++j)
8898  out << patch.data[i][j] << ' ';
8899  out << '\n';
8900  out << '\n';
8901 
8902  return out;
8903  }
8904 
8905 
8906  template <int dim, int spacedim>
8907  std::istream &
8908  operator>>(std::istream &in, Patch<dim, spacedim> &patch)
8909  {
8910  AssertThrow(in, ExcIO());
8911 
8912  // read a header line and compare it to what we usually write. skip all
8913  // lines that contain only blanks at the start
8914  {
8915  std::string header;
8916  do
8917  {
8918  getline(in, header);
8919  while ((header.size() != 0) && (header[header.size() - 1] == ' '))
8920  header.erase(header.size() - 1);
8921  }
8922  while ((header.empty()) && in);
8923 
8924  std::ostringstream s;
8925  s << "[deal.II intermediate Patch<" << dim << ',' << spacedim << ">]";
8926 
8927  Assert(header == s.str(), ExcUnexpectedInput(s.str(), header));
8928  }
8929 
8930 
8931  // then read all the data that is in this patch
8932  for (const unsigned int i : GeometryInfo<dim>::vertex_indices())
8933  in >> patch.vertices[GeometryInfo<dim>::ucd_to_deal[i]];
8934 
8935  for (unsigned int i : GeometryInfo<dim>::face_indices())
8936  in >> patch.neighbors[i];
8937 
8938  in >> patch.patch_index >> patch.n_subdivisions;
8939 
8940  in >> patch.points_are_available;
8941 
8942  unsigned int n_rows, n_cols;
8943  in >> n_rows >> n_cols;
8944  patch.data.reinit(n_rows, n_cols);
8945  for (unsigned int i = 0; i < patch.data.n_rows(); ++i)
8946  for (unsigned int j = 0; j < patch.data.n_cols(); ++j)
8947  in >> patch.data[i][j];
8948 
8949  AssertThrow(in, ExcIO());
8950 
8951  return in;
8952  }
8953 } // namespace DataOutBase
8954 
8955 
8956 
8957 // explicit instantiations
8958 #include "data_out_base.inst"
8959 
long int get_integer(const std::string &entry_string) const
bool get_bool(const std::string &entry_name) const
void declare_entry(const std::string &entry, const std::string &default_value, const Patterns::PatternBase &pattern=Patterns::Anything(), const std::string &documentation="", const bool has_to_be_set=false)
std::string get(const std::string &entry_string) const
double get_double(const std::string &entry_name) const
void enter_subsection(const std::string &subsection)
unsigned int n_vertices() const
SymmetricTensor< rank, dim, Number > sum(const SymmetricTensor< rank, dim, Number > &local, const MPI_Comm &mpi_communicator)
Definition: tensor.h:472
static constexpr TableIndices< rank_ > unrolled_to_component_indices(const unsigned int i)
constexpr void clear()
void join() const
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:396
#define DEAL_II_PACKAGE_VERSION
Definition: config.h:26
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:397
#define DEAL_II_FALLTHROUGH
Definition: config.h:168
#define DEAL_II_PACKAGE_NAME
Definition: config.h:24
Point< 2 > projected_vertices[4]
Point< 3 > center
float depth
Point< 2 > projected_center
Point< 3 > vertices[4]
float color_value
unsigned int level
Definition: grid_out.cc:4590
unsigned int cell_index
Definition: grid_tools.cc:1092
std::size_t memory_consumption() const
static void declare_parameters(ParameterHandler &prm)
virtual std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation > > get_nonscalar_data_ranges() const
const double * get_data_set(const unsigned int set_num) const
static void declare_parameters(ParameterHandler &prm)
std::string write_vtu_with_pvtu_record(const std::string &directory, const std::string &filename_without_extension, const unsigned int counter, const MPI_Comm &mpi_communicator, const unsigned int n_digits_for_counter=numbers::invalid_unsigned_int, const unsigned int n_groups=0) const
static void declare_parameters(ParameterHandler &prm)
void parse_parameters(ParameterHandler &prm)
static ::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
static ::ExceptionBase & ExcIncompatiblePatchLists()
static RgbValues default_color_function(const double value, const double min_value, const double max_value)
std::map< unsigned int, unsigned int > filtered_points
void write_filtered_data(DataOutBase::DataOutFilter &filtered_data) const
std::ostream & operator<<(std::ostream &out, const Patch< dim, spacedim > &patch)
std::vector< std::string > space_dimension_labels
static ::ExceptionBase & ExcErrorOpeningTecplotFile(char *arg1)
void write_pvtu_record(std::ostream &out, const std::vector< std::string > &piece_names) const
static void declare_parameters(ParameterHandler &prm)
void write_hdf5_parallel(const DataOutBase::DataOutFilter &data_filter, const std::string &filename, const MPI_Comm &comm) const
void parse_parameters(const ParameterHandler &prm)
ColorFunction color_function
std::string get_data_set_name(const unsigned int set_num) const
void write_ucd(std::ostream &out) const
static ::ExceptionBase & ExcLowerRange(int arg1, int arg2)
void merge(const DataOutReader< dim, spacedim > &other)
unsigned int patch_index
static ::ExceptionBase & ExcInternalError()
ReferenceCell reference_cell
void write_povray(std::ostream &out) const
RgbValues(*)(const double value, const double min_value, const double max_value) ColorFunction
std::string default_suffix(const DataOutBase::OutputFormat output_format=DataOutBase::default_format) const
Table< 2, float > data
static RgbValues grey_scale_color_function(const double value, const double min_value, const double max_value)
void internal_add_cell(const unsigned int cell_index, const unsigned int pt_index)
static void declare_parameters(ParameterHandler &prm)
void write_cell(const unsigned int index, const unsigned int start, const unsigned int d1, const unsigned int d2, const unsigned int d3)
ZlibCompressionLevel compression_level
static ::ExceptionBase & ExcNotInitialized()
XDMFEntry create_xdmf_entry(const DataOutBase::DataOutFilter &data_filter, const std::string &h5_filename, const double cur_time, const MPI_Comm &comm) const
static const unsigned int format_version
static const unsigned int no_neighbor
static ::ExceptionBase & ExcFileNotOpen(std::string arg1)
unsigned int dimension
PovrayFlags(const bool smooth=false, const bool bicubic_patch=false, const bool external_data=false)
void write_vtu_in_parallel(const std::string &filename, const MPI_Comm &comm) const
virtual const std::vector<::DataOutBase::Patch< dim, spacedim > > & get_patches() const override
unsigned int height_vector
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
unsigned int num_nodes
void write_cell_single(const unsigned int index, const unsigned int start, const unsigned int n_points)
EpsFlags(const unsigned int height_vector=0, const unsigned int color_vector=0, const SizeType size_type=width, const unsigned int size=300, const double line_width=0.5, const double azimut_angle=60, const double turn_angle=30, const double z_scaling=1.0, const bool draw_mesh=true, const bool draw_cells=true, const bool shade_cells=true, const ColorFunction color_function=&default_color_function)
void parse_parameters(const ParameterHandler &prm)
std::vector< unsigned int > data_set_dims
std::size_t memory_consumption() const
void set_default_format(const DataOutBase::OutputFormat default_format)
unsigned int n_nodes() const
#define Assert(cond, exc)
Definition: exceptions.h:1465
void parse_parameters(const ParameterHandler &prm)
unsigned int color_vector
Point< spacedim > vertices[GeometryInfo< dim >::vertices_per_cell]
static ::ExceptionBase & ExcIncompatibleDatasetNames()
void write(std::ostream &out, const DataOutBase::OutputFormat output_format=DataOutBase::default_format) const
static void declare_parameters(ParameterHandler &prm)
static ::ExceptionBase & ExcNotImplemented()
void fill_node_data(std::vector< double > &node_data) const
std::vector< std::vector< double > > data_sets
static ::ExceptionBase & ExcInvalidDatasetSize(int arg1, int arg2)
bool operator==(const Patch &patch) const
std::string h5_sol_filename
unsigned int get_data_set_dim(const unsigned int set_num) const
void write_gnuplot(std::ostream &out) const
void read(std::istream &in)
#define DeclException2(Exception2, type1, type2, outsequence)
Definition: exceptions.h:538
SvgFlags(const unsigned int height_vector=0, const int azimuth_angle=37, const int polar_angle=45, const unsigned int line_thickness=1, const bool margin=true, const bool draw_colorbar=true)
static RgbValues reverse_grey_scale_color_function(const double value, const double min_value, const double max_value)
void write_vtu(std::ostream &out) const
#define AssertDimension(dim1, dim2)
Definition: exceptions.h:1622
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1746
static const unsigned int space_dim
void write_tecplot(std::ostream &out) const
TecplotFlags(const char *zone_name=nullptr, const double solution_time=-1.0)
void write_data_set(const std::string &name, const unsigned int dimension, const unsigned int set_num, const Table< 2, double > &data_vectors)
void parse_parameters(const ParameterHandler &prm)
double entry_time
static ::ExceptionBase & ExcTecplotAPIError()
std::string h5_mesh_filename
static unsigned int n_subdivisions
std::string get_xdmf_content(const unsigned int indent_level) const
std::map< unsigned int, unsigned int > filtered_cells
void add_attribute(const std::string &attr_name, const unsigned int dimension)
virtual std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation > > get_nonscalar_data_ranges() const override
std::map< std::string, unsigned int > attribute_dims
#define AssertIndexRange(index, range)
Definition: exceptions.h:1690
virtual std::vector< std::string > get_dataset_names() const override
void write_svg(std::ostream &out) const
unsigned int height_vector
unsigned int n_subdivisions
void write_xdmf_file(const std::vector< XDMFEntry > &entries, const std::string &filename, const MPI_Comm &comm) const
static ::ExceptionBase & ExcIO()
void validate_dataset_names() const
void set_flags(const FlagType &flags)
std::vector< std::string > data_set_names
void write_vtk(std::ostream &out) const
unsigned int line_thickness
static ::ExceptionBase & ExcNoPatches()
void swap(Patch< dim, spacedim > &other_patch)
void fill_cell_data(const unsigned int local_node_offset, std::vector< unsigned int > &cell_data) const
std::istream & operator>>(std::istream &in, Patch< dim, spacedim > &patch)
DataOutFilterFlags(const bool filter_duplicate_vertices=false, const bool xdmf_hdf5_output=false)
void write_point(const unsigned int index, const Point< dim > &p)
UcdFlags(const bool write_preamble=false)
std::size_t memory_consumption() const
void parse_parameters(const ParameterHandler &prm)
DXFlags(const bool write_neighbors=false, const bool int_binary=false, const bool coordinates_binary=false, const bool data_binary=false)
unsigned int num_cells
std::array< unsigned int, GeometryInfo< dim >::faces_per_cell > neighbors
void write_gmv(std::ostream &out) const
static ::ExceptionBase & ExcMessage(std::string arg1)
void write_eps(std::ostream &out) const
unsigned int n_cells() const
unsigned int space_dimension
static void declare_parameters(ParameterHandler &prm)
DataOutBase::DataOutFilterFlags flags
void write_dx(std::ostream &out) const
#define AssertThrow(cond, exc)
Definition: exceptions.h:1575
unsigned int n_data_sets() const
void write_deal_II_intermediate(std::ostream &out) const
@ width
Scale to given width.
@ height
Scale to given height.
Task< RT > new_task(const std::function< RT()> &function)
#define DEAL_II_MPI_CONST_CAST(expr)
Definition: mpi.h:82
OutputOperator< VectorType > & operator<<(OutputOperator< VectorType > &out, unsigned int step)
Definition: operator.h:165
std::pair< unsigned int, unsigned int > determine_intermediate_format_dimensions(std::istream &input)
void write_vtk(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const VtkFlags &flags, std::ostream &out)
void write_vtu(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const VtkFlags &flags, std::ostream &out)
void write_gnuplot(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const GnuplotFlags &flags, std::ostream &out)
void write_data(const std::vector< Patch< dim, spacedim >> &patches, unsigned int n_data_sets, const bool double_precision, StreamType &out)
void write_filtered_data(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, DataOutFilter &filtered_data)
void write_ucd(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const UcdFlags &flags, std::ostream &out)
void write_vtu_header(std::ostream &out, const VtkFlags &flags)
void write_pvd_record(std::ostream &out, const std::vector< std::pair< double, std::string >> &times_and_names)
void write_deal_II_intermediate(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const Deal_II_IntermediateFlags &flags, std::ostream &out)
void write_dx(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const DXFlags &flags, std::ostream &out)
void write_tecplot_binary(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const TecplotFlags &flags, std::ostream &out)
void write_eps(const std::vector< Patch< 2, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const EpsFlags &flags, std::ostream &out)
void write_vtu_footer(std::ostream &out)
void write_nodes(const std::vector< Patch< dim, spacedim >> &patches, StreamType &out)
void write_tecplot(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const TecplotFlags &flags, std::ostream &out)
OutputFormat parse_output_format(const std::string &format_name)
void write_svg(const std::vector< Patch< dim, spacedim >> &, const std::vector< std::string > &, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &, const SvgFlags &, std::ostream &)
void write_vtu_main(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const VtkFlags &flags, std::ostream &out)
void write_pvtu_record(std::ostream &out, const std::vector< std::string > &piece_names, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges)
void write_cells(const std::vector< Patch< dim, spacedim >> &patches, StreamType &out)
void write_svg(const std::vector< Patch< 2, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const SvgFlags &flags, std::ostream &out)
void write_high_order_cells(const std::vector< Patch< dim, spacedim >> &patches, StreamType &out)
std::string get_output_format_names()
void write_visit_record(std::ostream &out, const std::vector< std::string > &piece_names)
void write_povray(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const PovrayFlags &flags, std::ostream &out)
std::string default_suffix(const OutputFormat output_format)
void write_hdf5_parallel(const std::vector< Patch< dim, spacedim >> &patches, const DataOutFilter &data_filter, const std::string &filename, const MPI_Comm &comm)
void write_gmv(const std::vector< Patch< dim, spacedim >> &patches, const std::vector< std::string > &data_names, const std::vector< std::tuple< unsigned int, unsigned int, std::string, DataComponentInterpretation::DataComponentInterpretation >> &nonscalar_data_ranges, const GmvFlags &flags, std::ostream &out)
void reference_cell(Triangulation< dim, spacedim > &tria, const ReferenceCell &reference_cell)
void scale(const double scaling_factor, Triangulation< dim, spacedim > &triangulation)
Definition: grid_tools.cc:2042
@ valid
Iterator points to a valid object.
static const char A
static const char T
types::global_dof_index size_type
Definition: cuda_kernels.h:45
double norm(const FEValuesBase< dim > &fe, const ArrayView< const std::vector< Tensor< 1, dim >>> &Du)
Definition: divergence.h:472
std::enable_if< std::is_fundamental< T >::value, std::size_t >::type memory_consumption(const T &t)
void swap(MemorySpaceData< Number, MemorySpace > &, MemorySpaceData< Number, MemorySpace > &)
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
Definition: utilities.cc:188
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
SymmetricTensor< 2, dim, Number > epsilon(const Tensor< 2, dim, Number > &Grad_u)
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
constexpr const ReferenceCell Tetrahedron
constexpr const ReferenceCell Quadrilateral
constexpr const ReferenceCell Wedge
constexpr const ReferenceCell Pyramid
constexpr const ReferenceCell Triangle
constexpr const ReferenceCell Hexahedron
constexpr const ReferenceCell & get_hypercube()
VectorType::value_type * begin(VectorType &V)
VectorType::value_type * end(VectorType &V)
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:128
T sum(const T &t, const MPI_Comm &mpi_communicator)
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:117
std::string get_time()
Definition: utilities.cc:1019
std::string get_date()
Definition: utilities.cc:1035
constexpr T pow(const T base, const int iexp)
Definition: utilities.h:461
std::string encode_base64(const std::vector< unsigned char > &binary_input)
Definition: utilities.cc:436
std::string int_to_string(const unsigned int value, const unsigned int digits=numbers::invalid_unsigned_int)
Definition: utilities.cc:473
unsigned int needed_digits(const unsigned int max_number)
Definition: utilities.cc:568
unsigned int n_cells(const internal::TriangulationImplementation::NumberCache< 1 > &c)
Definition: tria.cc:12587
void copy(const T *begin, const T *end, U *dest)
static constexpr double PI
Definition: numbers.h:231
static const unsigned int invalid_unsigned_int
Definition: types.h:196
unsigned int global_dof_index
Definition: types.h:76
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
bool operator<(const SynchronousIterators< Iterators > &a, const SynchronousIterators< Iterators > &b)