1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkLSDynaReader.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 Copyright (c) Sandia Corporation
17 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
18 ----------------------------------------------------------------------------*/
19
20 // NOTE TO DEVELOPERS: ========================================================
21 //
22 // This is a really big reader.
23 // It uses several classes defined in Utilities/LSDyna:
24 // - LSDynaFamily:
25 // A class to abstract away I/O from families of output files.
26 // This performs the actual reads and writes plus any required byte swapping.
27 // Also contains a subclass, LSDynaFamilyAdaptLevel, used to store
28 // file+offset
29 // information for each mesh adaptation's state info.
30 // - LSDynaMetaData:
31 // A class to hold metadata about a particular file (such as time steps,
32 // the start of state information for each time step, the number of
33 // adaptive remeshes, and the large collection of constants that determine
34 // the available attributes). It contains an LSDynaFamily instance.
35
36 //It also uses a helper vtk class
37 // - vtkLSDynaSummaryParser:
38 // A class to parse XML summary files containing part names and their IDs.
39 // This class is used by vtkLSDynaReader::ReadInputDeckXML().
40
41 // This class is preceded by some file-static constants and utility routines.
42
43 #include "vtkLSDynaReader.h"
44 #include "vtkLSDynaSummaryParser.h"
45 #include "vtkLSDynaPartCollection.h"
46 #include "LSDynaFamily.h"
47 #include "LSDynaMetaData.h"
48
49 #include "vtksys/SystemTools.hxx"
50
51 #include <string>
52 #include <vector>
53 #include <algorithm>
54 #include <map>
55 #include <cassert>
56
57 #include "vtkCellType.h"
58 #include "vtkDataObject.h"
59 #include "vtkDoubleArray.h"
60 #include "vtkFloatArray.h"
61 #include "vtkIdTypeArray.h"
62 #include "vtkInformation.h"
63 #include "vtkInformationDoubleVectorKey.h"
64 #include "vtkInformationVector.h"
65 #include "vtkMultiBlockDataSet.h"
66 #include "vtkObjectFactory.h"
67 #include "vtkPointData.h"
68 #include "vtkPoints.h"
69 #include "vtkSmartPointer.h"
70 #include "vtkStreamingDemandDrivenPipeline.h"
71 #include "vtkUnsignedCharArray.h"
72 #include "vtkUnstructuredGrid.h"
73 #include "vtkVectorOperators.h"
74
75 vtkStandardNewMacro(vtkLSDynaReader);
76
77 // Names of vtkDataArrays provided with grid:
78 #define LS_ARRAYNAME_DEATH "Death"
79 #define LS_ARRAYNAME_USERID "UserID"
80 #define LS_ARRAYNAME_SPECIES_BLNK "SpeciesXX"
81 #define LS_ARRAYNAME_SPECIES_FMT "Species%02d"
82 #define LS_ARRAYNAME_SPECIES_01 "Species01"
83 #define LS_ARRAYNAME_SPECIES_02 "Species02"
84 #define LS_ARRAYNAME_SPECIES_03 "Species03"
85 #define LS_ARRAYNAME_SPECIES_04 "Species04"
86 #define LS_ARRAYNAME_SPECIES_05 "Species05"
87 #define LS_ARRAYNAME_SPECIES_06 "Species06"
88 #define LS_ARRAYNAME_SPECIES_07 "Species07"
89 #define LS_ARRAYNAME_SPECIES_08 "Species08"
90 #define LS_ARRAYNAME_SPECIES_09 "Species09"
91 #define LS_ARRAYNAME_SPECIES_10 "Species10"
92 #define LS_ARRAYNAME_TEMPERATURE "Temperature"
93 #define LS_ARRAYNAME_DEFLECTION "Deflected Coordinates"
94 #define LS_ARRAYNAME_VELOCITY "Velocity"
95 #define LS_ARRAYNAME_ACCELERATION "Acceleration"
96 #define LS_ARRAYNAME_PRESSURE "Pressure"
97 #define LS_ARRAYNAME_VORTICITY "Vorticity"
98 #define LS_ARRAYNAME_RESULTANTVORTICITY "ResVorticity"
99 #define LS_ARRAYNAME_ENSTROPHY "Enstrophy"
100 #define LS_ARRAYNAME_HELICITY "Helicity"
101 #define LS_ARRAYNAME_STREAMFUNCTION "StreamFunc"
102 #define LS_ARRAYNAME_ENTHALPY "Enthalpy"
103 #define LS_ARRAYNAME_DENSITY "Density"
104 #define LS_ARRAYNAME_TURBULENTKE "TurbulentKE"
105 #define LS_ARRAYNAME_DISSIPATION "Dissipation"
106 #define LS_ARRAYNAME_EDDYVISCOSITY "EddyVisc"
107 #define LS_ARRAYNAME_RADIUSOFINFLUENCE "InfluenceRadius"
108 #define LS_ARRAYNAME_NUMNEIGHBORS "NumberOfNeighbors"
109 #define LS_ARRAYNAME_SEGMENTID "SegmentID"
110 #define LS_ARRAYNAME_STRAIN "Strain"
111 #define LS_ARRAYNAME_STRESS "Stress"
112 #define LS_ARRAYNAME_EPSTRAIN "EffPlastStrn"
113 #define LS_ARRAYNAME_INTEGRATIONPOINT "IntPtData"
114 #define LS_ARRAYNAME_RESULTANTS "Resultants"
115 #define LS_ARRAYNAME_ELEMENTMISC "ElementMisc"
116 #define LS_ARRAYNAME_INTERNALENERGY "InternalEnergy"
117 #define LS_ARRAYNAME_AXIALFORCE "AxialForce"
118 #define LS_ARRAYNAME_SHEARRESULTANT "ShearResultant"
119 #define LS_ARRAYNAME_BENDINGRESULTANT "BendingResultant"
120 #define LS_ARRAYNAME_TORSIONRESULTANT "TorsionResultant"
121 #define LS_ARRAYNAME_NORMALRESULTANT "NormalResultant"
122 #define LS_ARRAYNAME_AXIALSTRAIN "AxialStrain"
123 #define LS_ARRAYNAME_AXIALSTRESS "AxialStress"
124 #define LS_ARRAYNAME_SHEARSTRAIN "ShearStrain"
125 #define LS_ARRAYNAME_SHEARSTRESS "ShearStress"
126 #define LS_ARRAYNAME_PLASTICSTRAIN "PlasticStrain"
127 #define LS_ARRAYNAME_THICKNESS "Thickness"
128 #define LS_ARRAYNAME_MASS "Mass"
129 #define LS_ARRAYNAME_VOLUME_FRACTION_FMT "VolumeFraction%02d"
130 #define LS_ARRAYNAME_DOMINANT_GROUP "DominantGroup"
131 #define LS_ARRAYNAME_SPECIES_MASS_FMT "SpeciesMass%02d"
132 #define LS_ARRAYNAME_MATERIAL "Material"
133
134 // Possible material options
135 #define LS_MDLOPT_NONE 0
136 #define LS_MDLOPT_POINT 1
137 #define LS_MDLOPT_CELL 2
138
139 #ifdef VTK_LSDYNA_DBG_MULTIBLOCK
140 static void vtkDebugMultiBlockStructure( vtkIndent indent, vtkMultiGroupDataSet* mbds );
141 #endif // VTK_LSDYNA_DBG_MULTIBLOCK
142
143 namespace
144 {
145 static const char* vtkLSDynaCellTypes[] =
146 {
147 "Point",
148 "Beam",
149 "Shell",
150 "Thick Shell",
151 "Solid",
152 "Rigid Body",
153 "Road Surface"
154 };
155
156 // Read in lines until one that's
157 // - not empty, and
158 // - not a comment
159 // is encountered. Return with that text stored in \a line.
160 // If an error or EOF is hit, return 0. Otherwise, return 1.
vtkLSNextSignificantLine(ifstream & deck,std::string & line)161 static int vtkLSNextSignificantLine( ifstream& deck, std::string& line )
162 {
163 while ( deck.good() )
164 {
165 std::getline( deck, line, '\n' );
166 if ( ! line.empty() && line[0] != '$' )
167 {
168 return 1;
169 }
170 }
171 return 0;
172 }
173
vtkLSTrimWhitespace(std::string & line)174 static void vtkLSTrimWhitespace( std::string& line )
175 {
176 std::string::size_type llen = line.length();
177 while ( llen &&
178 ( line[llen - 1] == ' ' ||
179 line[llen - 1] == '\t' ||
180 line[llen - 1] == '\r' ||
181 line[llen - 1] == '\n' ) )
182 {
183 --llen;
184 }
185
186 std::string::size_type nameStart = 0;
187 while ( nameStart < llen &&
188 ( line[nameStart] == ' ' ||
189 line[nameStart] == '\t' ) )
190 {
191 ++nameStart;
192 }
193
194 line = line.substr( nameStart, llen - nameStart );
195 }
196
vtkLSDowncaseFirstWord(std::string & downcased,const std::string & line)197 static void vtkLSDowncaseFirstWord( std::string& downcased, const std::string& line )
198 {
199 std::string::size_type i;
200 std::string::value_type chr;
201 int leadingSpace = 0;
202 downcased = "";
203 for ( i = 0; i < line.length(); ++i )
204 {
205 chr = tolower( line[i] );
206 if ( chr == ' ' || chr == '\t' )
207 {
208 if ( leadingSpace )
209 { // We've trimmed leading whitespace already, so we're done with the word.
210 return;
211 }
212 }
213 else
214 {
215 leadingSpace = 1;
216 if ( chr == ',' )
217 { // We're at a separator (other than whitespace). No need to continue.
218 return;
219 }
220 }
221 downcased += chr;
222 }
223 }
224
vtkLSSplitString(std::string & input,std::vector<std::string> & splits,const char * separators)225 void vtkLSSplitString( std::string& input, std::vector<std::string>& splits, const char* separators )
226 {
227 std::string::size_type posBeg = 0;
228 std::string::size_type posEnd;
229 do {
230 posEnd = input.find_first_of( separators, posBeg );
231 if ( posEnd > posBeg )
232 {
233 // don't include empty entries in splits.
234 // NOTE: This means ",comp,1, ,3" with separators ", " yields "comp","1","3", not "","comp","1","","","3".
235 splits.push_back( input.substr( posBeg, posEnd - posBeg ) );
236 }
237 posBeg = input.find_first_not_of( separators, posEnd );
238 } while ( posBeg != std::string::npos );
239 }
240
241 template<int hostBitSize, int fileBitSize, int cellLength> struct Converter
242 {
243 //general use case that the host
244 //bit size and file bit size are the same
convert__anon4070b03b0111::Converter245 vtkIdType* convert(vtkIdType* buff, const vtkIdType&)
246 {
247 return buff;
248 }
249 };
250
251 template<int cellLength> struct Converter<8,4,cellLength>
252 {
253 //specilization of 64bit machine and 32bit file
254 //so we have to copy each item individually
convert__anon4070b03b0111::Converter255 vtkIdType* convert(int* buff, const vtkIdType& size)
256 {
257 for(vtkIdType i=0;i<size;++i)
258 {
259 this->Conn[i]=static_cast<vtkIdType>(buff[i]);
260 }
261 return Conn;
262 }
263 vtkIdType Conn[cellLength];
264 };
265
266 template<int cellLength> struct Converter<4,8,cellLength>
267 {
268 //specilization for reading 64 bit files on a 32 bit machine
269 //which means reading the bottom half of the long long
convert__anon4070b03b0111::Converter270 vtkIdType* convert(int* buff, const vtkIdType& size)
271 {
272 vtkIdType idx=0;
273 for(vtkIdType i=0;i<size;i+=2,++idx)
274 {
275 this->Conn[idx]=static_cast<vtkIdType>(buff[i]);
276 }
277 return Conn;
278 }
279 vtkIdType Conn[cellLength];
280 };
281
282 template<int type,int wordSize,int cellLength>
283 struct FillBlock
284 {
285 Converter<sizeof(vtkIdType),wordSize,cellLength> BC;
286
287 template<typename T>
FillBlock__anon4070b03b0111::FillBlock288 FillBlock(T* buff, vtkLSDynaPartCollection *parts,LSDynaMetaData *p,
289 const vtkIdType& numWordsPerCell, const int& cellType)
290 {
291 //determine the relationship between the file bit size and
292 //the host machine bit size. This allows us to read 64 bit files on a
293 //32 bit machine. The Converter allows us to easily convert 32bit
294 //arrays to 64bit arrays
295 const int numWordsPerIdType (p->Fam.GetWordSize() / sizeof(T));
296 const vtkIdType numFileWordsPerCell(numWordsPerCell * numWordsPerIdType);
297 const vtkIdType offsetToMatId(numWordsPerIdType *(numWordsPerCell-1));
298 vtkIdType *conn;
299
300 vtkIdType nc=0,j=0,matlId=0;
301 vtkIdType numCellsToSkip=0, numCellsToSkipEnd=0, chunkSize=0;
302
303
304 //get from the part the read information for this lsdyna block type
305 parts->GetPartReadInfo(type,nc,numCellsToSkip,numCellsToSkipEnd);
306
307 p->Fam.SkipWords(numFileWordsPerCell * numCellsToSkip ); //skip to the right start id
308
309 //buffer the amount in small chunks so we don't create a massive buffer
310 vtkIdType numChunks = p->Fam.InitPartialChunkBuffering(nc,numWordsPerCell);
311 for(vtkIdType i=0; i < numChunks; ++i)
312 {
313 chunkSize = p->Fam.GetNextChunk( LSDynaFamily::Int);
314 buff = p->Fam.GetBufferAs<T>();
315 for (j=0; j<chunkSize;j+=numWordsPerCell)
316 {
317 conn = BC.convert(buff,offsetToMatId);
318 buff+=offsetToMatId;
319 matlId = static_cast<vtkIdType>(*buff);
320 buff+=numWordsPerIdType;
321 parts->InsertCell(type,matlId,cellType,cellLength,conn);
322 }
323 }
324 p->Fam.SkipWords(numFileWordsPerCell * numCellsToSkipEnd);
325 }
326 };
327
328 template<int wordSize,int cellLength>
329 struct FillBlock<LSDynaMetaData::SOLID,wordSize,cellLength>
330 {
331 Converter<sizeof(vtkIdType),wordSize,cellLength> BC;
332
333 template<typename T>
FillBlock__anon4070b03b0111::FillBlock334 FillBlock(T* buff, vtkLSDynaPartCollection *parts,LSDynaMetaData *p,
335 const vtkIdType& numWordsPerCell, const int& vtkNotUsed(cellType) )
336 {
337 //determine the relationship between the file bit size and
338 //the host machine bit size. This allows us to read 64 bit files on a
339 //32 bit machine. The Converter allows us to easily convert 32bit
340 //arrays to 64bit arrays
341 const int numWordsPerIdType (p->Fam.GetWordSize() / sizeof(T));
342 const vtkIdType numFileWordsPerCell(numWordsPerCell * numWordsPerIdType);
343 const vtkIdType offsetToMatId(numWordsPerIdType * cellLength);
344 vtkIdType *conn;
345
346 //This is a read solids template specialization since it has a special use
347 //case for cell length based on the connectivity mapping
348 vtkIdType nc=0,j=0,matlId=0;
349 vtkIdType numCellsToSkip=0, numCellsToSkipEnd=0, chunkSize=0;
350
351 //get from the part the read information for this lsdyna block type
352 parts->GetPartReadInfo(LSDynaMetaData::SOLID,nc,numCellsToSkip,numCellsToSkipEnd);
353
354 p->Fam.SkipWords(numFileWordsPerCell * numCellsToSkip); //skip to the right start id
355
356 //buffer the amount in small chunks so we don't create a massive buffer
357 vtkIdType numChunks = p->Fam.InitPartialChunkBuffering(nc,numWordsPerCell);
358 vtkIdType npts = 0;
359 int ctype = 0;
360 for(vtkIdType i=0; i < numChunks; ++i)
361 {
362 chunkSize = p->Fam.GetNextChunk( LSDynaFamily::Int);
363 buff = p->Fam.GetBufferAs<T>();
364 for (j=0; j<chunkSize;j+=numWordsPerCell)
365 {
366 conn = BC.convert(buff,offsetToMatId);
367 buff+=offsetToMatId;
368 matlId = static_cast<vtkIdType>(*buff);
369 buff+=numWordsPerIdType;
370
371 //Detect repeated connectivity entries to determine element type
372 if (conn[3] == conn[7])
373 {
374 ctype = VTK_TETRA;
375 npts = 4;
376 }
377 else if (conn[4] == conn[7])
378 {
379 ctype = VTK_PYRAMID;
380 npts = 5;
381 }
382 else if (conn[5] == conn[7])
383 {
384 ctype = VTK_WEDGE;
385 npts = 6;
386 }
387 else
388 {
389 ctype = VTK_HEXAHEDRON;
390 npts = 8;
391 }
392
393 //push this cell back into the unstructured grid for this part(if the part is active)
394 parts->InsertCell(LSDynaMetaData::SOLID,matlId,ctype,npts,conn);
395 }
396 }
397 p->Fam.SkipWords(numFileWordsPerCell * numCellsToSkipEnd);
398 }
399 };
400
401 template<int wordSize,int cellLength>
402 struct FillBlock<LSDynaMetaData::SHELL,wordSize,cellLength>
403 {
404 Converter<sizeof(vtkIdType),wordSize,cellLength> BC;
405
406 template<typename T>
FillBlock__anon4070b03b0111::FillBlock407 FillBlock(T* buff, vtkLSDynaPartCollection *parts,LSDynaMetaData *p,
408 const vtkIdType& numWordsPerCell, const int& cellType)
409 {
410 //determine the relationship between the file bit size and
411 //the host machine bit size. This allows us to read 64 bit files on a
412 //32 bit machine. The Converter allows us to easily convert 32bit
413 //arrays to 64bit arrays
414 const int numWordsPerIdType (p->Fam.GetWordSize() / sizeof(T));
415 const vtkIdType numFileWordsPerCell(numWordsPerCell * numWordsPerIdType);
416 const vtkIdType offsetToMatId(numWordsPerIdType * cellLength);
417 vtkIdType *conn;
418
419 //This is a read RIGID_BODY and SHELL template specialization since it
420 //has a weird weaving of cell types
421 bool haveRigidMaterials = (p->Dict["MATTYP"] != 0) &&
422 !p->RigidMaterials.empty();
423
424 vtkIdType nc=0, j=0,matlId=0;
425 vtkIdType numCellsToSkip=0, numCellsToSkipEnd=0, chunkSize=0;
426
427 //get from the part the read information for this lsdyna block type
428 parts->GetPartReadInfo(LSDynaMetaData::SHELL,nc,numCellsToSkip,numCellsToSkipEnd);
429
430 p->Fam.SkipWords(numFileWordsPerCell * numCellsToSkip); //skip to the right start id
431
432 //buffer the amount in small chunks so we don't create a massive buffer
433 vtkIdType numChunks = p->Fam.InitPartialChunkBuffering(nc,numWordsPerCell);
434 int pType = 0;
435 for(vtkIdType i=0; i < numChunks; ++i)
436 {
437 chunkSize = p->Fam.GetNextChunk( LSDynaFamily::Int);
438 buff = p->Fam.GetBufferAs<T>();
439 for (j=0; j<chunkSize;j+=numWordsPerCell)
440 {
441 conn = BC.convert(buff,offsetToMatId);
442 buff+=offsetToMatId;
443 matlId = static_cast<vtkIdType>(*buff);
444 buff+=numWordsPerIdType;
445
446 if ( haveRigidMaterials &&
447 p->RigidMaterials.find( matlId ) == p->RigidMaterials.end())
448 {
449 pType = LSDynaMetaData::RIGID_BODY;
450 }
451 else
452 {
453 pType = LSDynaMetaData::SHELL;
454 }
455 parts->InsertCell(pType,matlId,cellType,cellLength,conn);
456 }
457 }
458 p->Fam.SkipWords(numFileWordsPerCell * numCellsToSkipEnd);
459 }
460 };
461
462 template<int wordSize,int cellLength>
463 struct FillBlock<LSDynaMetaData::ROAD_SURFACE,wordSize,cellLength>
464 {
465 template<typename T>
FillBlock__anon4070b03b0111::FillBlock466 FillBlock(T*, vtkLSDynaPartCollection *parts,LSDynaMetaData *p,
467 const vtkIdType&, const int& cellType)
468 {
469 //This is a ROAD_SURFACE specialization
470 //has a weird weaving of cell types
471 vtkIdType nc=0,segId=0,segSz=0;
472 vtkIdType numCellsToSkip=0, numCellsToSkipEnd=0;
473
474 //get from the part the read information for this lsdyna block type
475 parts->GetPartReadInfo(LSDynaMetaData::SHELL,nc,numCellsToSkip,numCellsToSkipEnd);
476
477 //the road surface format is horrible for parallel reading.
478 //we don't know the number of cells in each road surface.
479 //only the total number of cells. So we have to do some fun stuff to correctly skip
480 //this is unoptimized since I don't have any road surface data
481 vtkIdType currentCell=0;
482 vtkIdType conn[4];
483 for (vtkIdType i=0; i<p->Dict["NSURF"]; ++i)
484 {
485 p->Fam.BufferChunk( LSDynaFamily::Int, 2 );
486 segId = p->Fam.GetNextWordAsInt();
487 segSz = p->Fam.GetNextWordAsInt();
488 p->Fam.BufferChunk( LSDynaFamily::Int, 4*segSz );
489 for (vtkIdType t=0; t<segSz; ++t, ++currentCell)
490 {
491 if(currentCell >= numCellsToSkip)
492 {
493 for (int j=0; j<4; ++j )
494 {
495 conn[j] = p->Fam.GetNextWordAsInt() - 1;
496 }
497 parts->InsertCell(LSDynaMetaData::ROAD_SURFACE,segId,cellType,4,conn);
498 }
499 }
500 }
501 }
502 };
503
504 }
505 // =================================================== Start of public interface
vtkLSDynaReader()506 vtkLSDynaReader::vtkLSDynaReader()
507 {
508 this->P = new LSDynaMetaData;
509 this->SetNumberOfInputPorts(0);
510 this->SetNumberOfOutputPorts(1);
511 this->TimeStepRange[0] = 0;
512 this->TimeStepRange[1] = 0;
513 this->DeformedMesh = 1;
514 this->RemoveDeletedCells = 1;
515 this->DeletedCellsAsGhostArray = 0;
516 this->InputDeck = nullptr;
517 this->Parts = nullptr;
518 }
519
~vtkLSDynaReader()520 vtkLSDynaReader::~vtkLSDynaReader()
521 {
522 this->ResetPartsCache();
523 this->SetInputDeck(nullptr);
524 delete this->P;
525 this->P = nullptr;
526 }
527
PrintSelf(ostream & os,vtkIndent indent)528 void vtkLSDynaReader::PrintSelf( ostream &os, vtkIndent indent )
529 {
530 this->Superclass::PrintSelf( os, indent );
531
532 os << indent << "Title: \"" << this->GetTitle() << "\"" << endl;
533 os << indent << "InputDeck: " << (this->InputDeck ? this->InputDeck : "(null)") << endl;
534 os << indent << "DeformedMesh: " << (this->DeformedMesh ? "On" : "Off") << endl;
535 os << indent << "RemoveDeletedCells: " << (this->RemoveDeletedCells ? "On" : "Off") << endl;
536 os << indent << "TimeStepRange: " << this->TimeStepRange[0] << ", " << this->TimeStepRange[1] << endl;
537
538 if (this->P)
539 {
540 os << indent << "PrivateData: " << this->P << endl;
541 }
542 else
543 {
544 os << indent << "PrivateData: (none)" << endl;
545 }
546 os << indent << "Show Deleted Cells as Ghost Cells: "<<
547 (this->DeletedCellsAsGhostArray ? "On" : "Off") << endl;
548
549 os << indent << "Dimensionality: " << this->GetDimensionality() << endl;
550 os << indent << "Nodes: " << this->GetNumberOfNodes() << endl;
551 os << indent << "Cells: " << this->GetNumberOfCells() << endl;
552
553 os << indent << "PointArrays: ";
554 for ( int i=0; i<this->GetNumberOfPointArrays(); ++i )
555 {
556 os << this->GetPointArrayName( i ) << " ";
557 }
558 os << endl;
559
560 os << "CellArrays: " << endl;
561 for ( int ct = 0; ct < LSDynaMetaData::NUM_CELL_TYPES; ++ct )
562 {
563 os << vtkLSDynaCellTypes[ct] << ":" << endl;
564 for ( int i = 0; i < this->GetNumberOfCellArrays( ct ); ++i )
565 {
566 os << this->GetCellArrayName( ct, i ) << " ";
567 }
568 os << endl;
569 }
570 os << endl;
571
572 os << indent << "Time Steps: " << this->GetNumberOfTimeSteps() << endl;
573 for ( int j=0; j<this->GetNumberOfTimeSteps(); ++j )
574 {
575 os.precision(5);
576 os.width(12);
577 os << this->GetTimeValue(j) ;
578 if ( (j+1) % 8 == 0 && j != this->GetNumberOfTimeSteps()-1 )
579 {
580 os << endl << indent;
581 }
582 else
583 {
584 os << " ";
585 }
586 }
587 os << endl;
588 }
589
Dump(ostream & os)590 void vtkLSDynaReader::Dump( ostream& os )
591 {
592 vtkIndent indent;
593 os << indent << "Title: \"" << this->GetTitle() << "\"" << endl
594 << indent << "DeformedMesh: " << (this->DeformedMesh ? "On" : "Off") << endl
595 << indent << "RemoveDeletedCells: " << (this->RemoveDeletedCells ? "On" : "Off") << endl
596 << indent << "TimeStepRange: " << this->TimeStepRange[0] << ", " << this->TimeStepRange[1] << endl
597 << indent << "PrivateData: " << this->P << endl
598 << indent << "Dimensionality: " << this->GetDimensionality() << endl
599 << indent << "Nodes: " << this->GetNumberOfNodes() << endl
600 << indent << "Cells: " << this->GetNumberOfCells() << endl
601 << indent << "PointArrays: ";
602 for ( int i=0; i<this->GetNumberOfPointArrays(); ++i )
603 {
604 os << this->GetPointArrayName( i ) << " ";
605 }
606 os << endl
607 << "CellArrays:" << endl;
608 for ( int ct = 0; ct < LSDynaMetaData::NUM_CELL_TYPES; ++ct )
609 {
610 os << vtkLSDynaCellTypes[ct] << ":" << endl;
611 for ( int i = 0; i < this->GetNumberOfCellArrays( ct ); ++i )
612 {
613 os << this->GetCellArrayName( ct, i ) << " ";
614 }
615 os << endl;
616 }
617 os << endl;
618
619 os << indent << "Time Steps: " << this->GetNumberOfTimeSteps() << endl;
620 for ( int j=0; j<this->GetNumberOfTimeSteps(); ++j )
621 {
622 os.precision(5);
623 os.width(12);
624 os << this->GetTimeValue(j) ;
625 if ( (j+1) % 8 == 0 && j != this->GetNumberOfTimeSteps()-1 )
626 {
627 os << endl << indent;
628 }
629 else
630 {
631 os << " ";
632 }
633 }
634 os << endl;
635 }
636
DebugDump()637 void vtkLSDynaReader::DebugDump()
638 {
639 this->Dump( cout );
640 }
641
CanReadFile(const char * fname)642 int vtkLSDynaReader::CanReadFile( const char* fname )
643 {
644 if ( ! fname )
645 return 0;
646
647 std::string dbDir = vtksys::SystemTools::GetFilenamePath( fname );
648 std::string dbName = vtksys::SystemTools::GetFilenameName( fname );
649 std::string dbExt;
650 std::string::size_type dot;
651 LSDynaMetaData* p = new LSDynaMetaData;
652 int result = 0;
653
654 // GetFilenameExtension doesn't look for the rightmost "." ... do it ourselves.
655 dot = dbName.rfind( '.' );
656 if ( dot != std::string::npos )
657 {
658 dbExt = dbName.substr( dot );
659 }
660 else
661 {
662 dbExt = "";
663 }
664
665 p->Fam.SetDatabaseDirectory( dbDir );
666
667 if ( dbExt == ".k" || dbExt == ".lsdyna" )
668 {
669 p->Fam.SetDatabaseBaseName( "/d3plot" );
670 }
671 else
672 {
673 vtksys::SystemTools::Stat_t st;
674 if ( vtksys::SystemTools::Stat( fname, &st ) == 0 )
675 {
676 dbName.insert( 0, "/" );
677 p->Fam.SetDatabaseBaseName( dbName );
678 }
679 else
680 {
681 p->Fam.SetDatabaseBaseName( "/d3plot" );
682 }
683 }
684 // If the time step is set before RequestInformation is called, we must
685 // read the header information immediately in order to determine whether
686 // the timestep that's been passed is valid. If it's not, we ignore it.
687 if ( ! p->FileIsValid )
688 {
689 if ( p->Fam.GetDatabaseDirectory().empty() )
690 {
691 result = -1;
692 }
693 else
694 {
695 if ( p->Fam.GetDatabaseBaseName().empty() )
696 {
697 p->Fam.SetDatabaseBaseName( "/d3plot" ); // not a bad assumption.
698 }
699 p->Fam.ScanDatabaseDirectory();
700 if ( p->Fam.GetNumberOfFiles() < 1 )
701 {
702 result = -1;
703 }
704 else
705 {
706 if ( p->Fam.DetermineStorageModel() != 0 )
707 result = 0;
708 else
709 result = 1;
710 }
711 }
712 }
713 delete p;
714
715 return result > 0; // -1 and 0 are both problems, 1 indicates success.
716 }
717
SetDatabaseDirectory(const char * f)718 void vtkLSDynaReader::SetDatabaseDirectory( const char* f )
719 {
720 vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting DatabaseDirectory to " << f );
721 if ( ! f )
722 {
723 if ( ! this->P->Fam.GetDatabaseDirectory().empty() )
724 { // no string => no database directory
725 this->P->Reset();
726 this->SetInputDeck( nullptr );
727 this->ResetPartsCache();
728 this->Modified();
729 }
730 return;
731 }
732 if ( strcmp(this->P->Fam.GetDatabaseDirectory().c_str(), f) )
733 {
734 this->P->Reset();
735 this->SetInputDeck( nullptr );
736 this->P->Fam.SetDatabaseDirectory( std::string(f) );
737 this->ResetPartsCache();
738 this->Modified();
739 }
740 }
741
GetDatabaseDirectory()742 const char* vtkLSDynaReader::GetDatabaseDirectory()
743 {
744 return this->P->Fam.GetDatabaseDirectory().c_str();
745 }
746
IsDatabaseValid()747 int vtkLSDynaReader::IsDatabaseValid()
748 {
749 return this->P->FileIsValid;
750 }
751
SetFileName(const char * f)752 void vtkLSDynaReader::SetFileName( const char* f )
753 {
754 std::string dbDir = vtksys::SystemTools::GetFilenamePath( f );
755 std::string dbName = vtksys::SystemTools::GetFilenameName( f );
756 std::string dbExt;
757 std::string::size_type dot;
758
759 // GetFilenameExtension doesn't look for the rightmost "." ... do it ourselves.
760 dot = dbName.rfind( '.' );
761 if ( dot != std::string::npos )
762 {
763 dbExt = dbName.substr( dot );
764 }
765 else
766 {
767 dbExt = "";
768 }
769
770 this->SetDatabaseDirectory( dbDir.c_str() );
771
772 if ( dbExt == ".k" || dbExt == ".lsdyna" )
773 {
774 this->SetInputDeck( f );
775 this->P->Fam.SetDatabaseBaseName( "/d3plot" );
776 }
777 else
778 {
779 vtksys::SystemTools::Stat_t st;
780 if ( vtksys::SystemTools::Stat( f, &st ) == 0 )
781 {
782 dbName.insert( 0, "/" );
783 this->P->Fam.SetDatabaseBaseName( dbName );
784 }
785 else
786 {
787 this->P->Fam.SetDatabaseBaseName( "/d3plot" );
788 }
789 }
790 }
791
GetFileName()792 const char* vtkLSDynaReader::GetFileName()
793 {
794 // This is completely thread UNsafe. But what to do?
795 static std::string filenameSurrogate;
796 filenameSurrogate = this->P->Fam.GetDatabaseDirectory() + "/d3plot";
797 return filenameSurrogate.c_str();
798 }
799
GetTitle()800 char* vtkLSDynaReader::GetTitle()
801 {
802 return this->P->Title;
803 }
804
GetDimensionality()805 int vtkLSDynaReader::GetDimensionality()
806 {
807 return this->P->Dimensionality;
808 }
809
SetTimeStep(vtkIdType t)810 void vtkLSDynaReader::SetTimeStep( vtkIdType t )
811 {
812 LSDynaMetaData* p = this->P;
813 if ( p->CurrentState == t )
814 {
815 return;
816 }
817
818 // If the time step is set before RequestInformation is called, we must
819 // read the header information immediately in order to determine whether
820 // the timestep that's been passed is valid. If it's not, we ignore it.
821 if ( ! p->FileIsValid )
822 {
823 if ( p->Fam.GetDatabaseDirectory().empty() )
824 {
825 vtkErrorMacro( "You haven't set the LS-Dyna database directory!" );
826 return;
827 }
828
829 p->Fam.SetDatabaseBaseName( "/d3plot" ); // force this for now.
830 p->Fam.ScanDatabaseDirectory();
831 if ( p->Fam.GetNumberOfFiles() < 1 )
832 {
833 p->FileIsValid = 0;
834 return;
835 }
836 p->Fam.DetermineStorageModel();
837 p->MaxFileLength = p->FileSizeFactor*512*512*p->Fam.GetWordSize();
838 p->FileIsValid = 1;
839
840 // OK, now we have a list of files. Next, determine the length of the
841 // state vector (#bytes of data stored per time step):
842 this->ReadHeaderInformation( 0 );
843
844 // Finally, we can loop through and determine where all the state
845 // vectors start for each time step.
846 this->ScanDatabaseTimeSteps();
847 }
848
849 // Now, make sure we update the dictionary to contain information
850 // relevant to the adaptation level that matches the requested timestep.
851 if ( t >= 0 && t < (int) p->TimeValues.size() )
852 {
853 if ( p->Fam.GetCurrentAdaptLevel() != p->Fam.TimeAdaptLevel( t ) )
854 {
855 if ( this->ReadHeaderInformation( p->Fam.TimeAdaptLevel( t ) ) == 0 )
856 {
857 // unable to read the header information for the adaptation level corresponding
858 // to the requested time step
859 return;
860 }
861 }
862 }
863
864 p->CurrentState = t;
865 this->Modified();
866 }
867
GetTimeStep()868 vtkIdType vtkLSDynaReader::GetTimeStep()
869 {
870 return this->P->CurrentState;
871 }
872
GetNumberOfTimeSteps()873 vtkIdType vtkLSDynaReader::GetNumberOfTimeSteps()
874 {
875 return (vtkIdType) this->P->TimeValues.size();
876 }
877
GetTimeValue(vtkIdType s)878 double vtkLSDynaReader::GetTimeValue( vtkIdType s )
879 {
880 if ( s < 0 || s >= (vtkIdType) this->P->TimeValues.size() )
881 {
882 return -1.0;
883 }
884
885 return this->P->TimeValues[s];
886 }
887
GetNumberOfNodes()888 vtkIdType vtkLSDynaReader::GetNumberOfNodes()
889 {
890 return this->P->NumberOfNodes;
891 }
892
GetNumberOfCells()893 vtkIdType vtkLSDynaReader::GetNumberOfCells()
894 {
895 vtkIdType tmp=0;
896 for ( int c=0; c<LSDynaMetaData::NUM_CELL_TYPES; ++c )
897 {
898 tmp += this->P->NumberOfCells[c];
899 }
900 return tmp;
901 }
902
GetNumberOfSolidCells()903 vtkIdType vtkLSDynaReader::GetNumberOfSolidCells()
904 {
905 return this->P->NumberOfCells[LSDynaMetaData::SOLID];
906 }
907
GetNumberOfThickShellCells()908 vtkIdType vtkLSDynaReader::GetNumberOfThickShellCells()
909 {
910 return this->P->NumberOfCells[LSDynaMetaData::THICK_SHELL];
911 }
912
GetNumberOfShellCells()913 vtkIdType vtkLSDynaReader::GetNumberOfShellCells()
914 {
915 return this->P->NumberOfCells[LSDynaMetaData::SHELL];
916 }
917
GetNumberOfRigidBodyCells()918 vtkIdType vtkLSDynaReader::GetNumberOfRigidBodyCells()
919 {
920 return this->P->NumberOfCells[LSDynaMetaData::RIGID_BODY];
921 }
922
GetNumberOfRoadSurfaceCells()923 vtkIdType vtkLSDynaReader::GetNumberOfRoadSurfaceCells()
924 {
925 return this->P->NumberOfCells[LSDynaMetaData::ROAD_SURFACE];
926 }
927
GetNumberOfBeamCells()928 vtkIdType vtkLSDynaReader::GetNumberOfBeamCells()
929 {
930 return this->P->NumberOfCells[LSDynaMetaData::BEAM];
931 }
932
GetNumberOfParticleCells()933 vtkIdType vtkLSDynaReader::GetNumberOfParticleCells()
934 {
935 return this->P->NumberOfCells[LSDynaMetaData::PARTICLE];
936 }
937
GetNumberOfContinuumCells()938 vtkIdType vtkLSDynaReader::GetNumberOfContinuumCells()
939 {
940 vtkIdType tmp=0;
941 for ( int c=LSDynaMetaData::PARTICLE+1; c<LSDynaMetaData::NUM_CELL_TYPES; ++c )
942 {
943 tmp += this->P->NumberOfCells[c];
944 }
945 return tmp;
946 }
947
948 // =================================== Point array queries
GetNumberOfPointArrays()949 int vtkLSDynaReader::GetNumberOfPointArrays()
950 {
951 return (int) this->P->PointArrayNames.size();
952 }
953
GetPointArrayName(int a)954 const char* vtkLSDynaReader::GetPointArrayName( int a )
955 {
956 if ( a < 0 || a >= (int) this->P->PointArrayNames.size() )
957 return nullptr;
958
959 return this->P->PointArrayNames[a].c_str();
960 }
961
GetPointArrayStatus(int a)962 int vtkLSDynaReader::GetPointArrayStatus( int a )
963 {
964 if ( a < 0 || a >= (int) this->P->PointArrayStatus.size() )
965 return 0;
966
967 return this->P->PointArrayStatus[a];
968 }
969
SetPointArrayStatus(int a,int stat)970 void vtkLSDynaReader::SetPointArrayStatus( int a, int stat )
971 {
972 if ( a < 0 || a >= (int) this->P->PointArrayStatus.size() )
973 {
974 vtkWarningMacro( "Cannot set status of non-existent point array " << a );
975 return;
976 }
977
978 if ( stat == this->P->PointArrayStatus[a] )
979 return;
980
981 this->P->PointArrayStatus[a] = stat;
982 this->ResetPartsCache();
983 this->Modified();
984 }
985
GetNumberOfComponentsInPointArray(int a)986 int vtkLSDynaReader::GetNumberOfComponentsInPointArray( int a )
987 {
988 if ( a < 0 || a >= (int) this->P->PointArrayStatus.size() )
989 return 0;
990
991 return this->P->PointArrayComponents[a];
992 }
993
994 // =================================== Cell array queries
GetNumberOfCellArrays(int ct)995 int vtkLSDynaReader::GetNumberOfCellArrays( int ct )
996 {
997 return (int) this->P->CellArrayNames[ct].size();
998 }
999
GetCellArrayName(int ct,int a)1000 const char* vtkLSDynaReader::GetCellArrayName( int ct, int a )
1001 {
1002 if ( a < 0 || a >= (int) this->P->CellArrayNames[ct].size() )
1003 return nullptr;
1004
1005 return this->P->CellArrayNames[ct][a].c_str();
1006 }
1007
GetCellArrayStatus(int ct,int a)1008 int vtkLSDynaReader::GetCellArrayStatus( int ct, int a )
1009 {
1010 if ( a < 0 || a >= (int) this->P->CellArrayStatus[ct].size() )
1011 return 0;
1012
1013 return this->P->CellArrayStatus[ct][a];
1014 }
1015
GetNumberOfComponentsInCellArray(int ct,int a)1016 int vtkLSDynaReader::GetNumberOfComponentsInCellArray( int ct, int a )
1017 {
1018 if ( a < 0 || a >= (int) this->P->CellArrayStatus[ct].size() )
1019 return 0;
1020
1021 return this->P->CellArrayComponents[ct][a];
1022 }
1023
SetCellArrayStatus(int ct,int a,int stat)1024 void vtkLSDynaReader::SetCellArrayStatus( int ct, int a, int stat )
1025 {
1026 if ( a < 0 || a >= (int) this->P->CellArrayStatus[ct].size() )
1027 {
1028 vtkWarningMacro( "Cannot set status of non-existent point array " << a );
1029 return;
1030 }
1031
1032 if ( stat == this->P->CellArrayStatus[ct][a] )
1033 return;
1034
1035 this->P->CellArrayStatus[ct][a] = stat;
1036 this->ResetPartsCache();
1037 this->Modified();
1038 }
1039
1040 // =================================== Cell array queries
GetNumberOfSolidArrays()1041 int vtkLSDynaReader::GetNumberOfSolidArrays()
1042 {
1043 return (int) this->P->CellArrayNames[LSDynaMetaData::SOLID].size();
1044 }
1045
GetSolidArrayName(int a)1046 const char* vtkLSDynaReader::GetSolidArrayName( int a )
1047 {
1048 if ( a < 0 || a >= (int) this->P->CellArrayNames[LSDynaMetaData::SOLID].size() )
1049 return nullptr;
1050
1051 return this->P->CellArrayNames[LSDynaMetaData::SOLID][a].c_str();
1052 }
1053
GetSolidArrayStatus(int a)1054 int vtkLSDynaReader::GetSolidArrayStatus( int a )
1055 {
1056 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::SOLID].size() )
1057 return 0;
1058
1059 return this->P->CellArrayStatus[LSDynaMetaData::SOLID][a];
1060 }
1061
GetNumberOfComponentsInSolidArray(int a)1062 int vtkLSDynaReader::GetNumberOfComponentsInSolidArray( int a )
1063 {
1064 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::SOLID].size() )
1065 return 0;
1066
1067 return this->P->CellArrayComponents[LSDynaMetaData::SOLID][a];
1068 }
1069
SetSolidArrayStatus(int a,int stat)1070 void vtkLSDynaReader::SetSolidArrayStatus( int a, int stat )
1071 {
1072 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::SOLID].size() )
1073 {
1074 vtkWarningMacro( "Cannot set status of non-existent point array " << a );
1075 return;
1076 }
1077
1078 if ( stat == this->P->CellArrayStatus[LSDynaMetaData::SOLID][a] )
1079 return;
1080
1081 this->P->CellArrayStatus[LSDynaMetaData::SOLID][a] = stat;
1082 this->ResetPartsCache();
1083 this->Modified();
1084 }
1085
1086 // =================================== Cell array queries
GetNumberOfThickShellArrays()1087 int vtkLSDynaReader::GetNumberOfThickShellArrays()
1088 {
1089 return (int) this->P->CellArrayNames[LSDynaMetaData::THICK_SHELL].size();
1090 }
1091
GetThickShellArrayName(int a)1092 const char* vtkLSDynaReader::GetThickShellArrayName( int a )
1093 {
1094 if ( a < 0 || a >= (int) this->P->CellArrayNames[LSDynaMetaData::THICK_SHELL].size() )
1095 return nullptr;
1096
1097 return this->P->CellArrayNames[LSDynaMetaData::THICK_SHELL][a].c_str();
1098 }
1099
GetThickShellArrayStatus(int a)1100 int vtkLSDynaReader::GetThickShellArrayStatus( int a )
1101 {
1102 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::THICK_SHELL].size() )
1103 return 0;
1104
1105 return this->P->CellArrayStatus[LSDynaMetaData::THICK_SHELL][a];
1106 }
1107
GetNumberOfComponentsInThickShellArray(int a)1108 int vtkLSDynaReader::GetNumberOfComponentsInThickShellArray( int a )
1109 {
1110 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::THICK_SHELL].size() )
1111 return 0;
1112
1113 return this->P->CellArrayComponents[LSDynaMetaData::THICK_SHELL][a];
1114 }
1115
SetThickShellArrayStatus(int a,int stat)1116 void vtkLSDynaReader::SetThickShellArrayStatus( int a, int stat )
1117 {
1118 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::THICK_SHELL].size() )
1119 {
1120 vtkWarningMacro( "Cannot set status of non-existent point array " << a );
1121 return;
1122 }
1123
1124 if ( stat == this->P->CellArrayStatus[LSDynaMetaData::THICK_SHELL][a] )
1125 return;
1126
1127 this->P->CellArrayStatus[LSDynaMetaData::THICK_SHELL][a] = stat;
1128 this->ResetPartsCache();
1129 this->Modified();
1130 }
1131
1132 // =================================== Cell array queries
GetNumberOfShellArrays()1133 int vtkLSDynaReader::GetNumberOfShellArrays()
1134 {
1135 return (int) this->P->CellArrayNames[LSDynaMetaData::SHELL].size();
1136 }
1137
GetShellArrayName(int a)1138 const char* vtkLSDynaReader::GetShellArrayName( int a )
1139 {
1140 if ( a < 0 || a >= (int) this->P->CellArrayNames[LSDynaMetaData::SHELL].size() )
1141 return nullptr;
1142
1143 return this->P->CellArrayNames[LSDynaMetaData::SHELL][a].c_str();
1144 }
1145
GetShellArrayStatus(int a)1146 int vtkLSDynaReader::GetShellArrayStatus( int a )
1147 {
1148 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::SHELL].size() )
1149 return 0;
1150
1151 return this->P->CellArrayStatus[LSDynaMetaData::SHELL][a];
1152 }
1153
GetNumberOfComponentsInShellArray(int a)1154 int vtkLSDynaReader::GetNumberOfComponentsInShellArray( int a )
1155 {
1156 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::SHELL].size() )
1157 return 0;
1158
1159 return this->P->CellArrayComponents[LSDynaMetaData::SHELL][a];
1160 }
1161
SetShellArrayStatus(int a,int stat)1162 void vtkLSDynaReader::SetShellArrayStatus( int a, int stat )
1163 {
1164 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::SHELL].size() )
1165 {
1166 vtkWarningMacro( "Cannot set status of non-existent point array " << a );
1167 return;
1168 }
1169
1170 if ( stat == this->P->CellArrayStatus[LSDynaMetaData::SHELL][a] )
1171 return;
1172
1173 this->P->CellArrayStatus[LSDynaMetaData::SHELL][a] = stat;
1174 this->ResetPartsCache();
1175 this->Modified();
1176 }
1177
1178 // =================================== Cell array queries
GetNumberOfRigidBodyArrays()1179 int vtkLSDynaReader::GetNumberOfRigidBodyArrays()
1180 {
1181 return (int) this->P->CellArrayNames[LSDynaMetaData::RIGID_BODY].size();
1182 }
1183
GetRigidBodyArrayName(int a)1184 const char* vtkLSDynaReader::GetRigidBodyArrayName( int a )
1185 {
1186 if ( a < 0 || a >= (int) this->P->CellArrayNames[LSDynaMetaData::RIGID_BODY].size() )
1187 return nullptr;
1188
1189 return this->P->CellArrayNames[LSDynaMetaData::RIGID_BODY][a].c_str();
1190 }
1191
GetRigidBodyArrayStatus(int a)1192 int vtkLSDynaReader::GetRigidBodyArrayStatus( int a )
1193 {
1194 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::RIGID_BODY].size() )
1195 return 0;
1196
1197 return this->P->CellArrayStatus[LSDynaMetaData::RIGID_BODY][a];
1198 }
1199
GetNumberOfComponentsInRigidBodyArray(int a)1200 int vtkLSDynaReader::GetNumberOfComponentsInRigidBodyArray( int a )
1201 {
1202 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::RIGID_BODY].size() )
1203 return 0;
1204
1205 return this->P->CellArrayComponents[LSDynaMetaData::RIGID_BODY][a];
1206 }
1207
SetRigidBodyArrayStatus(int a,int stat)1208 void vtkLSDynaReader::SetRigidBodyArrayStatus( int a, int stat )
1209 {
1210 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::RIGID_BODY].size() )
1211 {
1212 vtkWarningMacro( "Cannot set status of non-existent point array " << a );
1213 return;
1214 }
1215
1216 if ( stat == this->P->CellArrayStatus[LSDynaMetaData::RIGID_BODY][a] )
1217 return;
1218
1219 this->P->CellArrayStatus[LSDynaMetaData::RIGID_BODY][a] = stat;
1220 this->ResetPartsCache();
1221 this->Modified();
1222 }
1223
1224 // =================================== Cell array queries
GetNumberOfRoadSurfaceArrays()1225 int vtkLSDynaReader::GetNumberOfRoadSurfaceArrays()
1226 {
1227 return (int) this->P->CellArrayNames[LSDynaMetaData::ROAD_SURFACE].size();
1228 }
1229
GetRoadSurfaceArrayName(int a)1230 const char* vtkLSDynaReader::GetRoadSurfaceArrayName( int a )
1231 {
1232 if ( a < 0 || a >= (int) this->P->CellArrayNames[LSDynaMetaData::ROAD_SURFACE].size() )
1233 return nullptr;
1234
1235 return this->P->CellArrayNames[LSDynaMetaData::ROAD_SURFACE][a].c_str();
1236 }
1237
GetRoadSurfaceArrayStatus(int a)1238 int vtkLSDynaReader::GetRoadSurfaceArrayStatus( int a )
1239 {
1240 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::ROAD_SURFACE].size() )
1241 return 0;
1242
1243 return this->P->CellArrayStatus[LSDynaMetaData::ROAD_SURFACE][a];
1244 }
1245
GetNumberOfComponentsInRoadSurfaceArray(int a)1246 int vtkLSDynaReader::GetNumberOfComponentsInRoadSurfaceArray( int a )
1247 {
1248 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::ROAD_SURFACE].size() )
1249 return 0;
1250
1251 return this->P->CellArrayComponents[LSDynaMetaData::ROAD_SURFACE][a];
1252 }
1253
SetRoadSurfaceArrayStatus(int a,int stat)1254 void vtkLSDynaReader::SetRoadSurfaceArrayStatus( int a, int stat )
1255 {
1256 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::ROAD_SURFACE].size() )
1257 {
1258 vtkWarningMacro( "Cannot set status of non-existent point array " << a );
1259 return;
1260 }
1261
1262 if ( stat == this->P->CellArrayStatus[LSDynaMetaData::ROAD_SURFACE][a] )
1263 return;
1264
1265 this->P->CellArrayStatus[LSDynaMetaData::ROAD_SURFACE][a] = stat;
1266 this->ResetPartsCache();
1267 this->Modified();
1268 }
1269
1270 // =================================== Cell array queries
GetNumberOfBeamArrays()1271 int vtkLSDynaReader::GetNumberOfBeamArrays()
1272 {
1273 return (int) this->P->CellArrayNames[LSDynaMetaData::BEAM].size();
1274 }
1275
GetBeamArrayName(int a)1276 const char* vtkLSDynaReader::GetBeamArrayName( int a )
1277 {
1278 if ( a < 0 || a >= (int) this->P->CellArrayNames[LSDynaMetaData::BEAM].size() )
1279 return nullptr;
1280
1281 return this->P->CellArrayNames[LSDynaMetaData::BEAM][a].c_str();
1282 }
1283
GetBeamArrayStatus(int a)1284 int vtkLSDynaReader::GetBeamArrayStatus( int a )
1285 {
1286 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::BEAM].size() )
1287 return 0;
1288
1289 return this->P->CellArrayStatus[LSDynaMetaData::BEAM][a];
1290 }
1291
GetNumberOfComponentsInBeamArray(int a)1292 int vtkLSDynaReader::GetNumberOfComponentsInBeamArray( int a )
1293 {
1294 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::BEAM].size() )
1295 return 0;
1296
1297 return this->P->CellArrayComponents[LSDynaMetaData::BEAM][a];
1298 }
1299
SetBeamArrayStatus(int a,int stat)1300 void vtkLSDynaReader::SetBeamArrayStatus( int a, int stat )
1301 {
1302 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::BEAM].size() )
1303 {
1304 vtkWarningMacro( "Cannot set status of non-existent point array " << a );
1305 return;
1306 }
1307
1308 if ( stat == this->P->CellArrayStatus[LSDynaMetaData::BEAM][a] )
1309 return;
1310
1311 this->P->CellArrayStatus[LSDynaMetaData::BEAM][a] = stat;
1312 this->ResetPartsCache();
1313 this->Modified();
1314 }
1315
1316 // =================================== Cell array queries
GetNumberOfParticleArrays()1317 int vtkLSDynaReader::GetNumberOfParticleArrays()
1318 {
1319 return (int) this->P->CellArrayNames[LSDynaMetaData::PARTICLE].size();
1320 }
1321
GetParticleArrayName(int a)1322 const char* vtkLSDynaReader::GetParticleArrayName( int a )
1323 {
1324 if ( a < 0 || a >= (int) this->P->CellArrayNames[LSDynaMetaData::PARTICLE].size() )
1325 return nullptr;
1326
1327 return this->P->CellArrayNames[LSDynaMetaData::PARTICLE][a].c_str();
1328 }
1329
GetParticleArrayStatus(int a)1330 int vtkLSDynaReader::GetParticleArrayStatus( int a )
1331 {
1332 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::PARTICLE].size() )
1333 return 0;
1334
1335 return this->P->CellArrayStatus[LSDynaMetaData::PARTICLE][a];
1336 }
1337
GetNumberOfComponentsInParticleArray(int a)1338 int vtkLSDynaReader::GetNumberOfComponentsInParticleArray( int a )
1339 {
1340 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::PARTICLE].size() )
1341 return 0;
1342
1343 return this->P->CellArrayComponents[LSDynaMetaData::PARTICLE][a];
1344 }
1345
SetParticleArrayStatus(int a,int stat)1346 void vtkLSDynaReader::SetParticleArrayStatus( int a, int stat )
1347 {
1348 if ( a < 0 || a >= (int) this->P->CellArrayStatus[LSDynaMetaData::PARTICLE].size() )
1349 {
1350 vtkWarningMacro( "Cannot set status of non-existent point array " << a );
1351 return;
1352 }
1353
1354 if ( stat == this->P->CellArrayStatus[LSDynaMetaData::PARTICLE][a] )
1355 return;
1356
1357 this->P->CellArrayStatus[LSDynaMetaData::PARTICLE][a] = stat;
1358 this->ResetPartsCache();
1359 this->Modified();
1360 }
1361
1362 // =================================== Part queries
GetNumberOfPartArrays()1363 int vtkLSDynaReader::GetNumberOfPartArrays()
1364 {
1365 return (int) this->P->PartNames.size();
1366 }
1367
GetPartArrayName(int a)1368 const char* vtkLSDynaReader::GetPartArrayName( int a )
1369 {
1370 if ( a < 0 || a >= (int) this->P->PartNames.size() )
1371 return nullptr;
1372
1373 return this->P->PartNames[a].c_str();
1374 }
1375
GetPartArrayStatus(int a)1376 int vtkLSDynaReader::GetPartArrayStatus( int a )
1377 {
1378 if ( a < 0 || a >= (int) this->P->PartStatus.size() )
1379 return 0;
1380
1381 return this->P->PartStatus[a];
1382 }
1383
SetPartArrayStatus(int a,int stat)1384 void vtkLSDynaReader::SetPartArrayStatus( int a, int stat )
1385 {
1386 if ( a < 0 || a >= (int) this->P->PartStatus.size() )
1387 {
1388 vtkWarningMacro( "Cannot set status of non-existent point array " << a );
1389 return;
1390 }
1391
1392 if ( stat == this->P->PartStatus[a] )
1393 return;
1394
1395 this->P->PartStatus[a] = stat;
1396 this->ResetPartsCache();
1397 this->Modified();
1398 }
1399
1400 // ===================================
ResetPartsCache()1401 void vtkLSDynaReader::ResetPartsCache()
1402 {
1403 if(this->Parts)
1404 {
1405 this->Parts->Delete();
1406 this->Parts=nullptr;
1407 }
1408 }
1409
1410 // =================================== Read the control word header for the current adaptation level
ReadHeaderInformation(int curAdapt)1411 int vtkLSDynaReader::ReadHeaderInformation( int curAdapt )
1412 {
1413 LSDynaMetaData* p = this->P;
1414
1415 // =================================== Control Word Section
1416 p->Fam.SkipToWord( LSDynaFamily::ControlSection, curAdapt /*timestep*/, 0 );
1417 p->Fam.BufferChunk( LSDynaFamily::Char, 10 );
1418 memcpy( p->Title, p->Fam.GetNextWordAsChars(), 40*sizeof(char) );
1419 p->Title[40] = '\0';
1420
1421 p->Fam.SkipToWord( LSDynaFamily::ControlSection, curAdapt /*timestep*/, 13 );
1422
1423 // Release number: Release number in character*4 form: 50 for R5.0, 511c for R5.1.1c.
1424 p->Fam.BufferChunk( LSDynaFamily::Char, 1 );
1425 memcpy( p->ReleaseNumber, p->Fam.GetNextWordAsChars(), 4*sizeof(char));
1426 p->ReleaseNumber[4] = '\0';
1427
1428 // Version: Code version, floating number, eg 960.0 it is used to distinguish the
1429 // floating point format, like cray, ieee, and dpieee.
1430 p->Fam.BufferChunk( LSDynaFamily::Float, 1 );
1431 p->CodeVersion = p->Fam.GetNextWordAsFloat();
1432
1433 p->Fam.BufferChunk( LSDynaFamily::Int, 49 );
1434 p->Dict[ "NDIM"] = p->Fam.GetNextWordAsInt();
1435 p->Dict[ "NUMNP"] = p->Fam.GetNextWordAsInt();
1436 p->Dict[ "ICODE"] = p->Fam.GetNextWordAsInt();
1437 p->Dict[ "NGLBV"] = p->Fam.GetNextWordAsInt();
1438 p->Dict[ "IT"] = p->Fam.GetNextWordAsInt();
1439 p->Dict[ "IU"] = p->Fam.GetNextWordAsInt();
1440 p->Dict[ "IV"] = p->Fam.GetNextWordAsInt();
1441 p->Dict[ "IA"] = p->Fam.GetNextWordAsInt();
1442 p->Dict[ "NEL8"] = p->Fam.GetNextWordAsInt();
1443 p->Dict[ "NUMMAT8"] = p->Fam.GetNextWordAsInt();
1444 p->Fam.GetNextWordAsInt(); // BLANK
1445 p->Fam.GetNextWordAsInt(); // BLANK
1446 p->Dict[ "NV3D"] = p->Fam.GetNextWordAsInt();
1447 p->Dict[ "NEL2"] = p->Fam.GetNextWordAsInt();
1448 p->Dict[ "NUMMAT2"] = p->Fam.GetNextWordAsInt();
1449 p->Dict[ "NV1D"] = p->Fam.GetNextWordAsInt();
1450 p->Dict[ "NEL4"] = p->Fam.GetNextWordAsInt();
1451 p->Dict[ "NUMMAT4"] = p->Fam.GetNextWordAsInt();
1452 p->Dict[ "NV2D"] = p->Fam.GetNextWordAsInt();
1453 p->Dict[ "NEIPH"] = p->Fam.GetNextWordAsInt();
1454 p->Dict[ "NEIPS"] = p->Fam.GetNextWordAsInt();
1455 p->Dict[ "MAXINT"] = p->Fam.GetNextWordAsInt();
1456 // do MDLOPT here?
1457 p->Dict[ "NMSPH"] = p->Fam.GetNextWordAsInt();
1458 p->Dict[ "EDLOPT"] = p->Dict["NMSPH"]; // EDLOPT is not standard
1459 p->Dict[ "NGPSPH"] = p->Fam.GetNextWordAsInt();
1460 p->Dict[ "NARBS"] = p->Fam.GetNextWordAsInt();
1461 p->Dict[ "NELT"] = p->Fam.GetNextWordAsInt();
1462 p->Dict[ "NUMMATT"] = p->Fam.GetNextWordAsInt();
1463 p->Dict[ "NV3DT"] = p->Fam.GetNextWordAsInt();
1464 p->Dict["IOSHL(1)"] = p->Fam.GetNextWordAsInt() == 1000 ? 1 : 0;
1465 p->Dict["IOSHL(2)"] = p->Fam.GetNextWordAsInt() == 1000 ? 1 : 0;
1466 p->Dict["IOSHL(3)"] = p->Fam.GetNextWordAsInt() == 1000 ? 1 : 0;
1467 p->Dict["IOSHL(4)"] = p->Fam.GetNextWordAsInt() == 1000 ? 1 : 0;
1468 p->Dict[ "IALEMAT"] = p->Fam.GetNextWordAsInt();
1469 p->Dict[ "NCFDV1"] = p->Fam.GetNextWordAsInt();
1470 p->Dict[ "NCFDV2"] = p->Fam.GetNextWordAsInt();
1471 p->Dict[ "NADAPT"] = p->Fam.GetNextWordAsInt();
1472 p->Dict[ "NMMAT"] = p->Fam.GetNextWordAsInt();
1473
1474 // NUMFLUID: Total number of ALE fluid groups. Fluid density and
1475 // volume fractions output as history variables, and a flag
1476 // for the dominant group. If negative multi-material
1477 // species mass for each group is also output. Order is: rho,
1478 // vf1, ... vfn, dvf flag, m1, ... mn. Density is at position 8
1479 // after the location for plastic strain. Any element material
1480 // history variables are written before the Ale variables, and
1481 // the six element strains components after these if
1482 // ISTRN=1.
1483 p->Dict["NUMFLUID"] = p->Fam.GetNextWordAsInt();
1484
1485 // Compute the derived values in this->P
1486 // =========================================== Control Word Section Processing
1487 int itmp;
1488 vtkIdType iddtmp;
1489 char ctmp[128]; // temp space for generating keywords (i.e. isphfg) and attribute names (i.e., StressIntPt3)
1490
1491 // --- Initialize some values
1492 p->ReadRigidRoadMvmt = 0;
1493 p->PreStateSize = 64*p->Fam.GetWordSize();
1494 p->StateSize = p->Fam.GetWordSize(); // Account for "time word"
1495 p->Dimensionality = p->Dict["NDIM"];
1496 switch (p->Dimensionality)
1497 {
1498 case 2:
1499 case 3:
1500 p->Dict["MATTYP"] = 0;
1501 p->ConnectivityUnpacked = 0;
1502 break;
1503 case 7:
1504 p->ReadRigidRoadMvmt = 1;
1505 VTK_FALLTHROUGH;
1506 case 5:
1507 p->Dict["MATTYP"] = 1;
1508 p->ConnectivityUnpacked = 1;
1509 p->Dimensionality = 3;
1510 break;
1511 case 4:
1512 p->ConnectivityUnpacked = 1;
1513 p->Dict["MATTYP"] = 0;
1514 p->Dimensionality = 3;
1515 break;
1516 default:
1517 vtkErrorMacro("Unknown Dimensionality " << p->Dimensionality << " encountered" );
1518 p->FileIsValid = 0;
1519 return 0;
1520 }
1521
1522 // FIXME Are these marks valid since we are marking the word past the end of the chunk?
1523 p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::StaticSection );
1524 p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::MaterialTypeData );
1525 if ( p->Dict["MATTYP"] != 0 )
1526 {
1527 p->Fam.BufferChunk( LSDynaFamily::Int, 2 );
1528 p->Dict["NUMRBE"] = p->Fam.GetNextWordAsInt();
1529 p->Dict["NUMMAT"] = p->Fam.GetNextWordAsInt();
1530 }
1531 else
1532 {
1533 p->Dict["NUMRBE"] = 0;
1534 p->Dict["NUMMAT"] = 0;
1535 }
1536 p->NumberOfNodes = p->Dict["NUMNP"];
1537
1538 p->NumberOfCells[LSDynaMetaData::RIGID_BODY] = p->Dict["NUMRBE"];
1539 p->NumberOfCells[LSDynaMetaData::SOLID] = p->Dict["NEL8"];
1540 p->NumberOfCells[LSDynaMetaData::THICK_SHELL] = p->Dict["NELT"];
1541 p->NumberOfCells[LSDynaMetaData::SHELL] = p->Dict["NEL4"];
1542 p->NumberOfCells[LSDynaMetaData::BEAM] = p->Dict["NEL2"];
1543 p->NumberOfCells[LSDynaMetaData::PARTICLE] = p->Dict["NMSPH"];
1544
1545 p->StateSize += p->Dict["NGLBV"]*p->Fam.GetWordSize();
1546
1547 if ( p->Dict["IT"] != 0 )
1548 {
1549 p->AddPointArray( LS_ARRAYNAME_TEMPERATURE, 1, 1 );
1550 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1551 }
1552 if ( p->Dict["IU"] != 0 )
1553 {
1554 p->AddPointArray( LS_ARRAYNAME_DEFLECTION, p->Dimensionality, 1 );
1555 p->StateSize += p->NumberOfNodes * p->Dimensionality * p->Fam.GetWordSize();
1556 }
1557 if ( p->Dict["IV"] != 0 )
1558 {
1559 p->AddPointArray( LS_ARRAYNAME_VELOCITY, p->Dimensionality, 1 );
1560 p->StateSize += p->NumberOfNodes * p->Dimensionality * p->Fam.GetWordSize();
1561 }
1562 if ( p->Dict["IA"] != 0 )
1563 {
1564 p->AddPointArray( LS_ARRAYNAME_ACCELERATION, p->Dimensionality, 1 );
1565 p->StateSize += p->NumberOfNodes * p->Dimensionality * p->Fam.GetWordSize();
1566 }
1567 p->Dict["cfdPressure"] = 0;
1568 p->Dict["cfdVort"] = 0;
1569 p->Dict["cfdXVort"] = 0;
1570 p->Dict["cfdYVort"] = 0;
1571 p->Dict["cfdZVort"] = 0;
1572 p->Dict["cfdRVort"] = 0;
1573 p->Dict["cfdEnstrophy"] = 0;
1574 p->Dict["cfdHelicity"] = 0;
1575 p->Dict["cfdStream"] = 0;
1576 p->Dict["cfdEnthalpy"] = 0;
1577 p->Dict["cfdDensity"] = 0;
1578 p->Dict["cfdTurbKE"] = 0;
1579 p->Dict["cfdDiss"] = 0;
1580 p->Dict["cfdEddyVisc"] = 0;
1581 itmp = p->Dict["NCFDV1"];
1582 if ( itmp & 2 )
1583 {
1584 p->AddPointArray( LS_ARRAYNAME_PRESSURE, 1, 1 );
1585 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1586 p->Dict["cfdPressure"] = 1;
1587 }
1588 if ( (itmp & 28) == 28 )
1589 {
1590 p->AddPointArray( LS_ARRAYNAME_VORTICITY, 3, 1 );
1591 p->StateSize += p->NumberOfNodes * 3 * p->Fam.GetWordSize();
1592 p->Dict["cfdVort"] = 1;
1593 p->Dict["cfdXVort"] = 1;
1594 p->Dict["cfdYVort"] = 1;
1595 p->Dict["cfdZVort"] = 1;
1596 }
1597 else
1598 { // OK, we don't have all the vector components... maybe we have some of them?
1599 if ( itmp & 4 )
1600 {
1601 p->AddPointArray( LS_ARRAYNAME_VORTICITY "_X", 1, 1 );
1602 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1603 p->Dict["cfdXVort"] = 1;
1604 }
1605 if ( itmp & 8 )
1606 {
1607 p->AddPointArray( LS_ARRAYNAME_VORTICITY "_Y", 1, 1 );
1608 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1609 p->Dict["cfdYVort"] = 1;
1610 }
1611 if ( itmp & 16 )
1612 {
1613 p->AddPointArray( LS_ARRAYNAME_VORTICITY "_Z", 1, 1 );
1614 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1615 p->Dict["cfdZVort"] = 1;
1616 }
1617 }
1618 if ( itmp & 32 )
1619 {
1620 p->AddPointArray( LS_ARRAYNAME_RESULTANTVORTICITY, 1, 1 );
1621 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1622 p->Dict["cfdRVort"] = 1;
1623 if ( itmp & 64 )
1624 {
1625 p->AddPointArray( LS_ARRAYNAME_ENSTROPHY, 1, 1 );
1626 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1627 p->Dict["cfdEnstrophy"] = 1;
1628 }
1629 if ( itmp & 128 )
1630 {
1631 p->AddPointArray( LS_ARRAYNAME_HELICITY, 1, 1 );
1632 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1633 p->Dict["cfdHelicity"] = 1;
1634 }
1635 if ( itmp & 256 )
1636 {
1637 p->AddPointArray( LS_ARRAYNAME_STREAMFUNCTION, 1, 1 );
1638 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1639 p->Dict["cfdStream"] = 1;
1640 }
1641 if ( itmp & 512 )
1642 {
1643 p->AddPointArray( LS_ARRAYNAME_ENTHALPY, 1, 1 );
1644 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1645 p->Dict["cfdEnthalpy"] = 1;
1646 }
1647 if ( itmp & 1024 )
1648 {
1649 p->AddPointArray( LS_ARRAYNAME_DENSITY, 1, 1 );
1650 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1651 p->Dict["cfdDensity"] = 1;
1652 }
1653 if ( itmp & 2048 )
1654 {
1655 p->AddPointArray( LS_ARRAYNAME_TURBULENTKE, 1, 1 );
1656 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1657 p->Dict["cfdTurbKE"] = 1;
1658 }
1659 if ( itmp & 4096 )
1660 {
1661 p->AddPointArray( LS_ARRAYNAME_DISSIPATION, 1, 1 );
1662 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1663 p->Dict["cfdDiss"] = 1;
1664 }
1665 if ( itmp & 1040384 )
1666 {
1667 p->AddPointArray( LS_ARRAYNAME_EDDYVISCOSITY, 1, 1 );
1668 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1669 p->Dict["cfdEddyVisc"] = 1;
1670 }
1671 }
1672
1673 char sname[]=LS_ARRAYNAME_SPECIES_BLNK;
1674 iddtmp = p->Dict["NCFDV2"];
1675 for ( itmp=1; itmp<11; ++itmp )
1676 {
1677 if ( iddtmp & (static_cast<vtkIdType>(1)<<itmp) )
1678 {
1679 snprintf( sname, sizeof(sname), LS_ARRAYNAME_SPECIES_FMT, itmp );
1680 p->AddPointArray( sname, 1, 1 );
1681 p->StateSize += p->NumberOfNodes * p->Fam.GetWordSize();
1682 snprintf( sname, sizeof(sname), "cfdSpec%02d", itmp );
1683 p->Dict[ sname ] = 1;
1684 }
1685 else
1686 {
1687 snprintf( sname, sizeof(sname), "cfdSpec%02d", itmp );
1688 p->Dict[ sname ] = 0;
1689 }
1690 }
1691
1692 // Solid element state size FIXME: 7 + NEIPH should really be NV3D (in case things change)
1693 p->StateSize += (7+p->Dict["NEIPH"])*p->NumberOfCells[LSDynaMetaData::SOLID]*p->Fam.GetWordSize();
1694 // Thick shell state size
1695 p->StateSize += p->Dict["NV3DT"]*p->NumberOfCells[LSDynaMetaData::THICK_SHELL]*p->Fam.GetWordSize();
1696 // (Thin) shell state size (we remove rigid body shell element state below)
1697 p->StateSize += p->Dict["NV2D"]*p->NumberOfCells[LSDynaMetaData::SHELL]*p->Fam.GetWordSize();
1698 // Beam state size
1699 p->StateSize += p->Dict["NV1D"]*p->NumberOfCells[LSDynaMetaData::BEAM]*p->Fam.GetWordSize();
1700
1701 // ================================================ Static Information Section
1702 // This is marked above so we can read NUMRBE in time to do StateSize calculations
1703 // ================================================ Material Type Data Section
1704 // This is marked above so we can read NUMRBE in time to do StateSize calculations
1705 if ( p->Dict["MATTYP"] != 0 )
1706 {
1707 // If there are rigid body elements, they won't have state data and we must
1708 // reduce the state size
1709 p->StateSize -= p->Dict["NV2D"] * p->NumberOfCells[ LSDynaMetaData::RIGID_BODY ];
1710
1711 p->Fam.BufferChunk( LSDynaFamily::Int, p->Dict["NUMMAT"] );
1712 for ( itmp = 0; itmp < p->Dict["NUMMAT"]; ++itmp )
1713 {
1714 p->RigidMaterials.insert( p->Fam.GetNextWordAsInt() );
1715 }
1716 p->PreStateSize += (2 + p->Dict["NUMMAT"])*p->Fam.GetWordSize();
1717 }
1718
1719 //process the deletion array
1720 //save the position we currently have as it is the offset to jump to
1721 //when reading deletion
1722 p->ElementDeletionOffset = p->StateSize/p->Fam.GetWordSize();
1723
1724 int mdlopt;
1725 int intpts2;
1726 mdlopt = p->Dict["MAXINT"];
1727 if ( mdlopt >= 0 && mdlopt <= 10000)
1728 {
1729 intpts2 = mdlopt;
1730 mdlopt = LS_MDLOPT_NONE;
1731 }
1732 else if ( mdlopt < -10000 )
1733 {
1734 intpts2 = -mdlopt -10000;
1735 mdlopt = LS_MDLOPT_CELL;
1736
1737 // WARNING: This needs NumberOfCells[LSDynaMetaData::RIGID_BODY] set, which relies on NUMRBE
1738 p->StateSize += this->GetNumberOfContinuumCells() * p->Fam.GetWordSize();
1739 }
1740 else if ( mdlopt > 10000)
1741 {
1742 intpts2 = mdlopt -10000;
1743 mdlopt = LS_MDLOPT_CELL;
1744
1745 // WARNING: This needs NumberOfCells[LSDynaMetaData::RIGID_BODY] set, which relies on NUMRBE
1746 p->StateSize += this->GetNumberOfContinuumCells() * p->Fam.GetWordSize();
1747 }
1748 else
1749 {
1750 intpts2 = -mdlopt;
1751 mdlopt = LS_MDLOPT_POINT;
1752 //p->AddPointArray( LS_ARRAYNAME_DEATH, 1, 1 );
1753 p->StateSize += this->GetNumberOfNodes() * p->Fam.GetWordSize();
1754 }
1755 p->Dict["MDLOPT"] = mdlopt;
1756 p->Dict["_MAXINT_"] = intpts2;
1757 if ( p->Dict["NV2D"] > 0 )
1758 {
1759 if ( p->Dict["NV2D"]-(p->Dict["_MAXINT_"]*(6*p->Dict["IOSHL(1)"]+p->Dict["IOSHL(2)"]+p->Dict["NEIPS"])+8*p->Dict["IOSHL(3)"]+4*p->Dict["IOSHL(4)"]) > 1 )
1760 {
1761 p->Dict["ISTRN"] = 1;
1762 }
1763 else
1764 {
1765 p->Dict["ISTRN"] = 0;
1766 }
1767 }
1768 else if ( p->Dict["NELT"] > 0 )
1769 {
1770 if ( p->Dict["NV3D"] - p->Dict["_MAXINT_"]*(6*p->Dict["IOSHL(1)"]+p->Dict["IOSHL(2)"]+p->Dict["NEIPS"]) > 1 )
1771 {
1772 p->Dict["ISTRN"] = 1;
1773 }
1774 else
1775 {
1776 p->Dict["ISTRN"] = 0;
1777 }
1778 }
1779 else
1780 {
1781 p->Dict["ISTRN"] = 0;
1782 }
1783
1784 // OK, we are done processing the header (control) section.
1785
1786
1787 p->SPHStateOffset = p->StateSize/p->Fam.GetWordSize();
1788 // ============================================ Fluid Material ID Data Section
1789 // IALEMAT offset
1790 p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::FluidMaterialIdData );
1791 p->PreStateSize += p->Dict["IALEMAT"];
1792 p->Fam.BufferChunk( LSDynaFamily::Int, p->Dict["IALEMAT"] );
1793 for ( itmp = 0; itmp < p->Dict["IALEMAT"]; ++itmp )
1794 {
1795 p->FluidMaterials.insert( p->Fam.GetNextWordAsInt() );
1796 }
1797 //p->Fam.SkipToWord( LSDynaFamily::FluidMaterialIdData, curAdapt, p->Dict["IALEMAT"] );
1798
1799 // ======================= Smooth Particle Hydrodynamics Element Data Section
1800 // Only when NMSPH > 0
1801 p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::SPHElementData );
1802 if ( p->NumberOfCells[LSDynaMetaData::PARTICLE] > 0 )
1803 {
1804 p->Fam.BufferChunk( LSDynaFamily::Int, 1 );
1805 vtkIdType sphAttributes = p->Fam.GetNextWordAsInt();
1806 p->Dict["isphfg(1)"] = sphAttributes;
1807 if ( sphAttributes >= 9 )
1808 {
1809 p->Fam.BufferChunk( LSDynaFamily::Int, sphAttributes - 1 ); // should be 9 or 10
1810 // Dyna docs call statePerParticle "NUM_SPH_DATA":
1811 int statePerParticle = 1; // start at 1 because we always have material ID of particle.
1812 for ( itmp = 2; itmp <= sphAttributes; ++itmp )
1813 {
1814 int numComponents = p->Fam.GetNextWordAsInt();
1815 snprintf( ctmp, sizeof(ctmp), "isphfg(%d)", itmp );
1816 p->Dict[ ctmp ] = numComponents;
1817 statePerParticle += numComponents;
1818 }
1819 p->Dict["NUM_SPH_DATA"] = statePerParticle;
1820 p->StateSize += statePerParticle * p->NumberOfCells[LSDynaMetaData::PARTICLE] * p->Fam.GetWordSize();
1821 }
1822 else
1823 {
1824 p->FileIsValid = 0;
1825 return 0;
1826 }
1827 p->Fam.SkipToWord( LSDynaFamily::SPHElementData, curAdapt, p->Dict["isphfg(1)"] );
1828 p->PreStateSize += p->Dict["isphfg(1)"]*p->Fam.GetWordSize();
1829 }
1830
1831 // ===================================================== Geometry Data Section
1832 p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::GeometryData );
1833 iddtmp = this->GetNumberOfNodes()*p->Dimensionality*p->Fam.GetWordSize(); // Size of nodes on disk
1834 iddtmp += p->NumberOfCells[LSDynaMetaData::SOLID]*9*p->Fam.GetWordSize(); // Size of hexes on disk
1835 iddtmp += p->NumberOfCells[LSDynaMetaData::THICK_SHELL]*9*p->Fam.GetWordSize(); // Size of thick shells on disk
1836 iddtmp += p->NumberOfCells[LSDynaMetaData::SHELL]*5*p->Fam.GetWordSize(); // Size of quads on disk
1837 iddtmp += p->NumberOfCells[LSDynaMetaData::BEAM]*6*p->Fam.GetWordSize(); // Size of beams on disk
1838 p->PreStateSize += iddtmp;
1839 p->Fam.SkipToWord( LSDynaFamily::GeometryData, curAdapt, iddtmp/p->Fam.GetWordSize() ); // Skip to end of geometry
1840
1841 // =========== User Material, Node, And Element Identification Numbers Section
1842 p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::UserIdData );
1843 if ( p->Dict["NARBS"] != 0 )
1844 {
1845 // For sequential material numbering
1846 // NARBS = 10+NUMNP+NEL8+NEL2+NEL4+NELT+3*NMMAT (even though the 3*NMMAT numbers are unused)
1847 // For arbitrary material numbering (NSORT<0)
1848 // NARBS = 16+NUMNP+NEL8+NEL2+NEL4+NELT+3*NMMAT (Note 6 extra params)
1849
1850 p->Fam.BufferChunk( LSDynaFamily::Int, 10 );
1851 p->Dict["NSORT"] = p->Fam.GetNextWordAsInt();
1852 p->Dict["NSRH"] = p->Fam.GetNextWordAsInt();
1853 p->Dict["NSRB"] = p->Fam.GetNextWordAsInt();
1854 p->Dict["NSRS"] = p->Fam.GetNextWordAsInt();
1855 p->Dict["NSRT"] = p->Fam.GetNextWordAsInt();
1856 p->Dict["NSORTD"] = p->Fam.GetNextWordAsInt();
1857 p->Dict["NSRHD"] = p->Fam.GetNextWordAsInt();
1858 p->Dict["NSRBD"] = p->Fam.GetNextWordAsInt();
1859 p->Dict["NSRSD"] = p->Fam.GetNextWordAsInt();
1860 p->Dict["NSRTD"] = p->Fam.GetNextWordAsInt();
1861
1862 if ( p->Dict["NSORT"] < 0 )
1863 {
1864 p->Fam.BufferChunk( LSDynaFamily::Int, 6 );
1865 p->Dict["NSRMA"] = p->Fam.GetNextWordAsInt();
1866 p->Dict["NSRMU"] = p->Fam.GetNextWordAsInt();
1867 p->Dict["NSRMP"] = p->Fam.GetNextWordAsInt();
1868 p->Dict["NSRTM"] = p->Fam.GetNextWordAsInt();
1869 p->Dict["NUMRBS"] = p->Fam.GetNextWordAsInt();
1870 p->Dict["NMMAT"] = p->Fam.GetNextWordAsInt();
1871 }
1872
1873 iddtmp = p->Dict["NARBS"] * p->Fam.GetWordSize();
1874 p->PreStateSize += iddtmp;
1875 p->Fam.SkipToWord( LSDynaFamily::UserIdData, curAdapt, p->Dict["NARBS"] );
1876 }
1877 else
1878 {
1879 p->Dict["NSORT"] = 0;
1880 }
1881 // Break from convention and read in actual array values (as opposed to just summary information)
1882 // about the material IDs. This is required because the reader must present part names after
1883 // RequestInformation is called and that cannot be done without a list of material IDs.
1884 this->ReadUserMaterialIds();
1885
1886 // ======================================= Adapted Element Parent List Section
1887 p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::AdaptedParentData );
1888 p->Fam.SkipToWord( LSDynaFamily::AdaptedParentData, curAdapt, 2*p->Dict["NADAPT"] );
1889 iddtmp = 2*p->Dict["NADAPT"]*p->Fam.GetWordSize();
1890 p->PreStateSize += iddtmp;
1891
1892 // ============== Smooth Particle Hydrodynamics Node And Material List Section
1893 p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::SPHNodeData );
1894 iddtmp = 2*p->NumberOfCells[LSDynaMetaData::PARTICLE]*p->Fam.GetWordSize();
1895 p->PreStateSize += iddtmp;
1896 p->Fam.SkipToWord( LSDynaFamily::SPHNodeData, curAdapt, 2*p->NumberOfCells[LSDynaMetaData::PARTICLE] );
1897
1898 // =========================================== Rigid Road Surface Data Section
1899 p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::RigidSurfaceData );
1900 if ( p->Dict["NDIM"] > 5 )
1901 {
1902 p->Fam.BufferChunk( LSDynaFamily::Int, 4 );
1903 p->PreStateSize += 4*p->Fam.GetWordSize();
1904 p->Dict["NNODE"] = p->Fam.GetNextWordAsInt();
1905 p->Dict["NSEG"] = p->Fam.GetNextWordAsInt();
1906 p->Dict["NSURF"] = p->Fam.GetNextWordAsInt();
1907 p->Dict["MOTION"] = p->Fam.GetNextWordAsInt();
1908 iddtmp = 4*p->Dict["NNODE"]*p->Fam.GetWordSize();
1909 p->PreStateSize += iddtmp;
1910 p->Fam.SkipWords( 4*p->Dict["NNODE"] );
1911 p->NumberOfCells[LSDynaMetaData::ROAD_SURFACE] = p->Dict["NSEG"];
1912
1913 for ( itmp = 0; itmp < p->Dict["NSURF"]; ++itmp )
1914 {
1915 p->Fam.BufferChunk( LSDynaFamily::Int, 2 );
1916 p->Fam.GetNextWordAsInt(); // Skip SURFID
1917 iddtmp = p->Fam.GetNextWordAsInt(); // Read SURFNSEG[SURFID]
1918 p->RigidSurfaceSegmentSizes.push_back( iddtmp );
1919 p->PreStateSize += (2 + 4*iddtmp)*p->Fam.GetWordSize();
1920 p->Fam.SkipWords( 4*iddtmp );
1921 }
1922
1923 if ( p->Dict["NSEG"] > 0 )
1924 {
1925 p->AddCellArray( LSDynaMetaData::ROAD_SURFACE, LS_ARRAYNAME_SEGMENTID, 1, 1 );
1926 //FIXME: p->AddRoadPointArray( LSDynaMetaData::ROAD_SURFACE, LS_ARRAYNAME_USERID, 1, 1 );
1927 }
1928
1929 if ( p->Dict["MOTION"] )
1930 {
1931 p->StateSize += 6*p->Dict["NSURF"]*p->Fam.GetWordSize();
1932 }
1933 }
1934
1935 //if ( curAdapt == 0 )
1936 {
1937 p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::EndOfStaticSection );
1938 p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::TimeStepSection );
1939 }
1940 p->Fam.SetStateSize( p->StateSize / p->Fam.GetWordSize() );
1941
1942
1943 // ==========================================================================
1944 // Now that we've read the header, create a list of the cell arrays for
1945 // each output mesh.
1946
1947 // Currently, the LS-Dyna reader only gives users a few knobs to control which cell variables are loaded.
1948 // It is a difficult problem since many attributes only occur on some element types, there are many
1949 // dyna flags that conditionally omit results, and some quantities are repeated over differing numbers
1950 // of points for different types of cells.
1951 // Given the complexity, we punt by defining some knobs for "types" of data and define related fields.
1952 // In a perfect world, finer-grained control would be available.
1953 //
1954 // As an example: if there are any
1955 // - 3-D cells, OR
1956 // - non-rigid 2-D cells with IOSHL(1)==1, OR
1957 // - beam cells with NV1D > 6, OR
1958 // - SPH cells with isphfg(4)==6
1959 // then there will be stresses present
1960
1961 // Every cell always has a material type
1962 // FIXME: Is this true? Rigid bodies may be an exception, in which
1963 // case we need to check that the number of cells in the other 5 meshes sum to >0
1964
1965 // Total number of ALE fluid groups. Fluid density and
1966 // volume fractions output as history variables, and a flag
1967 // for the dominant group. If negative multi-material
1968 // species mass for each group is also output. Order is: rho,
1969 // vf1, … vfn, dvf flag, m1, … mn. Density is at position 8
1970 // after the location for plastic strain. Any element material
1971 // history variables are written before the Ale variables, and
1972 // the six element strains components after these if
1973 // ISTRN=1.
1974 int numGroups = std::abs(static_cast<int>(p->Dict["NUMFLUID"]));
1975 bool hasMass = (p->Dict["NUMFLUID"] < 0);
1976 int numALEvalues = (numGroups > 0) ? 1 + numGroups + 1 + (hasMass? numGroups : 0) : 0;
1977
1978 if ( p->Dict["NARBS"] )
1979 {
1980 p->AddPointArray( LS_ARRAYNAME_USERID, 1, 1 );
1981 }
1982
1983 if ( p->NumberOfCells[ LSDynaMetaData::PARTICLE ] )
1984 {
1985 // One value is always output which is the material number as a floating point number for each particle.
1986 // If this value is negative then the particle has been deleted from the model.
1987 p->AddCellArray( LSDynaMetaData::PARTICLE, LS_ARRAYNAME_MATERIAL, 1, 1 );
1988 //p->AddCellArray( LSDynaMetaData::PARTICLE, LS_ARRAYNAME_DEATH, 1, 1 ); // There is no mention of this in manual... Was this the -ve Material case?
1989 if ( p->Dict["isphfg(2)"] == 1 )
1990 {
1991 p->AddCellArray( LSDynaMetaData::PARTICLE, LS_ARRAYNAME_RADIUSOFINFLUENCE, 1, 1 );
1992 }
1993 if ( p->Dict["isphfg(3)"] == 1 )
1994 {
1995 p->AddCellArray( LSDynaMetaData::PARTICLE, LS_ARRAYNAME_PRESSURE, 1, 1 );
1996 }
1997 if ( p->Dict["isphfg(4)"] == 6 )
1998 {
1999 p->AddCellArray( LSDynaMetaData::PARTICLE, LS_ARRAYNAME_STRESS, 6, 1 );
2000 }
2001 if ( p->Dict["isphfg(5)"] == 1 )
2002 {
2003 p->AddCellArray( LSDynaMetaData::PARTICLE, LS_ARRAYNAME_EPSTRAIN, 1, 1 );
2004 }
2005 if ( p->Dict["isphfg(6)"] == 1 )
2006 {
2007 p->AddCellArray( LSDynaMetaData::PARTICLE, LS_ARRAYNAME_DENSITY, 1, 1 );
2008 }
2009 if ( p->Dict["isphfg(7)"] == 1 )
2010 {
2011 p->AddCellArray( LSDynaMetaData::PARTICLE, LS_ARRAYNAME_INTERNALENERGY, 1, 1 );
2012 }
2013 if ( p->Dict["isphfg(8)"] == 1 )
2014 {
2015 p->AddCellArray( LSDynaMetaData::PARTICLE, LS_ARRAYNAME_NUMNEIGHBORS, 1, 1 );
2016 }
2017 if ( p->Dict["isphfg(9)"] == 6 )
2018 {
2019 p->AddCellArray( LSDynaMetaData::PARTICLE, LS_ARRAYNAME_STRAIN, 6, 1 );
2020 }
2021 if ( p->Dict["isphfg(10)"] == 1 )
2022 {
2023 p->AddCellArray( LSDynaMetaData::PARTICLE, LS_ARRAYNAME_MASS, 1, 1 );
2024 }
2025 }
2026
2027 if ( p->NumberOfCells[ LSDynaMetaData::BEAM ] )
2028 {
2029 // p->AddCellArray( LSDynaMetaData::BEAM, LS_ARRAYNAME_MATERIAL, 1, 1 );
2030 // if ( p->Dict["MDLOPT"] == LS_MDLOPT_CELL )
2031 // {
2032 // p->AddCellArray( LSDynaMetaData::BEAM, LS_ARRAYNAME_DEATH, 1, 1 );
2033 // }
2034
2035 if ( p->Dict["NARBS"] != 0 )
2036 {
2037 p->AddCellArray( LSDynaMetaData::BEAM, LS_ARRAYNAME_USERID, 1, 1 );
2038 }
2039 if ( p->Dict["NV1D"] >= 6 )
2040 {
2041 p->AddCellArray( LSDynaMetaData::BEAM, LS_ARRAYNAME_AXIALFORCE, 1, 1 );
2042 p->AddCellArray( LSDynaMetaData::BEAM, LS_ARRAYNAME_SHEARRESULTANT, 2, 1 );
2043 p->AddCellArray( LSDynaMetaData::BEAM, LS_ARRAYNAME_BENDINGRESULTANT, 2, 1 );
2044 p->AddCellArray( LSDynaMetaData::BEAM, LS_ARRAYNAME_TORSIONRESULTANT, 1, 1 );
2045 }
2046 if ( p->Dict["NV1D"] > 6 )
2047 {
2048 p->AddCellArray( LSDynaMetaData::BEAM, LS_ARRAYNAME_SHEARSTRESS, 2, 1 );
2049 p->AddCellArray( LSDynaMetaData::BEAM, LS_ARRAYNAME_AXIALSTRESS, 1, 1 );
2050 p->AddCellArray( LSDynaMetaData::BEAM, LS_ARRAYNAME_PLASTICSTRAIN, 1, 1 );
2051 p->AddCellArray( LSDynaMetaData::BEAM, LS_ARRAYNAME_AXIALSTRAIN, 1, 1 );
2052 }
2053 }
2054
2055 if ( p->NumberOfCells[ LSDynaMetaData::SHELL ] )
2056 {
2057 // p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_MATERIAL, 1, 1 );
2058 // if ( p->Dict["MDLOPT"] == LS_MDLOPT_CELL )
2059 // {
2060 // p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_DEATH, 1, 1 );
2061 // }
2062 if ( p->Dict["NARBS"] != 0 )
2063 {
2064 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_USERID, 1, 1 );
2065 }
2066 if ( p->Dict["IOSHL(1)"] )
2067 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_STRESS, 6, 1 );
2068 if ( p->Dict["IOSHL(2)"] )
2069 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_EPSTRAIN, 1, 1 );
2070
2071 int neips = p->Dict["NEIPS"];
2072 int extraValues = neips;
2073 if (extraValues>0)
2074 {
2075 // Any element material history variables are written before the Ale variables, and the six element strains components after these if ISTRN=1
2076 int materialValues = extraValues - numALEvalues;
2077 if (materialValues > 0)
2078 {
2079 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_INTEGRATIONPOINT, materialValues, 1 );
2080 extraValues -= materialValues;
2081 }
2082
2083 if ( (numALEvalues > 0) && (extraValues>=numALEvalues) )
2084 {
2085 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_DENSITY, 1, 1 );
2086 extraValues--;
2087
2088 for (int g=0; g < numGroups; ++g)
2089 {
2090 snprintf( ctmp, sizeof(ctmp), LS_ARRAYNAME_VOLUME_FRACTION_FMT, static_cast<int>(g+1) );
2091 p->AddCellArray( LSDynaMetaData::SHELL, ctmp, 1, 1 );
2092 extraValues--;
2093 }
2094
2095 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_DOMINANT_GROUP, 1, 1 );
2096 extraValues--;
2097
2098 for (int g=0; hasMass && (g < numGroups); ++g)
2099 {
2100 snprintf( ctmp, sizeof(ctmp), LS_ARRAYNAME_SPECIES_MASS_FMT, static_cast<int>(g+1) );
2101 p->AddCellArray( LSDynaMetaData::SHELL, ctmp, 1, 1 );
2102 extraValues--;
2103 }
2104 }
2105 }
2106
2107 if ( p->Dict["_MAXINT_"] >= 2 )
2108 {
2109 if ( p->Dict["IOSHL(1)"] )
2110 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_STRESS "InnerSurf", 6, 1 );
2111 if ( p->Dict["IOSHL(2)"] )
2112 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_EPSTRAIN "InnerSurf", 1, 1 );
2113 if ( neips )
2114 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_INTEGRATIONPOINT "InnerSurf", neips, 1 );
2115 }
2116 if ( p->Dict["_MAXINT_"] >= 3 )
2117 {
2118 if ( p->Dict["IOSHL(1)"] )
2119 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_STRESS "OuterSurf", 6, 1 );
2120 if ( p->Dict["IOSHL(2)"] )
2121 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_EPSTRAIN "OuterSurf", 1, 1 );
2122 if ( neips )
2123 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_INTEGRATIONPOINT "OuterSurf", neips, 1 );
2124 }
2125
2126 for ( itmp = 3; itmp < p->Dict["_MAXINT_"]; ++itmp )
2127 {
2128 if ( p->Dict["IOSHL(1)"] )
2129 {
2130 snprintf( ctmp, sizeof(ctmp), "%sIntPt%d", LS_ARRAYNAME_STRESS, itmp + 1 );
2131 p->AddCellArray( LSDynaMetaData::SHELL, ctmp, 6, 1 );
2132 }
2133 if ( p->Dict["IOSHL(2)"] )
2134 {
2135 snprintf( ctmp, sizeof(ctmp), "%sIntPt%d", LS_ARRAYNAME_EPSTRAIN, itmp + 1 );
2136 p->AddCellArray( LSDynaMetaData::SHELL, ctmp, 1, 1 );
2137 }
2138 if ( neips )
2139 {
2140 snprintf( ctmp, sizeof(ctmp), "%sIntPt%d", LS_ARRAYNAME_INTEGRATIONPOINT, itmp + 1 );
2141 p->AddCellArray( LSDynaMetaData::SHELL, ctmp, neips, 1 );
2142 }
2143 }
2144 if ( p->Dict["IOSHL(3)"] )
2145 {
2146 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_NORMALRESULTANT, 3, 1 );
2147 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_SHEARRESULTANT, 2, 1 );
2148 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_BENDINGRESULTANT, 3, 1 );
2149 }
2150 if ( p->Dict["IOSHL(4)"] )
2151 {
2152 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_THICKNESS, 1, 1 );
2153 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_ELEMENTMISC, 2, 1 );
2154 }
2155
2156 if ( p->Dict["ISTRN"] )
2157 {
2158 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_STRAIN "InnerSurf", 6, 1 );
2159 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_STRAIN "OuterSurf", 6, 1 );
2160 }
2161 if ( ! p->Dict["ISTRN"] || (p->Dict["NV2D"] >= 45) )
2162 {
2163 p->AddCellArray( LSDynaMetaData::SHELL, LS_ARRAYNAME_INTERNALENERGY, 1, 1 );
2164 }
2165 }
2166
2167 if ( p->NumberOfCells[ LSDynaMetaData::THICK_SHELL ] )
2168 {
2169 // p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_MATERIAL, 1, 1 );
2170 // if ( p->Dict["MDLOPT"] == LS_MDLOPT_CELL )
2171 // {
2172 // p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_DEATH, 1, 1 );
2173 // }
2174 if ( p->Dict["NARBS"] != 0 )
2175 {
2176 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_USERID, 1, 1 );
2177 }
2178 if ( p->Dict["IOSHL(1)"] )
2179 {
2180 if ( p->Dict["_MAXINT_"] >= 3 )
2181 {
2182 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_STRESS, 6, 1 );
2183 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_STRESS "InnerSurf", 6, 1 );
2184 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_STRESS "OuterSurf", 6, 1 );
2185 }
2186 for ( itmp = 3; itmp < p->Dict["_MAXINT_"]; ++itmp )
2187 {
2188 snprintf( ctmp, sizeof(ctmp), "%sIntPt%d", LS_ARRAYNAME_STRESS, itmp + 1 );
2189 p->AddCellArray( LSDynaMetaData::THICK_SHELL, ctmp, 6, 1 );
2190 }
2191 }
2192 if ( p->Dict["IOSHL(2)"] )
2193 {
2194 if ( p->Dict["_MAXINT_"] >= 3 )
2195 {
2196 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_EPSTRAIN, 1, 1 );
2197 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_EPSTRAIN "InnerSurf", 1, 1 );
2198 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_EPSTRAIN "OuterSurf", 1, 1 );
2199 }
2200 for ( itmp = 3; itmp < p->Dict["_MAXINT_"]; ++itmp )
2201 {
2202 snprintf( ctmp, sizeof(ctmp), "%sIntPt%d", LS_ARRAYNAME_EPSTRAIN, itmp + 1 );
2203 p->AddCellArray( LSDynaMetaData::THICK_SHELL, ctmp, 1, 1 );
2204 }
2205 }
2206 if ( p->Dict["NEIPS"] )
2207 {
2208 int neips = p->Dict["NEIPS"];
2209 if ( p->Dict["_MAXINT_"] >= 3 )
2210 {
2211 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_INTEGRATIONPOINT, neips, 1 );
2212 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_INTEGRATIONPOINT, neips, 1 );
2213 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_INTEGRATIONPOINT "InnerSurf", neips, 1 );
2214 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_INTEGRATIONPOINT "OuterSurf", neips, 1 );
2215 }
2216 for ( itmp = 3; itmp < p->Dict["_MAXINT_"]; ++itmp )
2217 {
2218 snprintf( ctmp, sizeof(ctmp), "%sIntPt%d", LS_ARRAYNAME_INTEGRATIONPOINT, itmp + 1 );
2219 p->AddCellArray( LSDynaMetaData::THICK_SHELL, ctmp, 6, 1 );
2220 }
2221 }
2222 if ( p->Dict["ISTRN"] )
2223 {
2224 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_STRAIN "InnerSurf", 6, 1 );
2225 p->AddCellArray( LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_STRAIN "OuterSurf", 6, 1 );
2226 }
2227 }
2228
2229 if ( p->NumberOfCells[ LSDynaMetaData::SOLID ] )
2230 {
2231 // p->AddCellArray( LSDynaMetaData::SOLID, LS_ARRAYNAME_MATERIAL, 1, 1 );
2232 // if ( p->Dict["MDLOPT"] == LS_MDLOPT_CELL )
2233 // {
2234 // p->AddCellArray( LSDynaMetaData::SOLID, LS_ARRAYNAME_DEATH, 1, 1 );
2235 // }
2236 if ( p->Dict["NARBS"] != 0 )
2237 {
2238 p->AddCellArray( LSDynaMetaData::SOLID, LS_ARRAYNAME_USERID, 1, 1 );
2239 }
2240 p->AddCellArray( LSDynaMetaData::SOLID, LS_ARRAYNAME_STRESS, 6, 1 );
2241 p->AddCellArray( LSDynaMetaData::SOLID, LS_ARRAYNAME_EPSTRAIN, 1, 1 );
2242
2243 int extraValues = p->Dict["NEIPH"];
2244 if (extraValues>0)
2245 {
2246 int strainValues = ( p->Dict["ISTRN"]==1 ) ? 6 : 0; // last six values are strain.
2247
2248 // Any element material history variables are written before the Ale variables, and the six element strains components after these if ISTRN=1
2249 int materialValues = extraValues - (numALEvalues+strainValues);
2250 if (materialValues > 0)
2251 {
2252 p->AddCellArray( LSDynaMetaData::SOLID, LS_ARRAYNAME_INTEGRATIONPOINT, materialValues, 1 );
2253 extraValues -= materialValues;
2254 }
2255
2256 if ( (numALEvalues > 0) && (extraValues>=numALEvalues) )
2257 {
2258 p->AddCellArray( LSDynaMetaData::SOLID, LS_ARRAYNAME_DENSITY, 1, 1 );
2259 extraValues--;
2260
2261 for (int g=0; g < numGroups; ++g)
2262 {
2263 snprintf( ctmp, sizeof(ctmp), LS_ARRAYNAME_VOLUME_FRACTION_FMT, static_cast<int>(g+1) );
2264 p->AddCellArray( LSDynaMetaData::SOLID, ctmp, 1, 1 );
2265 extraValues--;
2266 }
2267
2268 p->AddCellArray( LSDynaMetaData::SOLID, LS_ARRAYNAME_DOMINANT_GROUP, 1, 1 );
2269 extraValues--;
2270
2271 for (int g=0; hasMass && (g < numGroups); ++g)
2272 {
2273 snprintf( ctmp, sizeof(ctmp), LS_ARRAYNAME_SPECIES_MASS_FMT, static_cast<int>(g+1) );
2274 p->AddCellArray( LSDynaMetaData::SOLID, ctmp, 1, 1 );
2275 extraValues--;
2276 }
2277 }
2278 if ( (strainValues > 0) && (extraValues>=strainValues))
2279 {
2280 p->AddCellArray( LSDynaMetaData::SOLID, LS_ARRAYNAME_STRAIN, strainValues, 1 );
2281 }
2282 }
2283 }
2284
2285 // Only try reading the keyword file if we don't have part names.
2286 if ( curAdapt == 0 && p->PartNames.empty() )
2287 {
2288 this->ResetPartInfo();
2289
2290 int result = this->ReadInputDeck();
2291
2292 if (result == 0)
2293 {
2294 //we failed to read the input deck so we are going to read the first binary file for part names
2295 this->ReadPartTitlesFromRootFile();
2296 }
2297 }
2298
2299 return -1;
2300 }
2301
ScanDatabaseTimeSteps()2302 int vtkLSDynaReader::ScanDatabaseTimeSteps()
2303 {
2304 LSDynaMetaData* p = this->P;
2305
2306 // ======================================================= State Data Sections
2307 // The 2 lines below are now in ReadHeaderInformation:
2308 // p->Fam.MarkSectionStart( curAdapt, LSDynaFamily::TimeStepSection );
2309 // p->Fam.SetStateSize( p->StateSize / p->Fam.GetWordSize() );
2310 // It may be useful to call
2311 // p->JumpToMark( LSDynaFamily::TimeStepSection );
2312 // here.
2313 if ( p->Fam.GetStateSize() <= 0 )
2314 {
2315 vtkErrorMacro( "Database has bad state size (" << p->Fam.GetStateSize() << ")." );
2316 return 1;
2317 }
2318
2319 // Discover the number of states and record the time value for each.
2320 int ntimesteps = 0;
2321 double time;
2322 int itmp = 1;
2323 int lastAdapt = 0;
2324 do {
2325 if ( p->Fam.BufferChunk( LSDynaFamily::Float, 1 ) == 0 )
2326 {
2327 time = p->Fam.GetNextWordAsFloat();
2328 if ( time != LSDynaFamily::EOFMarker )
2329 {
2330 p->Fam.MarkTimeStep();
2331 p->TimeValues.push_back( time );
2332 //fprintf( stderr, "%d %f\n", (int) p->TimeValues.size() - 1, time ); fflush(stderr);
2333 if ( p->Fam.SkipToWord( LSDynaFamily::TimeStepSection, ntimesteps++, p->Fam.GetStateSize() ) )
2334 {
2335 itmp = 0;
2336 }
2337 }
2338 else
2339 {
2340 if ( p->Fam.AdvanceFile() )
2341 {
2342 itmp = 0;
2343 }
2344 else
2345 {
2346 if ( ntimesteps == 0 )
2347 {
2348 // First time step was an EOF marker... move the marker to the
2349 // beginning of the first real time step...
2350 p->Fam.MarkSectionStart( lastAdapt, LSDynaFamily::TimeStepSection );
2351 }
2352 }
2353 int nextAdapt = p->Fam.GetCurrentAdaptLevel();
2354 if ( nextAdapt != lastAdapt )
2355 {
2356 // Read the next static header section... state size has changed.
2357 p->Fam.MarkSectionStart( nextAdapt, LSDynaFamily::ControlSection );
2358 this->ReadHeaderInformation( nextAdapt );
2359 //p->Fam.SkipToWord( LSDynaFamily::EndOfStaticSection, nextAdapt, 0 );
2360 lastAdapt = nextAdapt;
2361 }
2362 }
2363 }
2364 else
2365 {
2366 itmp = 0;
2367 }
2368 } while (itmp);
2369
2370 this->TimeStepRange[0] = 0;
2371 this->TimeStepRange[1] = ntimesteps ? ntimesteps - 1 : 0;
2372
2373 return -1;
2374 }
2375
2376 // =================================== Provide information about the database to the pipeline
RequestInformation(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (iinfo),vtkInformationVector * oinfo)2377 int vtkLSDynaReader::RequestInformation( vtkInformation* vtkNotUsed(request),
2378 vtkInformationVector** vtkNotUsed(iinfo),
2379 vtkInformationVector* oinfo )
2380 {
2381 LSDynaMetaData* p = this->P;
2382 // If the time step is set before RequestInformation is called, we must
2383 // read the header information immediately in order to determine whether
2384 // the timestep that's been passed is valid. If it's not, we ignore it.
2385 if ( ! p->FileIsValid )
2386 {
2387 if ( p->Fam.GetDatabaseDirectory().empty() )
2388 {
2389 // fail silently for CanReadFile()'s sake.
2390 //vtkErrorMacro( "You haven't set the LS-Dyna database directory!" );
2391 return 1;
2392 }
2393
2394 if ( p->Fam.GetDatabaseBaseName().empty() )
2395 {
2396 p->Fam.SetDatabaseBaseName( "/d3plot" ); // not a bad assumption.
2397 }
2398 p->Fam.ScanDatabaseDirectory();
2399 if ( p->Fam.GetNumberOfFiles() < 1 )
2400 {
2401 p->FileIsValid = 0;
2402 return 1;
2403 }
2404 p->Fam.DetermineStorageModel();
2405 p->MaxFileLength = p->FileSizeFactor*512*512*p->Fam.GetWordSize();
2406 p->FileIsValid = 1;
2407
2408 // OK, now we have a list of files. Next, determine the length of the
2409 // state vector (#bytes of data stored per time step):
2410 this->ReadHeaderInformation( 0 );
2411
2412 // Finally, we can loop through and determine where all the state
2413 // vectors start for each time step.
2414 // This will call ReadHeaderInformation when it encounters any
2415 // mesh adaptations (so that it can get the new state vector size).
2416 this->ScanDatabaseTimeSteps();
2417 }
2418
2419 if ( p->TimeValues.empty() )
2420 {
2421 vtkErrorMacro( "No valid time steps in the LS-Dyna database" );
2422 return 0;
2423 }
2424
2425 // Clamp timestep to be valid here.
2426 if ( p->CurrentState < 0 )
2427 {
2428 p->CurrentState = 0;
2429 }
2430 else if ( p->CurrentState >= static_cast<vtkIdType>(p->TimeValues.size()) )
2431 {
2432 p->CurrentState = static_cast<vtkIdType>(p->TimeValues.size() - 1);
2433 }
2434
2435 int newAdaptLevel = p->Fam.TimeAdaptLevel( p->CurrentState );
2436 if ( p->Fam.GetCurrentAdaptLevel() != newAdaptLevel )
2437 {
2438 // Requested time step has a different mesh adaptation than current one.
2439 // Update the header information so that queries like GetNumberOfCells() work properly.
2440 int result;
2441 result = this->ReadHeaderInformation( newAdaptLevel );
2442 if ( result >= 0 )
2443 {
2444 this->ResetPartsCache();
2445 return result;
2446 }
2447 }
2448
2449 // Every output object has all the time steps.
2450 vtkInformation* outInfo = oinfo->GetInformationObject(0);
2451 outInfo->Set( vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &p->TimeValues[0], (int)p->TimeValues.size() );
2452 double timeRange[2];
2453 timeRange[0] = p->TimeValues[0];
2454 timeRange[1] = p->TimeValues[p->TimeValues.size() - 1];
2455 outInfo->Set( vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2 );
2456
2457 return 1;
2458 }
2459
2460 //----------------------------------------------------------------------------
ReadTopology()2461 int vtkLSDynaReader::ReadTopology()
2462 {
2463 bool readTopology=false;
2464 if(!this->Parts)
2465 {
2466 readTopology=true;
2467 this->Parts = vtkLSDynaPartCollection::New();
2468 this->Parts->InitCollection(this->P,nullptr,nullptr);
2469 }
2470 if(!readTopology)
2471 {
2472 return 0;
2473 }
2474
2475 if( this->ReadPartSizes())
2476 {
2477 vtkErrorMacro( "Could not read cell sizes." );
2478 return 1;
2479 }
2480
2481 if ( this->ReadConnectivityAndMaterial() )
2482 {
2483 vtkErrorMacro( "Could not read connectivity." );
2484 return 1;
2485 }
2486
2487 this->Parts->FinalizeTopology();
2488
2489 if(this->ReadNodes())
2490 {
2491 vtkErrorMacro("Could not read static node values.");
2492 return 1;
2493 }
2494
2495
2496 // we need to read the user ids after we have read the topology
2497 // so we know how many cells are in each part
2498 if ( this->ReadUserIds() )
2499 {
2500 vtkErrorMacro( "Could not read user node/element IDs." );
2501 return 1;
2502 }
2503
2504 return 0;
2505 }
2506
2507 // ============================================================= Section parsing
ReadNodes()2508 int vtkLSDynaReader::ReadNodes()
2509 {
2510 LSDynaMetaData* p = this->P;
2511
2512 // Always read geometry, even if the mesh will be deformed using deflected coordinates
2513 // (LS_ARRAYNAME_DEFLECTION). That way, we can compute deflection array later on.
2514 p->Fam.SkipToWord(LSDynaFamily::GeometryData, p->Fam.GetCurrentAdaptLevel(), 0);
2515 this->Parts->ReadPointProperty(p->NumberOfNodes, p->Dimensionality, nullptr, false, true, false);
2516
2517 // Note that in any event we still have to read the rigid road coordinates.
2518 // If the mesh is deformed each state will have the points so see ReadState
2519 if ( p->ReadRigidRoadMvmt )
2520 {
2521 vtkIdType nnode = p->Dict["NNODE"];
2522 p->Fam.SkipToWord( LSDynaFamily::RigidSurfaceData, p->Fam.GetCurrentAdaptLevel(), 4 + nnode );
2523 this->Parts->ReadPointProperty(nnode,3,nullptr,false,false,true);
2524 }
2525
2526 return 0;
2527 }
2528
2529 //-----------------------------------------------------------------------------
ReadUserIds()2530 int vtkLSDynaReader::ReadUserIds()
2531 {
2532 // Below here is code that runs when user node or element numbers are present
2533 int arbitraryMaterials = this->P->Dict["NSORT"] < 0 ? 1 : 0;
2534 vtkIdType isz = this->GetNumberOfNodes();
2535 if ( arbitraryMaterials )
2536 {
2537 this->P->Fam.SkipToWord( LSDynaFamily::UserIdData,
2538 this->P->Fam.GetCurrentAdaptLevel(), 16 );
2539 }
2540 else
2541 {
2542 this->P->Fam.SkipToWord( LSDynaFamily::UserIdData,
2543 this->P->Fam.GetCurrentAdaptLevel(), 10 );
2544 }
2545
2546 // Node numbers
2547 bool nodeIdStatus = this->GetPointArrayStatus( LS_ARRAYNAME_USERID ) == 1;
2548 if(nodeIdStatus)
2549 {
2550 this->Parts->ReadPointUserIds(isz,LS_ARRAYNAME_USERID);
2551 }
2552
2553 // FIXME: This won't work if Rigid Body and Shell elements are interleaved (which I now believe they are)
2554 this->Parts->ReadCellUserIds(LSDynaMetaData::BEAM,
2555 this->GetCellArrayStatus(LSDynaMetaData::BEAM, LS_ARRAYNAME_USERID));
2556 this->Parts->ReadCellUserIds(LSDynaMetaData::SHELL,
2557 this->GetCellArrayStatus(LSDynaMetaData::SHELL, LS_ARRAYNAME_USERID));
2558 this->Parts->ReadCellUserIds(LSDynaMetaData::THICK_SHELL,
2559 this->GetCellArrayStatus(LSDynaMetaData::THICK_SHELL, LS_ARRAYNAME_USERID));
2560 this->Parts->ReadCellUserIds(LSDynaMetaData::SOLID,
2561 this->GetCellArrayStatus(LSDynaMetaData::SOLID, LS_ARRAYNAME_USERID));
2562 this->Parts->ReadCellUserIds(LSDynaMetaData::RIGID_BODY,
2563 this->GetCellArrayStatus(LSDynaMetaData::RIGID_BODY, LS_ARRAYNAME_USERID));
2564 return 0;
2565 }
2566
2567 //-----------------------------------------------------------------------------
ReadDeletion()2568 int vtkLSDynaReader::ReadDeletion()
2569 {
2570 enum LSDynaMetaData::LSDYNA_TYPES validCellTypes[4] = {
2571 LSDynaMetaData::SOLID,
2572 LSDynaMetaData::THICK_SHELL,
2573 LSDynaMetaData::SHELL,
2574 LSDynaMetaData::BEAM};
2575
2576 if(!this->RemoveDeletedCells)
2577 {
2578 //this functions doesn't have to lead the reader to a certain
2579 //position in the files
2580 this->Parts->DisbleDeadCells();
2581 return 0;
2582 }
2583
2584 LSDynaMetaData* p = this->P;
2585 vtkUnsignedCharArray* death;
2586 switch ( p->Dict["MDLOPT"] )
2587 {
2588 case LS_MDLOPT_POINT:
2589 vtkErrorMacro("We currently only support cell death");
2590 break;
2591 case LS_MDLOPT_CELL:
2592 for(int i=0; i < 4; ++i)
2593 {
2594 const LSDynaMetaData::LSDYNA_TYPES type = validCellTypes[i];
2595 vtkIdType numCells,numSkipStart,numSkipEnd;
2596 this->Parts->GetPartReadInfo(type,numCells,numSkipStart,numSkipEnd);
2597
2598 death = vtkUnsignedCharArray::New();
2599 death->SetName( LS_ARRAYNAME_DEATH );
2600 death->SetNumberOfComponents( 1 );
2601 death->SetNumberOfTuples(numCells);
2602
2603 p->Fam.SkipWords(numSkipStart);
2604 this->ReadDeletionArray(death,0,1);
2605 p->Fam.SkipWords(numSkipEnd);
2606 this->Parts->SetCellDeadFlags(type,death,this->DeletedCellsAsGhostArray);
2607 death->Delete();
2608 }
2609
2610 //we are now at the position to read the SPH deletion info from the sph state info
2611 if(p->NumberOfCells[LSDynaMetaData::PARTICLE]>0)
2612 {
2613 const LSDynaMetaData::LSDYNA_TYPES type = LSDynaMetaData::PARTICLE;
2614 vtkIdType numCells,numSkipStart,numSkipEnd;
2615 this->Parts->GetPartReadInfo(type,numCells,numSkipStart,numSkipEnd);
2616
2617 death = vtkUnsignedCharArray::New();
2618 death->SetName( LS_ARRAYNAME_DEATH );
2619 death->SetNumberOfComponents( 1 );
2620 death->SetNumberOfTuples(numCells);
2621
2622 p->Fam.SkipWords(numSkipStart);
2623 //we are really reading the material id as the death flag
2624 //and each particle has twenty words of info, so we have to skip 19
2625 //since luckily material id is first
2626 this->ReadDeletionArray(death,0,20);
2627 p->Fam.SkipWords(numSkipEnd);
2628 this->Parts->SetCellDeadFlags(type,death,this->DeletedCellsAsGhostArray);
2629 death->Delete();
2630 }
2631 break;
2632 case LS_MDLOPT_NONE:
2633 default:
2634 // do nothing.
2635 break;
2636 }
2637 return 0;
2638 }
2639
2640 //-----------------------------------------------------------------------------
ReadDeletionArray(vtkUnsignedCharArray * arr,const int & pos,const int & size)2641 void vtkLSDynaReader::ReadDeletionArray(vtkUnsignedCharArray* arr, const int& pos, const int& size)
2642 {
2643 //setup to do a block read, way faster than converting each
2644 //float/double individually
2645 LSDynaMetaData *p = this->P;
2646 vtkIdType startId = 0;
2647 vtkIdType numChunks = p->Fam.InitPartialChunkBuffering(arr->GetNumberOfTuples(),size);
2648 if(p->Fam.GetWordSize() == 8)
2649 {
2650 for(vtkIdType i=0;i<numChunks;++i)
2651 {
2652 vtkIdType chunkSize = p->Fam.GetNextChunk(LSDynaFamily::Float );
2653 vtkIdType numCellsInChunk = chunkSize/size;
2654 double *dbuf = p->Fam.GetBufferAs<double>();
2655 this->FillDeletionArray(dbuf,arr,startId,numCellsInChunk,pos,size);
2656 startId+=numCellsInChunk;
2657 }
2658 }
2659 else
2660 {
2661 for(vtkIdType i=0;i<numChunks;++i)
2662 {
2663 vtkIdType chunkSize = p->Fam.GetNextChunk(LSDynaFamily::Float );
2664 vtkIdType numCellsInChunk = chunkSize/size;
2665 float *fbuf = p->Fam.GetBufferAs<float>();
2666 this->FillDeletionArray(fbuf,arr,startId,numCellsInChunk,pos,size);
2667 startId+=numCellsInChunk;
2668 }
2669 }
2670 }
2671
2672 //-----------------------------------------------------------------------------
ReadState(vtkIdType step)2673 int vtkLSDynaReader::ReadState( vtkIdType step )
2674 {
2675 //remember C style return so zero is pass
2676 if(this->ReadNodeStateInfo(step))
2677 {
2678 vtkErrorMacro( "Problem reading state point information." );
2679 return 1;
2680 }
2681 if(this->ReadCellStateInfo( step ))
2682 {
2683 vtkErrorMacro( "Problem reading state cell information." );
2684 return 1;
2685 }
2686 if(this->ReadDeletion())
2687 {
2688 vtkErrorMacro( "Problem reading state deletion information." );
2689 return 1;
2690 }
2691 return 0;
2692 }
2693
2694 //-----------------------------------------------------------------------------
ReadNodeStateInfo(vtkIdType step)2695 int vtkLSDynaReader::ReadNodeStateInfo( vtkIdType step )
2696 {
2697 LSDynaMetaData* p = this->P;
2698
2699 // Skip global variables for now
2700 p->Fam.SkipToWord( LSDynaFamily::TimeStepSection, step, 1 + p->Dict["NGLBV"] );
2701
2702 // Read nodal data ===========================================================
2703 std::vector<std::string> names;
2704 std::vector<int> cmps;
2705 // Important: push_back in the order these are interleaved on disk
2706 // Note that temperature and deflection are swapped relative to the order they
2707 // are specified in the header section.
2708 const char * aNames[] = {
2709 LS_ARRAYNAME_DEFLECTION,
2710 LS_ARRAYNAME_TEMPERATURE,
2711 LS_ARRAYNAME_VELOCITY,
2712 LS_ARRAYNAME_ACCELERATION,
2713 LS_ARRAYNAME_PRESSURE,
2714 LS_ARRAYNAME_VORTICITY "_X",
2715 LS_ARRAYNAME_VORTICITY "_Y",
2716 LS_ARRAYNAME_VORTICITY "_Z",
2717 LS_ARRAYNAME_RESULTANTVORTICITY,
2718 LS_ARRAYNAME_ENSTROPHY,
2719 LS_ARRAYNAME_HELICITY,
2720 LS_ARRAYNAME_STREAMFUNCTION,
2721 LS_ARRAYNAME_ENTHALPY,
2722 LS_ARRAYNAME_DENSITY,
2723 LS_ARRAYNAME_TURBULENTKE,
2724 LS_ARRAYNAME_DISSIPATION,
2725 LS_ARRAYNAME_EDDYVISCOSITY,
2726 LS_ARRAYNAME_SPECIES_01,
2727 LS_ARRAYNAME_SPECIES_02,
2728 LS_ARRAYNAME_SPECIES_03,
2729 LS_ARRAYNAME_SPECIES_04,
2730 LS_ARRAYNAME_SPECIES_05,
2731 LS_ARRAYNAME_SPECIES_06,
2732 LS_ARRAYNAME_SPECIES_07,
2733 LS_ARRAYNAME_SPECIES_08,
2734 LS_ARRAYNAME_SPECIES_09,
2735 LS_ARRAYNAME_SPECIES_10
2736 };
2737
2738 const char* aDictNames[] = {
2739 "IU",
2740 "IT",
2741 "IV",
2742 "IA",
2743 "cfdPressure",
2744 "cfdXVort",
2745 "cfdYVort",
2746 "cfdZVort",
2747 "cfdRVort",
2748 "cfdEnstrophy",
2749 "cfdHelicity",
2750 "cfdStream",
2751 "cfdEnthalpy",
2752 "cfdDensity",
2753 "cfdTurbKE",
2754 "cfdDiss",
2755 "cfdEddyVisc",
2756 "cfdSpec01",
2757 "cfdSpec02",
2758 "cfdSpec03",
2759 "cfdSpec04",
2760 "cfdSpec05",
2761 "cfdSpec06",
2762 "cfdSpec07",
2763 "cfdSpec08",
2764 "cfdSpec09",
2765 "cfdSpec10"
2766 };
2767 int aComponents[] = {
2768 -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
2769 };
2770 int vppt = 0; // values per point
2771 int allVortPresent = p->Dict["cfdXVort"] && p->Dict["cfdYVort"] && p->Dict["cfdZVort"];
2772
2773 for ( int nvnum = 0; nvnum < (int) (sizeof(aComponents)/sizeof(aComponents[0])); ++nvnum )
2774 {
2775 if ( p->Dict[ aDictNames[nvnum] ] )
2776 {
2777 if ( allVortPresent && ! strncmp( LS_ARRAYNAME_VORTICITY, aNames[ nvnum ], sizeof(LS_ARRAYNAME_VORTICITY) ) )
2778 {
2779 // turn the vorticity components from individual scalars into one vector (with a hack)
2780 if ( nvnum < 7 )
2781 continue;
2782 aComponents[ nvnum ] = 3;
2783 aNames[ nvnum ] = LS_ARRAYNAME_VORTICITY;
2784 }
2785 names.push_back(aNames[ nvnum ]);
2786 cmps.push_back( aComponents[ nvnum ] == -1 ? p->Dimensionality : aComponents[ nvnum ] );
2787 vppt += cmps.back();
2788 }
2789 }
2790
2791 if ( vppt != 0 )
2792 {
2793 for(size_t i=0; i < cmps.size(); i++)
2794 {
2795 // Note, we don't do anything special when reading deflected coordinates here.
2796 // See `ComputeDeflectionAndUpdateGeometry` for computing of deflection and
2797 // updating for geometry if requested to be deformed.
2798 bool valid = this->GetPointArrayStatus( names[i].c_str() ) != 0;
2799 this->Parts->ReadPointProperty(p->NumberOfNodes, cmps[i], names[i].c_str(), valid);
2800 }
2801
2802 //clear the buffer as it will be very large and not needed
2803 p->Fam.ClearBuffer();
2804 }
2805 return 0;
2806 }
2807
2808 //-----------------------------------------------------------------------------
ReadCellStateInfo(vtkIdType vtkNotUsed (step))2809 int vtkLSDynaReader::ReadCellStateInfo( vtkIdType vtkNotUsed(step) )
2810 {
2811
2812 LSDynaMetaData* p = this->P;
2813
2814 // ENN (Total element data for state) = Sum of
2815 // NEL8 (# 8 node solid elems) * NV3D
2816 // NELT (# 8 node thick shell elems) * NV3DT
2817 // NEL2 (# 2 node one-dimensional elems) * NV1D
2818 // NEL4 (# 4 node shells elems) * NV2D
2819 // NMSPH (#of SPH Nodes) * NUM_SPH_VARS
2820 // where:
2821 // NV3D = 7 + NEIPH ( NEIPH = # ALE Data + # Strain Data)
2822 // NV2D = MAXINT* (6*IOSHL(1) + 1*IOSHL(2) + NEIPS) +8*IOSHL(3) + 4*IOSHL(4) + 12*ISTRN
2823 //
2824
2825 // Instead of repeating the specification of what array values are read for each cell type here
2826 // we can use the Property lists which we generated in ReadHeaderInformation().
2827
2828 LSDynaMetaData::LSDYNA_TYPES celltypes[] = {LSDynaMetaData::SOLID, LSDynaMetaData::THICK_SHELL, LSDynaMetaData::BEAM, LSDynaMetaData::SHELL};
2829 vtkIdType cells[] = {p->Dict["NEL8"], p->Dict["NELT"], p->Dict["NEL2"], p->Dict["NEL4"]};
2830 vtkIdType cellVals[] = {p->Dict["NV3D"], p->Dict["NV3DT"], p->Dict["NV1D"], p->Dict["NV2D"]};
2831
2832 // Be careful to exclude arrays which are not part State data
2833 unsigned int firstStateArrayNdx = (p->Dict["NARBS"]>0) ? 1 : 0; // Skip first Array if it is UserIds
2834
2835 for (int i=0; i<4; i++)
2836 {
2837 if (cells[i]>0)
2838 {
2839 LSDynaMetaData::LSDYNA_TYPES celltype = celltypes[i];
2840 int startPos = 0;
2841 for (unsigned int a = firstStateArrayNdx; a < p->CellArrayNames[celltype].size(); a++ )
2842 {
2843 int numComps = this->GetNumberOfComponentsInCellArray(celltype, a);
2844 //std::cout << setw(3) << numComps << " " << this->GetCellArrayName(celltype,a) << std::endl;
2845 if (this->GetCellArrayStatus(celltype, a))
2846 this->Parts->AddProperty(celltype,this->GetCellArrayName(celltype,a), startPos, numComps);
2847 startPos += numComps;
2848 }
2849 this->ReadCellProperties(celltype, cellVals[i]);
2850 }
2851 }
2852
2853 #undef VTK_LS_CELLARRAY
2854 return 0;
2855 }
2856
2857 //-----------------------------------------------------------------------------
ReadCellProperties(const int & type,const int & numTuples)2858 void vtkLSDynaReader::ReadCellProperties(const int& type,const int& numTuples)
2859 {
2860 LSDynaMetaData::LSDYNA_TYPES t =
2861 static_cast<LSDynaMetaData::LSDYNA_TYPES>(type);
2862 vtkIdType numCells,numSkipStart,numSkipEnd;
2863 this->Parts->GetPartReadInfo(type,numCells,numSkipStart,numSkipEnd);
2864
2865 this->P->Fam.SkipWords(numSkipStart * numTuples);
2866 vtkIdType numChunks = this->P->Fam.InitPartialChunkBuffering(numCells,numTuples);
2867 vtkIdType startId = 0;
2868 if(this->P->Fam.GetWordSize() == 8 && numCells > 0)
2869 {
2870 for(vtkIdType i=0; i < numChunks; ++i)
2871 {
2872 //we need offsets!
2873 vtkIdType chunkSize = this->P->Fam.GetNextChunk( LSDynaFamily::Float);
2874 vtkIdType numCellsInChunk = chunkSize/numTuples;
2875 double *dbuf = this->P->Fam.GetBufferAs<double>();
2876 this->Parts->FillCellProperties(dbuf,t,startId,numCellsInChunk,numTuples);
2877 startId += numCellsInChunk;
2878 }
2879 }
2880 else if (numCells > 0)
2881 {
2882 for(vtkIdType i=0; i < numChunks; ++i)
2883 {
2884 vtkIdType chunkSize = this->P->Fam.GetNextChunk( LSDynaFamily::Float);
2885 vtkIdType numCellsInChunk = chunkSize/numTuples;
2886 float *fbuf = this->P->Fam.GetBufferAs<float>();
2887 this->Parts->FillCellProperties(fbuf,t,startId,numCellsInChunk,numTuples);
2888 startId += numCellsInChunk;
2889 }
2890 }
2891 this->P->Fam.SkipWords(numSkipEnd * numTuples);
2892
2893 //clear the buffer as it will be very large and not needed
2894 this->P->Fam.ClearBuffer();
2895 }
2896
2897
ReadSPHState(vtkIdType vtkNotUsed (step))2898 int vtkLSDynaReader::ReadSPHState( vtkIdType vtkNotUsed(step) )
2899 {
2900 LSDynaMetaData* p = this->P;
2901
2902 //Make sure we are at the start of the SPH state data
2903 p->Fam.SkipToWord(LSDynaFamily::TimeStepSection, p->CurrentState,0);
2904 p->Fam.SkipWords(p->SPHStateOffset);
2905
2906 #define VTK_LS_SPHARRAY(cond,celltype,arrayname,numComps)\
2907 if ( (cond) && this->GetCellArrayStatus( celltype, arrayname ) ) \
2908 { \
2909 this->Parts->AddProperty(celltype,arrayname,startPos,numComps); \
2910 } \
2911 if (cond) startPos+=(numComps);
2912
2913 // Smooth Particle ========================================================
2914
2915 // currently have a bug when reading SPH properties disabling for now
2916 int startPos=0; //used to keep track of the startpos between calls to VTK_LS_CELLARRAY
2917 VTK_LS_SPHARRAY( true ,LSDynaMetaData::PARTICLE,LS_ARRAYNAME_MATERIAL,1); //always keep material id / death
2918 VTK_LS_SPHARRAY(p->Dict["isphfg(2)"],LSDynaMetaData::PARTICLE,LS_ARRAYNAME_RADIUSOFINFLUENCE,1);
2919 VTK_LS_SPHARRAY(p->Dict["isphfg(3)"],LSDynaMetaData::PARTICLE,LS_ARRAYNAME_PRESSURE,1);
2920 VTK_LS_SPHARRAY(p->Dict["isphfg(4)"],LSDynaMetaData::PARTICLE,LS_ARRAYNAME_STRESS,6);
2921 VTK_LS_SPHARRAY(p->Dict["isphfg(5)"],LSDynaMetaData::PARTICLE,LS_ARRAYNAME_EPSTRAIN,1);
2922 VTK_LS_SPHARRAY(p->Dict["isphfg(6)"],LSDynaMetaData::PARTICLE,LS_ARRAYNAME_DENSITY,1);
2923 VTK_LS_SPHARRAY(p->Dict["isphfg(7)"],LSDynaMetaData::PARTICLE,LS_ARRAYNAME_INTERNALENERGY,1);
2924 VTK_LS_SPHARRAY(p->Dict["isphfg(8)"],LSDynaMetaData::PARTICLE,LS_ARRAYNAME_NUMNEIGHBORS,1);
2925 VTK_LS_SPHARRAY(p->Dict["isphfg(9)"],LSDynaMetaData::PARTICLE,LS_ARRAYNAME_STRAIN,6);
2926 VTK_LS_SPHARRAY(p->Dict["isphfg(10)"],LSDynaMetaData::PARTICLE,LS_ARRAYNAME_MASS,1);
2927
2928 // std::cout << "NUM_SPH_DATA: " << p->Dict["NUM_SPH_DATA"] << "start Pos is " << startPos << std::endl;
2929 this->ReadCellProperties(LSDynaMetaData::PARTICLE,p->Dict["NUM_SPH_DATA"]);
2930
2931
2932 #undef VTK_LS_SPHARRAY
2933 return 0;
2934 }
2935
ReadUserMaterialIds()2936 int vtkLSDynaReader::ReadUserMaterialIds()
2937 {
2938 LSDynaMetaData* p = this->P;
2939 vtkIdType m, numMats;
2940
2941 p->MaterialsOrdered.clear();
2942 p->MaterialsUnordered.clear();
2943 p->MaterialsLookup.clear();
2944 // Does the file contain arbitrary material IDs?
2945
2946 if ( (p->Dict["NARBS"] > 0) && (p->Dict["NSORT"] < 0))
2947 { // Yes, it does. Read them.
2948
2949
2950 // Skip over arbitrary node and element IDs:
2951 vtkIdType skipIds = p->Dict["NUMNP"] + p->Dict["NEL8"] + p->Dict["NEL2"] + p->Dict["NEL4"] + p->Dict["NELT"];
2952 p->Fam.SkipToWord( LSDynaFamily::UserIdData, p->Fam.GetCurrentAdaptLevel(), 16 + skipIds );
2953
2954 //in some cases the number of materials in NMMAT is incorrect since we are loading
2955 //SPH materials.
2956 numMats = p->Dict["NMMAT"];
2957
2958 // Read in material ID lists:
2959 p->Fam.BufferChunk( LSDynaFamily::Int, numMats*3 );
2960 for ( m=0; m<numMats; ++m )
2961 {
2962 p->MaterialsOrdered.push_back( p->Fam.GetNextWordAsInt() );
2963 }
2964 for ( m=0; m<numMats; ++m )
2965 {
2966 p->MaterialsUnordered.push_back( p->Fam.GetNextWordAsInt() );
2967 }
2968 for ( m=0; m<numMats; ++m )
2969 {
2970 p->MaterialsLookup.push_back( p->Fam.GetNextWordAsInt() );
2971 }
2972
2973 }
2974 else
2975 {
2976 numMats = p->Dict["NUMMAT8"] + p->Dict["NUMMATT"] + p->Dict["NUMMAT4"] + p->Dict["NUMMAT2"] + p->Dict["NGPSPH"];
2977 // No, it doesn't. Fabricate a list of sequential IDs
2978 // construct the (trivial) material lookup tables
2979 for ( m = 1; m <= numMats; ++m )
2980 {
2981 p->MaterialsOrdered.push_back( m );
2982 p->MaterialsUnordered.push_back( m );
2983 p->MaterialsLookup.push_back( m );
2984 }
2985 }
2986 return 0;
2987 }
2988
ReadPartTitlesFromRootFile()2989 int vtkLSDynaReader::ReadPartTitlesFromRootFile()
2990 {
2991 /*
2992 The extra data is written at the end of the following files:
2993 d3plot, d3part and intfor files, and the header and part titles are written directly after the
2994 EOF (= -999999.0) marker.
2995 Value Length Description
2996 -------------------------------
2997
2998 NTYPE 1 entity type = 90001
2999 NUMPROP 1 number of parts
3000
3001 For NUMPROP parts:
3002 IDP 1 part id
3003 PTITLE 18 Part title (72 characters)
3004
3005 For NUMPROP parts:
3006 NTYPE 1 entity type = 90000
3007 HEAD 18 Header title (72 characters)
3008 */
3009
3010 LSDynaMetaData* p = this->P;
3011 if ( p->PreStateSize <= 0 )
3012 {
3013 vtkErrorMacro( "Database has bad pre state size(" << p->PreStateSize << ")." );
3014 return 1;
3015 }
3016
3017 //when called this method is at the right spot to read the part names
3018 vtkIdType currentFileLoc = p->Fam.GetCurrentFWord();
3019 vtkIdType currentAdaptLevel = p->Fam.GetCurrentAdaptLevel();
3020
3021 p->Fam.BufferChunk( LSDynaFamily::Float, 1 );
3022 double eofM = p->Fam.GetNextWordAsFloat();
3023 if(eofM !=LSDynaFamily::EOFMarker)
3024 {
3025 //we failed to find a marker stop on the part names
3026 p->Fam.SkipToWord(LSDynaFamily::ControlSection,currentAdaptLevel,currentFileLoc);
3027 return 1;
3028 }
3029
3030 //make sure that the root files has room left for the amount of data we are going to request
3031 //if it doesn't we know it can't have part names
3032 vtkIdType numParts = static_cast<vtkIdType>(p->PartIds.size());
3033 vtkIdType partTitlesByteSize = p->Fam.GetWordSize() * (2 + numParts); //NType + NUMPRop + (header part ids)
3034 partTitlesByteSize += (numParts * 72); //names are constant at 72 bytes each independent of word size
3035
3036 vtkIdType fileSize = p->Fam.GetFileSize(0);
3037 if ( fileSize < partTitlesByteSize + p->Fam.GetCurrentFWord())
3038 {
3039 //this root file doesn't part names
3040 p->Fam.SkipToWord(LSDynaFamily::ControlSection,currentAdaptLevel,currentFileLoc);
3041 return 1;
3042 }
3043
3044 //we can now safely read the part titles
3045 p->Fam.SkipWords(2); //skip types and num of parts
3046 vtkIdType nameWordSize = 72 / p->Fam.GetWordSize();
3047 for(vtkIdType i=0; i < numParts; ++i)
3048 {
3049 p->Fam.BufferChunk(LSDynaFamily::Int, 1);
3050 p->Fam.GetNextWordAsInt(); //vtkIdType partId
3051
3052 p->Fam.BufferChunk( LSDynaFamily::Char, nameWordSize);
3053 std::string name(p->Fam.GetNextWordAsChars(),72);
3054 if(!name.empty() && name[0]!=' ')
3055 {
3056 //strip the name to the subset that
3057 size_t found = name.find_last_not_of(' ');
3058 if(found != std::string::npos)
3059 {
3060 name = name.substr(0,found+1);
3061 }
3062 //get the right part id
3063 p->PartNames[i] = name;
3064 }
3065 }
3066 p->Fam.SkipToWord(LSDynaFamily::ControlSection,currentAdaptLevel,currentFileLoc);
3067 return 0;
3068 }
3069
ResetPartInfo()3070 void vtkLSDynaReader::ResetPartInfo()
3071 {
3072 LSDynaMetaData* p = this->P;
3073 p->PartNames.clear();
3074 p->PartIds.clear();
3075 p->PartMaterials.clear();
3076 p->PartStatus.clear();
3077
3078 // Create simple part names as place holders
3079 int mat = 1, realMat = 1;
3080 int i;
3081 int N;
3082 char partLabel[64];
3083 int arbitraryMaterials = p->Dict["NSORT"] < 0 ? 1 : 0;
3084
3085 #define VTK_LSDYNA_PARTLABEL(dict,fmt) \
3086 N = p->Dict[dict]; \
3087 for ( i = 0; i < N; ++i, ++mat ) \
3088 { \
3089 if(arbitraryMaterials) \
3090 { \
3091 if(mat < static_cast<int>(p->MaterialsOrdered.size())) \
3092 { \
3093 realMat = p->MaterialsOrdered[mat - 1]; \
3094 } \
3095 else \
3096 { \
3097 realMat = mat; \
3098 } \
3099 snprintf( partLabel, sizeof(partLabel), fmt " (Matl%d)", mat, realMat ); \
3100 } \
3101 else{ \
3102 realMat = mat; \
3103 snprintf( partLabel, sizeof(partLabel), fmt, mat ); \
3104 } \
3105 p->PartNames.push_back( partLabel ); \
3106 p->PartIds.push_back( realMat ); \
3107 p->PartMaterials.push_back( mat ); \
3108 p->PartStatus.push_back( 1 ); \
3109 }
3110
3111 VTK_LSDYNA_PARTLABEL("NUMMAT8","Part%d"); // was "PartSolid%d
3112 VTK_LSDYNA_PARTLABEL("NUMMATT","Part%d"); // was "PartThickShell%d
3113 VTK_LSDYNA_PARTLABEL("NUMMAT4","Part%d"); // was "PartShell%d
3114 VTK_LSDYNA_PARTLABEL("NUMMAT2","Part%d"); // was "PartBeam%d
3115 VTK_LSDYNA_PARTLABEL("NGPSPH", "Part%d"); // was "PartParticle%d
3116 VTK_LSDYNA_PARTLABEL("NSURF", "Part%d"); // was "PartRoadSurface%d
3117 VTK_LSDYNA_PARTLABEL("NUMMAT", "Part%d"); // was "PartRigidBody%d
3118
3119 #undef VTK_LSDYNA_PARTLABEL
3120 }
3121
ReadInputDeck()3122 int vtkLSDynaReader::ReadInputDeck()
3123 {
3124 if ( ! this->InputDeck )
3125 {
3126 // nothing more we can do
3127 return 0;
3128 }
3129
3130 ifstream deck( this->InputDeck, ios::in );
3131 if ( ! deck.good() )
3132 {
3133 return 0;
3134 }
3135
3136 std::string header;
3137 std::getline( deck, header, '\n' );
3138 deck.seekg( 0, ios::beg );
3139 int retval;
3140 if ( vtksys::SystemTools::StringStartsWith( header.c_str(), "<?xml" ) )
3141 {
3142 retval = this->ReadInputDeckXML( deck );
3143 }
3144 else
3145 {
3146 retval = this->ReadInputDeckKeywords( deck );
3147 }
3148
3149 return retval;
3150 }
3151
ReadInputDeckXML(ifstream & deck)3152 int vtkLSDynaReader::ReadInputDeckXML( ifstream& deck )
3153 {
3154 vtkLSDynaSummaryParser* parser = vtkLSDynaSummaryParser::New();
3155 parser->MetaData = this->P;
3156 parser->SetStream( &deck );
3157 // We must be able to parse the file and end up with 1 part per material ID
3158 if ( ! parser->Parse() || this->P->GetTotalMaterialCount() != (int)this->P->PartNames.size() )
3159 {
3160 // We had a problem identifying a part, give up and start over by resetting the parts
3161 this->ResetPartInfo();
3162 }
3163 parser->Delete();
3164
3165 return 0;
3166 }
3167
ReadInputDeckKeywords(ifstream & deck)3168 int vtkLSDynaReader::ReadInputDeckKeywords( ifstream& deck )
3169 {
3170 int success = 1;
3171 std::map<std::string,int> parameters;
3172 std::string line;
3173 std::string lineLowercase;
3174 std::string partName;
3175 int partMaterial;
3176 int partId;
3177 int curPart = 0;
3178
3179 while ( deck.good() && vtkLSNextSignificantLine( deck, line ) && curPart < (int)this->P->PartNames.size() )
3180 {
3181 if ( line[0] == '*' )
3182 {
3183 vtkLSDowncaseFirstWord( lineLowercase, line.substr( 1 ) );
3184 if ( vtksys::SystemTools::StringStartsWith( lineLowercase.c_str(), "part" ) )
3185 {
3186 // found a part
3187 // ... read the next non-comment line as the part name
3188 if ( vtkLSNextSignificantLine( deck, line ) )
3189 {
3190 // Get rid of leading and trailing newlines, whitespace, etc.
3191 vtkLSTrimWhitespace( line );
3192 partName = line;
3193 }
3194 else
3195 {
3196 partName = "";
3197 }
3198 // ... read the next non-comment line as the part id or a reference to it.
3199 if ( vtkLSNextSignificantLine( deck, line ) )
3200 {
3201 std::vector<std::string> splits;
3202 vtkLSSplitString( line, splits, "& ,\t\n\r" );
3203 if ( line[0] == '&' )
3204 {
3205 // found a reference. look it up.
3206 partId = !splits.empty() ? parameters[splits[0]] : -1;
3207 }
3208 else
3209 {
3210 if ( splits.empty() || sscanf( splits[0].c_str(), "%d", &partId ) <= 0 )
3211 {
3212 partId = -1;
3213 }
3214 }
3215 if ( splits.size() < 3 )
3216 {
3217 partMaterial = -1;
3218 }
3219 else
3220 {
3221 if ( splits[2][0] == '&' )
3222 {
3223 partMaterial = parameters[splits[2]];
3224 }
3225 else
3226 {
3227 if ( sscanf( splits[2].c_str(), "%d", &partMaterial ) <= 0 )
3228 {
3229 partMaterial = -1;
3230 }
3231 }
3232 }
3233 } // read the part id or reference
3234 else
3235 {
3236 partId = -1;
3237 partMaterial = -1;
3238 }
3239 // Comment on next line: partId values need not be consecutive. FIXME: ... or even positive?
3240 if ( ! partName.empty() && partId >= 0 )
3241 {
3242 this->P->PartNames[curPart] = partName;
3243 this->P->PartIds[curPart] = partId;
3244 this->P->PartMaterials[curPart] = partMaterial;
3245 this->P->PartStatus[curPart] = 1;
3246 fprintf( stderr, "%2d: Part: \"%s\" Id: %d\n", curPart, partName.c_str(), partId );
3247 ++curPart;
3248 }
3249 else
3250 {
3251 success = 0;
3252 }
3253 }
3254 else if ( vtksys::SystemTools::StringStartsWith( lineLowercase.c_str(), "parameter" ) )
3255 {
3256 // found a reference
3257 // ... read the next non-comment line to decode the reference
3258 if ( vtkLSNextSignificantLine( deck, line ) )
3259 {
3260 std::string paramName;
3261 int paramIntVal;
3262 // Look for "^[IiRr]\s*(\w+)\s+([\w\.-]+)" and set parameters[\2]=\1
3263 if ( line[0] == 'I' || line[0] == 'i' )
3264 { // We found an integer parameter. Those are the only ones we care about.
3265 line = line.substr( 1 );
3266 std::string::size_type paramStart = line.find_first_not_of( " \t," );
3267 if ( paramStart == std::string::npos )
3268 { // ignore a bad parameter line
3269 continue;
3270 }
3271 std::string::size_type paramEnd = line.find_first_of( " \t,", paramStart );
3272 if ( paramEnd == std::string::npos )
3273 { // found the parameter name, but no value after it
3274 continue;
3275 }
3276 paramName = line.substr( paramStart, paramEnd - paramStart );
3277 if ( sscanf( line.substr( paramEnd + 1 ).c_str(), "%d", ¶mIntVal ) <= 0 )
3278 { // unable to read id
3279 continue;
3280 }
3281 parameters[ paramName ] = paramIntVal;
3282 }
3283 }
3284 else
3285 {
3286 // no valid line after "*parameter" keyword. Silently ignore it.
3287 }
3288 } // "parameter line"
3289 } // line starts with "*"
3290 } // while ( deck.good() )
3291
3292 if ( success )
3293 {
3294 // Save a summary file if possible. The user can open the summary file next
3295 // time and not be forced to parse the entire input deck to get part IDs.
3296 std::string deckDir = vtksys::SystemTools::GetFilenamePath( this->InputDeck );
3297 std::string deckName = vtksys::SystemTools::GetFilenameName( this->InputDeck );
3298 std::string deckExt;
3299 std::string::size_type dot;
3300 std::string xmlSummary;
3301
3302 // GetFilenameExtension doesn't look for the rightmost "." ... do it ourselves.
3303 dot = deckName.rfind( '.' );
3304 if ( dot != std::string::npos )
3305 {
3306 deckExt = deckName.substr( dot );
3307 deckName = deckName.substr( 0, dot );
3308 }
3309 else
3310 {
3311 deckExt = "";
3312 }
3313 #ifndef _WIN32
3314 xmlSummary = deckDir + "/" + deckName + ".lsdyna";
3315 #else
3316 xmlSummary = deckDir + "\\" + deckName + ".lsdyna";
3317 #endif // _WIN32
3318 // As long as we don't kill the input deck, write the summary XML:
3319 if ( xmlSummary != this->InputDeck )
3320 {
3321 this->WriteInputDeckSummary( xmlSummary.c_str() );
3322 }
3323 }
3324 else
3325 {
3326 // We had a problem identifying a part, give up and reset part info
3327 this->ResetPartInfo();
3328 }
3329
3330 return ! success;
3331 }
3332
WriteInputDeckSummary(const char * fname)3333 int vtkLSDynaReader::WriteInputDeckSummary( const char* fname )
3334 {
3335 ofstream xmlSummary( fname, ios::out | ios::trunc );
3336 if ( ! xmlSummary.good() )
3337 {
3338 return 1;
3339 }
3340
3341 xmlSummary
3342 << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl
3343 << "<lsdyna>" << endl;
3344
3345 std::string dbDir = this->P->Fam.GetDatabaseDirectory();
3346 std::string dbName = this->P->Fam.GetDatabaseBaseName();
3347 if ( this->IsDatabaseValid() && ! dbDir.empty() && ! dbName.empty() )
3348 {
3349 #ifndef _WIN32
3350 if ( dbDir[0] == '/' )
3351 #else
3352 if ( dbDir[0] == '\\' )
3353 #endif // _WIN32
3354 {
3355 // OK, we have an absolute path, so it should be safe to write it out.
3356 xmlSummary
3357 << " <database path=\"" << dbDir.c_str()
3358 << "\" name=\"" << dbName.c_str() << "\"/>" << endl;
3359 }
3360 }
3361
3362 for ( unsigned p = 0; p < this->P->PartNames.size(); ++p )
3363 {
3364 xmlSummary
3365 << " <part id=\"" << this->P->PartIds[p]
3366 << "\" material_id=\"" << this->P->PartMaterials[p]
3367 << "\" status=\"" << this->P->PartStatus[p]
3368 << "\"><name>" << this->P->PartNames[p].c_str()
3369 << "</name></part>" << endl;
3370 }
3371
3372 xmlSummary
3373 << "</lsdyna>" << endl;
3374
3375 return 0;
3376 }
3377
3378 // ================================================== OK Already! Read the file!
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (iinfo),vtkInformationVector * oinfo)3379 int vtkLSDynaReader::RequestData(
3380 vtkInformation* vtkNotUsed(request),
3381 vtkInformationVector** vtkNotUsed(iinfo),
3382 vtkInformationVector* oinfo )
3383 {
3384 LSDynaMetaData* p = this->P;
3385
3386 if ( ! p->FileIsValid )
3387 {
3388 // This should have been set in RequestInformation()
3389 return 0;
3390 }
3391 p->Fam.ClearBuffer();
3392 p->Fam.OpenFileHandles();
3393
3394 vtkMultiBlockDataSet* mbds = nullptr;
3395 vtkInformation* oi = oinfo->GetInformationObject(0);
3396 if ( ! oi )
3397 {
3398 return 0;
3399 }
3400
3401 if ( oi->Has( vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP() ) )
3402 {
3403 // Only return single time steps for now.
3404 double requestedTimeStep = oi->Get( vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
3405 int timeStepLen = oi->Length( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
3406 double* timeSteps = oi->Get( vtkStreamingDemandDrivenPipeline::TIME_STEPS() );
3407
3408 int cnt = 0;
3409 while ( cnt < timeStepLen - 1 && timeSteps[cnt] < requestedTimeStep )
3410 {
3411 ++cnt;
3412 }
3413 this->SetTimeStep( cnt );
3414
3415 oi->Set( vtkDataObject::DATA_TIME_STEP(), p->TimeValues[ p->CurrentState ] );
3416 }
3417
3418 mbds = vtkMultiBlockDataSet::SafeDownCast( oi->Get(vtkDataObject::DATA_OBJECT()) );
3419 if ( ! mbds )
3420 {
3421 return 0;
3422 }
3423 this->UpdateProgress( 0.01 );
3424
3425 if ( p->Dict["MATTYP"] )
3426 {
3427 // Do something with material type data
3428 }
3429 this->UpdateProgress( 0.05 );
3430
3431 if ( p->Dict["IALEMAT"] )
3432 {
3433 // Do something with fluid material ID data
3434 }
3435 this->UpdateProgress( 0.10 );
3436
3437 if ( p->Dict["NMSPH"] )
3438 {
3439 // Do something with smooth partical hydrodynamics element data
3440 }
3441 this->UpdateProgress( 0.15 );
3442
3443 //Read in the topology information for caching
3444 this->ReadTopology();
3445
3446 // Adapted element parent list
3447 // This isn't even implemented by LS-Dyna yet
3448
3449 // Smooth Particle Hydrodynamics Node and Material List are handled in ReadConnectivityAndMaterial()
3450
3451 // Start of state data ===================
3452 // I. Node and Cell State
3453 this->UpdateProgress( 0.6 );
3454 if ( this->ReadState( p->CurrentState ) )
3455 {
3456 vtkErrorMacro( "Problem reading state data for time step " << p->CurrentState );
3457 return 1;
3458 }
3459
3460 // III. SPH Node State
3461 this->UpdateProgress( 0.7 );
3462 if ( this->GetNumberOfParticleCells() )
3463 {
3464 if ( this->ReadSPHState( p->CurrentState ) )
3465 {
3466 vtkErrorMacro( "Problem reading smooth particle hydrodynamics state." );
3467 return 1;
3468 }
3469 }
3470
3471 this->UpdateProgress( 0.8 );
3472 //add all the parts as child blocks to the output
3473 int size = this->Parts->GetNumberOfParts();
3474 for(int i=0; i < size;++i)
3475 {
3476 if (this->Parts->IsActivePart(i))
3477 {
3478 vtkUnstructuredGrid *ug = this->Parts->GetGridForPart(i);
3479 this->ComputeDeflectionAndUpdateGeometry(ug);
3480
3481 mbds->SetBlock(i,ug);
3482 mbds->GetMetaData(i)->Set(vtkCompositeDataSet::NAME(),
3483 this->P->PartNames[i].c_str());
3484 }
3485 else
3486 {
3487 mbds->SetBlock(i,nullptr);
3488 }
3489 }
3490
3491 this->P->Fam.ClearBuffer();
3492 this->UpdateProgress( 1.0 );
3493 return 1;
3494 }
3495
3496 //-----------------------------------------------------------------------------
3497 template<typename T>
FillDeletionArray(T * buffer,vtkUnsignedCharArray * arr,const vtkIdType & start,const vtkIdType & numCells,const int & deathPos,const int & cellSize)3498 void vtkLSDynaReader::FillDeletionArray(T *buffer, vtkUnsignedCharArray* arr,
3499 const vtkIdType& start, const vtkIdType& numCells,
3500 const int& deathPos, const int& cellSize)
3501 {
3502 unsigned char val;
3503 for ( vtkIdType i=0; i<numCells; ++i )
3504 {
3505 //Quote from LSDyna Manual:
3506 //"each value is set to the element material number or =0,
3507 //if the element is deleted"
3508 val = (buffer[deathPos] == 0.0) ? 1 : 0;
3509 buffer+=cellSize;
3510 arr->SetTuple1(start+i, val);
3511 }
3512 }
3513
3514 //-----------------------------------------------------------------------------
3515 template <int wordSize,typename T>
FillTopology(T * buff)3516 int vtkLSDynaReader::FillTopology(T *buff)
3517 {
3518 //the passed in buffer is null, and only used to specialze the method
3519 //as pure method specialization isn't support by some compilers
3520 //READ PARTICLES
3521 this->P->Fam.SkipToWord(LSDynaFamily::SPHNodeData,
3522 this->P->Fam.GetCurrentAdaptLevel(), 0 );
3523 FillBlock<LSDynaMetaData::PARTICLE,wordSize,1>(buff,this->Parts,this->P,2,
3524 VTK_VERTEX);
3525
3526 //READ SOLIDS
3527 this->P->Fam.SkipToWord(LSDynaFamily::GeometryData,
3528 this->P->Fam.GetCurrentAdaptLevel(),
3529 this->P->NumberOfNodes*this->P->Dimensionality );
3530
3531 //other than buff, these parameters are changed by the template specialization
3532 //as SOLID is a unique case
3533 FillBlock<LSDynaMetaData::SOLID,wordSize,8>(buff,this->Parts,this->P,9,
3534 VTK_HEXAHEDRON);
3535
3536 //READ THICK_SHELL
3537 FillBlock<LSDynaMetaData::THICK_SHELL,wordSize,8>(buff,this->Parts,this->P,9,
3538 VTK_QUADRATIC_QUAD);
3539
3540 //READ BEAM
3541 FillBlock<LSDynaMetaData::BEAM,wordSize,2>(buff,this->Parts,this->P,6,VTK_LINE);
3542
3543 //READ SHELL and RIGID_BODY
3544 //uses a specialization to weave SHELL and RIGID BODY cells together
3545 FillBlock<LSDynaMetaData::SHELL,wordSize,4>(buff,this->Parts,this->P,5,VTK_QUAD);
3546
3547 //Read Road Surface
3548 if ( this->P->ReadRigidRoadMvmt )
3549 {
3550 this->P->Fam.SkipToWord( LSDynaFamily::RigidSurfaceData,
3551 this->P->Fam.GetCurrentAdaptLevel(),
3552 4 + 4*this->P->Dict["NNODE"] );
3553 FillBlock<LSDynaMetaData::ROAD_SURFACE,wordSize,4>(buff,this->Parts,this->P,5,
3554 VTK_QUAD);
3555 }
3556 return 0;
3557 }
3558
3559 //-----------------------------------------------------------------------------
ReadConnectivityAndMaterial()3560 int vtkLSDynaReader::ReadConnectivityAndMaterial()
3561 {
3562 LSDynaMetaData* p = this->P;
3563 if ( p->ConnectivityUnpacked == 0 )
3564 {
3565 // FIXME
3566 vtkErrorMacro( "Packed connectivity isn't supported yet." );
3567 return 1;
3568 }
3569
3570 this->Parts->InitCellInsertion();
3571 if(p->Fam.GetWordSize() == 8)
3572 {
3573 vtkIdType *buf=nullptr;
3574 return this->FillTopology<8>(buf);
3575 }
3576 else
3577 {
3578 int *buf=nullptr;
3579 return this->FillTopology<4>(buf);
3580 }
3581 }
3582
3583 //-----------------------------------------------------------------------------
3584 template<typename T, int blockType, vtkIdType numWordsPerCell, vtkIdType cellLength>
ReadBlockCellSizes()3585 void vtkLSDynaReader::ReadBlockCellSizes()
3586 {
3587 //determine the relationship between the file bit size and
3588 //the host machine bit size. This allows us to read 64 bit files on a
3589 //32 bit machine
3590 const int numWordsPerIdType (this->P->Fam.GetWordSize() / sizeof(T));
3591
3592 vtkIdType nc=0, t=0,j=0,matlId=0;
3593 vtkIdType numCellsToSkip=0, numCellsToSkipEnd=0, chunkSize=0;
3594 const T fileNumWordsPerCell(numWordsPerCell * numWordsPerIdType);
3595 const T offsetToMatId(numWordsPerIdType * (numWordsPerCell-1));
3596 T* buff = nullptr;
3597
3598 //get from the part the read information for this lsdyna block type
3599 this->Parts->GetPartReadInfo(blockType,nc,numCellsToSkip,numCellsToSkipEnd);
3600
3601 this->P->Fam.SkipWords(fileNumWordsPerCell * numCellsToSkip ); //skip to the right start id
3602
3603 //buffer the amount in small chunks so we don't create a massive buffer
3604 vtkIdType numChunks = this->P->Fam.InitPartialChunkBuffering(nc,numWordsPerCell);
3605 for(vtkIdType i=0; i < numChunks; ++i)
3606 {
3607 chunkSize = this->P->Fam.GetNextChunk( LSDynaFamily::Int);
3608 buff = this->P->Fam.GetBufferAs<T>();
3609
3610 for (j=0; j<chunkSize;j+=numWordsPerCell)
3611 {
3612 buff+=offsetToMatId;
3613 matlId = static_cast<vtkIdType>(*buff);
3614 buff+=numWordsPerIdType;
3615 this->Parts->RegisterCellIndexToPart(blockType,matlId,t++,cellLength);
3616 }
3617 }
3618 this->P->Fam.SkipWords(fileNumWordsPerCell * numCellsToSkipEnd);
3619 }
3620
3621 //-----------------------------------------------------------------------------
3622 template <typename T>
FillPartSizes()3623 int vtkLSDynaReader::FillPartSizes()
3624 {
3625 //READ PARTICLES
3626 this->P->Fam.SkipToWord(LSDynaFamily::SPHNodeData,
3627 this->P->Fam.GetCurrentAdaptLevel(), 0 );
3628 this->ReadBlockCellSizes<T,LSDynaMetaData::PARTICLE,2,1>();
3629
3630 //READ SOLIDS
3631 this->P->Fam.SkipToWord(LSDynaFamily::GeometryData,
3632 this->P->Fam.GetCurrentAdaptLevel(),
3633 this->P->NumberOfNodes*this->P->Dimensionality );
3634
3635 this->ReadBlockCellSizes<T,LSDynaMetaData::SOLID,9,8>();
3636
3637 //READ THICK_SHELL
3638 this->ReadBlockCellSizes<T,LSDynaMetaData::THICK_SHELL,9,8>();
3639
3640 //READ BEAM
3641 this->ReadBlockCellSizes<T,LSDynaMetaData::BEAM,6,2>();
3642
3643 //READ SHELL and RIGID_BODY
3644 //uses a specialization to weave SHELL and RIGID BODY cells together
3645 this->ReadBlockCellSizes<T,LSDynaMetaData::SHELL,5,4>();
3646
3647 //Read Road Surface
3648 if ( this->P->ReadRigidRoadMvmt )
3649 {
3650 this->P->Fam.SkipToWord( LSDynaFamily::RigidSurfaceData,
3651 this->P->Fam.GetCurrentAdaptLevel(),
3652 4 + 4*this->P->Dict["NNODE"] );
3653 this->ReadBlockCellSizes<T,LSDynaMetaData::ROAD_SURFACE,5,4>();
3654 }
3655
3656 //now that all the registering is done tell the collection
3657 //it can allocate the necessary space for each part
3658 this->Parts->AllocateParts();
3659 return 0;
3660 }
3661
3662 //-----------------------------------------------------------------------------
ReadPartSizes()3663 int vtkLSDynaReader::ReadPartSizes()
3664 {
3665 LSDynaMetaData* p = this->P;
3666 if ( p->ConnectivityUnpacked == 0 )
3667 {
3668 // FIXME
3669 vtkErrorMacro( "Packed connectivity isn't supported yet." );
3670 return 1;
3671 }
3672
3673 if(p->Fam.GetWordSize() == 8)
3674 {
3675 return this->FillPartSizes<vtkIdType>();
3676 }
3677 else
3678 {
3679 return this->FillPartSizes<int>();
3680 }
3681 }
3682
3683 //-----------------------------------------------------------------------------
SetDeformedMesh(vtkTypeBool deformed)3684 void vtkLSDynaReader::SetDeformedMesh(vtkTypeBool deformed)
3685 {
3686 if (this->DeformedMesh != deformed)
3687 {
3688 this->DeformedMesh = deformed;
3689 this->ResetPartsCache();
3690 this->Modified();
3691 }
3692 }
3693
3694 namespace
3695 {
3696 template <class T, int NumberOfComponents>
vtkComputeDifference(T * aArray,T * bArray)3697 vtkSmartPointer<T> vtkComputeDifference(T* aArray, T* bArray)
3698 {
3699 if (aArray == nullptr || bArray == nullptr)
3700 {
3701 return nullptr;
3702 }
3703
3704 const vtkIdType numTuples = aArray->GetNumberOfTuples();
3705 const int numComps = aArray->GetNumberOfComponents();
3706 if (bArray->GetNumberOfTuples() != numTuples || bArray->GetNumberOfComponents() != numComps ||
3707 numComps != NumberOfComponents)
3708 {
3709 return nullptr;
3710 }
3711
3712 vtkVector<typename T::ValueType, NumberOfComponents> tupleA, tupleB;
3713 vtkSmartPointer<T> result = vtkSmartPointer<T>::New();
3714 result->SetNumberOfComponents(NumberOfComponents);
3715 result->SetNumberOfTuples(numTuples);
3716 for (vtkIdType cc = 0, max = numTuples; cc < max; ++cc)
3717 {
3718 aArray->GetTypedTuple(cc, tupleA.GetData());
3719 bArray->GetTypedTuple(cc, tupleB.GetData());
3720 result->SetTypedTuple(cc, (tupleA - tupleB).GetData());
3721 }
3722 return result;
3723 }
3724 }
3725
3726 //-----------------------------------------------------------------------------
ComputeDeflectionAndUpdateGeometry(vtkUnstructuredGrid * ug)3727 int vtkLSDynaReader::ComputeDeflectionAndUpdateGeometry(vtkUnstructuredGrid* ug)
3728 {
3729 // If LS_ARRAYNAME_DEFLECTION is preset then this computes the deflection.
3730 // If this->DeformedMesh is true, this additionally swaps the output geometry points
3731 // to be the LS_ARRAYNAME_DEFLECTION (which is the deflected coordinates).
3732 LSDynaMetaData* p = this->P;
3733 vtkDataArray* deflectedCoords =
3734 ug ? ug->GetPointData()->GetArray(LS_ARRAYNAME_DEFLECTION) : nullptr;
3735 if (deflectedCoords)
3736 {
3737 vtkSmartPointer<vtkDataArray> deflection;
3738 if (p->Fam.GetWordSize() == 8)
3739 {
3740 deflection =
3741 vtkComputeDifference<vtkDoubleArray, 3>(vtkDoubleArray::SafeDownCast(deflectedCoords),
3742 vtkDoubleArray::SafeDownCast(ug->GetPoints()->GetData()));
3743 }
3744 else
3745 {
3746 deflection =
3747 vtkComputeDifference<vtkFloatArray, 3>(vtkFloatArray::SafeDownCast(deflectedCoords),
3748 vtkFloatArray::SafeDownCast(ug->GetPoints()->GetData()));
3749 }
3750
3751 if (deflection)
3752 {
3753 deflection->SetName("Deflection");
3754 ug->GetPointData()->AddArray(deflection);
3755 }
3756
3757 if (this->DeformedMesh)
3758 {
3759 ug->GetPoints()->SetData(deflectedCoords);
3760 }
3761 }
3762 return EXIT_SUCCESS;
3763 }
3764