/*========================================================================= Program: Visualization Toolkit Module: vtkADIOSWriter.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 #include #include #include #include #include #include "vtkAbstractArray.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkDataArray.h" #include "vtkDataObject.h" #include "vtkDataSet.h" #include "vtkDemandDrivenPipeline.h" #include "vtkFieldData.h" #include "vtkImageData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkLookupTable.h" #include "vtkMPIController.h" #include "vtkMPI.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkPolyData.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkUnstructuredGrid.h" #include "vtkADIOSUtilities.h" #include "ADIOSDefs.h" #include "ADIOSWriter.h" #include "vtkADIOSWriter.h" //---------------------------------------------------------------------------- vtkStandardNewMacro(vtkADIOSWriter); //---------------------------------------------------------------------------- vtkADIOSWriter::vtkADIOSWriter() : FileName(nullptr), TransportMethod(static_cast(ADIOS::TransportMethod_POSIX)), TransportMethodArguments(nullptr), Transform(static_cast(ADIOS::Transform_NONE)), CurrentStep(-1), Controller(nullptr), Writer(nullptr), NumberOfPieces(-1), RequestPiece(-1), NumberOfGhostLevels(-1), WriteAllTimeSteps(false), TimeSteps(), CurrentTimeStepIndex(-1) { std::memset(this->RequestExtent, 0, 6*sizeof(int)); this->SetNumberOfInputPorts(1); this->SetNumberOfOutputPorts(0); this->SetController(vtkMultiProcessController::GetGlobalController()); } //---------------------------------------------------------------------------- vtkADIOSWriter::~vtkADIOSWriter() { delete this->Writer; this->SetFileName(nullptr); this->SetTransportMethodArguments(nullptr); this->SetController(nullptr); } //---------------------------------------------------------------------------- void vtkADIOSWriter::PrintSelf(std::ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "FileName: " << (this->FileName ? this->FileName : "(null)") << std::endl; } //---------------------------------------------------------------------------- const char* vtkADIOSWriter::GetDefaultFileExtension() { static const char ext[] = "vta"; return ext; } //---------------------------------------------------------------------------- void vtkADIOSWriter::SetController(vtkMultiProcessController *controller) { vtkMPIController *mpiController = vtkMPIController::SafeDownCast(controller); if(controller && !mpiController) { vtkErrorMacro("ADIOS Writer can only be used with an MPI controller"); return; } vtkSetObjectBodyMacro(Controller, vtkMultiProcessController, controller); if(mpiController) { vtkMPICommunicator *comm = static_cast( this->Controller->GetCommunicator()); ADIOS::Writer::SetCommunicator(*comm->GetMPIComm()->GetHandle()); this->NumberOfPieces = this->Controller->GetNumberOfProcesses(); this->RequestPiece = this->Controller->GetLocalProcessId(); } else { this->NumberOfPieces = -1; this->RequestPiece = -1; } } //---------------------------------------------------------------------------- template bool vtkADIOSWriter::DefineAndWrite(vtkDataObject *input) { const T *data = T::SafeDownCast(input); if(!data) { return false; } const int localProc = this->Controller->GetLocalProcessId(); try { ++this->CurrentStep; // Make sure we're within time bounds if(this->CurrentTimeStepIndex >= static_cast(this->TimeSteps.size())) { vtkErrorMacro(<< "All timesteps have been exhausted"); return false; } // Things to do on the first step, before writing any data if(this->CurrentStep == 0) { // Before any data can be written, it's structure must be declared this->Define("", data); if(localProc == 0) { // Global time step is only used by Rank 0 this->Writer->DefineScalar("/TimeStamp"); // Define all appropriate attributes this->Writer->DefineAttribute("::NumberOfPieces", this->NumberOfPieces); } } if(localProc == 0) { if(this->CurrentTimeStepIndex >= 0) { this->Writer->WriteScalar("/TimeStamp", this->TimeSteps[this->CurrentTimeStepIndex]); } else { this->Writer->WriteScalar("/TimeStamp", this->CurrentStep); } } this->Write("", data); this->Writer->Commit(this->FileName, this->CurrentStep > 0); } catch(const ADIOS::WriteError &err) { vtkErrorMacro(<< err.what()); return false; } return true; } //---------------------------------------------------------------------------- bool vtkADIOSWriter::WriteInternal(void) { vtkDataObject *input = this->GetInputDataObject(0, 0); if(!input) { return false; } switch(input->GetDataObjectType()) { case VTK_IMAGE_DATA: return this->DefineAndWrite(input); case VTK_POLY_DATA: return this->DefineAndWrite(input); case VTK_UNSTRUCTURED_GRID: return this->DefineAndWrite(input); default: vtkErrorMacro("Input vtkDataObject type not supported by ADIOS writer"); return false; } } //---------------------------------------------------------------------------- int vtkADIOSWriter::FillInputPortInformation(int port, vtkInformation *info) { // Only 1 port if(port != 0) { return 0; } info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkDataObject"); return 1; } //---------------------------------------------------------------------------- int vtkADIOSWriter::ProcessRequest(vtkInformation* request, vtkInformationVector** input, vtkInformationVector* output) { // Make sure the ADIOS subsystem is initialized before processing any // sort of request. if(!this->Writer) { this->Writer = new ADIOS::Writer( static_cast(this->TransportMethod), this->TransportMethodArguments ? this->TransportMethodArguments : ""); } return this->Superclass::ProcessRequest(request, input, output); } //---------------------------------------------------------------------------- int vtkADIOSWriter::RequestInformation(vtkInformation *vtkNotUsed(req), vtkInformationVector **input, vtkInformationVector *vtkNotUsed(output)) { vtkInformation *inInfo = input[0]->GetInformationObject(0); this->TimeSteps.clear(); this->CurrentTimeStepIndex = -1; if(inInfo->Has(vtkStreamingDemandDrivenPipeline::TIME_STEPS())) { int len = inInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); double *steps = inInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); this->TimeSteps.reserve(len); this->TimeSteps.insert(this->TimeSteps.begin(), steps, steps+len); this->CurrentTimeStepIndex = 0; } return 1; } //---------------------------------------------------------------------------- int vtkADIOSWriter::RequestUpdateExtent(vtkInformation *vtkNotUsed(req), vtkInformationVector **input, vtkInformationVector *vtkNotUsed(output)) { vtkInformation* inInfo = input[0]->GetInformationObject(0); inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(), this->NumberOfPieces); inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), this->RequestPiece); if(this->WriteAllTimeSteps && this->CurrentTimeStepIndex >= 0 && this->CurrentTimeStepIndex < static_cast(this->TimeSteps.size())) { inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP(), this->TimeSteps[this->CurrentTimeStepIndex]); } return 1; } //---------------------------------------------------------------------------- int vtkADIOSWriter::RequestData(vtkInformation *req, vtkInformationVector **vtkNotUsed(input), vtkInformationVector *vtkNotUsed(output)) { int numSteps = static_cast(this->TimeSteps.size()); // Make sure the time step is one we know about { vtkDataObject* inDataObject = this->GetInputDataObject(0, 0); vtkInformation *inDataInfo = inDataObject->GetInformation(); if(inDataInfo->Has(vtkDataObject::DATA_TIME_STEP())) { double ts = inDataInfo->Get(vtkDataObject::DATA_TIME_STEP()); std::vector::iterator tsit = std::lower_bound(this->TimeSteps.begin(), this->TimeSteps.end(), ts); if(tsit != this->TimeSteps.end() && *tsit == ts) { this->CurrentTimeStepIndex = std::distance(this->TimeSteps.begin(), tsit); } else { vtkWarningMacro(<< "Unknown timestamp " << ts << " requested."); this->CurrentTimeStepIndex = -1; } } } // Continue looping if we're not at the end if(this->CurrentTimeStepIndex >= 0 && // index of -1 means no steps this->WriteAllTimeSteps && this->CurrentTimeStepIndex < numSteps) { req->Set(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING(), 1); } if(!this->WriteInternal()) { return 0; } if(this->CurrentTimeStepIndex >= 0) { ++this->CurrentTimeStepIndex; // End looping if we're at the end if(this->WriteAllTimeSteps && this->CurrentTimeStepIndex >= numSteps) { req->Remove(vtkStreamingDemandDrivenPipeline::CONTINUE_EXECUTING()); } } return 1; } //---------------------------------------------------------------------------- void vtkADIOSWriter::Define(const std::string& path, const vtkAbstractArray* v) { vtkAbstractArray* valueTmp = const_cast(v); // String arrays not currently supported if(valueTmp->GetDataType() == VTK_STRING) { vtkWarningMacro(<< "Skipping string array " << path); return; } this->Writer->DefineScalar(path+"#NC"); this->Writer->DefineScalar(path+"#NT"); std::vector dims; dims.push_back(ADIOS::ArrayDim(path+"#NC")); dims.push_back(ADIOS::ArrayDim(path+"#NT")); this->Writer->DefineLocalArray(path, ADIOS::Type::VTKToADIOS(valueTmp->GetDataType()), dims, static_cast(this->Transform)); } //---------------------------------------------------------------------------- void vtkADIOSWriter::Define(const std::string& path, const vtkDataArray* v) { vtkDataArray* valueTmp = const_cast(v); vtkLookupTable *lut = valueTmp->GetLookupTable(); if(lut) { /* this->Define(path+"/LookupTable", static_cast(lut->GetTable())); this->Define(path+"/Values", static_cast(valueTmp)); */ } else { this->Define(path, static_cast(valueTmp)); } } //---------------------------------------------------------------------------- void vtkADIOSWriter::Define(const std::string& path, const vtkCellArray* v) { this->Writer->DefineScalar(path+"/NumberOfCells"); vtkCellArray *valueTmp = const_cast(v); this->Define(path+"/IndexArray", valueTmp->GetData()); } //---------------------------------------------------------------------------- void vtkADIOSWriter::Define(const std::string& path, const vtkFieldData* v) { vtkFieldData* valueTmp = const_cast(v); for(int i = 0; i < valueTmp->GetNumberOfArrays(); ++i) { vtkDataArray *da = valueTmp->GetArray(i); vtkAbstractArray *aa = da ? da : valueTmp->GetAbstractArray(i); std::string name = aa->GetName(); if(name.empty()) // skip unnamed arrays { vtkWarningMacro(<< "Skipping unnamed array in " << path); continue; } this->Define(path+"/"+name, da ? da : aa); } } //---------------------------------------------------------------------------- void vtkADIOSWriter::Define(const std::string& path, const vtkDataSet* v) { vtkDataSet* valueTmp = const_cast(v); this->Define(path+"/FieldData", valueTmp->GetFieldData()); this->Define(path+"/CellData", valueTmp->GetCellData()); this->Define(path+"/PointData", valueTmp->GetPointData()); } //---------------------------------------------------------------------------- void vtkADIOSWriter::Define(const std::string& path, const vtkImageData* v) { this->Define(path+"/DataSet", static_cast(v)); this->Writer->DefineScalar(path+"/DataObjectType"); this->Writer->DefineScalar(path+"/OriginX"); this->Writer->DefineScalar(path+"/OriginY"); this->Writer->DefineScalar(path+"/OriginZ"); this->Writer->DefineScalar(path+"/SpacingX"); this->Writer->DefineScalar(path+"/SpacingY"); this->Writer->DefineScalar(path+"/SpacingZ"); this->Writer->DefineScalar(path+"/ExtentXMin"); this->Writer->DefineScalar(path+"/ExtentXMax"); this->Writer->DefineScalar(path+"/ExtentYMin"); this->Writer->DefineScalar(path+"/ExtentYMax"); this->Writer->DefineScalar(path+"/ExtentZMin"); this->Writer->DefineScalar(path+"/ExtentZMax"); } //---------------------------------------------------------------------------- void vtkADIOSWriter::Define(const std::string& path, const vtkPolyData* v) { this->Define(path+"/DataSet", static_cast(v)); vtkPolyData *valueTmp = const_cast(v); this->Writer->DefineScalar(path+"/DataObjectType"); vtkPoints *p; if((p = valueTmp->GetPoints())) { this->Define(path+"/Points", p->GetData()); } this->Define(path+"/Verticies", valueTmp->GetVerts()); this->Define(path+"/Lines", valueTmp->GetLines()); this->Define(path+"/Polygons", valueTmp->GetPolys()); this->Define(path+"/Strips", valueTmp->GetStrips()); } //---------------------------------------------------------------------------- void vtkADIOSWriter::Define(const std::string& path, const vtkUnstructuredGrid* v) { this->Define(path+"/DataSet", static_cast(v)); vtkUnstructuredGrid *valueTmp = const_cast(v); this->Writer->DefineScalar(path+"/DataObjectType"); vtkPoints *p; if((p = valueTmp->GetPoints())) { this->Define(path+"/Points", p->GetData()); } vtkUnsignedCharArray *cta = valueTmp->GetCellTypesArray(); vtkIdTypeArray *cla = valueTmp->GetCellLocationsArray(); vtkCellArray *ca = valueTmp->GetCells(); if(cta && cla && ca) { this->Define(path+"/CellTypes", cta); this->Define(path+"/CellLocations", cla); this->Define(path+"/Cells", ca); } } //---------------------------------------------------------------------------- bool vtkADIOSWriter::UpdateMTimeTable(const std::string& path, const vtkObject* value) { vtkMTimeType &mtimeCurrent = this->LastUpdated[path]; vtkMTimeType mtimeNew = const_cast(value)->GetMTime(); vtkMTimeType mtimePrev = mtimeCurrent; mtimeCurrent = mtimeNew; return mtimeNew != mtimePrev; } //---------------------------------------------------------------------------- void vtkADIOSWriter::Write(const std::string& path, const vtkAbstractArray* v) { if(!this->UpdateMTimeTable(path, v)) { return; } vtkAbstractArray* valueTmp = const_cast(v); // String arrays not currently supported if(valueTmp->GetDataType() == VTK_STRING) { return; } size_t nc = valueTmp->GetNumberOfComponents(); size_t nt = valueTmp->GetNumberOfTuples(); this->Writer->WriteScalar(path+"#NC", nc); this->Writer->WriteScalar(path+"#NT", nt); this->Writer->WriteArray(path, valueTmp->GetVoidPointer(0)); } //---------------------------------------------------------------------------- void vtkADIOSWriter::Write(const std::string& path, const vtkDataArray* v) { vtkDataArray* valueTmp = const_cast(v); vtkLookupTable *lut = valueTmp->GetLookupTable(); if(lut) { // Only check the mtime here if a LUT is present. Otherwise it will be // handled appropriately by the abstract array writer if(!this->UpdateMTimeTable(path, v)) { return; } this->Write(path+"/LookupTable", static_cast(lut->GetTable())); this->Write(path+"/Values", static_cast(valueTmp)); } else { this->Write(path, static_cast(valueTmp)); } } //---------------------------------------------------------------------------- void vtkADIOSWriter::Write(const std::string& path, const vtkCellArray* v) { if(!this->UpdateMTimeTable(path, v)) { return; } vtkCellArray* valueTmp = const_cast(v); this->Writer->WriteScalar(path+"/NumberOfCells", valueTmp->GetNumberOfCells()); this->Write(path+"/IndexArray", valueTmp->GetData()); } //---------------------------------------------------------------------------- void vtkADIOSWriter::Write(const std::string& path, const vtkFieldData* v) { if(!this->UpdateMTimeTable(path, v)) { return; } vtkFieldData* valueTmp = const_cast(v); for(int i = 0; i < valueTmp->GetNumberOfArrays(); ++i) { vtkDataArray *da = valueTmp->GetArray(i); vtkAbstractArray *aa = da ? da : valueTmp->GetAbstractArray(i); std::string name = aa->GetName(); if(name.empty()) // skip unnamed arrays { continue; } this->Write(path+"/"+name, da ? da : aa); } } //---------------------------------------------------------------------------- void vtkADIOSWriter::Write(const std::string& path, const vtkDataSet* v) { if(!this->UpdateMTimeTable(path, v)) { return; } vtkDataSet* valueTmp = const_cast(v); this->Write(path+"/FieldData", valueTmp->GetFieldData()); this->Write(path+"/CellData", valueTmp->GetCellData()); this->Write(path+"/PointData", valueTmp->GetPointData()); } //---------------------------------------------------------------------------- void vtkADIOSWriter::Write(const std::string& path, const vtkImageData* v) { if(!this->UpdateMTimeTable(path, v)) { return; } this->Write(path+"/DataSet", static_cast(v)); vtkImageData* valueTmp = const_cast(v); this->Writer->WriteScalar(path+"/DataObjectType", VTK_IMAGE_DATA); double *origin = valueTmp->GetOrigin(); this->Writer->WriteScalar(path+"/OriginX", origin[0]); this->Writer->WriteScalar(path+"/OriginY", origin[1]); this->Writer->WriteScalar(path+"/OriginZ", origin[2]); double *spacing = valueTmp->GetSpacing(); this->Writer->WriteScalar(path+"/SpacingX", spacing[0]); this->Writer->WriteScalar(path+"/SpacingY", spacing[1]); this->Writer->WriteScalar(path+"/SpacingZ", spacing[2]); int *extent = valueTmp->GetExtent(); this->Writer->WriteScalar(path+"/ExtentXMin", extent[0]); this->Writer->WriteScalar(path+"/ExtentXMax", extent[1]); this->Writer->WriteScalar(path+"/ExtentYMin", extent[2]); this->Writer->WriteScalar(path+"/ExtentYMax", extent[3]); this->Writer->WriteScalar(path+"/ExtentZMin", extent[4]); this->Writer->WriteScalar(path+"/ExtentZMax", extent[5]); } //---------------------------------------------------------------------------- void vtkADIOSWriter::Write(const std::string& path, const vtkPolyData* v) { if(!this->UpdateMTimeTable(path, v)) { return; } this->Write(path+"/DataSet", static_cast(v)); vtkPolyData* valueTmp = const_cast(v); this->Writer->WriteScalar(path+"/DataObjectType", VTK_POLY_DATA); vtkPoints *p; if((p = valueTmp->GetPoints())) { this->Write(path+"/Points", p->GetData()); } this->Write(path+"/Verticies", valueTmp->GetVerts()); this->Write(path+"/Lines", valueTmp->GetLines()); this->Write(path+"/Polygons", valueTmp->GetPolys()); this->Write(path+"/Strips", valueTmp->GetStrips()); } //---------------------------------------------------------------------------- void vtkADIOSWriter::Write(const std::string& path, const vtkUnstructuredGrid* v) { if(!this->UpdateMTimeTable(path, v)) { return; } this->Write(path+"/DataSet", static_cast(v)); vtkUnstructuredGrid *valueTmp = const_cast(v); this->Writer->WriteScalar(path+"/DataObjectType", VTK_UNSTRUCTURED_GRID); vtkPoints *p; if((p = valueTmp->GetPoints())) { this->Write(path+"/Points", p->GetData()); } vtkUnsignedCharArray *cta = valueTmp->GetCellTypesArray(); vtkIdTypeArray *cla = valueTmp->GetCellLocationsArray(); vtkCellArray *ca = valueTmp->GetCells(); if(cta && cla && ca) { this->Write(path+"/CellTypes", cta); this->Write(path+"/CellLocations", cla); this->Write(path+"/Cells", ca); } }