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