//============================================================================ // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt for details. // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ #include #include #include #include #include namespace vtkm { namespace cont { //----------------------------------------------------------------------------- VTKM_CONT vtkm::cont::ArrayHandle 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 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 MergeRangesGlobal( const vtkm::cont::ArrayHandle& ranges) { auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); if (comm.size() == 1) { return ranges; } std::vector v_ranges(static_cast(ranges.GetNumberOfValues())); std::copy(vtkm::cont::ArrayPortalToIteratorBegin(ranges.ReadPortal()), vtkm::cont::ArrayPortalToIteratorEnd(ranges.ReadPortal()), v_ranges.begin()); using VectorOfRangesT = std::vector; vtkmdiy::Master master( comm, 1, -1, []() -> void* { return new VectorOfRangesT(); }, [](void* ptr) { delete static_cast(ptr); }); vtkmdiy::ContiguousAssigner assigner(/*num ranks*/ comm.size(), /*global-num-blocks*/ comm.size()); vtkmdiy::RegularDecomposer 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(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 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()); } } // 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(0), vtkm::CopyFlag::On); } } // namespace detail } } // namespace vtkm::cont