//============================================================================ // 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. // // Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS). // Copyright 2014 UT-Battelle, LLC. // Copyright 2014 Los Alamos National Security. // // Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National // Laboratory (LANL), the U.S. Government retains certain rights in // this software. //============================================================================ #include #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); std::generate(vtkm::cont::ArrayPortalToIteratorBegin(handle.GetPortalControl()), vtkm::cont::ArrayPortalToIteratorEnd(handle.GetPortalControl()), [&]() { 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); std::generate(vtkm::cont::ArrayPortalToIteratorBegin(handle.GetPortalControl()), vtkm::cont::ArrayPortalToIteratorEnd(handle.GetPortalControl()), [&]() { 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) { diy::mpi::communicator comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); VTKM_TEST_ASSERT(ranges.GetNumberOfValues() == 1, "Wrong number of ranges"); auto portal = ranges.GetPortalConstControl(); 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) { diy::mpi::communicator comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); VTKM_TEST_ASSERT(ranges.GetNumberOfValues() == size, "Wrong number of ranges"); auto portal = ranges.GetPortalConstControl(); 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) { diy::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) { diy::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; vtkm::cont::DataSetFieldAdd::AddPointField( dataset, "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 TryRangeGlobalComputeMB(const ValueType& min, const ValueType& max) { diy::mpi::communicator comm = vtkm::cont::EnvironmentTracker::GetCommunicator(); PRINT_INFO("Trying type (multiblock): " << vtkm::testing::TypeName::Name()); vtkm::cont::MultiBlock mb; for (int cc = 0; cc < 5; cc++) { // let's create a dummy dataset with a bunch of fields. vtkm::cont::DataSet dataset; vtkm::cont::DataSetFieldAdd::AddPointField( dataset, "pointvar", CreateArray(min, max, ARRAY_SIZE, typename vtkm::TypeTraits::DimensionalityTag())); mb.AddBlock(dataset); } vtkm::cont::ArrayHandle ranges = vtkm::cont::FieldRangeGlobalCompute(mb, "pointvar"); Validate(ranges, min, max); } static void TestFieldRangeGlobalCompute() { diy::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)); TryRangeGlobalComputeMB(0, 1000); TryRangeGlobalComputeMB(-1024, 1024); TryRangeGlobalComputeMB>(vtkm::make_Vec(1024, 0, -1024), vtkm::make_Vec(2048, 2048, 2048)); }; } int UnitTestFieldRangeGlobalCompute(int, char* []) { return vtkm::cont::testing::Testing::Run(TestFieldRangeGlobalCompute); }