mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 09:59:12 +00:00
7d681fb585
Instead, always use precompiled versions of range computing. This means you won't be able to specify the type. Currently, types are limited to scalars vecs up to size 4. The main motivation for this change is to allow you to include Field.h with a non-device compiler. This is an important feature for our customers. I plan in the future to implement a mechanism to pull out a component of most ArrayHandle's as a single array. This would enable us to support a precompiled version that can compute the range of arbitrarily sized Vecs.
125 lines
4.2 KiB
C++
125 lines
4.2 KiB
C++
//============================================================================
|
|
// 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/FieldRangeGlobalCompute.h>
|
|
|
|
#include <vtkm/cont/EnvironmentTracker.h>
|
|
|
|
#include <vtkm/thirdparty/diy/diy.h>
|
|
|
|
#include <algorithm>
|
|
#include <functional>
|
|
|
|
namespace vtkm
|
|
{
|
|
namespace cont
|
|
{
|
|
|
|
//-----------------------------------------------------------------------------
|
|
VTKM_CONT
|
|
vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeGlobalCompute(const vtkm::cont::DataSet& dataset,
|
|
const std::string& name,
|
|
vtkm::cont::Field::Association assoc)
|
|
{
|
|
auto lrange = vtkm::cont::FieldRangeCompute(dataset, name, assoc);
|
|
return vtkm::cont::detail::MergeRangesGlobal(lrange);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
VTKM_CONT
|
|
vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeGlobalCompute(
|
|
const vtkm::cont::PartitionedDataSet& pds,
|
|
const std::string& name,
|
|
vtkm::cont::Field::Association assoc)
|
|
{
|
|
auto lrange = vtkm::cont::FieldRangeCompute(pds, name, assoc);
|
|
return vtkm::cont::detail::MergeRangesGlobal(lrange);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
namespace detail
|
|
{
|
|
VTKM_CONT
|
|
vtkm::cont::ArrayHandle<vtkm::Range> MergeRangesGlobal(
|
|
const vtkm::cont::ArrayHandle<vtkm::Range>& ranges)
|
|
{
|
|
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
|
|
if (comm.size() == 1)
|
|
{
|
|
return ranges;
|
|
}
|
|
|
|
std::vector<vtkm::Range> v_ranges(static_cast<size_t>(ranges.GetNumberOfValues()));
|
|
std::copy(vtkm::cont::ArrayPortalToIteratorBegin(ranges.ReadPortal()),
|
|
vtkm::cont::ArrayPortalToIteratorEnd(ranges.ReadPortal()),
|
|
v_ranges.begin());
|
|
|
|
using VectorOfRangesT = std::vector<vtkm::Range>;
|
|
|
|
vtkmdiy::Master master(
|
|
comm,
|
|
1,
|
|
-1,
|
|
[]() -> void* { return new VectorOfRangesT(); },
|
|
[](void* ptr) { delete static_cast<VectorOfRangesT*>(ptr); });
|
|
|
|
vtkmdiy::ContiguousAssigner assigner(/*num ranks*/ comm.size(),
|
|
/*global-num-blocks*/ comm.size());
|
|
vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds> decomposer(
|
|
/*dim*/ 1, vtkmdiy::interval(0, comm.size() - 1), comm.size());
|
|
decomposer.decompose(comm.rank(), assigner, master);
|
|
assert(master.size() == 1); // each rank will have exactly 1 block.
|
|
*master.block<VectorOfRangesT>(0) = v_ranges;
|
|
|
|
vtkmdiy::RegularAllReducePartners all_reduce_partners(decomposer, /*k*/ 2);
|
|
|
|
auto callback = [](VectorOfRangesT* data,
|
|
const vtkmdiy::ReduceProxy& srp,
|
|
const vtkmdiy::RegularMergePartners&) {
|
|
const auto selfid = srp.gid();
|
|
// 1. dequeue.
|
|
std::vector<int> incoming;
|
|
srp.incoming(incoming);
|
|
for (const int gid : incoming)
|
|
{
|
|
if (gid != selfid)
|
|
{
|
|
VectorOfRangesT message;
|
|
srp.dequeue(gid, message);
|
|
|
|
// if the number of components we've seen so far is less than those
|
|
// in the received message, resize so we can accommodate all components
|
|
// in the message. If the message has fewer components, it has no
|
|
// effect.
|
|
data->resize(std::max(data->size(), message.size()));
|
|
|
|
std::transform(
|
|
message.begin(), message.end(), data->begin(), data->begin(), std::plus<vtkm::Range>());
|
|
}
|
|
}
|
|
// 2. enqueue
|
|
for (int cc = 0; cc < srp.out_link().size(); ++cc)
|
|
{
|
|
auto target = srp.out_link().target(cc);
|
|
if (target.gid != selfid)
|
|
{
|
|
srp.enqueue(target, *data);
|
|
}
|
|
}
|
|
};
|
|
|
|
vtkmdiy::reduce(master, assigner, all_reduce_partners, callback);
|
|
assert(master.size() == 1); // each rank will have exactly 1 block.
|
|
|
|
return vtkm::cont::make_ArrayHandle(*master.block<VectorOfRangesT>(0), vtkm::CopyFlag::On);
|
|
}
|
|
} // namespace detail
|
|
}
|
|
} // namespace vtkm::cont
|