//============================================================================ // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt for details. // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ #include #include #include #include #include #include #include #include #include namespace { static unsigned int uid = 1; #define PRINT_INFO(msg) std::cout << "[" << comm.rank() << ":" << __LINE__ << "] " msg << std::endl; #define PRINT_INFO_0(msg) \ if (comm.rank() == 0) \ { \ std::cout << "[" << comm.rank() << ":" << __LINE__ << "] " msg << std::endl; \ } template vtkm::cont::ArrayHandle CreateArray(T min, T max, vtkm::Id numVals, vtkm::TypeTraitsScalarTag) { std::mt19937 gen(uid++); std::uniform_real_distribution dis(static_cast(min), static_cast(max)); vtkm::cont::ArrayHandle handle; handle.Allocate(numVals); auto portal = handle.WritePortal(); std::generate(vtkm::cont::ArrayPortalToIteratorBegin(portal), vtkm::cont::ArrayPortalToIteratorEnd(portal), [&]() { return static_cast(dis(gen)); }); return handle; } template vtkm::cont::ArrayHandle CreateArray(const T& min, const T& max, vtkm::Id numVals, vtkm::TypeTraitsVectorTag) { constexpr int size = T::NUM_COMPONENTS; std::mt19937 gen(uid++); std::uniform_real_distribution dis[size]; for (int cc = 0; cc < size; ++cc) { dis[cc] = std::uniform_real_distribution(static_cast(min[cc]), static_cast(max[cc])); } vtkm::cont::ArrayHandle handle; handle.Allocate(numVals); auto portal = handle.WritePortal(); std::generate(vtkm::cont::ArrayPortalToIteratorBegin(portal), vtkm::cont::ArrayPortalToIteratorEnd(portal), [&]() { T val; for (int cc = 0; cc < size; ++cc) { val[cc] = static_cast(dis[cc](gen)); } return val; }); return handle; } static constexpr vtkm::Id ARRAY_SIZE = 1025; template void Validate(const vtkm::cont::ArrayHandle& ranges, const ValueType& min, const ValueType& max) { vtkmdiy::mpi::communicator comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); VTKM_TEST_ASSERT(ranges.GetNumberOfValues() == 1, "Wrong number of ranges"); auto portal = ranges.ReadPortal(); auto range = portal.Get(0); PRINT_INFO(<< " expecting [" << min << ", " << max << "], got [" << range.Min << ", " << range.Max << "]"); VTKM_TEST_ASSERT(range.IsNonEmpty() && range.Min >= static_cast(min) && range.Max <= static_cast(max), "Got wrong range."); } template void Validate(const vtkm::cont::ArrayHandle& ranges, const vtkm::Vec& min, const vtkm::Vec& max) { vtkmdiy::mpi::communicator comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); VTKM_TEST_ASSERT(ranges.GetNumberOfValues() == size, "Wrong number of ranges"); auto portal = ranges.ReadPortal(); for (int cc = 0; cc < size; ++cc) { auto range = portal.Get(cc); PRINT_INFO(<< " [" << cc << "] expecting [" << min[cc] << ", " << max[cc] << "], got [" << range.Min << ", " << range.Max << "]"); VTKM_TEST_ASSERT(range.IsNonEmpty() && range.Min >= static_cast(min[cc]) && range.Max <= static_cast(max[cc]), "Got wrong range."); } } template void DecomposeRange(ValueType& min, ValueType& max) { vtkmdiy::mpi::communicator comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); auto delta = (max - min) / static_cast(comm.size()); min = min + static_cast(comm.rank()) * delta; max = (comm.rank() == comm.size() - 1) ? max : min + delta; } template void DecomposeRange(vtkm::Vec& min, vtkm::Vec& max) { for (int cc = 0; cc < size; ++cc) { DecomposeRange(min[0], max[0]); } } template void TryRangeGlobalComputeDS(const ValueType& min, const ValueType& max) { vtkmdiy::mpi::communicator comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); PRINT_INFO_0("Trying type (dataset): " << vtkm::testing::TypeName::Name()); // distribute range among all ranks, so we can confirm reduction works. ValueType lmin = min, lmax = max; DecomposeRange(lmin, lmax); PRINT_INFO("gmin=" << min << ", gmax=" << max << " lmin=" << lmin << ", lmax=" << lmax); // let's create a dummy dataset with a bunch of fields. vtkm::cont::DataSet dataset; dataset.AddPointField( "pointvar", CreateArray(lmin, lmax, ARRAY_SIZE, typename vtkm::TypeTraits::DimensionalityTag())); vtkm::cont::ArrayHandle ranges = vtkm::cont::FieldRangeGlobalCompute(dataset, "pointvar"); Validate(ranges, min, max); } template void TryRangeGlobalComputePDS(const ValueType& min, const ValueType& max) { vtkmdiy::mpi::communicator comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); PRINT_INFO("Trying type (PartitionedDataSet): " << vtkm::testing::TypeName::Name()); vtkm::cont::PartitionedDataSet mb; for (int cc = 0; cc < 5; cc++) { // let's create a dummy dataset with a bunch of fields. vtkm::cont::DataSet dataset; dataset.AddPointField( "pointvar", CreateArray(min, max, ARRAY_SIZE, typename vtkm::TypeTraits::DimensionalityTag())); mb.AppendPartition(dataset); } vtkm::cont::ArrayHandle ranges = vtkm::cont::FieldRangeGlobalCompute(mb, "pointvar"); Validate(ranges, min, max); } static void TestFieldRangeGlobalCompute() { vtkmdiy::mpi::communicator comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); PRINT_INFO_0("Running on " << comm.size() << " ranks."); // init random seed. std::srand(static_cast(100 + 1024 * comm.rank())); TryRangeGlobalComputeDS(0, 1000); TryRangeGlobalComputeDS(-1024, 1024); TryRangeGlobalComputeDS(vtkm::make_Vec(1024, 0, -1024), vtkm::make_Vec(2048, 2048, 2048)); TryRangeGlobalComputePDS(0, 1000); TryRangeGlobalComputePDS(-1024, 1024); TryRangeGlobalComputePDS(vtkm::make_Vec(1024, 0, -1024), vtkm::make_Vec(2048, 2048, 2048)); }; } int UnitTestFieldRangeGlobalCompute(int argc, char* argv[]) { return vtkm::cont::testing::Testing::Run(TestFieldRangeGlobalCompute, argc, argv); }