1 #include "vtkMath.h"
2 #include "vtkStdString.h"
3 #include "vtkIntArray.h"
4 #include "vtkUnstructuredGrid.h"
5 #include "vtkPolyData.h"
6 #include "vtkExodusIIReader.h"
7 #include "vtkExodusIIReaderPrivate.h"
8 #include "vtkExodusIIReaderVariableCheck.h"
9 #include <vtksys/RegularExpression.hxx>
10 #include <vtksys/SystemTools.hxx>
11 #include <string>
12 #include <vector>
13 #include <set>
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,
39 int startIndex, 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.push_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(); ++ it, ++ truth )
77 {
78 if ( *truth != *it )
79 {
80 return false;
81 }
82 }
83
84 return true;
85 }
86
UniquifyName(vtkExodusIIReaderPrivate::ArrayInfoType & ainfo,std::vector<vtkExodusIIReaderPrivate::ArrayInfoType> & arrays)87 bool vtkExodusIIReaderVariableCheck::UniquifyName(
88 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 (
163 ( ! this->StillAdding ) ||
164 ( this->OriginalNames.size() >= this->Endings.size() ) ||
165 ( ! this->CheckTruth( truth ) ) )
166 {
167 this->StillAdding = false;
168 return false;
169 }
170 std::string::size_type len = name.size();
171 if (
172 ( len != this->Prefix.size() + 1 ) ||
173 ( name.substr( 0, len - 1 ) != this->Prefix ) ||
174 ( tolower( name[len - 1] ) != this->Endings[this->OriginalNames.size()] ) )
175 {
176 this->StillAdding = false;
177 return false;
178 }
179
180 this->OriginalNames.push_back( name );
181 return true;
182 }
183
Length()184 std::vector<std::string>::size_type vtkExodusIIReaderVectorCheck::Length()
185 {
186 std::vector<std::string>::size_type len = this->OriginalNames.size();
187 return ( len == this->Endings.size() ) ? len : 0;
188 }
189
190 /*
191 rank 1:
192 dim 1( 1): x
193 dim 2( 2): x y
194 dim 3( 3): x y z
195 dim 4( 4): x y z w
196 1
197 1 1
198 1 1 1
199 1 1 1 1
200 rank 2:
201 dim 1( 1): xx
202 dim 2( 3): xx yy xy
203 dim 3( 6): xx yy zz xy xz yz
204 dim 4(10): xx yy zz ww xy xz xw yz yw zw
205 1
206 2 1
207 3 2 1
208 4 3 2 1
209 rank 3:
210 dim 1( 1): xxx
211 dim 2( 4): xxx yyy xxy xyy
212 dim 3(10): xxx yyy zzz xxy xxz xyy xyz xzz yyz yzz
213 dim 4(20): xxx yyy zzz www xxy xxz xxw xyy xyz xyw xzz xzw xww yyz yyw yzz yzw yww zzw zww
214 1
215 3 1
216 6 3 1
217 10 6 3 1
218 5!/3!/2 + 4!/2!/2 + 3!/1!/2 + 2!/0!/2 = 20
219 4!/2!/2 + 3!/1!/2 + 2!/0!/2 = 10
220 3!/1!/2 + 2!/0!/2 = 4
221 2!/0!/2 = 1
222
223 number of endings = nchoosek( rank + dim - 1, rank )
224 */
225
vtkExodusIIReaderTensorCheck(const char * seq,int n,int rank,int dim)226 vtkExodusIIReaderTensorCheck::vtkExodusIIReaderTensorCheck( const char* seq, int n, int rank, int dim )
227 {
228 this->NumEndings = vtkMath::Binomial( rank + dim - 1, rank );
229 if ( n == (int) this->NumEndings && rank > 0 && dim > 0 )
230 {
231 this->Dimension = dim;
232 this->Rank = rank;
233 this->Endings.insert( this->Endings.begin(), seq, seq + n * rank );
234 this->Endings = vtksys::SystemTools::LowerCase( this->Endings );
235 if ( this->Rank == 1 && this->Dimension == 2 )
236 {
237 this->GlomType = vtkExodusIIReaderPrivate::Vector2;
238 }
239 else if ( this->Rank == 1 && this->Dimension == 3 )
240 {
241 this->GlomType = vtkExodusIIReaderPrivate::Vector3;
242 }
243 else
244 {
245 this->GlomType = vtkExodusIIReaderPrivate::SymmetricTensor;
246 }
247 }
248 else
249 {
250 vtkGenericWarningMacro(
251 "Invalid number of tensor endings " << n << " for "
252 "rank " << rank << " and dimension " << dim << "; expected "
253 "vtkMath::Binomial( " << ( rank + dim - 1 ) << ", " << rank << ")"
254 " = " << this->NumEndings );
255 this->GlomType = -1;
256 this->NumEndings = 0;
257 }
258 }
259
StartInternal(std::string name,const int *,int)260 bool vtkExodusIIReaderTensorCheck::StartInternal( std::string name, const int*, int )
261 {
262 std::string::size_type len = name.size();
263 if ( ( len > (unsigned) this->Rank ) &&
264 vtksys::SystemTools::LowerCase( name.substr(len - this->Rank ) ) == this->Endings.substr( 0, this->Rank ) )
265 {
266 this->Prefix = name.substr( 0, len - this->Rank );
267 this->OriginalNames.push_back( name );
268 this->StillAdding = true;
269 return true;
270 }
271 this->Prefix = "";
272 this->StillAdding = false;
273 return false;
274 }
275
Add(std::string name,const int * truth)276 bool vtkExodusIIReaderTensorCheck::Add( std::string name, const int* truth )
277 {
278 if (
279 ( ! this->StillAdding ) ||
280 ( this->OriginalNames.size() >= this->NumEndings ) ||
281 ( ! this->CheckTruth( truth ) ) )
282 {
283 this->StillAdding = false;
284 return false;
285 }
286 std::string::size_type len = name.size();
287 if (
288 ( 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 ) ) != this->Endings.substr( endingOffset, this->Rank ) )
296 {
297 this->StillAdding = false;
298 return false;
299 }
300
301 this->OriginalNames.push_back( name );
302 return true;
303 }
304
Length()305 std::vector<std::string>::size_type vtkExodusIIReaderTensorCheck::Length()
306 {
307 std::vector<std::string>::size_type len = this->OriginalNames.size();
308 //std::vector<std::string>::size_type expected = this->Rank * this->Dimension;
309 return ( len == this->NumEndings ) ? len : 0;
310 }
311
vtkExodusIIReaderIntPointCheck()312 vtkExodusIIReaderIntPointCheck::vtkExodusIIReaderIntPointCheck()
313 : RegExp( "(.*)_([^_]*)_GP([0-9,]+)$" )
314 {
315 this->GlomType = vtkExodusIIReaderPrivate::IntegrationPoint;
316 }
317
StartInternal(std::string name,const int *,int)318 bool vtkExodusIIReaderIntPointCheck::StartInternal( std::string name, const int*, int )
319 {
320 if ( this->RegExp.find( name ) )
321 {
322 this->VarName = this->RegExp.match( 1 );
323 this->CellType = this->RegExp.match( 2 );
324 this->Prefix = this->VarName + "_" + this->CellType;
325 // Can't have 3-D Gauss points on a quad (unless it's a shell) or 2-D Gauss points for a hex,
326 // so verify that the integration domain has a rank appropriate to the cell type.
327 // This also verifies that the cell type is valid and initializes IntPtMin, IntPtMax, and IntPtNames.
328 if ( this->StartIntegrationPoints( this->CellType, this->RegExp.match( 3 ) ) )
329 {
330 this->OriginalNames.push_back( name );
331 this->StillAdding = true;
332 return true;
333 }
334 }
335 this->Prefix = "";
336 this->StillAdding = false;
337 return false;
338 }
339
Add(std::string name,const int *)340 bool vtkExodusIIReaderIntPointCheck::Add( std::string name, const int* )
341 {
342 if (
343 ( ! this->StillAdding ) ||
344 ( 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 (
352 ( nlen != plen + this->Rank + 3 /* for "_GP" */ ) ||
353 ( name.substr( 0, plen ) != this->Prefix ) ||
354 ( ! this->AddIntegrationPoint( name.substr( nlen - this->Rank ) ) ) )
355 {
356 this->StillAdding = false;
357 return false;
358 }
359
360 this->OriginalNames.push_back( name );
361 return true;
362 }
363
Length()364 std::vector<std::string>::size_type vtkExodusIIReaderIntPointCheck::Length()
365 {
366 if ( this->IntPtMin.size() != this->IntPtMax.size() )
367 return 0;
368
369 // Compute the size of the product space of the integration point indices.
370 // FIXME: This assumes that integration points will be placed in a full-tensor
371 // product arrangement, which may not be true for triangular, tetrahedral
372 // wedge, or pyramidal elements depending on how they are parameterized.
373 vtkTypeUInt64 numExpected = 1;
374 for ( unsigned int i = 0; i < this->IntPtMax.size(); ++ i )
375 {
376 numExpected *= ( this->IntPtMax[i] - this->IntPtMin[i] + 1 );
377 }
378 if ( numExpected < 1 || numExpected != this->OriginalNames.size() )
379 return 0;
380
381 return this->OriginalNames.size();
382 }
383
384 /*
385 int vtkExodusIIReaderIntPointCheck::Accept(
386 std::vector<vtkExodusIIReaderPrivate::ArrayInfoType>& arr, int startIndex, vtkExodusIIReaderPrivate* priv, int objtyp )
387 {
388 }
389 */
390
StartIntegrationPoints(std::string cellType,std::string iptName)391 bool vtkExodusIIReaderIntPointCheck::StartIntegrationPoints(
392 std::string cellType, std::string iptName )
393 {
394 struct
395 {
396 const char* RE;
397 int Rank;
398 }
399 cellTypes[] =
400 {
401 { "[Qq][Uu][Aa][Dd]", 2 },
402 { "[Hh][Ee][Xx]", 3 },
403 { "[Tt][Ee][Tt]", 3 },
404 { "[Tt][Rr][Ii]", 2 },
405 { "[Ww][Ee][Dd][Gg][Ee]", 3 },
406 { "[Pp][Yy][Rr]", 3 }
407 };
408 vtksys::RegularExpression ctrexp;
409 std::string::size_type expectedRank = static_cast<std::string::size_type>( -1 );
410 for ( unsigned int i = 0; i < sizeof(cellTypes)/sizeof(cellTypes[0]); ++ i )
411 {
412 ctrexp.compile( cellTypes[i].RE );
413 if ( ctrexp.find( cellType ) )
414 {
415 expectedRank = cellTypes[i].Rank;
416 break;
417 }
418 }
419 std::string::size_type rank = iptName.size();
420 if ( expectedRank > 0 && rank != expectedRank )
421 {
422 this->Rank = 0;
423 return false;
424 }
425 this->Rank = rank;
426 this->IntPtMin.clear();
427 this->IntPtMax.clear();
428 for ( std::string::size_type i = 0; i < rank; ++ i )
429 {
430 int ival = iptName[i] - '0';
431 if ( ival < 0 || ival > 9 )
432 {
433 this->Rank = 0;
434 return false;
435 }
436 this->IntPtMin.push_back( ival );
437 this->IntPtMax.push_back( ival );
438 }
439 this->IntPtNames.clear(); // clear out any old values
440 this->IntPtNames.insert( iptName );
441 return true;
442 }
443
AddIntegrationPoint(std::string iptName)444 bool vtkExodusIIReaderIntPointCheck::AddIntegrationPoint( std::string iptName )
445 {
446 std::string::size_type rank = iptName.size();
447 if ( rank != this->Rank )
448 {
449 this->Rank = 0;
450 return false;
451 }
452 std::pair<std::set<std::string>::iterator,bool> result;
453 result = this->IntPtNames.insert( iptName );
454 if ( ! result.second )
455 { // Oops, this integration point is a duplicate.
456 this->Rank = 0;
457 return false;
458 }
459 for ( std::string::size_type i = 0; i < rank; ++ i )
460 {
461 int ival = iptName[i] - '0';
462 if ( ival < 0 || ival > 9 )
463 {
464 this->Rank = 0;
465 return false;
466 }
467 if ( this->IntPtMin[i] > ival )
468 this->IntPtMin[i] = ival;
469 if ( this->IntPtMax[i] < ival )
470 this->IntPtMax[i] = ival;
471 }
472 return true;
473 }
474