VTUGridReader.cpp
1 /*---------------------------------------------------------------------------*\
2  *
3  * mimmo
4  *
5  * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6  *
7  * -------------------------------------------------------------------------
8  * License
9  * This file is part of mimmo.
10  *
11  * mimmo is free software: you can redistribute it and/or modify it
12  * under the terms of the GNU Lesser General Public License v3 (LGPL)
13  * as published by the Free Software Foundation.
14  *
15  * mimmo is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18  * License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with mimmo. If not, see <http://www.gnu.org/licenses/>.
22  *
23 \*---------------------------------------------------------------------------*/
24 
25 #include "VTUGridReader.hpp"
26 
27 namespace mimmo{
28 
32 VTUAbsorbStreamer::VTUAbsorbStreamer() : VTKBaseStreamer(){}
33 
38 
48 void VTUAbsorbStreamer::absorbData(std::fstream &stream, const std::string &name, bitpit::VTKFormat format,
49  uint64_t entries, uint8_t components, bitpit::VTKDataType datatype)
50 {
51  bitpit::VTKBaseStreamer::absorbData(stream, name, format, entries, components, datatype);
52 }
53 
58 
63 
74 void VTUGridStreamer::absorbData(std::fstream &stream, const std::string &name, bitpit::VTKFormat format,
75  uint64_t entries, uint8_t components, bitpit::VTKDataType datatype)
76 {
77  std::size_t sizeData = std::size_t(entries/components);
78  if (name == "Points") {
79  //get correct data type
80  points.resize(sizeData);
81  for (auto & p :points) {
82  for(auto &pval : p){
83  readDoublePod(stream, format, datatype, pval);
84  }
85  }
86  } else if (name == "offsets") {
87  offsets.resize(sizeData);
88  for (auto & voffset : offsets) {
89  readIntegerPod(stream, format, datatype, voffset);
90  }
91  } else if (name == "types") {
92  types.resize(sizeData);
93  for (auto & vtype : types) {
94  long dumType;
95  readIntegerPod(stream, format, datatype, dumType);
96  //find ElementType
97  switch (dumType) {
98  case 1:
99  vtype = bitpit::ElementType::VERTEX;
100  break;
101 
102  case 3:
103  vtype = bitpit::ElementType::LINE;
104  break;
105 
106  case 5:
107  vtype = bitpit::ElementType::TRIANGLE;
108  break;
109 
110  case 7:
111  vtype = bitpit::ElementType::POLYGON;
112  break;
113 
114  case 8:
115  vtype = bitpit::ElementType::PIXEL;
116  break;
117 
118  case 9:
119  vtype = bitpit::ElementType::QUAD;
120  break;
121 
122  case 10:
123  vtype = bitpit::ElementType::TETRA;
124  break;
125 
126  case 11:
127  vtype = bitpit::ElementType::VOXEL;
128  break;
129 
130  case 12:
131  vtype = bitpit::ElementType::HEXAHEDRON;
132  break;
133 
134  case 13:
135  vtype = bitpit::ElementType::WEDGE;
136  break;
137 
138  case 14:
139  vtype = bitpit::ElementType::PYRAMID;
140  break;
141 
142  case 42:
143  vtype = bitpit::ElementType::POLYHEDRON;
144  break;
145 
146  default:
147  vtype = bitpit::ElementType::UNDEFINED;
148  break;
149 
150  }
151  }
152  } else if (name == "connectivity") {
153  connectivitylist.resize(sizeData);
154  for (auto & vconn : connectivitylist) {
155  readIntegerPod(stream, format, datatype, vconn);
156  }
157  } else if (name == "faces") {
158  faces.resize(sizeData);
159  for (auto & vface : faces) {
160  readIntegerPod(stream, format, datatype, vface);
161  }
162  } else if (name == "faceoffsets") {
163  faceoffsets.resize(sizeData);
164  for (auto & vfoffset : faceoffsets) {
165  readIntegerPod(stream, format, datatype, vfoffset);
166  }
167  } else if (name == "cellIndex") {
168  cellsID.resize(sizeData);
169  for (auto & vcid : cellsID) {
170  readIntegerPod(stream, format, datatype, vcid);
171  }
172  } else if (name == "PID") {
173  pids.resize(sizeData);
174  for (auto & pid : pids) {
175  readIntegerPod(stream, format, datatype, pid);
176  }
177  } else if (name == "vertexIndex") {
178  pointsID.resize(sizeData);
179  for (auto & vpid : pointsID) {
180  readIntegerPod(stream, format, datatype, vpid);
181  }
182 #if MIMMO_ENABLE_MPI
183  }else if (name == "cellRank") {
184  cellsRank.resize(sizeData);
185  for (auto & cellRank : cellsRank) {
186  readIntegerPod(stream, format, datatype, cellRank);
187  }
188  }else if (name == "vertexRank") {
189  verticesRank.resize(sizeData);
190  for (auto & vertexRank : verticesRank) {
191  readIntegerPod(stream, format, datatype, vertexRank);
192  }
193  }else if (name == "cellGlobalIndex") {
194  cellsGlobalIndex.resize(sizeData);
195  for (auto & cellGlobalIndex : cellsGlobalIndex) {
196  readIntegerPod(stream, format, datatype, cellGlobalIndex);
197  }
198 #endif
199  }
200  //end of absorption.
201 }
202 
208 void VTUGridStreamer::decodeRawData(bitpit::PatchKernel & patch)
209 {
210 
211  //time to check reading result.
212  std::size_t nVertices, nCells;
213  nVertices = points.size();
214  nCells = offsets.size();
215  if(connectivitylist.size() < nCells ){
216  throw std::runtime_error("Error VTUGridStreamer : no valid connectivity info detected while reading *.vtu file.");
217  }
218 
219  //check for undefined cell types, if found throw a runtime error. Impossible to absorb completely the mesh.
220  bool checkUndefined = false;
221  {
222  std::vector<bitpit::ElementType>::iterator it = std::find(types.begin(), types.end(), bitpit::ElementType::UNDEFINED);
223  checkUndefined = (it != types.end());
224  }
225  if(checkUndefined){
226  throw std::runtime_error("Error VTUGridStreamer : found unsupported cell elements. Impossible to absorb mesh");
227  }
228 
229  //TODO for DEVELOPERS: here vertexRank and cellGlobalIndex field are not used to recreate the
230  // partitioned mesh in MPI versions. bitpit Patch will create them automatically (bitpit 1.7)
231  //starting from cellRank info only.
232  // If for some reason you need them or bitpit change its behaviour, abilitate their reading in VTUGridReader constructor
233  // and provide compliant implementation in this method, accordingly.
234 
235  patch.reserveVertices(nVertices);
236  patch.reserveCells(nCells);
237 
238  //reading mesh nodes and store it in vertices.
239  //check labels if any;
240  bool checkPointsID;
241  {
242  std::unordered_set<long> checkSet(pointsID.begin(), pointsID.end());
243  checkPointsID = ( checkSet.size() == nVertices);
244  }
245  //insert points and recover local/global map of vertices;
246  std::unordered_map<int, long> mapVert;
247  int counter = 0;
248  long idV=0;
249  for(const auto & p : points){
250  idV = bitpit::Vertex::NULL_ID;
251  if(checkPointsID) idV = pointsID[counter];
252  bitpit::PatchKernel::VertexIterator it = patch.addVertex(p, idV);
253  mapVert[counter] = (*it).getId();
254  ++counter;
255  }
256 
257  //reading mesh connectivity by offsets and store it in cells.
258  //check cell labels if any;
259  bool checkCellsID, checkFaceOffset, checkPID;
260  std::unordered_set<long> checkSet(cellsID.begin(), cellsID.end());
261  checkCellsID = ( checkSet.size() == nCells);
262  checkFaceOffset = ( (faceoffsets.size() == nCells) && (faces.size()>= nCells) );
263  checkPID = (pids.size() == nCells);
264 #if MIMMO_ENABLE_MPI
265  bool checkRank = (cellsRank.size() == nCells);
266 #endif
267  checkSet.clear();
268  //insert points;
269  counter = 0;
270  long idC = bitpit::Cell::NULL_ID;
271 #if MIMMO_ENABLE_MPI
272  int rank = -1;
273 #endif
274  int posCellBegin = 0, posFaceBegin=0;
275  bitpit::ElementType eltype;
276  long PID = 0;
277  livector1D conn;
278  std::size_t connSize;
279 
280  for(const auto & off : offsets){
281  if(checkCellsID) {idC= cellsID[counter];}
282  if(checkPID) {PID = pids[counter];}
283 #if MIMMO_ENABLE_MPI
284  if(checkRank) {rank = cellsRank[counter];}
285 #endif
286  eltype = types[counter];
287 
288  if(eltype == bitpit::ElementType::POLYHEDRON){
289  if(!checkFaceOffset){
290  throw std::runtime_error("Error VTUGridStreamer : trying to acquire POLYHEDRON info without faces and faceoffsets data");
291  }
292  connSize = faceoffsets[counter] - posFaceBegin;
293  conn.resize(connSize);
294  int loc = 0;
295  for(int i=posFaceBegin; i<faceoffsets[counter]; ++i){
296  conn[loc] = faces[i];
297  ++loc;
298  }
299  //remap vertices: conn is now written face by face with local vertex indices
300  int posfbegin = 1, posfend; //begin from 1- value. 0 value of conn contains the total number fo faces
301  while(posfbegin < int(connSize)){
302  posfend = posfbegin +conn[posfbegin] + 1;
303  for(int i=posfbegin+1; i<posfend; ++i){
304  conn[i] = mapVert[conn[i]];
305  }
306  posfbegin = posfend;
307  }
308  }else if(eltype == bitpit::ElementType::POLYGON){
309  connSize = off - posCellBegin;
310  conn.resize(connSize +1);
311  conn[0] = connSize;
312  int loc =1;
313  for(int i=posCellBegin; i<off; ++i){
314  conn[loc] = mapVert[connectivitylist[i]];
315  ++loc;
316  }
317  }else{
318  connSize = off - posCellBegin;
319  conn.resize(connSize);
320  int loc =0;
321  for(int i=posCellBegin; i<off; ++i){
322  conn[loc] = mapVert[connectivitylist[i]];
323  ++loc;
324  }
325  }
326 
327 #if MIMMO_ENABLE_MPI
328  if(rank < 0) rank = patch.getRank();
329  bitpit::PatchKernel::CellIterator it = patch.addCell(eltype, conn, rank, idC);
330 #else
331  bitpit::PatchKernel::CellIterator it = patch.addCell(eltype, conn, idC);
332 #endif
333 
334  (*it).setPID(PID);
335 
336  posCellBegin = off;
337  if(checkFaceOffset){
338  if(faceoffsets[counter] > 0) posFaceBegin = faceoffsets[counter];
339  }
340  ++counter;
341  }
342 }
343 
350 void
351 VTUGridStreamer::readIntegerPod(std::fstream & stream, bitpit::VTKFormat& format, bitpit::VTKDataType& datatype, long &target){
352 
353  //check ascii first.
354  if(format == bitpit::VTKFormat::ASCII){
355  bitpit::genericIO::absorbASCII(stream,target);
356  return;
357  }
358  //get datatype and read binary
359  switch(datatype){
360  case bitpit::VTKDataType::Int8 :
361  {
362  int8_t val;
363  bitpit::genericIO::absorbBINARY(stream, val);
364  target = val;
365  }
366  break;
367  case bitpit::VTKDataType::UInt8 :
368  {
369  uint8_t val;
370  bitpit::genericIO::absorbBINARY(stream, val);
371  target = val;
372  }
373  break;
374  case bitpit::VTKDataType::Int16 :
375  {
376  int16_t val;
377  bitpit::genericIO::absorbBINARY(stream, val);
378  target = val;
379  }
380  break;
381  case bitpit::VTKDataType::UInt16 :
382  {
383  uint16_t val;
384  bitpit::genericIO::absorbBINARY(stream, val);
385  target = val;
386  }
387  break;
388  case bitpit::VTKDataType::Int32 :
389  {
390  int32_t val;
391  bitpit::genericIO::absorbBINARY(stream, val);
392  target = val;
393  }
394  break;
395  case bitpit::VTKDataType::UInt32 :
396  {
397  uint32_t val;
398  bitpit::genericIO::absorbBINARY(stream, val);
399  target = val;
400  }
401  break;
402  case bitpit::VTKDataType::Int64 :
403  {
404  int64_t val;
405  bitpit::genericIO::absorbBINARY(stream, val);
406  target = val;
407  }
408  break;
409  case bitpit::VTKDataType::UInt64 :
410  //not supported here, but very unlikely in paraview/vtk meshes.
411  default:
412  throw std::runtime_error("VTUGridStreamer::absorbData :integer pod binary absorption, VTKDataType format unavailable");
413  break;
414  }
415 }
416 
423 void
424 VTUGridStreamer::readDoublePod(std::fstream & stream, bitpit::VTKFormat& format, bitpit::VTKDataType& datatype, double&target){
425 
426  //check ascii first
427  if(format == bitpit::VTKFormat::ASCII){
428  bitpit::genericIO::absorbASCII(stream,target);
429  return;
430  }
431  //check datatype for binary absorption
432  switch (datatype){
433  case bitpit::VTKDataType::Float32 :
434  {
435  float val;
436  bitpit::genericIO::absorbBINARY(stream, val);
437  target = val;
438  }
439  break;
440  case bitpit::VTKDataType::Float64:
441  {
442  double val;
443  bitpit::genericIO::absorbBINARY(stream, val);
444  target = val;
445  }
446  break;
447  default:
448  throw std::runtime_error("VTUGridStreamer::absorbData : double pod binary absorption, VTKDataType format unavailable");
449  break;
450  }
451 }
452 
453 
466 VTUGridReader::VTUGridReader( std::string dir, std::string name, VTUAbsorbStreamer & streamer, bitpit::PatchKernel & patch, bool masterRankOnly, bitpit::VTKElementType eltype) :
467  VTKUnstructuredGrid(dir, name, eltype), m_patch(patch), m_streamer(streamer)
468 {
469  for(auto & field : m_geometry){
470  field.enable();
471  field.setStreamer(streamer);
472  }
473 
474  addData<long>("vertexIndex", bitpit::VTKFieldType::SCALAR, bitpit::VTKLocation::POINT, &streamer);
475  addData<long>("cellIndex", bitpit::VTKFieldType::SCALAR, bitpit::VTKLocation::CELL, &streamer);
476  addData<int>("PID", bitpit::VTKFieldType::SCALAR, bitpit::VTKLocation::CELL, &streamer);
477 
478 #if MIMMO_ENABLE_MPI
479  addData<int>("cellRank", bitpit::VTKFieldType::SCALAR, bitpit::VTKLocation::CELL, &streamer);
480  //TODO for DEVELOPERS: vertexRank and CellGlobalIndex are not needed for now
481  //(bitpit 1.7) to reconstruct the parallel mesh. Please enable again the Data adding to restore
482  // the reading of these 2 fields and provide a compliant implentation of VTUGridStreamer::decodeRawData
483  // that use properly these fields.
484 
485 // addData<int>("vertexRank", bitpit::VTKFieldType::SCALAR, bitpit::VTKLocation::POINT, &streamer);
486 // addData<int>("cellGlobalIndex", bitpit::VTKFieldType::SCALAR, bitpit::VTKLocation::CELL, &streamer);
487 
488  //set 0-rank or multi rank mode.
489  m_masterRankOnly = true;
490  if (m_patch.getProcessorCount() > 1 && !masterRankOnly) {
491  setParallel(m_patch.getProcessorCount(), m_patch.getRank());
492  m_masterRankOnly = false;
493  }
494 #else
495  BITPIT_UNUSED(masterRankOnly);
496 #endif
497 
498 }
499 
504 
509  //clear target data
510  m_patch.reset();
511 
512 #if MIMMO_ENABLE_MPI
513  //MPI version, check if master rank only reading is forced.
514  if (!m_masterRankOnly){ //all ranks do the calls
515  VTKUnstructuredGrid::read();
516  m_streamer.decodeRawData(m_patch);
517  }else{
518  if(m_patch.getRank() == 0){ //do it with 0 rank only
519  VTKUnstructuredGrid::read();
520  m_streamer.decodeRawData(m_patch);
521  }
522  }
523 #else
524  //normal serial working
525  VTKUnstructuredGrid::read();
526  m_streamer.decodeRawData(m_patch);
527 #endif
528 }
529 
530 }
virtual void decodeRawData(bitpit::PatchKernel &)=0
std::vector< long > livector1D
Abstract class for custom reader/absorber of *.vtu mesh external files.
void readDoublePod(std::fstream &stream, bitpit::VTKFormat &format, bitpit::VTKDataType &datatype, double &target)
std::vector< bitpit::ElementType > types
virtual void absorbData(std::fstream &stream, const std::string &name, bitpit::VTKFormat format, uint64_t entries, uint8_t components, bitpit::VTKDataType datatype)
VTUGridReader(std::string dir, std::string name, VTUAbsorbStreamer &streamer, bitpit::PatchKernel &patch, bool masterRankOnly=true, bitpit::VTKElementType eltype=bitpit::VTKElementType::UNDEFINED)
virtual void absorbData(std::fstream &stream, const std::string &name, bitpit::VTKFormat format, uint64_t entries, uint8_t components, bitpit::VTKDataType datatype)
void readIntegerPod(std::fstream &stream, bitpit::VTKFormat &format, bitpit::VTKDataType &datatype, long &target)
void decodeRawData(bitpit::PatchKernel &patch)