From: heien Date: Fri, 27 Sep 2013 23:48:07 +0000 (+0000) Subject: Added DataOutFilter class to remove duplicate vertices/values and serialization for... X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=db4d96ba49e309b05030a7f6d864905b7b5b76e8;p=dealii-svn.git Added DataOutFilter class to remove duplicate vertices/values and serialization for XDMFEntry class git-svn-id: https://svn.dealii.org/trunk@30991 0785d39b-7218-0410-832d-ea1e28bc413d --- diff --git a/deal.II/doc/news/changes.h b/deal.II/doc/news/changes.h index 28389d0e3b..16257eeffb 100644 --- a/deal.II/doc/news/changes.h +++ b/deal.II/doc/news/changes.h @@ -53,6 +53,29 @@ inconvenience this causes.
    +
  1. + Fixed: The DataOutBase::XDMFEntry class now has a proper serialization + function to allow for checkpointing. +
    + (Eric Heien, 2013/09/27) +
  2. + +
  3. + New: DataOutBase::DataOutFilter provides a way to remove duplicate vertices + and values from a solution vector when generating output. Currently it only + supports HDF5/XDMF output. +
    + (Eric Heien, 2013/09/27) +
  4. + +
  5. + Removed: DataOutBase::HDF5MemStream was removed and the functionality replaced + by DataOutBase::DataOutFilter. The user only manipulates these through + DataOutBase::write_hdf5_parallel so this change should be transparent. +
    + (Eric Heien, 2013/09/27) +
  6. +
  7. New: Like the usual DoFHandler class, the hp::DoFHandler class now also has a cache that makes operations such as cell-@>get_dof_indices(...) diff --git a/deal.II/include/deal.II/base/data_out_base.h b/deal.II/include/deal.II/base/data_out_base.h index 9693e21c6f..c8d60b3e0f 100644 --- a/deal.II/include/deal.II/base/data_out_base.h +++ b/deal.II/include/deal.II/base/data_out_base.h @@ -44,6 +44,7 @@ DEAL_II_NAMESPACE_OPEN class ParameterHandler; class XDMFEntry; +class DataOutFilter; /** * This is a base class for output of data on meshes of very general @@ -975,12 +976,12 @@ public: */ unsigned int cycle; - /** - * Flag to determine whether the current date and time shall be - * printed as a comment in the file's second line. - * - * Default is true. - */ + /** + * Flag to determine whether the current date and time shall be + * printed as a comment in the file's second line. + * + * Default is true. + */ bool print_date_and_time; /** @@ -1031,18 +1032,18 @@ public: struct SvgFlags { public: - /** - * Height of the image in SVG - * units. Default value is 4000. - */ - unsigned int height; - - /** - * Width of the image in SVG + /** + * Height of the image in SVG + * units. Default value is 4000. + */ + unsigned int height; + + /** + * Width of the image in SVG units. If left zero, the width is computed from the height. - */ - unsigned int width; - + */ + unsigned int width; + /** * This denotes the number of the data vector which shall be used * for generating the height information. By default, the first @@ -1050,8 +1051,8 @@ public: * is any data vector. If there is no data vector, no height * information is generated. */ - unsigned int height_vector; - + unsigned int height_vector; + /** * Angles for the perspective view */ @@ -1059,19 +1060,19 @@ public: unsigned int line_thickness; - /** - * Draw a margin of 5% around the plotted area - */ + /** + * Draw a margin of 5% around the plotted area + */ bool margin; - /** - * Draw a colorbar encoding the cell coloring - */ + /** + * Draw a colorbar encoding the cell coloring + */ bool draw_colorbar; - /** - * Constructor. - */ + /** + * Constructor. + */ SvgFlags(const unsigned int height_vector = 0, const int azimuth_angle = 37, const int polar_angle = 45, @@ -1150,6 +1151,233 @@ public: std::size_t memory_consumption () const; }; + /** + * Flags controlling the DataOutFilter. + * + * @ingroup output + */ + + struct DataOutFilterFlags + { + /** + * Filter duplicate vertices and associated values. This will + * drastically reduce the output data size but may affect the + * correctness of some calculated values. + */ + bool filter_duplicate_vertices; + + /** + * Whether the XDMF output refers to HDF5 files. + * This affects how output is structured. + */ + bool xdmf_hdf5_output; + + /** + * Constructor. + */ + DataOutFilterFlags (const bool filter_duplicate_vertices = false, + const bool xdmf_hdf5_output = false); + + /** + * Declare all flags with name + * and type as offered by this + * class, for use in input files. + */ + static void declare_parameters (ParameterHandler &prm); + + /** + * Read the parameters declared in + * declare_parameters and set the + * flags for this output format + * accordingly. + * + * The flags thus obtained overwrite + * all previous contents of this object. + */ + void parse_parameters (const ParameterHandler &prm); + + /** + * Determine an estimate for + * the memory consumption (in + * bytes) of this + * object. + */ + std::size_t memory_consumption () const; + }; + + /** + * DataOutFilter provides a way to remove redundant vertices and values + * generated by the deal.II output. By default, DataOutBase and the classes + * that build on it output data at each corner of each cell. This means + * that data is output multiple times for each vertex of the mesh. The + * purpose of this scheme is to support output of discontinuous quantities, + * either because the finite element space is discontinuous or because the + * quantity that is output is computed from a solution field and is + * discontinuous across faces. + * + * This class is an attempt to rein in the amount of data that is written. + * If the fields that are written to files are indeed discontinuous, the + * only way to faithfully represent them is indeed to write multiple + * values for each vertex (this is typically done by writing multiple + * node locations for the same vertex and defining data at these nodes). + * However, for fine meshes, one may not necessarily be interested in an + * exact representation of output fields that will likely only have + * small discontinuities. Rather, it may be sufficient to just output one + * value per vertex, which may be chosen arbitrarily from among those that + * are defined at this vertex from any of the adjacent cells. + */ + class DataOutFilter + { + private: + /** + * Empty class to provide comparison function for Map3DPoint. + */ + struct Point3Comp + { + bool operator() (const Point<3> &lhs, const Point<3> &rhs) const + { + return (lhs(0) < rhs(0) || (!(rhs(0) < lhs(0)) && (lhs(1) < rhs(1) || (!(rhs(1) < lhs(1)) && lhs(2) < rhs(2))))); + } + }; + + typedef std::multimap, unsigned int, Point3Comp> Map3DPoint; + + /// Flags used to specify filtering behavior + DataOutBase::DataOutFilterFlags flags; + + /// Dimensionality of the nodes, used to properly output filtered data + int node_dim; + + /// Number of vertices per cell + int n_cell_verts; + + /// Map of points to an internal index + Map3DPoint existing_points; + + /// Map of actual point index to internal point index + std::map filtered_points; + + /// Map of cells to the filtered points + std::map filtered_cells; + + /// Data set names + std::vector data_set_names; + + /// Data set dimensions + std::vector data_set_dims; + + /// Data set data + std::vector > data_sets; + + /** + * Record a cell vertex index based on the internal reordering. + */ + void internal_add_cell(const unsigned int &cell_index, const unsigned int &pt_index); + + public: + DataOutFilter() : flags(false, true) {}; + DataOutFilter(const DataOutBase::DataOutFilterFlags &flags) : flags(flags) {}; + + /** + * Write a point with the specified index into the filtered + * data set. If the point already exists and we are filtering + * redundant values, the provided index will internally refer + * to another recorded point. + */ + template + void write_point(const unsigned int &index, const Point &p); + + /** + * Record a deal.II cell in the internal reordered format. + */ + template + void write_cell(unsigned int index, unsigned int start, unsigned int d1, unsigned int d2, unsigned int d3); + + /** + * Filter and record a data set. If there are multiple values + * at a given vertex and redundant values are being removed, one + * is arbitrarily chosen as the recorded value. In the future + * this can be expanded to average/min/max multiple values + * at a given vertex. + */ + void write_data_set(const std::string &name, const unsigned int &dimension, const unsigned int &set_num, const Table<2,double> &data_vectors); + + /** + * Resize and fill a vector with all the filtered + * node vertex points, for output to a file. + */ + void fill_node_data(std::vector &node_data) const; + + /** + * Resize and fill a vector with all the filtered + * cell vertex indices, for output to a file. + */ + void fill_cell_data(const unsigned int &local_node_offset, std::vector &cell_data) const; + + /** + * Get the name of the data set indicated by the set number. + */ + std::string get_data_set_name(const unsigned int &set_num) const + { + return data_set_names.at(set_num); + }; + + /** + * Get the dimensionality of the data set indicated by the set number. + */ + unsigned int get_data_set_dim(const unsigned int &set_num) const + { + return data_set_dims.at(set_num); + }; + + /** + * Get the raw double valued data of the data set indicated by the set number. + */ + const double *get_data_set(const unsigned int &set_num) const + { + return &data_sets[set_num][0]; + }; + + /** + * Return the number of nodes in this DataOutFilter. This may be smaller + * than the original number of nodes if filtering is enabled. + */ + unsigned int n_nodes() const + { + return existing_points.size(); + }; + + /** + * Return the number of filtered cells in this DataOutFilter. Cells are + * not filtered so this will be the original number of cells. + */ + unsigned int n_cells() const + { + return filtered_cells.size()/n_cell_verts; + }; + + /** + * Return the number of filtered data sets in this DataOutFilter. Data sets are + * not filtered so this will be the original number of data sets. + */ + unsigned int n_data_sets() const + { + return data_set_names.size(); + }; + + /** + * Empty functions to do base class inheritance. + */ + void flush_points () {}; + + /** + * Empty functions to do base class inheritance. + */ + void flush_cells () {}; + + }; + + /** * Provide a data type specifying the presently supported output * formats. @@ -1659,28 +1887,42 @@ public: const Deal_II_IntermediateFlags &flags, std::ostream &out); + /** + * Write the data in data_filter to a single HDF5 file containing both + * the mesh and solution values. + */ template - static void write_hdf5_parallel ( - const std::vector > &patches, - const std::vector &data_names, - const std::vector > &vector_data_ranges, - const char *filename, - MPI_Comm comm); + static void write_hdf5_parallel (const std::vector > &patches, + const DataOutFilter &data_filter, + const std::string &filename, + MPI_Comm comm); + /** + * Write the data in data_filter to HDF5 file(s). If write_mesh_file + * is false, the mesh data will not be written and the solution + * file will contain only the solution values. If write_mesh_file + * is true and the filenames are the same, the resulting file will + * contain both mesh data and solution values. + */ template - static XDMFEntry create_xdmf_entry (const std::vector > &patches, - const std::vector &data_names, - const std::vector > &vector_data_ranges, - const char *h5_filename, - const double cur_time, - MPI_Comm comm); + static void write_hdf5_parallel (const std::vector > &patches, + const DataOutFilter &data_filter, + const bool &write_mesh_file, + const std::string &mesh_filename, + const std::string &solution_filename, + MPI_Comm comm); + /** + * DataOutFilter is an intermediate data format that reduces the amount of + * data that will be written to files. The object filled by this function + * can then later be used again to write data in a concrete file format; + * see, for example, DataOutBase::write_hdf5_parallel(). + */ template - static void write_xdmf_file ( - const std::vector > &patches, - const std::vector &entries, - const char *filename, - MPI_Comm comm); + static void write_filtered_data (const std::vector > &patches, + const std::vector &data_names, + const std::vector > &vector_data_ranges, + DataOutFilter &filtered_data); /** * Given an input stream that contains data written by @@ -2375,15 +2617,98 @@ public: */ void write_deal_II_intermediate (std::ostream &out) const; - XDMFEntry create_xdmf_entry (const char *h5_filename, + /** + * Create an XDMFEntry based on the data in this DataOutInterface. + @deprecated: use create_xdmf_entry(DataOutFilter, ...) instead + */ + XDMFEntry create_xdmf_entry (const std::string &h5_filename, + const double cur_time, + MPI_Comm comm) const DEAL_II_DEPRECATED; + + /** + * Create an XDMFEntry based on the data in the data_filter. This assumes + * the mesh and solution data were written to a single file. See + * write_xdmf_file() for an example of usage. + */ + XDMFEntry create_xdmf_entry (const DataOutFilter &data_filter, + const std::string &h5_filename, const double cur_time, MPI_Comm comm) const; + /** + * Create an XDMFEntry based on the data in the data_filter. This assumes + * the mesh and solution data were written to separate files. See + * write_xdmf_file() for an example of usage. + */ + XDMFEntry create_xdmf_entry (const DataOutFilter &data_filter, + const std::string &h5_mesh_filename, + const std::string &h5_solution_filename, + const double cur_time, + MPI_Comm comm) const; + + /** + * Write an XDMF file based on the provided vector of XDMFEntry objects. Below is + * an example of how to use this function with HDF5 and the DataOutFilter: + * + * @code + * DataOutBase::DataOutFilter data_filter(DataOutBase::DataOutFilterFlags(true, true)); + * std::vector xdmf_entries; + * // Filter the data and store it in data_filter + * data_out.write_filtered_data(data_filter); + * // Write the filtered data to HDF5 + * data_out.write_hdf5_parallel(data_filter, "solution.h5", MPI_COMM_WORLD); + * // Create an XDMF entry detailing the HDF5 file + * new_xdmf_entry = data_out.create_xdmf_entry(data_filter, "solution.h5", simulation_time, MPI_COMM_WORLD); + * // Add the XDMF entry to the list + * xdmf_entries.push_back(new_xdmf_entry); + * // Create an XDMF file from all stored entries + * data_out.write_xdmf_file(xdmf_entries, "solution.xdmf", MPI_COMM_WORLD); + * @endcode + */ void write_xdmf_file (const std::vector &entries, - const char *filename, + const std::string &filename, MPI_Comm comm) const; - void write_hdf5_parallel (const char *filename, MPI_Comm comm) const; + /** + * Write the data in this class without redundancy filtering to a + * single HDF5 file containing both the mesh and solution values. + @deprecated: use write_hdf5_parallel(DataOutFilter, ...) instead + */ + void write_hdf5_parallel (const std::string &filename, MPI_Comm comm) const DEAL_II_DEPRECATED; + + /** + * Write the data in data_filter to a single HDF5 file containing both + * the mesh and solution values. Below is an example of how to use this + * function with the DataOutFilter: + * + * @code + * DataOutBase::DataOutFilter data_filter(DataOutBase::DataOutFilterFlags(true, true)); + * // Filter the data and store it in data_filter + * data_out.write_filtered_data(data_filter); + * // Write the filtered data to HDF5 + * data_out.write_hdf5_parallel(data_filter, "solution.h5", MPI_COMM_WORLD); + * @endcode + */ + void write_hdf5_parallel (const DataOutFilter &data_filter, const std::string &filename, MPI_Comm comm) const; + + /** + * Write the data in data_filter to HDF5 file(s). If write_mesh_file + * is false, the mesh data will not be written and the solution + * file will contain only the solution values. If write_mesh_file + * is true and the filenames are the same, the resulting file will + * contain both mesh data and solution values. + */ + void write_hdf5_parallel (const DataOutFilter &data_filter, const bool &write_mesh_file, const std::string &mesh_filename, const std::string &solution_filename, MPI_Comm comm) const; + + /** + * DataOutFilter is an intermediate data format that reduces the amount of + * data that will be written to files. The object filled by this function + * can then later be used again to write data in a concrete file format; + * see, for example, DataOutBase::write_hdf5_parallel(). + */ + void write_filtered_data (DataOutFilter &filtered_data) const; + + /** * Write data and grid to out * according to the given data @@ -2806,24 +3131,30 @@ 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 +/** + * 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 allows the mesh to be separated from + * the the point data. + */ class XDMFEntry { private: - // Whether this entry is valid and contains data to be written + /// Whether this entry is valid and contains data to be written bool valid; - // The name of the HDF5 heavy data file this entry references - std::string h5_filename; - // The simulation time associated with this entry + /// 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 + /// 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 + /// The attributes associated with this entry and their dimension std::map attribute_dims; - // Small function to create indentation for XML file + /// Small function to create indentation for XML file std::string indent(const unsigned int indent_level) const { std::string res = ""; @@ -2832,17 +3163,35 @@ private: } public: - XDMFEntry(void) : 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_filename(filename), entry_time(time), num_nodes(nodes), num_cells(cells), dimension(dim) {}; + 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) {}; - // Record an attribute and associated dimensionality + /** + * Record an attribute and associated dimensionality. + */ void add_attribute(const std::string &attr_name, const unsigned int dimension) { attribute_dims[attr_name] = dimension; } - // Get the XDMF content associated with this entry - // If the entry is not valid, this returns false + /** + * Read or write the data of this object for serialization + */ + template + void serialize(Archive &ar, const unsigned int version) { + ar &valid + &h5_sol_filename + &h5_mesh_filename + &entry_time + &num_nodes + &num_cells + &dimension + &attribute_dims; + } + + /// 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; }; diff --git a/deal.II/source/base/data_out_base.cc b/deal.II/source/base/data_out_base.cc index edb10d95e5..37b34d217f 100644 --- a/deal.II/source/base/data_out_base.cc +++ b/deal.II/source/base/data_out_base.cc @@ -273,6 +273,116 @@ namespace #endif } +//----------------------------------------------------------------------// +// DataOutFilter class member functions +//----------------------------------------------------------------------// + +template +void DataOutBase::DataOutFilter::write_point(const unsigned int &index, const Point &p) +{ + Map3DPoint::const_iterator it; + unsigned int internal_ind; + Point<3> int_pt; + + for (int d=0; d<3; ++d) int_pt(d) = (d < dim ? p(d) : 0); + node_dim = dim; + it = existing_points.find(int_pt); + + // If the point isn't in the set, or we're not filtering duplicate points, add it + if (it == existing_points.end() || !flags.filter_duplicate_vertices) + { + internal_ind = existing_points.size(); + existing_points.insert(std::make_pair(int_pt, internal_ind)); + } + else + { + internal_ind = it->second; + } + // Now add the index to the list of filtered points + filtered_points[index] = internal_ind; +} + +void DataOutBase::DataOutFilter::internal_add_cell(const unsigned int &cell_index, const unsigned int &pt_index) +{ + filtered_cells[cell_index] = filtered_points[pt_index]; +} + +void DataOutBase::DataOutFilter::fill_node_data(std::vector &node_data) const +{ + Map3DPoint::const_iterator it; + + node_data.resize(existing_points.size()*node_dim); + + for (it=existing_points.begin(); it!=existing_points.end(); ++it) + { + for (int d=0; dsecond+d] = it->first(d); + } +} + +void DataOutBase::DataOutFilter::fill_cell_data(const unsigned int &local_node_offset, std::vector &cell_data) const +{ + std::map::const_iterator it; + + cell_data.resize(filtered_cells.size()); + + for (it=filtered_cells.begin(); it!=filtered_cells.end(); ++it) + { + cell_data[it->first] = it->second+local_node_offset; + } +} + +template +void +DataOutBase::DataOutFilter::write_cell( + unsigned int index, + unsigned int start, + unsigned int d1, + unsigned int d2, + unsigned int d3) +{ + unsigned int base_entry = index * GeometryInfo::vertices_per_cell; + n_cell_verts = GeometryInfo::vertices_per_cell; + internal_add_cell(base_entry+0, start); + internal_add_cell(base_entry+1, start+d1); + if (dim>=2) + { + 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); + } + } +} + +void DataOutBase::DataOutFilter::write_data_set(const std::string &name, const unsigned int &dimension, const unsigned int &set_num, const Table<2,double> &data_vectors) +{ + unsigned int num_verts = existing_points.size(); + unsigned int i, r, d, new_dim; + + // HDF5/XDMF output only supports 1D or 3D output, so force rearrangement if needed + if (flags.xdmf_hdf5_output && dimension != 1) new_dim = 3; + else new_dim = dimension; + + // Record the data set name, dimension, and allocate space for it + data_set_names.push_back(name); + data_set_dims.push_back(new_dim); + data_sets.push_back(std::vector(new_dim*num_verts)); + + // TODO: averaging, min/max, etc for merged vertices + for (i=0; i - void write_point (const unsigned int index, - const Point &); - - /** - * Do whatever is necessary to - * terminate the list of points. - * In this case, nothing. - */ - void flush_points () {}; - - /** - * Write dim-dimensional cell - * with first vertex at - * number start and further - * vertices offset by the - * specified values. Values - * not needed are ignored. - * - * The order of vertices for - * these cells in different - * dimensions is - *
      - *
    1. [0,1] - *
    2. [] - *
    3. [] - *
    - */ - template - void write_cell(const unsigned int index, - const unsigned int start, - const unsigned int x_offset, - const unsigned int y_offset, - const unsigned int z_offset); - - /** - * Do whatever is necessary to - * terminate the list of cells. - * In this case, nothing. - */ - void flush_cells () {}; - - const double *node_data(void) const - { - return &vertices[0]; - }; - const unsigned int *cell_data(void) const - { - return &cells[0]; - }; - - private: - /** - * A list of vertices and - * cells, used to write HDF5 data. - */ - std::vector vertices; - std::vector cells; - unsigned int node_offset; - }; - - //----------------------------------------------------------------------// DXStream::DXStream(std::ostream &out, @@ -1550,49 +1581,6 @@ namespace return stream; } - HDF5MemStream::HDF5MemStream(const unsigned int local_points_cell_count[2], const unsigned int global_points_cell_offsets[2], const unsigned int dim) - { - unsigned int entries_per_cell = (2 << (dim-1)); - - vertices.resize(local_points_cell_count[0]*dim); - cells.resize(local_points_cell_count[1]*entries_per_cell); - node_offset = global_points_cell_offsets[0]; - } - - template - void - HDF5MemStream::write_point (const unsigned int index, - const Point &p) - { - for (int i=0; i - void - HDF5MemStream::write_cell( - unsigned int index, - unsigned int start, - unsigned int d1, - unsigned int d2, - unsigned int d3) - { - unsigned int base_entry = index * GeometryInfo::vertices_per_cell; - cells[base_entry+0] = node_offset+start; - cells[base_entry+1] = node_offset+start+d1; - if (dim>=2) - { - cells[base_entry+2] = node_offset+start+d2+d1; - cells[base_entry+3] = node_offset+start+d2; - if (dim>=3) - { - cells[base_entry+4] = node_offset+start+d3; - cells[base_entry+5] = node_offset+start+d3+d1; - cells[base_entry+6] = node_offset+start+d3+d2+d1; - cells[base_entry+7] = node_offset+start+d3+d2; - } - } - } - template std::ostream & DXStream::operator<< (const T &t) @@ -1734,6 +1722,41 @@ DataOutBase::PovrayFlags::PovrayFlags (const bool smooth, {} +DataOutBase::DataOutFilterFlags::DataOutFilterFlags (const bool filter_duplicate_vertices, + const bool xdmf_hdf5_output) : + filter_duplicate_vertices(filter_duplicate_vertices), + xdmf_hdf5_output(xdmf_hdf5_output) {} + +void DataOutBase::DataOutFilterFlags::declare_parameters (ParameterHandler &prm) +{ + prm.declare_entry ("Filter duplicate vertices", "false", + Patterns::Bool(), + "Whether to remove duplicate vertex values."); + prm.declare_entry ("XDMF HDF5 output", "false", + Patterns::Bool(), + "Whether the data will be used in an XDMF/HDF5 combination."); +} + + + +void DataOutBase::DataOutFilterFlags::parse_parameters (const ParameterHandler &prm) +{ + filter_duplicate_vertices = prm.get_bool ("Filter duplicate vertices"); + xdmf_hdf5_output = prm.get_bool ("XDMF HDF5 output"); +} + + + +std::size_t +DataOutBase::DataOutFilterFlags::memory_consumption () const +{ + // only simple data elements, so + // use sizeof operator + return sizeof (*this); +} + + + DataOutBase::DXFlags::DXFlags (const bool write_neighbors, const bool int_binary, const bool coordinates_binary, @@ -2229,15 +2252,15 @@ DataOutBase::SvgFlags::SvgFlags (const unsigned int height_vector, const unsigned int line_thickness, const bool margin, const bool draw_colorbar) - : - height(4000), - width(0), - height_vector(height_vector), - azimuth_angle(azimuth_angle), - polar_angle(polar_angle), - line_thickness(line_thickness), - margin(margin), - draw_colorbar(draw_colorbar) + : + height(4000), + width(0), + height_vector(height_vector), + azimuth_angle(azimuth_angle), + polar_angle(polar_angle), + line_thickness(line_thickness), + margin(margin), + draw_colorbar(draw_colorbar) {} @@ -4952,15 +4975,15 @@ DataOutBase::write_vtk (const std::vector > &patches, << '\n' << "#This file was generated by the deal.II library"; if (flags.print_date_and_time) - out << " on " - << time->tm_year+1900 << "/" - << time->tm_mon+1 << "/" - << time->tm_mday << " at " - << time->tm_hour << ":" - << std::setw(2) << time->tm_min << ":" - << std::setw(2) << time->tm_sec; + out << " on " + << time->tm_year+1900 << "/" + << time->tm_mon+1 << "/" + << time->tm_mday << " at " + << time->tm_hour << ":" + << std::setw(2) << time->tm_min << ":" + << std::setw(2) << time->tm_sec; else - out << "."; + out << "."; out << '\n' << "ASCII" << '\n'; @@ -5183,15 +5206,15 @@ void DataOutBase::write_vtu_header (std::ostream &out, << '\n' << "#This file was generated by the deal.II library"; if (flags.print_date_and_time) - out << " on " - << time->tm_year+1900 << "/" - << time->tm_mon+1 << "/" - << time->tm_mday << " at " - << time->tm_hour << ":" - << std::setw(2) << time->tm_min << ":" - << std::setw(2) << time->tm_sec; + out << " on " + << time->tm_year+1900 << "/" + << time->tm_mon+1 << "/" + << time->tm_mday << " at " + << time->tm_hour << ":" + << std::setw(2) << time->tm_min << ":" + << std::setw(2) << time->tm_sec; else - out << "."; + out << "."; out << "\n-->\n"; out << " > &patches, } } } - + // write the svg file if (width==0) @@ -6713,11 +6736,11 @@ DataOutInterface::write_visit_record (std::ostream &out, out << "!NBLOCKS " << nblocks << '\n'; for (std::vector >::const_iterator domain = piece_names.begin(); domain != piece_names.end(); ++domain) - { - Assert(domain->size() == nblocks, ExcMessage("piece_names should be a vector of equal sized vectors.") ) - for (std::vector::const_iterator subdomain = domain->begin(); subdomain != domain->end(); ++subdomain) - out << *subdomain << '\n'; - } + { + Assert(domain->size() == nblocks, ExcMessage("piece_names should be a vector of equal sized vectors.") ) + for (std::vector::const_iterator subdomain = domain->begin(); subdomain != domain->end(); ++subdomain) + out << *subdomain << '\n'; + } out << std::flush; } @@ -6736,39 +6759,42 @@ write_deal_II_intermediate (std::ostream &out) const template XDMFEntry DataOutInterface:: -create_xdmf_entry (const char *h5_filename, const double cur_time, MPI_Comm comm) const +create_xdmf_entry (const std::string &h5_filename, const double cur_time, MPI_Comm comm) const +{ + DataOutBase::DataOutFilter data_filter(DataOutBase::DataOutFilterFlags(false, true)); + write_filtered_data(data_filter); + return create_xdmf_entry(data_filter, h5_filename, cur_time, comm); +} + +template +XDMFEntry DataOutInterface:: +create_xdmf_entry (const DataOutFilter &data_filter, const std::string &h5_filename, const double cur_time, MPI_Comm comm) const { - return DataOutBase::create_xdmf_entry(get_patches(), get_dataset_names(), get_vector_data_ranges(), - h5_filename, cur_time, comm); + return create_xdmf_entry(data_filter, h5_filename, h5_filename, cur_time, comm); } template -XDMFEntry DataOutBase::create_xdmf_entry (const std::vector > &patches, - const std::vector &data_names, - const std::vector > &vector_data_ranges, - const char *h5_filename, - const double cur_time, - MPI_Comm comm) +XDMFEntry DataOutInterface:: +create_xdmf_entry (const DataOutFilter &data_filter, const std::string &h5_mesh_filename, const std::string &h5_solution_filename, const double cur_time, MPI_Comm comm) const { unsigned int local_node_cell_count[2], global_node_cell_count[2]; - const unsigned int n_data_sets = data_names.size(); int myrank; #ifndef DEAL_II_WITH_HDF5 // throw an exception, but first make // sure the compiler does not warn about // the now unused function arguments - (void)patches; - (void)data_names; - (void)vector_data_ranges; - (void)h5_filename; + (void)data_filter; + (void)h5_mesh_filename; + (void)h5_solution_filename; (void)cur_time; (void)comm; AssertThrow(false, ExcMessage ("XDMF support requires HDF5 to be turned on.")); #endif AssertThrow(dim == 2 || dim == 3, ExcMessage ("XDMF only supports 2 or 3 dimensions.")); - compute_sizes(patches, local_node_cell_count[0], local_node_cell_count[1]); + local_node_cell_count[0] = data_filter.n_nodes(); + local_node_cell_count[1] = data_filter.n_cells(); // And compute the global total #ifdef DEAL_II_WITH_MPI @@ -6783,56 +6809,14 @@ XDMFEntry DataOutBase::create_xdmf_entry (const std::vector // Output the XDMF file only on the root process if (myrank == 0) { - XDMFEntry entry(h5_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); + unsigned int n_data_sets = data_filter.n_data_sets(); // The vector names generated here must match those generated in the HDF5 file - unsigned int i, n_th_vector, data_set, pt_data_vector_dim; - std::string vector_name; - for (n_th_vector=0,data_set=0; data_set(vector_data_ranges[n_th_vector]) < data_set) n_th_vector++; - - // Determine whether the data is multiple dimensions or one - if (n_th_vector < vector_data_ranges.size() && std_cxx1x::get<0>(vector_data_ranges[n_th_vector]) == data_set) - { - // Multiple dimensions - pt_data_vector_dim = std_cxx1x::get<1>(vector_data_ranges[n_th_vector]) - std_cxx1x::get<0>(vector_data_ranges[n_th_vector])+1; - - // Ensure the dimensionality of the data is correct - AssertThrow (std_cxx1x::get<1>(vector_data_ranges[n_th_vector]) >= std_cxx1x::get<0>(vector_data_ranges[n_th_vector]), - ExcLowerRange (std_cxx1x::get<1>(vector_data_ranges[n_th_vector]), std_cxx1x::get<0>(vector_data_ranges[n_th_vector]))); - AssertThrow (std_cxx1x::get<1>(vector_data_ranges[n_th_vector]) < n_data_sets, - ExcIndexRange (std_cxx1x::get<1>(vector_data_ranges[n_th_vector]), 0, n_data_sets)); - - // Determine the vector name - // Concatenate all the - // component names with double - // underscores unless a vector - // name has been specified - if (std_cxx1x::get<2>(vector_data_ranges[n_th_vector]) != "") - { - vector_name = std_cxx1x::get<2>(vector_data_ranges[n_th_vector]); - } - else - { - vector_name = ""; - for (i=std_cxx1x::get<0>(vector_data_ranges[n_th_vector]); i(vector_data_ranges[n_th_vector]); ++i) - vector_name += data_names[i] + "__"; - vector_name += data_names[std_cxx1x::get<1>(vector_data_ranges[n_th_vector])]; - } - } - else - { - // One dimension - pt_data_vector_dim = 1; - vector_name = data_names[data_set]; - } - - entry.add_attribute(vector_name, pt_data_vector_dim); - - // Advance the current data set - data_set += pt_data_vector_dim; + entry.add_attribute(data_filter.get_data_set_name(i), data_filter.get_data_set_dim(i)); } return entry; @@ -6846,19 +6830,8 @@ XDMFEntry DataOutBase::create_xdmf_entry (const std::vector template void DataOutInterface:: write_xdmf_file (const std::vector &entries, - const char *filename, + const std::string &filename, MPI_Comm comm) const -{ - DataOutBase::write_xdmf_file(get_patches(), entries, filename, comm); -} - - - -template -void DataOutBase::write_xdmf_file (const std::vector > &, - const std::vector &entries, - const char *filename, - MPI_Comm comm) { int myrank; @@ -6872,7 +6845,7 @@ void DataOutBase::write_xdmf_file (const std::vector > &, // Only rank 0 process writes the XDMF file if (myrank == 0) { - std::ofstream xdmf_file(filename); + std::ofstream xdmf_file(filename.c_str()); std::vector::const_iterator it; xdmf_file << "\n"; @@ -6894,8 +6867,10 @@ void DataOutBase::write_xdmf_file (const std::vector > &, } -// Get the XDMF content associated with this entry -// If the entry is not valid, this returns false +/* + * 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; @@ -6907,7 +6882,7 @@ std::string XDMFEntry::get_xdmf_content(const unsigned int indent_level) const ss << indent(indent_level+1) << "