1 /*========================================================================= 2 3 Program: Visualization Toolkit 4 Module: $RCSfile: vtkPPhastaReader.cxx,v $ 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 #include "vtkPPhastaReader.h" 16 17 #include "vtkCellData.h" 18 #include "vtkFieldData.h" 19 #include "vtkInformation.h" 20 #include "vtkInformationVector.h" 21 #include "vtkMultiBlockDataSet.h" 22 #include "vtkMultiPieceDataSet.h" 23 #include "vtkObjectFactory.h" 24 #include "vtkPointData.h" 25 #include "vtkPVXMLElement.h" 26 #include "vtkPVXMLParser.h" 27 #include "vtkPhastaReader.h" 28 #include "vtkSmartPointer.h" 29 #include "vtkStreamingDemandDrivenPipeline.h" 30 #include "vtkUnstructuredGrid.h" 31 32 #include <vtksys/SystemTools.hxx> 33 34 #include <vtkstd/map> 35 #include <vtksys/ios/sstream> 36 37 int NUM_PIECES; 38 int NUM_FILES; 39 int TIME_STEP; 40 char * FILE_PATH; 41 int PART_ID; 42 int FILE_ID; 43 44 double opentime_total = 0.0; 45 46 /* 47 * Modified part is dealing with new phasta data format 48 * SyncIO and rbIO library, contact liun2@cs.rpi.edu 49 * 50 * ------ Ning Liu 51 * ------ Sept. 2010 52 */ 53 54 struct vtkPPhastaReaderInternal 55 { 56 struct TimeStepInfo 57 { 58 int GeomIndex; 59 int FieldIndex; 60 double TimeValue; 61 62 TimeStepInfo() : GeomIndex(-1), FieldIndex(-1), TimeValue(0.0) 63 { 64 } 65 }; 66 67 typedef vtkstd::map<int, TimeStepInfo> TimeStepInfoMapType; 68 TimeStepInfoMapType TimeStepInfoMap; 69 typedef vtkstd::map<int, vtkSmartPointer<vtkUnstructuredGrid> > 70 CachedGridsMapType; 71 CachedGridsMapType CachedGrids; 72 }; 73 74 //---------------------------------------------------------------------------- 75 vtkCxxRevisionMacro(vtkPPhastaReader, "$Revision: 1.6 $"); 76 vtkStandardNewMacro(vtkPPhastaReader); 77 78 //---------------------------------------------------------------------------- 79 vtkPPhastaReader::vtkPPhastaReader() 80 { 81 //this->DebugOn(); // comment out this line when in production 82 this->FileName = 0; 83 84 this->TimeStepIndex = 0; 85 this->ActualTimeStep = 0; 86 87 this->Reader = vtkPhastaReader::New(); 88 89 this->SetNumberOfInputPorts(0); 90 91 this->Parser = 0; 92 93 this->Internal = new vtkPPhastaReaderInternal; 94 95 this->TimeStepRange[0] = 0; 96 this->TimeStepRange[1] = 0; 97 } 98 99 //---------------------------------------------------------------------------- 100 vtkPPhastaReader::~vtkPPhastaReader() 101 { 102 this->Reader->Delete(); 103 this->SetFileName(0); 104 105 if (this->Parser) 106 { 107 this->Parser->Delete(); 108 } 109 110 delete this->Internal; 111 } 112 113 //---------------------------------------------------------------------------- 114 int vtkPPhastaReader::RequestData(vtkInformation*, 115 vtkInformationVector**, 116 vtkInformationVector* outputVector) 117 { 118 vtkDebugMacro("Entering PP RequestData()\n"); 119 // get the data object 120 vtkInformation *outInfo = 121 outputVector->GetInformationObject(0); 122 123 this->ActualTimeStep = this->TimeStepIndex; 124 125 int tsLength = 126 outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); 127 double* steps = 128 outInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); 129 130 // Check if a particular time was requested. 131 if(outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS())) 132 { 133 // Get the requested time step. We only supprt requests of a single time 134 // step in this reader right now 135 double *requestedTimeSteps = 136 outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEPS()); 137 double timeValue = requestedTimeSteps[0]; 138 139 // find the first time value larger than requested time value 140 // this logic could be improved 141 int cnt = 0; 142 while (cnt < tsLength-1 && steps[cnt] < timeValue) 143 { 144 cnt++; 145 } 146 this->ActualTimeStep = cnt; 147 } 148 149 if (this->ActualTimeStep > this->TimeStepRange[1]) 150 { 151 vtkErrorMacro("Timestep index too large."); 152 return 0; 153 } 154 155 // get the current piece being requested 156 int piece = 157 outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()); 158 159 int numProcPieces = 160 outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()); 161 162 // this is actually # of proc 163 vtkDebugMacro(<<"numProcPieces (i.e. # of proc) = "<< numProcPieces); 164 165 if (!this->Parser) 166 { 167 vtkErrorMacro("No parser was created. Cannot read file"); 168 return 0; 169 } 170 171 vtkPVXMLElement* rootElement = this->Parser->GetRootElement(); 172 173 int numPieces; 174 int numFiles, timeStep; 175 if (!rootElement->GetScalarAttribute("number_of_pieces", &numPieces)) 176 { 177 numPieces = 1; 178 } 179 180 if (!rootElement->GetScalarAttribute("number_of_files", &numFiles)) 181 { 182 numFiles = 1; 183 } 184 185 NUM_PIECES=numPieces; 186 NUM_FILES=numFiles; 187 188 vtkDebugMacro(<<"NEW PHT Parameter: number_of_files = "<< numFiles ); 189 190 vtkMultiBlockDataSet *output = vtkMultiBlockDataSet::SafeDownCast( 191 outInfo->Get(vtkDataObject::DATA_OBJECT())); 192 output->SetNumberOfBlocks(1); 193 vtkMultiPieceDataSet* MultiPieceDataSet = vtkMultiPieceDataSet::New(); 194 // the following line was deleted in Ning's version 195 MultiPieceDataSet->SetNumberOfPieces(numPieces); 196 output->SetBlock(0, MultiPieceDataSet); 197 MultiPieceDataSet->Delete(); 198 199 const char* geometryPattern = 0; 200 int geomHasPiece = 0; 201 int geomHasTime = 0; 202 const char* fieldPattern = 0; 203 int fieldHasPiece = 0; 204 int fieldHasTime = 0; 205 206 unsigned int numElements = rootElement->GetNumberOfNestedElements(); 207 for (unsigned int i=0; i<numElements; i++) 208 { 209 vtkPVXMLElement* nested = rootElement->GetNestedElement(i); 210 211 if (strcmp("GeometryFileNamePattern", nested->GetName()) == 0) 212 { 213 geometryPattern = nested->GetAttribute("pattern"); 214 if (!nested->GetScalarAttribute("has_piece_entry", &geomHasPiece)) 215 { 216 geomHasPiece = 0; 217 } 218 if (!nested->GetScalarAttribute("has_time_entry", &geomHasTime)) 219 { 220 geomHasTime = 0; 221 } 222 } 223 224 if (strcmp("FieldFileNamePattern", nested->GetName()) == 0) 225 { 226 fieldPattern = nested->GetAttribute("pattern"); 227 if (!nested->GetScalarAttribute("has_piece_entry", &fieldHasPiece)) 228 { 229 fieldHasPiece = 0; 230 } 231 if (!nested->GetScalarAttribute("has_time_entry", &fieldHasTime)) 232 { 233 fieldHasTime = 0; 234 } 235 } 236 } 237 238 if (!geometryPattern) 239 { 240 vtkErrorMacro("No geometry pattern was specified. Cannot load file"); 241 return 0; 242 } 243 244 if (!fieldPattern) 245 { 246 vtkErrorMacro("No field pattern was specified. Cannot load file"); 247 return 0; 248 } 249 250 char* geom_name = new char [ strlen(geometryPattern) + 60 ]; 251 char* field_name = new char [ strlen(fieldPattern) + 60 ]; 252 253 ////////////////////// 254 int numPiecesPerFile = numPieces/numFiles; 255 ////////////////////// 256 257 // now loop over all of the files that I should load 258 for(int loadingPiece=piece;loadingPiece<numPieces;loadingPiece+=numProcPieces) 259 { 260 TIME_STEP=this->Internal->TimeStepInfoMap[this->ActualTimeStep].FieldIndex; 261 FILE_ID = int(loadingPiece/numPiecesPerFile)+1; // this will be passed to PhastaReader by extern... 262 PART_ID = loadingPiece+1; 263 264 vtkDebugMacro(<<"PP In loop, piece="<< piece <<", loadingPiece+1="<< loadingPiece +1 << ", numPieces="<<numPieces<<", FILE_ID=" << FILE_ID<<", numProcPieces=" << numProcPieces); 265 266 if (geomHasTime && geomHasPiece) 267 { 268 sprintf(geom_name, 269 geometryPattern, 270 this->Internal->TimeStepInfoMap[this->ActualTimeStep].GeomIndex, 271 FILE_ID); 272 } 273 else if (geomHasPiece) 274 { 275 sprintf(geom_name, geometryPattern, FILE_ID); 276 } 277 else if (geomHasTime) 278 { 279 sprintf(geom_name, 280 geometryPattern, 281 this->Internal->TimeStepInfoMap[this->ActualTimeStep].GeomIndex); 282 } 283 else 284 { 285 strcpy(geom_name, geometryPattern); 286 } 287 288 if (fieldHasTime && fieldHasPiece) 289 { 290 sprintf(field_name, 291 fieldPattern, 292 this->Internal->TimeStepInfoMap[this->ActualTimeStep].FieldIndex, 293 // FILE_ID); // don't use file id, otherwise dup geom and field file id will make PhastaReader not update -- jingfu 294 loadingPiece+1); 295 } 296 else if (fieldHasPiece) 297 { 298 sprintf(field_name, fieldPattern, loadingPiece+1); 299 //FILE_ID); 300 } 301 else if (fieldHasTime) 302 { 303 sprintf(field_name, 304 fieldPattern, 305 this->Internal->TimeStepInfoMap[this->ActualTimeStep].FieldIndex); 306 } 307 else 308 { 309 strcpy(geom_name, fieldPattern); 310 } 311 312 vtksys_ios::ostringstream geomFName; 313 vtkstd::string gpath = vtksys::SystemTools::GetFilenamePath(geom_name); 314 if (gpath.empty() || !vtksys::SystemTools::FileIsFullPath(gpath.c_str())) 315 { 316 vtkstd::string path = vtksys::SystemTools::GetFilenamePath(this->FileName); 317 if (!path.empty()) 318 { 319 geomFName << path.c_str() << "/"; 320 } 321 } 322 geomFName << geom_name << ends; 323 this->Reader->SetGeometryFileName(geomFName.str().c_str()); 324 325 vtksys_ios::ostringstream fieldFName; 326 // try to strip out the path of file, if it's a full path file name 327 vtkstd::string fpath = vtksys::SystemTools::GetFilenamePath(field_name); 328 329 /////////////////////////////////////////// 330 FILE_PATH = new char[fpath.size()+1]; 331 strcpy(FILE_PATH,fpath.c_str()); 332 /////////////////////////////////////////// 333 334 if (fpath.empty() || !vtksys::SystemTools::FileIsFullPath(fpath.c_str())) 335 { 336 vtkstd::string path = vtksys::SystemTools::GetFilenamePath(this->FileName); // FileName is the .pht file 337 if (!path.empty()) 338 { 339 ///////////////////////////////////////// 340 delete [] FILE_PATH; 341 FILE_PATH = new char[path.size()+1]; 342 strcpy(FILE_PATH,path.c_str()); 343 ///////////////////////////////////////// 344 fieldFName << path.c_str() << "/"; 345 //std::cout << "something might be wrong here, string path=" << path << ", fieldFName=" << fieldFName<< std::endl; 346 } 347 } 348 fieldFName << field_name << ends; 349 this->Reader->SetFieldFileName(fieldFName.str().c_str()); 350 351 vtkPPhastaReaderInternal::CachedGridsMapType::iterator CachedCopy = 352 this->Internal->CachedGrids.find(loadingPiece); 353 354 // the following "if" was commented out in previous new version (tweaked by Ning) 355 // if there is a cached copy, use that 356 /* 357 if(CachedCopy != this->Internal->CachedGrids.end()) 358 { 359 this->Reader->SetCachedGrid(CachedCopy->second); 360 printf("should use cached copy but can't compile\n"); 361 } 362 */ 363 364 // In order to register etc, Reader need a new executative in every 365 // update call, otherwise it doesn't do anything 366 this->Reader->Update(); 367 // the following "if" was commented out in previous new version (tweaked by Ning) 368 369 /* 370 if(CachedCopy == this->Internal->CachedGrids.end()) 371 { 372 vtkSmartPointer<vtkUnstructuredGrid> cached = 373 vtkSmartPointer<vtkUnstructuredGrid>::New(); 374 cached->ShallowCopy(this->Reader->GetOutput()); 375 cached->GetPointData()->Initialize(); 376 cached->GetCellData()->Initialize(); 377 cached->GetFieldData()->Initialize(); 378 this->Internal->CachedGrids[loadingPiece] = cached; 379 } 380 */ 381 382 vtkSmartPointer<vtkUnstructuredGrid> copy = 383 vtkSmartPointer<vtkUnstructuredGrid>::New(); 384 copy->ShallowCopy(this->Reader->GetOutput()); 385 MultiPieceDataSet->SetPiece(loadingPiece, copy); 386 //MultiPieceDataSet->SetPiece(MultiPieceDataSet->GetNumberOfPieces(),copy); // Ning's version 387 } 388 389 delete [] FILE_PATH; 390 delete [] geom_name; 391 delete [] field_name; 392 393 if (steps) 394 { 395 output->GetInformation()->Set(vtkDataObject::DATA_TIME_STEPS(), 396 steps+this->ActualTimeStep, 1); 397 } 398 399 vtkDebugMacro("End of PP RequestData()\n, total open time is " << opentime_total); 400 // if it's not too many printf, print it out 401 if( numProcPieces < 16) printf("total open time for sync-io is %lf (nf=%d, np=%d)\n", opentime_total, numFiles, numProcPieces); 402 403 return 1; 404 } 405 406 //---------------------------------------------------------------------------- 407 int vtkPPhastaReader::RequestInformation(vtkInformation*, 408 vtkInformationVector**, 409 vtkInformationVector* outputVector) 410 { 411 vtkDebugMacro(<<"In PP requestInformation() -- nothing modified in this func\n"); 412 this->Internal->TimeStepInfoMap.clear(); 413 this->Reader->ClearFieldInfo(); 414 415 vtkInformation *outInfo = 416 outputVector->GetInformationObject(0); 417 418 if (!this->FileName) 419 { 420 vtkErrorMacro("FileName has to be specified."); 421 return 0; 422 } 423 424 if (this->Parser) 425 { 426 this->Parser->Delete(); 427 this->Parser = 0; 428 } 429 430 vtkSmartPointer<vtkPVXMLParser> parser = 431 vtkSmartPointer<vtkPVXMLParser>::New(); 432 433 parser->SetFileName(this->FileName); 434 if (!parser->Parse()) 435 { 436 return 0; 437 } 438 439 vtkPVXMLElement* rootElement = parser->GetRootElement(); 440 if (!rootElement) 441 { 442 vtkErrorMacro("Cannot parse file."); 443 return 0; 444 } 445 446 if (strcmp(rootElement->GetName(), "PhastaMetaFile") != 0) 447 { 448 vtkErrorMacro("This is not a phasta metafile."); 449 return 0; 450 } 451 452 this->Parser = parser; 453 parser->Register(this); 454 455 int numTimeSteps=1; 456 int hasTimeValues = 0; 457 458 unsigned int numElements = rootElement->GetNumberOfNestedElements(); 459 for (unsigned int i=0; i<numElements; i++) 460 { 461 vtkPVXMLElement* nested = rootElement->GetNestedElement(i); 462 if (strcmp("TimeSteps", nested->GetName()) == 0) 463 { 464 if (!nested->GetScalarAttribute("number_of_steps", &numTimeSteps)) 465 { 466 numTimeSteps = 1; 467 } 468 int autoGen; 469 int indexIncr; 470 int startIndex; 471 if (!nested->GetScalarAttribute("auto_generate_indices", &autoGen)) 472 { 473 autoGen = 0; 474 } 475 if (!nested->GetScalarAttribute("increment_index_by", &indexIncr)) 476 { 477 indexIncr = 1; 478 } 479 if (!nested->GetScalarAttribute("start_index", &startIndex)) 480 { 481 startIndex = 0; 482 } 483 double startValue = 0.; 484 double valueIncr = 1.*indexIncr; 485 if (nested->GetScalarAttribute("start_value", &startValue)) 486 { 487 hasTimeValues = 1; 488 } 489 if (nested->GetScalarAttribute("increment_value_by", &valueIncr)) 490 { 491 hasTimeValues = 1; 492 } 493 if (autoGen) 494 { 495 for (int j=0; j<numTimeSteps; j++) 496 { 497 vtkPPhastaReaderInternal::TimeStepInfo& info = 498 this->Internal->TimeStepInfoMap[j]; 499 info.GeomIndex = startIndex; 500 info.FieldIndex = startIndex; 501 info.TimeValue = startValue; 502 startIndex += indexIncr; 503 startValue += valueIncr; 504 } 505 } 506 507 unsigned int numElements2 = nested->GetNumberOfNestedElements(); 508 for (unsigned int j=0; j<numElements2; j++) 509 { 510 vtkPVXMLElement* nested2 = nested->GetNestedElement(j); 511 if (strcmp("TimeStep", nested2->GetName()) == 0) 512 { 513 int index; 514 if (nested2->GetScalarAttribute("index", &index)) 515 { 516 if ( (index+1) > numTimeSteps ) 517 { 518 numTimeSteps = index+1; 519 } 520 vtkPPhastaReaderInternal::TimeStepInfo& info = 521 this->Internal->TimeStepInfoMap[index]; 522 int gIdx; 523 if (nested2->GetScalarAttribute("geometry_index", 524 &gIdx)) 525 { 526 info.GeomIndex = gIdx; 527 } 528 int fIdx; 529 if (nested2->GetScalarAttribute("field_index", 530 &fIdx)) 531 { 532 info.FieldIndex = fIdx; 533 } 534 double val; 535 if (nested2->GetScalarAttribute("value", 536 &val)) 537 { 538 info.TimeValue = val; 539 hasTimeValues = 1; 540 } 541 } 542 } 543 } 544 break; 545 } 546 } 547 548 int numberOfFields=0, numberOfFields2=0; 549 for (unsigned int i=0; i<numElements; i++) 550 { 551 vtkPVXMLElement* nested = rootElement->GetNestedElement(i); 552 if (strcmp("Fields", nested->GetName()) == 0) 553 { 554 if (!nested->GetScalarAttribute("number_of_fields", &numberOfFields)) 555 { 556 numberOfFields = 1; 557 } 558 559 numberOfFields2 = 0; 560 unsigned int numElements2 = nested->GetNumberOfNestedElements(); 561 for (unsigned int j=0; j<numElements2; j++) 562 { 563 vtkPVXMLElement* nested2 = nested->GetNestedElement(j); 564 if (strcmp("Field", nested2->GetName()) == 0) 565 { 566 numberOfFields2++; 567 vtkstd::string paraviewFieldTagStr, dataTypeStr; 568 const char* paraviewFieldTag = 0; 569 paraviewFieldTag = nested2->GetAttribute("paraview_field_tag"); 570 if (!paraviewFieldTag) 571 { 572 vtksys_ios::ostringstream paraviewFieldTagStrStream; 573 paraviewFieldTagStrStream << "Field " << numberOfFields2 << ends; 574 paraviewFieldTagStr = paraviewFieldTagStrStream.str(); 575 paraviewFieldTag = paraviewFieldTagStr.c_str(); 576 } 577 const char* phastaFieldTag = 0; 578 phastaFieldTag = nested2->GetAttribute("phasta_field_tag"); 579 if (!phastaFieldTag) 580 { 581 vtkErrorMacro("No phasta field tag was specified"); 582 return 0; 583 } 584 int index; // 0 as default (for safety) 585 if (!nested2->GetScalarAttribute("start_index_in_phasta_array", &index)) 586 { 587 index = 0; 588 } 589 int numOfComps; // 1 as default (for safety) 590 if (!nested2->GetScalarAttribute("number_of_components", &numOfComps)) 591 { 592 numOfComps = 1; 593 } 594 int dataDependency; // nodal as default 595 if (!nested2->GetScalarAttribute("data_dependency", &dataDependency)) 596 { 597 dataDependency = 0; 598 } 599 const char* dataType = 0; 600 dataType = nested2->GetAttribute("data_type"); 601 if (!dataType) // "double" as default 602 { 603 dataTypeStr = "double"; 604 dataType = dataTypeStr.c_str(); 605 } 606 607 this->Reader->SetFieldInfo(paraviewFieldTag,phastaFieldTag,index,numOfComps,dataDependency,dataType); 608 } 609 } 610 611 if (numberOfFields<numberOfFields2) 612 { 613 numberOfFields = numberOfFields2; 614 } 615 616 break; 617 } 618 } 619 620 if (!numberOfFields2) // by default take "solution" with only flow variables 621 { 622 numberOfFields = 3; 623 this->Reader->SetFieldInfo("pressure","solution",0,1,0,"double"); 624 this->Reader->SetFieldInfo("velocity","solution",1,3,0,"double"); 625 this->Reader->SetFieldInfo("temperature","solution",4,1,0,"double"); 626 } 627 628 int tidx; 629 // Make sure all indices are there 630 for (tidx=1; tidx<numTimeSteps; tidx++) 631 { 632 vtkPPhastaReaderInternal::TimeStepInfoMapType::iterator iter = 633 this->Internal->TimeStepInfoMap.find(tidx); 634 if (iter == this->Internal->TimeStepInfoMap.end()) 635 { 636 vtkErrorMacro("Missing timestep, index=" << tidx); 637 return 0; 638 } 639 } 640 641 if (hasTimeValues) 642 { 643 double* timeSteps = new double[numTimeSteps]; 644 for (tidx=0; tidx<numTimeSteps; tidx++) 645 { 646 timeSteps[tidx] = this->Internal->TimeStepInfoMap[tidx].TimeValue; 647 } 648 outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), 649 timeSteps, 650 numTimeSteps); 651 double timeRange[2]; 652 timeRange[0] = timeSteps[0]; 653 timeRange[1] = timeSteps[numTimeSteps-1]; 654 outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), 655 timeRange, 2); 656 delete[] timeSteps; 657 } 658 659 this->TimeStepRange[0] = 0; 660 this->TimeStepRange[1] = numTimeSteps-1; 661 662 vtkInformation* info = outputVector->GetInformationObject(0); 663 info->Set( 664 vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1); 665 666 return 1; 667 } 668 669 //----------------------------------------------------------------------------- 670 int vtkPPhastaReader::CanReadFile(const char *filename) 671 { 672 vtkSmartPointer<vtkPVXMLParser> parser 673 = vtkSmartPointer<vtkPVXMLParser>::New(); 674 parser->SuppressErrorMessagesOn(); 675 parser->SetFileName(filename); 676 677 // Make sure we can parse the XML metafile. 678 if (!parser->Parse()) return 0; 679 680 // Make sure the XML file has a root element and it is of the right tag. 681 vtkPVXMLElement *rootElement = parser->GetRootElement(); 682 if (!rootElement) return 0; 683 if (strcmp(rootElement->GetName(), "PhastaMetaFile") != 0) return 0; 684 685 // The file clearly is supposed to be a Phasta file. 686 return 1; 687 } 688 689 //---------------------------------------------------------------------------- 690 void vtkPPhastaReader::PrintSelf(ostream& os, vtkIndent indent) 691 { 692 this->Superclass::PrintSelf(os,indent); 693 694 os << indent << "FileName: " 695 << (this->FileName?this->FileName:"(none)") 696 << endl; 697 os << indent << "TimeStepIndex: " << this->TimeStepIndex << endl; 698 os << indent << "TimeStepRange: " 699 << this->TimeStepRange[0] << " " << this->TimeStepRange[1] 700 << endl; 701 } 702 703