Merge topic '405_partitioned_ds'

63050f68f `MultiBlock` renamed to `PartitionedDataSet`

Acked-by: Kitware Robot <kwrobot@kitware.com>
Acked-by: Utkarsh Ayachit <utkarsh.ayachit@kitware.com>
Merge-request: !1821
This commit is contained in:
Allison Vacanti 2019-09-04 11:21:55 +00:00 committed by Kitware Robot
commit e8afcfd7d8
45 changed files with 836 additions and 781 deletions

@ -0,0 +1,16 @@
# `MultiBlock` renamed to `PartitionedDataSet`
The `MultiBlock` class has been renamed to `PartitionedDataSet`, and its API
has been refactored to refer to "partitions", rather than "blocks".
Additionally, the `AddBlocks` method has been changed to `AppendPartitions` to
more accurately reflect the operation performed. The associated
`AssignerMultiBlock` class has also been renamed to
`AssignerPartitionedDataSet`.
This change is motivated towards unifying VTK-m's data model with VTK. VTK has
started to move away from `vtkMultiBlockDataSet`, which is a hierarchical tree
of nested datasets, to `vtkPartitionedDataSet`, which is always a flat vector
of datasets used to assist geometry distribution in multi-process environments.
This simplifies traversal during processing and clarifies the intent of the
container: The component datasets are partitions for distribution, not
organizational groupings (e.g. materials).

@ -80,18 +80,18 @@ int main(int argc, char* argv[])
const vtkm::Id num_bins = static_cast<vtkm::Id>(std::atoi(argv[1]));
const vtkm::Id numVals = 1024;
vtkm::cont::MultiBlock mb;
vtkm::cont::PartitionedDataSet pds;
vtkm::cont::DataSet ds;
vtkm::cont::DataSetFieldAdd::AddPointField(ds, "pointvar", CreateArray(-1024, 1024, numVals));
mb.AddBlock(ds);
pds.AppendPartition(ds);
example::HistogramMPI histogram;
histogram.SetActiveField("pointvar");
histogram.SetNumberOfBins(std::max<vtkm::Id>(1, num_bins));
vtkm::cont::MultiBlock result = histogram.Execute(mb);
vtkm::cont::PartitionedDataSet result = histogram.Execute(pds);
vtkm::cont::ArrayHandle<vtkm::Id> bins;
result.GetBlock(0).GetField("histogram").GetData().CopyTo(bins);
result.GetPartition(0).GetField("histogram").GetData().CopyTo(bins);
auto binPortal = bins.GetPortalConstControl();
if (rank == 0)
{

@ -65,16 +65,16 @@ public:
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
//@{
/// when operating on vtkm::cont::MultiBlock, we
/// when operating on vtkm::cont::PartitionedDataSet, we
/// want to do processing across ranks as well. Just adding pre/post handles
/// for the same does the trick.
template <typename DerivedPolicy>
VTKM_CONT void PreExecute(const vtkm::cont::MultiBlock& input,
VTKM_CONT void PreExecute(const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
template <typename DerivedPolicy>
VTKM_CONT void PostExecute(const vtkm::cont::MultiBlock& input,
vtkm::cont::MultiBlock& output,
VTKM_CONT void PostExecute(const vtkm::cont::PartitionedDataSet& input,
vtkm::cont::PartitionedDataSet& output,
const vtkm::filter::PolicyBase<DerivedPolicy>&);
//@}

@ -12,7 +12,7 @@
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/AssignerMultiBlock.h>
#include <vtkm/cont/AssignerPartitionedDataSet.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/ErrorFilterExecution.h>
#include <vtkm/cont/FieldRangeGlobalCompute.h>
@ -143,7 +143,7 @@ inline VTKM_CONT vtkm::cont::DataSet HistogramMPI::DoExecute(
//-----------------------------------------------------------------------------
template <typename DerivedPolicy>
inline VTKM_CONT void HistogramMPI::PreExecute(const vtkm::cont::MultiBlock& input,
inline VTKM_CONT void HistogramMPI::PreExecute(const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>&)
{
if (this->Range.IsNonEmpty())
@ -164,15 +164,15 @@ inline VTKM_CONT void HistogramMPI::PreExecute(const vtkm::cont::MultiBlock& inp
//-----------------------------------------------------------------------------
template <typename DerivedPolicy>
inline VTKM_CONT void HistogramMPI::PostExecute(const vtkm::cont::MultiBlock&,
vtkm::cont::MultiBlock& result,
inline VTKM_CONT void HistogramMPI::PostExecute(const vtkm::cont::PartitionedDataSet&,
vtkm::cont::PartitionedDataSet& result,
const vtkm::filter::PolicyBase<DerivedPolicy>&)
{
// iterate and compute HistogramMPI for each local block.
detail::DistributedHistogram helper(result.GetNumberOfBlocks());
for (vtkm::Id cc = 0; cc < result.GetNumberOfBlocks(); ++cc)
detail::DistributedHistogram helper(result.GetNumberOfPartitions());
for (vtkm::Id cc = 0; cc < result.GetNumberOfPartitions(); ++cc)
{
auto& ablock = result.GetBlock(cc);
auto& ablock = result.GetPartition(cc);
helper.SetLocalHistogram(cc, ablock.GetField(this->GetOutputFieldName()));
}
@ -182,6 +182,6 @@ inline VTKM_CONT void HistogramMPI::PostExecute(const vtkm::cont::MultiBlock&,
helper.ReduceAll(this->NumberOfBins));
output.AddField(rfield);
result = vtkm::cont::MultiBlock(output);
result = vtkm::cont::PartitionedDataSet(output);
}
} // namespace example

@ -51,46 +51,47 @@ vtkm::cont::DataSet make_test3DImageData(vtkm::Id3 dims)
}
//=================================================================
void io_generator(TaskQueue<vtkm::cont::MultiBlock>& queue, std::size_t numberOfTasks)
void io_generator(TaskQueue<vtkm::cont::PartitionedDataSet>& queue, std::size_t numberOfTasks)
{
//Step 1. We want to build an initial set of blocks
//Step 1. We want to build an initial set of partitions
//that vary in size. This way we can generate uneven
//work to show off the vtk-m filter work distribution
vtkm::Id3 small(128, 128, 128);
vtkm::Id3 medium(256, 256, 128);
vtkm::Id3 large(512, 256, 128);
std::vector<vtkm::Id3> block_sizes;
block_sizes.push_back(small);
block_sizes.push_back(medium);
block_sizes.push_back(large);
std::vector<vtkm::Id3> partition_sizes;
partition_sizes.push_back(small);
partition_sizes.push_back(medium);
partition_sizes.push_back(large);
std::mt19937 rng;
//uniform_int_distribution is a closed interval [] so both the min and max
//can be chosen values
std::uniform_int_distribution<vtkm::Id> blockNumGen(6, 32);
std::uniform_int_distribution<std::size_t> blockPicker(0, block_sizes.size() - 1);
std::uniform_int_distribution<vtkm::Id> partitionNumGen(6, 32);
std::uniform_int_distribution<std::size_t> partitionPicker(0, partition_sizes.size() - 1);
for (std::size_t i = 0; i < numberOfTasks; ++i)
{
//Step 2. Construct a random number of blocks
const vtkm::Id numberOfBlocks = blockNumGen(rng);
//Step 2. Construct a random number of partitions
const vtkm::Id numberOfPartitions = partitionNumGen(rng);
//Step 3. Randomly pick the blocks in the dataset
vtkm::cont::MultiBlock mb(numberOfBlocks);
for (vtkm::Id b = 0; b < numberOfBlocks; ++b)
//Step 3. Randomly pick the partitions in the dataset
vtkm::cont::PartitionedDataSet pds(numberOfPartitions);
for (vtkm::Id p = 0; p < numberOfPartitions; ++p)
{
const auto& dims = block_sizes[blockPicker(rng)];
auto block = make_test3DImageData(dims);
mb.AddBlock(block);
const auto& dims = partition_sizes[partitionPicker(rng)];
auto partition = make_test3DImageData(dims);
pds.AppendPartition(partition);
}
std::cout << "adding multi-block with " << mb.GetNumberOfBlocks() << " blocks" << std::endl;
std::cout << "adding partitioned dataset with " << pds.GetNumberOfPartitions() << " partitions"
<< std::endl;
//Step 4. Add the multi-block to the queue. We explicitly
//Step 4. Add the partitioned dataset to the queue. We explicitly
//use std::move to signal that this thread can't use the
//mb object after this call
queue.push(std::move(mb));
//pds object after this call
queue.push(std::move(pds));
//Step 5. Go to sleep for a period of time to replicate
//data stream in

@ -12,9 +12,9 @@
#include "TaskQueue.h"
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
vtkm::cont::DataSet make_test3DImageData(int xdim, int ydim, int zdim);
void io_generator(TaskQueue<vtkm::cont::MultiBlock>& queue, std::size_t numberOfTasks);
void io_generator(TaskQueue<vtkm::cont::PartitionedDataSet>& queue, std::size_t numberOfTasks);
#endif

@ -12,7 +12,7 @@
#include <thread>
#include <vtkm/cont/Initialize.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include "IOGenerator.h"
#include "MultiDeviceGradient.h"
@ -22,9 +22,9 @@
//
//At a high level we have 2 primary threads, an IO thread and a Worker thread
//The IO thread will generate all data using the vtk-m serial device, and
//will post this data to a worker queue as a vtk-m multiblock.
//The Worker thread will pull down these vtk-m multiblock data and run a
//vtk-m filter on the multiblock.
//will post this data to a worker queue as a vtk-m partitioned dataset.
//The Worker thread will pull down these vtk-m data and run a
//vtk-m filter on the partitions.
//The vtk-m filter it runs will itself have a worker pool which it will
//distribute work too. The number of workers is based on what device adapters
//are enabled but uses the following logic:
@ -38,7 +38,7 @@
//and single GPU we should expect that we will have 2 primary 'main loop'
//threads, and 5 threads for heavy 'task' work.
void multiblock_processing(TaskQueue<vtkm::cont::MultiBlock>& queue);
void partition_processing(TaskQueue<vtkm::cont::PartitionedDataSet>& queue);
int main(int argc, char** argv)
{
auto opts =
@ -48,9 +48,9 @@ int main(int argc, char** argv)
//Step 1. Construct the two primary 'main loops'. The threads
//share a queue object so we need to explicitly pass it
//by reference (the std::ref call)
TaskQueue<vtkm::cont::MultiBlock> queue;
TaskQueue<vtkm::cont::PartitionedDataSet> queue;
std::thread io(io_generator, std::ref(queue), 6);
std::thread worker(multiblock_processing, std::ref(queue));
std::thread worker(partition_processing, std::ref(queue));
//Step N. Wait for the work to finish
io.join();
@ -59,7 +59,7 @@ int main(int argc, char** argv)
}
//=================================================================
void multiblock_processing(TaskQueue<vtkm::cont::MultiBlock>& queue)
void partition_processing(TaskQueue<vtkm::cont::PartitionedDataSet>& queue)
{
//Step 1. Construct the gradient filter outside the work loop
//so that we can reuse the thread pool it constructs
@ -67,42 +67,37 @@ void multiblock_processing(TaskQueue<vtkm::cont::MultiBlock>& queue)
gradient.SetComputePointGradient(true);
while (queue.hasTasks())
{
//Step 2. grab the next multi-block skipping any that are empty
//Step 2. grab the next partition skipping any that are empty
//as empty ones can be returned when the queue is about
//to say it has no work
vtkm::cont::MultiBlock mb = queue.pop();
if (mb.GetNumberOfBlocks() == 0)
vtkm::cont::PartitionedDataSet pds = queue.pop();
if (pds.GetNumberOfPartitions() == 0)
{
continue;
}
//Step 3. Get the first field name from the multi-block
std::string fieldName = mb.GetBlock(0).GetField(0).GetName();
//Step 3. Get the first field name from the partition
std::string fieldName = pds.GetPartition(0).GetField(0).GetName();
//Step 4. Run a multi device gradient
gradient.SetActiveField(fieldName);
vtkm::cont::MultiBlock result = gradient.Execute(mb);
std::cout << "finished processing a multi-block" << std::endl;
vtkm::cont::PartitionedDataSet result = gradient.Execute(pds);
std::cout << "finished processing a partitioned dataset" << std::endl;
//Step 5. Verify each block has a "Gradients" field
for (auto&& block : result)
//Step 5. Verify each partition has a "Gradients" field
for (auto&& partition : result)
{
// std::cout << std::endl << std::endl << std::endl;
// std::cout << "block: " << std::endl;
// block.PrintSummary(std::cout);
try
{
const auto& field = block.GetField("Gradients", vtkm::cont::Field::Association::POINTS);
(void)field;
}
catch (const vtkm::cont::ErrorBadValue& error)
// std::cout << "partition: " << std::endl;
// partition.PrintSummary(std::cout);
if (!partition.HasField("Gradients", vtkm::cont::Field::Association::POINTS))
{
std::cerr << "Gradient filter failed!" << std::endl;
std::cerr << error.GetMessage() << std::endl;
std::cerr << "Missing Gradient field on output partition." << std::endl;
break;
}
}
}
std::cout << "multiblock_processing finished" << std::endl;
std::cout << "partition_processing finished" << std::endl;
}

@ -13,6 +13,6 @@
#include "MultiDeviceGradient.h"
#include "MultiDeviceGradient.hxx"
template vtkm::cont::MultiBlock MultiDeviceGradient::PrepareForExecution<
vtkm::filter::PolicyDefault>(const vtkm::cont::MultiBlock&,
template vtkm::cont::PartitionedDataSet MultiDeviceGradient::PrepareForExecution<
vtkm::filter::PolicyDefault>(const vtkm::cont::PartitionedDataSet&,
const vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>&);

@ -18,7 +18,7 @@
using RuntimeTaskQueue = TaskQueue<std::function<void()>>;
/// \brief Construct a MultiDeviceGradient for a given multiblock dataset
/// \brief Construct a MultiDeviceGradient for a given partitioned dataset
///
/// The Policy used with MultiDeviceGradient must include the TBB and CUDA
/// backends.
@ -45,8 +45,8 @@ public:
/// Will submit each block to a work queue that the threads will
/// pull work from
template <typename DerivedPolicy>
VTKM_CONT vtkm::cont::MultiBlock PrepareForExecution(
const vtkm::cont::MultiBlock&,
VTKM_CONT vtkm::cont::PartitionedDataSet PrepareForExecution(
const vtkm::cont::PartitionedDataSet&,
const vtkm::filter::PolicyBase<DerivedPolicy>&);
private:
@ -56,8 +56,8 @@ private:
};
#ifndef vtk_m_examples_multibackend_MultiDeviceGradient_cxx
extern template vtkm::cont::MultiBlock MultiDeviceGradient::PrepareForExecution<
vtkm::filter::PolicyDefault>(const vtkm::cont::MultiBlock&,
extern template vtkm::cont::PartitionedDataSet MultiDeviceGradient::PrepareForExecution<
vtkm::filter::PolicyDefault>(const vtkm::cont::PartitionedDataSet&,
const vtkm::filter::PolicyBase<vtkm::filter::PolicyDefault>&);
#endif

@ -32,7 +32,7 @@ int determine_cuda_gpu_count()
return count;
}
void process_block_tbb(RuntimeTaskQueue& queue)
void process_partition_tbb(RuntimeTaskQueue& queue)
{
//Step 1. Set the device adapter to this thread to TBB.
//This makes sure that any vtkm::filters used by our
@ -56,11 +56,11 @@ void process_block_tbb(RuntimeTaskQueue& queue)
//Step 4. Notify the queue that we finished processing this task
queue.completedTask();
std::cout << "finished a block on tbb (" << std::this_thread::get_id() << ")" << std::endl;
std::cout << "finished a partition on tbb (" << std::this_thread::get_id() << ")" << std::endl;
}
}
void process_block_openMP(RuntimeTaskQueue& queue)
void process_partition_openMP(RuntimeTaskQueue& queue)
{
//Step 1. Set the device adapter to this thread to TBB.
//This makes sure that any vtkm::filters used by our
@ -84,11 +84,11 @@ void process_block_openMP(RuntimeTaskQueue& queue)
//Step 4. Notify the queue that we finished processing this task
queue.completedTask();
std::cout << "finished a block on tbb (" << std::this_thread::get_id() << ")" << std::endl;
std::cout << "finished a partition on tbb (" << std::this_thread::get_id() << ")" << std::endl;
}
}
void process_block_cuda(RuntimeTaskQueue& queue, int gpuId)
void process_partition_cuda(RuntimeTaskQueue& queue, int gpuId)
{
//Step 1. Set the device adapter to this thread to cuda.
//This makes sure that any vtkm::filters used by our
@ -113,7 +113,7 @@ void process_block_cuda(RuntimeTaskQueue& queue, int gpuId)
//Step 4. Notify the queue that we finished processing this task
queue.completedTask();
std::cout << "finished a block on cuda (" << std::this_thread::get_id() << ")" << std::endl;
std::cout << "finished a partition on cuda (" << std::this_thread::get_id() << ")" << std::endl;
}
}
@ -149,10 +149,10 @@ VTKM_CONT MultiDeviceGradient::MultiDeviceGradient()
//The number of workers per GPU is purely arbitrary currently,
//but in general we want multiple of them so we can overlap compute
//and transfer
this->Workers.emplace_back(std::bind(process_block_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_block_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_block_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_block_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
this->Workers.emplace_back(std::bind(process_partition_cuda, std::ref(this->Queue), i));
}
}
//Step 3. Launch a worker that will use openMP (if enabled).
@ -161,7 +161,7 @@ VTKM_CONT MultiDeviceGradient::MultiDeviceGradient()
else if (runOnOpenMP)
{
std::cout << "adding a openMP worker" << std::endl;
this->Workers.emplace_back(std::bind(process_block_openMP, std::ref(this->Queue)));
this->Workers.emplace_back(std::bind(process_partition_openMP, std::ref(this->Queue)));
}
//Step 4. Launch a worker that will use tbb (if enabled).
//The threads share a queue object so we need to explicitly pass it
@ -169,7 +169,7 @@ VTKM_CONT MultiDeviceGradient::MultiDeviceGradient()
else if (runOnTbb)
{
std::cout << "adding a tbb worker" << std::endl;
this->Workers.emplace_back(std::bind(process_block_tbb, std::ref(this->Queue)));
this->Workers.emplace_back(std::bind(process_partition_tbb, std::ref(this->Queue)));
}
}
@ -187,49 +187,50 @@ VTKM_CONT MultiDeviceGradient::~MultiDeviceGradient()
//-----------------------------------------------------------------------------
template <typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::MultiBlock MultiDeviceGradient::PrepareForExecution(
const vtkm::cont::MultiBlock& mb,
inline VTKM_CONT vtkm::cont::PartitionedDataSet MultiDeviceGradient::PrepareForExecution(
const vtkm::cont::PartitionedDataSet& pds,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy)
{
//Step 1. Say that we have no more to submit for this multi block
//Step 1. Say that we have no more to submit for this PartitionedDataSet
//This is needed to happen for each execute as we want to support
//the same filter being used for multiple inputs
this->Queue.reset();
//Step 2. Construct the multi-block we are going to fill. The size signature
//to MultiBlock just reserves size
vtkm::cont::MultiBlock output;
output.AddBlocks(std::vector<vtkm::cont::DataSet>(static_cast<size_t>(mb.GetNumberOfBlocks())));
vtkm::cont::MultiBlock* outPtr = &output;
//Step 2. Construct the PartitionedDataSet we are going to fill. The size
//signature to PartitionedDataSet just reserves size
vtkm::cont::PartitionedDataSet output;
output.AppendPartitions(
std::vector<vtkm::cont::DataSet>(static_cast<size_t>(pds.GetNumberOfPartitions())));
vtkm::cont::PartitionedDataSet* outPtr = &output;
//Step 3. Construct the filter we want to run on each block
//Step 3. Construct the filter we want to run on each partition
vtkm::filter::Gradient gradient;
gradient.SetComputePointGradient(this->GetComputePointGradient());
gradient.SetActiveField(this->GetActiveFieldName());
//Step 3b. Post 1 block up as work and block intil it is
//Step 3b. Post 1 partition up as work and block until it is
//complete. This is needed as currently constructing the virtual
//Point Coordinates is not thread safe.
auto block = mb.cbegin();
auto partition = pds.cbegin();
{
vtkm::cont::DataSet input = *block;
vtkm::cont::DataSet input = *partition;
this->Queue.push( //build a lambda that is the work to do
[=]() {
vtkm::filter::Gradient perThreadGrad = gradient;
vtkm::cont::DataSet result = perThreadGrad.Execute(input, policy);
outPtr->ReplaceBlock(0, result);
outPtr->ReplacePartition(0, result);
});
this->Queue.waitForAllTasksToComplete();
block++;
partition++;
}
vtkm::Id index = 1;
for (; block != mb.cend(); ++block)
for (; partition != pds.cend(); ++partition)
{
vtkm::cont::DataSet input = *block;
//Step 4. For each input block construct a lambda
vtkm::cont::DataSet input = *partition;
//Step 4. For each input partition construct a lambda
//and add it to the queue for workers to take. This
//will allows us to have multiple works execute in a non
//blocking manner
@ -238,7 +239,7 @@ inline VTKM_CONT vtkm::cont::MultiBlock MultiDeviceGradient::PrepareForExecution
vtkm::filter::Gradient perThreadGrad = gradient;
vtkm::cont::DataSet result = perThreadGrad.Execute(input, policy);
outPtr->ReplaceBlock(index, result);
outPtr->ReplacePartition(index, result);
});
index++;
}

@ -10,7 +10,7 @@
#ifndef vtk_m_examples_multibackend_TaskQueue_h
#define vtk_m_examples_multibackend_TaskQueue_h
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <condition_variable>
#include <mutex>

@ -10,7 +10,7 @@
#include <vtkm/ImplicitFunction.h>
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/AssignerMultiBlock.h>
#include <vtkm/cont/AssignerPartitionedDataSet.h>
#include <vtkm/cont/BoundsGlobalCompute.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/Serialization.h>
@ -204,14 +204,14 @@ public:
~RedistributePoints() {}
template <typename DerivedPolicy>
VTKM_CONT vtkm::cont::MultiBlock PrepareForExecution(
const vtkm::cont::MultiBlock& input,
VTKM_CONT vtkm::cont::PartitionedDataSet PrepareForExecution(
const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
};
template <typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::MultiBlock RedistributePoints::PrepareForExecution(
const vtkm::cont::MultiBlock& input,
inline VTKM_CONT vtkm::cont::PartitionedDataSet RedistributePoints::PrepareForExecution(
const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy)
{
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
@ -219,7 +219,7 @@ inline VTKM_CONT vtkm::cont::MultiBlock RedistributePoints::PrepareForExecution(
// let's first get the global bounds of the domain
vtkm::Bounds gbounds = vtkm::cont::BoundsGlobalCompute(input);
vtkm::cont::AssignerMultiBlock assigner(input.GetNumberOfBlocks());
vtkm::cont::AssignerPartitionedDataSet assigner(input.GetNumberOfPartitions());
vtkmdiy::RegularDecomposer<vtkmdiy::ContinuousBounds> decomposer(
/*dim*/ 3, internal::convert(gbounds), assigner.nblocks());
@ -230,19 +230,19 @@ inline VTKM_CONT vtkm::cont::MultiBlock RedistributePoints::PrepareForExecution(
[](void* ptr) { delete static_cast<vtkm::cont::DataSet*>(ptr); });
decomposer.decompose(comm.rank(), assigner, master);
assert(static_cast<vtkm::Id>(master.size()) == input.GetNumberOfBlocks());
assert(static_cast<vtkm::Id>(master.size()) == input.GetNumberOfPartitions());
// let's populate local blocks
master.foreach ([&input](vtkm::cont::DataSet* ds, const vtkmdiy::Master::ProxyWithLink& proxy) {
auto lid = proxy.master()->lid(proxy.gid());
*ds = input.GetBlock(lid);
*ds = input.GetPartition(lid);
});
internal::Redistributor<DerivedPolicy> redistributor(decomposer, policy);
vtkmdiy::all_to_all(master, assigner, redistributor, /*k=*/2);
vtkm::cont::MultiBlock result;
vtkm::cont::PartitionedDataSet result;
master.foreach ([&result](vtkm::cont::DataSet* ds, const vtkmdiy::Master::ProxyWithLink&) {
result.AddBlock(*ds);
result.AppendPartition(*ds);
});
return result;

@ -1,80 +0,0 @@
//============================================================================
// 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/AssignerMultiBlock.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/thirdparty/diy/diy.h>
#include <algorithm> // std::lower_bound
#include <numeric> // std::iota
namespace vtkm
{
namespace cont
{
VTKM_CONT
AssignerMultiBlock::AssignerMultiBlock(const vtkm::cont::MultiBlock& mb)
: AssignerMultiBlock(mb.GetNumberOfBlocks())
{
}
VTKM_CONT
AssignerMultiBlock::AssignerMultiBlock(vtkm::Id num_blocks)
: vtkmdiy::StaticAssigner(vtkm::cont::EnvironmentTracker::GetCommunicator().size(), 1)
, IScanBlockCounts()
{
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
if (comm.size() > 1)
{
vtkm::Id iscan;
vtkmdiy::mpi::scan(comm, num_blocks, iscan, std::plus<vtkm::Id>());
vtkmdiy::mpi::all_gather(comm, iscan, this->IScanBlockCounts);
}
else
{
this->IScanBlockCounts.push_back(num_blocks);
}
this->set_nblocks(static_cast<int>(this->IScanBlockCounts.back()));
}
VTKM_CONT
void AssignerMultiBlock::local_gids(int my_rank, std::vector<int>& gids) const
{
const size_t s_rank = static_cast<size_t>(my_rank);
if (my_rank == 0)
{
assert(this->IScanBlockCounts.size() > 0);
gids.resize(static_cast<size_t>(this->IScanBlockCounts[s_rank]));
std::iota(gids.begin(), gids.end(), 0);
}
else if (my_rank > 0 && s_rank < this->IScanBlockCounts.size())
{
gids.resize(
static_cast<size_t>(this->IScanBlockCounts[s_rank] - this->IScanBlockCounts[s_rank - 1]));
std::iota(gids.begin(), gids.end(), static_cast<int>(this->IScanBlockCounts[s_rank - 1]));
}
}
VTKM_CONT
int AssignerMultiBlock::rank(int gid) const
{
return static_cast<int>(
std::lower_bound(this->IScanBlockCounts.begin(), this->IScanBlockCounts.end(), gid + 1) -
this->IScanBlockCounts.begin());
}
} // vtkm::cont
} // vtkm

@ -0,0 +1,81 @@
//============================================================================
// 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/AssignerPartitionedDataSet.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/thirdparty/diy/diy.h>
#include <algorithm> // std::lower_bound
#include <numeric> // std::iota
namespace vtkm
{
namespace cont
{
VTKM_CONT
AssignerPartitionedDataSet::AssignerPartitionedDataSet(const vtkm::cont::PartitionedDataSet& pds)
: AssignerPartitionedDataSet(pds.GetNumberOfPartitions())
{
}
VTKM_CONT
AssignerPartitionedDataSet::AssignerPartitionedDataSet(vtkm::Id num_partitions)
: vtkmdiy::StaticAssigner(vtkm::cont::EnvironmentTracker::GetCommunicator().size(), 1)
, IScanPartitionCounts()
{
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
if (comm.size() > 1)
{
vtkm::Id iscan;
vtkmdiy::mpi::scan(comm, num_partitions, iscan, std::plus<vtkm::Id>());
vtkmdiy::mpi::all_gather(comm, iscan, this->IScanPartitionCounts);
}
else
{
this->IScanPartitionCounts.push_back(num_partitions);
}
this->set_nblocks(static_cast<int>(this->IScanPartitionCounts.back()));
}
VTKM_CONT
void AssignerPartitionedDataSet::local_gids(int my_rank, std::vector<int>& gids) const
{
const size_t s_rank = static_cast<size_t>(my_rank);
if (my_rank == 0)
{
assert(this->IScanPartitionCounts.size() > 0);
gids.resize(static_cast<size_t>(this->IScanPartitionCounts[s_rank]));
std::iota(gids.begin(), gids.end(), 0);
}
else if (my_rank > 0 && s_rank < this->IScanPartitionCounts.size())
{
gids.resize(static_cast<size_t>(this->IScanPartitionCounts[s_rank] -
this->IScanPartitionCounts[s_rank - 1]));
std::iota(gids.begin(), gids.end(), static_cast<int>(this->IScanPartitionCounts[s_rank - 1]));
}
}
VTKM_CONT
int AssignerPartitionedDataSet::rank(int gid) const
{
return static_cast<int>(std::lower_bound(this->IScanPartitionCounts.begin(),
this->IScanPartitionCounts.end(),
gid + 1) -
this->IScanPartitionCounts.begin());
}
} // vtkm::cont
} // vtkm

@ -7,8 +7,8 @@
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_AssignerMultiBlock_h
#define vtk_m_cont_AssignerMultiBlock_h
#ifndef vtk_m_cont_AssignerPartitionedDataSet_h
#define vtk_m_cont_AssignerPartitionedDataSet_h
#include <vtkm/cont/vtkm_cont_export.h>
@ -31,31 +31,32 @@ namespace vtkm
namespace cont
{
class MultiBlock;
class PartitionedDataSet;
/// \brief Assigner for `MultiBlock` blocks.
/// \brief Assigner for PartitionedDataSet partitions.
///
/// `AssignerMultiBlock` is a `vtkmdiy::StaticAssigner` implementation that uses
/// `MultiBlock`'s block distribution to build global-id/rank associations
/// needed for several `diy` operations.
/// It uses a contiguous assignment strategy to map blocks to global ids i.e.
/// blocks on rank 0 come first, then rank 1, etc. Any rank may have 0 blocks.
/// `AssignerPartitionedDataSet` is a `vtkmdiy::StaticAssigner` implementation
/// that uses `PartitionedDataSet`'s partition distribution to build
/// global-id/rank associations needed for several `diy` operations.
/// It uses a contiguous assignment strategy to map partitions to global ids,
/// i.e. partitions on rank 0 come first, then rank 1, etc. Any rank may have 0
/// partitions.
///
/// AssignerMultiBlock uses collectives in the constructor hence it is
/// AssignerPartitionedDataSet uses collectives in the constructor hence it is
/// essential it gets created on all ranks irrespective of whether the rank has
/// any blocks.
/// any partitions.
///
class VTKM_CONT_EXPORT AssignerMultiBlock : public vtkmdiy::StaticAssigner
class VTKM_CONT_EXPORT AssignerPartitionedDataSet : public vtkmdiy::StaticAssigner
{
public:
/// Initialize the assigner using a multiblock dataset.
/// Initialize the assigner using a partitioned dataset.
/// This may initialize collective operations to populate the assigner with
/// information about blocks on all ranks.
/// information about partitions on all ranks.
VTKM_CONT
AssignerMultiBlock(const vtkm::cont::MultiBlock& mb);
AssignerPartitionedDataSet(const vtkm::cont::PartitionedDataSet& pds);
VTKM_CONT
AssignerMultiBlock(vtkm::Id num_blocks);
AssignerPartitionedDataSet(vtkm::Id num_partitions);
///@{
/// vtkmdiy::Assigner API implementation.
@ -66,7 +67,7 @@ public:
int rank(int gid) const override;
//@}
private:
std::vector<vtkm::Id> IScanBlockCounts;
std::vector<vtkm::Id> IScanPartitionCounts;
};
}
}

@ -11,7 +11,7 @@
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <numeric> // for std::accumulate
@ -31,14 +31,15 @@ vtkm::Bounds BoundsCompute(const vtkm::cont::DataSet& dataset, vtkm::Id coordina
//-----------------------------------------------------------------------------
VTKM_CONT
vtkm::Bounds BoundsCompute(const vtkm::cont::MultiBlock& multiblock,
vtkm::Bounds BoundsCompute(const vtkm::cont::PartitionedDataSet& pds,
vtkm::Id coordinate_system_index)
{
return std::accumulate(multiblock.begin(),
multiblock.end(),
return std::accumulate(pds.begin(),
pds.end(),
vtkm::Bounds(),
[=](const vtkm::Bounds& val, const vtkm::cont::DataSet& block) {
return val + vtkm::cont::BoundsCompute(block, coordinate_system_index);
[=](const vtkm::Bounds& val, const vtkm::cont::DataSet& partition) {
return val +
vtkm::cont::BoundsCompute(partition, coordinate_system_index);
});
}
@ -59,13 +60,13 @@ vtkm::Bounds BoundsCompute(const vtkm::cont::DataSet& dataset, const std::string
//-----------------------------------------------------------------------------
VTKM_CONT
vtkm::Bounds BoundsCompute(const vtkm::cont::MultiBlock& multiblock, const std::string& name)
vtkm::Bounds BoundsCompute(const vtkm::cont::PartitionedDataSet& pds, const std::string& name)
{
return std::accumulate(multiblock.begin(),
multiblock.end(),
return std::accumulate(pds.begin(),
pds.end(),
vtkm::Bounds(),
[=](const vtkm::Bounds& val, const vtkm::cont::DataSet& block) {
return val + vtkm::cont::BoundsCompute(block, name);
[=](const vtkm::Bounds& val, const vtkm::cont::DataSet& partition) {
return val + vtkm::cont::BoundsCompute(partition, name);
});
}
}

@ -19,19 +19,19 @@ namespace cont
{
class DataSet;
class MultiBlock;
class PartitionedDataSet;
//@{
/// \brief Functions to compute bounds for a dataset or multiblock
/// \brief Functions to compute bounds for a single dataSset or partition dataset
///
/// These are utility functions that compute bounds for the dataset or
/// multiblock. 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.
/// 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 MultiBlock, blocks without the chosen CoordinateSystem
/// are skipped.
/// are returned. Likewise, for PartitionedDataSet, partitions without the
/// chosen CoordinateSystem are skipped.
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::Bounds BoundsCompute(const vtkm::cont::DataSet& dataset,
@ -39,7 +39,7 @@ vtkm::Bounds BoundsCompute(const vtkm::cont::DataSet& dataset,
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::Bounds BoundsCompute(const vtkm::cont::MultiBlock& multiblock,
vtkm::Bounds BoundsCompute(const vtkm::cont::PartitionedDataSet& pds,
vtkm::Id coordinate_system_index = 0);
VTKM_CONT_EXPORT
@ -49,7 +49,7 @@ vtkm::Bounds BoundsCompute(const vtkm::cont::DataSet& dataset,
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::Bounds BoundsCompute(const vtkm::cont::MultiBlock& multiblock,
vtkm::Bounds BoundsCompute(const vtkm::cont::PartitionedDataSet& pds,
const std::string& coordinate_system_name);
//@}
}

@ -13,7 +13,7 @@
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/FieldRangeGlobalCompute.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <numeric> // for std::accumulate
@ -50,10 +50,10 @@ vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::DataSet& dataset,
//-----------------------------------------------------------------------------
VTKM_CONT
vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::MultiBlock& multiblock,
vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::PartitionedDataSet& pds,
vtkm::Id coordinate_system_index)
{
return detail::MergeBoundsGlobal(vtkm::cont::BoundsCompute(multiblock, coordinate_system_index));
return detail::MergeBoundsGlobal(vtkm::cont::BoundsCompute(pds, coordinate_system_index));
}
//-----------------------------------------------------------------------------
@ -65,9 +65,9 @@ vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::DataSet& dataset, const std::
//-----------------------------------------------------------------------------
VTKM_CONT
vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::MultiBlock& multiblock, const std::string& name)
vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::PartitionedDataSet& pds, const std::string& name)
{
return detail::MergeBoundsGlobal(vtkm::cont::BoundsCompute(multiblock, name));
return detail::MergeBoundsGlobal(vtkm::cont::BoundsCompute(pds, name));
}
}
}

@ -19,19 +19,20 @@ namespace cont
{
class DataSet;
class MultiBlock;
class PartitionedDataSet;
//@{
/// \brief Functions to compute bounds for a dataset or multiblock globally
/// \brief Functions to compute bounds for a single dataset or partitioned
/// dataset globally
///
/// These are utility functions that compute bounds for the dataset or
/// multiblock globally i.e. across all ranks when operating in a distributed
/// environment. When VTK-m not operating in an distributed environment, these
/// behave same as `vtkm::cont::BoundsCompute`.
/// These are utility functions that compute bounds for a single dataset or
/// partitioned dataset globally i.e. across all ranks when operating in a
/// distributed environment. When VTK-m not operating in an distributed
/// environment, these behave same as `vtkm::cont::BoundsCompute`.
///
/// Note that if the provided CoordinateSystem does not exists, empty bounds
/// are returned. Likewise, for MultiBlock, blocks without the chosen CoordinateSystem
/// are skipped.
/// are returned. Likewise, for PartitionedDataSet, partitions without the
/// chosen CoordinateSystem are skipped.
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::DataSet& dataset,
@ -39,7 +40,7 @@ vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::DataSet& dataset,
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::MultiBlock& multiblock,
vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::PartitionedDataSet& pds,
vtkm::Id coordinate_system_index = 0);
VTKM_CONT_EXPORT
@ -49,7 +50,7 @@ vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::DataSet& dataset,
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::MultiBlock& multiblock,
vtkm::Bounds BoundsGlobalCompute(const vtkm::cont::PartitionedDataSet& pds,
const std::string& coordinate_system_name);
//@}
}

@ -43,7 +43,7 @@ set(headers
ArrayPortal.h
ArrayPortalToIterators.h
ArrayRangeCompute.h
AssignerMultiBlock.h
AssignerPartitionedDataSet.h
AtomicArray.h
BitField.h
BoundsCompute.h
@ -93,7 +93,7 @@ set(headers
Initialize.h
Invoker.h
Logging.h
MultiBlock.h
PartitionedDataSet.h
PointLocator.h
PointLocatorUniformGrid.h
RuntimeDeviceInformation.h
@ -152,7 +152,7 @@ set(sources
set(device_sources
ArrayHandleVirtual.cxx
ArrayRangeCompute.cxx
AssignerMultiBlock.cxx
AssignerPartitionedDataSet.cxx
BoundsCompute.cxx
BoundsGlobalCompute.cxx
CellLocator.cxx
@ -175,7 +175,7 @@ set(sources
Field.cxx
FieldRangeCompute.cxx
FieldRangeGlobalCompute.cxx
MultiBlock.cxx
PartitionedDataSet.cxx
PointLocator.cxx
PointLocatorUniformGrid.cxx
RuntimeDeviceInformation.cxx

@ -29,12 +29,11 @@ vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeCompute(const vtkm::cont::DataSet
//-----------------------------------------------------------------------------
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeCompute(const vtkm::cont::MultiBlock& multiblock,
vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeCompute(const vtkm::cont::PartitionedDataSet& pds,
const std::string& name,
vtkm::cont::Field::Association assoc)
{
return vtkm::cont::detail::FieldRangeComputeImpl(
multiblock, name, assoc, VTKM_DEFAULT_TYPE_LIST_TAG());
return vtkm::cont::detail::FieldRangeComputeImpl(pds, name, assoc, VTKM_DEFAULT_TYPE_LIST_TAG());
}
}
} // namespace vtkm::cont

@ -12,7 +12,7 @@
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/Field.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/cont/FieldRangeCompute.hxx>
@ -20,9 +20,10 @@ namespace vtkm
{
namespace cont
{
/// \brief Compute ranges for fields in a DataSet or MultiBlock.
/// \brief Compute ranges for fields in a DataSet or PartitionedDataSet.
///
/// These methods to compute ranges for fields in a dataset or a multiblock.
/// These methods to compute ranges for fields in a single dataset or a
/// partitioned dataset.
/// When using VTK-m in a hybrid-parallel environment with distributed processing,
/// this class uses ranges for locally available data alone. Use FieldRangeGlobalCompute
/// to compute ranges globally across all ranks even in distributed mode.
@ -51,28 +52,30 @@ VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeCompute(
//@}
//{@
/// Returns the range for a field from a multiblock. If the field is not present on any
/// of the blocks, an empty ArrayHandle will be returned. If the field is present on some blocks,
/// but not all, those blocks without the field are skipped.
/// Returns the range for a field from a PartitionedDataSet. If the field is
/// not present on any of the partitions, an empty ArrayHandle will be
/// returned. If the field is present on some partitions, but not all, those
/// partitions without the field are skipped.
///
/// The returned array handle will have as many values as the maximum number of
/// components for the selected field across all partitions.
///
/// The returned array handle will have as many values as the maximum number of components for
/// the selected field across all blocks.
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeCompute(
const vtkm::cont::MultiBlock& multiblock,
const vtkm::cont::PartitionedDataSet& pds,
const std::string& name,
vtkm::cont::Field::Association assoc = vtkm::cont::Field::Association::ANY);
template <typename TypeList>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeCompute(
const vtkm::cont::MultiBlock& multiblock,
const vtkm::cont::PartitionedDataSet& pds,
const std::string& name,
vtkm::cont::Field::Association assoc,
TypeList)
{
VTKM_IS_LIST_TAG(TypeList);
return vtkm::cont::detail::FieldRangeComputeImpl(multiblock, name, assoc, TypeList());
return vtkm::cont::detail::FieldRangeComputeImpl(pds, name, assoc, TypeList());
}
//@}

@ -10,6 +10,12 @@
#ifndef vtk_m_cont_FieldRangeCompute_hxx
#define vtk_m_cont_FieldRangeCompute_hxx
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/Range.h>
#include <numeric> // for std::accumulate
namespace vtkm
@ -42,26 +48,27 @@ VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeComputeImpl(
template <typename TypeList>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeComputeImpl(
const vtkm::cont::MultiBlock& multiblock,
const vtkm::cont::PartitionedDataSet& pds,
const std::string& name,
vtkm::cont::Field::Association assoc,
TypeList)
{
std::vector<vtkm::Range> result_vector = std::accumulate(
multiblock.begin(),
multiblock.end(),
pds.begin(),
pds.end(),
std::vector<vtkm::Range>(),
[&](const std::vector<vtkm::Range>& accumulated_value, const vtkm::cont::DataSet& dataset) {
vtkm::cont::ArrayHandle<vtkm::Range> block_range =
vtkm::cont::ArrayHandle<vtkm::Range> partition_range =
vtkm::cont::detail::FieldRangeComputeImpl(dataset, name, assoc, TypeList());
std::vector<vtkm::Range> result = accumulated_value;
// if the current block has more components than we have seen so far,
// if the current partition has more components than we have seen so far,
// resize the result to fit all components.
result.resize(std::max(result.size(), static_cast<size_t>(block_range.GetNumberOfValues())));
result.resize(
std::max(result.size(), static_cast<size_t>(partition_range.GetNumberOfValues())));
auto portal = block_range.GetPortalConstControl();
auto portal = partition_range.GetPortalConstControl();
std::transform(vtkm::cont::ArrayPortalToIteratorBegin(portal),
vtkm::cont::ArrayPortalToIteratorEnd(portal),
result.begin(),

@ -33,11 +33,11 @@ vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeGlobalCompute(const vtkm::cont::D
//-----------------------------------------------------------------------------
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeGlobalCompute(
const vtkm::cont::MultiBlock& multiblock,
const vtkm::cont::PartitionedDataSet& pds,
const std::string& name,
vtkm::cont::Field::Association assoc)
{
return detail::FieldRangeGlobalComputeImpl(multiblock, name, assoc, VTKM_DEFAULT_TYPE_LIST_TAG());
return detail::FieldRangeGlobalComputeImpl(pds, name, assoc, VTKM_DEFAULT_TYPE_LIST_TAG());
}
//-----------------------------------------------------------------------------

@ -20,7 +20,8 @@ namespace cont
{
/// \brief utility functions to compute global ranges for dataset fields.
///
/// These functions compute global ranges for fields in a dataset or a multiblock.
/// These functions compute global ranges for fields in a single DataSet or a
/// PartitionedDataSet.
/// In non-distributed environments, this is exactly same as `FieldRangeCompute`. In
/// distributed environments, however, the range is computed locally on each rank
/// and then a reduce-all collective is performed to reduces the ranges on all ranks.
@ -49,28 +50,29 @@ VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeGlobalCompute(
//@}
//{@
/// Returns the range for a field from a multiblock. If the field is not present on any
/// of the blocks, an empty ArrayHandle will be returned. If the field is present on some blocks,
/// but not all, those blocks without the field are skipped.
/// Returns the range for a field from a PartitionedDataSet. If the field is
/// not present on any of the partitions, an empty ArrayHandle will be
/// returned. If the field is present on some partitions, but not all, those
/// partitions without the field are skipped.
///
/// The returned array handle will have as many values as the maximum number of components for
/// the selected field across all blocks.
/// The returned array handle will have as many values as the maximum number of
/// components for the selected field across all partitions.
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeGlobalCompute(
const vtkm::cont::MultiBlock& multiblock,
const vtkm::cont::PartitionedDataSet& pds,
const std::string& name,
vtkm::cont::Field::Association assoc = vtkm::cont::Field::Association::ANY);
template <typename TypeList>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeGlobalCompute(
const vtkm::cont::MultiBlock& multiblock,
const vtkm::cont::PartitionedDataSet& pds,
const std::string& name,
vtkm::cont::Field::Association assoc,
TypeList)
{
VTKM_IS_LIST_TAG(TypeList);
return detail::FieldRangeGlobalComputeImpl(multiblock, name, assoc, TypeList());
return detail::FieldRangeGlobalComputeImpl(pds, name, assoc, TypeList());
}
//@}
}

@ -35,12 +35,12 @@ VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeGlobalComputeImpl(
template <typename TypeList>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeGlobalComputeImpl(
const vtkm::cont::MultiBlock& multiblock,
const vtkm::cont::PartitionedDataSet& pds,
const std::string& name,
vtkm::cont::Field::Association assoc,
TypeList)
{
auto lrange = vtkm::cont::FieldRangeCompute(multiblock, name, assoc, TypeList());
auto lrange = vtkm::cont::FieldRangeCompute(pds, name, assoc, TypeList());
return vtkm::cont::detail::MergeRangesGlobal(lrange);
}
}

@ -1,143 +0,0 @@
//============================================================================
// 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/StaticAssert.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/ErrorExecution.h>
#include <vtkm/cont/Field.h>
#include <vtkm/cont/MultiBlock.h>
namespace vtkm
{
namespace cont
{
VTKM_CONT
MultiBlock::MultiBlock(const vtkm::cont::DataSet& ds)
{
this->Blocks.insert(this->Blocks.end(), ds);
}
VTKM_CONT
MultiBlock::MultiBlock(const vtkm::cont::MultiBlock& src)
{
this->Blocks = src.GetBlocks();
}
VTKM_CONT
MultiBlock::MultiBlock(const std::vector<vtkm::cont::DataSet>& mblocks)
{
this->Blocks = mblocks;
}
VTKM_CONT
MultiBlock::MultiBlock(vtkm::Id size)
{
this->Blocks.reserve(static_cast<std::size_t>(size));
}
VTKM_CONT
MultiBlock::MultiBlock()
{
}
VTKM_CONT
MultiBlock::~MultiBlock()
{
}
VTKM_CONT
MultiBlock& MultiBlock::operator=(const vtkm::cont::MultiBlock& src)
{
this->Blocks = src.GetBlocks();
return *this;
}
VTKM_CONT
vtkm::cont::Field MultiBlock::GetField(const std::string& field_name, const int& block_index)
{
assert(block_index >= 0);
assert(static_cast<std::size_t>(block_index) < this->Blocks.size());
return this->Blocks[static_cast<std::size_t>(block_index)].GetField(field_name);
}
VTKM_CONT
vtkm::Id MultiBlock::GetNumberOfBlocks() const
{
return static_cast<vtkm::Id>(this->Blocks.size());
}
VTKM_CONT
const vtkm::cont::DataSet& MultiBlock::GetBlock(vtkm::Id blockId) const
{
return this->Blocks[static_cast<std::size_t>(blockId)];
}
VTKM_CONT
const std::vector<vtkm::cont::DataSet>& MultiBlock::GetBlocks() const
{
return this->Blocks;
}
VTKM_CONT
void MultiBlock::AddBlock(const vtkm::cont::DataSet& ds)
{
this->Blocks.insert(this->Blocks.end(), ds);
return;
}
void MultiBlock::AddBlocks(const std::vector<vtkm::cont::DataSet>& mblocks)
{
this->Blocks.insert(this->Blocks.end(), mblocks.begin(), mblocks.end());
return;
}
VTKM_CONT
void MultiBlock::InsertBlock(vtkm::Id index, const vtkm::cont::DataSet& ds)
{
if (index <= static_cast<vtkm::Id>(this->Blocks.size()))
this->Blocks.insert(this->Blocks.begin() + index, ds);
else
{
std::string msg = "invalid insert position\n ";
throw ErrorExecution(msg);
}
}
VTKM_CONT
void MultiBlock::ReplaceBlock(vtkm::Id index, const vtkm::cont::DataSet& ds)
{
if (index < static_cast<vtkm::Id>(this->Blocks.size()))
this->Blocks.at(static_cast<std::size_t>(index)) = ds;
else
{
std::string msg = "invalid replace position\n ";
throw ErrorExecution(msg);
}
}
VTKM_CONT
void MultiBlock::PrintSummary(std::ostream& stream) const
{
stream << "block "
<< "\n";
for (size_t block_index = 0; block_index < this->Blocks.size(); ++block_index)
{
stream << "block " << block_index << "\n";
this->Blocks[block_index].PrintSummary(stream);
}
}
}
} // namespace vtkm::cont

@ -1,92 +0,0 @@
//============================================================================
// 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_cont_MultiBlock_h
#define vtk_m_cont_MultiBlock_h
#include <limits>
#include <vtkm/StaticAssert.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/Field.h>
namespace vtkm
{
namespace cont
{
class VTKM_CONT_EXPORT MultiBlock
{
public:
/// create a new MultiBlock containng a single DataSet "ds"
VTKM_CONT
MultiBlock(const vtkm::cont::DataSet& ds);
/// create a new MultiBlock with the existing one "src"
VTKM_CONT
MultiBlock(const vtkm::cont::MultiBlock& src);
/// create a new MultiBlock with a DataSet vector "mblocks"
VTKM_CONT
explicit MultiBlock(const std::vector<vtkm::cont::DataSet>& mblocks);
/// create a new MultiBlock with the capacity set to be "size"
VTKM_CONT
explicit MultiBlock(vtkm::Id size);
VTKM_CONT
MultiBlock();
VTKM_CONT
MultiBlock& operator=(const vtkm::cont::MultiBlock& src);
VTKM_CONT
~MultiBlock();
/// get the field "field_name" from block "block_index"
VTKM_CONT
vtkm::cont::Field GetField(const std::string& field_name, const int& block_index);
VTKM_CONT
vtkm::Id GetNumberOfBlocks() const;
VTKM_CONT
const vtkm::cont::DataSet& GetBlock(vtkm::Id blockId) const;
VTKM_CONT
const std::vector<vtkm::cont::DataSet>& GetBlocks() const;
/// add DataSet "ds" to the end of the contained DataSet vector
VTKM_CONT
void AddBlock(const vtkm::cont::DataSet& ds);
/// add DataSet "ds" to position "index" of the contained DataSet vector
VTKM_CONT
void InsertBlock(vtkm::Id index, const vtkm::cont::DataSet& ds);
/// replace the "index" positioned element of the contained DataSet vector with "ds"
VTKM_CONT
void ReplaceBlock(vtkm::Id index, const vtkm::cont::DataSet& ds);
/// append the DataSet vector "mblocks" to the end of the contained one
VTKM_CONT
void AddBlocks(const std::vector<vtkm::cont::DataSet>& mblocks);
VTKM_CONT
void PrintSummary(std::ostream& stream) const;
//@{
/// API to support range-based for loops on blocks.
std::vector<DataSet>::iterator begin() noexcept { return this->Blocks.begin(); }
std::vector<DataSet>::iterator end() noexcept { return this->Blocks.end(); }
std::vector<DataSet>::const_iterator begin() const noexcept { return this->Blocks.begin(); }
std::vector<DataSet>::const_iterator end() const noexcept { return this->Blocks.end(); }
std::vector<DataSet>::const_iterator cbegin() const noexcept { return this->Blocks.begin(); }
std::vector<DataSet>::const_iterator cend() const noexcept { return this->Blocks.end(); }
//@}
private:
std::vector<vtkm::cont::DataSet> Blocks;
};
}
} // namespace vtkm::cont
#endif

@ -0,0 +1,143 @@
//============================================================================
// 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/StaticAssert.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/Field.h>
#include <vtkm/cont/PartitionedDataSet.h>
namespace vtkm
{
namespace cont
{
VTKM_CONT
PartitionedDataSet::PartitionedDataSet(const vtkm::cont::DataSet& ds)
{
this->Partitions.insert(this->Partitions.end(), ds);
}
VTKM_CONT
PartitionedDataSet::PartitionedDataSet(const vtkm::cont::PartitionedDataSet& src)
{
this->Partitions = src.GetPartitions();
}
VTKM_CONT
PartitionedDataSet::PartitionedDataSet(const std::vector<vtkm::cont::DataSet>& partitions)
{
this->Partitions = partitions;
}
VTKM_CONT
PartitionedDataSet::PartitionedDataSet(vtkm::Id size)
{
this->Partitions.reserve(static_cast<std::size_t>(size));
}
VTKM_CONT
PartitionedDataSet::PartitionedDataSet()
{
}
VTKM_CONT
PartitionedDataSet::~PartitionedDataSet()
{
}
VTKM_CONT
PartitionedDataSet& PartitionedDataSet::operator=(const vtkm::cont::PartitionedDataSet& src)
{
this->Partitions = src.GetPartitions();
return *this;
}
VTKM_CONT
vtkm::cont::Field PartitionedDataSet::GetField(const std::string& field_name, int partition_index)
{
assert(partition_index >= 0);
assert(static_cast<std::size_t>(partition_index) < this->Partitions.size());
return this->Partitions[static_cast<std::size_t>(partition_index)].GetField(field_name);
}
VTKM_CONT
vtkm::Id PartitionedDataSet::GetNumberOfPartitions() const
{
return static_cast<vtkm::Id>(this->Partitions.size());
}
VTKM_CONT
const vtkm::cont::DataSet& PartitionedDataSet::GetPartition(vtkm::Id blockId) const
{
return this->Partitions[static_cast<std::size_t>(blockId)];
}
VTKM_CONT
const std::vector<vtkm::cont::DataSet>& PartitionedDataSet::GetPartitions() const
{
return this->Partitions;
}
VTKM_CONT
void PartitionedDataSet::AppendPartition(const vtkm::cont::DataSet& ds)
{
this->Partitions.insert(this->Partitions.end(), ds);
}
VTKM_CONT
void PartitionedDataSet::AppendPartitions(const std::vector<vtkm::cont::DataSet>& partitions)
{
this->Partitions.insert(this->Partitions.end(), partitions.begin(), partitions.end());
}
VTKM_CONT
void PartitionedDataSet::InsertPartition(vtkm::Id index, const vtkm::cont::DataSet& ds)
{
if (index <= static_cast<vtkm::Id>(this->Partitions.size()))
{
this->Partitions.insert(this->Partitions.begin() + index, ds);
}
else
{
std::string msg = "invalid insert position\n ";
throw ErrorBadValue(msg);
}
}
VTKM_CONT
void PartitionedDataSet::ReplacePartition(vtkm::Id index, const vtkm::cont::DataSet& ds)
{
if (index < static_cast<vtkm::Id>(this->Partitions.size()))
this->Partitions.at(static_cast<std::size_t>(index)) = ds;
else
{
std::string msg = "invalid replace position\n ";
throw ErrorBadValue(msg);
}
}
VTKM_CONT
void PartitionedDataSet::PrintSummary(std::ostream& stream) const
{
stream << "PartitionedDataSet [" << this->Partitions.size() << " partitions]:\n";
for (size_t part = 0; part < this->Partitions.size(); ++part)
{
stream << "Partition " << part << ":\n";
this->Partitions[part].PrintSummary(stream);
}
}
}
} // namespace vtkm::cont

@ -0,0 +1,111 @@
//============================================================================
// 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_cont_PartitionedDataSet_h
#define vtk_m_cont_PartitionedDataSet_h
#include <limits>
#include <vtkm/StaticAssert.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/Field.h>
namespace vtkm
{
namespace cont
{
class VTKM_CONT_EXPORT PartitionedDataSet
{
using StorageVec = std::vector<vtkm::cont::DataSet>;
public:
using iterator = typename StorageVec::iterator;
using const_iterator = typename StorageVec::const_iterator;
using value_type = typename StorageVec::value_type;
using reference = typename StorageVec::reference;
using const_reference = typename StorageVec::const_reference;
/// create a new PartitionedDataSet containng a single DataSet @a ds
VTKM_CONT
PartitionedDataSet(const vtkm::cont::DataSet& ds);
/// create a new PartitionedDataSet with the existing one @a src
VTKM_CONT
PartitionedDataSet(const vtkm::cont::PartitionedDataSet& src);
/// create a new PartitionedDataSet with a DataSet vector @a partitions.
VTKM_CONT
explicit PartitionedDataSet(const std::vector<vtkm::cont::DataSet>& partitions);
/// create a new PartitionedDataSet with the capacity set to be @a size
VTKM_CONT
explicit PartitionedDataSet(vtkm::Id size);
VTKM_CONT
PartitionedDataSet();
VTKM_CONT
PartitionedDataSet& operator=(const vtkm::cont::PartitionedDataSet& src);
VTKM_CONT
~PartitionedDataSet();
/// get the field @a field_name from partition @a partition_index
VTKM_CONT
vtkm::cont::Field GetField(const std::string& field_name, int partition_index);
VTKM_CONT
vtkm::Id GetNumberOfPartitions() const;
VTKM_CONT
const vtkm::cont::DataSet& GetPartition(vtkm::Id partId) const;
VTKM_CONT
const std::vector<vtkm::cont::DataSet>& GetPartitions() const;
/// add DataSet @a ds to the end of the contained DataSet vector
VTKM_CONT
void AppendPartition(const vtkm::cont::DataSet& ds);
/// add DataSet @a ds to position @a index of the contained DataSet vector
VTKM_CONT
void InsertPartition(vtkm::Id index, const vtkm::cont::DataSet& ds);
/// replace the @a index positioned element of the contained DataSet vector
/// with @a ds
VTKM_CONT
void ReplacePartition(vtkm::Id index, const vtkm::cont::DataSet& ds);
/// append the DataSet vector "partitions" to the end of the contained one
VTKM_CONT
void AppendPartitions(const std::vector<vtkm::cont::DataSet>& partitions);
VTKM_CONT
void PrintSummary(std::ostream& stream) const;
//@{
/// API to support range-based for loops on partitions.
VTKM_CONT
iterator begin() noexcept { return this->Partitions.begin(); }
VTKM_CONT
iterator end() noexcept { return this->Partitions.end(); }
VTKM_CONT
const_iterator begin() const noexcept { return this->Partitions.begin(); }
VTKM_CONT
const_iterator end() const noexcept { return this->Partitions.end(); }
VTKM_CONT
const_iterator cbegin() const noexcept { return this->Partitions.cbegin(); }
VTKM_CONT
const_iterator cend() const noexcept { return this->Partitions.cend(); }
//@}
private:
std::vector<vtkm::cont::DataSet> Partitions;
};
}
} // namespace vtkm::cont
#endif

@ -72,7 +72,7 @@ set(unit_tests
UnitTestInitialize.cxx
UnitTestLogging.cxx
UnitTestMoveConstructors.cxx
UnitTestMultiBlock.cxx
UnitTestPartitionedDataSet.cxx
UnitTestRuntimeDeviceInformation.cxx
UnitTestRuntimeDeviceNames.cxx
UnitTestScopedRuntimeDeviceTracker.cxx

@ -118,12 +118,12 @@ void TryRangeComputeDS(const ValueType& min, const ValueType& max)
}
template <typename ValueType>
void TryRangeComputeMB(const ValueType& min, const ValueType& max)
void TryRangeComputePDS(const ValueType& min, const ValueType& max)
{
std::cout << "Trying type (multiblock): " << vtkm::testing::TypeName<ValueType>::Name()
std::cout << "Trying type (PartitionedDataSet): " << vtkm::testing::TypeName<ValueType>::Name()
<< std::endl;
vtkm::cont::MultiBlock mb;
vtkm::cont::PartitionedDataSet mb;
for (int cc = 0; cc < 5; cc++)
{
// let's create a dummy dataset with a bunch of fields.
@ -132,7 +132,7 @@ void TryRangeComputeMB(const ValueType& min, const ValueType& max)
dataset,
"pointvar",
CreateArray(min, max, ARRAY_SIZE, typename vtkm::TypeTraits<ValueType>::DimensionalityTag()));
mb.AddBlock(dataset);
mb.AppendPartition(dataset);
}
vtkm::cont::ArrayHandle<vtkm::Range> ranges = vtkm::cont::FieldRangeCompute(mb, "pointvar");
@ -148,10 +148,10 @@ static void TestFieldRangeCompute()
TryRangeComputeDS<vtkm::Int32>(-1024, 1024);
TryRangeComputeDS<vtkm::Vec3f_32>(vtkm::make_Vec(1024, 0, -1024),
vtkm::make_Vec(2048, 2048, 2048));
TryRangeComputeMB<vtkm::Float64>(0, 1000);
TryRangeComputeMB<vtkm::Int32>(-1024, 1024);
TryRangeComputeMB<vtkm::Vec3f_32>(vtkm::make_Vec(1024, 0, -1024),
vtkm::make_Vec(2048, 2048, 2048));
TryRangeComputePDS<vtkm::Float64>(0, 1000);
TryRangeComputePDS<vtkm::Int32>(-1024, 1024);
TryRangeComputePDS<vtkm::Vec3f_32>(vtkm::make_Vec(1024, 0, -1024),
vtkm::make_Vec(2048, 2048, 2048));
};
int UnitTestFieldRangeCompute(int argc, char* argv[])

@ -162,12 +162,12 @@ void TryRangeGlobalComputeDS(const ValueType& min, const ValueType& max)
}
template <typename ValueType>
void TryRangeGlobalComputeMB(const ValueType& min, const ValueType& max)
void TryRangeGlobalComputePDS(const ValueType& min, const ValueType& max)
{
vtkmdiy::mpi::communicator comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
PRINT_INFO("Trying type (multiblock): " << vtkm::testing::TypeName<ValueType>::Name());
PRINT_INFO("Trying type (PartitionedDataSet): " << vtkm::testing::TypeName<ValueType>::Name());
vtkm::cont::MultiBlock mb;
vtkm::cont::PartitionedDataSet mb;
for (int cc = 0; cc < 5; cc++)
{
// let's create a dummy dataset with a bunch of fields.
@ -176,7 +176,7 @@ void TryRangeGlobalComputeMB(const ValueType& min, const ValueType& max)
dataset,
"pointvar",
CreateArray(min, max, ARRAY_SIZE, typename vtkm::TypeTraits<ValueType>::DimensionalityTag()));
mb.AddBlock(dataset);
mb.AppendPartition(dataset);
}
vtkm::cont::ArrayHandle<vtkm::Range> ranges = vtkm::cont::FieldRangeGlobalCompute(mb, "pointvar");
@ -195,10 +195,10 @@ static void TestFieldRangeGlobalCompute()
TryRangeGlobalComputeDS<vtkm::Int32>(-1024, 1024);
TryRangeGlobalComputeDS<vtkm::Vec3f_32>(vtkm::make_Vec(1024, 0, -1024),
vtkm::make_Vec(2048, 2048, 2048));
TryRangeGlobalComputeMB<vtkm::Float64>(0, 1000);
TryRangeGlobalComputeMB<vtkm::Int32>(-1024, 1024);
TryRangeGlobalComputeMB<vtkm::Vec3f_32>(vtkm::make_Vec(1024, 0, -1024),
vtkm::make_Vec(2048, 2048, 2048));
TryRangeGlobalComputePDS<vtkm::Float64>(0, 1000);
TryRangeGlobalComputePDS<vtkm::Int32>(-1024, 1024);
TryRangeGlobalComputePDS<vtkm::Vec3f_32>(vtkm::make_Vec(1024, 0, -1024),
vtkm::make_Vec(2048, 2048, 2048));
};
}

@ -18,7 +18,7 @@
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/cont/FieldRangeCompute.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
@ -28,26 +28,26 @@
#include <vtkm/thirdparty/diy/diy.h>
void DataSet_Compare(vtkm::cont::DataSet& LeftDateSet, vtkm::cont::DataSet& RightDateSet);
static void MultiBlockTest()
static void PartitionedDataSetTest()
{
vtkm::cont::testing::MakeTestDataSet testDataSet;
vtkm::cont::MultiBlock multiblock;
vtkm::cont::PartitionedDataSet pds;
vtkm::cont::DataSet TDset1 = testDataSet.Make2DUniformDataSet0();
vtkm::cont::DataSet TDset2 = testDataSet.Make3DUniformDataSet0();
multiblock.AddBlock(TDset1);
multiblock.AddBlock(TDset2);
pds.AppendPartition(TDset1);
pds.AppendPartition(TDset2);
VTKM_TEST_ASSERT(multiblock.GetNumberOfBlocks() == 2, "Incorrect number of blocks");
VTKM_TEST_ASSERT(pds.GetNumberOfPartitions() == 2, "Incorrect number of partitions");
vtkm::cont::DataSet TestDSet = multiblock.GetBlock(0);
vtkm::cont::DataSet TestDSet = pds.GetPartition(0);
VTKM_TEST_ASSERT(TDset1.GetNumberOfFields() == TestDSet.GetNumberOfFields(),
"Incorrect number of fields");
VTKM_TEST_ASSERT(TDset1.GetNumberOfCoordinateSystems() == TestDSet.GetNumberOfCoordinateSystems(),
"Incorrect number of coordinate systems");
TestDSet = multiblock.GetBlock(1);
TestDSet = pds.GetPartition(1);
VTKM_TEST_ASSERT(TDset2.GetNumberOfFields() == TestDSet.GetNumberOfFields(),
"Incorrect number of fields");
VTKM_TEST_ASSERT(TDset2.GetNumberOfCoordinateSystems() == TestDSet.GetNumberOfCoordinateSystems(),
@ -59,11 +59,10 @@ static void MultiBlockTest()
GlobalBound.Include(Set1Bounds);
GlobalBound.Include(Set2Bounds);
VTKM_TEST_ASSERT(vtkm::cont::BoundsCompute(multiblock) == GlobalBound,
"Global bounds info incorrect");
VTKM_TEST_ASSERT(vtkm::cont::BoundsCompute(multiblock.GetBlock(0)) == Set1Bounds,
VTKM_TEST_ASSERT(vtkm::cont::BoundsCompute(pds) == GlobalBound, "Global bounds info incorrect");
VTKM_TEST_ASSERT(vtkm::cont::BoundsCompute(pds.GetPartition(0)) == Set1Bounds,
"Local bounds info incorrect");
VTKM_TEST_ASSERT(vtkm::cont::BoundsCompute(multiblock.GetBlock(1)) == Set2Bounds,
VTKM_TEST_ASSERT(vtkm::cont::BoundsCompute(pds.GetPartition(1)) == Set2Bounds,
"Local bounds info incorrect");
vtkm::Range Set1Field1Range;
@ -84,59 +83,59 @@ static void MultiBlockTest()
Field2GlobeRange.Include(Set2Field2Range);
using vtkm::cont::FieldRangeCompute;
VTKM_TEST_ASSERT(FieldRangeCompute(multiblock, "pointvar").GetPortalConstControl().Get(0) ==
VTKM_TEST_ASSERT(FieldRangeCompute(pds, "pointvar").GetPortalConstControl().Get(0) ==
Field1GlobeRange,
"Local field value range info incorrect");
VTKM_TEST_ASSERT(FieldRangeCompute(multiblock, "cellvar").GetPortalConstControl().Get(0) ==
VTKM_TEST_ASSERT(FieldRangeCompute(pds, "cellvar").GetPortalConstControl().Get(0) ==
Field2GlobeRange,
"Local field value range info incorrect");
vtkm::Range SourceRange; //test the validity of member function GetField(FieldName, BlockId)
multiblock.GetField("cellvar", 0).GetRange(&SourceRange);
pds.GetField("cellvar", 0).GetRange(&SourceRange);
vtkm::Range TestRange;
multiblock.GetBlock(0).GetField("cellvar").GetRange(&TestRange);
pds.GetPartition(0).GetField("cellvar").GetRange(&TestRange);
VTKM_TEST_ASSERT(TestRange == SourceRange, "Local field value info incorrect");
vtkm::cont::MultiBlock testblocks1;
std::vector<vtkm::cont::DataSet> blocks = multiblock.GetBlocks();
testblocks1.AddBlocks(blocks);
VTKM_TEST_ASSERT(multiblock.GetNumberOfBlocks() == testblocks1.GetNumberOfBlocks(),
"inconsistent number of blocks");
vtkm::cont::PartitionedDataSet testblocks1;
std::vector<vtkm::cont::DataSet> partitions = pds.GetPartitions();
testblocks1.AppendPartitions(partitions);
VTKM_TEST_ASSERT(pds.GetNumberOfPartitions() == testblocks1.GetNumberOfPartitions(),
"inconsistent number of partitions");
vtkm::cont::MultiBlock testblocks2(2);
testblocks2.InsertBlock(0, TDset1);
testblocks2.InsertBlock(1, TDset2);
vtkm::cont::PartitionedDataSet testblocks2(2);
testblocks2.InsertPartition(0, TDset1);
testblocks2.InsertPartition(1, TDset2);
TestDSet = testblocks2.GetBlock(0);
TestDSet = testblocks2.GetPartition(0);
DataSet_Compare(TDset1, TestDSet);
TestDSet = testblocks2.GetBlock(1);
TestDSet = testblocks2.GetPartition(1);
DataSet_Compare(TDset2, TestDSet);
testblocks2.ReplaceBlock(0, TDset2);
testblocks2.ReplaceBlock(1, TDset1);
testblocks2.ReplacePartition(0, TDset2);
testblocks2.ReplacePartition(1, TDset1);
TestDSet = testblocks2.GetBlock(0);
TestDSet = testblocks2.GetPartition(0);
DataSet_Compare(TDset2, TestDSet);
TestDSet = testblocks2.GetBlock(1);
TestDSet = testblocks2.GetPartition(1);
DataSet_Compare(TDset1, TestDSet);
}
void DataSet_Compare(vtkm::cont::DataSet& LeftDateSet, vtkm::cont::DataSet& RightDateSet)
void DataSet_Compare(vtkm::cont::DataSet& leftDataSet, vtkm::cont::DataSet& rightDataSet)
{
for (vtkm::Id j = 0; j < LeftDateSet.GetNumberOfFields(); j++)
for (vtkm::Id j = 0; j < leftDataSet.GetNumberOfFields(); j++)
{
vtkm::cont::ArrayHandle<vtkm::Float32> LDataArray;
LeftDateSet.GetField(j).GetData().CopyTo(LDataArray);
vtkm::cont::ArrayHandle<vtkm::Float32> RDataArray;
RightDateSet.GetField(j).GetData().CopyTo(RDataArray);
VTKM_TEST_ASSERT(LDataArray == RDataArray, "field value info incorrect");
vtkm::cont::ArrayHandle<vtkm::Float32> lDataArray;
leftDataSet.GetField(j).GetData().CopyTo(lDataArray);
vtkm::cont::ArrayHandle<vtkm::Float32> rDataArray;
rightDataSet.GetField(j).GetData().CopyTo(rDataArray);
VTKM_TEST_ASSERT(lDataArray == rDataArray, "field value info incorrect");
}
return;
}
int UnitTestMultiBlock(int argc, char* argv[])
int UnitTestPartitionedDataSet(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(MultiBlockTest, argc, argv);
return vtkm::cont::testing::Testing::Run(PartitionedDataSetTest, argc, argv);
}

@ -14,7 +14,7 @@
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/Field.h>
#include <vtkm/cont/Invoker.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/filter/CreateResult.h>
#include <vtkm/filter/FieldSelection.h>
@ -50,21 +50,22 @@ namespace filter
/// vtkm::cont::DataSet dsInput = ...
/// auto outputDS = filter.Execute(dsInput);
///
/// // or, execute on a vtkm::cont::MultiBlock
/// vtkm::cont::MultiBlock mbInput = ...
/// // or, execute on a vtkm::cont::PartitionedDataSet
/// vtkm::cont::PartitionedDataSet mbInput = ...
/// auto outputMB = filter.Execute(mbInput);
/// \endcode
///
/// `Execute` methods take in the input dataset or multiblock to process and
/// return the result. The type of the result is same as the input type, thus
/// `Execute(DataSet&)` returns a DataSet while `Execute(MultiBlock&)` returns a
/// MultiBlock.
/// `Execute` methods take in the input DataSet or PartitionedDataSet to
/// process and return the result. The type of the result is same as the input
/// type, thus `Execute(DataSet&)` returns a DataSet while
/// `Execute(PartitionedDataSet&)` returns a PartitionedDataSet.
///
/// The implementation for `Execute(DataSet&)` is merely provided for
/// convenience. Internally, it creates MultiBlock with a single block for the
/// input and then forwards the call to `Execute(MultiBlock&)`. The method
/// returns the first block, if any, from the MultiBlock returned by the
/// forwarded call. If the MultiBlock returned has more than 1 block, then
/// convenience. Internally, it creates a PartitionedDataSet with a single
/// partition for the input and then forwards the call to
/// `Execute(PartitionedDataSet&)`. The method returns the first partition, if
/// any, from the PartitionedDataSet returned by the forwarded call. If the
/// PartitionedDataSet returned has more than 1 partition, then
/// `vtkm::cont::ErrorFilterExecution` will be thrown.
///
/// \section FilterSubclassing Subclassing
@ -83,22 +84,22 @@ namespace filter
/// \code{cpp}
///
/// template <typename DerivedPolicy>
/// void PreExecute(const vtkm::cont::MultiBlock& input,
/// void PreExecute(const vtkm::cont::PartitionedDataSet& input,
/// const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
///
/// template <typename DerivedPolicy>
/// void PostExecute(const vtkm::cont::MultiBlock& input, vtkm::cont::MultiBlock& output
/// void PostExecute(const vtkm::cont::PartitionedDataSet& input, vtkm::cont::PartitionedDataSet& output
/// const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
///
/// \endcode
///
/// As the name suggests, these are called and the beginning and before the end
/// of an `Filter::Execute` call. Most filters that don't need to handle
/// multiblock datasets specially, e.g. clip, cut, iso-contour, need not worry
/// PartitionedDataSet specially, e.g. clip, cut, iso-contour, need not worry
/// about these methods or provide any implementation. If, however, your filter
/// needs do to some initialization e.g. allocation buffers to accumulate
/// results, or finalization e.g. reduce results across all blocks, then these
/// methods provide convenient hooks for the same.
/// results, or finalization e.g. reduce results across all partitions, then
/// these methods provide convenient hooks for the same.
///
/// \subsection FilterPrepareForExecution PrepareForExecution
///
@ -108,11 +109,11 @@ namespace filter
/// available; which one to implement depends on the nature of the filter.
///
/// Let's consider simple filters that do not need to do anything special to
/// handle multiblock datasets e.g. clip, contour, etc. These are the filters
/// where executing the filter on a MultiBlock simply means executing the filter
/// on one block at a time and packing the output for each iteration info the
/// result MultiBlock. For such filters, one must implement the following
/// signature.
/// handle PartitionedDataSet e.g. clip, contour, etc. These are the filters
/// where executing the filter on a PartitionedDataSet simply means executing
/// the filter on one partition at a time and packing the output for each
/// iteration info the result PartitionedDataSet. For such filters, one must
/// implement the following signature.
///
/// \code{cpp}
///
@ -127,21 +128,22 @@ namespace filter
/// result and return it. If there are any errors, the subclass must throw an
/// exception (e.g. `vtkm::cont::ErrorFilterExecution`).
///
/// In this case, the Filter superclass handles iterating over multiple blocks
/// in the input MultiBlock and calling `PrepareForExecution` iteratively.
/// In this case, the Filter superclass handles iterating over multiple
/// partitions in the input PartitionedDataSet and calling
/// `PrepareForExecution` iteratively.
///
/// The aforementioned approach is also suitable for filters that need special
/// handling for multiblock datasets which can be modelled as PreExecute and
/// handling for PartitionedDataSets which can be modelled as PreExecute and
/// PostExecute steps (e.g. `vtkm::filter::Histogram`).
///
/// For more complex filters, like streamlines, particle tracking, where the
/// processing of multiblock datasets cannot be modelled as a reduction of the
/// processing of PartitionedDataSets cannot be modelled as a reduction of the
/// results, one can implement the following signature.
///
/// \code{cpp}
/// template <typename DerivedPolicy>
/// vtkm::cont::MultiBlock PrepareForExecution(
/// const vtkm::cont::MultiBlock& input,
/// vtkm::cont::PartitionedDataSet PrepareForExecution(
/// const vtkm::cont::PartitionedDataSet& input,
/// const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
/// \endcode
///
@ -163,8 +165,9 @@ namespace filter
///
/// \endcode
///
/// When present, this method will be called after each block execution to map
/// an input field from the corresponding input block to the output block.
/// When present, this method will be called after each partition execution to
/// map an input field from the corresponding input partition to the output
/// partition.
///
template <typename Derived>
class Filter
@ -235,14 +238,15 @@ public:
//@}
//@{
/// Executes the filter on the input MultiBlock and produces a result MultiBlock.
/// Executes the filter on the input PartitionedDataSet and produces a result PartitionedDataSet.
///
/// On success, this the dataset produced. On error, vtkm::cont::ErrorExecution will be thrown.
VTKM_CONT vtkm::cont::MultiBlock Execute(const vtkm::cont::MultiBlock& input);
VTKM_CONT vtkm::cont::PartitionedDataSet Execute(const vtkm::cont::PartitionedDataSet& input);
template <typename DerivedPolicy>
VTKM_CONT vtkm::cont::MultiBlock Execute(const vtkm::cont::MultiBlock& input,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
VTKM_CONT vtkm::cont::PartitionedDataSet Execute(
const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
//@}
/// Map fields from input dataset to output.

@ -171,22 +171,22 @@ InputType CallPrepareForExecutionInternal(std::true_type,
}
//--------------------------------------------------------------------------------
// specialization for MultiBlock input when `PrepareForExecution` is not provided
// specialization for PartitionedDataSet input when `PrepareForExecution` is not provided
// by the subclass. we iterate over blocks and execute for each block
// individually.
template <typename Derived, typename DerivedPolicy>
vtkm::cont::MultiBlock CallPrepareForExecutionInternal(
vtkm::cont::PartitionedDataSet CallPrepareForExecutionInternal(
std::false_type,
Derived* self,
const vtkm::cont::MultiBlock& input,
const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy)
{
vtkm::cont::MultiBlock output;
vtkm::cont::PartitionedDataSet output;
for (const auto& inBlock : input)
{
vtkm::cont::DataSet outBlock = CallPrepareForExecution(self, inBlock, policy);
CallMapFieldOntoOutput(self, inBlock, outBlock, policy);
output.AddBlock(outBlock);
output.AppendPartition(outBlock);
}
return output;
}
@ -254,8 +254,8 @@ inline VTKM_CONT vtkm::cont::DataSet Filter<Derived>::Execute(const vtkm::cont::
//----------------------------------------------------------------------------
template <typename Derived>
inline VTKM_CONT vtkm::cont::MultiBlock Filter<Derived>::Execute(
const vtkm::cont::MultiBlock& input)
inline VTKM_CONT vtkm::cont::PartitionedDataSet Filter<Derived>::Execute(
const vtkm::cont::PartitionedDataSet& input)
{
return this->Execute(input, vtkm::filter::PolicyDefault());
}
@ -272,23 +272,24 @@ inline VTKM_CONT vtkm::cont::DataSet Filter<Derived>::Execute(
vtkm::cont::LogLevel::Perf, "Filter: '%s'", vtkm::cont::TypeToString<Derived>().c_str());
Derived* self = static_cast<Derived*>(this);
vtkm::cont::MultiBlock output = self->Execute(vtkm::cont::MultiBlock(input), policy);
if (output.GetNumberOfBlocks() > 1)
vtkm::cont::PartitionedDataSet output =
self->Execute(vtkm::cont::PartitionedDataSet(input), policy);
if (output.GetNumberOfPartitions() > 1)
{
throw vtkm::cont::ErrorFilterExecution("Expecting at most 1 block.");
}
return output.GetNumberOfBlocks() == 1 ? output.GetBlock(0) : vtkm::cont::DataSet();
return output.GetNumberOfPartitions() == 1 ? output.GetPartition(0) : vtkm::cont::DataSet();
}
//----------------------------------------------------------------------------
template <typename Derived>
template <typename DerivedPolicy>
inline VTKM_CONT vtkm::cont::MultiBlock Filter<Derived>::Execute(
const vtkm::cont::MultiBlock& input,
inline VTKM_CONT vtkm::cont::PartitionedDataSet Filter<Derived>::Execute(
const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy)
{
VTKM_LOG_SCOPE(vtkm::cont::LogLevel::Perf,
"Filter (MultiBlock): '%s'",
"Filter (PartitionedDataSet): '%s'",
vtkm::cont::TypeToString<Derived>().c_str());
Derived* self = static_cast<Derived*>(this);
@ -297,7 +298,7 @@ inline VTKM_CONT vtkm::cont::MultiBlock Filter<Derived>::Execute(
internal::CallPreExecute(self, input, policy);
// Call `PrepareForExecution` (which should probably be renamed at some point)
vtkm::cont::MultiBlock output = internal::CallPrepareForExecution(self, input, policy);
vtkm::cont::PartitionedDataSet output = internal::CallPrepareForExecution(self, input, policy);
// Call `Derived::PostExecute<DerivedPolicy>(input, output, policy)` if defined.
internal::CallPostExecute(self, input, output, policy);

@ -15,7 +15,7 @@
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DynamicCellSet.h>
#include <vtkm/cont/Field.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/filter/Filter.h>
#include <vtkm/filter/PolicyBase.h>

@ -15,7 +15,7 @@
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DynamicCellSet.h>
#include <vtkm/cont/Field.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/filter/Filter.h>
#include <vtkm/filter/PolicyBase.h>

@ -14,7 +14,7 @@
#include <vtkm/cont/CoordinateSystem.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/Field.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/filter/Filter.h>
#include <vtkm/filter/PolicyBase.h>

@ -65,16 +65,16 @@ public:
vtkm::filter::PolicyBase<DerivedPolicy> policy);
//@{
/// when operating on vtkm::cont::MultiBlock, we
/// when operating on vtkm::cont::PartitionedDataSet, we
/// want to do processing across ranks as well. Just adding pre/post handles
/// for the same does the trick.
template <typename DerivedPolicy>
VTKM_CONT void PreExecute(const vtkm::cont::MultiBlock& input,
VTKM_CONT void PreExecute(const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>& policy);
template <typename DerivedPolicy>
VTKM_CONT void PostExecute(const vtkm::cont::MultiBlock& input,
vtkm::cont::MultiBlock& output,
VTKM_CONT void PostExecute(const vtkm::cont::PartitionedDataSet& input,
vtkm::cont::PartitionedDataSet& output,
const vtkm::filter::PolicyBase<DerivedPolicy>&);
//@}

@ -12,7 +12,7 @@
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayCopy.h>
#include <vtkm/cont/AssignerMultiBlock.h>
#include <vtkm/cont/AssignerPartitionedDataSet.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/ErrorFilterExecution.h>
#include <vtkm/cont/FieldRangeGlobalCompute.h>
@ -105,7 +105,7 @@ public:
[]() -> void* { return new vtkm::cont::ArrayHandle<vtkm::Id>(); },
[](void* ptr) { delete static_cast<vtkm::cont::ArrayHandle<vtkm::Id>*>(ptr); });
vtkm::cont::AssignerMultiBlock assigner(numLocalBlocks);
vtkm::cont::AssignerPartitionedDataSet assigner(numLocalBlocks);
vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds> decomposer(
/*dims*/ 1, vtkmdiy::interval(0, assigner.nblocks() - 1), assigner.nblocks());
decomposer.decompose(comm.rank(), assigner, master);
@ -206,7 +206,7 @@ inline VTKM_CONT vtkm::cont::DataSet Histogram::DoExecute(
//-----------------------------------------------------------------------------
template <typename DerivedPolicy>
inline VTKM_CONT void Histogram::PreExecute(const vtkm::cont::MultiBlock& input,
inline VTKM_CONT void Histogram::PreExecute(const vtkm::cont::PartitionedDataSet& input,
const vtkm::filter::PolicyBase<DerivedPolicy>&)
{
using TypeList = typename DerivedPolicy::FieldTypeList;
@ -228,15 +228,15 @@ inline VTKM_CONT void Histogram::PreExecute(const vtkm::cont::MultiBlock& input,
//-----------------------------------------------------------------------------
template <typename DerivedPolicy>
inline VTKM_CONT void Histogram::PostExecute(const vtkm::cont::MultiBlock&,
vtkm::cont::MultiBlock& result,
inline VTKM_CONT void Histogram::PostExecute(const vtkm::cont::PartitionedDataSet&,
vtkm::cont::PartitionedDataSet& result,
const vtkm::filter::PolicyBase<DerivedPolicy>&)
{
// iterate and compute histogram for each local block.
detail::DistributedHistogram helper(result.GetNumberOfBlocks());
for (vtkm::Id cc = 0; cc < result.GetNumberOfBlocks(); ++cc)
detail::DistributedHistogram helper(result.GetNumberOfPartitions());
for (vtkm::Id cc = 0; cc < result.GetNumberOfPartitions(); ++cc)
{
auto& ablock = result.GetBlock(cc);
auto& ablock = result.GetPartition(cc);
helper.SetLocalHistogram(cc, ablock.GetField(this->GetOutputFieldName()));
}
@ -245,7 +245,7 @@ inline VTKM_CONT void Histogram::PostExecute(const vtkm::cont::MultiBlock&,
this->GetOutputFieldName(), vtkm::cont::Field::Association::WHOLE_MESH, helper.ReduceAll());
output.AddField(rfield);
result = vtkm::cont::MultiBlock(output);
result = vtkm::cont::PartitionedDataSet(output);
}
}
} // namespace vtkm::filter

@ -39,10 +39,10 @@ set(unit_tests
UnitTestMaskFilter.cxx
UnitTestMaskPointsFilter.cxx
UnitTestMeshQualityFilter.cxx
UnitTestMultiBlockFilters.cxx
UnitTestMultiBlockHistogramFilter.cxx
UnitTestNDEntropyFilter.cxx
UnitTestNDHistogramFilter.cxx
UnitTestPartitionedDataSetFilters.cxx
UnitTestPartitionedDataSetHistogramFilter.cxx
UnitTestPointAverageFilter.cxx
UnitTestPointElevationFilter.cxx
UnitTestPointTransform.cxx

@ -1,124 +0,0 @@
//============================================================================
// 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/CellShape.h>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
#include <vtkm/exec/ConnectivityStructured.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/CellAverage.h>
template <typename T>
vtkm::cont::MultiBlock MultiBlockBuilder(std::size_t BlockNum, std::string FieldName)
{
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
vtkm::cont::DataSet dataSet;
vtkm::cont::DataSetFieldAdd dsf;
vtkm::Vec<T, 2> origin(0);
vtkm::Vec<T, 2> spacing(1);
vtkm::cont::MultiBlock Blocks;
for (vtkm::Id BlockId = 0; BlockId < static_cast<vtkm::Id>(BlockNum); BlockId++)
{
vtkm::Id2 dimensions((BlockId + 2) * (BlockId + 2), (BlockId + 2) * (BlockId + 2));
if (FieldName == "cellvar")
{
vtkm::Id numCells = (dimensions[0] - 1) * (dimensions[1] - 1);
std::vector<T> varC2D(static_cast<std::size_t>(numCells));
for (vtkm::Id i = 0; i < numCells; i++)
{
varC2D[static_cast<std::size_t>(i)] = static_cast<T>(BlockId * i);
}
dataSet = dataSetBuilder.Create(vtkm::Id2(dimensions[0], dimensions[1]),
vtkm::Vec<T, 2>(origin[0], origin[1]),
vtkm::Vec<T, 2>(spacing[0], spacing[1]));
dsf.AddCellField(dataSet, "cellvar", varC2D);
}
if (FieldName == "pointvar")
{
vtkm::Id numPoints = dimensions[0] * dimensions[1];
std::vector<T> varP2D(static_cast<std::size_t>(numPoints));
for (vtkm::Id i = 0; i < numPoints; i++)
{
varP2D[static_cast<std::size_t>(i)] = static_cast<T>(BlockId);
}
dataSet = dataSetBuilder.Create(vtkm::Id2(dimensions[0], dimensions[1]),
vtkm::Vec<T, 2>(origin[0], origin[1]),
vtkm::Vec<T, 2>(spacing[0], spacing[1]));
dsf.AddPointField(dataSet, "pointvar", varP2D);
}
Blocks.AddBlock(dataSet);
}
return Blocks;
}
template <typename D>
void Result_Verify(const vtkm::cont::MultiBlock& Result,
D& Filter,
const vtkm::cont::MultiBlock& Blocks,
std::string FieldName)
{
VTKM_TEST_ASSERT(Result.GetNumberOfBlocks() == Blocks.GetNumberOfBlocks(),
"result block number incorrect");
const std::string outputFieldName = Filter.GetOutputFieldName();
for (vtkm::Id j = 0; j < Result.GetNumberOfBlocks(); j++)
{
Filter.SetActiveField(FieldName);
vtkm::cont::DataSet BlockResult = Filter.Execute(Blocks.GetBlock(j));
VTKM_TEST_ASSERT(Result.GetBlock(j).GetField(outputFieldName).GetNumberOfValues() ==
BlockResult.GetField(outputFieldName).GetNumberOfValues(),
"result vectors' size incorrect");
vtkm::cont::ArrayHandle<vtkm::Id> MBlockArray;
Result.GetBlock(j).GetField(outputFieldName).GetData().CopyTo(MBlockArray);
vtkm::cont::ArrayHandle<vtkm::Id> SDataSetArray;
BlockResult.GetField(outputFieldName).GetData().CopyTo(SDataSetArray);
for (vtkm::Id i = 0; i < Result.GetBlock(j).GetField(outputFieldName).GetNumberOfValues(); i++)
{
VTKM_TEST_ASSERT(MBlockArray.GetPortalConstControl().Get(i) ==
SDataSetArray.GetPortalConstControl().Get(i),
"result values incorrect");
}
}
return;
}
void TestMultiBlockFilters()
{
std::size_t BlockNum = 7;
vtkm::cont::MultiBlock result;
vtkm::cont::MultiBlock Blocks;
Blocks = MultiBlockBuilder<vtkm::Id>(BlockNum, "pointvar");
vtkm::filter::CellAverage cellAverage;
cellAverage.SetOutputFieldName("average");
cellAverage.SetActiveField("pointvar");
result = cellAverage.Execute(Blocks);
Result_Verify(result, cellAverage, Blocks, std::string("pointvar"));
}
int UnitTestMultiBlockFilters(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestMultiBlockFilters, argc, argv);
}

@ -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/CellShape.h>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/DataSetFieldAdd.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
#include <vtkm/exec/ConnectivityStructured.h>
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/CellAverage.h>
template <typename T>
vtkm::cont::PartitionedDataSet PartitionedDataSetBuilder(std::size_t partitionNum,
std::string fieldName)
{
vtkm::cont::DataSetBuilderUniform dataSetBuilder;
vtkm::cont::DataSet dataSet;
vtkm::cont::DataSetFieldAdd dsf;
vtkm::Vec<T, 2> origin(0);
vtkm::Vec<T, 2> spacing(1);
vtkm::cont::PartitionedDataSet partitions;
for (vtkm::Id partId = 0; partId < static_cast<vtkm::Id>(partitionNum); partId++)
{
vtkm::Id2 dimensions((partId + 2) * (partId + 2), (partId + 2) * (partId + 2));
if (fieldName == "cellvar")
{
vtkm::Id numCells = (dimensions[0] - 1) * (dimensions[1] - 1);
std::vector<T> varC2D(static_cast<std::size_t>(numCells));
for (vtkm::Id i = 0; i < numCells; i++)
{
varC2D[static_cast<std::size_t>(i)] = static_cast<T>(partId * i);
}
dataSet = dataSetBuilder.Create(vtkm::Id2(dimensions[0], dimensions[1]),
vtkm::Vec<T, 2>(origin[0], origin[1]),
vtkm::Vec<T, 2>(spacing[0], spacing[1]));
dsf.AddCellField(dataSet, "cellvar", varC2D);
}
if (fieldName == "pointvar")
{
vtkm::Id numPoints = dimensions[0] * dimensions[1];
std::vector<T> varP2D(static_cast<std::size_t>(numPoints));
for (vtkm::Id i = 0; i < numPoints; i++)
{
varP2D[static_cast<std::size_t>(i)] = static_cast<T>(partId);
}
dataSet = dataSetBuilder.Create(vtkm::Id2(dimensions[0], dimensions[1]),
vtkm::Vec<T, 2>(origin[0], origin[1]),
vtkm::Vec<T, 2>(spacing[0], spacing[1]));
dsf.AddPointField(dataSet, "pointvar", varP2D);
}
partitions.AppendPartition(dataSet);
}
return partitions;
}
template <typename D>
void Result_Verify(const vtkm::cont::PartitionedDataSet& result,
D& filter,
const vtkm::cont::PartitionedDataSet& partitions,
std::string fieldName)
{
VTKM_TEST_ASSERT(result.GetNumberOfPartitions() == partitions.GetNumberOfPartitions(),
"result partition number incorrect");
const std::string outputFieldName = filter.GetOutputFieldName();
for (vtkm::Id j = 0; j < result.GetNumberOfPartitions(); j++)
{
filter.SetActiveField(fieldName);
vtkm::cont::DataSet partitionResult = filter.Execute(partitions.GetPartition(j));
VTKM_TEST_ASSERT(result.GetPartition(j).GetField(outputFieldName).GetNumberOfValues() ==
partitionResult.GetField(outputFieldName).GetNumberOfValues(),
"result vectors' size incorrect");
vtkm::cont::ArrayHandle<vtkm::Id> partitionArray;
result.GetPartition(j).GetField(outputFieldName).GetData().CopyTo(partitionArray);
vtkm::cont::ArrayHandle<vtkm::Id> sDataSetArray;
partitionResult.GetField(outputFieldName).GetData().CopyTo(sDataSetArray);
const vtkm::Id numValues = result.GetPartition(j).GetField(outputFieldName).GetNumberOfValues();
for (vtkm::Id i = 0; i < numValues; i++)
{
VTKM_TEST_ASSERT(partitionArray.GetPortalConstControl().Get(i) ==
sDataSetArray.GetPortalConstControl().Get(i),
"result values incorrect");
}
}
return;
}
void TestPartitionedDataSetFilters()
{
std::size_t partitionNum = 7;
vtkm::cont::PartitionedDataSet result;
vtkm::cont::PartitionedDataSet partitions;
partitions = PartitionedDataSetBuilder<vtkm::Id>(partitionNum, "pointvar");
vtkm::filter::CellAverage cellAverage;
cellAverage.SetOutputFieldName("average");
cellAverage.SetActiveField("pointvar");
result = cellAverage.Execute(partitions);
Result_Verify(result, cellAverage, partitions, std::string("pointvar"));
}
int UnitTestPartitionedDataSetFilters(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestPartitionedDataSetFilters, argc, argv);
}

@ -10,7 +10,7 @@
#include <vtkm/filter/Histogram.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/MultiBlock.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <algorithm>
@ -79,32 +79,34 @@ void AddField(vtkm::cont::DataSet& dataset,
}
}
static void TestMultiBlockHistogram()
static void TestPartitionedDataSetHistogram()
{
// init random seed.
std::srand(100);
vtkm::cont::MultiBlock mb;
vtkm::cont::PartitionedDataSet mb;
vtkm::cont::DataSet block0;
AddField<double>(block0, 0.0, 100.0, 1024, "double");
mb.AddBlock(block0);
vtkm::cont::DataSet partition0;
AddField<double>(partition0, 0.0, 100.0, 1024, "double");
mb.AppendPartition(partition0);
vtkm::cont::DataSet block1;
AddField<int>(block1, 100, 1000, 1024, "double");
mb.AddBlock(block1);
vtkm::cont::DataSet partition1;
AddField<int>(partition1, 100, 1000, 1024, "double");
mb.AppendPartition(partition1);
vtkm::cont::DataSet block2;
AddField<double>(block2, 100.0, 500.0, 1024, "double");
mb.AddBlock(block2);
vtkm::cont::DataSet partition2;
AddField<double>(partition2, 100.0, 500.0, 1024, "double");
mb.AppendPartition(partition2);
vtkm::filter::Histogram histogram;
histogram.SetActiveField("double");
auto result = histogram.Execute(mb);
VTKM_TEST_ASSERT(result.GetNumberOfBlocks() == 1, "Expecting 1 block.");
VTKM_TEST_ASSERT(result.GetNumberOfPartitions() == 1, "Expecting 1 partition.");
auto bins =
result.GetBlock(0).GetField("histogram").GetData().Cast<vtkm::cont::ArrayHandle<vtkm::Id>>();
auto bins = result.GetPartition(0)
.GetField("histogram")
.GetData()
.Cast<vtkm::cont::ArrayHandle<vtkm::Id>>();
VTKM_TEST_ASSERT(bins.GetNumberOfValues() == 10, "Expecting 10 bins.");
auto count = std::accumulate(vtkm::cont::ArrayPortalToIteratorBegin(bins.GetPortalConstControl()),
vtkm::cont::ArrayPortalToIteratorEnd(bins.GetPortalConstControl()),
@ -120,7 +122,7 @@ static void TestMultiBlockHistogram()
std::cout << std::endl;
};
int UnitTestMultiBlockHistogramFilter(int argc, char* argv[])
int UnitTestPartitionedDataSetHistogramFilter(int argc, char* argv[])
{
return vtkm::cont::testing::Testing::Run(TestMultiBlockHistogram, argc, argv);
return vtkm::cont::testing::Testing::Run(TestPartitionedDataSetHistogram, argc, argv);
}