From: Rene Gassmoeller Date: Tue, 18 Jul 2017 17:04:51 +0000 (-0600) Subject: Instantiate output for zero dim. X-Git-Tag: v9.0.0-rc1~1396^2~1 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=29edad9436ade6cd87bff9b68dd9af25bb316c28;p=dealii.git Instantiate output for zero dim. --- diff --git a/cmake/config/template-arguments.in b/cmake/config/template-arguments.in index 7946207164..cd7ce39559 100644 --- a/cmake/config/template-arguments.in +++ b/cmake/config/template-arguments.in @@ -152,7 +152,10 @@ SPARSITY_PATTERNS := { SparsityPattern; // all supported logical dimensions DIMENSIONS := { 1; 2; 3 } -// all supported spacial dimensions +// all supported output dimensions +OUTPUT_DIMENSIONS := { 0; 1; 2; 3 } + +// all supported spatial dimensions SPACE_DIMENSIONS := { 1; 2; 3 } // all ranks used for instantiating tensors diff --git a/doc/news/changes/minor/20170718ReneGassmoeller b/doc/news/changes/minor/20170718ReneGassmoeller new file mode 100644 index 0000000000..88503ccd02 --- /dev/null +++ b/doc/news/changes/minor/20170718ReneGassmoeller @@ -0,0 +1,6 @@ +New: DataOutBase now supports writing zero-dimensional +data in a higher spatial dimension (e.g. vertices, quadrature points, particles) +for a number of output formats (vtu,vtk,gnuplot,hdf5). A consequence of the +change is that HDF5 now in general supports output for dim +(Rene Gassmoeller, 2017/07/18) diff --git a/include/deal.II/base/data_out_base.h b/include/deal.II/base/data_out_base.h index b7a2aee1b2..7f4424663c 100644 --- a/include/deal.II/base/data_out_base.h +++ b/include/deal.II/base/data_out_base.h @@ -260,7 +260,8 @@ namespace DataOutBase * Numbers of neighbors of a patch. OpenDX format requires neighbor * information for advanced output. Here the neighborship relationship of * patches is stored. During output, this must be transformed into - * neighborship of sub-grid cells. + * neighborship of sub-grid cells. For dim==0 we still allow one + * neighbor, to avoid compiler warnings about zero-sized arrays. */ unsigned int neighbors[dim > 0 ? @@ -2826,47 +2827,57 @@ private: /** - * A class to store relevant data to use when writing the light data XDMF - * file. This should only contain valid data on the root node which writes the - * files, the rest of the nodes will have valid set to false. The XDMF file in - * turn points to heavy data files (such as HDF5) where the actual simulation - * data is stored. This allows flexibility in arranging the data, and also + * A class to store relevant data to use when writing a lightweight XDMF + * file. The XDMF file in turn points to heavy data files (such as HDF5) + * where the actual simulation data is stored. + * This allows flexibility in arranging the data, and also * allows the mesh to be separated from the point data. */ class XDMFEntry { -private: - /// Whether this entry is valid and contains data to be written - bool valid; - /// The name of the HDF5 heavy data solution and/or mesh files this entry references - std::string h5_sol_filename, h5_mesh_filename; - /// The simulation time associated with this entry - double entry_time; - /// The number of nodes, cells and dimensionality associated with the data - unsigned int num_nodes, num_cells, dimension; - /// The attributes associated with this entry and their dimension - std::map attribute_dims; +public: + /** + * Default constructor that creates an invalid object. + */ + XDMFEntry(); - /// Small function to create indentation for XML file - std::string indent(const unsigned int indent_level) const - { - std::string res = ""; - for (unsigned int i=0; isolution_filename == mesh_filename, and + * dim==spacedim. + */ + XDMFEntry(const std::string filename, + const double time, + const unsigned int nodes, + const unsigned int cells, + const unsigned int dim); -public: - XDMFEntry() : valid(false) {}; - XDMFEntry(const std::string filename, const double time, const unsigned int nodes, const unsigned int cells, const unsigned int dim) : valid(true), h5_sol_filename(filename), h5_mesh_filename(filename), entry_time(time), num_nodes(nodes), num_cells(cells), dimension(dim) {}; - 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) : valid(true), h5_sol_filename(solution_filename), h5_mesh_filename(mesh_filename), entry_time(time), num_nodes(nodes), num_cells(cells), dimension(dim) {}; + /** + * Simplified constructor that calls the complete constructor for + * cases where dim==spacedim. + */ + 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); + + /** + * Constructor that sets all members to provided parameters. + */ + 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); /** * Record an attribute and associated dimensionality. */ - void add_attribute(const std::string &attr_name, const unsigned int dimension) - { - attribute_dims[attr_name] = dimension; - } + void add_attribute(const std::string &attr_name, const unsigned int dimension); /** * Read or write the data of this object for serialization @@ -2884,9 +2895,58 @@ public: &attribute_dims; } - /// Get the XDMF content associated with this entry. - /// If the entry is not valid, this returns an empty string. + /** + * Get the XDMF content associated with this entry. + * If the entry is not valid, this returns an empty string. + */ std::string get_xdmf_content(const unsigned int indent_level) const; + +private: + /** + * Whether this entry is valid and contains data to be written. + */ + const bool valid; + + /** + * The name of the HDF5 heavy data solution file this entry references. + */ + const std::string h5_sol_filename; + + /** + * The name of the HDF5 mesh file this entry references. + */ + const std::string h5_mesh_filename; + + /** + * The simulation time associated with this entry. + */ + const double entry_time; + + /** + * The number of data nodes. + */ + const unsigned int num_nodes; + + /** + * The number of data cells. + */ + const unsigned int num_cells; + + /** + * The dimension associated with the data. + */ + const unsigned int dimension; + + /** + * The dimension of the space the data lives in. + * Note that dimension <= space_dimension. + */ + const unsigned int space_dimension; + + /** + * The attributes associated with this entry and their dimension. + */ + std::map attribute_dims; }; diff --git a/include/deal.II/base/geometry_info.h b/include/deal.II/base/geometry_info.h index 36e369d848..caafecd2fb 100644 --- a/include/deal.II/base/geometry_info.h +++ b/include/deal.II/base/geometry_info.h @@ -928,6 +928,40 @@ struct GeometryInfo<0> * Number of hexahedra of a cell. */ static const unsigned int hexes_per_cell = 0; + + /** + * Rearrange vertices for UCD output. For a cell being written in UCD + * format, each entry in this field contains the number of a vertex in + * deal.II that corresponds to the UCD numbering at this location. + * + * Typical example: write a cell and arrange the vertices, such that UCD + * understands them. + * + * @code + * for (i=0; i< n_vertices; ++i) + * out << cell->vertex(ucd_to_deal[i]); + * @endcode + * + * As the vertex numbering in deal.II versions <= 5.1 happened to coincide + * with the UCD numbering, this field can also be used like a + * old_to_lexicographic mapping. + */ + static constexpr unsigned int ucd_to_deal[vertices_per_cell] = {0}; + + /** + * Rearrange vertices for OpenDX output. For a cell being written in OpenDX + * format, each entry in this field contains the number of a vertex in + * deal.II that corresponds to the DX numbering at this location. + * + * Typical example: write a cell and arrange the vertices, such that OpenDX + * understands them. + * + * @code + * for (i=0; i< n_vertices; ++i) + * out << cell->vertex(dx_to_deal[i]); + * @endcode + */ + static constexpr unsigned int dx_to_deal[vertices_per_cell] = {0}; }; diff --git a/include/deal.II/base/utilities.h b/include/deal.II/base/utilities.h index 39a848324c..e46c586d66 100644 --- a/include/deal.II/base/utilities.h +++ b/include/deal.II/base/utilities.h @@ -597,9 +597,11 @@ namespace Utilities inline T fixed_power (const T n) { - Assert (N>0, ExcNotImplemented()); + Assert (N>=0, ExcNotImplemented()); switch (N) { + case 0: + return 1; case 1: return n; case 2: diff --git a/source/base/data_out_base.cc b/source/base/data_out_base.cc index 4d2a2af337..7bdb0a58d7 100644 --- a/source/base/data_out_base.cc +++ b/source/base/data_out_base.cc @@ -526,17 +526,20 @@ DataOutBase::DataOutFilter::write_cell( unsigned int base_entry = index * GeometryInfo::vertices_per_cell; vertices_per_cell = GeometryInfo::vertices_per_cell; internal_add_cell(base_entry+0, start); - internal_add_cell(base_entry+1, start+d1); - if (dim>=2) + if (dim>=1) { - internal_add_cell(base_entry+2, start+d2+d1); - internal_add_cell(base_entry+3, start+d2); - if (dim>=3) + internal_add_cell(base_entry+1, start+d1); + if (dim>=2) { - internal_add_cell(base_entry+4, start+d3); - internal_add_cell(base_entry+5, start+d3+d1); - internal_add_cell(base_entry+6, start+d3+d2+d1); - internal_add_cell(base_entry+7, start+d3+d2); + internal_add_cell(base_entry+2, start+d2+d1); + internal_add_cell(base_entry+3, start+d2); + if (dim>=3) + { + internal_add_cell(base_entry+4, start+d3); + internal_add_cell(base_entry+5, start+d3+d1); + internal_add_cell(base_entry+6, start+d3+d2+d1); + internal_add_cell(base_entry+7, start+d3+d2); + } } } } @@ -581,7 +584,7 @@ namespace const char *ucd_cell_type[4] = { - "", "line", "quad", "hex" + "pt", "line", "quad", "hex" }; const char *tecplot_cell_type[4] = @@ -602,7 +605,7 @@ namespace // choice avoids a -Warray-bounds check warning const unsigned int vtk_cell_type[5] = { - 0, 3, 9, 12, static_cast(-1) + 1, 3, 9, 12, static_cast(-1) }; //----------------------------------------------------------------------// @@ -1104,19 +1107,22 @@ namespace { int nodes[1<::dx_to_deal[0]] = start; - nodes[GeometryInfo::dx_to_deal[1]] = start+d1; - if (dim>=2) + if (dim>=1) { - // Add shifted line in y direction - nodes[GeometryInfo::dx_to_deal[2]] = start+d2; - nodes[GeometryInfo::dx_to_deal[3]] = start+d2+d1; - if (dim>=3) + nodes[GeometryInfo::dx_to_deal[1]] = start+d1; + if (dim>=2) { - // Add shifted quad in z direction - nodes[GeometryInfo::dx_to_deal[4]] = start+d3; - nodes[GeometryInfo::dx_to_deal[5]] = start+d3+d1; - nodes[GeometryInfo::dx_to_deal[6]] = start+d3+d2; - nodes[GeometryInfo::dx_to_deal[7]] = start+d3+d2+d1; + // Add shifted line in y direction + nodes[GeometryInfo::dx_to_deal[2]] = start+d2; + nodes[GeometryInfo::dx_to_deal[3]] = start+d2+d1; + if (dim>=3) + { + // Add shifted quad in z direction + nodes[GeometryInfo::dx_to_deal[4]] = start+d3; + nodes[GeometryInfo::dx_to_deal[5]] = start+d3+d1; + nodes[GeometryInfo::dx_to_deal[6]] = start+d3+d2; + nodes[GeometryInfo::dx_to_deal[7]] = start+d3+d2+d1; + } } } @@ -1189,18 +1195,21 @@ namespace const unsigned int start=s+1; stream << gmv_cell_type[dim] << '\n'; - stream << start << '\t' - << start+d1; - if (dim>=2) + stream << start; + if (dim>=1) { - stream << '\t' << start+d2+d1 - << '\t' << start+d2; - if (dim>=3) + stream << '\t' << start+d1; + if (dim>=2) { - stream << '\t' << start+d3 - << '\t' << start+d3+d1 - << '\t' << start+d3+d2+d1 - << '\t' << start+d3+d2; + stream << '\t' << start+d2+d1 + << '\t' << start+d2; + if (dim>=3) + { + stream << '\t' << start+d3 + << '\t' << start+d3+d1 + << '\t' << start+d3+d2+d1 + << '\t' << start+d3+d2; + } } } stream << '\n'; @@ -1237,18 +1246,21 @@ namespace { const unsigned int start = s+1; - stream << start << '\t' - << start+d1; - if (dim>=2) + stream << start; + if (dim >=1) { - stream << '\t' << start+d2+d1 - << '\t' << start+d2; - if (dim>=3) + stream << '\t' << start+d1; + if (dim>=2) { - stream << '\t' << start+d3 - << '\t' << start+d3+d1 - << '\t' << start+d3+d2+d1 - << '\t' << start+d3+d2; + stream << '\t' << start+d2+d1 + << '\t' << start+d2; + if (dim>=3) + { + stream << '\t' << start+d3 + << '\t' << start+d3+d1 + << '\t' << start+d3+d2+d1 + << '\t' << start+d3+d2; + } } } stream << '\n'; @@ -1291,19 +1303,22 @@ namespace { int nodes[1<::ucd_to_deal[0]] = start; - nodes[GeometryInfo::ucd_to_deal[1]] = start+d1; - if (dim>=2) + if (dim>=1) { - // Add shifted line in y direction - nodes[GeometryInfo::ucd_to_deal[2]] = start+d2; - nodes[GeometryInfo::ucd_to_deal[3]] = start+d2+d1; - if (dim>=3) + nodes[GeometryInfo::ucd_to_deal[1]] = start+d1; + if (dim>=2) { - // Add shifted quad in z direction - nodes[GeometryInfo::ucd_to_deal[4]] = start+d3; - nodes[GeometryInfo::ucd_to_deal[5]] = start+d3+d1; - nodes[GeometryInfo::ucd_to_deal[6]] = start+d3+d2; - nodes[GeometryInfo::ucd_to_deal[7]] = start+d3+d2+d1; + // Add shifted line in y direction + nodes[GeometryInfo::ucd_to_deal[2]] = start+d2; + nodes[GeometryInfo::ucd_to_deal[3]] = start+d2+d1; + if (dim>=3) + { + // Add shifted quad in z direction + nodes[GeometryInfo::ucd_to_deal[4]] = start+d3; + nodes[GeometryInfo::ucd_to_deal[5]] = start+d3+d1; + nodes[GeometryInfo::ucd_to_deal[6]] = start+d3+d2; + nodes[GeometryInfo::ucd_to_deal[7]] = start+d3+d2+d1; + } } } @@ -1366,20 +1381,23 @@ namespace unsigned int d3) { stream << GeometryInfo::vertices_per_cell << '\t' - << start << '\t' - << start+d1; - if (dim>=2) - { - stream << '\t' << start+d2+d1 - << '\t' << start+d2; - if (dim>=3) - { - stream << '\t' << start+d3 - << '\t' << start+d3+d1 - << '\t' << start+d3+d2+d1 - << '\t' << start+d3+d2; - } - } + << start; + if (dim>=1) + stream << '\t' << start+d1; + { + if (dim>=2) + { + stream << '\t' << start+d2+d1 + << '\t' << start+d2; + if (dim>=3) + { + stream << '\t' << start+d3 + << '\t' << start+d3+d1 + << '\t' << start+d3+d2+d1 + << '\t' << start+d3+d2; + } + } + } stream << '\n'; } @@ -1438,34 +1456,41 @@ namespace unsigned int d3) { #if !defined(DEAL_II_WITH_ZLIB) - stream << start << '\t' - << start+d1; - if (dim>=2) + stream << start; + if (dim>=1) { - stream << '\t' << start+d2+d1 - << '\t' << start+d2; - if (dim>=3) + stream << '\t' + << start+d1; + if (dim>=2) { - stream << '\t' << start+d3 - << '\t' << start+d3+d1 - << '\t' << start+d3+d2+d1 - << '\t' << start+d3+d2; + stream << '\t' << start+d2+d1 + << '\t' << start+d2; + if (dim>=3) + { + stream << '\t' << start+d3 + << '\t' << start+d3+d1 + << '\t' << start+d3+d2+d1 + << '\t' << start+d3+d2; + } } } stream << '\n'; #else cells.push_back (start); - cells.push_back (start+d1); - if (dim>=2) + if (dim >=1) { - cells.push_back (start+d2+d1); - cells.push_back (start+d2); - if (dim>=3) + cells.push_back (start+d1); + if (dim>=2) { - cells.push_back (start+d3); - cells.push_back (start+d3+d1); - cells.push_back (start+d3+d2+d1); - cells.push_back (start+d3+d2); + cells.push_back (start+d2+d1); + cells.push_back (start+d2); + if (dim>=3) + { + cells.push_back (start+d3); + cells.push_back (start+d3+d1); + cells.push_back (start+d3+d2+d1); + cells.push_back (start+d3+d2); + } } } #endif @@ -2564,6 +2589,10 @@ namespace DataOutBase const UcdFlags &flags, std::ostream &out) { + // Note that while in theory dim==0 should be implemented, + // this is not tested, therefore currently not allowed. + AssertThrow (dim>0, ExcNotImplemented()); + AssertThrow (out, ExcIO()); #ifndef DEAL_II_WITH_MPI @@ -2655,6 +2684,9 @@ namespace DataOutBase const DXFlags &flags, std::ostream &out) { + // Point output is currently not implemented. + AssertThrow (dim>0, ExcNotImplemented()); + AssertThrow (out, ExcIO()); #ifndef DEAL_II_WITH_MPI @@ -2769,6 +2801,13 @@ namespace DataOutBase const unsigned int ny = i2*dy; const unsigned int nz = i3*dz; + // There are no neighbors for dim==0. + // Note that this case is caught by the + // AssertThrow at the beginning of this function anyway. + // This condition avoids compiler warnings. + if (dim<1) + continue; + out << '\n'; // Direction -x // Last cell in row @@ -3898,6 +3937,12 @@ namespace DataOutBase const GmvFlags &flags, std::ostream &out) { + // The gmv format does not support cells that only consist + // of a single point. It does support the output of point data + // using the keyword 'tracers' instead of 'nodes' and 'cells', + // but this output format is currently not implemented. + AssertThrow (dim>0, ExcNotImplemented()); + Assert(dim<=3, ExcNotImplemented()); AssertThrow (out, ExcIO()); @@ -4055,6 +4100,11 @@ namespace DataOutBase { AssertThrow (out, ExcIO()); + // The FEBLOCK or FEPOINT formats of tecplot only allows full elements + // (e.g. triangles), not single points. Other tecplot format allow + // point output, but they are currently not implemented. + AssertThrow (dim>0, ExcNotImplemented()); + #ifndef DEAL_II_WITH_MPI // verify that there are indeed // patches to be written out. most @@ -4296,6 +4346,10 @@ namespace DataOutBase const TecplotFlags &flags, std::ostream &out) { + // The FEBLOCK or FEPOINT formats of tecplot only allows full elements + // (e.g. triangles), not single points. Other tecplot format allow + // point output, but they are currently not implemented. + AssertThrow (dim>0, ExcNotImplemented()); #ifndef DEAL_II_HAVE_TECPLOT @@ -6508,7 +6562,7 @@ create_xdmf_entry (const DataOutBase::DataOutFilter &data_filter, // Output the XDMF file only on the root process if (myrank == 0) { - XDMFEntry entry(h5_mesh_filename, h5_solution_filename, cur_time, global_node_cell_count[0], global_node_cell_count[1], dim); + XDMFEntry entry(h5_mesh_filename, h5_solution_filename, cur_time, global_node_cell_count[0], global_node_cell_count[1], dim, spacedim); unsigned int n_data_sets = data_filter.n_data_sets(); // The vector names generated here must match those generated in the HDF5 file @@ -6532,7 +6586,7 @@ write_xdmf_file (const std::vector &entries, const std::string &filename, MPI_Comm comm) const { - int myrank; + int myrank; #ifdef DEAL_II_WITH_MPI const int ierr = MPI_Comm_rank(comm, &myrank); @@ -6567,54 +6621,6 @@ write_xdmf_file (const std::vector &entries, } -/* - * Get the XDMF content associated with this entry. - * If the entry is not valid, this returns an empty string. - */ -std::string XDMFEntry::get_xdmf_content(const unsigned int indent_level) const -{ - std::stringstream ss; - std::map::const_iterator it; - - if (!valid) return ""; - - ss << indent(indent_level+0) << "\n"; - ss << indent(indent_level+1) << "\n"; - - return ss.str(); -} /* * Write the data in this DataOutInterface to a DataOutFilter object. @@ -6766,6 +6772,11 @@ void DataOutBase::write_hdf5_parallel (const std::vector > & const std::string &solution_filename, MPI_Comm comm) { + + AssertThrow(spacedim>=2, + ExcMessage("DataOutBase was asked to write HDF5 output for a space dimension of 1. " + "HDF5 only supports datasets that live in 2 or 3 dimensions.")); + int ierr; (void)ierr; #ifndef DEAL_II_WITH_HDF5 @@ -6861,8 +6872,9 @@ void DataOutBase::write_hdf5_parallel (const std::vector > & AssertThrow(h5_mesh_file_id >= 0, ExcIO()); // Create the dataspace for the nodes and cells + // HDF5 only supports 2- or 3-dimensional coordinates node_ds_dim[0] = global_node_cell_count[0]; - node_ds_dim[1] = dim; + node_ds_dim[1] = (spacedim<2) ? 2 : spacedim; node_dataspace = H5Screate_simple(2, node_ds_dim, NULL); AssertThrow(node_dataspace >= 0, ExcIO()); @@ -6892,10 +6904,13 @@ void DataOutBase::write_hdf5_parallel (const std::vector > & AssertThrow(status >= 0, ExcIO()); // Create the data subset we'll use to read from memory + // HDF5 only supports 2- or 3-dimensional coordinates count[0] = local_node_cell_count[0]; - count[1] = dim; + count[1] = (spacedim<2) ? 2 : spacedim; + offset[0] = global_node_cell_offsets[0]; offset[1] = 0; + node_memory_dataspace = H5Screate_simple(2, count, NULL); AssertThrow(node_memory_dataspace >= 0, ExcIO()); @@ -7547,6 +7562,156 @@ DataOutReader::get_vector_data_ranges () const +// ---------------------------------------------- XDMFEntry ---------- + +XDMFEntry::XDMFEntry() + : + valid(false), + h5_sol_filename(""), + h5_mesh_filename(""), + entry_time(0.0), + num_nodes(numbers::invalid_unsigned_int), + num_cells(numbers::invalid_unsigned_int), + dimension(numbers::invalid_unsigned_int), + space_dimension(numbers::invalid_unsigned_int) +{} + + + +XDMFEntry::XDMFEntry(const std::string filename, + const double time, + const unsigned int nodes, + const unsigned int cells, + const unsigned int dim) + : + XDMFEntry(filename, + filename, + time, + nodes, + cells, + dim, + dim) +{} + + + +XDMFEntry::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) + : + XDMFEntry(mesh_filename, + solution_filename, + time, + nodes, + cells, + dim, + dim) +{} + + + +XDMFEntry::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) + : + valid(true), + h5_sol_filename(solution_filename), + h5_mesh_filename(mesh_filename), + entry_time(time), + num_nodes(nodes), + num_cells(cells), + dimension(dim), + space_dimension(spacedim) +{} + + + +void +XDMFEntry::add_attribute(const std::string &attr_name, const unsigned int dimension) +{ + attribute_dims[attr_name] = dimension; +} + + + +namespace +{ + /** + * Small function to create indentation for XML file. + */ + std::string indent(const unsigned int indent_level) + { + std::string res = ""; + for (unsigned int i=0; i\n"; + ss << indent(indent_level+1) << "