1 #pragma once 2 3 #include <iosfwd> 4 #include <map> 5 #include <memory> 6 #include <vector> 7 8 #include <dune/common/shared_ptr.hh> 9 #include <dune/common/typelist.hh> 10 #include <dune/common/typeutilities.hh> 11 12 #include <dune/vtk/filereader.hh> 13 #include <dune/vtk/types.hh> 14 #include <dune/vtk/utility/errors.hh> 15 16 // default GridCreator 17 #include <dune/vtk/gridcreators/continuousgridcreator.hh> 18 #include <dune/vtk/gridfunctions/common.hh> 19 20 namespace Dune 21 { 22 /// File-Reader for Vtk unstructured .vtu files 23 /** 24 * Reads .vtu files and constructs a grid from the cells stored in the file 25 * Additionally, stored data can be read. 26 * 27 * NOTE: Assumption on the file structure: Each XML tag must be on a separate line. 28 * 29 * \tparam Grid The type of the grid to construct. 30 * \tparam GC GridCreator policy type to control what to pass to a grid factory with 31 * data given from the file. [ContinuousGridCreator] 32 * \tparam FieldType Type of the components of the data to extract from the file [default: double] 33 **/ 34 template <class Grid, class GC = Vtk::ContinuousGridCreator<Grid>, class FieldType = double> 35 class VtkReader 36 : public Vtk::FileReader<Grid, VtkReader<Grid, GC>> 37 { 38 // Sections visited during the xml parsing 39 enum Sections { 40 NO_SECTION = 0, VTK_FILE, UNSTRUCTURED_GRID, PIECE, POINT_DATA, PD_DATA_ARRAY, CELL_DATA, CD_DATA_ARRAY, 41 POINTS, POINTS_DATA_ARRAY, CELLS, CELLS_DATA_ARRAY, APPENDED_DATA, XML_NAME, XML_NAME_ASSIGN, XML_VALUE 42 }; 43 44 // Type storing information about read data 45 struct DataArrayAttributes 46 { 47 std::string name; 48 Vtk::DataTypes type; 49 unsigned int components = 1; 50 std::uint64_t offset = 0; 51 Sections section = NO_SECTION; 52 }; 53 54 // Type of global world coordinates 55 using GlobalCoordinate = typename GC::GlobalCoordinate; 56 57 // Template representing a grid-function that is created in getPointData() and getCellData() 58 // with Context either Vtk::PointContext or Vek::CellContext, respectively. 59 // To each GridCreator a GridFunction is associated, see, e.g. Vtk::ContinuousGridFunction 60 // or Vtk::LagrangeGridFunction. 61 template <class Context> 62 using GridFunction = typename Vtk::AssociatedGridFunction<GC, FieldType, Context>::type; 63 64 public: 65 using GridCreator = GC; 66 67 /// GridFunction representing the data stored on the points in the file 68 using PointGridFunction = GridFunction<Vtk::PointContext>; 69 70 /// GridFunction representing the data stored on the cells in the file 71 using CellGridFunction = GridFunction<Vtk::CellContext>; 72 73 public: 74 /// Constructor. Creates a new GridCreator with the passed factory 75 /** 76 * \param args... Either pass a GridFactory by reference or shared_ptr, or a list of arguments 77 * passed to the constructor of a Dune::GridFactory (typically and empty parameter 78 * list). See the constructor of \ref GridCreatorInterface and the GridCreator 79 * passed to this reader. 80 **/ 81 template <class... Args, 82 std::enable_if_t<std::is_constructible<GridCreator, Args...>::value,int> = 0> VtkReader(Args &&...args)83 explicit VtkReader (Args&&... args) 84 : VtkReader(std::make_shared<GridCreator>(std::forward<Args>(args)...)) 85 {} 86 87 /// Constructor. Stores the references in a non-destroying shared_ptr VtkReader(GridCreator & creator)88 explicit VtkReader (GridCreator& creator) 89 : VtkReader(stackobject_to_shared_ptr(creator)) 90 {} 91 92 /// Constructor. Stores the shared_ptr VtkReader(std::shared_ptr<GridCreator> creator)93 explicit VtkReader (std::shared_ptr<GridCreator> creator) 94 : creator_(std::move(creator)) 95 {} 96 97 /// Read the grid from file with `filename` into the GridCreator 98 /** 99 * This function fills internal data containers representing the information from the 100 * passed file. 101 * 102 * \param filename The name of the input file 103 * \param fillCreator If `false`, only fill internal data structures, if `true`, pass 104 * the internal data to the GridCreator. [true] 105 **/ 106 void read (std::string const& filename, bool fillCreator = true); 107 108 /// Obtains the creator of the reader gridCreator()109 GridCreator& gridCreator () 110 { 111 return *creator_; 112 } 113 114 /// Construct the actual grid using the GridCreator 115 /// [[expects: read_ == true]] createGrid() const116 std::unique_ptr<Grid> createGrid () const 117 { 118 return creator_->createGrid(); 119 } 120 121 /// Construct a grid-function representing the point-data with the given name 122 /// [[expects: read_ == true]] getPointData(std::string const & name) const123 GridFunction<Vtk::PointContext> getPointData (std::string const& name) const 124 { 125 auto data_it = dataArray_.find("PointData." + name); 126 auto point_it = pointData_.find("PointData." + name); 127 VTK_ASSERT_MSG(data_it != dataArray_.end() && point_it != pointData_.end(), 128 "The data to extract is not found in point-data. Try `getCellData()` instead!"); 129 VTK_ASSERT(data_it->second.section == POINT_DATA); 130 131 return {*creator_, point_it->second, data_it->second.name, data_it->second.components, 132 data_it->second.type, vec_types, vec_offsets, vec_connectivity}; 133 } 134 135 /// Return a vector of DataArrayAttributes for all POINT_DATA blocks 136 /// [[expects: read_ == true]] getPointDataAttributes() const137 std::vector<DataArrayAttributes> getPointDataAttributes () const 138 { 139 std::vector<DataArrayAttributes> attributes; 140 attributes.reserve(pointData_.size()); 141 for (auto const& da : dataArray_) { 142 if (da.second.section == POINT_DATA) 143 attributes.push_back(da.second); 144 } 145 return attributes; 146 } 147 148 /// Construct a grid-function representing the cell-data with the given name 149 /// [[expects: read_ == true]] getCellData(std::string const & name) const150 GridFunction<Vtk::CellContext> getCellData (std::string const& name) const 151 { 152 auto data_it = dataArray_.find("CellData." + name); 153 auto cell_it = cellData_.find("CellData." + name); 154 VTK_ASSERT_MSG(data_it != dataArray_.end() && cell_it != cellData_.end(), 155 "The data to extract is not found in cell-data. Try `getPointData()` instead!"); 156 VTK_ASSERT(data_it->second.section == CELL_DATA); 157 158 return {*creator_, cell_it->second, data_it->second.name, data_it->second.components, 159 data_it->second.type, vec_types, vec_offsets, vec_connectivity}; 160 } 161 162 /// Return a vector of DataArrayAttributes for all CELL_DATA blocks 163 /// [[expects: read_ == true]] getCellDataAttributes() const164 std::vector<DataArrayAttributes> getCellDataAttributes () const 165 { 166 std::vector<DataArrayAttributes> attributes; 167 attributes.reserve(cellData_.size()); 168 for (auto const& da : dataArray_) { 169 if (da.second.section == CELL_DATA) 170 attributes.push_back(da.second); 171 } 172 return attributes; 173 } 174 175 /// Advanced read methods 176 /// @{ 177 178 /// Read the grid from an input stream, referring to a .vtu file, into the GridFactory \ref factory_ 179 /** 180 * \param input A STL input stream to read the VTK file from. 181 * \param create If `false`, only fill internal data structures, if `true`, also create the grid. [true] 182 **/ 183 void readSerialFileFromStream (std::ifstream& input, bool create = true); 184 185 /// Read the grid from and input stream, referring to a .pvtu file, into the GridFactory \ref factory_ 186 /** 187 * \param input A STL input stream to read the VTK file from. 188 * \param create If `false`, only fill internal data structures, if `true`, also create the grid. [true] 189 **/ 190 void readParallelFileFromStream (std::ifstream& input, int rank, int size, bool create = true); 191 192 /// Insert all internal data to the GridCreator 193 /// NOTE: requires an aforegoing call to \ref read() 194 void fillGridCreator (bool insertPieces = true); 195 196 /// @} 197 198 /// Return the filenames of parallel pieces pieces() const199 std::vector<std::string> const& pieces () const 200 { 201 return pieces_; 202 } 203 204 #ifndef DOXYGEN 205 // Implementation of the FileReader interface fillFactoryImpl(GridFactory<Grid> & factory,std::string const & filename)206 static void fillFactoryImpl (GridFactory<Grid>& factory, std::string const& filename) 207 { 208 VtkReader reader{factory}; 209 reader.read(filename); 210 } 211 #endif 212 213 private: 214 // Read values stored on the cells with ID `id` 215 Sections readCellData (std::ifstream& input, std::string id); 216 217 template <class F, class H> 218 void readCellDataAppended (MetaType<F>, MetaType<H>, std::ifstream& input, std::string id); 219 220 // Read values stored on the points with ID `id` 221 Sections readPointData (std::ifstream& input, std::string id); 222 223 template <class F, class H> 224 void readPointDataAppended (MetaType<F>, MetaType<H>, std::ifstream& input, std::string id); 225 226 227 // Read vertex coordinates from `input` stream and store in into `factory` 228 Sections readPoints (std::ifstream& input, std::string id); 229 230 template <class F, class H> 231 void readPointsAppended (MetaType<F>, MetaType<H>, std::ifstream& input); 232 233 234 // Read cell type, cell offsets and connectivity from `input` stream 235 Sections readCells (std::ifstream& input, std::string id); 236 237 template <class H> 238 void readCellsAppended (MetaType<H>, std::ifstream& input); 239 240 // Read data from appended section in vtk file, starting from `offset` 241 template <class FloatType, class HeaderType> 242 void readAppended (std::ifstream& input, std::vector<FloatType>& values, HeaderType offset); 243 244 // Test whether line belongs to section isSection(std::string line,std::string key,Sections current,Sections parent=NO_SECTION) const245 bool isSection (std::string line, 246 std::string key, 247 Sections current, 248 Sections parent = NO_SECTION) const 249 { 250 bool result = line.substr(1, key.length()) == key; 251 if (result && current != parent) 252 DUNE_THROW(Exception , "<" << key << "> in wrong section." ); 253 return result; 254 } 255 256 // Convert a section into a string 257 std::string toString (Sections s) const; 258 259 // Find beginning of appended binary data 260 std::uint64_t findAppendedDataPosition (std::ifstream& input) const; 261 262 // Read attributes from current xml tag 263 std::map<std::string, std::string> parseXml (std::string const& line, bool& closed); 264 265 // clear all vectors 266 void clear (); 267 comm() const268 auto comm () const 269 { 270 return MPIHelper::getCollectiveCommunication(); 271 } 272 273 private: 274 std::shared_ptr<GridCreator> creator_; 275 276 /// Data format, i.e. ASCII, BINARY or COMPRESSED. Read from xml attributes. 277 Vtk::FormatTypes format_; 278 279 /// Type of compression algorithm used for binary data 280 Vtk::CompressorTypes compressor_; 281 282 // Temporary data to construct the grid elements 283 std::vector<GlobalCoordinate> vec_points; 284 std::vector<std::uint64_t> vec_point_ids; //< Global unique vertex ID 285 std::vector<std::uint8_t> vec_types; //< VTK cell type ID 286 std::vector<std::int64_t> vec_offsets; //< offset of vertices of cell 287 std::vector<std::int64_t> vec_connectivity; //< vertex indices of cell 288 289 std::size_t numberOfCells_ = 0; //< Number of cells in the grid 290 std::size_t numberOfPoints_ = 0; //< Number of vertices in the grid 291 292 // offset information for appended data 293 // map: id -> {Name,DataType,NumberOfComponents,Offset} 294 std::map<std::string, DataArrayAttributes> dataArray_; 295 296 // storage for internal point and cell data 297 // map: id -> vector of data entries per point/cell 298 std::map<std::string, std::vector<FieldType>> pointData_; 299 std::map<std::string, std::vector<FieldType>> cellData_; 300 301 // vector of filenames of parallel pieces 302 std::vector<std::string> pieces_; 303 304 /// Offset of beginning of appended data 305 std::uint64_t offset0_ = 0; 306 307 bool read_ = false; 308 }; 309 310 // deduction guides 311 template <class Grid> 312 VtkReader (GridFactory<Grid>&) 313 -> VtkReader<Grid, Vtk::ContinuousGridCreator<Grid>>; 314 315 template <class GridCreator, 316 class = std::void_t<typename GridCreator::Grid>> 317 VtkReader (GridCreator&) 318 -> VtkReader<typename GridCreator::Grid, GridCreator>; 319 320 template <class GridCreator, 321 class = std::void_t<typename GridCreator::Grid>> 322 VtkReader (std::shared_ptr<GridCreator>) 323 -> VtkReader<typename GridCreator::Grid, GridCreator>; 324 325 } // end namespace Dune 326 327 #include "vtkreader.impl.hh" 328