/*========================================================================= Program: ParaView Module: vtkPlot3DMetaReader.cxx Copyright (c) Kitware, Inc. All rights reserved. See Copyright.txt or http://www.paraview.org/HTML/Copyright.html 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 "vtkPlot3DMetaReader.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMath.h" #include "vtkMultiBlockDataSet.h" #include "vtkMultiBlockPLOT3DReader.h" #include "vtkObjectFactory.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtksys/FStream.hxx" #include #include #include #include #include "vtk_jsoncpp.h" #define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember)) vtkStandardNewMacro(vtkPlot3DMetaReader); typedef void (vtkPlot3DMetaReader::*Plot3DFunction)(Json::Value* val); struct Plot3DTimeStep { double Time; std::string XYZFile; std::string QFile; std::string FunctionFile; }; struct vtkPlot3DMetaReaderInternals { std::map FunctionMap; std::vector TimeSteps; std::string ResolveFileName(const std::string& metaFileName, std::string fileName) { if (vtksys::SystemTools::FileIsFullPath(fileName.c_str())) { return fileName; } else { std::string path = vtksys::SystemTools::GetFilenamePath(metaFileName); std::vector components; components.push_back(path + "/"); components.push_back(fileName); return vtksys::SystemTools::JoinPath(components); } } }; //------------------------------------------------------------------------------ vtkPlot3DMetaReader::vtkPlot3DMetaReader() { this->SetNumberOfInputPorts(0); this->SetNumberOfOutputPorts(1); this->Reader = vtkMultiBlockPLOT3DReader::New(); this->Reader->AutoDetectFormatOn(); this->FileName = nullptr; this->Internal = new vtkPlot3DMetaReaderInternals; this->Internal->FunctionMap["auto-detect-format"] = &vtkPlot3DMetaReader::SetAutoDetectFormat; this->Internal->FunctionMap["byte-order"] = &vtkPlot3DMetaReader::SetByteOrder; this->Internal->FunctionMap["precision"] = &vtkPlot3DMetaReader::SetPrecision; this->Internal->FunctionMap["multi-grid"] = &vtkPlot3DMetaReader::SetMultiGrid; this->Internal->FunctionMap["format"] = &vtkPlot3DMetaReader::SetFormat; this->Internal->FunctionMap["blanking"] = &vtkPlot3DMetaReader::SetBlanking; this->Internal->FunctionMap["language"] = &vtkPlot3DMetaReader::SetLanguage; this->Internal->FunctionMap["2D"] = &vtkPlot3DMetaReader::Set2D; this->Internal->FunctionMap["R"] = &vtkPlot3DMetaReader::SetR; this->Internal->FunctionMap["gamma"] = &vtkPlot3DMetaReader::SetGamma; this->Internal->FunctionMap["filenames"] = &vtkPlot3DMetaReader::SetFileNames; this->Internal->FunctionMap["functions"] = &vtkPlot3DMetaReader::AddFunctions; this->Internal->FunctionMap["function-names"] = &vtkPlot3DMetaReader::SetFunctionNames; } //------------------------------------------------------------------------------ vtkPlot3DMetaReader::~vtkPlot3DMetaReader() { this->Reader->Delete(); delete this->Internal; delete[] this->FileName; } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::SetAutoDetectFormat(Json::Value* val) { bool value = val->asBool(); if (value) { this->Reader->AutoDetectFormatOn(); } else { this->Reader->AutoDetectFormatOff(); } } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::SetByteOrder(Json::Value* val) { std::string value = val->asString(); if (value == "little") { this->Reader->SetByteOrderToLittleEndian(); } else if (value == "big") { this->Reader->SetByteOrderToBigEndian(); } else { vtkErrorMacro("Unrecognized byte order: " << value.c_str() << ". Valid options are \"little\" and \"big\"." " Setting to little endian"); this->Reader->SetByteOrderToLittleEndian(); } } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::SetLanguage(Json::Value* val) { std::string value = val->asString(); if (value == "fortran") { this->Reader->HasByteCountOn(); } else if (value == "C") { this->Reader->HasByteCountOff(); } else { vtkErrorMacro("Unrecognized language: " << value.c_str() << ". Valid options are \"fortran\" and \"C\"." " Setting to little fortran"); this->Reader->HasByteCountOn(); } } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::SetPrecision(Json::Value* val) { int value = val->asInt(); if (value == 32) { this->Reader->DoublePrecisionOff(); } else if (value == 64) { this->Reader->DoublePrecisionOn(); } else { vtkErrorMacro("Unrecognized precision: " << value << ". Valid options are 32 and 64 (bits)." " Setting to 32 bits"); this->Reader->DoublePrecisionOff(); } } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::SetMultiGrid(Json::Value* val) { bool value = val->asBool(); if (value) { this->Reader->MultiGridOn(); } else { this->Reader->MultiGridOff(); } } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::SetFormat(Json::Value* val) { std::string value = val->asString(); if (value == "binary") { this->Reader->BinaryFileOn(); } else if (value == "ascii") { this->Reader->BinaryFileOff(); } else { vtkErrorMacro("Unrecognized file type: " << value.c_str() << ". Valid options are \"binary\" and \"ascii\"." " Setting to binary"); this->Reader->BinaryFileOn(); } } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::SetBlanking(Json::Value* val) { bool value = val->asBool(); if (value) { this->Reader->IBlankingOn(); } else { this->Reader->IBlankingOff(); } } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::Set2D(Json::Value* val) { bool value = val->asBool(); if (value) { this->Reader->TwoDimensionalGeometryOn(); } else { this->Reader->TwoDimensionalGeometryOff(); } } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::SetR(Json::Value* val) { double R = val->asDouble(); this->Reader->SetR(R); } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::SetGamma(Json::Value* val) { double gamma = val->asDouble(); this->Reader->SetGamma(gamma); } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::AddFunctions(Json::Value* val) { const Json::Value& functions = *val; for (size_t index = 0; index < functions.size(); ++index) { this->Reader->AddFunction(functions[(int)index].asInt()); } } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::SetFileNames(Json::Value* val) { const Json::Value& filenames = *val; for (size_t index = 0; index < filenames.size(); ++index) { const Json::Value& astep = filenames[(int)index]; bool doAdd = true; Plot3DTimeStep aTime; if (!astep.isMember("time")) { vtkErrorMacro("Missing time value in timestep " << index); doAdd = false; } else { aTime.Time = astep["time"].asDouble(); } if (!astep.isMember("xyz")) { vtkErrorMacro("Missing xyz filename in timestep " << index); doAdd = false; } else { std::string xyzfile = astep["xyz"].asString(); aTime.XYZFile = this->Internal->ResolveFileName(this->FileName, xyzfile); } if (astep.isMember("q")) { std::string qfile = astep["q"].asString(); aTime.QFile = this->Internal->ResolveFileName(this->FileName, qfile); } if (astep.isMember("function")) { std::string functionfile = astep["function"].asString(); aTime.FunctionFile = this->Internal->ResolveFileName(this->FileName, functionfile); } if (doAdd) { this->Internal->TimeSteps.push_back(aTime); } } } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::SetFunctionNames(Json::Value* val) { const Json::Value& functionNames = *val; for (size_t index = 0; index < functionNames.size(); ++index) { this->Reader->AddFunctionName(functionNames[(int)index].asString()); } } //------------------------------------------------------------------------------ int vtkPlot3DMetaReader::RequestInformation(vtkInformation* vtkNotUsed(request), vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector) { vtkInformation* outInfo = outputVector->GetInformationObject(0); outInfo->Set(vtkAlgorithm::CAN_HANDLE_PIECE_REQUEST(), 1); this->Internal->TimeSteps.clear(); this->Reader->RemoveAllFunctions(); if (!this->FileName) { vtkErrorMacro("No file name was specified. Cannot execute."); return 0; } vtksys::ifstream file(this->FileName); Json::CharReaderBuilder rbuilder; rbuilder["collectComments"] = true; Json::Value root; std::string formattedErrorMessages; bool parsingSuccessful = Json::parseFromStream(rbuilder, file, &root, &formattedErrorMessages); if (!parsingSuccessful) { // report to the user the failure and their locations in the document. vtkErrorMacro("Failed to parse configuration\n" << formattedErrorMessages); return 0; } Json::Value::Members members = root.getMemberNames(); Json::Value::Members::iterator memberIterator; for (memberIterator = members.begin(); memberIterator != members.end(); ++memberIterator) { std::map::iterator iter = this->Internal->FunctionMap.find(*memberIterator); if (iter != this->Internal->FunctionMap.end()) { Json::Value val = root[*memberIterator]; Plot3DFunction func = iter->second; CALL_MEMBER_FN(*this, func)(&val); } else { vtkErrorMacro( "Syntax error in file. Option \"" << memberIterator->c_str() << "\" is not valid."); } } std::vector::iterator iter; std::vector timeValues; for (iter = this->Internal->TimeSteps.begin(); iter != this->Internal->TimeSteps.end(); ++iter) { timeValues.push_back(iter->Time); } size_t numSteps = timeValues.size(); if (numSteps > 0) { outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_STEPS(), &timeValues[0], (int)numSteps); double timeRange[2]; timeRange[0] = timeValues[0]; timeRange[1] = timeValues[numSteps - 1]; outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange, 2); } return 1; } //------------------------------------------------------------------------------ int vtkPlot3DMetaReader::RequestData( vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector) { vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkMultiBlockDataSet* output = vtkMultiBlockDataSet::GetData(outputVector->GetInformationObject(0)); double timeValue = 0; if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP())) { // Get the requested time step. We only support requests of a single time // step in this reader right now timeValue = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()); } int tsLength = outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); double* steps = outInfo->Get(vtkStreamingDemandDrivenPipeline::TIME_STEPS()); if (tsLength < 1) { vtkErrorMacro("No timesteps were found. Please specify at least one " "filenames entry in the input file."); return 0; } // find the first time value larger than requested time value // this logic could be improved int cnt = 0; while (cnt < tsLength - 1 && steps[cnt] < timeValue) { cnt++; } int updateTime = cnt; if (updateTime >= tsLength) { updateTime = tsLength - 1; } if (tsLength > updateTime) { this->Reader->SetXYZFileName(this->Internal->TimeSteps[updateTime].XYZFile.c_str()); const char* qname = this->Internal->TimeSteps[updateTime].QFile.c_str(); if (strlen(qname) > 0) { this->Reader->SetQFileName(qname); } else { this->Reader->SetQFileName(nullptr); } const char* fname = this->Internal->TimeSteps[updateTime].FunctionFile.c_str(); if (strlen(fname) > 0) { this->Reader->SetFunctionFileName(fname); } else { this->Reader->SetFunctionFileName(nullptr); } this->Reader->UpdatePiece(outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()), outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES()), outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS())); vtkDataObject* ioutput = this->Reader->GetOutput(); output->ShallowCopy(ioutput); output->GetInformation()->Set(vtkDataObject::DATA_NUMBER_OF_GHOST_LEVELS(), ioutput->GetInformation()->Get(vtkDataObject::DATA_NUMBER_OF_GHOST_LEVELS())); } else { vtkErrorMacro("Time step " << updateTime << " was not found."); return 0; } return 1; } //------------------------------------------------------------------------------ void vtkPlot3DMetaReader::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); }