diff --git a/IO/ParallelXML/CMakeLists.txt b/IO/ParallelXML/CMakeLists.txt index 9c9a10b54ad19c3f2df75eb7fa90f56db7e8414b..f32a47dc33ac58dbc846f1e19447833f667bea57 100644 --- a/IO/ParallelXML/CMakeLists.txt +++ b/IO/ParallelXML/CMakeLists.txt @@ -6,6 +6,7 @@ set(Module_SRCS vtkXMLPRectilinearGridWriter.cxx vtkXMLPStructuredDataWriter.cxx vtkXMLPStructuredGridWriter.cxx + vtkXMLPTableWriter.cxx vtkXMLPUnstructuredDataWriter.cxx vtkXMLPUnstructuredGridWriter.cxx vtkXMLPHierarchicalBoxDataWriter.cxx diff --git a/IO/ParallelXML/Testing/Python/testParallelXMLWriters.py b/IO/ParallelXML/Testing/Python/testParallelXMLWriters.py index 68d9aff99ce738395b823e6049e52207a99af392..ca844d4d9294c3823b0ad88bdfb69c8efdb872e1 100644 --- a/IO/ParallelXML/Testing/Python/testParallelXMLWriters.py +++ b/IO/ParallelXML/Testing/Python/testParallelXMLWriters.py @@ -17,14 +17,18 @@ pf = vtk.vtkProgrammableFilter() def execute(): info = pf.GetOutputInformation(0) et = vtk.vtkExtentTranslator() - et.SetWholeExtent(info.Get(vtk.vtkStreamingDemandDrivenPipeline.WHOLE_EXTENT())) - et.SetPiece(info.Get(vtk.vtkStreamingDemandDrivenPipeline.UPDATE_PIECE_NUMBER())) - et.SetNumberOfPieces(info.Get(vtk.vtkStreamingDemandDrivenPipeline.UPDATE_NUMBER_OF_PIECES())) - et.PieceToExtent() + + if pf.GetInput().IsA("vtkDataSet"): + et.SetWholeExtent(info.Get(vtk.vtkStreamingDemandDrivenPipeline.WHOLE_EXTENT())) + et.SetPiece(info.Get(vtk.vtkStreamingDemandDrivenPipeline.UPDATE_PIECE_NUMBER())) + et.SetNumberOfPieces(info.Get(vtk.vtkStreamingDemandDrivenPipeline.UPDATE_NUMBER_OF_PIECES())) + et.PieceToExtent() + output = pf.GetOutput() input = pf.GetInput() output.ShallowCopy(input) - output.Crop(et.GetExtent()) + if pf.GetInput().IsA("vtkDataSet"): + output.Crop(et.GetExtent()) pf.SetExecuteMethod(execute) @@ -90,6 +94,26 @@ def GetSource(dataType): pf.SetInputData(sg) return pf + elif dataType == 'Table': + s.Update() + input = s.GetOutput() + + table = vtk.vtkTable() + RTData = input.GetPointData().GetArray(0) + nbTuples = RTData.GetNumberOfTuples() + + array = vtk.vtkFloatArray() + array.SetName("RTData") + array.SetNumberOfTuples(nbTuples) + + for i in range(0, nbTuples): + array.SetTuple1(i, float(RTData.GetTuple1(i))) + + table.AddColumn(array) + + pf.SetInputData(table) + return pf + def TestDataType(dataType, reader, writer, ext, numTris, useSubdir=False): s = GetSource(dataType) @@ -114,17 +138,27 @@ def TestDataType(dataType, reader, writer, ext, numTris, useSubdir=False): reader.SetFileName(filename) - cf = vtk.vtkContourFilter() - cf.SetValue(0, 130) - cf.SetComputeNormals(0) - cf.SetComputeGradients(0) - cf.SetInputConnection(reader.GetOutputPort()) - cf.UpdateInformation() - cf.GetOutputInformation(0).Set(vtk.vtkStreamingDemandDrivenPipeline.UPDATE_NUMBER_OF_PIECES(), nranks) - cf.GetOutputInformation(0).Set(vtk.vtkStreamingDemandDrivenPipeline.UPDATE_PIECE_NUMBER(), rank) - cf.Update() - - ntris = cf.GetOutput().GetNumberOfCells() + ntris = 0 + + if dataType != "Table": + cf = vtk.vtkContourFilter() + cf.SetValue(0, 130) + cf.SetComputeNormals(0) + cf.SetComputeGradients(0) + cf.SetInputConnection(reader.GetOutputPort()) + cf.UpdateInformation() + cf.GetOutputInformation(0).Set(vtk.vtkStreamingDemandDrivenPipeline.UPDATE_NUMBER_OF_PIECES(), nranks) + cf.GetOutputInformation(0).Set(vtk.vtkStreamingDemandDrivenPipeline.UPDATE_PIECE_NUMBER(), rank) + cf.Update() + + ntris = cf.GetOutput().GetNumberOfCells() + else: + reader.UpdateInformation() + reader.GetOutputInformation(0).Set(vtk.vtkStreamingDemandDrivenPipeline.UPDATE_NUMBER_OF_PIECES(), nranks) + reader.GetOutputInformation(0).Set(vtk.vtkStreamingDemandDrivenPipeline.UPDATE_PIECE_NUMBER(), rank) + reader.Update() + ntris = reader.GetOutput().GetNumberOfRows() + da = vtk.vtkIntArray() da.InsertNextValue(ntris) @@ -148,9 +182,11 @@ TestDataType('ImageData', vtk.vtkXMLPImageDataReader(), vtk.vtkXMLPImageDataWrit TestDataType('RectilinearGrid', vtk.vtkXMLPRectilinearGridReader(), vtk.vtkXMLPRectilinearGridWriter(), 'vtr', 4924) TestDataType('StructuredGrid', vtk.vtkXMLPStructuredGridReader(), vtk.vtkXMLPStructuredGridWriter(), 'vts', 4924) TestDataType('UnstructuredGrid', vtk.vtkXMLPUnstructuredGridReader(), vtk.vtkXMLPUnstructuredGridWriter(), 'vtu', 11856) +TestDataType('Table', vtk.vtkXMLPTableReader(), vtk.vtkXMLPTableWriter(), 'vtt', 18522) # Test writers with UseSubdirectory on TestDataType('ImageData', vtk.vtkXMLPImageDataReader(), vtk.vtkXMLPImageDataWriter(), 'vti', 4924, useSubdir=True) TestDataType('RectilinearGrid', vtk.vtkXMLPRectilinearGridReader(), vtk.vtkXMLPRectilinearGridWriter(), 'vtr', 4924, useSubdir=True) TestDataType('StructuredGrid', vtk.vtkXMLPStructuredGridReader(), vtk.vtkXMLPStructuredGridWriter(), 'vts', 4924, useSubdir=True) TestDataType('UnstructuredGrid', vtk.vtkXMLPUnstructuredGridReader(), vtk.vtkXMLPUnstructuredGridWriter(), 'vtu', 11856, useSubdir=True) +TestDataType('Table', vtk.vtkXMLPTableReader(), vtk.vtkXMLPTableWriter(), 'vtt', 18522, useSubdir=True) diff --git a/IO/ParallelXML/vtkXMLPTableWriter.cxx b/IO/ParallelXML/vtkXMLPTableWriter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..22d6b294d41ef8f28720c9526146d79579f5649c --- /dev/null +++ b/IO/ParallelXML/vtkXMLPTableWriter.cxx @@ -0,0 +1,527 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkXMLPTableWriter.cxx + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkXMLPTableWriter.h" + +#include "vtkCallbackCommand.h" +#include "vtkDataSetAttributes.h" +#include "vtkErrorCode.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkMultiProcessController.h" +#include "vtkObjectFactory.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkTable.h" +#include "vtkXMLTableWriter.h" + +#include <vtksys/SystemTools.hxx> + +#include <cassert> + +vtkStandardNewMacro(vtkXMLPTableWriter); +vtkCxxSetObjectMacro(vtkXMLPTableWriter, Controller, vtkMultiProcessController); + +//---------------------------------------------------------------------------- +vtkXMLPTableWriter::vtkXMLPTableWriter() +{ + this->StartPiece = 0; + this->EndPiece = 0; + this->NumberOfPieces = 1; + this->GhostLevel = 0; + this->WriteSummaryFile = 1; + + this->UseSubdirectory = false; + + this->PathName = nullptr; + this->FileNameBase = nullptr; + this->FileNameExtension = nullptr; + this->PieceFileNameExtension = nullptr; + + // Setup a callback for the internal writer to report progress. + this->InternalProgressObserver = vtkCallbackCommand::New(); + this->InternalProgressObserver->SetCallback(&vtkXMLPTableWriter::ProgressCallbackFunction); + this->InternalProgressObserver->SetClientData(this); + + this->Controller = nullptr; + this->SetController(vtkMultiProcessController::GetGlobalController()); + + this->ContinuingExecution = false; + this->CurrentPiece = -1; + this->PieceWrittenFlags = nullptr; +} + +//---------------------------------------------------------------------------- +vtkXMLPTableWriter::~vtkXMLPTableWriter() +{ + delete[] this->PathName; + delete[] this->FileNameBase; + delete[] this->FileNameExtension; + delete[] this->PieceFileNameExtension; + delete[] this->PieceWrittenFlags; + this->SetController(nullptr); + this->InternalProgressObserver->Delete(); +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + os << indent << "NumberOfPieces: " << this->NumberOfPieces << "\n"; + os << indent << "StartPiece: " << this->StartPiece << "\n"; + os << indent << "EndPiece: " << this->EndPiece << "\n"; + os << indent << "GhostLevel: " << this->GhostLevel << "\n"; + os << indent << "WriteSummaryFile: " << this->WriteSummaryFile << "\n"; +} + +//---------------------------------------------------------------------------- +vtkTable* vtkXMLPTableWriter::GetInput() +{ + return vtkTable::SafeDownCast(this->Superclass::GetInput()); +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableWriter::ProcessRequest( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + if (request->Has(vtkStreamingDemandDrivenPipeline::REQUEST_UPDATE_EXTENT())) + { + return this->RequestUpdateExtent(request, inputVector, outputVector); + } + + int retVal = this->Superclass::ProcessRequest(request, inputVector, outputVector); + if (request->Has(vtkDemandDrivenPipeline::REQUEST_DATA())) + { + if (retVal && this->ContinuingExecution) + { + request->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); + } + else + { + request->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); + this->ContinuingExecution = false; + } + } + return retVal; +} + +//---------------------------------------------------------------------------- +const char* vtkXMLPTableWriter::GetDataSetName() +{ + return "PTable"; +} + +//---------------------------------------------------------------------------- +const char* vtkXMLPTableWriter::GetDefaultFileExtension() +{ + return "pvtt"; +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::SetWriteSummaryFile(int flag) +{ + vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting WriteSummaryFile to " + << flag); + if (this->WriteSummaryFile != flag) + { + this->WriteSummaryFile = flag; + this->Modified(); + } +} + +//---------------------------------------------------------------------------- +vtkXMLWriter* vtkXMLPTableWriter::CreatePieceWriter(int index) +{ + // Create the writer for the piece. + vtkXMLTableWriter* pWriter = vtkXMLTableWriter::New(); + pWriter->SetInputConnection(this->GetInputConnection(0, 0)); + pWriter->SetNumberOfPieces(this->NumberOfPieces); + pWriter->SetWritePiece(index); + + return pWriter; +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::WritePData(vtkIndent indent) +{ + vtkTable* input = this->GetInput(); + this->WritePRowData(input->GetRowData(), indent); +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableWriter::RequestUpdateExtent(vtkInformation* vtkNotUsed(request), + vtkInformationVector** inputVector, vtkInformationVector* vtkNotUsed(outputVector)) +{ + vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); + int piece = 0; + if (this->ContinuingExecution) + { + assert(this->CurrentPiece >= this->StartPiece && this->CurrentPiece <= this->EndPiece && + this->CurrentPiece < this->NumberOfPieces); + piece = this->CurrentPiece; + } + else + { + piece = this->StartPiece; + } + + inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), piece); + inInfo->Set( + vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(), this->GetNumberOfPieces()); + inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(), this->GhostLevel); + return 1; +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableWriter::WriteInternal() +{ + bool beginning = (this->ContinuingExecution == false); + bool end = true; + + this->ContinuingExecution = false; + this->CurrentPiece = beginning ? this->StartPiece : this->CurrentPiece; + + assert(this->CurrentPiece >= this->StartPiece && this->CurrentPiece <= this->EndPiece); + end = (this->CurrentPiece == this->EndPiece); + + if (beginning) + { + // Prepare the file name. + this->SplitFileName(); + delete[] this->PieceWrittenFlags; + this->PieceWrittenFlags = new unsigned char[this->NumberOfPieces]; + memset(this->PieceWrittenFlags, 0, sizeof(unsigned char) * this->NumberOfPieces); + + // Prepare the extension. + this->SetupPieceFileNameExtension(); + } + + // Write the current piece. + + // Split progress range by piece. Just assume all pieces are the + // same size. + float progressRange[2] = { 0.f, 0.f }; + this->GetProgressRange(progressRange); + + this->SetProgressRange( + progressRange, this->CurrentPiece - this->StartPiece, this->EndPiece - this->StartPiece + 1); + vtkTable* inputTable = this->GetInput(); + if (inputTable && inputTable->GetNumberOfRows() > 0) + { + if (!this->WritePiece(this->CurrentPiece)) + { + vtkErrorMacro("Could not write the current piece."); + this->DeleteFiles(); + return 0; + } + this->PieceWrittenFlags[this->CurrentPiece] = static_cast<unsigned char>(0x1); + } + + // Write the summary file if requested. + if (end && this->WriteSummaryFile) + { + // Decide whether to write the summary file. + bool writeSummaryLocally = + (this->Controller == nullptr || this->Controller->GetLocalProcessId() == 0); + + // Let subclasses collect information, if any to write the summary file. + this->PrepareSummaryFile(); + + if (writeSummaryLocally) + { + if (!this->Superclass::WriteInternal()) + { + vtkErrorMacro("Ran out of disk space; deleting file(s) already written"); + this->DeleteFiles(); + return 0; + } + } + } + + if (end == false) + { + this->CurrentPiece++; + assert(this->CurrentPiece <= this->EndPiece); + this->ContinuingExecution = true; + } + return 1; +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::PrepareSummaryFile() +{ + if (this->Controller && this->Controller->GetNumberOfProcesses() > 1) + { + assert(this->PieceWrittenFlags != nullptr); + // Reduce information about which pieces were written out to rank 0. + int myId = this->Controller->GetLocalProcessId(); + unsigned char* recvBuffer = (myId == 0) ? new unsigned char[this->NumberOfPieces] : nullptr; + this->Controller->Reduce( + this->PieceWrittenFlags, recvBuffer, this->NumberOfPieces, vtkCommunicator::MAX_OP, 0); + if (myId == 0) + { + std::swap(this->PieceWrittenFlags, recvBuffer); + } + delete[] recvBuffer; + } +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::WritePrimaryElementAttributes(std::ostream& os, vtkIndent indent) +{ + this->WriteScalarAttribute("GhostLevel", this->GhostLevel); +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableWriter::WriteData() +{ + // Write the summary file. + ostream& os = *(this->Stream); + vtkIndent indent = vtkIndent().GetNextIndent(); + vtkIndent nextIndent = indent.GetNextIndent(); + + this->StartFile(); + if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) + { + return 0; + } + + os << indent << "<" << this->GetDataSetName(); + this->WritePrimaryElementAttributes(os, indent); + if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) + { + return 0; + } + os << ">\n"; + + // Write the information needed for a reader to produce the output's + // information during UpdateInformation without reading a piece. + this->WritePData(indent.GetNextIndent()); + if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) + { + return 0; + } + + // Write the elements referencing each piece and its file. + for (int i = 0; i < this->NumberOfPieces; ++i) + { + if (this->PieceWrittenFlags[i] == 0) + { + continue; + } + os << nextIndent << "<Piece"; + this->WritePPieceAttributes(i); + if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) + { + return 0; + } + os << "/>\n"; + } + + os << indent << "</" << this->GetDataSetName() << ">\n"; + + this->EndFile(); + return (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) ? 0 : 1; +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::WritePPieceAttributes(int index) +{ + char* fileName = this->CreatePieceFileName(index); + this->WriteStringAttribute("Source", fileName); + delete[] fileName; +} + +//---------------------------------------------------------------------------- +char* vtkXMLPTableWriter::CreatePieceFileName(int index, const char* path) +{ + std::ostringstream s; + if (path) + { + s << path; + } + s << this->FileNameBase; + if (this->UseSubdirectory) + { + s << "/" << this->FileNameBase; + } + s << "_" << index; + if (this->PieceFileNameExtension) + { + s << this->PieceFileNameExtension; + } + + size_t len = s.str().length(); + char* buffer = new char[len + 1]; + strncpy(buffer, s.str().c_str(), len); + buffer[len] = '\0'; + + return buffer; +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::SplitFileName() +{ + // Split the FileName into its PathName, FileNameBase, and + // FileNameExtension components. + + std::string pathname = vtksys::SystemTools::GetProgramPath(this->FileName); + // Pathname may be empty if FileName is simply a filename without any leading + // "/". + if (!pathname.empty()) + { + pathname += "/"; + } + std::string filename_wo_ext = vtksys::SystemTools::GetFilenameWithoutExtension(this->FileName); + std::string ext = vtksys::SystemTools::GetFilenameExtension(this->FileName); + + delete[] this->PathName; + delete[] this->FileNameBase; + delete[] this->FileNameExtension; + + this->PathName = vtksys::SystemTools::DuplicateString(pathname.c_str()); + this->FileNameBase = vtksys::SystemTools::DuplicateString(filename_wo_ext.c_str()); + this->FileNameExtension = vtksys::SystemTools::DuplicateString(ext.c_str()); +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableWriter::WritePiece(int index) +{ + // Create the writer for the piece. Its configuration should match + // our own writer. + vtkXMLWriter* pWriter = this->CreatePieceWriter(index); + pWriter->AddObserver(vtkCommand::ProgressEvent, this->InternalProgressObserver); + + char* fileName = this->CreatePieceFileName(index, this->PathName); + std::string path = vtksys::SystemTools::GetParentDirectory(fileName); + if (!path.empty() && !vtksys::SystemTools::PathExists(path)) + { + vtksys::SystemTools::MakeDirectory(path); + } + pWriter->SetFileName(fileName); + delete[] fileName; + + // Copy the writer settings. + pWriter->SetDebug(this->Debug); + pWriter->SetCompressor(this->Compressor); + pWriter->SetDataMode(this->DataMode); + pWriter->SetByteOrder(this->ByteOrder); + pWriter->SetEncodeAppendedData(this->EncodeAppendedData); + pWriter->SetHeaderType(this->HeaderType); + pWriter->SetBlockSize(this->BlockSize); + + // Write the piece. + int result = pWriter->Write(); + this->SetErrorCode(pWriter->GetErrorCode()); + + // Cleanup. + pWriter->RemoveObserver(this->InternalProgressObserver); + pWriter->Delete(); + + return result; +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::ProgressCallbackFunction( + vtkObject* caller, unsigned long, void* clientdata, void*) +{ + vtkAlgorithm* w = vtkAlgorithm::SafeDownCast(caller); + if (w) + { + reinterpret_cast<vtkXMLPTableWriter*>(clientdata)->ProgressCallback(w); + } +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::ProgressCallback(vtkAlgorithm* w) +{ + float width = this->ProgressRange[1] - this->ProgressRange[0]; + float internalProgress = w->GetProgress(); + float progress = this->ProgressRange[0] + internalProgress * width; + this->UpdateProgressDiscrete(progress); + if (this->AbortExecute) + { + w->SetAbortExecute(1); + } +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::WritePRowData(vtkDataSetAttributes* ds, vtkIndent indent) +{ + if (ds->GetNumberOfArrays() == 0) + { + return; + } + ostream& os = *(this->Stream); + char** names = this->CreateStringArray(ds->GetNumberOfArrays()); + + os << indent << "<PRowData"; + this->WriteAttributeIndices(ds, names); + if (this->ErrorCode != vtkErrorCode::NoError) + { + this->DestroyStringArray(ds->GetNumberOfArrays(), names); + return; + } + os << ">\n"; + + for (int i = 0; i < ds->GetNumberOfArrays(); ++i) + { + this->WritePArray(ds->GetAbstractArray(i), indent.GetNextIndent(), names[i]); + if (this->ErrorCode != vtkErrorCode::NoError) + { + this->DestroyStringArray(ds->GetNumberOfArrays(), names); + return; + } + } + + os << indent << "</PRowData>\n"; + os.flush(); + if (os.fail()) + { + this->SetErrorCode(vtkErrorCode::GetLastSystemError()); + } + + this->DestroyStringArray(ds->GetNumberOfArrays(), names); +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::DeleteFiles() +{ + for (int i = this->StartPiece; i < this->EndPiece; ++i) + { + char* fileName = this->CreatePieceFileName(i, this->PathName); + this->DeleteAFile(fileName); + delete[] fileName; + } +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableWriter::SetupPieceFileNameExtension() +{ + delete[] this->PieceFileNameExtension; + + // Create a temporary piece writer and then initialize the extension. + vtkXMLWriter* writer = this->CreatePieceWriter(0); + const char* ext = writer->GetDefaultFileExtension(); + this->PieceFileNameExtension = new char[strlen(ext) + 2]; + this->PieceFileNameExtension[0] = '.'; + strcpy(this->PieceFileNameExtension + 1, ext); + writer->Delete(); +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableWriter::FillInputPortInformation(int, vtkInformation* info) +{ + info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTable"); + return 1; +} diff --git a/IO/ParallelXML/vtkXMLPTableWriter.h b/IO/ParallelXML/vtkXMLPTableWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..12f2166ba3c9ff6f2ad5816c784a106264cd554f --- /dev/null +++ b/IO/ParallelXML/vtkXMLPTableWriter.h @@ -0,0 +1,229 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkXMLPTableWriter.h + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/** + * @class vtkXMLPTableWriter + * @brief Write PVTK XML UnstructuredGrid files. + * + * vtkXMLPTableWriter writes the PVTK XML Table + * file format. One table input can be written into a + * parallel file format with any number of pieces spread across files. + * The standard extension for this writer's file format is "pvtt". + * This writer uses vtkXMLTableWriter to write the + * individual piece files. + * + * @sa + * vtkXMLTableWriter +*/ + +#ifndef vtkXMLPTableWriter_h +#define vtkXMLPTableWriter_h + +#include "vtkIOParallelXMLModule.h" // For export macro +#include "vtkXMLWriter.h" + +class vtkCallbackCommand; +class vtkMultiProcessController; +class vtkTable; +class vtkXMLTableWriter; + +class VTKIOPARALLELXML_EXPORT vtkXMLPTableWriter : public vtkXMLWriter +{ +public: + static vtkXMLPTableWriter* New(); + vtkTypeMacro(vtkXMLPTableWriter, vtkXMLWriter); + void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; + + /** + * Get/Set the writer's input. + */ + vtkTable* GetInput(); + + /** + * Get the default file extension for files written by this writer. + */ + const char* GetDefaultFileExtension() VTK_OVERRIDE; + + //@{ + /** + * Get/Set the number of pieces that are being written in parallel. + */ + vtkSetMacro(NumberOfPieces, int); + vtkGetMacro(NumberOfPieces, int); + //@} + + //@{ + /** + * Get/Set the range of pieces assigned to this writer. + */ + vtkSetMacro(StartPiece, int); + vtkGetMacro(StartPiece, int); + vtkSetMacro(EndPiece, int); + vtkGetMacro(EndPiece, int); + //@} + + //@{ + /** + * Get/Set the ghost level used for this writer's piece. + */ + vtkSetMacro(GhostLevel, int); + vtkGetMacro(GhostLevel, int); + //@} + + //@{ + /** + * Get/Set whether to use a subdirectory to store the pieces + */ + vtkSetMacro(UseSubdirectory, bool); + vtkGetMacro(UseSubdirectory, bool); + //@} + + //@{ + /** + * Get/Set whether the writer should write the summary file that + * refers to all of the pieces' individual files. + * This is on by default. Note that only the first process writes + * the summary file. + */ + virtual void SetWriteSummaryFile(int flag); + vtkGetMacro(WriteSummaryFile, int); + vtkBooleanMacro(WriteSummaryFile, int); + //@} + + //@{ + /** + * Controller used to communicate data type of blocks. + * By default, the global controller is used. If you want another + * controller to be used, set it with this. + */ + virtual void SetController(vtkMultiProcessController*); + vtkGetObjectMacro(Controller, vtkMultiProcessController); + //@} + + /** + * Overridden to handle passing the CONTINUE_EXECUTING() flags to the + * executive. + */ + int ProcessRequest(vtkInformation* request, vtkInformationVector** inputVector, + vtkInformationVector* outputVector) VTK_OVERRIDE; + +protected: + vtkXMLPTableWriter(); + ~vtkXMLPTableWriter() VTK_OVERRIDE; + + /** + * see algorithm for more info + */ + int FillInputPortInformation(int port, vtkInformation* info) VTK_OVERRIDE; + + const char* GetDataSetName() VTK_OVERRIDE; + vtkXMLTableWriter* CreateTablePieceWriter(); + + vtkXMLWriter* CreatePieceWriter(int index); + void WritePData(vtkIndent indent); + + /** + * Overridden to make appropriate piece request from upstream. + */ + virtual int RequestUpdateExtent(vtkInformation* request, vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + /** + * Override writing method from superclass. + */ + int WriteInternal() VTK_OVERRIDE; + + /** + * Collect information between ranks before writing the summary file. + * This method is called on all ranks while summary file is only written on 1 + * rank (rank 0). + */ + virtual void PrepareSummaryFile(); + + void WritePrimaryElementAttributes(ostream& os, vtkIndent indent) VTK_OVERRIDE; + int WriteData() VTK_OVERRIDE; + virtual void WritePPieceAttributes(int index); + + char* CreatePieceFileName(int index, const char* path = nullptr); + void SplitFileName(); + virtual int WritePiece(int index); + + /** + * Callback registered with the InternalProgressObserver. + */ + static void ProgressCallbackFunction(vtkObject*, unsigned long, void*, void*); + + /** + * Valid at end of WriteInternal to indicate if we're going to continue + * execution. + */ + vtkGetMacro(ContinuingExecution, bool); + + void WritePRowData(vtkDataSetAttributes* ds, vtkIndent indent); + /** + * Progress callback from internal writer. + */ + + /** + * The observer to report progress from the internal writer. + */ + vtkCallbackCommand* InternalProgressObserver; + + vtkMultiProcessController* Controller; + + virtual void ProgressCallback(vtkAlgorithm* w); + + int StartPiece; + int EndPiece; + int NumberOfPieces; + int GhostLevel; + int WriteSummaryFile; + bool UseSubdirectory; + + char* PathName; + char* FileNameBase; + char* FileNameExtension; + char* PieceFileNameExtension; + +private: + vtkXMLPTableWriter(const vtkXMLPTableWriter&) VTK_DELETE_FUNCTION; + void operator=(const vtkXMLPTableWriter&) VTK_DELETE_FUNCTION; + + /** + * Method used to delete all written files. + */ + void DeleteFiles(); + + /** + * Initializes PieceFileNameExtension. + */ + void SetupPieceFileNameExtension(); + + /** + * Indicates the piece currently being written. + */ + int CurrentPiece; + + /** + * Set in WriteInternal() to request continued execution from the executive to + * write more pieces. + */ + bool ContinuingExecution; + + /** + * Flags used to keep track of which pieces were written out. + */ + unsigned char* PieceWrittenFlags; +}; + +#endif diff --git a/IO/XML/CMakeLists.txt b/IO/XML/CMakeLists.txt index 71afbfe8b4725d893366b98ae06dd9f9e4ba0ddb..5d5e2155a43fcd1d5fa25864f9f39f1a6c7635b4 100644 --- a/IO/XML/CMakeLists.txt +++ b/IO/XML/CMakeLists.txt @@ -25,6 +25,7 @@ set(Module_SRCS vtkXMLPRectilinearGridReader.cxx vtkXMLPStructuredDataReader.cxx vtkXMLPStructuredGridReader.cxx + vtkXMLPTableReader.cxx vtkXMLPUnstructuredDataReader.cxx vtkXMLPUnstructuredGridReader.cxx vtkXMLReader.cxx diff --git a/IO/XML/vtkXMLPTableReader.cxx b/IO/XML/vtkXMLPTableReader.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0fed22796649336f1e78f5500cd943caa1afef52 --- /dev/null +++ b/IO/XML/vtkXMLPTableReader.cxx @@ -0,0 +1,719 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkXMLPTableReader.cxx + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +#include "vtkXMLPTableReader.h" + +#include "vtkCallbackCommand.h" +#include "vtkCellArray.h" +#include "vtkDataArraySelection.h" +#include "vtkDataSetAttributes.h" +#include "vtkXMLDataElement.h" +#include "vtkIdTypeArray.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkObjectFactory.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkTable.h" +#include "vtkXMLTableReader.h" + +#include <cassert> +#include <sstream> + +vtkStandardNewMacro(vtkXMLPTableReader); + +//---------------------------------------------------------------------------- +vtkXMLPTableReader::vtkXMLPTableReader() +{ + this->NumberOfPieces = 0; + + this->PieceElements = nullptr; + this->PieceReaders = nullptr; + this->CanReadPieceFlag = nullptr; + + this->PathName = nullptr; + + this->TotalNumberOfRows = 0; + + // Setup a callback for the internal serial readers to report + // progress. + this->PieceProgressObserver = vtkCallbackCommand::New(); + this->PieceProgressObserver->SetCallback(&vtkXMLPTableReader::PieceProgressCallbackFunction); + this->PieceProgressObserver->SetClientData(this); + + this->ColumnSelection = vtkDataArraySelection::New(); + this->ColumnSelection->AddObserver(vtkCommand::ModifiedEvent, this->SelectionObserver); +} + +//---------------------------------------------------------------------------- +vtkXMLPTableReader::~vtkXMLPTableReader() +{ + if (this->NumberOfPieces) + { + this->DestroyPieces(); + } + delete[] this->PathName; + this->PieceProgressObserver->Delete(); + + this->ColumnSelection->RemoveObserver(this->SelectionObserver); + this->ColumnSelection->Delete(); +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::CopyOutputInformation(vtkInformation* outInfo, int port) +{ + vtkInformation* localInfo = this->GetExecutive()->GetOutputInformation(port); + + if (localInfo->Has(CAN_HANDLE_PIECE_REQUEST())) + { + outInfo->CopyEntry(localInfo, CAN_HANDLE_PIECE_REQUEST()); + } +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + + os << indent << "ColumnSelection: " << this->ColumnSelection << "\n"; +} + +//---------------------------------------------------------------------------- +vtkTable* vtkXMLPTableReader::GetOutput() +{ + return this->GetOutput(0); +} + +//---------------------------------------------------------------------------- +vtkTable* vtkXMLPTableReader::GetOutput(int idx) +{ + return vtkTable::SafeDownCast(this->GetOutputDataObject(idx)); +} + +//---------------------------------------------------------------------------- +const char* vtkXMLPTableReader::GetDataSetName() +{ + return "PTable"; +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::GetOutputUpdateExtent(int& piece, int& numberOfPieces) +{ + vtkInformation* outInfo = this->GetCurrentOutputInformation(); + piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()); + numberOfPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()); +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::SetupOutputTotals() +{ + this->TotalNumberOfRows = 0; + for (int i = this->StartPiece; i < this->EndPiece; ++i) + { + if (this->PieceReaders[i]) + { + this->TotalNumberOfRows += this->PieceReaders[i]->GetNumberOfRows(); + } + } + this->StartRow = 0; +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::SetupOutputData() +{ + this->Superclass::SetupOutputData(); + + // Setup the output arrays. + vtkTable* output = vtkTable::SafeDownCast(this->GetCurrentOutput()); + vtkDataSetAttributes* rowData = output->GetRowData(); + + // Get the size of the output arrays. + unsigned long rowTuples = this->GetNumberOfRows(); + + // Allocate data in the arrays. + if (this->PRowElement) + { + for (int i = 0; i < this->PRowElement->GetNumberOfNestedElements(); ++i) + { + vtkXMLDataElement* eNested = this->PRowElement->GetNestedElement(i); + if (this->ColumnIsEnabled(eNested)) + { + vtkAbstractArray* array = this->CreateArray(eNested); + if (array) + { + array->SetNumberOfTuples(rowTuples); + rowData->AddArray(array); + array->Delete(); + } + else + { + this->DataError = 1; + } + } + } + } + + // Setup attribute indices for the point data and cell data. + this->ReadAttributeIndices(this->PRowElement, rowData); +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::ReadPieceData(int index) +{ + this->Piece = index; + + // We need data, make sure the piece can be read. + if (!this->CanReadPiece(this->Piece)) + { + vtkErrorMacro("File for piece " << this->Piece << " cannot be read."); + return 0; + } + + // Actually read the data. + this->PieceReaders[this->Piece]->SetAbortExecute(0); + vtkDataArraySelection* pds = this->PieceReaders[this->Piece]->GetPointDataArraySelection(); + vtkDataArraySelection* cds = this->PieceReaders[this->Piece]->GetCellDataArraySelection(); + pds->CopySelections(this->PointDataArraySelection); + cds->CopySelections(this->CellDataArraySelection); + return this->ReadPieceData(); +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::CanReadPiece(int index) +{ + // If necessary, test whether the piece can be read. + vtkXMLTableReader* reader = this->PieceReaders[index]; + if (reader && !this->CanReadPieceFlag[index]) + { + if (reader->CanReadFile(reader->GetFileName())) + { + // We can read the piece. Save result to avoid later repeat of + // test. + this->CanReadPieceFlag[index] = 1; + } + else + { + // We cannot read the piece. Destroy the reader to avoid later + // repeat of test. + this->PieceReaders[index] = nullptr; + reader->Delete(); + } + } + + return (this->PieceReaders[index] ? 1 : 0); +} + +//---------------------------------------------------------------------------- +char* vtkXMLPTableReader::CreatePieceFileName(const char* fileName) +{ + assert(fileName); + + std::ostringstream fn_with_warning_C4701; + + // only prepend the path if the given file name is not + // absolute (i.e. doesn't start with '/') + if (this->PathName && fileName[0] != '/') + { + fn_with_warning_C4701 << this->PathName; + } + fn_with_warning_C4701 << fileName; + + size_t len = fn_with_warning_C4701.str().length(); + char* buffer = new char[len + 1]; + strncpy(buffer, fn_with_warning_C4701.str().c_str(), len); + buffer[len] = '\0'; + + return buffer; +} +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::SplitFileName() +{ + if (!this->FileName) + { + vtkErrorMacro(<< "Need to specify a filename"); + return; + } + + // Pull the PathName component out of the FileName. + size_t length = strlen(this->FileName); + char* fileName = new char[length + 1]; + strcpy(fileName, this->FileName); + char* begin = fileName; + char* end = fileName + length; + char* s; + +#if defined(_WIN32) + // Convert to UNIX-style slashes. + for (s = begin; s != end; ++s) + { + if (*s == '\\') + { + *s = '/'; + } + } +#endif + + // Extract the path name up to the last '/'. + delete[] this->PathName; + this->PathName = nullptr; + char* rbegin = end - 1; + char* rend = begin - 1; + for (s = rbegin; s != rend; --s) + { + if (*s == '/') + { + break; + } + } + if (s >= begin) + { + length = (s - begin) + 1; + this->PathName = new char[length + 1]; + strncpy(this->PathName, this->FileName, length); + this->PathName[length] = '\0'; + } + + // Cleanup temporary name. + delete[] fileName; +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::PieceProgressCallbackFunction( + vtkObject*, unsigned long, void* clientdata, void*) +{ + reinterpret_cast<vtkXMLPTableReader*>(clientdata)->PieceProgressCallback(); +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::PieceProgressCallback() +{ + float width = this->ProgressRange[1] - this->ProgressRange[0]; + float pieceProgress = this->PieceReaders[this->Piece]->GetProgress(); + float progress = this->ProgressRange[0] + pieceProgress * width; + this->UpdateProgressDiscrete(progress); + if (this->AbortExecute) + { + this->PieceReaders[this->Piece]->SetAbortExecute(1); + } +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::SetupNextPiece() +{ + if (this->PieceReaders[this->Piece]) + { + this->StartRow += this->PieceReaders[this->Piece]->GetNumberOfRows(); + } +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::ReadPieceData() +{ + // Use the internal reader to read the piece. + this->PieceReaders[this->Piece]->UpdatePiece(0, 1, 0); + + vtkTable* input = this->GetPieceInputAsTable(this->Piece); + vtkTable* output = vtkTable::SafeDownCast(this->GetCurrentOutput()); + + // If there are some points, but no PPoints element, report the + // error. + if (!this->PRowElement && (this->GetNumberOfRows() > 0)) + { + vtkErrorMacro("Could not find PRows element with 1 array."); + return 0; + } + + if (!input->GetRowData()) + { + return 0; + } + + // copy any row data + if (input->GetRowData()) + { + int i; + for (i = 0; i < input->GetRowData()->GetNumberOfArrays(); i++) + { + if (this->ColumnSelection->ArrayIsEnabled(input->GetRowData()->GetArrayName(i))) + { + output->GetRowData()->AddArray(input->GetRowData()->GetArray(i)); + } + } + } + + // copy any field data + if (input->GetFieldData()) + { + int i; + for (i = 0; i < input->GetFieldData()->GetNumberOfArrays(); i++) + { + output->GetFieldData()->AddArray(input->GetFieldData()->GetArray(i)); + } + } + + return 1; +} + +//---------------------------------------------------------------------------- +vtkXMLTableReader* vtkXMLPTableReader::CreatePieceReader() +{ + return vtkXMLTableReader::New(); +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::FillOutputPortInformation(int, vtkInformation* info) +{ + info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkTable"); + return 1; +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::RequestInformation( + vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) +{ + vtkInformation* outInfo = outputVector->GetInformationObject(0); + outInfo->Set(CAN_HANDLE_PIECE_REQUEST(), 1); + return this->Superclass::RequestInformation(request, inputVector, outputVector); +} + +//---------------------------------------------------------------------------- +vtkTable* vtkXMLPTableReader::GetOutputAsTable() +{ + return vtkTable::SafeDownCast(this->GetOutputDataObject(0)); +} + +//---------------------------------------------------------------------------- +vtkTable* vtkXMLPTableReader::GetPieceInputAsTable(int piece) +{ + vtkXMLTableReader* reader = this->PieceReaders[piece]; + if (!reader || reader->GetNumberOfOutputPorts() < 1) + { + return nullptr; + } + return static_cast<vtkTable*>(reader->GetExecutive()->GetOutputData(0)); +} + +//---------------------------------------------------------------------------- +vtkIdType vtkXMLPTableReader::GetNumberOfRows() +{ + return this->TotalNumberOfRows; +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::SetupEmptyOutput() +{ + this->GetCurrentOutput()->Initialize(); +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::SetupOutputInformation(vtkInformation* outInfo) +{ + if (this->InformationError) + { + vtkErrorMacro("Should not still be processing output information if have set InformationError"); + return; + } + + // Initialize DataArraySelections to enable all that are present + this->SetDataArraySelections(this->PRowElement, this->ColumnSelection); + + // Setup the Field Information for RowData. We only need the + // information from one piece because all pieces have the same set of arrays. + vtkInformationVector* infoVector = nullptr; + if (!this->SetFieldDataInfo(this->PRowElement, vtkDataObject::FIELD_ASSOCIATION_ROWS, + this->GetNumberOfRows(), infoVector)) + { + return; + } + if (infoVector) + { + infoVector->Delete(); + } + + outInfo->Set(CAN_HANDLE_PIECE_REQUEST(), 1); +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::ReadXMLData() +{ + // Get the update request. + vtkInformation* outInfo = this->GetCurrentOutputInformation(); + int piece = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()); + int numberOfPieces = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()); + + vtkDebugMacro("Updating piece " << piece << " of " << numberOfPieces); + + // Setup the range of pieces that will be read. + this->SetupUpdateExtent(piece, numberOfPieces); + + // If there are no data to read, stop now. + if (this->StartPiece == this->EndPiece) + { + return; + } + + vtkDebugMacro( + "Reading piece range [" << this->StartPiece << ", " << this->EndPiece << ") from file."); + + // Let superclasses read data. This also allocates output data. + this->Superclass::ReadXMLData(); + + // Split current progress range based on fraction contributed by + // each piece. + float progressRange[2] = { 0.f, 0.f }; + this->GetProgressRange(progressRange); + + // Calculate the cumulative fraction of data contributed by each + // piece (for progress). + std::vector<float> fractions(this->EndPiece - this->StartPiece + 1); + fractions[0] = 0; + for (int i = this->StartPiece; i < this->EndPiece; ++i) + { + int index = i - this->StartPiece; + fractions[index + 1] = (fractions[index] + this->GetNumberOfRowsInPiece(i)); + } + if (fractions[this->EndPiece - this->StartPiece] == 0) + { + fractions[this->EndPiece - this->StartPiece] = 1; + } + for (int i = this->StartPiece; i < this->EndPiece; ++i) + { + int index = i - this->StartPiece; + fractions[index + 1] = fractions[index + 1] / fractions[this->EndPiece - this->StartPiece]; + } + + // Read the data needed from each piece. + for (int i = this->StartPiece; (i < this->EndPiece && !this->AbortExecute && !this->DataError); + ++i) + { + // Set the range of progress for this piece. + this->SetProgressRange(progressRange, i - this->StartPiece, fractions.data()); + + if (!this->ReadPieceData(i)) + { + // An error occurred while reading the piece. + this->DataError = 1; + } + this->SetupNextPiece(); + } +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::ReadPrimaryElement(vtkXMLDataElement* ePrimary) +{ + + if (!this->Superclass::ReadPrimaryElement(ePrimary)) + { + return 0; + } + + // Read information about the pieces. + this->PRowElement = nullptr; + int i; + int numNested = ePrimary->GetNumberOfNestedElements(); + int numPieces = 0; + for (i = 0; i < numNested; ++i) + { + vtkXMLDataElement* eNested = ePrimary->GetNestedElement(i); + if (strcmp(eNested->GetName(), "Piece") == 0) + { + ++numPieces; + } + else if (strcmp(eNested->GetName(), "PRowData") == 0) + { + this->PRowElement = eNested; + } + } + this->SetupPieces(numPieces); + int piece = 0; + for (i = 0; i < numNested; ++i) + { + vtkXMLDataElement* eNested = ePrimary->GetNestedElement(i); + if (strcmp(eNested->GetName(), "Piece") == 0) + { + if (!this->ReadPiece(eNested, piece++)) + { + return 0; + } + } + } + + return 1; +} + +void vtkXMLPTableReader::SetupUpdateExtent(int piece, int numberOfPieces) +{ + this->UpdatePiece = piece; + this->UpdateNumberOfPieces = numberOfPieces; + + // If more pieces are requested than available, just return empty + // pieces for the extra ones.s + if (this->UpdateNumberOfPieces > this->NumberOfPieces) + { + this->UpdateNumberOfPieces = this->NumberOfPieces; + } + + // Find the range of pieces to read. + if (this->UpdatePiece < this->UpdateNumberOfPieces) + { + this->StartPiece = ((this->UpdatePiece * this->NumberOfPieces) / this->UpdateNumberOfPieces); + this->EndPiece = + (((this->UpdatePiece + 1) * this->NumberOfPieces) / this->UpdateNumberOfPieces); + } + else + { + this->StartPiece = 0; + this->EndPiece = 0; + } + + // Update the information of the pieces we need. + for (int i = this->StartPiece; i < this->EndPiece; ++i) + { + if (this->CanReadPiece(i)) + { + this->PieceReaders[i]->UpdateInformation(); + vtkXMLTableReader* pReader = this->PieceReaders[i]; + pReader->SetupUpdateExtent(0, 1); + } + } + + // Find the total size of the output. + this->SetupOutputTotals(); +} + +//---------------------------------------------------------------------------- +vtkIdType vtkXMLPTableReader::GetNumberOfRowsInPiece(int piece) +{ + return this->PieceReaders[piece] ? this->PieceReaders[piece]->GetNumberOfRows() : 0; +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::ReadXMLInformation() +{ + // First setup the filename components. + this->SplitFileName(); + + // Now proceed with reading the information. + return this->Superclass::ReadXMLInformation(); +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::SetupPieces(int numPieces) +{ + if (this->NumberOfPieces) + { + this->DestroyPieces(); + } + this->NumberOfPieces = numPieces; + this->PieceElements = new vtkXMLDataElement*[this->NumberOfPieces]; + this->PieceReaders = new vtkXMLTableReader*[this->NumberOfPieces]; + this->CanReadPieceFlag = new int[this->NumberOfPieces]; + int i; + for (i = 0; i < this->NumberOfPieces; ++i) + { + this->PieceElements[i] = nullptr; + this->PieceReaders[i] = nullptr; + this->CanReadPieceFlag[i] = 0; + } +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::DestroyPieces() +{ + int i; + for (i = 0; i < this->NumberOfPieces; ++i) + { + if (this->PieceReaders[i]) + { + this->PieceReaders[i]->RemoveObserver(this->PieceProgressObserver); + this->PieceReaders[i]->Delete(); + } + } + delete[] this->PieceElements; + delete[] this->CanReadPieceFlag; + delete[] this->PieceReaders; + this->PieceElements = nullptr; + this->PieceReaders = nullptr; + this->NumberOfPieces = 0; +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::ReadPiece(vtkXMLDataElement* ePiece, int index) +{ + this->Piece = index; + return this->ReadPiece(ePiece); +} +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::ReadPiece(vtkXMLDataElement* ePiece) +{ + this->PieceElements[this->Piece] = ePiece; + + const char* fileName = ePiece->GetAttribute("Source"); + if (!fileName) + { + vtkErrorMacro("Piece " << this->Piece << " has no Source attribute."); + return 0; + } + + // The file name is relative to the summary file. Convert it to + // something we can use. + char* pieceFileName = this->CreatePieceFileName(fileName); + + vtkXMLTableReader* reader = this->CreatePieceReader(); + this->PieceReaders[this->Piece] = reader; + this->PieceReaders[this->Piece]->AddObserver( + vtkCommand::ProgressEvent, this->PieceProgressObserver); + reader->SetFileName(pieceFileName); + + delete[] pieceFileName; + + return 1; +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::ColumnIsEnabled(vtkXMLDataElement* elementRowData) +{ + const char* name = elementRowData->GetAttribute("Name"); + return (name && this->ColumnSelection->ArrayIsEnabled(name)); +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::GetNumberOfColumnArrays() +{ + return this->ColumnSelection->GetNumberOfArrays(); +} + +//---------------------------------------------------------------------------- +const char* vtkXMLPTableReader::GetColumnArrayName(int index) +{ + return this->ColumnSelection->GetArrayName(index); +} + +//---------------------------------------------------------------------------- +int vtkXMLPTableReader::GetColumnArrayStatus(const char* name) +{ + return this->ColumnSelection->ArrayIsEnabled(name); +} + +//---------------------------------------------------------------------------- +void vtkXMLPTableReader::SetColumnArrayStatus(const char* name, int status) +{ + if (status) + { + this->ColumnSelection->EnableArray(name); + } + else + { + this->ColumnSelection->DisableArray(name); + } +} diff --git a/IO/XML/vtkXMLPTableReader.h b/IO/XML/vtkXMLPTableReader.h new file mode 100644 index 0000000000000000000000000000000000000000..9d9b3d49536cddbf494f7a966e0ef8ccd750e76d --- /dev/null +++ b/IO/XML/vtkXMLPTableReader.h @@ -0,0 +1,228 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkXMLPTableReader.h + + Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + All rights reserved. + See Copyright.txt or http://www.kitware.com/Copyright.htm for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notice for more information. + +=========================================================================*/ +/** + * @class vtkXMLPTableReader + * @brief Read PVTK XML Table files. + * + * vtkXMLPTableReader reads the PVTK XML Table + * file format. This reads the parallel format's summary file and + * then uses vtkXMLTableReader to read data from the + * individual Table piece files. Streaming is supported. + * The standard extension for this reader's file format is "pvtt". + * + * @sa + * vtkXMLTableReader +*/ + +#ifndef vtkXMLPTableReader_h +#define vtkXMLPTableReader_h + +#include "vtkIOXMLModule.h" // For export macro +#include "vtkXMLReader.h" + +//class vtkDataArray; +class vtkTable; +class vtkXMLTableReader; + +class VTKIOXML_EXPORT vtkXMLPTableReader : public vtkXMLReader +{ +public: + vtkTypeMacro(vtkXMLPTableReader,vtkXMLReader); + void PrintSelf(ostream& os, vtkIndent indent) VTK_OVERRIDE; + static vtkXMLPTableReader *New(); + + //@{ + /** + * Get the reader's output. + */ + vtkTable *GetOutput(); + vtkTable *GetOutput(int idx); + //@} + + /** + * For the specified port, copy the information this reader sets up in + * SetupOutputInformation to outInfo + */ + void CopyOutputInformation(vtkInformation *outInfo, int port) VTK_OVERRIDE; + + //@{ + /** + * Get the number of pieces from the summary file being read. + */ + vtkGetMacro(NumberOfPieces, int); + //@} + + //@{ + /** + * Get the number of columns arrays available in the input. + */ + int GetNumberOfColumnArrays(); + //@} + + //@{ + /** + * Get the name of the column with the given index in + * the input. + */ + const char* GetColumnArrayName(int index); + //@} + + //@{ + /** + * Get/Set whether the column array with the given name is to + * be read. + */ + int GetColumnArrayStatus(const char* name); + void SetColumnArrayStatus(const char* name, int status); + //@} + + //@{ + /** + * Get the data array selection tables used to configure which data + * arrays are loaded by the reader. + */ + vtkGetObjectMacro(ColumnSelection, vtkDataArraySelection); + //@} + +protected: + vtkXMLPTableReader(); + ~vtkXMLPTableReader() VTK_OVERRIDE; + + const char* GetDataSetName() VTK_OVERRIDE; + void GetOutputUpdateExtent(int& piece, int& numberOfPieces); + void SetupOutputTotals(); + + void SetupOutputData() VTK_OVERRIDE; + void SetupNextPiece(); + int ReadPieceData(); + + vtkXMLTableReader *CreatePieceReader(); + int FillOutputPortInformation(int, vtkInformation*) VTK_OVERRIDE; + + int RequestInformation(vtkInformation *request, + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) VTK_OVERRIDE; + + + vtkTable* GetOutputAsTable(); + vtkTable* GetPieceInputAsTable(int piece); + vtkIdType GetNumberOfRows(); + + void SetupEmptyOutput() VTK_OVERRIDE; + + /** + * Setup the output's information. + */ + void SetupOutputInformation(vtkInformation *outInfo) VTK_OVERRIDE; + + /** + * Pipeline execute data driver. Called by vtkXMLReader. + */ + void ReadXMLData() VTK_OVERRIDE; + int ReadPrimaryElement(vtkXMLDataElement* ePrimary) VTK_OVERRIDE; + void SetupUpdateExtent(int piece, int numberOfPieces); + + /** + * Get the number of rows in the given piece. Valid after + * UpdateInformation. + */ + virtual vtkIdType GetNumberOfRowsInPiece(int piece); + + /** + * The update request. + */ + int UpdatePiece; + int UpdateNumberOfPieces; + + /** + * The range of pieces from the file that will form the UpdatePiece. + */ + int StartPiece; + int EndPiece; + vtkIdType TotalNumberOfRows; + vtkIdType StartRow; + + /** + * Pipeline execute information driver. Called by vtkXMLReader. + */ + int ReadXMLInformation() VTK_OVERRIDE; + + virtual void SetupPieces(int numPieces); + virtual void DestroyPieces(); + int ReadPiece(vtkXMLDataElement* ePiece, int index); + virtual int ReadPiece(vtkXMLDataElement* ePiece); + int ReadPieceData(int index); + int CanReadPiece(int index); + + char* CreatePieceFileName(const char* fileName); + void SplitFileName(); + + /** + * Callback registered with the PieceProgressObserver. + */ + static void PieceProgressCallbackFunction(vtkObject*, unsigned long, void*, + void*); + virtual void PieceProgressCallback(); + + /** + * Pieces from the input summary file. + */ + int NumberOfPieces; + + /** + * The piece currently being read. + */ + int Piece; + + /** + * The path to the input file without the file name. + */ + char* PathName; + + /** + * Information per-piece. + */ + vtkXMLDataElement** PieceElements; + vtkXMLTableReader** PieceReaders; + int* CanReadPieceFlag; + + /** + * The PRowData element representations. + */ + vtkXMLDataElement* PRowElement; + + /** + * The observer to report progress from reading serial data in each + * piece. + */ + vtkCallbackCommand* PieceProgressObserver; + + /** + * Check whether the given array element is an enabled array. + */ + int ColumnIsEnabled(vtkXMLDataElement* elementRowData); + + int GetNumberOfRowArrays(); + const char* GetRowArrayName(int index); + + + vtkDataArraySelection* ColumnSelection; + +private: + vtkXMLPTableReader(const vtkXMLPTableReader&) VTK_DELETE_FUNCTION; + void operator=(const vtkXMLPTableReader&) VTK_DELETE_FUNCTION; +}; + +#endif