1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkMPIMultiBlockPLOT3DReader.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkMPIMultiBlockPLOT3DReader.h"
16
17 #include "vtkByteSwap.h"
18 #include "vtkDoubleArray.h"
19 #include "vtkErrorCode.h"
20 #include "vtkFloatArray.h"
21 #include "vtkIntArray.h"
22 #include "vtkMPICommunicator.h"
23 #include "vtkMPIController.h"
24 #include "vtkMPI.h"
25 #include "vtkMultiBlockPLOT3DReaderInternals.h"
26 #include "vtkObjectFactory.h"
27 #include "vtkStructuredData.h"
28 #include <exception>
29 #include <cassert>
30
31
32
33 #define DEFINE_MPI_TYPE(ctype, mpitype) \
34 template <> struct mpi_type<ctype> { static MPI_Datatype type() { return mpitype; } };
35
36 namespace
37 {
38 template <class T> struct mpi_type {};
39 DEFINE_MPI_TYPE(char, MPI_CHAR);
40 DEFINE_MPI_TYPE(signed char, MPI_SIGNED_CHAR);
41 DEFINE_MPI_TYPE(unsigned char, MPI_UNSIGNED_CHAR);
42 DEFINE_MPI_TYPE(short, MPI_SHORT);
43 DEFINE_MPI_TYPE(unsigned short, MPI_UNSIGNED_SHORT);
44 DEFINE_MPI_TYPE(int, MPI_INT);
45 DEFINE_MPI_TYPE(unsigned int, MPI_UNSIGNED);
46 DEFINE_MPI_TYPE(long, MPI_LONG);
47 DEFINE_MPI_TYPE(unsigned long, MPI_UNSIGNED_LONG);
48 DEFINE_MPI_TYPE(float, MPI_FLOAT);
49 DEFINE_MPI_TYPE(double, MPI_DOUBLE);
50 DEFINE_MPI_TYPE(long long, MPI_LONG_LONG);
51 DEFINE_MPI_TYPE(unsigned long long, MPI_UNSIGNED_LONG_LONG);
52
53 class MPIPlot3DException : public std::exception
54 {
55 };
56
57 template <class DataType>
58 class vtkMPIPLOT3DArrayReader
59 {
60 public:
vtkMPIPLOT3DArrayReader()61 vtkMPIPLOT3DArrayReader() : ByteOrder(
62 vtkMultiBlockPLOT3DReader::FILE_BIG_ENDIAN)
63 {
64 }
65
ReadScalar(void * vfp,vtkTypeUInt64 offset,vtkIdType preskip,vtkIdType n,vtkIdType vtkNotUsed (postskip),DataType * scalar,const vtkMultiBlockPLOT3DReaderRecord & record=vtkMultiBlockPLOT3DReaderRecord ())66 vtkIdType ReadScalar(void* vfp,
67 vtkTypeUInt64 offset,
68 vtkIdType preskip,
69 vtkIdType n,
70 vtkIdType vtkNotUsed(postskip),
71 DataType* scalar,
72 const vtkMultiBlockPLOT3DReaderRecord& record = vtkMultiBlockPLOT3DReaderRecord())
73 {
74 vtkMPIOpaqueFileHandle* fp = reinterpret_cast<vtkMPIOpaqueFileHandle*>(vfp);
75 assert(fp);
76
77 // skip preskip if we're setting over subrecord separators.
78 offset += record.GetLengthWithSeparators(offset, preskip*sizeof(DataType));
79
80 // Let's see if we encounter markers while reading the data from current
81 // position.
82 std::vector<std::pair<vtkTypeUInt64, vtkTypeUInt64> > chunks =
83 record.GetChunksToRead(offset, sizeof(DataType) * n);
84
85 const int dummy_INT_MAX = 2e9; /// XXX: arbitrary limit that seems
86 /// to work when reading large files.
87 vtkIdType bytesread = 0;
88 for (size_t cc=0; cc < chunks.size(); cc++)
89 {
90 vtkTypeUInt64 start = chunks[cc].first;
91 vtkTypeUInt64 length = chunks[cc].second;
92 while (length > 0)
93 {
94 int segment = length > static_cast<vtkTypeUInt64>(dummy_INT_MAX)?
95 (length - dummy_INT_MAX) : static_cast<int>(length);
96
97 MPI_Status status;
98 if (MPI_File_read_at(fp->Handle, start,
99 reinterpret_cast<char*>(scalar) + bytesread,
100 segment, MPI_UNSIGNED_CHAR, &status) != MPI_SUCCESS)
101 {
102 return 0; // let's assume nothing was read.
103 }
104 start += segment;
105 length -= segment;
106 bytesread += segment;
107 }
108 }
109
110 if (this->ByteOrder == vtkMultiBlockPLOT3DReader::FILE_LITTLE_ENDIAN)
111 {
112 if (sizeof(DataType) == 4)
113 {
114 vtkByteSwap::Swap4LERange(scalar, n);
115 }
116 else
117 {
118 vtkByteSwap::Swap8LERange(scalar, n);
119 }
120 }
121 else
122 {
123 if (sizeof(DataType) == 4)
124 {
125 vtkByteSwap::Swap4BERange(scalar, n);
126 }
127 else
128 {
129 vtkByteSwap::Swap8BERange(scalar, n);
130 }
131 }
132 return bytesread / sizeof(DataType);
133 }
134
ReadVector(void * vfp,vtkTypeUInt64 offset,int extent[6],int wextent[6],int numDims,DataType * vector,const vtkMultiBlockPLOT3DReaderRecord & record)135 vtkIdType ReadVector(void* vfp,
136 vtkTypeUInt64 offset,
137 int extent[6], int wextent[6],
138 int numDims, DataType* vector,
139 const vtkMultiBlockPLOT3DReaderRecord &record)
140 {
141 vtkIdType n = vtkStructuredData::GetNumberOfPoints(extent);
142 vtkIdType totalN = vtkStructuredData::GetNumberOfPoints(wextent);
143
144 // Setting to 0 in case numDims == 0. We still need to
145 // populate an array with 3 components but the code below
146 // does not read the 3rd component (it doesn't exist
147 // in the file)
148 memset(vector, 0, n*3*sizeof(DataType));
149
150 vtkIdType retVal = 0;
151 DataType* buffer = new DataType[n];
152 for (int component = 0; component < numDims; component++)
153 {
154 vtkIdType preskip, postskip;
155 vtkMultiBlockPLOT3DReaderInternals::CalculateSkips(extent, wextent, preskip, postskip);
156 vtkIdType valread = this->ReadScalar(vfp, offset, preskip, n, postskip, buffer, record);
157 if (valread != n)
158 {
159 return 0; // failed.
160 }
161 retVal += valread;
162 for (vtkIdType i=0; i<n; i++)
163 {
164 vector[3*i+component] = buffer[i];
165 }
166 offset += record.GetLengthWithSeparators(offset, totalN * sizeof(DataType));
167 }
168 delete[] buffer;
169 return retVal;
170 }
171 int ByteOrder;
172 };
173 }
174
175 vtkStandardNewMacro(vtkMPIMultiBlockPLOT3DReader);
176 //----------------------------------------------------------------------------
vtkMPIMultiBlockPLOT3DReader()177 vtkMPIMultiBlockPLOT3DReader::vtkMPIMultiBlockPLOT3DReader()
178 {
179 this->UseMPIIO = true;
180 }
181
182 //----------------------------------------------------------------------------
~vtkMPIMultiBlockPLOT3DReader()183 vtkMPIMultiBlockPLOT3DReader::~vtkMPIMultiBlockPLOT3DReader()
184 {
185 }
186
187 //----------------------------------------------------------------------------
CanUseMPIIO()188 bool vtkMPIMultiBlockPLOT3DReader::CanUseMPIIO()
189 {
190 return (this->UseMPIIO && this->BinaryFile &&
191 this->Internal->Settings.NumberOfDimensions == 3 &&
192 vtkMPIController::SafeDownCast(this->Controller) != nullptr);
193 }
194
195 //----------------------------------------------------------------------------
OpenFileForDataRead(void * & vfp,const char * fname)196 int vtkMPIMultiBlockPLOT3DReader::OpenFileForDataRead(void*& vfp, const char* fname)
197 {
198 if (!this->CanUseMPIIO())
199 {
200 return this->Superclass::OpenFileForDataRead(vfp, fname);
201 }
202
203 vtkMPICommunicator* mpiComm = vtkMPICommunicator::SafeDownCast(
204 this->Controller->GetCommunicator());
205 assert(mpiComm);
206
207 vtkMPIOpaqueFileHandle* handle = new vtkMPIOpaqueFileHandle();
208 try
209 {
210 if (MPI_File_open(*mpiComm->GetMPIComm()->GetHandle(),
211 const_cast<char*>(fname), MPI_MODE_RDONLY,
212 MPI_INFO_NULL, &handle->Handle) != MPI_SUCCESS)
213 {
214 this->SetErrorCode(vtkErrorCode::FileNotFoundError);
215 vtkErrorMacro("File: " << fname << " not found.");
216 throw MPIPlot3DException();
217 }
218 }
219 catch (const MPIPlot3DException &)
220 {
221 delete handle;
222 vfp = nullptr;
223 return VTK_ERROR;
224 }
225 vfp = handle;
226 return VTK_OK;
227 }
228
229 //----------------------------------------------------------------------------
CloseFile(void * vfp)230 void vtkMPIMultiBlockPLOT3DReader::CloseFile(void* vfp)
231 {
232 if (!this->CanUseMPIIO())
233 {
234 this->Superclass::CloseFile(vfp);
235 return;
236 }
237
238 vtkMPIOpaqueFileHandle* handle = reinterpret_cast<vtkMPIOpaqueFileHandle*>(vfp);
239 assert(handle);
240 if (MPI_File_close(&handle->Handle) != MPI_SUCCESS)
241 {
242 vtkErrorMacro("Failed to close file!");
243 }
244 }
245
246 //----------------------------------------------------------------------------
ReadIntScalar(void * vfp,int extent[6],int wextent[6],vtkDataArray * scalar,vtkTypeUInt64 offset,const vtkMultiBlockPLOT3DReaderRecord & record)247 int vtkMPIMultiBlockPLOT3DReader::ReadIntScalar(
248 void* vfp, int extent[6], int wextent[6],
249 vtkDataArray* scalar, vtkTypeUInt64 offset,
250 const vtkMultiBlockPLOT3DReaderRecord& record)
251
252 {
253 if (!this->CanUseMPIIO())
254 {
255 return this->Superclass::ReadIntScalar(vfp, extent, wextent, scalar, offset, record);
256 }
257
258 vtkIdType n = vtkStructuredData::GetNumberOfPoints(extent);
259 vtkMPIPLOT3DArrayReader<int> arrayReader;
260 arrayReader.ByteOrder = this->Internal->Settings.ByteOrder;
261 vtkIdType preskip, postskip;
262 vtkMultiBlockPLOT3DReaderInternals::CalculateSkips(extent, wextent, preskip, postskip);
263 vtkIntArray* intArray = static_cast<vtkIntArray*>(scalar);
264 return arrayReader.ReadScalar(
265 vfp, offset, preskip, n, postskip, intArray->GetPointer(0), record) == n;
266 }
267
268 //----------------------------------------------------------------------------
ReadScalar(void * vfp,int extent[6],int wextent[6],vtkDataArray * scalar,vtkTypeUInt64 offset,const vtkMultiBlockPLOT3DReaderRecord & record)269 int vtkMPIMultiBlockPLOT3DReader::ReadScalar(
270 void* vfp,
271 int extent[6], int wextent[6],
272 vtkDataArray* scalar, vtkTypeUInt64 offset,
273 const vtkMultiBlockPLOT3DReaderRecord& record)
274 {
275 if (!this->CanUseMPIIO())
276 {
277 return this->Superclass::ReadScalar(vfp, extent, wextent, scalar, offset, record);
278 }
279
280 vtkIdType n = vtkStructuredData::GetNumberOfPoints(extent);
281 if (this->Internal->Settings.Precision == 4)
282 {
283 vtkMPIPLOT3DArrayReader<float> arrayReader;
284 arrayReader.ByteOrder = this->Internal->Settings.ByteOrder;
285 vtkIdType preskip, postskip;
286 vtkMultiBlockPLOT3DReaderInternals::CalculateSkips(extent, wextent, preskip, postskip);
287 vtkFloatArray* floatArray = static_cast<vtkFloatArray*>(scalar);
288 return arrayReader.ReadScalar(
289 vfp, offset, preskip, n, postskip, floatArray->GetPointer(0),
290 record) == n;
291 }
292 else
293 {
294 vtkMPIPLOT3DArrayReader<double> arrayReader;
295 arrayReader.ByteOrder = this->Internal->Settings.ByteOrder;
296 vtkIdType preskip, postskip;
297 vtkMultiBlockPLOT3DReaderInternals::CalculateSkips(extent, wextent, preskip, postskip);
298 vtkDoubleArray* doubleArray = static_cast<vtkDoubleArray*>(scalar);
299 return arrayReader.ReadScalar(
300 vfp, offset, preskip, n, postskip, doubleArray->GetPointer(0),
301 record) == n;
302 }
303 }
304
305 //----------------------------------------------------------------------------
ReadVector(void * vfp,int extent[6],int wextent[6],int numDims,vtkDataArray * vector,vtkTypeUInt64 offset,const vtkMultiBlockPLOT3DReaderRecord & record)306 int vtkMPIMultiBlockPLOT3DReader::ReadVector(
307 void* vfp,
308 int extent[6], int wextent[6],
309 int numDims, vtkDataArray* vector, vtkTypeUInt64 offset,
310 const vtkMultiBlockPLOT3DReaderRecord& record)
311 {
312 if (!this->CanUseMPIIO())
313 {
314 return this->Superclass::ReadVector(vfp, extent, wextent, numDims, vector, offset, record);
315 }
316
317 vtkIdType n = vtkStructuredData::GetNumberOfPoints(extent);
318 vtkIdType nValues = n*numDims;
319 if (this->Internal->Settings.Precision == 4)
320 {
321 vtkMPIPLOT3DArrayReader<float> arrayReader;
322 arrayReader.ByteOrder = this->Internal->Settings.ByteOrder;
323 vtkFloatArray* floatArray = static_cast<vtkFloatArray*>(vector);
324 return arrayReader.ReadVector(
325 vfp, offset, extent, wextent, numDims, floatArray->GetPointer(0), record) == nValues;
326 }
327 else
328 {
329 vtkMPIPLOT3DArrayReader<double> arrayReader;
330 arrayReader.ByteOrder = this->Internal->Settings.ByteOrder;
331 vtkDoubleArray* doubleArray = static_cast<vtkDoubleArray*>(vector);
332 return arrayReader.ReadVector(
333 vfp, offset, extent, wextent, numDims, doubleArray->GetPointer(0), record) == nValues;
334 }
335 }
336
337 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)338 void vtkMPIMultiBlockPLOT3DReader::PrintSelf(ostream& os, vtkIndent indent)
339 {
340 this->Superclass::PrintSelf(os, indent);
341 os << indent << "UseMPIIO: " << this->UseMPIIO << endl;
342 }
343