#include "vtkPythonRepresentation.h" #include "vtkAppendFilter.h" #include "vtkAppendPolyData.h" #include "vtkAppendRectilinearGrid.h" #include "vtkClientServerMoveData.h" #include "vtkCompositeDataSet.h" #include "vtkDataObjectTypes.h" #include "vtkDataSetAttributes.h" #include "vtkFieldData.h" #include "vtkInformation.h" #include "vtkMultiBlockDataGroupFilter.h" #include "vtkMultiProcessController.h" #include "vtkObjectFactory.h" #include "vtkPassArrays.h" #include "vtkProcessModule.h" #include "vtkPVCacheKeeper.h" #include "vtkPVMergeTables.h" #include "vtkPVSession.h" #include "vtkPythonView.h" #include "vtkReductionFilter.h" #include class vtkPythonRepresentation::vtkPythonRepresentationInternal { public: vtkPythonRepresentationInternal() { // One map per attribute type this->AttributeArrayEnabled.resize(vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES); } std::vector< std::map< std::string, bool > > AttributeArrayEnabled; }; vtkStandardNewMacro(vtkPythonRepresentation); //---------------------------------------------------------------------------- vtkPythonRepresentation::vtkPythonRepresentation() { this->LocalInput = NULL; this->ClientDataObject = NULL; this->Internal = new vtkPythonRepresentationInternal(); } //---------------------------------------------------------------------------- vtkPythonRepresentation::~vtkPythonRepresentation() { if (this->LocalInput) { this->LocalInput->Delete(); } if (this->ClientDataObject) { this->ClientDataObject->Delete(); } if (this->Internal) { delete this->Internal; } } //---------------------------------------------------------------------------- int vtkPythonRepresentation::ProcessViewRequest(vtkInformationRequestKey* request_type, vtkInformation* inInfo, vtkInformation* outInfo) { if (this->GetVisibility() == false) { return 0; } if (request_type == vtkPythonView::REQUEST_DELIVER_DATA_TO_CLIENT()) { this->TransferLocalDataToClient(); } return this->Superclass::ProcessViewRequest(request_type, inInfo, outInfo); } //---------------------------------------------------------------------------- int vtkPythonRepresentation::GetNumberOfAttributeArrays(int attributeType) { if (this->LocalInput) { vtkFieldData* attributeData = this->LocalInput->GetAttributesAsFieldData(attributeType); if (attributeData) { return attributeData->GetNumberOfArrays(); } } return 0; } //---------------------------------------------------------------------------- const char* vtkPythonRepresentation::GetAttributeArrayName(int attributeType, int arrayIndex) { if (this->LocalInput) { vtkFieldData* attributeData = this->LocalInput->GetAttributesAsFieldData(attributeType); if (attributeData) { if (arrayIndex < 0 || arrayIndex >= attributeData->GetNumberOfArrays()) { vtkErrorMacro(<< "Invalid array index " << arrayIndex); return NULL; } return attributeData->GetArrayName(arrayIndex); } else { vtkErrorMacro(<< "No attribute " << vtkDataSetAttributes::GetAttributeTypeAsString(attributeType) << " available in the input"); } } return NULL; } //---------------------------------------------------------------------------- void vtkPythonRepresentation::SetAttributeArrayStatus(int attributeType, const char* name, int status) { std::string nameStr(name); this->Internal->AttributeArrayEnabled[attributeType][name] = (status != 0); } //---------------------------------------------------------------------------- int vtkPythonRepresentation::GetAttributeArrayStatus(int attributeType, const char* name) { std::string nameStr(name); if (this->Internal->AttributeArrayEnabled[attributeType].count(nameStr) > 0) { return this->Internal->AttributeArrayEnabled[attributeType][name]; } return 0; } //---------------------------------------------------------------------------- void vtkPythonRepresentation::EnableAllAttributeArrays() { for (int attributeType = 0; attributeType < vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES; ++attributeType) { for (int i = 0; i < this->GetNumberOfAttributeArrays(attributeType); ++i) { const char* attributeName = this->GetAttributeArrayName(attributeType, i); this->SetAttributeArrayStatus(attributeType, attributeName, 1); } } } //---------------------------------------------------------------------------- void vtkPythonRepresentation::DisableAllAttributeArrays() { for (size_t attributeType = 0; attributeType < this->Internal->AttributeArrayEnabled.size(); ++attributeType) { this->Internal->AttributeArrayEnabled[attributeType].clear(); } } //---------------------------------------------------------------------------- int vtkPythonRepresentation::FillInputPortInformation( int port, vtkInformation* info) { if (port == 0) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject"); info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1); } return 1; } //#define VTK_PYTHON_REPRESENTATION_DEBUG #if defined(VTK_PYTHON_REPRESENTATION_DEBUG) #define vtkPythonRepresentationDebug(x) \ { \ vtkMultiProcessController * globalController = \ vtkMultiProcessController::GetGlobalController(); \ \ int myId = globalController->GetLocalProcessId(); \ int numProcs = globalController->GetNumberOfProcesses(); \ std::cout << "Proc (" << myId << ", " << numProcs << "): " \ << x << std::endl; \ } #else #define vtkPythonRepresentationDebug(x) #endif //---------------------------------------------------------------------------- int vtkPythonRepresentation::RequestData(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { vtkPythonRepresentationDebug("Starting RequestData"); // Make a shallow copy of the input data vtkDataObject* input = vtkDataObject::GetData(inputVector[0]); if (input) { if (!this->LocalInput) { vtkPythonRepresentationDebug("Creating new instance of " << input->GetClassName() << " for LocalInput"); this->LocalInput = input->NewInstance(); } else if (!this->LocalInput->IsA(input->GetClassName())) { vtkPythonRepresentationDebug("Replacing LocalInput with new instance of " << input->GetClassName()); this->LocalInput->Delete(); this->LocalInput = input->NewInstance(); } else { this->LocalInput->Initialize(); } this->LocalInput->ShallowCopy(input); } return this->Superclass::RequestData(request, inputVector, outputVector); } //---------------------------------------------------------------------------- void vtkPythonRepresentation::InitializePreGatherHelper(vtkReductionFilter *reductionFilter, vtkDataObject* input) { if (input == NULL) { reductionFilter->SetPreGatherHelper(NULL); return; } if (input->IsA("vtkPolyData") || input->IsA("vtkTable") || input->IsA("vtkRectilinearGrid") || input->IsA("vtkStructuredGrid") || input->IsA("vtkUnstructuredGrid") || input->IsA("vtkCompositeDataSet")) { vtkPythonRepresentationDebug("vtkPassArrays used as pregather helper in ReductionFilter"); vtkPassArrays* passArraysHelper = vtkPassArrays::New(); passArraysHelper->UseFieldTypesOn(); reductionFilter->SetPreGatherHelper(passArraysHelper); passArraysHelper->Delete(); // Set which arrays to pass for (int attributeType = 0; attributeType < vtkDataObject::NUMBER_OF_ATTRIBUTE_TYPES; ++attributeType) { passArraysHelper->AddFieldType(attributeType); std::map::iterator arrayIter = this->Internal->AttributeArrayEnabled[attributeType].begin(); while (arrayIter != this->Internal->AttributeArrayEnabled[attributeType].end()) { std::string arrayName = arrayIter->first; int enabled = arrayIter->second; if (enabled) // enabled { passArraysHelper->AddArray(attributeType, arrayName.c_str()); } ++arrayIter; } } } else { vtkErrorMacro(<< "Unhandled input data type '" << input->GetClassName() << "' for deciding pre-gather helper"); reductionFilter->SetPreGatherHelper(NULL); } } //---------------------------------------------------------------------------- void vtkPythonRepresentation::InitializePostGatherHelper(vtkReductionFilter *reductionFilter, vtkDataObject* input) { if (input == NULL) { reductionFilter->SetPostGatherHelper(NULL); return; } // Set up the correct filter for putting together the datasets on // different server nodes. if (input->IsA("vtkPolyData")) { vtkPythonRepresentationDebug("vtkAppendPolyData used in ReductionFilter"); vtkAppendPolyData* appendPolyDataHelper = vtkAppendPolyData::New(); reductionFilter->SetPostGatherHelper(appendPolyDataHelper); appendPolyDataHelper->Delete(); } else if (input->IsA("vtkCompositeDataSet")) { vtkPythonRepresentationDebug("vtkMultiBlockDataGroupFilter used in ReductionFilter"); vtkMultiBlockDataGroupFilter* groupHelper = vtkMultiBlockDataGroupFilter::New(); reductionFilter->SetPostGatherHelper(groupHelper); groupHelper->Delete(); } else if (input->IsA("vtkRectilinearGrid")) { vtkPythonRepresentationDebug("vtkAppendRectilinearGrid used in ReductionFilter"); vtkAppendRectilinearGrid* gridHelper = vtkAppendRectilinearGrid::New(); reductionFilter->SetPostGatherHelper(gridHelper); gridHelper->Delete(); } else if (input->IsA("vtkDataSet")) { vtkPythonRepresentationDebug("vtkAppendFilter used in ReductionFilter"); vtkAppendFilter* appendHelper = vtkAppendFilter::New(); reductionFilter->SetPostGatherHelper(appendHelper); appendHelper->Delete(); } else if (input->IsA("vtkTable")) { vtkPythonRepresentationDebug("vtkPVMergeTable used in ReductionFilter"); vtkPVMergeTables* tablesHelper = vtkPVMergeTables::New(); reductionFilter->SetPostGatherHelper(tablesHelper); tablesHelper->Delete(); } else { vtkErrorMacro(<< "Unhandled input data type '" << input->GetClassName() << "' for deciding post-gather helper"); reductionFilter->SetPostGatherHelper(NULL); } } //---------------------------------------------------------------------------- bool vtkPythonRepresentation::HasProcessRole(vtkTypeUInt32 role) { vtkPVSession* session = vtkPVSession::SafeDownCast( vtkProcessModule::GetProcessModule()->GetSession()); if (!session) { vtkErrorMacro("No active ParaView session"); return 0; } return session->HasProcessRole(role); } //---------------------------------------------------------------------------- bool vtkPythonRepresentation::IsClientProcess() { return this->HasProcessRole(vtkPVSession::CLIENT); } //---------------------------------------------------------------------------- bool vtkPythonRepresentation::IsDataServerProcess() { return this->HasProcessRole(vtkPVSession::DATA_SERVER); } //---------------------------------------------------------------------------- int vtkPythonRepresentation::SendDataTypeToClient(int & dataType) { vtkMultiProcessController* controller = NULL; int processType = 0; enum { CLIENT, SERVER }; vtkPVSession* session = vtkPVSession::SafeDownCast( vtkProcessModule::GetProcessModule()->GetSession()); if (!session) { vtkErrorMacro("No active ParaView session"); return 0; } if (this->IsClientProcess()) { controller = session->GetController(vtkPVSession::DATA_SERVER); processType = CLIENT; } //else if (vtkProcessModule::GetProcessType() == // vtkProcessModule::PROCESS_DATA_SERVER) else if (this->IsDataServerProcess()) { controller = session->GetController(vtkPVSession::CLIENT); processType = SERVER; } int tag = 353848; if (controller) { if (processType == SERVER) { vtkDebugMacro("Server Root: Send data type to the client."); controller->Send(&dataType, 1, 1, tag); } else if (processType == CLIENT) { vtkDebugMacro("Client: Get data type from server."); controller->Receive(&dataType, 1, 1, tag); } } return 1; } //---------------------------------------------------------------------------- void vtkPythonRepresentation::TransferLocalDataToClient() { vtkSmartPointer reductionFilter = vtkSmartPointer::New(); reductionFilter->SetController(vtkMultiProcessController::GetGlobalController()); vtkSmartPointer dataMover = vtkSmartPointer::New(); int dataType = -1; if (this->LocalInput) { vtkDataObject* input = this->LocalInput; if (input) { dataType = input->GetDataObjectType(); // Tell the reduction filter how to process data on the server // nodes before merging it. this->InitializePreGatherHelper(reductionFilter, input); // Tell the reduction filter how it should merge data after gathering it this->InitializePostGatherHelper(reductionFilter, input); // The reduction should happen only among processes with input // data, i.e. server processes. vtkPythonRepresentationDebug("Setting input on ReductionFilter"); reductionFilter->SetInputData(input); reductionFilter->Update(); vtkPythonRepresentationDebug("Setting input to DataMover"); dataMover->SetInputConnection(reductionFilter->GetOutputPort()); } else { vtkErrorMacro(<< "No input data"); } } // Tell DataMover what the output type of the data should be this->SendDataTypeToClient(dataType); vtkPythonRepresentationDebug("dataType is " << vtkDataObjectTypes::GetClassNameFromTypeId(dataType)); dataMover->SetOutputDataType(dataType); if (this->IsClientProcess() || this->IsDataServerProcess()) { dataMover->Update(); } // Copy on the client side if (this->IsClientProcess()) { if (this->ClientDataObject) { this->ClientDataObject->Delete(); } this->ClientDataObject = vtkDataObjectTypes::NewDataObject(dataType); if (this->ClientDataObject) { this->ClientDataObject->ShallowCopy(dataMover->GetOutput()); } else { vtkErrorMacro(<< "Could not create LocalInput on client"); } } } //---------------------------------------------------------------------------- void vtkPythonRepresentation::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); }