1 #include "vtkExodusIIReaderVariableCheck.h"
2 #include "vtkExodusIIReader.h"
3 #include "vtkExodusIIReaderPrivate.h"
4 #include "vtkIntArray.h"
5 #include "vtkMath.h"
6 #include "vtkPolyData.h"
7 #include "vtkStdString.h"
8 #include "vtkUnstructuredGrid.h"
9 #include <set>
10 #include <string>
11 #include <vector>
12 #include <vtksys/RegularExpression.hxx>
13 #include <vtksys/SystemTools.hxx>
14
15 #include <cctype>
16
Start(std::string name,const int * truth,int numTruth)17 bool vtkExodusIIReaderVariableCheck::Start(std::string name, const int* truth, int numTruth)
18 {
19 this->SeqTruth.clear();
20 this->SeqTruth.insert(this->SeqTruth.begin(), truth, truth + numTruth);
21 this->OriginalNames.clear();
22 bool result = this->StartInternal(name, truth, numTruth);
23 bool atLeastOne = false;
24 for (int i = 0; i < numTruth; ++i)
25 {
26 if (truth[i])
27 atLeastOne = true;
28 }
29 return result && atLeastOne;
30 }
31
Length()32 std::vector<std::string>::size_type vtkExodusIIReaderVariableCheck::Length()
33 {
34 return this->OriginalNames.size();
35 }
36
Accept(std::vector<vtkExodusIIReaderPrivate::ArrayInfoType> & arr,int startIndex,vtkExodusIIReaderPrivate * priv,int objtyp)37 int vtkExodusIIReaderVariableCheck::Accept(
38 std::vector<vtkExodusIIReaderPrivate::ArrayInfoType>& arr, int startIndex,
39 vtkExodusIIReaderPrivate* priv, int objtyp)
40 {
41 std::string::size_type len = this->Length();
42 vtkExodusIIReaderPrivate::ArrayInfoType ainfo;
43 ainfo.Name = this->Prefix;
44 ainfo.Source = vtkExodusIIReaderPrivate::Result;
45 ainfo.Components = static_cast<int>(len);
46 for (unsigned int i = 0; i < len; ++i)
47 {
48 ainfo.OriginalIndices.push_back(startIndex + i + 1 /* FORTRAN. Blech. */);
49 ainfo.OriginalNames.emplace_back(this->OriginalNames[i]);
50 }
51 ainfo.GlomType = this->GlomType;
52 ainfo.StorageType = VTK_DOUBLE;
53 ainfo.Status = 0;
54 ainfo.ObjectTruth = this->SeqTruth;
55 this->UniquifyName(ainfo, arr);
56 if (priv)
57 {
58 priv->GetInitialObjectArrayStatus(objtyp, &ainfo);
59 }
60 arr.push_back(ainfo);
61 return static_cast<int>(this->Length());
62 }
63
vtkExodusIIReaderVariableCheck()64 vtkExodusIIReaderVariableCheck::vtkExodusIIReaderVariableCheck()
65 {
66 this->GlomType = -1;
67 }
68
69 vtkExodusIIReaderVariableCheck::~vtkExodusIIReaderVariableCheck() = default;
70
CheckTruth(const int * truth)71 bool vtkExodusIIReaderVariableCheck::CheckTruth(const int* truth)
72 {
73 if (!truth)
74 return false;
75
76 for (std::vector<int>::iterator it = this->SeqTruth.begin(); it != this->SeqTruth.end();
77 ++it, ++truth)
78 {
79 if (*truth != *it)
80 {
81 return false;
82 }
83 }
84
85 return true;
86 }
87
UniquifyName(vtkExodusIIReaderPrivate::ArrayInfoType & ainfo,std::vector<vtkExodusIIReaderPrivate::ArrayInfoType> & arrays)88 bool vtkExodusIIReaderVariableCheck::UniquifyName(vtkExodusIIReaderPrivate::ArrayInfoType& ainfo,
89 std::vector<vtkExodusIIReaderPrivate::ArrayInfoType>& arrays)
90 {
91 bool nameChanged = false;
92 std::vector<vtkExodusIIReaderPrivate::ArrayInfoType>::iterator it = arrays.begin();
93 while (it != arrays.end())
94 {
95 if (it->Name == ainfo.Name)
96 {
97 nameChanged = true;
98 ainfo.Name.append("_");
99 it = arrays.begin(); // Have to start over now that we've changed the name.
100 }
101 else
102 {
103 ++it;
104 }
105 }
106 return nameChanged;
107 }
108
vtkExodusIIReaderScalarCheck()109 vtkExodusIIReaderScalarCheck::vtkExodusIIReaderScalarCheck()
110 {
111 this->GlomType = vtkExodusIIReaderPrivate::Scalar;
112 }
113
StartInternal(std::string name,const int *,int)114 bool vtkExodusIIReaderScalarCheck::StartInternal(std::string name, const int*, int)
115 {
116 this->Prefix = name;
117 this->OriginalNames.push_back(name);
118 return false;
119 }
120
Add(std::string,const int *)121 bool vtkExodusIIReaderScalarCheck::Add(std::string, const int*)
122 { // Scalars never have more than 1 name
123 return false;
124 }
125
vtkExodusIIReaderVectorCheck(const char * seq,int n)126 vtkExodusIIReaderVectorCheck::vtkExodusIIReaderVectorCheck(const char* seq, int n)
127 {
128 this->Endings.clear();
129 this->Endings.insert(this->Endings.begin(), seq, seq + n);
130 this->Endings = vtksys::SystemTools::LowerCase(this->Endings);
131 switch (n)
132 {
133 case 2:
134 this->GlomType = vtkExodusIIReaderPrivate::Vector2;
135 break;
136 case 3:
137 this->GlomType = vtkExodusIIReaderPrivate::Vector3;
138 break;
139 default:
140 this->GlomType = -1; // Oops. What goes here?
141 break;
142 }
143 }
144
StartInternal(std::string name,const int *,int)145 bool vtkExodusIIReaderVectorCheck::StartInternal(std::string name, const int*, int)
146 {
147 std::string::size_type len = name.size();
148 if (len > 1 && tolower(name[len - 1]) == this->Endings[0])
149 {
150 this->Prefix = name.substr(0, len - 1);
151 this->OriginalNames.push_back(name);
152 this->StillAdding = true;
153 return true;
154 }
155 this->StillAdding = false;
156 this->Prefix = "";
157 return false;
158 }
159
Add(std::string name,const int * truth)160 bool vtkExodusIIReaderVectorCheck::Add(std::string name, const int* truth)
161 {
162 if ((!this->StillAdding) || (this->OriginalNames.size() >= this->Endings.size()) ||
163 (!this->CheckTruth(truth)))
164 {
165 this->StillAdding = false;
166 return false;
167 }
168 std::string::size_type len = name.size();
169 if ((len != this->Prefix.size() + 1) || (name.substr(0, len - 1) != this->Prefix) ||
170 (tolower(name[len - 1]) != this->Endings[this->OriginalNames.size()]))
171 {
172 this->StillAdding = false;
173 return false;
174 }
175
176 this->OriginalNames.push_back(name);
177 return true;
178 }
179
Length()180 std::vector<std::string>::size_type vtkExodusIIReaderVectorCheck::Length()
181 {
182 std::vector<std::string>::size_type len = this->OriginalNames.size();
183 return (len == this->Endings.size()) ? len : 0;
184 }
185
186 /*
187 rank 1:
188 dim 1( 1): x
189 dim 2( 2): x y
190 dim 3( 3): x y z
191 dim 4( 4): x y z w
192 1
193 1 1
194 1 1 1
195 1 1 1 1
196 rank 2:
197 dim 1( 1): xx
198 dim 2( 3): xx yy xy
199 dim 3( 6): xx yy zz xy xz yz
200 dim 4(10): xx yy zz ww xy xz xw yz yw zw
201 1
202 2 1
203 3 2 1
204 4 3 2 1
205 rank 3:
206 dim 1( 1): xxx
207 dim 2( 4): xxx yyy xxy xyy
208 dim 3(10): xxx yyy zzz xxy xxz xyy xyz xzz yyz yzz
209 dim 4(20): xxx yyy zzz www xxy xxz xxw xyy xyz xyw xzz xzw xww yyz yyw yzz yzw yww zzw zww
210 1
211 3 1
212 6 3 1
213 10 6 3 1
214 5!/3!/2 + 4!/2!/2 + 3!/1!/2 + 2!/0!/2 = 20
215 4!/2!/2 + 3!/1!/2 + 2!/0!/2 = 10
216 3!/1!/2 + 2!/0!/2 = 4
217 2!/0!/2 = 1
218
219 number of endings = nchoosek( rank + dim - 1, rank )
220 */
221
vtkExodusIIReaderTensorCheck(const char * seq,int n,int rank,int dim)222 vtkExodusIIReaderTensorCheck::vtkExodusIIReaderTensorCheck(
223 const char* seq, int n, int rank, int dim)
224 {
225 this->NumEndings = vtkMath::Binomial(rank + dim - 1, rank);
226 if (n == (int)this->NumEndings && rank > 0 && dim > 0)
227 {
228 this->Dimension = dim;
229 this->Rank = rank;
230 this->Endings.insert(this->Endings.begin(), seq, seq + n * rank);
231 this->Endings = vtksys::SystemTools::LowerCase(this->Endings);
232 if (this->Rank == 1 && this->Dimension == 2)
233 {
234 this->GlomType = vtkExodusIIReaderPrivate::Vector2;
235 }
236 else if (this->Rank == 1 && this->Dimension == 3)
237 {
238 this->GlomType = vtkExodusIIReaderPrivate::Vector3;
239 }
240 else
241 {
242 this->GlomType = vtkExodusIIReaderPrivate::SymmetricTensor;
243 }
244 }
245 else
246 {
247 vtkGenericWarningMacro("Invalid number of tensor endings " << n
248 << " for "
249 "rank "
250 << rank << " and dimension " << dim
251 << "; expected "
252 "vtkMath::Binomial( "
253 << (rank + dim - 1) << ", " << rank
254 << ")"
255 " = "
256 << this->NumEndings);
257 this->GlomType = -1;
258 this->NumEndings = 0;
259 }
260 }
261
StartInternal(std::string name,const int *,int)262 bool vtkExodusIIReaderTensorCheck::StartInternal(std::string name, const int*, int)
263 {
264 std::string::size_type len = name.size();
265 if ((len > (unsigned)this->Rank) &&
266 vtksys::SystemTools::LowerCase(name.substr(len - this->Rank)) ==
267 this->Endings.substr(0, this->Rank))
268 {
269 this->Prefix = name.substr(0, len - this->Rank);
270 this->OriginalNames.push_back(name);
271 this->StillAdding = true;
272 return true;
273 }
274 this->Prefix = "";
275 this->StillAdding = false;
276 return false;
277 }
278
Add(std::string name,const int * truth)279 bool vtkExodusIIReaderTensorCheck::Add(std::string name, const int* truth)
280 {
281 if ((!this->StillAdding) || (this->OriginalNames.size() >= this->NumEndings) ||
282 (!this->CheckTruth(truth)))
283 {
284 this->StillAdding = false;
285 return false;
286 }
287 std::string::size_type len = name.size();
288 if ((len != this->Prefix.size() + this->Rank) ||
289 (name.substr(0, len - this->Rank) != this->Prefix))
290 {
291 this->StillAdding = false;
292 return false;
293 }
294 std::string::size_type endingOffset = this->OriginalNames.size() * this->Rank;
295 if (vtksys::SystemTools::LowerCase(name.substr(len - this->Rank)) !=
296 this->Endings.substr(endingOffset, this->Rank))
297 {
298 this->StillAdding = false;
299 return false;
300 }
301
302 this->OriginalNames.push_back(name);
303 return true;
304 }
305
Length()306 std::vector<std::string>::size_type vtkExodusIIReaderTensorCheck::Length()
307 {
308 std::vector<std::string>::size_type len = this->OriginalNames.size();
309 // std::vector<std::string>::size_type expected = this->Rank * this->Dimension;
310 return (len == this->NumEndings) ? len : 0;
311 }
312
vtkExodusIIReaderIntPointCheck()313 vtkExodusIIReaderIntPointCheck::vtkExodusIIReaderIntPointCheck()
314 : RegExp("(.*)_([^_]*)_GP([0-9,]+)$")
315 {
316 this->GlomType = vtkExodusIIReaderPrivate::IntegrationPoint;
317 }
318
StartInternal(std::string name,const int *,int)319 bool vtkExodusIIReaderIntPointCheck::StartInternal(std::string name, const int*, int)
320 {
321 if (this->RegExp.find(name))
322 {
323 this->VarName = this->RegExp.match(1);
324 this->CellType = this->RegExp.match(2);
325 this->Prefix = this->VarName + "_" + this->CellType;
326 // Can't have 3-D Gauss points on a quad (unless it's a shell) or 2-D Gauss points for a hex,
327 // so verify that the integration domain has a rank appropriate to the cell type.
328 // This also verifies that the cell type is valid and initializes IntPtMin, IntPtMax, and
329 // IntPtNames.
330 if (this->StartIntegrationPoints(this->CellType, this->RegExp.match(3)))
331 {
332 this->OriginalNames.push_back(name);
333 this->StillAdding = true;
334 return true;
335 }
336 }
337 this->Prefix = "";
338 this->StillAdding = false;
339 return false;
340 }
341
Add(std::string name,const int *)342 bool vtkExodusIIReaderIntPointCheck::Add(std::string name, const int*)
343 {
344 if ((!this->StillAdding) || (this->Rank == 0))
345 {
346 this->StillAdding = false;
347 return false;
348 }
349 std::string::size_type nlen = name.size();
350 std::string::size_type plen = this->Prefix.size();
351 if ((nlen != plen + this->Rank + 3 /* for "_GP" */) || (name.substr(0, plen) != this->Prefix) ||
352 (!this->AddIntegrationPoint(name.substr(nlen - this->Rank))))
353 {
354 this->StillAdding = false;
355 return false;
356 }
357
358 this->OriginalNames.push_back(name);
359 return true;
360 }
361
Length()362 std::vector<std::string>::size_type vtkExodusIIReaderIntPointCheck::Length()
363 {
364 if (this->IntPtMin.size() != this->IntPtMax.size())
365 return 0;
366
367 // Compute the size of the product space of the integration point indices.
368 // FIXME: This assumes that integration points will be placed in a full-tensor
369 // product arrangement, which may not be true for triangular, tetrahedral
370 // wedge, or pyramidal elements depending on how they are parameterized.
371 vtkTypeUInt64 numExpected = 1;
372 for (unsigned int i = 0; i < this->IntPtMax.size(); ++i)
373 {
374 numExpected *= (this->IntPtMax[i] - this->IntPtMin[i] + 1);
375 }
376 if (numExpected < 1 || numExpected != this->OriginalNames.size())
377 return 0;
378
379 return this->OriginalNames.size();
380 }
381
382 /*
383 int vtkExodusIIReaderIntPointCheck::Accept(
384 std::vector<vtkExodusIIReaderPrivate::ArrayInfoType>& arr, int startIndex, vtkExodusIIReaderPrivate*
385 priv, int objtyp )
386 {
387 }
388 */
389
StartIntegrationPoints(std::string cellType,std::string iptName)390 bool vtkExodusIIReaderIntPointCheck::StartIntegrationPoints(
391 std::string cellType, std::string iptName)
392 {
393 struct
394 {
395 const char* RE;
396 int Rank;
397 } cellTypes[] = { { "[Qq][Uu][Aa][Dd]", 2 }, { "[Hh][Ee][Xx]", 3 }, { "[Tt][Ee][Tt]", 3 },
398 { "[Tt][Rr][Ii]", 2 }, { "[Ww][Ee][Dd][Gg][Ee]", 3 }, { "[Pp][Yy][Rr]", 3 } };
399 vtksys::RegularExpression ctrexp;
400 std::string::size_type expectedRank = static_cast<std::string::size_type>(-1);
401 for (unsigned int i = 0; i < sizeof(cellTypes) / sizeof(cellTypes[0]); ++i)
402 {
403 ctrexp.compile(cellTypes[i].RE);
404 if (ctrexp.find(cellType))
405 {
406 expectedRank = cellTypes[i].Rank;
407 break;
408 }
409 }
410 std::string::size_type rank = iptName.size();
411 if (expectedRank > 0 && rank != expectedRank)
412 {
413 this->Rank = 0;
414 return false;
415 }
416 this->Rank = rank;
417 this->IntPtMin.clear();
418 this->IntPtMax.clear();
419 for (std::string::size_type i = 0; i < rank; ++i)
420 {
421 int ival = iptName[i] - '0';
422 if (ival < 0 || ival > 9)
423 {
424 this->Rank = 0;
425 return false;
426 }
427 this->IntPtMin.push_back(ival);
428 this->IntPtMax.push_back(ival);
429 }
430 this->IntPtNames.clear(); // clear out any old values
431 this->IntPtNames.insert(iptName);
432 return true;
433 }
434
AddIntegrationPoint(std::string iptName)435 bool vtkExodusIIReaderIntPointCheck::AddIntegrationPoint(std::string iptName)
436 {
437 std::string::size_type rank = iptName.size();
438 if (rank != this->Rank)
439 {
440 this->Rank = 0;
441 return false;
442 }
443 std::pair<std::set<std::string>::iterator, bool> result;
444 result = this->IntPtNames.insert(iptName);
445 if (!result.second)
446 { // Oops, this integration point is a duplicate.
447 this->Rank = 0;
448 return false;
449 }
450 for (std::string::size_type i = 0; i < rank; ++i)
451 {
452 int ival = iptName[i] - '0';
453 if (ival < 0 || ival > 9)
454 {
455 this->Rank = 0;
456 return false;
457 }
458 if (this->IntPtMin[i] > ival)
459 this->IntPtMin[i] = ival;
460 if (this->IntPtMax[i] < ival)
461 this->IntPtMax[i] = ival;
462 }
463 return true;
464 }
465