1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkCPExodusInSituReader.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 
16 #include "vtkCPExodusIIInSituReader.h"
17 
18 #include "vtkCPExodusIIElementBlock.h"
19 #include "vtkCPExodusIINodalCoordinatesTemplate.h"
20 #include "vtkCPExodusIIResultsArrayTemplate.h"
21 #include "vtkCellData.h"
22 #include "vtkDemandDrivenPipeline.h"
23 #include "vtkDoubleArray.h"
24 #include "vtkInformation.h"
25 #include "vtkInformationVector.h"
26 #include "vtkMultiBlockDataSet.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkPointData.h"
29 #include "vtkPoints.h"
30 
31 #include "vtk_exodusII.h"
32 
33 vtkStandardNewMacro(vtkCPExodusIIInSituReader);
34 
35 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)36 void vtkCPExodusIIInSituReader::PrintSelf(ostream& os, vtkIndent indent)
37 {
38   this->Superclass::PrintSelf(os, indent);
39   os << indent << "FileName: " << (this->FileName ? this->FileName : "(none)") << endl;
40 }
41 
42 //------------------------------------------------------------------------------
vtkCPExodusIIInSituReader()43 vtkCPExodusIIInSituReader::vtkCPExodusIIInSituReader()
44   : FileName(nullptr)
45   , FileId(-1)
46   , NumberOfDimensions(0)
47   , NumberOfNodes(0)
48   , NumberOfElementBlocks(0)
49   , CurrentTimeStep(0)
50 {
51   this->TimeStepRange[0] = 0;
52   this->TimeStepRange[1] = 0;
53   this->SetNumberOfInputPorts(0);
54 }
55 
56 //------------------------------------------------------------------------------
~vtkCPExodusIIInSituReader()57 vtkCPExodusIIInSituReader::~vtkCPExodusIIInSituReader()
58 {
59   this->SetFileName(nullptr);
60 }
61 
62 //------------------------------------------------------------------------------
ProcessRequest(vtkInformation * request,vtkInformationVector ** inputVector,vtkInformationVector * outputVector)63 vtkTypeBool vtkCPExodusIIInSituReader::ProcessRequest(
64   vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector)
65 {
66   if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA()))
67   {
68     return this->RequestData(request, inputVector, outputVector);
69   }
70 
71   if (request->Has(vtkDemandDrivenPipeline::REQUEST_INFORMATION()))
72   {
73     return this->RequestInformation(request, inputVector, outputVector);
74   }
75 
76   return this->Superclass::ProcessRequest(request, inputVector, outputVector);
77 }
78 
79 //------------------------------------------------------------------------------
RequestData(vtkInformation *,vtkInformationVector **,vtkInformationVector * outputVector)80 int vtkCPExodusIIInSituReader::RequestData(
81   vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector)
82 {
83   // Get output object:
84   vtkInformation* outInfo(outputVector->GetInformationObject(0));
85   vtkMultiBlockDataSet* output(
86     vtkMultiBlockDataSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())));
87 
88   // Prepare high-level structure:
89   //
90   // output                             vtkMultiBlockDataSet
91   //   - Block 0: this->ElementBlocks   vtkMultiBlockDataSet
92   //     - Block N: Element blocks      vtkCPExodusIIElementBlock
93   output->SetNumberOfBlocks(1);
94   output->SetBlock(0, this->ElementBlocks);
95 
96   bool success = false;
97 
98   if (!this->ExOpen())
99   {
100     return 0;
101   }
102 
103   for (;;) // Used to skip reading rest of file and close handle if error occurs
104   {
105     if (!this->ExGetMetaData())
106     {
107       break;
108     }
109 
110     if (!this->ExGetCoords())
111     {
112       break;
113     }
114 
115     if (!this->ExGetNodalVars())
116     {
117       break;
118     }
119 
120     if (!this->ExGetElemBlocks())
121     {
122       break;
123     }
124 
125     success = true;
126     break;
127   }
128 
129   this->ExClose();
130 
131   if (!success)
132   {
133     output->Initialize();
134   }
135 
136   return success ? 1 : 0;
137 }
138 
139 //------------------------------------------------------------------------------
RequestInformation(vtkInformation *,vtkInformationVector **,vtkInformationVector *)140 int vtkCPExodusIIInSituReader::RequestInformation(
141   vtkInformation*, vtkInformationVector**, vtkInformationVector*)
142 {
143   if (!this->ExOpen())
144   {
145     return 0;
146   }
147 
148   bool success(this->ExGetMetaData());
149 
150   this->ExClose();
151 
152   return success ? 1 : 0;
153 }
154 
155 //------------------------------------------------------------------------------
ExOpen()156 bool vtkCPExodusIIInSituReader::ExOpen()
157 {
158   int doubleSize = sizeof(double);
159   int fileRealSize = 0;
160   float exodusVersion;
161 
162   this->FileId = ex_open(this->FileName, EX_READ, &doubleSize, &fileRealSize, &exodusVersion);
163 
164   if (this->FileId < 0)
165   {
166     vtkErrorMacro("Cannot open file: " << this->FileName);
167     return false;
168   }
169   return true;
170 }
171 
172 //------------------------------------------------------------------------------
ExGetMetaData()173 bool vtkCPExodusIIInSituReader::ExGetMetaData()
174 {
175   // Generic metadata:
176   int numElem, numNodeSets, numSideSets;
177   std::string title(MAX_LINE_LENGTH + 1, '\0');
178 
179   int error = ex_get_init(this->FileId, &title[0], &this->NumberOfDimensions, &this->NumberOfNodes,
180     &numElem, &NumberOfElementBlocks, &numNodeSets, &numSideSets);
181 
182   // Trim excess null characters from string:
183   title.resize(strlen(title.c_str()));
184 
185   if (error < 0)
186   {
187     vtkErrorMacro("Error retrieving file metadata.");
188     return false;
189   }
190 
191   // Number of nodal variables
192   int numNodalVars;
193 
194   error = ex_get_var_param(this->FileId, "n", &numNodalVars);
195 
196   if (error < 0)
197   {
198     vtkErrorMacro("Error retrieving number of nodal variables.");
199     return false;
200   }
201 
202   // Names of nodal variables
203   this->NodalVariableNames =
204     std::vector<std::string>(numNodalVars, std::string(MAX_STR_LENGTH + 1, '\0'));
205 
206   for (int i = 0; i < numNodalVars; ++i)
207   {
208     error = ex_get_var_name(this->FileId, "n", i + 1, &(this->NodalVariableNames[i][0]));
209     if (error < 0)
210     {
211       vtkErrorMacro("Error retrieving nodal variable name at index" << i);
212       return false;
213     }
214     // Trim excess null chars from the strings:
215     this->NodalVariableNames[i].resize(strlen(this->NodalVariableNames[i].c_str()));
216   }
217 
218   // Number of element variables
219   int numElemVars;
220 
221   error = ex_get_var_param(this->FileId, "e", &numElemVars);
222 
223   if (error < 0)
224   {
225     vtkErrorMacro("Error retrieving number of element variables.");
226     return false;
227   }
228 
229   // Names of element variables
230   this->ElementVariableNames =
231     std::vector<std::string>(numElemVars, std::string(MAX_STR_LENGTH + 1, '\0'));
232 
233   for (int i = 0; i < numElemVars; ++i)
234   {
235     error = ex_get_var_name(this->FileId, "e", i + 1, &(this->ElementVariableNames[i][0]));
236     if (error < 0)
237     {
238       vtkErrorMacro("Error retrieving element variable name at index" << i);
239       return false;
240     }
241     // Trim excess null chars from the strings:
242     this->ElementVariableNames[i].resize(strlen(this->ElementVariableNames[i].c_str()));
243   }
244 
245   // Element block ids:
246   this->ElementBlockIds.resize(this->NumberOfElementBlocks);
247 
248   error = ex_get_elem_blk_ids(this->FileId, &(this->ElementBlockIds[0]));
249 
250   if (error < 0)
251   {
252     vtkErrorMacro("Failed to get the element block ids.");
253     return false;
254   }
255 
256   // Timesteps
257   int numTimeSteps;
258 
259   error = ex_inquire(this->FileId, EX_INQ_TIME, &numTimeSteps, nullptr, nullptr);
260   if (error < 0)
261   {
262     vtkErrorMacro("Error retrieving the number of timesteps.");
263     return false;
264   }
265 
266   this->TimeStepRange[0] = 0;
267   this->TimeStepRange[1] = numTimeSteps - 1;
268   this->TimeSteps.resize(numTimeSteps);
269 
270   if (numTimeSteps > 0)
271   {
272     error = ex_get_all_times(this->FileId, &(this->TimeSteps[0]));
273 
274     if (error < 0)
275     {
276       vtkErrorMacro("Error retrieving timestep array.");
277       return false;
278     }
279   }
280   return true;
281 }
282 
283 //------------------------------------------------------------------------------
ExGetCoords()284 bool vtkCPExodusIIInSituReader::ExGetCoords()
285 {
286   this->Points->Reset();
287   vtkNew<vtkCPExodusIINodalCoordinatesTemplate<double>> nodeCoords;
288 
289   // Get coordinates
290   double* x(new double[this->NumberOfNodes]);
291   double* y(new double[this->NumberOfNodes]);
292   double* z(this->NumberOfDimensions >= 3 ? new double[this->NumberOfNodes] : nullptr);
293 
294   int error = ex_get_coord(this->FileId, x, y, z);
295 
296   if (error < 0)
297   {
298     delete[] x;
299     delete[] y;
300     delete[] z;
301     vtkErrorMacro("Error retrieving coordinates.");
302     return false;
303   }
304 
305   // NodalCoordinates takes ownership of the arrays.
306   nodeCoords->SetExodusScalarArrays(x, y, z, this->NumberOfNodes);
307   this->Points->SetData(nodeCoords);
308   return true;
309 }
310 
311 //------------------------------------------------------------------------------
ExGetNodalVars()312 bool vtkCPExodusIIInSituReader::ExGetNodalVars()
313 {
314   this->PointData->Reset();
315   const int numNodalVars = static_cast<int>(this->NodalVariableNames.size());
316   for (int nodalVarIndex = 0; nodalVarIndex < numNodalVars; ++nodalVarIndex)
317   {
318     double* nodalVars = new double[this->NumberOfNodes];
319     int error = ex_get_nodal_var(
320       this->FileId, this->CurrentTimeStep + 1, nodalVarIndex + 1, this->NumberOfNodes, nodalVars);
321     std::vector<double*> varsVector(1, nodalVars);
322     vtkNew<vtkCPExodusIIResultsArrayTemplate<double>> nodalVarArray;
323     nodalVarArray->SetExodusScalarArrays(varsVector, this->NumberOfNodes);
324     nodalVarArray->SetName(this->NodalVariableNames[nodalVarIndex].c_str());
325 
326     if (error < 0)
327     {
328       vtkErrorMacro(
329         "Failed to read nodal variable array '" << this->NodalVariableNames[nodalVarIndex] << "'");
330       return false;
331     }
332 
333     this->PointData->AddArray(nodalVarArray);
334   }
335   return true;
336 }
337 
338 //------------------------------------------------------------------------------
ExGetElemBlocks()339 bool vtkCPExodusIIInSituReader::ExGetElemBlocks()
340 {
341   const int numElemBlk = static_cast<int>(this->ElementBlockIds.size());
342   const int numElemVars = static_cast<int>(this->ElementVariableNames.size());
343   this->ElementBlocks->Initialize();
344   this->ElementBlocks->SetNumberOfBlocks(numElemBlk);
345   for (int blockInd = 0; blockInd < numElemBlk; ++blockInd)
346   {
347     std::string elemType(MAX_STR_LENGTH + 1, '\0');
348     int numElem;
349     int nodesPerElem;
350     int numAttributes;
351 
352     int error = ex_get_elem_block(this->FileId, this->ElementBlockIds[blockInd], &(elemType[0]),
353       &numElem, &nodesPerElem, &numAttributes);
354 
355     // Trim excess null chars from the type string:
356     elemType.resize(strlen(elemType.c_str()));
357 
358     if (error < 0)
359     {
360       vtkErrorMacro("Failed to get the element block metadata for block " << blockInd);
361       return false;
362     }
363 
364     // Get element block connectivity
365     vtkNew<vtkCPExodusIIElementBlock> block;
366     int* connect = new int[numElem * nodesPerElem];
367     error = ex_get_elem_conn(this->FileId, this->ElementBlockIds[blockInd], connect);
368     if (!block->GetImplementation()->SetExodusConnectivityArray(
369           connect, elemType, numElem, nodesPerElem))
370     {
371       delete[] connect;
372       return false;
373     }
374 
375     if (error < 0)
376     {
377       vtkErrorMacro("Failed to get the connectivity for block " << blockInd);
378       return false;
379     }
380 
381     // Use the mapped point container for the block points
382     block->SetPoints(this->Points);
383 
384     // Add the point data arrays
385     block->GetPointData()->ShallowCopy(this->PointData);
386 
387     // Read the element variables (cell data)
388     for (int elemVarIndex = 0; elemVarIndex < numElemVars; ++elemVarIndex)
389     {
390       double* elemVars = new double[numElem];
391       error = ex_get_elem_var(this->FileId, this->CurrentTimeStep + 1, elemVarIndex + 1,
392         this->ElementBlockIds[blockInd], numElem, elemVars);
393       std::vector<double*> varsVector(1, elemVars);
394       vtkNew<vtkCPExodusIIResultsArrayTemplate<double>> elemVarArray;
395       elemVarArray->SetExodusScalarArrays(varsVector, numElem);
396       elemVarArray->SetName(this->ElementVariableNames[elemVarIndex].c_str());
397 
398       if (error < 0)
399       {
400         vtkErrorMacro("Failed to read element block variable array '"
401           << this->ElementVariableNames[elemVarIndex] << "'");
402         return false;
403       }
404 
405       block->GetCellData()->AddArray(elemVarArray);
406     }
407 
408     // Add this element block to the multi-block data set
409     this->ElementBlocks->SetBlock(blockInd, block);
410   }
411 
412   return true;
413 }
414 
415 //------------------------------------------------------------------------------
ExClose()416 void vtkCPExodusIIInSituReader::ExClose()
417 {
418   ex_close(this->FileId);
419   this->FileId = -1;
420 }
421