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