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