//============================================================================= // // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt 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. // // Copyright 2012 Sandia Corporation. // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, // the U.S. Government retains certain rights in this software. // //============================================================================= #include "vtkmGradient.h" #include "vtkCellData.h" #include "vtkDataSet.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkmlib/ArrayConverters.h" #include "vtkmlib/DataSetConverters.h" #include "vtkmlib/PolyDataConverter.h" #include "vtkmlib/Storage.h" #include "vtkmCellSetExplicit.h" #include "vtkmCellSetSingleType.h" #include "vtkmFilterPolicy.h" #include #include vtkStandardNewMacro(vtkmGradient) namespace { struct GradientTypes : vtkm::ListTagBase< vtkm::Float32, vtkm::Float64, vtkm::Vec, vtkm::Vec, vtkm::Vec< vtkm::Vec, 3>, vtkm::Vec< vtkm::Vec, 3> > { }; //------------------------------------------------------------------------------ class vtkmGradientFilterPolicy : public vtkm::filter::PolicyBase { public: typedef GradientTypes FieldTypeList; typedef tovtkm::TypeListTagVTMOut FieldStorageList; typedef tovtkm::CellListStructuredInVTK StructuredCellSetList; typedef tovtkm::CellListUnstructuredInVTK UnstructuredCellSetList; typedef tovtkm::CellListAllInVTK AllCellSetList; typedef vtkm::TypeListTagFieldVec3 CoordinateTypeList; typedef tovtkm::PointListInVTK CoordinateStorageList; typedef vtkm::filter::PolicyDefault::DeviceAdapterList DeviceAdapterList; }; } //------------------------------------------------------------------------------ vtkmGradient::vtkmGradient() { } //------------------------------------------------------------------------------ vtkmGradient::~vtkmGradient() { } //------------------------------------------------------------------------------ void vtkmGradient::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //------------------------------------------------------------------------------ int vtkmGradient::RequestData(vtkInformation* request, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkDataSet* input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkDataSet* output = vtkDataSet::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); output->ShallowCopy(input); // grab the input array to process to determine the field want to compute // the gradient for int association = this->GetInputArrayAssociation(0, inputVector); // convert the input dataset to a vtkm::cont::DataSet. We explicitly drop // all arrays from the conversion as this algorithm doesn't change topology // and therefore doesn't need input fields converted through the VTK-m filter vtkm::cont::DataSet in = tovtkm::Convert(input, tovtkm::FieldsFlag::None); // convert the array over to vtkm vtkDataArray* inputArray = this->GetInputArrayToProcess(0, inputVector); vtkm::cont::Field field = tovtkm::Convert(inputArray, association); const bool dataSetValid = in.GetNumberOfCoordinateSystems() > 0 && in.GetNumberOfCellSets() > 0; const bool fieldIsPoint = field.GetAssociation() == vtkm::cont::Field::ASSOC_POINTS; const bool fieldIsCell = field.GetAssociation() == vtkm::cont::Field::ASSOC_CELL_SET; const bool fieldIsVec = (inputArray->GetNumberOfComponents() == 3); const bool fieldIsScalar = inputArray->GetDataType() == VTK_FLOAT || inputArray->GetDataType() == VTK_DOUBLE; const bool fieldValid = (fieldIsPoint || fieldIsCell) && fieldIsScalar && (field.GetName() != std::string()); if(!(dataSetValid && fieldValid)) { vtkWarningMacro(<< "Unable convert dataset over to VTK-m.\n" << "Falling back to vtkGradientFilter." ); return this->Superclass::RequestData(request, inputVector, outputVector); } vtkmGradientFilterPolicy policy; vtkm::filter::Gradient filter; filter.SetColumnMajorOrdering(); if( fieldIsVec ) { //this properties are only valid when processing a vec<3> field filter.SetComputeDivergence( this->ComputeDivergence != 0 ); filter.SetComputeVorticity( this->ComputeVorticity != 0 ); filter.SetComputeQCriterion( this->ComputeQCriterion != 0 ); } if(this->ResultArrayName) { filter.SetOutputFieldName(this->ResultArrayName); } if(this->DivergenceArrayName) { filter.SetDivergenceName( this->DivergenceArrayName ); } if(this->VorticityArrayName) { filter.SetVorticityName( this->VorticityArrayName ); } if(this->QCriterionArrayName) { filter.SetQCriterionName( this->QCriterionArrayName ); } else { filter.SetQCriterionName( "Q-criterion" ); } // Run the VTK-m Gradient Filter // ----------------------------- // vtkm::filter::Result result; if(fieldIsPoint) { filter.SetComputePointGradient( !this->FasterApproximation ); result = filter.Execute(in, field, policy); } else { //we need to convert the field to be a point field vtkm::filter::PointAverage cellToPoint; cellToPoint.SetOutputFieldName(field.GetName()); vtkm::filter::Result toPoint = cellToPoint.Execute(in, field, policy); filter.SetComputePointGradient( false ); result = filter.Execute(in, toPoint.GetField(), policy); } // Verify that the filter ran correctly // ----------------------------- // if(!result.IsFieldValid()) { vtkWarningMacro(<< "VTK-m gradient computation failed for an unknown reason.\n" << "Falling back to vtkGradientFilter." ); return this->Superclass::RequestData(request, inputVector, outputVector); } //When we have faster approximation enabled the VTK-m gradient will output //a cell field not a point field. So at that point we will need to convert //back to a point field if((fieldIsPoint && this->FasterApproximation)) { vtkm::cont::DataSet const& resultData = result.GetDataSet(); //We need to convert this field back to a point field vtkm::filter::PointAverage cellToPoint; cellToPoint.SetOutputFieldName(filter.GetOutputFieldName()); vtkm::filter::Result toPointResult = cellToPoint.Execute(in, result.GetField(), policy); if(this->ComputeGradient) { vtkDataArray* gradientArray = fromvtkm::Convert(toPointResult.GetField()); output->GetPointData()->AddArray(gradientArray); } if(this->ComputeDivergence && fieldIsVec) { vtkm::filter::Result dresult = cellToPoint.Execute(in, resultData.GetField(filter.GetDivergenceName())); vtkDataArray* divergenceArray = fromvtkm::Convert(dresult.GetField()); output->GetPointData()->AddArray(divergenceArray); } if(this->ComputeVorticity && fieldIsVec) { vtkm::filter::Result vresult = cellToPoint.Execute(in, resultData.GetField(filter.GetVorticityName())); vtkDataArray* vorticityArray = fromvtkm::Convert(vresult.GetField()); output->GetPointData()->AddArray(vorticityArray); } if(this->ComputeQCriterion && fieldIsVec) { vtkm::filter::Result qresult = cellToPoint.Execute(in,resultData.GetField(filter.GetQCriterionName())); vtkDataArray* qcriterionArray = fromvtkm::Convert(qresult.GetField()); output->GetPointData()->AddArray(qcriterionArray); } } else { // convert arrays back to VTK if (!fromvtkm::ConvertArrays(result.GetDataSet(), output)) { vtkErrorMacro(<< "Unable to convert VTKm DataSet back to VTK"); return 0; } } return 1; }