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