1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkPWindBladeReader.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 // This class was developed by Sohail Shafii; University of California Davis;
16 // Davis, CA 95616. sohailshafii@yahoo.com.
17 
18 #include "vtkPWindBladeReader.h"
19 
20 #include "vtkDataArraySelection.h"
21 #include "vtkFloatArray.h"
22 #include "vtkInformation.h"
23 #include "vtkInformationVector.h"
24 #include "vtkMPI.h"
25 #include "vtkMPIController.h"
26 #include "vtkObjectFactory.h"
27 #include "vtkStreamingDemandDrivenPipeline.h"
28 #include "vtksys/SystemTools.hxx"
29 
30 #include <sstream>
31 #include <vector>
32 
33 vtkStandardNewMacro(vtkPWindBladeReader);
34 
35 // This macro can be wrapped around MPI function calls to easily report errors.
36 // Reporting errors is more important with file I/O because, unlike network I/O,
37 // they usually don't terminate the program.
38 #define MPICall(funcall) \
39   { \
40   int __my_result = funcall; \
41   if (__my_result != MPI_SUCCESS) \
42   { \
43     char errormsg[MPI_MAX_ERROR_STRING]; \
44     int dummy; \
45     MPI_Error_string(__my_result, errormsg, &dummy); \
46     vtkErrorMacro(<< "Received error when calling" << endl \
47                   << #funcall << endl << endl \
48                   << errormsg); \
49   } \
50   }
51 
52 class PWindBladeReaderInternal
53 {
54 public:
55   MPI_File FilePtr;
56 };
57 
58 //-----------------------------------------------------------------------------
vtkPWindBladeReader()59 vtkPWindBladeReader::vtkPWindBladeReader()
60 {
61   this->PInternal = new PWindBladeReaderInternal();
62 }
63 
64 //-----------------------------------------------------------------------------
~vtkPWindBladeReader()65 vtkPWindBladeReader::~vtkPWindBladeReader()
66 {
67   delete this->PInternal;
68 }
69 
70 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)71 void vtkPWindBladeReader::PrintSelf(ostream &os, vtkIndent indent)
72 {
73   this->Superclass::PrintSelf(os, indent);
74 }
75 
76 //-----------------------------------------------------------------------------
RequestData(vtkInformation * reqInfo,vtkInformationVector ** inVector,vtkInformationVector * outVector)77 int vtkPWindBladeReader::RequestData(vtkInformation *reqInfo,
78                                      vtkInformationVector **inVector,
79                                      vtkInformationVector *outVector)
80 {
81   if (!vtkMPIController::GetGlobalController()->IsA("vtkMPIController"))
82   {
83     // serial case
84     return this->Superclass::RequestData(reqInfo, inVector, outVector);
85   }
86   int port = reqInfo->Get(vtkDemandDrivenPipeline::FROM_OUTPUT_PORT());
87 
88   // field data port
89   if (port == 0)
90   {
91     std::ostringstream fileName;
92     vtkStructuredGrid *field = this->GetFieldOutput();
93     this->InitFieldData(outVector, fileName, field);
94     char* cchar = new char[strlen(fileName.str().c_str()) + 1];
95     strcpy(cchar, fileName.str().c_str());
96     MPICall(MPI_File_open(MPI_COMM_WORLD, cchar, MPI_MODE_RDONLY, MPI_INFO_NULL, &this->PInternal->FilePtr));
97     delete [] cchar;
98     if (this->PInternal->FilePtr == nullptr)
99     {
100       vtkWarningMacro(<< "Could not open file " << fileName.str());
101     }
102     this->SetUpFieldVars(field);
103     MPICall(MPI_File_close(&this->PInternal->FilePtr));
104     return 1;
105   }
106   // Request data is on blade and is displayed only by processor 0
107   // Even if the blade is turned off, it must update with time along with field
108   else if (port == 1)
109   {
110     if (this->UseTurbineFile == 1 &&
111         vtkMultiProcessController::GetGlobalController()->GetLocalProcessId() == 0)
112     {
113       this->InitBladeData(outVector);
114     }
115     return 1;
116   }
117   // Request data in on ground
118   else if (port == 2)
119   {
120     this->SetUpGroundData(outVector);
121   }
122 
123   return 1;
124 }
125 
126 
127 //----------------------------------------------------------------------------
128 // Calculate pressure from tempg and density
129 // Calculate pressure - pre from pressure in first z position
130 // Requires that all data be present
131 //----------------------------------------------------------------------------
CalculatePressure(int pressure,int prespre,int tempg,int density)132 void vtkPWindBladeReader::CalculatePressure(int pressure, int prespre,
133                                             int tempg, int density)
134 {
135   if (!vtkMPIController::GetGlobalController()->IsA("vtkMPIController"))
136   {
137     return this->Superclass::CalculatePressure(pressure, prespre,
138                                                tempg, density);
139   }
140   float *pressureData = nullptr, *prespreData = nullptr;
141   this->InitPressureData(pressure, prespre, pressureData, prespreData);
142 
143   // Read tempg and Density components from file
144   float* tempgData   = new float[this->BlockSize];
145   float* densityData = new float[this->BlockSize];
146 
147   MPI_Status status;
148   char native[7] = "native";
149   MPICall(MPI_File_set_view(this->PInternal->FilePtr, this->VariableOffset[tempg], MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
150   MPICall(MPI_File_read_all(this->PInternal->FilePtr, tempgData, this->BlockSize, MPI_FLOAT, &status));
151   MPICall(MPI_File_set_view(this->PInternal->FilePtr, this->VariableOffset[density], MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
152   MPICall(MPI_File_read_all(this->PInternal->FilePtr, densityData, this->BlockSize, MPI_FLOAT, &status));
153 
154   // Only the requested subextents are stored on this processor
155   this->SetUpPressureData(pressureData, prespreData, tempgData, densityData);
156 
157   delete [] tempgData;
158   delete [] densityData;
159 }
160 
161 //----------------------------------------------------------------------------
162 // Calculate vorticity from UVW
163 // Requires ghost cell information so fetch all data from files for now
164 //----------------------------------------------------------------------------
CalculateVorticity(int vort,int uvw,int density)165 void vtkPWindBladeReader::CalculateVorticity(int vort, int uvw, int density)
166 {
167   if (!vtkMPIController::GetGlobalController()->IsA("vtkMPIController"))
168     return this->Superclass::CalculateVorticity(vort, uvw, density);
169 
170   // Set the number of components and tuples for the requested data
171   this->Data[vort]->SetNumberOfComponents(1);
172   this->Data[vort]->SetNumberOfTuples(this->NumberOfTuples);
173   float* vortData = this->Data[vort]->GetPointer(0);
174 
175   // Read U and V components (two int block sizes in between)
176   float* uData = new float[this->BlockSize];
177   float* vData = new float[this->BlockSize];
178 
179   MPI_Status status;
180   char native[7] = "native";
181   MPICall(MPI_File_set_view(this->PInternal->FilePtr, this->VariableOffset[uvw], MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
182   MPICall(MPI_File_read_all(this->PInternal->FilePtr, uData, this->BlockSize, MPI_FLOAT, &status));
183   MPICall(MPI_File_set_view(this->PInternal->FilePtr, (2 * sizeof(int)), MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
184   MPICall(MPI_File_read_all(this->PInternal->FilePtr, vData, this->BlockSize, MPI_FLOAT, &status));
185 
186   // Read Density component
187   float* densityData = new float[this->BlockSize];
188   MPICall(MPI_File_set_view(this->PInternal->FilePtr, this->VariableOffset[density], MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
189   MPICall(MPI_File_read_all(this->PInternal->FilePtr, densityData, this->BlockSize, MPI_FLOAT, &status));
190 
191   this->SetUpVorticityData(uData, vData, densityData, vortData);
192 
193   delete [] uData;
194   delete [] vData;
195   delete [] densityData;
196 }
197 
198 //----------------------------------------------------------------------------
199 // Load one variable data array of BLOCK structure into ParaView
200 //----------------------------------------------------------------------------
LoadVariableData(int var)201 void vtkPWindBladeReader::LoadVariableData(int var)
202 {
203   if (!vtkMPIController::GetGlobalController()->IsA("vtkMPIController"))
204     return this->Superclass::LoadVariableData(var);
205 
206   this->Data[var]->Delete();
207   this->Data[var] = vtkFloatArray::New();
208   this->Data[var]->SetName(VariableName[var].c_str());
209 
210   // Skip to the appropriate variable block and read byte count
211   char native[7] = "native";
212   MPICall(MPI_File_set_view(this->PInternal->FilePtr, this->VariableOffset[var], MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
213 
214   int numberOfComponents = 0, planeSize = 0, rowSize;
215   float *varData = nullptr;
216   float* block = new float[this->BlockSize];
217   this->InitVariableData(var, numberOfComponents, varData, planeSize, rowSize);
218   for (int comp = 0; comp < numberOfComponents; comp++)
219   {
220     MPI_Status status;
221     MPICall(MPI_File_read_all(this->PInternal->FilePtr, block, this->BlockSize, MPI_FLOAT, &status));
222 
223     int pos = comp;
224     for (int k = this->SubExtent[4]; k <= this->SubExtent[5]; k++)
225     {
226       for (int j = this->SubExtent[2]; j <= this->SubExtent[3]; j++)
227       {
228         for (int i = this->SubExtent[0]; i <= this->SubExtent[1]; i++)
229         {
230           int index = (k * planeSize) + (j * rowSize) + i;
231           varData[pos] = block[index];
232           pos += numberOfComponents;
233         }
234       }
235     }
236 
237     // Skip closing and opening byte sizes
238     MPICall(MPI_File_seek(this->PInternal->FilePtr, (2 * sizeof(int)), MPI_SEEK_CUR));
239   }
240   delete [] block;
241 }
242 
243 //----------------------------------------------------------------------------
244 // Load one variable data array of BLOCK structure into ParaView
245 //----------------------------------------------------------------------------
ReadGlobalData()246 bool vtkPWindBladeReader::ReadGlobalData()
247 {
248   if (!vtkMPIController::GetGlobalController()->IsA("vtkMPIController"))
249   {
250     return this->Superclass::ReadGlobalData();
251   }
252 
253   std::string fileName = this->Filename;
254   vtksys::SystemTools::ConvertToUnixSlashes(fileName);
255 
256   std::vector<char> inBuf(vtkWindBladeReader::LINE_SIZE);
257   MPI_File tempFile;
258   char native[7] = "native";
259   char* cchar = new char[strlen(fileName.c_str()) + 1];
260   strcpy(cchar, fileName.c_str());
261   MPICall(MPI_File_open(MPI_COMM_WORLD, cchar, MPI_MODE_RDONLY, MPI_INFO_NULL, &tempFile));
262   delete [] cchar;
263 
264   std::stringstream inStr;
265   MPI_Offset i, tempSize;
266   MPI_Status status;
267 
268   MPICall(MPI_File_get_size(tempFile, &tempSize));
269   MPICall(MPI_File_set_view(tempFile, 0, MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
270 
271   for(i = 0; i < tempSize; i = i + vtkWindBladeReader::LINE_SIZE)
272   {
273     if(i + vtkWindBladeReader::LINE_SIZE > tempSize)
274     {
275       MPICall(MPI_File_read_all(tempFile, &(inBuf[0]), tempSize - i, MPI_BYTE, &status));
276       inStr.write(&(inBuf[0]), tempSize - i);
277     }
278     else
279     {
280       MPICall(MPI_File_read_all(tempFile, &(inBuf[0]), vtkWindBladeReader::LINE_SIZE, MPI_BYTE, &status));
281       inStr.write(&(inBuf[0]), vtkWindBladeReader::LINE_SIZE);
282     }
283   }
284 
285   MPICall(MPI_File_close(&tempFile));
286   return this->SetUpGlobalData(fileName, inStr);
287 }
288 
289 //----------------------------------------------------------------------------
290 //
291 // Open the first data file and verify that the data is where is should be
292 // Each data block is enclosed by two ints which record the number of bytes
293 // Save the file offset for each variable
294 //
295 //----------------------------------------------------------------------------
FindVariableOffsets()296 bool vtkPWindBladeReader::FindVariableOffsets()
297 {
298   if (!vtkMPIController::GetGlobalController()->IsA("vtkMPIController"))
299     return this->Superclass::FindVariableOffsets();
300 
301   // Open the first data file
302   std::ostringstream fileName;
303   fileName << this->RootDirectory << "/"
304            << this->DataDirectory << "/"
305            << this->DataBaseName << this->TimeStepFirst;
306 
307   char* cchar = new char[strlen(fileName.str().c_str()) + 1];
308   strcpy(cchar, fileName.str().c_str());
309   MPICall(MPI_File_open(MPI_COMM_WORLD, cchar, MPI_MODE_RDONLY, MPI_INFO_NULL, &this->PInternal->FilePtr));
310   delete [] cchar;
311 
312   if (this->PInternal->FilePtr == nullptr)
313   {
314     vtkErrorMacro("Could not open file " << fileName.str());
315     return false;
316   }
317 
318   // Scan file recording offsets which points to the first data value
319   int byteCount;
320 
321   MPI_Status status;
322   char native[7] = "native";
323   MPICall(MPI_File_set_view(this->PInternal->FilePtr, 0, MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
324   MPICall(MPI_File_read_all(this->PInternal->FilePtr, &byteCount, 1, MPI_INT, &status));
325   MPI_Offset offset;
326   MPICall(MPI_File_get_position(this->PInternal->FilePtr, &offset));
327   MPICall(MPI_File_close(&this->PInternal->FilePtr));
328 
329   this->BlockSize = byteCount / BYTES_PER_DATA;
330 
331   for (int var = 0; var < this->NumberOfFileVariables; var++)
332   {
333     this->VariableOffset[var] = offset;
334 
335     // Skip over the SCALAR or VECTOR components for this variable
336     int numberOfComponents = 1;
337     if (this->VariableStruct[var] == VECTOR)
338     {
339       numberOfComponents = DIMENSION;
340     }
341 
342     // Skip data plus two integer byte counts, for each component.
343     offset += numberOfComponents * (byteCount + (2 * sizeof(int)));
344   }
345 
346   return true;
347 }
348 
349 //----------------------------------------------------------------------------
350 // Create the z topography from 2D (x,y) elevations and return in zData
351 //----------------------------------------------------------------------------
CreateZTopography(float * zValues)352 void vtkPWindBladeReader::CreateZTopography(float* zValues)
353 {
354   if (!vtkMPIController::GetGlobalController()->IsA("vtkMPIController"))
355     return this->Superclass::CreateZTopography(zValues);
356 
357   // Read the x,y topography data file
358   std::ostringstream fileName;
359   fileName << this->RootDirectory << "/"
360            << this->TopographyFile;
361 
362   int blockSize   = this->Dimension[0] * this->Dimension[1];
363   float* topoData = new float[blockSize];
364   char* cchar     = new char[strlen(fileName.str().c_str()) + 1];
365 
366   strcpy(cchar, fileName.str().c_str());
367   MPICall(MPI_File_open(MPI_COMM_WORLD, cchar, MPI_MODE_RDONLY, MPI_INFO_NULL, &this->PInternal->FilePtr));
368   delete [] cchar;
369 
370   MPI_Status status;
371   char native[7] = "native";
372   MPICall(MPI_File_set_view(this->PInternal->FilePtr, BYTES_PER_DATA, MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
373   MPICall(MPI_File_read_all(this->PInternal->FilePtr, topoData, blockSize, MPI_FLOAT, &status));
374 
375   this->ProcessZCoords(topoData, zValues);
376 
377   delete [] topoData;
378   MPICall(MPI_File_close(&this->PInternal->FilePtr));
379 }
380 
381 //----------------------------------------------------------------------------
382 // Build the turbine towers
383 // Parse a blade file to set the number of cells and points in blades
384 //----------------------------------------------------------------------------
SetupBladeData()385 void vtkPWindBladeReader::SetupBladeData()
386 {
387   if (!vtkMPIController::GetGlobalController()->IsA("vtkMPIController"))
388     return this->Superclass::SetupBladeData();
389 
390   // Load the tower information
391   std::ostringstream fileName;
392   fileName << this->RootDirectory << "/"
393            << this->TurbineDirectory << "/"
394            << this->TurbineTowerName;
395   std::vector<char> inBuf(vtkWindBladeReader::LINE_SIZE);
396 
397   MPI_File tempFile;
398   char native[7] = "native";
399   char* cchar = new char[strlen(fileName.str().c_str()) + 1];
400   strcpy(cchar, fileName.str().c_str());
401   MPICall(MPI_File_open(MPI_COMM_WORLD, cchar, MPI_MODE_RDONLY, MPI_INFO_NULL, &tempFile));
402   delete [] cchar;
403 
404   std::stringstream inStr;
405   MPI_Offset i, tempSize;
406   MPI_Status status;
407 
408   MPICall(MPI_File_get_size(tempFile, &tempSize));
409   MPICall(MPI_File_set_view(tempFile, 0, MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
410 
411   for(i = 0; i < tempSize; i = i + vtkWindBladeReader::LINE_SIZE)
412   {
413     if(i + vtkWindBladeReader::LINE_SIZE > tempSize)
414     {
415       MPICall(MPI_File_read_all(tempFile, &(inBuf[0]), tempSize - i, MPI_BYTE, &status));
416       inStr.write(&(inBuf[0]), tempSize - i);
417     }
418     else
419     {
420       MPICall(MPI_File_read_all(tempFile, &(inBuf[0]), vtkWindBladeReader::LINE_SIZE, MPI_BYTE, &status));
421       inStr.write(&(inBuf[0]), vtkWindBladeReader::LINE_SIZE);
422     }
423   }
424 
425   MPICall(MPI_File_close(&tempFile));
426 
427   if (!inStr)
428   {
429     vtkWarningMacro("Could not open " << fileName.str() << endl);
430   }
431 
432   int numColumns = 0;
433   this->ReadBladeHeader(fileName.str(), inStr, numColumns);
434 
435   // Calculate the number of cells in unstructured turbine blades
436   std::ostringstream fileName2;
437   fileName2 << this->RootDirectory << "/"
438             << this->TurbineDirectory << "/"
439             << this->TurbineBladeName << this->TimeStepFirst;
440 
441   cchar = new char[strlen(fileName2.str().c_str()) + 1];
442   strcpy(cchar, fileName2.str().c_str());
443   MPICall(MPI_File_open(MPI_COMM_WORLD, cchar, MPI_MODE_RDONLY, MPI_INFO_NULL, &tempFile));
444   delete [] cchar;
445 
446   std::stringstream inStr2;
447 
448   MPICall(MPI_File_get_size(tempFile, &tempSize));
449   MPICall(MPI_File_set_view(tempFile, 0, MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
450 
451   for(i = 0; i < tempSize; i = i + vtkWindBladeReader::LINE_SIZE)
452   {
453     if(i + vtkWindBladeReader::LINE_SIZE > tempSize)
454     {
455       MPICall(MPI_File_read_all(tempFile, &(inBuf[0]), tempSize - i, MPI_BYTE, &status));
456       inStr2.write(&(inBuf[0]), tempSize - i);
457     }
458     else
459     {
460       MPICall(MPI_File_read_all(tempFile, &(inBuf[0]), vtkWindBladeReader::LINE_SIZE, MPI_BYTE, &status));
461       inStr2.write(&(inBuf[0]), vtkWindBladeReader::LINE_SIZE);
462     }
463   }
464 
465   MPICall(MPI_File_close(&tempFile));
466 
467   if (!inStr2)
468   {
469     vtkWarningMacro("Could not open blade file: " << fileName2.str().c_str() <<
470                     " to calculate blade cells.");
471     for (int j = this->TimeStepFirst + this->TimeStepDelta; j <= this->TimeStepLast;
472          j += this->TimeStepDelta)
473     {
474       std::ostringstream fileName3;
475       fileName3 << this->RootDirectory << "/"
476                 << this->TurbineDirectory << "/"
477                 << this->TurbineBladeName << j;
478       //std::cout << "Trying " << fileName3.str().c_str() << "...";
479 
480       cchar = new char[strlen(fileName3.str().c_str()) + 1];
481       strcpy(cchar, fileName3.str().c_str());
482       MPICall(MPI_File_open(MPI_COMM_WORLD, cchar, MPI_MODE_RDONLY, MPI_INFO_NULL, &tempFile));
483       delete [] cchar;
484 
485       inStr2.clear();
486       inStr2.str("");
487 
488       MPICall(MPI_File_get_size(tempFile, &tempSize));
489       MPICall(MPI_File_set_view(tempFile, 0, MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
490 
491       for(i = 0; i < tempSize; i = i + vtkWindBladeReader::LINE_SIZE)
492       {
493         if(i + vtkWindBladeReader::LINE_SIZE > tempSize)
494         {
495           MPICall(MPI_File_read_all(tempFile, &(inBuf[0]), tempSize - i, MPI_BYTE, &status));
496           inStr2.write(&(inBuf[0]), tempSize - i);
497         }
498         else
499         {
500           MPICall(MPI_File_read_all(tempFile, &(inBuf[0]), vtkWindBladeReader::LINE_SIZE, MPI_BYTE, &status));
501           inStr2.write(&(inBuf[0]), vtkWindBladeReader::LINE_SIZE);
502         }
503       }
504       MPICall(MPI_File_close(&tempFile));
505 
506       if(inStr2.good())
507       {
508         vtkWarningMacro("Success with " << fileName3.str());
509         break;
510       }
511       else
512       {
513         vtkWarningMacro("Failure with " << fileName3.str());
514       }
515     }
516   }
517 
518   this->NumberOfBladeCells = 0;
519   // if we have at least 13 columns, then this is the new format with a header in the
520   // turbine blade file
521   if (numColumns >= 13 && inStr2)
522   {
523     int linesSkipped = 0;
524     // each blade tower tries to split the columns such that there are
525     // five items per line in header, so skip those lines
526     this->NumberOfLinesToSkip = this->NumberOfBladeTowers*(int)ceil(numColumns/5.0);
527     // now skip the first few lines based on header, if that applies
528     while(inStr2.getline(&(inBuf[0]), vtkWindBladeReader::LINE_SIZE) &&
529           linesSkipped < this->NumberOfLinesToSkip-1)
530     {
531       linesSkipped++;
532     }
533   }
534   while (inStr2.getline(&(inBuf[0]), vtkWindBladeReader::LINE_SIZE))
535   {
536     this->NumberOfBladeCells++;
537   }
538   this->NumberOfBladePoints = this->NumberOfBladeCells * NUM_PART_SIDES;
539   // Points and cells needed for constant towers
540   this->NumberOfBladePoints += this->NumberOfBladeTowers * NUM_BASE_SIDES;
541   this->NumberOfBladeCells += this->NumberOfBladeTowers;
542 }
543 
544 //----------------------------------------------------------------------------
545 // Build the turbine blades
546 //----------------------------------------------------------------------------
LoadBladeData(int timeStep)547 void vtkPWindBladeReader::LoadBladeData(int timeStep)
548 {
549   if (!vtkMPIController::GetGlobalController()->IsA("vtkMPIController"))
550     return this->Superclass::LoadBladeData(timeStep);
551 
552   this->BPoints->Delete();
553   this->BPoints = vtkPoints::New();
554 
555   // Open the file for this time step
556   std::ostringstream fileName;
557   fileName << this->RootDirectory << "/"
558            << this->TurbineDirectory << "/"
559            << this->TurbineBladeName
560            << this->TimeSteps[timeStep];
561   std::vector<char> inBuf(vtkWindBladeReader::LINE_SIZE);
562 
563   // only rank 0 reads this so we have to be careful
564   MPI_File tempFile;
565   char native[7] = "native";
566   char* cchar = new char[strlen(fileName.str().c_str()) + 1];
567   strcpy(cchar, fileName.str().c_str());
568   // here only rank 0 opens it : MPI_COMM_SELF
569   MPICall(MPI_File_open(MPI_COMM_SELF, cchar, MPI_MODE_RDONLY, MPI_INFO_NULL, &tempFile));
570   delete [] cchar;
571 
572   std::stringstream inStr;
573   MPI_Offset i, tempSize;
574   MPI_Status status;
575 
576   MPICall(MPI_File_get_size(tempFile, &tempSize));
577   MPICall(MPI_File_set_view(tempFile, 0, MPI_BYTE, MPI_BYTE, native, MPI_INFO_NULL));
578 
579   for(i = 0; i < tempSize; i = i + vtkWindBladeReader::LINE_SIZE)
580   {
581     if(i + vtkWindBladeReader::LINE_SIZE > tempSize)
582     {
583       MPICall(MPI_File_read(tempFile, &(inBuf[0]), tempSize - i, MPI_BYTE, &status));
584       inStr.write(&(inBuf[0]), tempSize - i);
585     }
586     else
587     {
588       MPICall(MPI_File_read(tempFile, &(inBuf[0]), vtkWindBladeReader::LINE_SIZE, MPI_BYTE, &status));
589       inStr.write(&(inBuf[0]), vtkWindBladeReader::LINE_SIZE);
590     }
591   }
592   MPICall(MPI_File_close(&tempFile));
593 
594   this->ReadBladeData(inStr);
595 }
596