vtk-m/vtkm/cont/FieldRangeGlobalCompute.cxx

125 lines
4.2 KiB
C++
Raw Normal View History

2018-04-05 01:13:44 +00:00
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt for details.
2019-04-15 23:24:21 +00:00
//
2018-04-05 01:13:44 +00:00
// 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>
2018-04-05 01:13:44 +00:00
#include <algorithm>
#include <functional>
2018-04-05 01:13:44 +00:00
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)
2018-04-05 01:13:44 +00:00
{
auto lrange = vtkm::cont::FieldRangeCompute(dataset, name, assoc);
return vtkm::cont::detail::MergeRangesGlobal(lrange);
2018-04-05 01:13:44 +00:00
}
//-----------------------------------------------------------------------------
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Range> FieldRangeGlobalCompute(
const vtkm::cont::PartitionedDataSet& pds,
2018-04-05 01:13:44 +00:00
const std::string& name,
vtkm::cont::Field::Association assoc)
2018-04-05 01:13:44 +00:00
{
auto lrange = vtkm::cont::FieldRangeCompute(pds, name, assoc);
return vtkm::cont::detail::MergeRangesGlobal(lrange);
2018-04-05 01:13:44 +00:00
}
//-----------------------------------------------------------------------------
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>;
2018-04-05 01:13:44 +00:00
vtkmdiy::Master master(
comm,
1,
-1,
[]() -> void* { return new VectorOfRangesT(); },
[](void* ptr) { delete static_cast<VectorOfRangesT*>(ptr); });
2018-04-05 01:13:44 +00:00
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());
2018-04-05 01:13:44 +00:00
decomposer.decompose(comm.rank(), assigner, master);
assert(master.size() == 1); // each rank will have exactly 1 block.
*master.block<VectorOfRangesT>(0) = v_ranges;
2018-04-05 01:13:44 +00:00
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)
2018-04-05 01:13:44 +00:00
{
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>());
2018-04-05 01:13:44 +00:00
}
}
// 2. enqueue
for (int cc = 0; cc < srp.out_link().size(); ++cc)
{
auto target = srp.out_link().target(cc);
if (target.gid != selfid)
2018-04-05 01:13:44 +00:00
{
srp.enqueue(target, *data);
2018-04-05 01:13:44 +00:00
}
}
};
2018-04-05 01:13:44 +00:00
vtkmdiy::reduce(master, assigner, all_reduce_partners, callback);
2018-04-05 01:13:44 +00:00
assert(master.size() == 1); // each rank will have exactly 1 block.
return vtkm::cont::make_ArrayHandle(*master.block<VectorOfRangesT>(0), vtkm::CopyFlag::On);
2018-04-05 01:13:44 +00:00
}
} // namespace detail
}
} // namespace vtkm::cont