add composite filter

This commit is contained in:
Jay 2023-01-11 01:29:56 +00:00
parent 92aba8b544
commit 90e1e82b86
6 changed files with 291 additions and 0 deletions

@ -0,0 +1,3 @@
# New Composite Vector filter
The composite vector filter combines multiple scalar fields into a single vector field. Scalar fields are selected as the active input fields, and the combined vector field is set at the output. The current composite vector filter only supports 2d and 3d scalar field composition. Users may use `vtkm::cont::make_ArrayHandleCompositeVector` to execute a more flexible scalar field composition.

@ -17,6 +17,7 @@ set(field_transform_headers
WarpScalar.h
WarpVector.h
LogValues.h
CompositeVectors.h
)
set(field_transform_sources
@ -29,6 +30,7 @@ set(field_transform_sources
WarpScalar.cxx
WarpVector.cxx
LogValues.cxx
CompositeVectors.cxx
)
vtkm_library(

@ -0,0 +1,100 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ErrorFilterExecution.h>
#include <vtkm/filter/field_transform/CompositeVectors.h>
namespace vtkm
{
namespace filter
{
namespace field_transform
{
VTKM_CONT vtkm::cont::DataSet CompositeVectors::DoExecute(const vtkm::cont::DataSet& inDataSet)
{
vtkm::cont::UnknownArrayHandle outArray;
if (this->NumberOfFields < 2)
{
throw vtkm::cont::ErrorFilterExecution("FieldNameList is supposed to be larger than 2.");
}
else if (this->NumberOfFields == 2)
{
auto fieldAssociation = this->GetFieldFromDataSet(0, inDataSet).GetAssociation();
if (fieldAssociation != this->GetFieldFromDataSet(1, inDataSet).GetAssociation())
{
throw vtkm::cont::ErrorFilterExecution("Field 0 and Field 2 have different associations.");
}
auto resolveType2d = [&](const auto& field0) {
using T = typename std::decay_t<decltype(field0)>::ValueType;
vtkm::cont::ArrayHandle<T> field1;
vtkm::cont::ArrayCopyShallowIfPossible(this->GetFieldFromDataSet(1, inDataSet).GetData(),
field1);
auto compositedArray = vtkm::cont::make_ArrayHandleCompositeVector(field0, field1);
using VecType = vtkm::Vec<T, 2>;
using ArrayHandleType = vtkm::cont::ArrayHandle<VecType>;
ArrayHandleType result;
vtkm::cont::ArrayCopy(compositedArray, result);
outArray = result;
};
const auto& inField0 = this->GetFieldFromDataSet(0, inDataSet);
inField0.GetData().CastAndCallForTypes<vtkm::TypeListScalarAll, VTKM_DEFAULT_STORAGE_LIST>(
resolveType2d);
}
else if (this->NumberOfFields == 3)
{
auto fieldAssociation0 = this->GetFieldFromDataSet(0, inDataSet).GetAssociation();
auto fieldAssociation1 = this->GetFieldFromDataSet(1, inDataSet).GetAssociation();
auto fieldAssociation2 = this->GetFieldFromDataSet(2, inDataSet).GetAssociation();
if (fieldAssociation0 != fieldAssociation1 || fieldAssociation1 != fieldAssociation2 ||
fieldAssociation0 != fieldAssociation2)
{
throw vtkm::cont::ErrorFilterExecution(
"Field 0, Field 1 and Field 2 have different associations.");
}
auto resolveType3d = [&](const auto& field0) {
using T = typename std::decay_t<decltype(field0)>::ValueType;
vtkm::cont::ArrayHandle<T> field1;
vtkm::cont::ArrayCopyShallowIfPossible(this->GetFieldFromDataSet(1, inDataSet).GetData(),
field1);
vtkm::cont::ArrayHandle<T> field2;
vtkm::cont::ArrayCopyShallowIfPossible(this->GetFieldFromDataSet(2, inDataSet).GetData(),
field2);
auto compositedArray = vtkm::cont::make_ArrayHandleCompositeVector(field0, field1, field2);
using VecType = vtkm::Vec<T, 3>;
using ArrayHandleType = vtkm::cont::ArrayHandle<VecType>;
ArrayHandleType result;
// ArrayHandleCompositeVector currently does not implement the ability to
// get to values on the control side, so copy to an array that is accessible.
vtkm::cont::ArrayCopy(compositedArray, result);
outArray = result;
};
const auto& inField0 = this->GetFieldFromDataSet(0, inDataSet);
inField0.GetData().CastAndCallForTypes<vtkm::TypeListScalarAll, VTKM_DEFAULT_STORAGE_LIST>(
resolveType3d);
}
else
{
throw vtkm::cont::ErrorFilterExecution(
"Using make_ArrayHandleCompositeVector to composite vectors more than 3.");
}
return this->CreateResultField(
inDataSet, this->GetOutputFieldName(), this->GetActiveFieldAssociation(), outArray);
}
} // namespace field_transform
} // namespace vtkm::filter
} // namespace vtkm

@ -0,0 +1,59 @@
//============================================================================
// 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.
//============================================================================
#ifndef vtk_m_filter_field_transform_CompositeVectors_h
#define vtk_m_filter_field_transform_CompositeVectors_h
#include <vtkm/filter/FilterField.h>
#include <vtkm/filter/field_transform/vtkm_filter_field_transform_export.h>
namespace vtkm
{
namespace filter
{
namespace field_transform
{
/// \brief The composite vector filter combines multiple scalar fields into a single vector field.
/// Scalar fields are selected as the active input fields, and the combined vector field is set at the output.
///
class VTKM_FILTER_FIELD_TRANSFORM_EXPORT CompositeVectors : public vtkm::filter::FilterField
{
public:
VTKM_CONT
CompositeVectors() { this->SetOutputFieldName("CompositedField"); };
VTKM_CONT
void SetFieldNameList(
const std::vector<std::string>& fieldNameList,
vtkm::cont::Field::Association association = vtkm::cont::Field::Association::Any)
{
vtkm::IdComponent index = 0;
for (auto& fieldName : fieldNameList)
{
this->SetActiveField(index, fieldName, association);
++index;
}
this->NumberOfFields = static_cast<vtkm::IdComponent>(fieldNameList.size());
}
VTKM_CONT
vtkm::IdComponent GetNumberOfFields() { return this->NumberOfFields; }
private:
vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input) override;
vtkm::IdComponent NumberOfFields;
};
} // namespace field_transform
} // namespace vtkm::filter
} // namespace vtkm
#endif //vtk_m_filter_field_transform_CompositeVectors_h

@ -17,6 +17,7 @@ set(unit_tests
UnitTestWarpScalarFilter.cxx
UnitTestWarpVectorFilter.cxx
UnitTestLogValues.cxx
UnitTestCompositeVectors.cxx
)
set(libraries

@ -0,0 +1,126 @@
//============================================================================
// 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.
//============================================================================
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/field_transform/CompositeVectors.h>
namespace
{
template <typename ScalarType>
vtkm::cont::DataSet MakeDataSet(vtkm::IdComponent numArrays)
{
vtkm::cont::DataSet dataSet;
vtkm::IdComponent arrayLen = 100;
for (vtkm::IdComponent i = 0; i < numArrays; ++i)
{
std::vector<ScalarType> pointarray;
std::vector<ScalarType> cellarray;
for (vtkm::IdComponent j = 0; j < arrayLen; ++j)
{
pointarray.push_back(static_cast<ScalarType>(i * 1.1 + j * 1.1));
cellarray.push_back(static_cast<ScalarType>(i * 2.1 + j * 2.1));
}
dataSet.AddPointField("pointArray" + std::to_string(i), pointarray);
dataSet.AddCellField("cellArray" + std::to_string(i), cellarray);
}
return dataSet;
}
template <typename ScalarType, typename VecType>
void CheckResults(vtkm::cont::DataSet inDataSet,
const std::vector<std::string> FieldNames,
const std::string compositedName)
{
//there are only three fields for this testing , it is ok to use vtkm::IdComponent
vtkm::IdComponent dims = static_cast<vtkm::IdComponent>(FieldNames.size());
auto compositedField = inDataSet.GetField(compositedName);
vtkm::IdComponent compositedFieldLen =
static_cast<vtkm::IdComponent>(compositedField.GetNumberOfValues());
using ArrayHandleType = vtkm::cont::ArrayHandle<VecType>;
ArrayHandleType compFieldArrayCopy;
compositedField.GetData().AsArrayHandle(compFieldArrayCopy);
auto compFieldReadPortal = compFieldArrayCopy.ReadPortal();
for (vtkm::IdComponent i = 0; i < dims; i++)
{
auto field = inDataSet.GetField(FieldNames[i]);
VTKM_TEST_ASSERT(compositedField.GetAssociation() == field.GetAssociation(),
"Got bad association value.");
vtkm::IdComponent fieldLen = static_cast<vtkm::IdComponent>(field.GetNumberOfValues());
VTKM_TEST_ASSERT(compositedFieldLen == fieldLen, "Got wrong field length.");
vtkm::cont::ArrayHandle<ScalarType> fieldArrayHandle;
field.GetData().AsArrayHandle(fieldArrayHandle);
auto fieldReadPortal = fieldArrayHandle.ReadPortal();
for (vtkm::IdComponent j = 0; j < fieldLen; j++)
{
auto compFieldVec = compFieldReadPortal.Get(j);
auto comFieldValue = compFieldVec[static_cast<vtkm::UInt64>(i)];
auto fieldValue = fieldReadPortal.Get(j);
VTKM_TEST_ASSERT(comFieldValue == fieldValue, "Got bad field value.");
}
}
}
template <typename ScalarType, typename VecType>
void TestCompositeVectors(vtkm::IdComponent dim)
{
vtkm::cont::DataSet inDataSet = MakeDataSet<ScalarType>(dim);
vtkm::filter::field_transform::CompositeVectors filter;
std::vector<std::string> pointFieldNames;
for (vtkm::IdComponent i = 0; i < dim; i++)
{
pointFieldNames.push_back("pointArray" + std::to_string(i));
}
filter.SetFieldNameList(pointFieldNames, vtkm::cont::Field::Association::Points);
filter.SetOutputFieldName("CompositedFieldPoint");
vtkm::cont::DataSet outDataSetPointAssoci = filter.Execute(inDataSet);
CheckResults<ScalarType, VecType>(
outDataSetPointAssoci, pointFieldNames, filter.GetOutputFieldName());
std::vector<std::string> cellFieldNames;
for (vtkm::IdComponent i = 0; i < dim; i++)
{
cellFieldNames.push_back("cellArray" + std::to_string(i));
}
filter.SetFieldNameList(cellFieldNames, vtkm::cont::Field::Association::Cells);
filter.SetOutputFieldName("CompositedFieldCell");
vtkm::cont::DataSet outDataSetCellAssoci = filter.Execute(inDataSet);
CheckResults<ScalarType, VecType>(
outDataSetCellAssoci, cellFieldNames, filter.GetOutputFieldName());
}
void CompositeVectors()
{
TestCompositeVectors<vtkm::FloatDefault, vtkm::Vec2f>(2);
TestCompositeVectors<vtkm::FloatDefault, vtkm::Vec3f>(3);
TestCompositeVectors<vtkm::Id, vtkm::Vec2i>(2);
TestCompositeVectors<vtkm::Id, vtkm::Vec3i>(3);
}
} // anonymous namespace
int UnitTestCompositeVectors(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(CompositeVectors, argc, argv);
}