From 72540723574b088e510e3e3112af191fe459bbfc Mon Sep 17 00:00:00 2001 From: Wang Date: Wed, 8 Nov 2023 11:27:59 -0500 Subject: [PATCH] add merge data sets filter --- docs/changelog/add-merge-datasets-filter.md | 3 + vtkm/cont/MergePartitionedDataSet.cxx | 470 +++++++++---- vtkm/cont/MergePartitionedDataSet.h | 17 +- .../UnitTestMergePartitionedDataSet.cxx | 2 + vtkm/filter/contour/SliceMultiple.cxx | 121 +--- vtkm/filter/multi_block/CMakeLists.txt | 2 + vtkm/filter/multi_block/MergeDataSets.cxx | 32 + vtkm/filter/multi_block/MergeDataSets.h | 46 ++ .../filter/multi_block/testing/CMakeLists.txt | 5 + .../testing/UnitTestMergeDataSetsFilter.cxx | 623 ++++++++++++++++++ vtkm/filter/multi_block/vtkm.module | 1 + 11 files changed, 1084 insertions(+), 238 deletions(-) create mode 100644 docs/changelog/add-merge-datasets-filter.md create mode 100644 vtkm/filter/multi_block/MergeDataSets.cxx create mode 100644 vtkm/filter/multi_block/MergeDataSets.h create mode 100644 vtkm/filter/multi_block/testing/UnitTestMergeDataSetsFilter.cxx diff --git a/docs/changelog/add-merge-datasets-filter.md b/docs/changelog/add-merge-datasets-filter.md new file mode 100644 index 000000000..edc317cd6 --- /dev/null +++ b/docs/changelog/add-merge-datasets-filter.md @@ -0,0 +1,3 @@ +# Adding MergeDataSets filter + +The MergeDataSets filter can accept partitioned data sets and output a merged data set. It assumes that all partitions have the same coordinate systems. If a field is missing in a specific partition, the user-specified invalid value will be adopted and filled into the corresponding places of the merged field array. diff --git a/vtkm/cont/MergePartitionedDataSet.cxx b/vtkm/cont/MergePartitionedDataSet.cxx index 9255df0cb..e6aa7f155 100644 --- a/vtkm/cont/MergePartitionedDataSet.cxx +++ b/vtkm/cont/MergePartitionedDataSet.cxx @@ -7,8 +7,6 @@ // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ -#include - #include #include #include @@ -17,15 +15,50 @@ #include #include #include +#include #include #include - +#include #include #include + namespace { +template +struct SetToInvalid : public vtkm::worklet::WorkletMapField +{ + T InvalidValue; + SetToInvalid(T invalidValue) + : InvalidValue(invalidValue) + { + } + typedef void ControlSignature(FieldInOut); + typedef void ExecutionSignature(_1); + template + VTKM_EXEC void operator()(ValueType& value) const + { + value = this->InvalidValue; + } +}; + +struct CopyWithOffsetWorklet : public vtkm::worklet::WorkletMapField +{ + vtkm::Id OffsetValue; + VTKM_CONT + CopyWithOffsetWorklet(const vtkm::Id offset) + : OffsetValue(offset) + { + } + typedef void ControlSignature(FieldIn, FieldInOut); + typedef void ExecutionSignature(_1, _2); + VTKM_EXEC void operator()(const vtkm::Id originalValue, vtkm::Id& outputValue) const + { + outputValue = originalValue + this->OffsetValue; + } +}; + void CountPointsAndCells(const vtkm::cont::PartitionedDataSet& partitionedDataSet, vtkm::Id& numPointsTotal, vtkm::Id& numCellsTotal) @@ -61,7 +94,8 @@ struct PassCellShapesNumIndices : vtkm::worklet::WorkletVisitCellsWithPoints void MergeShapes(const vtkm::cont::PartitionedDataSet& partitionedDataSet, vtkm::Id numCellsTotal, vtkm::cont::ArrayHandle& shapes, - vtkm::cont::ArrayHandle& numIndices) + vtkm::cont::ArrayHandle& numIndices, + const vtkm::Id firstNonEmptyPartitionId) { vtkm::cont::Invoker invoke; @@ -69,9 +103,14 @@ void MergeShapes(const vtkm::cont::PartitionedDataSet& partitionedDataSet, numIndices.Allocate(numCellsTotal); vtkm::Id cellStartIndex = 0; - for (vtkm::Id partitionId = 0; partitionId < partitionedDataSet.GetNumberOfPartitions(); + for (vtkm::Id partitionId = firstNonEmptyPartitionId; + partitionId < partitionedDataSet.GetNumberOfPartitions(); ++partitionId) { + if (partitionedDataSet.GetPartition(partitionId).GetNumberOfPoints() == 0) + { + continue; + } vtkm::cont::DataSet partition = partitionedDataSet.GetPartition(partitionId); vtkm::Id numCellsPartition = partition.GetNumberOfCells(); @@ -113,7 +152,8 @@ struct PassCellIndices : vtkm::worklet::WorkletVisitCellsWithPoints void MergeIndices(const vtkm::cont::PartitionedDataSet& partitionedDataSet, const vtkm::cont::ArrayHandle& offsets, vtkm::Id numIndicesTotal, - vtkm::cont::ArrayHandle& indices) + vtkm::cont::ArrayHandle& indices, + const vtkm::Id firstNonEmptyPartitionId) { vtkm::cont::Invoker invoke; @@ -121,9 +161,14 @@ void MergeIndices(const vtkm::cont::PartitionedDataSet& partitionedDataSet, vtkm::Id pointStartIndex = 0; vtkm::Id cellStartIndex = 0; - for (vtkm::Id partitionId = 0; partitionId < partitionedDataSet.GetNumberOfPartitions(); + for (vtkm::Id partitionId = firstNonEmptyPartitionId; + partitionId < partitionedDataSet.GetNumberOfPartitions(); ++partitionId) { + if (partitionedDataSet.GetPartition(partitionId).GetNumberOfPoints() == 0) + { + continue; + } vtkm::cont::DataSet partition = partitionedDataSet.GetPartition(partitionId); vtkm::Id numCellsPartition = partition.GetNumberOfCells(); @@ -139,22 +184,87 @@ void MergeIndices(const vtkm::cont::PartitionedDataSet& partitionedDataSet, VTKM_ASSERT(cellStartIndex == (offsets.GetNumberOfValues() - 1)); } -vtkm::cont::CellSetExplicit<> MergeCellSets( +vtkm::cont::CellSetSingleType<> MergeCellSetsSingleType( + const vtkm::cont::PartitionedDataSet& partitionedDataSet, + const vtkm::Id firstNonEmptyPartitionId) +{ + vtkm::Id numCells = 0; + vtkm::Id numPoints = 0; + vtkm::Id numOfDataSet = partitionedDataSet.GetNumberOfPartitions(); + std::vector cellOffsets(numOfDataSet); + std::vector pointOffsets(numOfDataSet); + //Mering cell set into single type + //checking the cell type to make sure how many points per cell + vtkm::IdComponent numberOfPointsPerCell = + partitionedDataSet.GetPartition(firstNonEmptyPartitionId) + .GetCellSet() + .GetNumberOfPointsInCell(0); + for (vtkm::Id partitionIndex = firstNonEmptyPartitionId; partitionIndex < numOfDataSet; + partitionIndex++) + { + if (partitionedDataSet.GetPartition(partitionIndex).GetNumberOfPoints() == 0) + { + continue; + } + cellOffsets[partitionIndex] = numCells; + numCells += partitionedDataSet.GetPartition(partitionIndex).GetNumberOfCells(); + pointOffsets[partitionIndex] = numPoints; + numPoints += partitionedDataSet.GetPartition(partitionIndex).GetNumberOfPoints(); + } + //We assume all cells have same type, which should have been previously checked. + const vtkm::Id mergedConnSize = numCells * numberOfPointsPerCell; + // Calculating merged offsets for all domains + vtkm::cont::ArrayHandle mergedConn; + mergedConn.Allocate(mergedConnSize); + for (vtkm::Id partitionIndex = firstNonEmptyPartitionId; partitionIndex < numOfDataSet; + partitionIndex++) + { + if (partitionedDataSet.GetPartition(partitionIndex).GetNumberOfPoints() == 0) + { + continue; + } + auto cellSet = partitionedDataSet.GetPartition(partitionIndex).GetCellSet(); + // Grabing the connectivity and copy it into the larger connectivity array + vtkm::cont::CellSetSingleType<> singleType = + cellSet.AsCellSet>(); + const vtkm::cont::ArrayHandle connPerDataSet = singleType.GetConnectivityArray( + vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()); + vtkm::Id copySize = connPerDataSet.GetNumberOfValues(); + VTKM_ASSERT(copySize == cellSet.GetNumberOfCells() * numberOfPointsPerCell); + // Mapping connectivity array per data into proper region of merged connectivity array + // and also adjust the value in merged connectivity array + vtkm::cont::Invoker invoker; + invoker(CopyWithOffsetWorklet{ pointOffsets[partitionIndex] }, + connPerDataSet, + vtkm::cont::make_ArrayHandleView( + mergedConn, cellOffsets[partitionIndex] * numberOfPointsPerCell, copySize)); + } + vtkm::cont::CellSetSingleType<> cellSet; + //Filling in the cellSet according to shapeId and number of points per cell. + vtkm::UInt8 cellShapeId = + partitionedDataSet.GetPartition(firstNonEmptyPartitionId).GetCellSet().GetCellShape(0); + cellSet.Fill(numPoints, cellShapeId, numberOfPointsPerCell, mergedConn); + return cellSet; +} + +vtkm::cont::CellSetExplicit<> MergeCellSetsExplicit( const vtkm::cont::PartitionedDataSet& partitionedDataSet, vtkm::Id numPointsTotal, - vtkm::Id numCellsTotal) + vtkm::Id numCellsTotal, + const vtkm::Id firstNonEmptyPartitionId) { vtkm::cont::ArrayHandle shapes; vtkm::cont::ArrayHandle numIndices; - MergeShapes(partitionedDataSet, numCellsTotal, shapes, numIndices); + MergeShapes(partitionedDataSet, numCellsTotal, shapes, numIndices, firstNonEmptyPartitionId); vtkm::cont::ArrayHandle offsets; vtkm::Id numIndicesTotal; vtkm::cont::ConvertNumComponentsToOffsets(numIndices, offsets, numIndicesTotal); numIndices.ReleaseResources(); + //Merging connectivity/indicies array vtkm::cont::ArrayHandle indices; - MergeIndices(partitionedDataSet, offsets, numIndicesTotal, indices); + MergeIndices(partitionedDataSet, offsets, numIndicesTotal, indices, firstNonEmptyPartitionId); vtkm::cont::CellSetExplicit<> outCells; outCells.Fill(numPointsTotal, shapes, indices, offsets); @@ -276,102 +386,219 @@ vtkm::cont::UnknownArrayHandle MergeArray(vtkm::Id numPartitions, return mergedArray; } -vtkm::cont::CoordinateSystem MergeCoordinateSystem( - const vtkm::cont::PartitionedDataSet& partitionedDataSet, - vtkm::IdComponent coordId, - vtkm::Id numPointsTotal) +vtkm::Id GetFirstEmptyPartition(const vtkm::cont::PartitionedDataSet& partitionedDataSet) { - std::string coordName = partitionedDataSet.GetPartition(0).GetCoordinateSystem(coordId).GetName(); - auto hasField = [&](vtkm::Id partitionId, vtkm::Id& partitionSize) -> bool { - vtkm::cont::DataSet partition = partitionedDataSet.GetPartition(partitionId); - partitionSize = partition.GetNumberOfPoints(); - // Should partitions match coordinates on name or coordinate id? They both should match, but - // for now let's go by id and check the name. - if (partition.GetNumberOfCoordinateSystems() <= coordId) + vtkm::Id numOfDataSet = partitionedDataSet.GetNumberOfPartitions(); + vtkm::Id firstNonEmptyPartitionId = -1; + for (vtkm::Id partitionIndex = 0; partitionIndex < numOfDataSet; partitionIndex++) + { + if (partitionedDataSet.GetPartition(partitionIndex).GetNumberOfPoints() != 0) { - VTKM_LOG_S(vtkm::cont::LogLevel::Warn, - "When merging partitions, partition " - << partitionId << " is missing coordinate system with index " << coordId); - return false; + firstNonEmptyPartitionId = partitionIndex; + break; } - if (partition.GetCoordinateSystem(coordId).GetName() != coordName) - { - VTKM_LOG_S(vtkm::cont::LogLevel::Warn, - "When merging partitions, partition " - << partitionId << " reported a coordinate system with name '" - << partition.GetCoordinateSystem(coordId).GetName() - << "' instead of expected name '" << coordName << "'"); - } - return true; - }; - auto getField = [&](vtkm::Id partitionId) -> vtkm::cont::Field { - return partitionedDataSet.GetPartition(partitionId).GetCoordinateSystem(coordId); - }; - vtkm::cont::UnknownArrayHandle mergedArray = - MergeArray(partitionedDataSet.GetNumberOfPartitions(), hasField, getField, numPointsTotal); - return vtkm::cont::CoordinateSystem{ coordName, mergedArray }; + } + return firstNonEmptyPartitionId; } -vtkm::cont::Field MergeField(const vtkm::cont::PartitionedDataSet& partitionedDataSet, - vtkm::IdComponent fieldId, - vtkm::Id numPointsTotal, - vtkm::Id numCellsTotal) +bool PartitionsAreSingleType(const vtkm::cont::PartitionedDataSet partitionedDataSet, + const vtkm::Id firstNonEmptyPartitionId) { - vtkm::cont::Field referenceField = partitionedDataSet.GetPartition(0).GetField(fieldId); - vtkm::Id totalSize = 0; - switch (referenceField.GetAssociation()) + vtkm::Id numOfDataSet = partitionedDataSet.GetNumberOfPartitions(); + for (vtkm::Id partitionIndex = firstNonEmptyPartitionId; partitionIndex < numOfDataSet; + partitionIndex++) { - case vtkm::cont::Field::Association::Points: - totalSize = numPointsTotal; - break; - case vtkm::cont::Field::Association::Cells: - totalSize = numCellsTotal; - break; - default: - VTKM_LOG_S(vtkm::cont::LogLevel::Info, - "Skipping merge of field '" << referenceField.GetName() - << "' because it has an unsupported association."); - return referenceField; - } - - auto hasField = [&](vtkm::Id partitionId, vtkm::Id& partitionSize) -> bool { - vtkm::cont::DataSet partition = partitionedDataSet.GetPartition(partitionId); - if (partition.HasField(referenceField.GetName(), referenceField.GetAssociation())) + if (partitionedDataSet.GetPartition(partitionIndex).GetNumberOfPoints() == 0) { - partitionSize = partition.GetField(referenceField.GetName(), referenceField.GetAssociation()) - .GetData() - .GetNumberOfValues(); - return true; + continue; } - else + auto cellSet = partitionedDataSet.GetPartition(partitionIndex).GetCellSet(); + if (!cellSet.IsType>()) { - VTKM_LOG_S(vtkm::cont::LogLevel::Info, - "Partition " << partitionId << " does not have field " - << referenceField.GetName()); - switch (referenceField.GetAssociation()) - { - case vtkm::cont::Field::Association::Points: - partitionSize = partition.GetNumberOfPoints(); - break; - case vtkm::cont::Field::Association::Cells: - partitionSize = partition.GetNumberOfCells(); - break; - default: - partitionSize = 0; - break; - } return false; } + } + + //Make sure the cell type of each non-empty partition is same + //with tested one, and they also have the same number of points. + //We know that all cell sets are of type `CellSetSingleType<>` at this point. + //Polygons may have different number of points even with the same shape id. + //It is more efficient to `GetCellShape(0)` from `CellSetSingleType` compared with `CellSetExplicit`. + auto cellSetFirst = partitionedDataSet.GetPartition(firstNonEmptyPartitionId).GetCellSet(); + vtkm::UInt8 cellShapeId = cellSetFirst.GetCellShape(0); + vtkm::IdComponent numPointsInCell = cellSetFirst.GetNumberOfPointsInCell(0); + for (vtkm::Id partitionIndex = firstNonEmptyPartitionId + 1; partitionIndex < numOfDataSet; + partitionIndex++) + { + auto cellSet = partitionedDataSet.GetPartition(partitionIndex).GetCellSet(); + if (cellSet.GetCellShape(0) != cellShapeId || + cellSet.GetNumberOfPointsInCell(0) != numPointsInCell) + { + return false; + } + } + return true; +} + +void CheckCoordsNames(const vtkm::cont::PartitionedDataSet partitionedDataSet, + const vtkm::Id firstNonEmptyPartitionId) +{ + vtkm::IdComponent numCoords = + partitionedDataSet.GetPartition(firstNonEmptyPartitionId).GetNumberOfCoordinateSystems(); + std::vector coordsNames; + for (vtkm::IdComponent coordsIndex = 0; coordsIndex < numCoords; coordsIndex++) + { + coordsNames.push_back(partitionedDataSet.GetPartition(firstNonEmptyPartitionId) + .GetCoordinateSystemName(coordsIndex)); + } + vtkm::Id numOfDataSet = partitionedDataSet.GetNumberOfPartitions(); + for (vtkm::Id partitionIndex = firstNonEmptyPartitionId; partitionIndex < numOfDataSet; + partitionIndex++) + { + if (partitionedDataSet.GetPartition(partitionIndex).GetNumberOfPoints() == 0) + { + //Skip the empty data sets in the partitioned data sets + continue; + } + if (numCoords != partitionedDataSet.GetPartition(partitionIndex).GetNumberOfCoordinateSystems()) + { + throw vtkm::cont::ErrorExecution("Data sets have different number of coordinate systems"); + } + for (vtkm::IdComponent coordsIndex = 0; coordsIndex < numCoords; coordsIndex++) + { + if (!partitionedDataSet.GetPartition(partitionIndex) + .HasCoordinateSystem(coordsNames[coordsIndex])) + { + throw vtkm::cont::ErrorExecution( + "Coordinates system name: " + coordsNames[coordsIndex] + + " in the first partition does not exist in other partitions"); + } + } + } +} + + +void MergeFieldsAndAddIntoDataSet(vtkm::cont::DataSet& outputDataSet, + const vtkm::cont::PartitionedDataSet partitionedDataSet, + const vtkm::Id numPoints, + const vtkm::Id numCells, + const vtkm::Float64 invalidValue, + const vtkm::Id firstNonEmptyPartitionId) +{ + // Merging selected fields and coordinates + // We get fields names in all partitions firstly + // The inserted map stores the field name and a index of the first partition that owns that field + vtkm::cont::Invoker invoke; + auto associationHash = [](vtkm::cont::Field::Association const& association) { + return static_cast(association); }; - auto getField = [&](vtkm::Id partitionId) -> vtkm::cont::Field { - return partitionedDataSet.GetPartition(partitionId) - .GetField(referenceField.GetName(), referenceField.GetAssociation()); - }; - vtkm::cont::UnknownArrayHandle mergedArray = - MergeArray(partitionedDataSet.GetNumberOfPartitions(), hasField, getField, totalSize); - return vtkm::cont::Field{ referenceField.GetName(), - referenceField.GetAssociation(), - mergedArray }; + std::unordered_map, + decltype(associationHash)> + fieldsMap(2, associationHash); + + vtkm::Id numOfDataSet = partitionedDataSet.GetNumberOfPartitions(); + for (vtkm::Id partitionIndex = firstNonEmptyPartitionId; partitionIndex < numOfDataSet; + partitionIndex++) + { + if (partitionedDataSet.GetPartition(partitionIndex).GetNumberOfPoints() == 0) + { + continue; + } + vtkm::IdComponent numFields = + partitionedDataSet.GetPartition(partitionIndex).GetNumberOfFields(); + for (vtkm::IdComponent fieldIndex = 0; fieldIndex < numFields; fieldIndex++) + { + const vtkm::cont::Field& field = + partitionedDataSet.GetPartition(partitionIndex).GetField(fieldIndex); + auto association = field.GetAssociation(); + bool isSupported = (association == vtkm::cont::Field::Association::Points || + association == vtkm::cont::Field::Association::Cells); + if (!isSupported) + { + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + "Skipping merge of field '" << field.GetName() + << "' because it has an unsupported association."); + } + //Do not store the field index again if it exists in fieldMap + if (fieldsMap[association].find(field.GetName()) != fieldsMap[association].end()) + { + continue; + } + fieldsMap[association][field.GetName()] = partitionIndex; + } + } + // Iterate all fields and create merged field arrays + for (auto fieldMapIter = fieldsMap.begin(); fieldMapIter != fieldsMap.end(); ++fieldMapIter) + { + auto fieldAssociation = fieldMapIter->first; + auto fieldNamesMap = fieldMapIter->second; + for (auto fieldNameIter = fieldNamesMap.begin(); fieldNameIter != fieldNamesMap.end(); + ++fieldNameIter) + { + std::string fieldName = fieldNameIter->first; + vtkm::Id partitionOwnsField = fieldNameIter->second; + const vtkm::cont::Field& field = + partitionedDataSet.GetPartition(partitionOwnsField).GetField(fieldName, fieldAssociation); + + vtkm::cont::UnknownArrayHandle mergedFieldArray = field.GetData().NewInstanceBasic(); + if (fieldAssociation == vtkm::cont::Field::Association::Points) + { + mergedFieldArray.Allocate(numPoints); + } + else + { + //We may add a new association (such as edges or faces) in future + VTKM_ASSERT(fieldAssociation == vtkm::cont::Field::Association::Cells); + mergedFieldArray.Allocate(numCells); + } + //Merging each field into the mergedField array + auto resolveType = [&](auto& concreteOut) { + vtkm::Id offset = 0; + for (vtkm::Id partitionIndex = firstNonEmptyPartitionId; partitionIndex < numOfDataSet; + ++partitionIndex) + { + if (partitionedDataSet.GetPartition(partitionIndex).GetNumberOfPoints() == 0) + { + continue; + } + if (partitionedDataSet.GetPartition(partitionIndex).HasField(fieldName, fieldAssociation)) + { + vtkm::cont::UnknownArrayHandle in = partitionedDataSet.GetPartition(partitionIndex) + .GetField(fieldName, fieldAssociation) + .GetData(); + vtkm::Id copySize = in.GetNumberOfValues(); + auto viewOut = vtkm::cont::make_ArrayHandleView(concreteOut, offset, copySize); + vtkm::cont::ArrayCopy(in, viewOut); + offset += copySize; + } + else + { + //Creating invalid values for the partition that does not have the field + using ComponentType = + typename std::decay_t::ValueType::ComponentType; + ComponentType castInvalid = + vtkm::cont::internal::CastInvalidValue(invalidValue); + vtkm::Id copySize = 0; + if (fieldAssociation == vtkm::cont::Field::Association::Points) + { + copySize = partitionedDataSet.GetPartition(partitionIndex).GetNumberOfPoints(); + } + else + { + copySize = partitionedDataSet.GetPartition(partitionIndex).GetNumberOfCells(); + } + auto viewOut = vtkm::cont::make_ArrayHandleView(concreteOut, offset, copySize); + invoke(SetToInvalid{ castInvalid }, viewOut); + offset += copySize; + } + } + }; + mergedFieldArray.CastAndCallWithExtractedArray(resolveType); + outputDataSet.AddField(vtkm::cont::Field(fieldName, fieldAssociation, mergedFieldArray)); + } + } + return; } } // anonymous namespace @@ -385,31 +612,54 @@ namespace cont VTKM_CONT vtkm::cont::DataSet MergePartitionedDataSet( - const vtkm::cont::PartitionedDataSet& partitionedDataSet) + const vtkm::cont::PartitionedDataSet& partitionedDataSet, + vtkm::Float64 invalidValue) { - // verify correctnees of data - VTKM_ASSERT(partitionedDataSet.GetNumberOfPartitions() > 0); + vtkm::cont::DataSet outputData; + //The name of coordinates system in the first non-empty partition will be used in merged data set + vtkm::Id firstNonEmptyPartitionId = GetFirstEmptyPartition(partitionedDataSet); + if (firstNonEmptyPartitionId == -1) + { + return outputData; + } + + //Checking the name of coordinates system, if all partitions have different name with the firstNonEmptyPartitionId + //just throw the exception now + CheckCoordsNames(partitionedDataSet, firstNonEmptyPartitionId); + + //Checking if all partitions have CellSetSingleType with the same cell type + bool allPartitionsAreSingleType = + PartitionsAreSingleType(partitionedDataSet, firstNonEmptyPartitionId); vtkm::Id numPointsTotal; vtkm::Id numCellsTotal; CountPointsAndCells(partitionedDataSet, numPointsTotal, numCellsTotal); - vtkm::cont::DataSet outputData; - outputData.SetCellSet(MergeCellSets(partitionedDataSet, numPointsTotal, numCellsTotal)); - - vtkm::cont::DataSet partition0 = partitionedDataSet.GetPartition(0); - for (vtkm::IdComponent coordId = 0; coordId < partition0.GetNumberOfCoordinateSystems(); - ++coordId) + if (allPartitionsAreSingleType) + { + outputData.SetCellSet(MergeCellSetsSingleType(partitionedDataSet, firstNonEmptyPartitionId)); + } + else + { + outputData.SetCellSet(MergeCellSetsExplicit( + partitionedDataSet, numPointsTotal, numCellsTotal, firstNonEmptyPartitionId)); + } + //Merging fields and coordinate systems + MergeFieldsAndAddIntoDataSet(outputData, + partitionedDataSet, + numPointsTotal, + numCellsTotal, + invalidValue, + firstNonEmptyPartitionId); + //Labeling fields that belong to the coordinate system. + //There might be multiple coordinates systems, assuming all partitions have the same name of the coordinates system + vtkm::IdComponent numCoordsNames = + partitionedDataSet.GetPartition(firstNonEmptyPartitionId).GetNumberOfCoordinateSystems(); + for (vtkm::IdComponent i = 0; i < numCoordsNames; i++) { outputData.AddCoordinateSystem( - MergeCoordinateSystem(partitionedDataSet, coordId, numPointsTotal)); + partitionedDataSet.GetPartition(firstNonEmptyPartitionId).GetCoordinateSystemName(i)); } - - for (vtkm::IdComponent fieldId = 0; fieldId < partition0.GetNumberOfFields(); ++fieldId) - { - outputData.AddField(MergeField(partitionedDataSet, fieldId, numPointsTotal, numCellsTotal)); - } - return outputData; } diff --git a/vtkm/cont/MergePartitionedDataSet.h b/vtkm/cont/MergePartitionedDataSet.h index c7a2bbf4f..d2075d821 100644 --- a/vtkm/cont/MergePartitionedDataSet.h +++ b/vtkm/cont/MergePartitionedDataSet.h @@ -22,20 +22,15 @@ class DataSet; class PartitionedDataSet; //@{ -/// \brief Functions to compute bounds for a single dataSset or partition dataset -/// -/// These are utility functions that compute bounds for a single dataset or -/// partitioned dataset. When VTK-m is operating in an distributed environment, -/// these are bounds on the local process. To get global bounds across all -/// ranks, use `vtkm::cont::BoundsGlobalCompute` instead. -/// -/// Note that if the provided CoordinateSystem does not exists, empty bounds -/// are returned. Likewise, for PartitionedDataSet, partitions without the -/// chosen CoordinateSystem are skipped. +/// \brief This function can merge multiple data sets into on data set. +/// This function assume all input partitions have the same coordinates systems. +/// If a field does not exist in a specific partition but exists in other partitions, +/// the invalide value will be used to fill the coresponding region of that field in the merged data set. VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::DataSet MergePartitionedDataSet( - const vtkm::cont::PartitionedDataSet& partitionedDataSet); + const vtkm::cont::PartitionedDataSet& partitionedDataSet, + vtkm::Float64 invalidValue = vtkm::Nan64()); //@} } diff --git a/vtkm/cont/testing/UnitTestMergePartitionedDataSet.cxx b/vtkm/cont/testing/UnitTestMergePartitionedDataSet.cxx index 36e62cefc..352f29871 100644 --- a/vtkm/cont/testing/UnitTestMergePartitionedDataSet.cxx +++ b/vtkm/cont/testing/UnitTestMergePartitionedDataSet.cxx @@ -83,5 +83,7 @@ static void MergePartitionedDataSetTest() int UnitTestMergePartitionedDataSet(int argc, char* argv[]) { + //More test cases can be found in the vtkm/filter/multi_block/testing/UnitTestMergeDataSetsFilter.cxx + //which is a filter that wraps MergePartitionedDataSet algorithm. return vtkm::cont::testing::Testing::Run(MergePartitionedDataSetTest, argc, argv); } diff --git a/vtkm/filter/contour/SliceMultiple.cxx b/vtkm/filter/contour/SliceMultiple.cxx index 9be415797..7a5e869a3 100644 --- a/vtkm/filter/contour/SliceMultiple.cxx +++ b/vtkm/filter/contour/SliceMultiple.cxx @@ -9,9 +9,10 @@ //============================================================================ #include #include +#include +#include #include #include -#include #include namespace vtkm { @@ -34,121 +35,7 @@ public: typedef void ExecutionSignature(_1); VTKM_EXEC void operator()(vtkm::Id& value) const { value += this->OffsetValue; } }; -// Original MergeContours code come from -// https://github.com/Alpine-DAV/ascent/blob/develop/src/libs/vtkh/filters/Slice.cpp#L517 -class MergeContours -{ - vtkm::cont::PartitionedDataSet DataSets; -public: - MergeContours(vtkm::cont::PartitionedDataSet& dataSets) - : DataSets(dataSets) - { - } - vtkm::cont::DataSet MergeDataSets() - { - vtkm::cont::DataSet res; - vtkm::Id numOfDataSet = this->DataSets.GetNumberOfPartitions(); - vtkm::Id numCells = 0; - vtkm::Id numPoints = 0; - std::vector cellOffsets(numOfDataSet); - std::vector pointOffsets(numOfDataSet); - for (vtkm::Id i = 0; i < numOfDataSet; i++) - { - auto cellSet = this->DataSets.GetPartition(i).GetCellSet(); - //We assume all cells are triangles here - if (!cellSet.IsType>()) - { - throw vtkm::cont::ErrorFilterExecution( - "Expected singletype cell set as the result of contour."); - } - cellOffsets[i] = numCells; - numCells += cellSet.GetNumberOfCells(); - pointOffsets[i] = numPoints; - numPoints += this->DataSets.GetPartition(i).GetNumberOfPoints(); - } - const vtkm::Id connSize = numCells * 3; - // Calculating merged offsets for all domains - vtkm::cont::ArrayHandle conn; - conn.Allocate(connSize); - for (vtkm::Id i = 0; i < numOfDataSet; i++) - { - auto cellSet = this->DataSets.GetPartition(i).GetCellSet(); - if (!cellSet.IsType>()) - { - throw vtkm::cont::ErrorFilterExecution( - "Expected singletype cell set as the result of contour."); - } - // Grabing the connectivity and copy it into the larger array - vtkm::cont::CellSetSingleType<> singleType = - cellSet.AsCellSet>(); - const vtkm::cont::ArrayHandle connPerDataSet = singleType.GetConnectivityArray( - vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()); - vtkm::Id copySize = connPerDataSet.GetNumberOfValues(); - vtkm::Id start = 0; - vtkm::cont::Algorithm::CopySubRange( - connPerDataSet, start, copySize, conn, cellOffsets[i] * 3); - // We offset the connectiviy we just copied in so we references the - // correct points - if (cellOffsets[i] != 0) - { - vtkm::cont::Invoker invoker; - invoker(OffsetWorklet{ pointOffsets[i] }, - vtkm::cont::make_ArrayHandleView(conn, cellOffsets[i] * 3, copySize)); - } - } - vtkm::cont::CellSetSingleType<> cellSet; - cellSet.Fill(numPoints, vtkm::CELL_SHAPE_TRIANGLE, 3, conn); - res.SetCellSet(cellSet); - // Merging selected fields and coordinates - vtkm::IdComponent numFields = this->DataSets.GetPartition(0).GetNumberOfFields(); - for (vtkm::IdComponent i = 0; i < numFields; i++) - { - const vtkm::cont::Field& field = this->DataSets.GetPartition(0).GetField(i); - bool isSupported = (field.GetAssociation() == vtkm::cont::Field::Association::Points || - field.GetAssociation() == vtkm::cont::Field::Association::Cells); - if (!isSupported) - { - continue; - } - vtkm::cont::UnknownArrayHandle outFieldArray = field.GetData().NewInstanceBasic(); - bool assocPoints = field.GetAssociation() == vtkm::cont::Field::Association::Points; - if (assocPoints) - { - outFieldArray.Allocate(numPoints); - } - else - { - outFieldArray.Allocate(numCells); - } - auto resolveType = [&](auto& concreteOut) { - vtkm::Id offset = 0; - for (vtkm::Id partitionId = 0; partitionId < this->DataSets.GetNumberOfPartitions(); - ++partitionId) - { - vtkm::cont::UnknownArrayHandle in = this->DataSets.GetPartition(partitionId) - .GetField(field.GetName(), field.GetAssociation()) - .GetData(); - vtkm::Id copySize = in.GetNumberOfValues(); - auto viewOut = vtkm::cont::make_ArrayHandleView(concreteOut, offset, copySize); - vtkm::cont::ArrayCopy(in, viewOut); - offset += copySize; - } - }; - outFieldArray.CastAndCallWithExtractedArray(resolveType); - res.AddField(vtkm::cont::Field(field.GetName(), field.GetAssociation(), outFieldArray)); - } - //Labeling fields that belong to the coordinate system. - //There might be multiple coordinates systems, assuming all partitions have the same name of the coordinates system - vtkm::IdComponent numCoordsNames = - this->DataSets.GetPartition(0).GetNumberOfCoordinateSystems(); - for (vtkm::IdComponent i = 0; i < numCoordsNames; i++) - { - res.AddCoordinateSystem(this->DataSets.GetPartition(0).GetCoordinateSystemName(i)); - } - return res; - } -}; vtkm::cont::DataSet SliceMultiple::DoExecute(const vtkm::cont::DataSet& input) { vtkm::cont::PartitionedDataSet slices; @@ -165,8 +52,8 @@ vtkm::cont::DataSet SliceMultiple::DoExecute(const vtkm::cont::DataSet& input) { //Since the slice filter have already selected fields //the mergeCountours will copy all existing fields - MergeContours merger(slices); - vtkm::cont::DataSet mergedResults = merger.MergeDataSets(); + vtkm::cont::DataSet mergedResults = + vtkm::cont::MergePartitionedDataSet(slices, vtkm::Float64(0)); return mergedResults; } return slices.GetPartition(0); diff --git a/vtkm/filter/multi_block/CMakeLists.txt b/vtkm/filter/multi_block/CMakeLists.txt index 695b9532c..24cafa6fb 100644 --- a/vtkm/filter/multi_block/CMakeLists.txt +++ b/vtkm/filter/multi_block/CMakeLists.txt @@ -9,10 +9,12 @@ ##============================================================================ set(multi_block_headers AmrArrays.h + MergeDataSets.h ) set(multi_block_sources AmrArrays.cxx + MergeDataSets.cxx ) vtkm_library( diff --git a/vtkm/filter/multi_block/MergeDataSets.cxx b/vtkm/filter/multi_block/MergeDataSets.cxx new file mode 100644 index 000000000..919242b75 --- /dev/null +++ b/vtkm/filter/multi_block/MergeDataSets.cxx @@ -0,0 +1,32 @@ +//============================================================================ +// 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 +#include +namespace vtkm +{ +namespace filter +{ +namespace multi_block +{ +vtkm::cont::PartitionedDataSet MergeDataSets::DoExecutePartitions( + const vtkm::cont::PartitionedDataSet& input) +{ + vtkm::cont::DataSet mergedResult = + vtkm::cont::MergePartitionedDataSet(input, this->GetInvalidValue()); + return vtkm::cont::PartitionedDataSet(mergedResult); +} +vtkm::cont::DataSet MergeDataSets::DoExecute(const vtkm::cont::DataSet&) +{ + throw vtkm::cont::ErrorFilterExecution("MergeDataSets only works for a PartitionedDataSet"); +} +} // namespace multi_block +} // namespace filter +} // namespace vtkm diff --git a/vtkm/filter/multi_block/MergeDataSets.h b/vtkm/filter/multi_block/MergeDataSets.h new file mode 100644 index 000000000..1ba697051 --- /dev/null +++ b/vtkm/filter/multi_block/MergeDataSets.h @@ -0,0 +1,46 @@ +//============================================================================ +// 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_multi_block_MergeDataSets_h +#define vtk_m_filter_multi_block_MergeDataSets_h + +#include +#include +#include + +namespace vtkm +{ +namespace filter +{ +namespace multi_block +{ +/// \brief Merging multiple data sets into one data set. +/// +/// This filter merges multiple data sets into one data set. We assume that the input data sets +/// have the same coordinate system. If there are missing fields in a specific data set, +// the filter uses the InvalidValue specified by the user to fill in the associated position of the field array. +class VTKM_FILTER_MULTI_BLOCK_EXPORT MergeDataSets : public vtkm::filter::Filter +{ +public: + void SetInvalidValue(vtkm::Float64 invalidValue) { this->InvalidValue = invalidValue; }; + vtkm::Float64 GetInvalidValue() { return this->InvalidValue; } + +private: + vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& inputDataSet) override; + + vtkm::cont::PartitionedDataSet DoExecutePartitions( + const vtkm::cont::PartitionedDataSet& input) override; + + vtkm::Float64 InvalidValue = vtkm::Nan64(); +}; +} // namespace multi_block +} // namesapce filter +} // namespace vtkm + +#endif //vtk_m_filter_multi_block_MergeDataSets_h diff --git a/vtkm/filter/multi_block/testing/CMakeLists.txt b/vtkm/filter/multi_block/testing/CMakeLists.txt index 9a4406306..1fddab52a 100644 --- a/vtkm/filter/multi_block/testing/CMakeLists.txt +++ b/vtkm/filter/multi_block/testing/CMakeLists.txt @@ -10,6 +10,7 @@ set(libraries vtkm_filter_multi_block + vtkm_filter_geometry_refinement vtkm_source vtkm_rendering vtkm_rendering_testing @@ -18,9 +19,13 @@ set(libraries set(unit_tests RenderTestAmrArrays.cxx ) +set(unit_tests_device + UnitTestMergeDataSetsFilter.cxx + ) vtkm_unit_tests( SOURCES ${unit_tests} + DEVICE_SOURCES ${unit_tests_device} LIBRARIES ${libraries} USE_VTKM_JOB_POOL ) diff --git a/vtkm/filter/multi_block/testing/UnitTestMergeDataSetsFilter.cxx b/vtkm/filter/multi_block/testing/UnitTestMergeDataSetsFilter.cxx new file mode 100644 index 000000000..0c158d01f --- /dev/null +++ b/vtkm/filter/multi_block/testing/UnitTestMergeDataSetsFilter.cxx @@ -0,0 +1,623 @@ +//============================================================================ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +namespace +{ +struct SetPointValuesV4Worklet : public vtkm::worklet::WorkletMapField +{ + using ControlSignature = void(FieldIn, FieldOut); + using ExecutionSignature = void(_1, _2); + template + VTKM_EXEC void operator()(const CoordinatesType& coordinates, V4Type& vec4) const + { + vec4 = { + coordinates[0] * 0.1, coordinates[1] * 0.1, coordinates[2] * 0.1, coordinates[0] * 0.1 + }; + return; + } +}; +struct SetPointValuesV1Worklet : public vtkm::worklet::WorkletMapField +{ + using ControlSignature = void(FieldIn, FieldOut); + using ExecutionSignature = void(_1, _2); + template + VTKM_EXEC void operator()(const CoordinatesType& coordinates, ScalarType& value) const + { + value = (coordinates[0] + coordinates[1] + coordinates[2]) * 0.1; + return; + } +}; +vtkm::cont::DataSet CreateSingleCellSetData(vtkm::Vec3f coordinates[4]) +{ + const int connectivitySize = 6; + vtkm::Id pointId[connectivitySize] = { 0, 1, 2, 1, 2, 3 }; + vtkm::cont::ArrayHandle connectivity; + connectivity.Allocate(connectivitySize); + for (vtkm::Id i = 0; i < connectivitySize; ++i) + { + connectivity.WritePortal().Set(i, pointId[i]); + } + vtkm::cont::CellSetSingleType<> cellSet; + cellSet.Fill(4, vtkm::CELL_SHAPE_TRIANGLE, 3, connectivity); + vtkm::cont::DataSet dataSet; + dataSet.AddCoordinateSystem( + vtkm::cont::make_CoordinateSystem("coords", coordinates, 4, vtkm::CopyFlag::On)); + dataSet.SetCellSet(cellSet); + + std::vector pointvar(4); + std::iota(pointvar.begin(), pointvar.end(), 15.f); + std::vector cellvar(connectivitySize / 3); + std::iota(cellvar.begin(), cellvar.end(), 132.f); + dataSet.AddPointField("pointVar", pointvar); + dataSet.AddCellField("cellVar", cellvar); + return dataSet; +} + +vtkm::cont::DataSet CreateUniformData(vtkm::Vec2f origin) +{ + vtkm::cont::DataSetBuilderUniform dsb; + vtkm::Id2 dimensions(3, 2); + vtkm::cont::DataSet dataSet = dsb.Create(dimensions, origin, vtkm::Vec2f(1, 1)); + constexpr vtkm::Id nVerts = 6; + constexpr vtkm::Float32 var[nVerts] = { 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }; + dataSet.AddPointField("pointVar", var, nVerts); + constexpr vtkm::Float32 cellvar[2] = { 100.1f, 200.1f }; + dataSet.AddCellField("cellVar", cellvar, 2); + return dataSet; +} + +void TestUniformSameFieldsSameDataTypeSingleCellSet() +{ + std::cout << "TestUniformSameFieldsSameDataTypeSingleCellSet" << std::endl; + const int nVerts = 4; + vtkm::Vec3f coordinates1[nVerts] = { vtkm::Vec3f(0.0, 0.0, 0.0), + vtkm::Vec3f(1.0, 0.0, 0.0), + vtkm::Vec3f(0.0, 1.0, 0.0), + vtkm::Vec3f(1.0, 1.0, 0.0) }; + vtkm::cont::DataSet dataSet1 = CreateSingleCellSetData(coordinates1); + vtkm::Vec3f coordinates2[nVerts] = { vtkm::Vec3f(1.0, 0.0, 0.0), + vtkm::Vec3f(2.0, 0.0, 0.0), + vtkm::Vec3f(1.0, 1.0, 0.0), + vtkm::Vec3f(2.0, 1.0, 0.0) }; + vtkm::cont::DataSet dataSet2 = CreateSingleCellSetData(coordinates2); + vtkm::cont::PartitionedDataSet inputDataSets; + inputDataSets.AppendPartition(dataSet1); + inputDataSets.AppendPartition(dataSet2); + vtkm::filter::multi_block::MergeDataSets mergeDataSets; + auto result = mergeDataSets.Execute(inputDataSets); + //Validating result cell sets + auto cellSet = result.GetPartition(0).GetCellSet(); + vtkm::cont::CellSetSingleType<> singleType = cellSet.AsCellSet>(); + VTKM_TEST_ASSERT(singleType.GetCellShapeAsId() == 5, "Wrong cellShape Id"); + VTKM_TEST_ASSERT(cellSet.GetNumberOfCells() == 4, "Wrong numberOfCells"); + VTKM_TEST_ASSERT(cellSet.GetNumberOfPoints() == 8, "Wrong numberOfPoints"); + const vtkm::cont::ArrayHandle connectivityArray = singleType.GetConnectivityArray( + vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()); + vtkm::cont::ArrayHandle validateConnArray = + vtkm::cont::make_ArrayHandle({ 0, 1, 2, 1, 2, 3, 4, 5, 6, 5, 6, 7 }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(connectivityArray, validateConnArray)); + //Validating result fields + vtkm::cont::ArrayHandle validatePointVar = + vtkm::cont::make_ArrayHandle({ 15.0, 16.0, 17.0, 18.0, 15.0, 16.0, 17.0, 18.0 }); + vtkm::cont::ArrayHandle validateCellVar = + vtkm::cont::make_ArrayHandle({ 132, 133, 132, 133 }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(result.GetPartition(0).GetField("pointVar").GetData(), + validatePointVar), + "wrong pointVar values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles(result.GetPartition(0).GetField("cellVar").GetData(), validateCellVar), + "wrong cellVar values"); + //Validating result coordinates + vtkm::cont::CoordinateSystem coords = result.GetPartition(0).GetCoordinateSystem(); + vtkm::cont::ArrayHandle resultCoords = + coords.GetData().AsArrayHandle>(); + vtkm::cont::ArrayHandle validateCoords = + vtkm::cont::make_ArrayHandle({ { 0, 0, 0 }, + { 1, 0, 0 }, + { 0, 1, 0 }, + { 1, 1, 0 }, + { 1, 0, 0 }, + { 2, 0, 0 }, + { 1, 1, 0 }, + { 2, 1, 0 } }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(resultCoords, validateCoords), + "wrong validateCoords values"); +} + +void TestUniformSameFieldsSameDataType() +{ + std::cout << "TestUniformSameFieldsSameDataType" << std::endl; + vtkm::cont::PartitionedDataSet inputDataSets; + vtkm::cont::DataSet dataSet0 = CreateUniformData(vtkm::Vec2f(0.0, 0.0)); + vtkm::cont::DataSet dataSet1 = CreateUniformData(vtkm::Vec2f(3.0, 0.0)); + inputDataSets.AppendPartition(dataSet0); + inputDataSets.AppendPartition(dataSet1); + vtkm::filter::multi_block::MergeDataSets mergeDataSets; + auto result = mergeDataSets.Execute(inputDataSets); + //validating cellsets + auto cellSet = result.GetPartition(0).GetCellSet(); + vtkm::cont::CellSetExplicit<> explicitType = cellSet.AsCellSet>(); + const vtkm::cont::ArrayHandle connectivityArray = explicitType.GetConnectivityArray( + vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()); + const vtkm::cont::ArrayHandle shapesArray = + explicitType.GetShapesArray(vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()); + const vtkm::cont::ArrayHandle offsetsArray = + explicitType.GetOffsetsArray(vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()); + vtkm::cont::ArrayHandle validateConnectivity = + vtkm::cont::make_ArrayHandle({ 0, 1, 4, 3, 1, 2, 5, 4, 6, 7, 10, 9, 7, 8, 11, 10 }); + vtkm::cont::ArrayHandle validateShapes = + vtkm::cont::make_ArrayHandle({ 9, 9, 9, 9 }); + vtkm::cont::ArrayHandle validateOffsets = + vtkm::cont::make_ArrayHandle({ 0, 4, 8, 12, 16 }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(connectivityArray, validateConnectivity), + "wrong connectivity array"); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(shapesArray, validateShapes), + "wrong connectivity array"); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(offsetsArray, validateOffsets), + "wrong connectivity array"); + // validating fields + vtkm::cont::ArrayHandle validatePointVar = + vtkm::cont::make_ArrayHandle( + { 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f, 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }); + vtkm::cont::ArrayHandle validateCellVar = + vtkm::cont::make_ArrayHandle({ 100.1f, 200.1f, 100.1f, 200.1f }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(result.GetPartition(0).GetField("pointVar").GetData(), + validatePointVar), + "wrong pointVar values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles(result.GetPartition(0).GetField("cellVar").GetData(), validateCellVar), + "wrong cellVar values"); + //validating coordinates + vtkm::cont::CoordinateSystem coords = result.GetPartition(0).GetCoordinateSystem(); + vtkm::cont::ArrayHandle resultCoords = + coords.GetData().AsArrayHandle>(); + vtkm::cont::ArrayHandle validateCoords = + vtkm::cont::make_ArrayHandle({ { 0, 0, 0 }, + { 1, 0, 0 }, + { 2, 0, 0 }, + { 0, 1, 0 }, + { 1, 1, 0 }, + { 2, 1, 0 }, + { 3, 0, 0 }, + { 4, 0, 0 }, + { 5, 0, 0 }, + { 3, 1, 0 }, + { 4, 1, 0 }, + { 5, 1, 0 } }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(resultCoords, validateCoords), + "wrong validateCoords values"); +} +void TestTriangleSameFieldsSameDataType() +{ + std::cout << "TestTriangleSameFieldsSameDataType" << std::endl; + vtkm::cont::PartitionedDataSet input; + vtkm::cont::DataSetBuilderUniform dsb; + vtkm::Id3 dimensions(3, 2, 1); + vtkm::cont::DataSet dataSet0 = dsb.Create(dimensions, + vtkm::make_Vec(0, 0, 0), + vtkm::make_Vec(1, 1, 0)); + constexpr vtkm::Id nVerts = 6; + constexpr vtkm::Float32 var[nVerts] = { 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }; + dataSet0.AddPointField("pointVar", var, nVerts); + constexpr vtkm::Float32 cellvar[2] = { 100.1f, 200.1f }; + dataSet0.AddCellField("cellVar", cellvar, 2); + vtkm::filter::geometry_refinement::Triangulate triangulate; + auto tranDataSet0 = triangulate.Execute(dataSet0); + vtkm::cont::DataSet dataSet1 = dsb.Create(dimensions, + vtkm::make_Vec(3, 0, 0), + vtkm::make_Vec(1, 1, 0)); + constexpr vtkm::Float32 var1[nVerts] = { 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }; + dataSet1.AddPointField("pointVar", var1, nVerts); + constexpr vtkm::Float32 cellvar1[2] = { 100.1f, 200.1f }; + dataSet1.AddCellField("cellVar", cellvar1, 2); + auto tranDataSet1 = triangulate.Execute(dataSet1); + input.AppendPartition(tranDataSet0); + input.AppendPartition(tranDataSet1); + vtkm::filter::multi_block::MergeDataSets mergeDataSets; + auto result = mergeDataSets.Execute(input); + //validating results + auto cellSet = result.GetPartition(0).GetCellSet(); + vtkm::cont::CellSetSingleType<> singleType = cellSet.AsCellSet>(); + VTKM_TEST_ASSERT(singleType.GetCellShapeAsId() == 5, "Wrong cellShape Id"); + VTKM_TEST_ASSERT(cellSet.GetNumberOfCells() == 8, "Wrong numberOfCells"); + VTKM_TEST_ASSERT(cellSet.GetNumberOfPoints() == 12, "Wrong numberOfPoints"); + const vtkm::cont::ArrayHandle connectivityArray = singleType.GetConnectivityArray( + vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()); + vtkm::cont::ArrayHandle validateConnArray = vtkm::cont::make_ArrayHandle( + { 0, 1, 4, 0, 4, 3, 1, 2, 5, 1, 5, 4, 6, 7, 10, 6, 10, 9, 7, 8, 11, 7, 11, 10 }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(connectivityArray, validateConnArray)); + //Validating result fields + vtkm::cont::ArrayHandle validatePointVar = + vtkm::cont::make_ArrayHandle( + { 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f, 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }); + vtkm::cont::ArrayHandle validateCellVar = + vtkm::cont::make_ArrayHandle( + { 100.1f, 100.1f, 200.1f, 200.1f, 100.1f, 100.1f, 200.1f, 200.1f }); + + VTKM_TEST_ASSERT(test_equal_ArrayHandles(result.GetPartition(0).GetField("pointVar").GetData(), + validatePointVar), + "wrong pointVar values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles(result.GetPartition(0).GetField("cellVar").GetData(), validateCellVar), + "wrong cellVar values"); + //Validating result coordinates + vtkm::cont::CoordinateSystem coords = result.GetPartition(0).GetCoordinateSystem(); + vtkm::cont::ArrayHandle resultCoords = + coords.GetData().AsArrayHandle>(); + vtkm::cont::ArrayHandle validateCoords = + vtkm::cont::make_ArrayHandle({ { 0, 0, 0 }, + { 1, 0, 0 }, + { 2, 0, 0 }, + { 0, 1, 0 }, + { 1, 1, 0 }, + { 2, 1, 0 }, + { 3, 0, 0 }, + { 4, 0, 0 }, + { 5, 0, 0 }, + { 3, 1, 0 }, + { 4, 1, 0 }, + { 5, 1, 0 } }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(resultCoords, validateCoords), + "wrong validateCoords values"); +} + +void TestDiffCellsSameFieldsSameDataType() +{ + std::cout << "TestDiffCellsSameFieldsSameDataType" << std::endl; + vtkm::Vec3f coordinates1[4] = { vtkm::Vec3f(0.0, 0.0, 0.0), + vtkm::Vec3f(1.0, 0.0, 0.0), + vtkm::Vec3f(0.0, 1.0, 0.0), + vtkm::Vec3f(1.0, 1.0, 0.0) }; + vtkm::cont::DataSet dataSet0 = CreateSingleCellSetData(coordinates1); + vtkm::cont::DataSet dataSet1 = CreateUniformData(vtkm::Vec2f(3.0, 0.0)); + vtkm::cont::PartitionedDataSet input; + input.AppendPartition(dataSet0); + input.AppendPartition(dataSet1); + vtkm::filter::multi_block::MergeDataSets mergeDataSets; + auto result = mergeDataSets.Execute(input); + //validating cellsets + auto cellSet = result.GetPartition(0).GetCellSet(); + vtkm::cont::CellSetExplicit<> explicitType = cellSet.AsCellSet>(); + const vtkm::cont::ArrayHandle connectivityArray = explicitType.GetConnectivityArray( + vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()); + const vtkm::cont::ArrayHandle shapesArray = + explicitType.GetShapesArray(vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()); + const vtkm::cont::ArrayHandle offsetsArray = + explicitType.GetOffsetsArray(vtkm::TopologyElementTagCell(), vtkm::TopologyElementTagPoint()); + vtkm::cont::ArrayHandle validateConnectivity = + vtkm::cont::make_ArrayHandle({ 0, 1, 2, 1, 2, 3, 4, 5, 8, 7, 5, 6, 9, 8 }); + vtkm::cont::ArrayHandle validateShapes = + vtkm::cont::make_ArrayHandle({ 5, 5, 9, 9 }); + vtkm::cont::ArrayHandle validateOffsets = + vtkm::cont::make_ArrayHandle({ 0, 3, 6, 10, 14 }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(connectivityArray, validateConnectivity), + "wrong connectivity array"); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(shapesArray, validateShapes), + "wrong connectivity array"); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(offsetsArray, validateOffsets), + "wrong connectivity array"); + // Validating fields + vtkm::cont::ArrayHandle validatePointVar = + vtkm::cont::make_ArrayHandle( + { 15.f, 16.f, 17.f, 18.f, 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }); + vtkm::cont::ArrayHandle validateCellVar = + vtkm::cont::make_ArrayHandle({ 132.0f, 133.0f, 100.1f, 200.1f }); + + VTKM_TEST_ASSERT(test_equal_ArrayHandles(result.GetPartition(0).GetField("pointVar").GetData(), + validatePointVar), + "wrong pointVar values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles(result.GetPartition(0).GetField("cellVar").GetData(), validateCellVar), + "wrong cellVar values"); + //Validating coordinates + vtkm::cont::CoordinateSystem coords = result.GetPartition(0).GetCoordinateSystem(); + vtkm::cont::ArrayHandle resultCoords = + coords.GetData().AsArrayHandle>(); + vtkm::cont::ArrayHandle validateCoords = + vtkm::cont::make_ArrayHandle({ { 0, 0, 0 }, + { 1, 0, 0 }, + { 0, 1, 0 }, + { 1, 1, 0 }, + { 3, 0, 0 }, + { 4, 0, 0 }, + { 5, 0, 0 }, + { 3, 1, 0 }, + { 4, 1, 0 }, + { 5, 1, 0 } }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(resultCoords, validateCoords), "Wrong coords values"); +} + +void TestDifferentCoords() +{ + std::cout << "TestDifferentCoords" << std::endl; + vtkm::cont::PartitionedDataSet inputDataSets; + vtkm::cont::DataSet dataSet0 = CreateUniformData(vtkm::Vec2f(0.0, 0.0)); + vtkm::Vec3f coordinates[6]; + dataSet0.AddCoordinateSystem( + vtkm::cont::make_CoordinateSystem("coordsExtra", coordinates, 6, vtkm::CopyFlag::On)); + vtkm::cont::DataSet dataSet1 = CreateUniformData(vtkm::Vec2f(3.0, 0.0)); + inputDataSets.AppendPartition(dataSet0); + inputDataSets.AppendPartition(dataSet1); + vtkm::filter::multi_block::MergeDataSets mergeDataSets; + try + { + auto result = mergeDataSets.Execute(inputDataSets); + } + catch (vtkm::cont::ErrorExecution& e) + { + VTKM_TEST_ASSERT(e.GetMessage().find("Data sets have different number of coordinate systems") != + std::string::npos); + } + vtkm::cont::DataSetBuilderUniform dsb; + vtkm::Id2 dimensions(3, 2); + vtkm::cont::DataSet dataSet2 = dsb.Create(dimensions, vtkm::Vec2f(0.0, 0.0), vtkm::Vec2f(1, 1)); + constexpr vtkm::Float32 var2[6] = { 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }; + dataSet2.AddPointField("pointVarExtra", var2, 6); + constexpr vtkm::Float32 cellvar2[2] = { 100.1f, 200.1f }; + dataSet2.AddCellField("cellVarExtra", cellvar2, 2); + vtkm::cont::PartitionedDataSet inputDataSets2; + inputDataSets2.AppendPartition(dataSet1); + inputDataSets2.AppendPartition(dataSet2); + try + { + auto result = mergeDataSets.Execute(inputDataSets2); + } + catch (vtkm::cont::ErrorExecution& e) + { + VTKM_TEST_ASSERT(e.GetMessage().find("Coordinates system name:") != std::string::npos); + } +} + +void TestSameFieldsDifferentDataType() +{ + std::cout << "TestSameFieldsDifferentDataType" << std::endl; + vtkm::cont::DataSetBuilderUniform dsb; + vtkm::Id2 dimensions(3, 2); + vtkm::cont::DataSet dataSet1 = dsb.Create(dimensions, vtkm::Vec2f(0.0, 0.0), vtkm::Vec2f(1, 1)); + constexpr vtkm::Float32 var[6] = { 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }; + dataSet1.AddPointField("pointVar", var, 6); + constexpr vtkm::Float32 cellvar[2] = { 100.1f, 200.1f }; + dataSet1.AddCellField("cellVar", cellvar, 2); + vtkm::cont::DataSet dataSet2 = dsb.Create(dimensions, vtkm::Vec2f(0.0, 0.0), vtkm::Vec2f(1, 1)); + constexpr vtkm::Id var2[6] = { 10, 20, 30, 40, 50, 60 }; + dataSet2.AddPointField("pointVar", var2, 6); + constexpr vtkm::Id cellvar2[2] = { 100, 200 }; + dataSet2.AddCellField("cellVar", cellvar2, 2); + vtkm::cont::PartitionedDataSet inputDataSets; + inputDataSets.AppendPartition(dataSet1); + inputDataSets.AppendPartition(dataSet2); + vtkm::filter::multi_block::MergeDataSets mergeDataSets; + auto result = mergeDataSets.Execute(inputDataSets); + //Validating fields in results, they will use the first partition's field type + vtkm::cont::ArrayHandle validatePointVar = + vtkm::cont::make_ArrayHandle( + { 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 60.0f }); + vtkm::cont::ArrayHandle validateCellVar = + vtkm::cont::make_ArrayHandle({ 100.1f, 200.1f, 100.0f, 200.0f }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(result.GetPartition(0).GetField("pointVar").GetData(), + validatePointVar), + "wrong pointVar values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles(result.GetPartition(0).GetField("cellVar").GetData(), validateCellVar), + "wrong cellVar values"); +} +void TestMissingFieldsAndSameFieldName() +{ + std::cout << "TestMissingFieldsAndSameFieldName" << std::endl; + vtkm::cont::DataSetBuilderUniform dsb; + vtkm::Id2 dimensions(3, 2); + vtkm::cont::DataSet dataSet1 = dsb.Create(dimensions, vtkm::Vec2f(0.0, 0.0), vtkm::Vec2f(1, 1)); + constexpr vtkm::Float32 pointVar[6] = { 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }; + vtkm::cont::DataSet dataSet2 = dsb.Create(dimensions, vtkm::Vec2f(0.0, 0.0), vtkm::Vec2f(1, 1)); + constexpr vtkm::Id cellvar[2] = { 100, 200 }; + vtkm::cont::PartitionedDataSet inputDataSets; + dataSet1.AddPointField("pointVar", pointVar, 6); + dataSet2.AddCellField("cellVar", cellvar, 2); + //For testing the case where one field is associated with point in one partition + //and one field (with a same name) is associated with cell in another partition + dataSet1.AddPointField("fieldSameName", pointVar, 6); + dataSet2.AddCellField("fieldSameName", cellvar, 2); + //For testing the case where one partition have point field and a cell field with the same name. + dataSet1.AddPointField("fieldSameName2", pointVar, 6); + dataSet2.AddPointField("fieldSameName2", pointVar, 6); + dataSet2.AddCellField("fieldSameName2", cellvar, 2); + inputDataSets.AppendPartition(dataSet1); + inputDataSets.AppendPartition(dataSet2); + vtkm::filter::multi_block::MergeDataSets mergeDataSets; + mergeDataSets.SetInvalidValue(vtkm::Float64(0)); + auto result = mergeDataSets.Execute(inputDataSets); + //Validating fields in results, they will use InvalidValues for missing fields + vtkm::cont::ArrayHandle validatePointVar1 = + vtkm::cont::make_ArrayHandle( + { 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }); + vtkm::cont::ArrayHandle validatePointVar2 = + vtkm::cont::make_ArrayHandle( + { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }); + vtkm::cont::ArrayHandle validatePointVar3 = + vtkm::cont::make_ArrayHandle( + { 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f, 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }); + vtkm::cont::ArrayHandle validateCellVar = + vtkm::cont::make_ArrayHandle({ 0, 0, 100, 200 }); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles( + result.GetPartition(0).GetField("pointVar", vtkm::cont::Field::Association::Points).GetData(), + validatePointVar1), + "wrong pointVar values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles( + result.GetPartition(0).GetField("cellVar", vtkm::cont::Field::Association::Cells).GetData(), + validateCellVar), + "wrong cellVar values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles(result.GetPartition(0) + .GetField("fieldSameName", vtkm::cont::Field::Association::Points) + .GetData(), + validatePointVar1), + "wrong fieldSameName values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles(result.GetPartition(0) + .GetField("fieldSameName", vtkm::cont::Field::Association::Cells) + .GetData(), + validateCellVar), + "wrong fieldSameName values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles(result.GetPartition(0) + .GetField("fieldSameName2", vtkm::cont::Field::Association::Points) + .GetData(), + validatePointVar3), + "wrong fieldSameName2 values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles(result.GetPartition(0) + .GetField("fieldSameName2", vtkm::cont::Field::Association::Cells) + .GetData(), + validateCellVar), + "wrong fieldSameName2 values"); +} + +void TestCustomizedVecField() +{ + std::cout << "TestCustomizedVecField" << std::endl; + vtkm::cont::DataSetBuilderUniform dsb; + vtkm::Id2 dimensions(3, 2); + vtkm::cont::DataSet dataSet1 = dsb.Create(dimensions, vtkm::Vec2f(0.0, 0.0), vtkm::Vec2f(1, 1)); + vtkm::cont::ArrayHandle> pointVar1Vec4; + pointVar1Vec4.Allocate(6); + vtkm::cont::Invoker invoker; + invoker(SetPointValuesV4Worklet{}, dataSet1.GetCoordinateSystem().GetData(), pointVar1Vec4); + dataSet1.AddPointField("pointVarV4", pointVar1Vec4); + vtkm::cont::DataSet dataSet2 = dsb.Create(dimensions, vtkm::Vec2f(3.0, 0.0), vtkm::Vec2f(1, 1)); + vtkm::cont::ArrayHandle> pointVar2Vec4; + pointVar2Vec4.Allocate(6); + invoker(SetPointValuesV4Worklet{}, dataSet2.GetCoordinateSystem().GetData(), pointVar2Vec4); + dataSet2.AddPointField("pointVarV4", pointVar2Vec4); + vtkm::cont::PartitionedDataSet inputDataSets; + inputDataSets.AppendPartition(dataSet1); + inputDataSets.AppendPartition(dataSet2); + vtkm::filter::multi_block::MergeDataSets mergeDataSets; + auto result = mergeDataSets.Execute(inputDataSets); + vtkm::cont::ArrayHandle> validatePointVar; + //Set point validatePointVar array based on coordinates. + invoker(SetPointValuesV4Worklet{}, + result.GetPartition(0).GetCoordinateSystem().GetData(), + validatePointVar); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(result.GetPartition(0).GetField("pointVarV4").GetData(), + validatePointVar), + "wrong pointVar values"); +} + +void TestMoreThanTwoPartitions() +{ + std::cout << "TestMoreThanTwoPartitions" << std::endl; + vtkm::cont::DataSetBuilderUniform dsb; + vtkm::Id2 dimensions(3, 2); + vtkm::cont::Invoker invoker; + vtkm::cont::PartitionedDataSet inputDataSets; + for (vtkm::Id i = 0; i < 5; i++) + { + for (vtkm::Id j = 0; j < 5; j++) + { + vtkm::cont::DataSet dataSet = dsb.Create( + dimensions, + vtkm::Vec2f(static_cast(i), static_cast(j)), + vtkm::Vec2f(1, 1)); + vtkm::cont::ArrayHandle pointVarArray; + invoker(SetPointValuesV1Worklet{}, dataSet.GetCoordinateSystem().GetData(), pointVarArray); + dataSet.AddPointField("pointVar", pointVarArray); + inputDataSets.AppendPartition(dataSet); + } + } + vtkm::filter::multi_block::MergeDataSets mergeDataSets; + auto result = mergeDataSets.Execute(inputDataSets); + vtkm::cont::ArrayHandle validatePointVar; + invoker(SetPointValuesV1Worklet{}, + result.GetPartition(0).GetCoordinateSystem().GetData(), + validatePointVar); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(result.GetPartition(0).GetField("pointVar").GetData(), + validatePointVar), + "wrong pointVar values"); +} + +void TestEmptyPartitions() +{ + std::cout << "TestEmptyPartitions" << std::endl; + vtkm::cont::PartitionedDataSet inputDataSets; + vtkm::cont::DataSet dataSet1 = CreateUniformData(vtkm::Vec2f(0.0, 0.0)); + vtkm::cont::DataSet dataSet2; + inputDataSets.AppendPartition(dataSet1); + inputDataSets.AppendPartition(dataSet2); + vtkm::filter::multi_block::MergeDataSets mergeDataSets; + auto result = mergeDataSets.Execute(inputDataSets); + //Validating data sets + VTKM_TEST_ASSERT(result.GetNumberOfPartitions() == 1, "Wrong number of partitions"); + auto cellSet = result.GetPartition(0).GetCellSet(); + VTKM_TEST_ASSERT(cellSet.GetNumberOfCells() == 2, "Wrong numberOfCells"); + VTKM_TEST_ASSERT(cellSet.GetNumberOfPoints() == 6, "Wrong numberOfPoints"); + vtkm::cont::ArrayHandle validatePointVar = + vtkm::cont::make_ArrayHandle({ 10.1f, 20.1f, 30.1f, 40.1f, 50.1f, 60.1f }); + vtkm::cont::ArrayHandle validateCellVar = + vtkm::cont::make_ArrayHandle({ 100.1f, 200.1f }); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(result.GetPartition(0).GetField("pointVar").GetData(), + validatePointVar), + "wrong pointVar values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles(result.GetPartition(0).GetField("cellVar").GetData(), validateCellVar), + "wrong cellVar values"); + vtkm::cont::PartitionedDataSet inputDataSets2; + inputDataSets2.AppendPartition(dataSet2); + inputDataSets2.AppendPartition(dataSet1); + auto result2 = mergeDataSets.Execute(inputDataSets2); + VTKM_TEST_ASSERT(result2.GetNumberOfPartitions() == 1, "Wrong number of partitions"); + cellSet = result2.GetPartition(0).GetCellSet(); + VTKM_TEST_ASSERT(cellSet.GetNumberOfCells() == 2, "Wrong numberOfCells"); + VTKM_TEST_ASSERT(cellSet.GetNumberOfPoints() == 6, "Wrong numberOfPoints"); + VTKM_TEST_ASSERT(test_equal_ArrayHandles(result2.GetPartition(0).GetField("pointVar").GetData(), + validatePointVar), + "wrong pointVar values"); + VTKM_TEST_ASSERT( + test_equal_ArrayHandles(result2.GetPartition(0).GetField("cellVar").GetData(), validateCellVar), + "wrong cellVar values"); +} + +void TestMergeDataSetsFilter() +{ + //same cell type (triangle), same field name, same data type, cellset is single type + TestUniformSameFieldsSameDataTypeSingleCellSet(); + //same cell type (square), same field name, same data type + TestUniformSameFieldsSameDataType(); + //same cell type (triangle), same field name, same data type + TestTriangleSameFieldsSameDataType(); + //same cell type (square), same field name, different data type + TestSameFieldsDifferentDataType(); + //different coordinates name + TestDifferentCoords(); + //different cell types, same field name, same type + TestDiffCellsSameFieldsSameDataType(); + //test multiple partitions + TestMoreThanTwoPartitions(); + //some partitions have missing fields + TestMissingFieldsAndSameFieldName(); + //test empty partitions + TestEmptyPartitions(); + //test customized types + TestCustomizedVecField(); +} +} // anonymous namespace +int UnitTestMergeDataSetsFilter(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(TestMergeDataSetsFilter, argc, argv); +} diff --git a/vtkm/filter/multi_block/vtkm.module b/vtkm/filter/multi_block/vtkm.module index 8503072c7..f06e5e7f3 100644 --- a/vtkm/filter/multi_block/vtkm.module +++ b/vtkm/filter/multi_block/vtkm.module @@ -10,3 +10,4 @@ TEST_DEPENDS vtkm_source vtkm_rendering vtkm_rendering_testing + vtkm_filter_geometry_refinement