1 /*=========================================================================
2
3 Program: ParaView
4 Module: vtkExodusIIReaderParser.cxx
5
6 Copyright (c) Kitware, Inc.
7 All rights reserved.
8 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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 "vtkExodusIIReaderParser.h"
16
17 #include "vtkDataSetAttributes.h"
18 #include "vtkMutableDirectedGraph.h"
19 #include "vtkObjectFactory.h"
20 #include "vtkStringArray.h"
21 #include "vtkUnsignedCharArray.h"
22
23 #include <cassert>
24 #include <sstream>
25
26 vtkStandardNewMacro(vtkExodusIIReaderParser);
27 //------------------------------------------------------------------------------
vtkExodusIIReaderParser()28 vtkExodusIIReaderParser::vtkExodusIIReaderParser()
29 {
30 this->SIL = vtkMutableDirectedGraph::New();
31 this->InBlocks = false;
32 this->InMaterialAssignments = false;
33 }
34
35 //------------------------------------------------------------------------------
~vtkExodusIIReaderParser()36 vtkExodusIIReaderParser::~vtkExodusIIReaderParser()
37 {
38 this->SIL->Delete();
39 this->SIL = nullptr;
40 }
41
42 //------------------------------------------------------------------------------
StartElement(const char * tagName,const char ** attrs)43 void vtkExodusIIReaderParser::StartElement(const char* tagName, const char** attrs)
44 {
45 const char* name = strrchr(tagName, ':');
46
47 // If tag name has xml namespace separator, get rid of namespace:
48 name = name ? name + 1 : tagName;
49 std::string tName(name);
50
51 if (tName == "solid-model")
52 {
53 // Move down to the Assemblies branch.
54 this->CurrentVertex.push_back(this->AssembliesVertex);
55 }
56 else if (tName == "assembly")
57 {
58 // Starting a new "assembly" node. Get paratmeters for this assembly.
59 const char* assemblyNumber = this->GetValue("number", attrs);
60 const char* assemblyDescription = this->GetValue("description", attrs);
61
62 // Setup the name for this node.
63 std::string node_name = std::string("Assembly: ") + assemblyDescription + std::string(" (") +
64 assemblyNumber + std::string(")");
65
66 // Now add a vertex in the SIL for this assembly node.
67 vtkIdType vertexID = this->AddVertexToSIL(node_name.c_str());
68 this->AddChildEdgeToSIL(this->CurrentVertex.back(), vertexID);
69 this->CurrentVertex.push_back(vertexID);
70 }
71 else if (tName == "part")
72 {
73 const char* instance = this->GetValue("instance", attrs);
74 std::string instanceString = instance ? instance : "";
75 const char* partNumber = this->GetValue("number", attrs);
76 std::string partNumberBasicString;
77 std::string partNumberString;
78 if (partNumber)
79 {
80 partNumberBasicString = std::string(partNumber);
81 partNumberString = std::string(partNumber) + std::string(" Instance: ") + instanceString;
82 }
83
84 const char* partDesc = this->GetValue("description", attrs);
85 std::string partDescString;
86 if (partDesc)
87 {
88 partDescString = std::string(partDesc);
89 }
90
91 // This will create a new vertex if none already present.
92 vtkIdType partVertex = this->GetPartVertex(partNumberString.c_str());
93
94 // Now fix the part vertex name.
95 std::string result = std::string("Part: ") + partDescString + std::string(" (") +
96 partNumberBasicString + std::string(")") + std::string(" Instance: ") + instanceString;
97 this->NamesArray->InsertValue(partVertex, result.c_str());
98
99 // Insert the part vertex info the assemblies hierarchy.
100 this->AddChildEdgeToSIL(this->CurrentVertex.back(), partVertex);
101 // The cross link between the part at the blocks it refers is added when the
102 // <blocks/> are parsed.
103
104 // Save the description for this part, this description is used later to
105 // name the block appropriately.
106 this->PartVertexID_To_Descriptions[partVertex] = partDescString;
107
108 // Add a "part" vertex in the "Assemblies" hierarchy.
109 this->CurrentVertex.push_back(partVertex);
110 }
111 else if (tName == "material-specification")
112 {
113 // The <part /> element may contain material-specification for each part.
114 // These are used only if <material-assignments/> are not present.
115 vtkIdType partVertex = this->CurrentVertex.back();
116
117 const char* materialDescriptionString = this->GetValue("description", attrs);
118 std::string material = materialDescriptionString ? materialDescriptionString : "";
119 material += " : ";
120
121 const char* materialSpecificationString = this->GetValue("specification", attrs);
122 material += materialSpecificationString ? materialSpecificationString : "";
123
124 this->MaterialSpecifications[partVertex] = material;
125 }
126 else if (tName == "mesh")
127 {
128 assert(this->CurrentVertex.empty());
129 this->CurrentVertex.push_back(this->BlocksVertex);
130 }
131 else if (tName == "blocks")
132 {
133 const char* instance = this->GetValue("part-instance", attrs);
134 std::string instanceString = instance ? instance : "";
135 const char* partNumber = this->GetValue("part-number", attrs);
136 std::string partNumberString;
137 if (partNumber)
138 {
139 partNumberString = std::string(partNumber) + std::string(" Instance: ") + instanceString;
140 }
141
142 this->InBlocks = true;
143 this->BlockPartNumberString = partNumberString;
144 }
145 else if (tName == "block")
146 {
147 const char* blockString = this->GetValue("id", attrs);
148 int id = -1;
149 if (blockString)
150 {
151 id = atoi(blockString);
152 }
153
154 if (id >= 0)
155 {
156 if (this->InBlocks && !this->BlockPartNumberString.empty())
157 {
158 // the name for the block is re-generated at the end.
159 vtkIdType blockVertex = this->AddVertexToSIL(blockString);
160 this->AddChildEdgeToSIL(this->BlocksVertex, blockVertex);
161
162 // This <block /> element was encountered while reading the <mesh />.
163 this->BlockID_To_VertexID[id] = blockVertex;
164
165 this->BlockID_To_Part[id] = this->BlockPartNumberString;
166 // // Add cross edge linking the assembly part to the block.
167 // vtkIdType partVertex = this->CurrentVertex.back();
168 // this->AddCrossEdgeToSIL(partVertex, blockVertex);
169 // this->BlockID_To_PartVertexID[id] = partVertex;
170 }
171 else if (this->InMaterialAssignments)
172 {
173 // This <block /> element was encountered while reading the
174 // <material-assignments />
175 const char* tmaterialName = this->GetValue("material-name", attrs);
176 if (tmaterialName)
177 {
178 // Save the material information for later since we may not have
179 // seen the <blocks /> yet, consequently we have no mapping from
180 // vertex to block id.
181 this->BlockID_To_MaterialName[id] = tmaterialName;
182 }
183 }
184 }
185 }
186 else if (tName == "material-assignments")
187 {
188 this->CurrentVertex.push_back(this->MaterialsVertex);
189 this->InMaterialAssignments = true;
190 }
191 else if (tName == "material")
192 {
193 const char* material = this->GetValue("name", attrs);
194 if (material)
195 {
196 const char* spec = this->GetValue("specification", attrs);
197 const char* desc = this->GetValue("description", attrs);
198 std::string node_name;
199 if (desc)
200 {
201 node_name = desc;
202 }
203 else
204 {
205 node_name = material;
206 }
207 if (spec)
208 {
209 node_name += " : ";
210 node_name += spec;
211 }
212
213 vtkIdType vertex = this->AddVertexToSIL(node_name.c_str());
214 this->AddChildEdgeToSIL(this->MaterialsVertex, vertex);
215 this->MaterialName_To_VertexID[material] = vertex;
216 }
217 }
218 }
219
220 //------------------------------------------------------------------------------
EndElement(const char * tagName)221 void vtkExodusIIReaderParser::EndElement(const char* tagName)
222 {
223 const char* name = strrchr(tagName, ':');
224 // If tag name has xml namespace separator, get rid of namespace:
225 name = name ? name + 1 : tagName;
226 std::string tName(name);
227 if (tName == "solid-model")
228 {
229 this->CurrentVertex.pop_back();
230 }
231 else if (tName == "assembly")
232 {
233 this->CurrentVertex.pop_back();
234 }
235 else if (tName == "part")
236 {
237 this->CurrentVertex.pop_back();
238 }
239 else if (tName == "mesh")
240 {
241 this->CurrentVertex.pop_back();
242 }
243 else if (tName == "blocks")
244 {
245 this->InBlocks = false;
246 this->BlockPartNumberString = "";
247 }
248 else if (tName == "material-assignments")
249 {
250 this->InMaterialAssignments = false;
251 this->CurrentVertex.pop_back();
252 }
253 }
254
255 //------------------------------------------------------------------------------
FinishedParsing()256 void vtkExodusIIReaderParser::FinishedParsing()
257 {
258 std::map<int, vtkIdType> blockID_to_partVertexID;
259
260 // * Is assembly was parsed, add cross links between assembly parts and blocks
261 // belonging to that part.
262 if (!this->Part_To_VertexID.empty())
263 {
264 std::map<int, std::string>::iterator iterIS;
265 for (iterIS = this->BlockID_To_Part.begin(); iterIS != this->BlockID_To_Part.end(); ++iterIS)
266 {
267 if (this->Part_To_VertexID.find(iterIS->second) == this->Part_To_VertexID.end())
268 {
269 // This block blongs to a part not present in the assembly.
270 continue;
271 }
272 vtkIdType partVertex = this->Part_To_VertexID[iterIS->second];
273 vtkIdType blockVertex = this->BlockID_To_VertexID[iterIS->first];
274 this->AddCrossEdgeToSIL(partVertex, blockVertex);
275 blockID_to_partVertexID[iterIS->first] = partVertex;
276 }
277 }
278
279 // * Assign correct names for all the "block" vertices.
280 std::map<int, vtkIdType>::iterator iter;
281 for (iter = this->BlockID_To_VertexID.begin(); iter != this->BlockID_To_VertexID.end(); ++iter)
282 {
283 // To locate the part description for this block, first locate the part to
284 // which this block belongs.
285 std::string desc = "None";
286 if (blockID_to_partVertexID.find(iter->first) != blockID_to_partVertexID.end())
287 {
288 vtkIdType partVertex = blockID_to_partVertexID[iter->first];
289 desc = this->PartVertexID_To_Descriptions[partVertex];
290 }
291
292 std::ostringstream stream;
293 stream << "Block: " << iter->first << " (" << desc.c_str() << ") "
294 << this->BlockID_To_Part[iter->first].c_str();
295 this->NamesArray->SetValue(iter->second, stream.str().c_str());
296 }
297
298 //// * If <material-assignments /> are not present use
299 //// <material-specification /> to construct material assignments.
300 if (this->BlockID_To_MaterialName.empty())
301 {
302 std::map<int, vtkIdType>::iterator iterII;
303 for (iterII = blockID_to_partVertexID.begin(); iterII != blockID_to_partVertexID.end();
304 ++iterII)
305 {
306 int blockID = iterII->first;
307 vtkIdType partVertex = iterII->second;
308
309 std::string node_name = this->MaterialSpecifications[partVertex];
310 vtkIdType materialVertex;
311 if (this->MaterialName_To_VertexID.find(node_name) == this->MaterialName_To_VertexID.end())
312 {
313 materialVertex = this->AddVertexToSIL(node_name.c_str());
314 this->AddChildEdgeToSIL(this->MaterialsVertex, materialVertex);
315 this->MaterialName_To_VertexID[node_name] = materialVertex;
316 }
317 else
318 {
319 materialVertex = this->MaterialName_To_VertexID[node_name];
320 }
321 this->BlockID_To_MaterialName[blockID] = node_name;
322 }
323 }
324
325 //// * Add cross-links between "block" vertices and "material" vertices.
326 std::map<int, std::string>::iterator iter2;
327 for (iter2 = this->BlockID_To_MaterialName.begin(); iter2 != this->BlockID_To_MaterialName.end();
328 ++iter2)
329 {
330 vtkIdType blockVertex = this->BlockID_To_VertexID[iter2->first];
331 if (this->MaterialName_To_VertexID.find(iter2->second) != this->MaterialName_To_VertexID.end())
332 {
333 vtkIdType materialVertex = this->MaterialName_To_VertexID[iter2->second];
334 this->AddCrossEdgeToSIL(materialVertex, blockVertex);
335 }
336 }
337 }
338
339 //------------------------------------------------------------------------------
AddVertexToSIL(const char * name)340 vtkIdType vtkExodusIIReaderParser::AddVertexToSIL(const char* name)
341 {
342 vtkIdType vertex = this->SIL->AddVertex();
343 this->NamesArray->InsertValue(vertex, name);
344 return vertex;
345 }
346
347 //------------------------------------------------------------------------------
AddChildEdgeToSIL(vtkIdType src,vtkIdType dst)348 vtkIdType vtkExodusIIReaderParser::AddChildEdgeToSIL(vtkIdType src, vtkIdType dst)
349 {
350 vtkIdType id = this->SIL->AddEdge(src, dst).Id;
351 this->CrossEdgesArray->InsertValue(id, 0);
352 return id;
353 }
354
355 //------------------------------------------------------------------------------
AddCrossEdgeToSIL(vtkIdType src,vtkIdType dst)356 vtkIdType vtkExodusIIReaderParser::AddCrossEdgeToSIL(vtkIdType src, vtkIdType dst)
357 {
358 vtkIdType id = this->SIL->AddEdge(src, dst).Id;
359 this->CrossEdgesArray->InsertValue(id, 1);
360 return id;
361 }
362
363 //------------------------------------------------------------------------------
GetPartVertex(const char * part_number_instance_string)364 vtkIdType vtkExodusIIReaderParser::GetPartVertex(const char* part_number_instance_string)
365 {
366 std::map<std::string, vtkIdType>::iterator iter =
367 this->Part_To_VertexID.find(part_number_instance_string);
368 if (iter != this->Part_To_VertexID.end())
369 {
370 return iter->second;
371 }
372
373 // The name here is temporary. The full name for a the "part" nodes is
374 // determined when the assembly is parsed.
375 vtkIdType vertex = this->AddVertexToSIL(part_number_instance_string);
376 // Save the vertex for later use.
377 this->Part_To_VertexID[part_number_instance_string] = vertex;
378 return vertex;
379 }
380
381 //------------------------------------------------------------------------------
Go(const char * filename)382 void vtkExodusIIReaderParser::Go(const char* filename)
383 {
384 this->SIL->Initialize();
385 this->CurrentVertex.clear();
386 this->BlockID_To_VertexID.clear();
387 this->BlockID_To_MaterialName.clear();
388 this->MaterialName_To_VertexID.clear();
389 this->PartVertexID_To_Descriptions.clear();
390 this->Part_To_VertexID.clear();
391 this->MaterialSpecifications.clear();
392 this->BlockID_To_Part.clear();
393 this->InBlocks = false;
394 this->InMaterialAssignments = false;
395
396 this->NamesArray = vtkSmartPointer<vtkStringArray>::New();
397 this->NamesArray->SetName("Names");
398 this->CrossEdgesArray = vtkSmartPointer<vtkUnsignedCharArray>::New();
399 this->CrossEdgesArray->SetName("CrossEdges");
400 this->SIL->GetVertexData()->AddArray(this->NamesArray);
401 this->SIL->GetEdgeData()->AddArray(this->CrossEdgesArray);
402
403 this->RootVertex = this->AddVertexToSIL("SIL");
404 this->BlocksVertex = this->AddVertexToSIL("Blocks");
405 this->AssembliesVertex = this->AddVertexToSIL("Assemblies");
406 this->MaterialsVertex = this->AddVertexToSIL("Materials");
407 this->AddChildEdgeToSIL(this->RootVertex, this->BlocksVertex);
408 this->AddChildEdgeToSIL(this->RootVertex, this->AssembliesVertex);
409 this->AddChildEdgeToSIL(this->RootVertex, this->MaterialsVertex);
410
411 this->SetFileName(filename);
412 this->Parse();
413 this->FinishedParsing();
414 }
415
416 //------------------------------------------------------------------------------
GetBlockName(int id)417 std::string vtkExodusIIReaderParser::GetBlockName(int id)
418 {
419 if (this->BlockID_To_VertexID.find(id) != this->BlockID_To_VertexID.end())
420 {
421 vtkIdType vertex = this->BlockID_To_VertexID[id];
422 return this->NamesArray->GetValue(vertex);
423 }
424 return "";
425 }
426
427 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)428 void vtkExodusIIReaderParser::PrintSelf(ostream& os, vtkIndent indent)
429 {
430 this->Superclass::PrintSelf(os, indent);
431 os << indent << "SIL: " << this->SIL << endl;
432 }
433